forked from github/verilator
Speed up Verilator itself by prefetching pointer-chase
This commit is contained in:
parent
8b77379e2c
commit
c595d67311
@ -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);
|
||||
|
11
src/V3Ast.h
11
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
|
||||
|
@ -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 "<<vvertexp->varScp()<<endl);
|
||||
UINFO(4, "No drivers "<<vvertexp->varScp()<<endl);
|
||||
if (0) {
|
||||
// If we warned here after constant propagation, what the user considered
|
||||
// reasonable logic may have disappeared. Issuing a warning would
|
||||
|
Loading…
Reference in New Issue
Block a user