Speed up Verilator itself by prefetching pointer-chase

This commit is contained in:
Wilson Snyder 2008-11-22 14:59:22 -05:00
parent 8b77379e2c
commit c595d67311
3 changed files with 46 additions and 26 deletions

View File

@ -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);

View File

@ -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

View File

@ -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