mirror of
https://github.com/verilator/verilator.git
synced 2026-09-03 08:24:31 +02:00
Improve V3List user interface (#4996)
This commit is contained in:
+90
-120
@@ -41,7 +41,7 @@ V3GraphVertex::V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old)
|
||||
, m_color{old.m_color}
|
||||
, m_rank{old.m_rank} {
|
||||
m_userp = nullptr;
|
||||
verticesPushBack(graphp);
|
||||
graphp->vertices().linkBack(this);
|
||||
}
|
||||
|
||||
V3GraphVertex::V3GraphVertex(V3Graph* graphp)
|
||||
@@ -49,67 +49,61 @@ V3GraphVertex::V3GraphVertex(V3Graph* graphp)
|
||||
, m_color{0}
|
||||
, m_rank{0} {
|
||||
m_userp = nullptr;
|
||||
verticesPushBack(graphp);
|
||||
}
|
||||
|
||||
void V3GraphVertex::verticesPushBack(V3Graph* graphp) {
|
||||
m_vertices.pushBack(graphp->m_vertices, this);
|
||||
graphp->vertices().linkBack(this);
|
||||
}
|
||||
|
||||
void V3GraphVertex::unlinkEdges(V3Graph*) {
|
||||
for (V3GraphEdge* edgep = outBeginp(); edgep; /*BELOW*/) {
|
||||
V3GraphEdge* nextp = edgep->outNextp();
|
||||
edgep->unlinkDelete();
|
||||
edgep = nextp;
|
||||
}
|
||||
for (V3GraphEdge* edgep = inBeginp(); edgep; /*BELOW*/) {
|
||||
V3GraphEdge* nextp = edgep->inNextp();
|
||||
edgep->unlinkDelete();
|
||||
edgep = nextp;
|
||||
}
|
||||
while (V3GraphEdge* const ep = m_outs.frontp()) VL_DO_DANGLING(ep->unlinkDelete(), ep);
|
||||
while (V3GraphEdge* const ep = m_ins.frontp()) VL_DO_DANGLING(ep->unlinkDelete(), ep);
|
||||
}
|
||||
|
||||
void V3GraphVertex::unlinkDelete(V3Graph* graphp) {
|
||||
// Delete edges
|
||||
unlinkEdges(graphp);
|
||||
// Unlink from vertex list
|
||||
m_vertices.unlink(graphp->m_vertices, this);
|
||||
graphp->m_vertices.unlink(this);
|
||||
// Delete
|
||||
delete this; // this=nullptr;
|
||||
}
|
||||
|
||||
void V3GraphVertex::rerouteEdges(V3Graph* graphp) {
|
||||
// Make new edges for each from/to pair
|
||||
for (V3GraphEdge* iedgep = inBeginp(); iedgep; iedgep = iedgep->inNextp()) {
|
||||
for (V3GraphEdge* oedgep = outBeginp(); oedgep; oedgep = oedgep->outNextp()) {
|
||||
new V3GraphEdge{graphp, iedgep->fromp(), oedgep->top(),
|
||||
std::min(iedgep->weight(), oedgep->weight()),
|
||||
iedgep->cutable() && oedgep->cutable()};
|
||||
for (V3GraphEdge& iedge : inEdges()) {
|
||||
for (V3GraphEdge& oedge : outEdges()) {
|
||||
new V3GraphEdge{graphp, iedge.fromp(), oedge.top(),
|
||||
std::min(iedge.weight(), oedge.weight()),
|
||||
iedge.cutable() && oedge.cutable()};
|
||||
}
|
||||
}
|
||||
// Remove old edges
|
||||
unlinkEdges(graphp);
|
||||
}
|
||||
|
||||
bool V3GraphVertex::inSize1() const { return !inEmpty() && !inBeginp()->inNextp(); }
|
||||
bool V3GraphVertex::outSize1() const { return !outEmpty() && !outBeginp()->outNextp(); }
|
||||
|
||||
V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, const V3GraphVertex* waywardp) {
|
||||
template <GraphWay::en T_Way>
|
||||
V3GraphEdge* V3GraphVertex::findConnectingEdgep(V3GraphVertex* waywardp) {
|
||||
// O(edges) linear search. Searches search both nodes' edge lists in
|
||||
// parallel. The lists probably aren't _both_ huge, so this is
|
||||
// unlikely to blow up even on fairly nasty graphs.
|
||||
const GraphWay inv = way.invert();
|
||||
V3GraphEdge* aedgep = this->beginp(way);
|
||||
V3GraphEdge* bedgep = waywardp->beginp(inv);
|
||||
while (aedgep && bedgep) {
|
||||
if (aedgep->furtherp(way) == waywardp) return aedgep;
|
||||
if (bedgep->furtherp(inv) == this) return bedgep;
|
||||
aedgep = aedgep->nextp(way);
|
||||
bedgep = bedgep->nextp(inv);
|
||||
constexpr GraphWay way{T_Way};
|
||||
constexpr GraphWay inv = way.invert();
|
||||
auto& aEdges = this->edges<way>();
|
||||
auto aIt = aEdges.begin();
|
||||
auto aEnd = aEdges.end();
|
||||
auto& bEdges = waywardp->edges<inv>();
|
||||
auto bIt = bEdges.begin();
|
||||
auto bEnd = bEdges.end();
|
||||
while (aIt != aEnd && bIt != bEnd) {
|
||||
V3GraphEdge& aedge = *aIt++;
|
||||
if (aedge.furtherp<way>() == waywardp) return &aedge;
|
||||
V3GraphEdge& bedge = *bIt++;
|
||||
if (bedge.furtherp<inv>() == this) return &bedge;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template V3GraphEdge* V3GraphVertex::findConnectingEdgep<GraphWay::FORWARD>(V3GraphVertex*);
|
||||
template V3GraphEdge* V3GraphVertex::findConnectingEdgep<GraphWay::REVERSE>(V3GraphVertex*);
|
||||
|
||||
// cppcheck-has-bug-suppress constParameter
|
||||
void V3GraphVertex::v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) {
|
||||
std::ostringstream nsstr;
|
||||
@@ -153,43 +147,36 @@ void V3GraphEdge::init(V3Graph* /*graphp*/, V3GraphVertex* fromp, V3GraphVertex*
|
||||
m_cutable = cutable;
|
||||
m_userp = nullptr;
|
||||
// Link vertices to this edge
|
||||
outPushBack();
|
||||
inPushBack();
|
||||
m_fromp->outEdges().linkBack(this);
|
||||
m_top->inEdges().linkBack(this);
|
||||
}
|
||||
|
||||
V3GraphEdge* V3GraphEdge::relinkFromp(V3GraphVertex* newFromp) {
|
||||
V3GraphEdge* oldNxt = outNextp();
|
||||
m_outs.unlink(m_fromp->m_outs, this);
|
||||
void V3GraphEdge::relinkFromp(V3GraphVertex* newFromp) {
|
||||
m_fromp->outEdges().unlink(this);
|
||||
m_fromp = newFromp;
|
||||
outPushBack();
|
||||
return oldNxt;
|
||||
m_fromp->outEdges().linkBack(this);
|
||||
}
|
||||
|
||||
V3GraphEdge* V3GraphEdge::relinkTop(V3GraphVertex* newTop) {
|
||||
V3GraphEdge* oldNxt = inNextp();
|
||||
m_ins.unlink(m_top->m_ins, this);
|
||||
void V3GraphEdge::relinkTop(V3GraphVertex* newTop) {
|
||||
m_top->inEdges().unlink(this);
|
||||
m_top = newTop;
|
||||
inPushBack();
|
||||
return oldNxt;
|
||||
m_top->inEdges().linkBack(this);
|
||||
}
|
||||
|
||||
void V3GraphEdge::unlinkDelete() {
|
||||
// Unlink from side
|
||||
m_outs.unlink(m_fromp->m_outs, this);
|
||||
m_fromp->outEdges().unlink(this);
|
||||
// Unlink to side
|
||||
m_ins.unlink(m_top->m_ins, this);
|
||||
m_top->inEdges().unlink(this);
|
||||
// Delete
|
||||
delete this; // this=nullptr;
|
||||
delete this;
|
||||
}
|
||||
|
||||
void V3GraphEdge::outPushBack() {
|
||||
// m_fromp->m_outsp.push_back(this);
|
||||
m_outs.pushBack(m_fromp->m_outs, this);
|
||||
}
|
||||
std::string V3GraphEdge::name() const { return m_fromp->name() + "->" + m_top->name(); }
|
||||
|
||||
void V3GraphEdge::inPushBack() {
|
||||
// m_top->m_insp.push_back(this);
|
||||
m_ins.pushBack(m_top->m_ins, this);
|
||||
int V3GraphEdge::sortCmp(const V3GraphEdge* rhsp) const {
|
||||
if (!m_weight || !rhsp->m_weight) return 0;
|
||||
return top()->sortCmp(rhsp->top());
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
@@ -197,61 +184,50 @@ void V3GraphEdge::inPushBack() {
|
||||
// Graph top level
|
||||
// Constructors
|
||||
|
||||
V3Graph::V3Graph() {
|
||||
// Anything here is probably needed in clear() also
|
||||
verticesUnlink();
|
||||
}
|
||||
V3Graph::V3Graph() {}
|
||||
|
||||
V3Graph::~V3Graph() { clear(); }
|
||||
|
||||
void V3Graph::clear() {
|
||||
// Empty it of all points, as if making a new object
|
||||
// Delete the old edges
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; /*BELOW*/) {
|
||||
V3GraphEdge* nextp = edgep->outNextp();
|
||||
for (V3GraphVertex& vertex : vertices()) {
|
||||
while (V3GraphEdge* const edgep = vertex.outEdges().unlinkFront()) {
|
||||
VL_DO_DANGLING(delete edgep, edgep);
|
||||
edgep = nextp;
|
||||
}
|
||||
vertexp->outUnlink();
|
||||
}
|
||||
// Delete the old vertices
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; /*BELOW*/) {
|
||||
V3GraphVertex* nextp = vertexp->verticesNextp();
|
||||
while (V3GraphVertex* const vertexp = vertices().unlinkFront()) {
|
||||
VL_DO_DANGLING(delete vertexp, vertexp);
|
||||
vertexp = nextp;
|
||||
}
|
||||
verticesUnlink();
|
||||
}
|
||||
|
||||
void V3Graph::userClearVertices() {
|
||||
// Clear user() in all of tree
|
||||
// We may use the userCnt trick in V3Ast later... (but gblCnt would be
|
||||
// in V3Graph instead of static - which has the complication of finding
|
||||
// the graph pointer given a vertex.) For now we don't call this often, and
|
||||
// the graph pointer given a vertex.) For now, we don't call this often, and
|
||||
// the extra code on each read of user() would probably slow things
|
||||
// down more than help.
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
vertexp->user(0);
|
||||
vertexp->userp(nullptr); // Its a union, but might be different size than user()
|
||||
for (V3GraphVertex& vertex : vertices()) {
|
||||
vertex.user(0);
|
||||
vertex.userp(nullptr); // It's a union, but might be different size than user()
|
||||
}
|
||||
}
|
||||
|
||||
void V3Graph::userClearEdges() {
|
||||
// Clear user() in all of tree
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
edgep->user(0);
|
||||
edgep->userp(nullptr); // Its a union, but might be different size than user()
|
||||
for (V3GraphVertex& vertex : vertices()) {
|
||||
for (V3GraphEdge& edge : vertex.outEdges()) {
|
||||
edge.user(0);
|
||||
edge.userp(nullptr); // It's a union, but might be different size than user()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void V3Graph::clearColors() {
|
||||
// Reset colors
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
vertexp->m_color = 0;
|
||||
}
|
||||
for (V3GraphVertex& vertex : vertices()) vertex.color(0);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
@@ -270,35 +246,29 @@ void V3Graph::dump(std::ostream& os) const {
|
||||
// This generates a file used by graphviz, https://www.graphviz.org
|
||||
os << " Graph:\n";
|
||||
// Print vertices
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
os << "\tNode: " << vertexp->name();
|
||||
if (vertexp->color()) os << " color=" << vertexp->color();
|
||||
for (const V3GraphVertex& vertex : vertices()) {
|
||||
os << "\tNode: " << vertex.name();
|
||||
if (vertex.color()) os << " color=" << vertex.color();
|
||||
os << '\n';
|
||||
// Print edges
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
dumpEdge(os, vertexp, edgep);
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
dumpEdge(os, vertexp, edgep);
|
||||
}
|
||||
for (const V3GraphEdge& edge : vertex.inEdges()) dumpEdge(os, vertex, edge);
|
||||
for (const V3GraphEdge& edge : vertex.outEdges()) dumpEdge(os, vertex, edge);
|
||||
}
|
||||
}
|
||||
|
||||
void V3Graph::dumpEdge(std::ostream& os, const V3GraphVertex* vertexp,
|
||||
const V3GraphEdge* edgep) const {
|
||||
if (edgep->weight() && (edgep->fromp() == vertexp || edgep->top() == vertexp)) {
|
||||
void V3Graph::dumpEdge(std::ostream& os, const V3GraphVertex& vertex,
|
||||
const V3GraphEdge& edge) const {
|
||||
if (edge.weight() && (edge.fromp() == &vertex || edge.top() == &vertex)) {
|
||||
os << "\t\t";
|
||||
if (edgep->fromp() == vertexp) os << "-> " << edgep->top()->name();
|
||||
if (edgep->top() == vertexp) os << "<- " << edgep->fromp()->name();
|
||||
if (edgep->cutable()) os << " [CUTABLE]";
|
||||
if (edge.fromp() == &vertex) os << "-> " << edge.top()->name();
|
||||
if (edge.top() == &vertex) os << "<- " << edge.fromp()->name();
|
||||
if (edge.cutable()) os << " [CUTABLE]";
|
||||
os << '\n';
|
||||
}
|
||||
}
|
||||
void V3Graph::dumpEdges(std::ostream& os, const V3GraphVertex* vertexp) const {
|
||||
for (const V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp())
|
||||
dumpEdge(os, vertexp, edgep);
|
||||
for (const V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp())
|
||||
dumpEdge(os, vertexp, edgep);
|
||||
void V3Graph::dumpEdges(std::ostream& os, const V3GraphVertex& vertex) const {
|
||||
for (const V3GraphEdge& edge : vertex.inEdges()) dumpEdge(os, vertex, edge);
|
||||
for (const V3GraphEdge& edge : vertex.outEdges()) dumpEdge(os, vertex, edge);
|
||||
}
|
||||
|
||||
void V3Graph::dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph) const {
|
||||
@@ -326,16 +296,16 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
|
||||
// List of all possible subgraphs
|
||||
// Collections of explicit ranks
|
||||
std::unordered_set<std::string> ranks;
|
||||
std::unordered_multimap<std::string, V3GraphVertex*> rankSets;
|
||||
std::multimap<std::string, V3GraphVertex*> subgraphs;
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
std::unordered_multimap<std::string, const V3GraphVertex*> rankSets;
|
||||
std::multimap<std::string, const V3GraphVertex*> subgraphs;
|
||||
for (const V3GraphVertex& vertex : vertices()) {
|
||||
const string vertexSubgraph
|
||||
= (colorAsSubgraph && vertexp->color()) ? cvtToStr(vertexp->color()) : "";
|
||||
subgraphs.emplace(vertexSubgraph, vertexp);
|
||||
const string& dotRank = vertexp->dotRank();
|
||||
= (colorAsSubgraph && vertex.color()) ? cvtToStr(vertex.color()) : "";
|
||||
subgraphs.emplace(vertexSubgraph, &vertex);
|
||||
const string& dotRank = vertex.dotRank();
|
||||
if (!dotRank.empty()) {
|
||||
ranks.emplace(dotRank);
|
||||
rankSets.emplace(dotRank, vertexp);
|
||||
rankSets.emplace(dotRank, &vertex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,20 +343,20 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
|
||||
if (subgr != "") *logp << "\t};\n";
|
||||
|
||||
// Print edges
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (edgep->weight()) {
|
||||
const int fromVnum = numMap[edgep->fromp()];
|
||||
const int toVnum = numMap[edgep->top()];
|
||||
*logp << "\tn" << edgep->fromp()->dotName() << fromVnum << " -> n"
|
||||
<< edgep->top()->dotName() << toVnum
|
||||
for (const V3GraphVertex& vertex : vertices()) {
|
||||
for (const V3GraphEdge& edge : vertex.outEdges()) {
|
||||
if (edge.weight()) {
|
||||
const int fromVnum = numMap[edge.fromp()];
|
||||
const int toVnum = numMap[edge.top()];
|
||||
*logp << "\tn" << edge.fromp()->dotName() << fromVnum << " -> n"
|
||||
<< edge.top()->dotName() << toVnum
|
||||
<< " ["
|
||||
// <<"fontsize=8 label=\""<<(edgep->name()!="" ? edgep->name() : "\\E")<<"\""
|
||||
<< "fontsize=8 label=\""
|
||||
<< (edgep->dotLabel() != "" ? edgep->dotLabel() : "") << "\""
|
||||
<< " weight=" << edgep->weight() << " color=" << edgep->dotColor();
|
||||
if (edgep->dotStyle() != "") *logp << " style=" << edgep->dotStyle();
|
||||
// if (edgep->cutable()) *logp << ",constraint=false"; // to rank without
|
||||
// <<"fontsize=8 label=\""<<(edge.name()!="" ? edge.name() : "\\E")<<"\""
|
||||
<< "fontsize=8 label=\"" << (edge.dotLabel() != "" ? edge.dotLabel() : "")
|
||||
<< "\""
|
||||
<< " weight=" << edge.weight() << " color=" << edge.dotColor();
|
||||
if (edge.dotStyle() != "") *logp << " style=" << edge.dotStyle();
|
||||
// if (edge.cutable()) *logp << ",constraint=false"; // to rank without
|
||||
// following edges
|
||||
*logp << "];\n";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user