mirror of
https://github.com/verilator/verilator.git
synced 2025-05-02 05:26:53 +00:00
Internals: Make const iterator to fix missed-edits on dump. Merge from bug683 branch.
This commit is contained in:
parent
446b0e4e5e
commit
ed39c66715
@ -239,6 +239,9 @@ inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next)
|
|||||||
//if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<": "<<(void*)this<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
|
//if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<": "<<(void*)this<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
|
||||||
//if (debug()) {
|
//if (debug()) {
|
||||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||||
|
// // Commenting out the section below may crash, as the tree state
|
||||||
|
// // between edits is not always consistent for printing
|
||||||
|
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||||
// v3Global.rootp()->dumpTree(cout,"-treeChange: ");
|
// v3Global.rootp()->dumpTree(cout,"-treeChange: ");
|
||||||
// if (next||1) this->dumpTreeAndNext(cout, prefix);
|
// if (next||1) this->dumpTreeAndNext(cout, prefix);
|
||||||
// else this->dumpTree(cout, prefix);
|
// else this->dumpTree(cout, prefix);
|
||||||
@ -561,7 +564,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
|
|||||||
if (linkerp->m_iterpp) {
|
if (linkerp->m_iterpp) {
|
||||||
// If we're iterating over a next() link, we need to follow links off the
|
// If we're iterating over a next() link, we need to follow links off the
|
||||||
// NEW node. Thus we pass iteration information via a pointer in the node.
|
// NEW node. Thus we pass iteration information via a pointer in the node.
|
||||||
// This adds a unfortunate 4 bytes to every AstNode, but is faster than passing
|
// This adds a unfortunate hot 8 bytes to every AstNode, but is faster than passing
|
||||||
// across every function.
|
// across every function.
|
||||||
// If anyone has a cleaner way, I'd be grateful.
|
// If anyone has a cleaner way, I'd be grateful.
|
||||||
*(linkerp->m_iterpp) = newp;
|
*(linkerp->m_iterpp) = newp;
|
||||||
@ -750,6 +753,20 @@ void AstNode::iterateChildren(AstNVisitor& v, AstNUser* vup) {
|
|||||||
if (m_op4p) m_op4p->iterateAndNext(v, vup);
|
if (m_op4p) m_op4p->iterateAndNext(v, vup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AstNode::iterateChildrenConst(AstNVisitor& v, AstNUser* vup) {
|
||||||
|
// This is a very hot function
|
||||||
|
if (!this) return;
|
||||||
|
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->iterateAndNextConst(v, vup);
|
||||||
|
if (m_op2p) m_op2p->iterateAndNextConst(v, vup);
|
||||||
|
if (m_op3p) m_op3p->iterateAndNextConst(v, vup);
|
||||||
|
if (m_op4p) m_op4p->iterateAndNextConst(v, vup);
|
||||||
|
}
|
||||||
|
|
||||||
void AstNode::iterateAndNext(AstNVisitor& v, AstNUser* vup) {
|
void AstNode::iterateAndNext(AstNVisitor& v, AstNUser* vup) {
|
||||||
// This is a very hot function
|
// This is a very hot function
|
||||||
// IMPORTANT: If you replace a node that's the target of this iterator,
|
// IMPORTANT: If you replace a node that's the target of this iterator,
|
||||||
@ -764,16 +781,18 @@ void AstNode::iterateAndNext(AstNVisitor& v, AstNUser* vup) {
|
|||||||
while (nodep) {
|
while (nodep) {
|
||||||
AstNode* niterp = nodep; // This address may get stomped via m_iterpp if the node is edited
|
AstNode* niterp = nodep; // This address may get stomped via m_iterpp if the node is edited
|
||||||
ASTNODE_PREFETCH(nodep->m_nextp);
|
ASTNODE_PREFETCH(nodep->m_nextp);
|
||||||
|
// Desirable check, but many places where multiple iterations are OK
|
||||||
|
//if (VL_UNLIKELY(niterp->m_iterpp)) niterp->v3fatalSrc("IterateAndNext under iterateAndNext may miss edits");
|
||||||
// cppcheck-suppress nullPointer
|
// cppcheck-suppress nullPointer
|
||||||
niterp->m_iterpp = &niterp;
|
niterp->m_iterpp = &niterp;
|
||||||
niterp->accept(v, vup);
|
niterp->accept(v, vup);
|
||||||
// accept may do a replaceNode and change niterp on us...
|
// accept may do a replaceNode and change niterp on us...
|
||||||
//if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<(void*)nodep<<" now into "<<(void*)niterp<<endl); // niterp maybe NULL, so need cast
|
//if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<(void*)nodep<<" now into "<<(void*)niterp<<endl); // niterp maybe NULL, so need cast
|
||||||
if (!niterp) return;
|
if (!niterp) return; // Perhaps node deleted inside accept
|
||||||
niterp->m_iterpp = NULL;
|
niterp->m_iterpp = NULL;
|
||||||
if (VL_UNLIKELY(niterp!=nodep)) { // Edited it
|
if (VL_UNLIKELY(niterp!=nodep)) { // Edited node inside accept
|
||||||
nodep = niterp;
|
nodep = niterp;
|
||||||
} else { // Same node, just loop
|
} else { // Unchanged node, just continue loop
|
||||||
nodep = niterp->m_nextp;
|
nodep = niterp->m_nextp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -799,11 +818,12 @@ void AstNode::iterateChildrenBackwards(AstNVisitor& v, AstNUser* vup) {
|
|||||||
this->op4p()->iterateListBackwards(v,vup);
|
this->op4p()->iterateListBackwards(v,vup);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::iterateAndNextIgnoreEdit(AstNVisitor& v, AstNUser* vup) {
|
void AstNode::iterateAndNextConst(AstNVisitor& v, AstNUser* vup) {
|
||||||
// Keep following the current list even if edits change it
|
// Keep following the current list even if edits change it
|
||||||
if (!this) return;
|
if (!this) return;
|
||||||
for (AstNode* nodep=this; nodep; ) {
|
for (AstNode* nodep=this; nodep; ) {
|
||||||
AstNode* nnextp = nodep->m_nextp;
|
AstNode* nnextp = nodep->m_nextp;
|
||||||
|
ASTNODE_PREFETCH(nnextp);
|
||||||
nodep->accept(v, vup);
|
nodep->accept(v, vup);
|
||||||
nodep = nnextp;
|
nodep = nnextp;
|
||||||
}
|
}
|
||||||
|
@ -1186,9 +1186,11 @@ public:
|
|||||||
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) = 0;
|
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) = 0;
|
||||||
void iterate(AstNVisitor& v, AstNUser* vup=NULL) { this->accept(v,vup); } // Does this; excludes following this->next
|
void iterate(AstNVisitor& v, AstNUser* vup=NULL) { this->accept(v,vup); } // Does this; excludes following this->next
|
||||||
void iterateAndNext(AstNVisitor& v, AstNUser* vup=NULL);
|
void iterateAndNext(AstNVisitor& v, AstNUser* vup=NULL);
|
||||||
void iterateAndNextIgnoreEdit(AstNVisitor& v, AstNUser* vup=NULL);
|
void iterateAndNextConst(AstNVisitor& v, AstNUser* vup=NULL);
|
||||||
|
void iterateAndNextIgnoreEdit(AstNVisitor& v, AstNUser* vup=NULL) { iterateAndNextConst(v, vup); }
|
||||||
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL); // Excludes following this->next
|
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL); // Excludes following this->next
|
||||||
void iterateChildrenBackwards(AstNVisitor& v, AstNUser* vup=NULL); // Excludes following this->next
|
void iterateChildrenBackwards(AstNVisitor& v, AstNUser* vup=NULL); // Excludes following this->next
|
||||||
|
void iterateChildrenConst(AstNVisitor& v, AstNUser* vup=NULL); // Excludes following this->next
|
||||||
AstNode* acceptSubtreeReturnEdits(AstNVisitor& v, AstNUser* vup=NULL); // Return edited nodep; see comments in V3Ast.cpp
|
AstNode* acceptSubtreeReturnEdits(AstNVisitor& v, AstNUser* vup=NULL); // Return edited nodep; see comments in V3Ast.cpp
|
||||||
|
|
||||||
// CONVERSION
|
// CONVERSION
|
||||||
|
33
src/V3AstConstOnly.h
Normal file
33
src/V3AstConstOnly.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//*************************************************************************
|
||||||
|
// DESCRIPTION: Verilator: Ast node structure
|
||||||
|
//
|
||||||
|
// Code available from: http://www.veripool.org/verilator
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2014 by Wilson Snyder. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// Verilator is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#ifndef _V3ASTCONSTONLY_H_
|
||||||
|
#define _V3ASTCONSTONLY_H_ 1
|
||||||
|
|
||||||
|
// Include only in visitors that do not not edit nodes, so should use constant iterators
|
||||||
|
#define iterateAndNext error_use_iterateAndNextConst
|
||||||
|
#define iterateChildren error_use_iterateChildrenConst
|
||||||
|
|
||||||
|
#define addNext error_no_addNext_in_ConstOnlyVisitor
|
||||||
|
#define replaceWith error_no_replaceWith_in_ConstOnlyVisitor
|
||||||
|
#define deleteTree error_no_deleteTree_in_ConstOnlyVisitor
|
||||||
|
#define unlinkFrBack error_no_unlinkFrBack_in_ConstOnlyVisitor
|
||||||
|
|
||||||
|
#endif // Guard
|
@ -37,6 +37,9 @@
|
|||||||
#include "V3Broken.h"
|
#include "V3Broken.h"
|
||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
|
|
||||||
|
// This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
|
||||||
|
#include "V3AstConstOnly.h"
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
class BrokenTable : public AstNVisitor {
|
class BrokenTable : public AstNVisitor {
|
||||||
@ -185,7 +188,7 @@ private:
|
|||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
BrokenTable::addInTree(nodep, nodep->maybePointedTo());
|
BrokenTable::addInTree(nodep, nodep->maybePointedTo());
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildrenConst(*this);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
// CONSTUCTORS
|
// CONSTUCTORS
|
||||||
@ -228,7 +231,7 @@ private:
|
|||||||
nodep->v3fatalSrc("Width != WidthMin");
|
nodep->v3fatalSrc("Width != WidthMin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildrenConst(*this);
|
||||||
BrokenTable::setUnder(nodep,false);
|
BrokenTable::setUnder(nodep,false);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
#include "V3File.h"
|
#include "V3File.h"
|
||||||
|
|
||||||
|
// This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
|
||||||
|
#include "V3AstConstOnly.h"
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Stats class functions
|
// Stats class functions
|
||||||
|
|
||||||
@ -74,14 +77,14 @@ private:
|
|||||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||||
allNodes(nodep);
|
allNodes(nodep);
|
||||||
if (!m_fast) {
|
if (!m_fast) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildrenConst(*this);
|
||||||
} else {
|
} else {
|
||||||
for (AstNode* searchp = nodep->stmtsp(); searchp; searchp=searchp->nextp()) {
|
for (AstNode* searchp = nodep->stmtsp(); searchp; searchp=searchp->nextp()) {
|
||||||
if (AstCFunc* funcp = searchp->castCFunc()) {
|
if (AstCFunc* funcp = searchp->castCFunc()) {
|
||||||
if (funcp->name() == "_eval") {
|
if (funcp->name() == "_eval") {
|
||||||
m_instrs=0;
|
m_instrs=0;
|
||||||
m_counting = true;
|
m_counting = true;
|
||||||
funcp->iterateChildren(*this);
|
funcp->iterateChildrenConst(*this);
|
||||||
m_counting = false;
|
m_counting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,7 +93,7 @@ private:
|
|||||||
}
|
}
|
||||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||||
allNodes(nodep);
|
allNodes(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildrenConst(*this);
|
||||||
if (m_counting && nodep->dtypep()) {
|
if (m_counting && nodep->dtypep()) {
|
||||||
if (nodep->isUsedClock()) ++m_statVarClock;
|
if (nodep->isUsedClock()) ++m_statVarClock;
|
||||||
if (nodep->dtypeSkipRefp()->castUnpackArrayDType()) ++m_statVarArray;
|
if (nodep->dtypeSkipRefp()->castUnpackArrayDType()) ++m_statVarArray;
|
||||||
@ -103,7 +106,7 @@ private:
|
|||||||
}
|
}
|
||||||
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
||||||
allNodes(nodep);
|
allNodes(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildrenConst(*this);
|
||||||
if (m_counting) {
|
if (m_counting) {
|
||||||
if (nodep->varp()->dtypeSkipRefp()->castBasicDType()) {
|
if (nodep->varp()->dtypeSkipRefp()->castBasicDType()) {
|
||||||
m_statVarScpBytes += nodep->varp()->dtypeSkipRefp()->widthTotalBytes();
|
m_statVarScpBytes += nodep->varp()->dtypeSkipRefp()->widthTotalBytes();
|
||||||
@ -114,13 +117,13 @@ private:
|
|||||||
UINFO(4," IF "<<nodep<<endl);
|
UINFO(4," IF "<<nodep<<endl);
|
||||||
allNodes(nodep);
|
allNodes(nodep);
|
||||||
// Condition is part of PREVIOUS block
|
// Condition is part of PREVIOUS block
|
||||||
nodep->condp()->iterateAndNext(*this);
|
nodep->condp()->iterateAndNextConst(*this);
|
||||||
// Track prediction
|
// Track prediction
|
||||||
if (m_counting) {
|
if (m_counting) {
|
||||||
++m_statPred[nodep->branchPred()];
|
++m_statPred[nodep->branchPred()];
|
||||||
}
|
}
|
||||||
if (!m_fast) {
|
if (!m_fast) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildrenConst(*this);
|
||||||
} else {
|
} else {
|
||||||
// See which path we want to take
|
// See which path we want to take
|
||||||
bool takeElse = false;
|
bool takeElse = false;
|
||||||
@ -135,11 +138,11 @@ private:
|
|||||||
m_counting = false;
|
m_counting = false;
|
||||||
// Check if
|
// Check if
|
||||||
m_instrs = 0;
|
m_instrs = 0;
|
||||||
nodep->ifsp()->iterateAndNext(*this);
|
nodep->ifsp()->iterateAndNextConst(*this);
|
||||||
double instrIf = m_instrs;
|
double instrIf = m_instrs;
|
||||||
// Check else
|
// Check else
|
||||||
m_instrs = 0;
|
m_instrs = 0;
|
||||||
nodep->elsesp()->iterateAndNext(*this);
|
nodep->elsesp()->iterateAndNextConst(*this);
|
||||||
double instrElse = m_instrs;
|
double instrElse = m_instrs;
|
||||||
// Max of if or else condition
|
// Max of if or else condition
|
||||||
takeElse = (instrElse > instrIf);
|
takeElse = (instrElse > instrIf);
|
||||||
@ -150,9 +153,9 @@ private:
|
|||||||
// Count the block
|
// Count the block
|
||||||
if (m_counting) {
|
if (m_counting) {
|
||||||
if (takeElse) {
|
if (takeElse) {
|
||||||
nodep->elsesp()->iterateAndNext(*this);
|
nodep->elsesp()->iterateAndNextConst(*this);
|
||||||
} else {
|
} else {
|
||||||
nodep->ifsp()->iterateAndNext(*this);
|
nodep->ifsp()->iterateAndNextConst(*this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,7 +166,7 @@ private:
|
|||||||
virtual void visit(AstCCall* nodep, AstNUser*) {
|
virtual void visit(AstCCall* nodep, AstNUser*) {
|
||||||
//UINFO(4," CCALL "<<nodep<<endl);
|
//UINFO(4," CCALL "<<nodep<<endl);
|
||||||
allNodes(nodep);
|
allNodes(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildrenConst(*this);
|
||||||
if (m_fast) {
|
if (m_fast) {
|
||||||
// Enter the function and trace it
|
// Enter the function and trace it
|
||||||
nodep->funcp()->accept(*this);
|
nodep->funcp()->accept(*this);
|
||||||
@ -172,12 +175,12 @@ private:
|
|||||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||||
m_cfuncp = nodep;
|
m_cfuncp = nodep;
|
||||||
allNodes(nodep);
|
allNodes(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildrenConst(*this);
|
||||||
m_cfuncp = NULL;
|
m_cfuncp = NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
allNodes(nodep);
|
allNodes(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildrenConst(*this);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
|
Loading…
Reference in New Issue
Block a user