diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 159ec6ab3..3626bd9f9 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -680,11 +680,38 @@ void AstNode::operator delete(void* objp, size_t size) { // Iterators void AstNode::iterateChildren(AstNVisitor& v, AstNUser* vup) { + // This is a very hot function if (!this) return; - m_op1p->iterateAndNext(v, vup); - m_op2p->iterateAndNext(v, vup); - m_op3p->iterateAndNext(v, vup); - m_op4p->iterateAndNext(v, vup); + ASTNODE_PREFETCH(m_op1p); + ASTNODE_PREFETCH(m_op2p); + ASTNODE_PREFETCH(m_op3p); + ASTNODE_PREFETCH(m_op4p); + // if () not needed since iterateAndNext accepts null this, but faster with it. + if (m_op1p) m_op1p->iterateAndNext(v, vup); + if (m_op2p) m_op2p->iterateAndNext(v, vup); + if (m_op3p) m_op3p->iterateAndNext(v, vup); + if (m_op4p) m_op4p->iterateAndNext(v, vup); +} + +void AstNode::iterateAndNext(AstNVisitor& v, AstNUser* vup) { + // This is a very hot function + // IMPORTANT: If you replace a node that's the target of this iterator, + // then the NEW node will be iterated on next, it isn't skipped! + // if (!this) return; // Part of for() + for (AstNode* nodep=this; nodep;) { + AstNode* niterp = nodep; + ASTNODE_PREFETCH(nodep->m_nextp); + niterp->m_iterpp = &niterp; + niterp->accept(v, vup); + // accept may do a replaceNode and change niterp on us... + if (!niterp) return; + niterp->m_iterpp = NULL; + if (niterp!=nodep) { // Edited it + nodep = niterp; + } else { // Same node, just loop + nodep = niterp->m_nextp; + } + } } void AstNode::iterateListBackwards(AstNVisitor& v, AstNUser* vup) { @@ -707,25 +734,6 @@ void AstNode::iterateChildrenBackwards(AstNVisitor& v, AstNUser* vup) { this->op4p()->iterateListBackwards(v,vup); } -void AstNode::iterateAndNext(AstNVisitor& v, AstNUser* vup) { - // IMPORTANT: If you replace a node that's the target of this iterator, - // then the NEW node will be iterated on next, it isn't skipped! - // if (!this) return; // Part of for() - for (AstNode* nodep=this; nodep;) { - AstNode* niterp = nodep; - niterp->m_iterpp = &niterp; - niterp->accept(v, vup); - // accept may do a replaceNode and change niterp on us... - if (!niterp) return; - niterp->m_iterpp = NULL; - if (niterp!=nodep) { // Edited it - nodep = niterp; - } else { // Same node, just loop - nodep = niterp->m_nextp; - } - } -} - void AstNode::iterateAndNextIgnoreEdit(AstNVisitor& v, AstNUser* vup) { // Keep following the current list even if edits change it if (!this) return; @@ -796,6 +804,11 @@ void AstNode::checkTreeIter(AstNode* backp) { if (backp != this->backp()) { this->v3fatalSrc("Back node inconsistent"); } + if (castNodeTermop()) { + // Termops have a short-circuited iterateChildren, so check usage + if (op1p()||op2p()||op3p()||op4p()) + this->v3fatalSrc("Terminal operation with non-terminals"); + } if (op1p()) op1p()->checkTreeIterList(this); if (op2p()) op2p()->checkTreeIterList(this); if (op3p()) op3p()->checkTreeIterList(this); diff --git a/src/V3Ast.h b/src/V3Ast.h index e4533aa00..1a5553753 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -541,16 +541,23 @@ ostream& operator<<(ostream& os, V3Hash rhs); //###################################################################### // AstNode -- Base type of all Ast types +// Prefetch a node. +// The if() makes it faster, even though prefetch won't fault on null pointers +#define ASTNODE_PREFETCH(nodep) \ + { if (nodep) { VL_PREFETCH_RD(&(nodep->m_nextp)); VL_PREFETCH_RD(&(nodep->m_iterpp)); }} + class AstNode { -private: + // v ASTNODE_PREFETCH depends on below ordering of members AstNode* m_nextp; // Next peer in the parent's list AstNode* m_backp; // Node that points to this one (via next/op1/op2/...) - AstNode* m_headtailp; // When at begin/end of list, the opposite end of the list AstNode* m_op1p; // Generic pointer 1 AstNode* m_op2p; // Generic pointer 2 AstNode* m_op3p; // Generic pointer 3 AstNode* m_op4p; // Generic pointer 4 AstNode** m_iterpp; // Pointer to node iterating on, change it if we replace this node. + // ^ ASTNODE_PREFETCH depends on above ordering of members + + AstNode* m_headtailp; // When at begin/end of list, the opposite end of the list AstNode* m_clonep; // Pointer to clone of/ source of this module (for *LAST* cloneTree() ONLY) int m_cloneCnt; // Mark of when userp was set diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index f2f37116b..cd13d8e5a 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -421,7 +421,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) { if (!vvertexp->isTop() // Ok if top inputs are driverless && !vvertexp->varScp()->varp()->initp() && !vvertexp->varScp()->varp()->isSigPublic()) { - UINFO(1, "No drivers "<varScp()<varScp()<