clang-format remaining sources. No functional change.

This commit is contained in:
Wilson Snyder 2020-04-15 07:58:34 -04:00
parent 1b94e3b0e2
commit f3308d236b
85 changed files with 14640 additions and 13099 deletions

View File

@ -456,6 +456,12 @@ analyzer-include:
-rm -rf examples/*/obj*
scan-build $(MAKE) -k examples
CLANGFORMAT = clang-format
CLANGFORMAT_FLAGS = -i
clang-format:
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H)
ftp: info
install-msg:

View File

@ -1,236 +0,0 @@
#!/bin/bash
#
# clang-format is used to standardize the indentation of the internal C++
# code.
#
# For the most part clang-format changes provide good consistency, the two
# main exceptions being the indentation of preprocessor directives, and
# tables of statements. Reformatting is generally performed only before
# other large changes are to be made to a file.
#
# "##" files commented out below are not yet clang-format clean.
# "#" files commented out hit a clang-format limitation with ifdefs.
clang-format -i examples/make_hello_c/sim_main.cpp
clang-format -i examples/make_hello_sc/sc_main.cpp
#clang-format -i examples/make_protect_lib/sim_main.cpp
clang-format -i examples/make_tracing_c/sim_main.cpp
clang-format -i examples/make_tracing_sc/sc_main.cpp
clang-format -i include/*.cpp
clang-format -i include/*.h
clang-format -i include/verilated_config.h.in
clang-format -i nodist/fuzzer/wrapper.cpp
clang-format -i src/V3Active.cpp
clang-format -i src/V3Active.h
clang-format -i src/V3ActiveTop.cpp
clang-format -i src/V3ActiveTop.h
clang-format -i src/V3Assert.cpp
clang-format -i src/V3Assert.h
clang-format -i src/V3AssertPre.cpp
clang-format -i src/V3AssertPre.h
##clang-format -i src/V3Ast.cpp
##clang-format -i src/V3Ast.h
clang-format -i src/V3AstConstOnly.h
##clang-format -i src/V3AstNodes.cpp
##clang-format -i src/V3AstNodes.h
##clang-format -i src/V3Begin.cpp
clang-format -i src/V3Begin.h
clang-format -i src/V3Branch.cpp
clang-format -i src/V3Branch.h
##clang-format -i src/V3Broken.cpp
clang-format -i src/V3Broken.h
##clang-format -i src/V3CCtors.cpp
clang-format -i src/V3CCtors.h
clang-format -i src/V3CUse.cpp
clang-format -i src/V3CUse.h
##clang-format -i src/V3Case.cpp
clang-format -i src/V3Case.h
##clang-format -i src/V3Cast.cpp
clang-format -i src/V3Cast.h
##clang-format -i src/V3Cdc.cpp
clang-format -i src/V3Cdc.h
##clang-format -i src/V3Changed.cpp
clang-format -i src/V3Changed.h
clang-format -i src/V3Class.cpp
clang-format -i src/V3Class.h
##clang-format -i src/V3Clean.cpp
clang-format -i src/V3Clean.h
##clang-format -i src/V3Clock.cpp
clang-format -i src/V3Clock.h
##clang-format -i src/V3Combine.cpp
clang-format -i src/V3Combine.h
clang-format -i src/V3Config.cpp
clang-format -i src/V3Config.h
##clang-format -i src/V3Const.cpp
clang-format -i src/V3Const.h
clang-format -i src/V3Coverage.cpp
clang-format -i src/V3Coverage.h
clang-format -i src/V3CoverageJoin.cpp
clang-format -i src/V3CoverageJoin.h
##clang-format -i src/V3Dead.cpp
clang-format -i src/V3Dead.h
##clang-format -i src/V3Delayed.cpp
clang-format -i src/V3Delayed.h
clang-format -i src/V3Depth.cpp
clang-format -i src/V3Depth.h
clang-format -i src/V3DepthBlock.cpp
clang-format -i src/V3DepthBlock.h
clang-format -i src/V3Descope.cpp
clang-format -i src/V3Descope.h
##clang-format -i src/V3EmitC.cpp
clang-format -i src/V3EmitC.h
##clang-format -i src/V3EmitCBase.h
clang-format -i src/V3EmitCInlines.cpp
##clang-format -i src/V3EmitCMake.cpp
clang-format -i src/V3EmitCMake.h
clang-format -i src/V3EmitCSyms.cpp
##clang-format -i src/V3EmitMk.cpp
clang-format -i src/V3EmitMk.h
##clang-format -i src/V3EmitV.cpp
clang-format -i src/V3EmitV.h
##clang-format -i src/V3EmitXml.cpp
clang-format -i src/V3EmitXml.h
##clang-format -i src/V3Error.cpp
##clang-format -i src/V3Error.h
##clang-format -i src/V3Expand.cpp
clang-format -i src/V3Expand.h
##clang-format -i src/V3File.cpp
##clang-format -i src/V3File.h
##clang-format -i src/V3FileLine.cpp
##clang-format -i src/V3FileLine.h
##clang-format -i src/V3Gate.cpp
clang-format -i src/V3Gate.h
##clang-format -i src/V3GenClk.cpp
clang-format -i src/V3GenClk.h
clang-format -i src/V3Global.cpp
clang-format -i src/V3Global.h
##clang-format -i src/V3Graph.cpp
clang-format -i src/V3Graph.h
##clang-format -i src/V3GraphAcyc.cpp
##clang-format -i src/V3GraphAlg.cpp
clang-format -i src/V3GraphAlg.h
clang-format -i src/V3GraphDfa.cpp
clang-format -i src/V3GraphDfa.h
clang-format -i src/V3GraphPathChecker.cpp
clang-format -i src/V3GraphPathChecker.h
clang-format -i src/V3GraphStream.h
##clang-format -i src/V3GraphTest.cpp
##clang-format -i src/V3Hashed.cpp
clang-format -i src/V3Hashed.h
##clang-format -i src/V3Inline.cpp
clang-format -i src/V3Inline.h
##clang-format -i src/V3Inst.cpp
clang-format -i src/V3Inst.h
clang-format -i src/V3InstrCount.cpp
clang-format -i src/V3InstrCount.h
clang-format -i src/V3LangCode.h
clang-format -i src/V3LanguageWords.h
##clang-format -i src/V3Life.cpp
clang-format -i src/V3Life.h
##clang-format -i src/V3LifePost.cpp
clang-format -i src/V3LifePost.h
##clang-format -i src/V3LinkCells.cpp
clang-format -i src/V3LinkCells.h
##clang-format -i src/V3LinkDot.cpp
clang-format -i src/V3LinkDot.h
##clang-format -i src/V3LinkJump.cpp
clang-format -i src/V3LinkJump.h
clang-format -i src/V3LinkLValue.cpp
clang-format -i src/V3LinkLValue.h
##clang-format -i src/V3LinkLevel.cpp
clang-format -i src/V3LinkLevel.h
##clang-format -i src/V3LinkParse.cpp
clang-format -i src/V3LinkParse.h
##clang-format -i src/V3LinkResolve.cpp
clang-format -i src/V3LinkResolve.h
clang-format -i src/V3List.h
clang-format -i src/V3Localize.cpp
clang-format -i src/V3Localize.h
clang-format -i src/V3Name.cpp
clang-format -i src/V3Name.h
##clang-format -i src/V3Number.cpp
##clang-format -i src/V3Number.h
clang-format -i src/V3Number_test.cpp
clang-format -i src/V3Options.cpp
clang-format -i src/V3Options.h
##clang-format -i src/V3Order.cpp
clang-format -i src/V3Order.h
clang-format -i src/V3OrderGraph.h
clang-format -i src/V3Os.cpp
clang-format -i src/V3Os.h
##clang-format -i src/V3Param.cpp
clang-format -i src/V3Param.h
clang-format -i src/V3Parse.h
##clang-format -i src/V3ParseGrammar.cpp
##clang-format -i src/V3ParseImp.cpp
##clang-format -i src/V3ParseImp.h
clang-format -i src/V3ParseLex.cpp
clang-format -i src/V3ParseSym.h
##clang-format -i src/V3Partition.cpp
clang-format -i src/V3Partition.h
clang-format -i src/V3PartitionGraph.h
clang-format -i src/V3PreLex.h
##clang-format -i src/V3PreProc.cpp
clang-format -i src/V3PreProc.h
clang-format -i src/V3PreShell.cpp
clang-format -i src/V3PreShell.h
##clang-format -i src/V3Premit.cpp
clang-format -i src/V3Premit.h
##clang-format -i src/V3ProtectLib.cpp
clang-format -i src/V3ProtectLib.h
clang-format -i src/V3Reloop.cpp
clang-format -i src/V3Reloop.h
##clang-format -i src/V3Scope.cpp
clang-format -i src/V3Scope.h
clang-format -i src/V3Scoreboard.cpp
clang-format -i src/V3Scoreboard.h
clang-format -i src/V3SenTree.h
##clang-format -i src/V3Simulate.h
##clang-format -i src/V3Slice.cpp
clang-format -i src/V3Slice.h
##clang-format -i src/V3Split.cpp
clang-format -i src/V3Split.h
##clang-format -i src/V3SplitAs.cpp
clang-format -i src/V3SplitAs.h
##clang-format -i src/V3SplitVar.cpp
clang-format -i src/V3SplitVar.h
clang-format -i src/V3Stats.cpp
clang-format -i src/V3Stats.h
clang-format -i src/V3StatsReport.cpp
clang-format -i src/V3String.cpp
clang-format -i src/V3String.h
##clang-format -i src/V3Subst.cpp
clang-format -i src/V3Subst.h
clang-format -i src/V3SymTable.h
##clang-format -i src/V3TSP.cpp
clang-format -i src/V3TSP.h
##clang-format -i src/V3Table.cpp
clang-format -i src/V3Table.h
##clang-format -i src/V3Task.cpp
clang-format -i src/V3Task.h
clang-format -i src/V3Trace.cpp
clang-format -i src/V3Trace.h
clang-format -i src/V3TraceDecl.cpp
clang-format -i src/V3TraceDecl.h
##clang-format -i src/V3Tristate.cpp
clang-format -i src/V3Tristate.h
##clang-format -i src/V3Undriven.cpp
clang-format -i src/V3Undriven.h
##clang-format -i src/V3Unknown.cpp
clang-format -i src/V3Unknown.h
##clang-format -i src/V3Unroll.cpp
clang-format -i src/V3Unroll.h
##clang-format -i src/V3Width.cpp
clang-format -i src/V3Width.h
clang-format -i src/V3WidthCommit.h
##clang-format -i src/V3WidthSel.cpp
clang-format -i src/Verilator.cpp
clang-format -i src/VlcBucket.h
clang-format -i src/VlcMain.cpp
clang-format -i src/VlcOptions.h
clang-format -i src/VlcPoint.h
clang-format -i src/VlcSource.h
clang-format -i src/VlcTest.h
clang-format -i src/VlcTop.cpp
clang-format -i src/VlcTop.h
clang-format -i src/config_build.h.in

View File

@ -364,7 +364,7 @@ private:
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
// Move always to appropriate ACTIVE based on its sense list
UINFO(4, " ALW " << nodep << endl);
// if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
if (!nodep->bodysp()) {
// Empty always. Kill it.
@ -376,7 +376,7 @@ private:
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
// Move always to appropriate ACTIVE based on its sense list
UINFO(4, " ALWPub " << nodep << endl);
// if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
}
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {

View File

@ -322,7 +322,7 @@ private:
AstNode* assp = new AstAssignDly(nodep->fileline(),
new AstVarRef(nodep->fileline(), outvarp, true), inp);
alwaysp->addStmtp(assp);
// if (debug()>-9) assp->dumpTree(cout, "-ass: ");
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
invarp = outvarp;
inp = new AstVarRef(nodep->fileline(), invarp, false);
}

View File

@ -51,7 +51,6 @@ bool AstUser5InUse::s_userBusy = false;
int AstNodeDType::s_uniqueNum = 0;
//######################################################################
// V3AstType
@ -102,15 +101,16 @@ AstNode* AstNode::abovep() const {
string AstNode::encodeName(const string& namein) {
// Encode signal name raw from parser, then not called again on same signal
string out;
for (string::const_iterator pos = namein.begin(); pos!=namein.end(); ++pos) {
if ((pos==namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers
: isalnum(pos[0])) {
for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) {
if ((pos == namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers
: isalnum(pos[0])) {
out += pos[0];
} else if (pos[0]=='_') {
if (pos[1]=='_') {
out += "_"; out += "__05F"; // hex(_) = 0x5F
} else if (pos[0] == '_') {
if (pos[1] == '_') {
out += "_";
out += "__05F"; // hex(_) = 0x5F
++pos;
if (pos==namein.end()) break;
if (pos == namein.end()) break;
} else {
out += pos[0];
}
@ -120,7 +120,8 @@ string AstNode::encodeName(const string& namein) {
// We also do *NOT* use __DOT__ etc, as we search for those
// in some replacements, and don't want to mangle the user's names.
unsigned val = pos[0] & 0xff; // Mask to avoid sign extension
char hex[10]; sprintf(hex, "__0%02X", val);
char hex[10];
sprintf(hex, "__0%02X", val);
out += hex;
}
}
@ -133,34 +134,26 @@ string AstNode::encodeName(const string& namein) {
string AstNode::encodeNumber(vlsint64_t num) {
if (num < 0) {
return "__02D"+cvtToStr(-num); // 2D=-
return "__02D" + cvtToStr(-num); // 2D=-
} else {
return cvtToStr(num);
}
}
string AstNode::nameProtect() const {
return VIdProtect::protectIf(name(), protect());
}
string AstNode::origNameProtect() const {
return VIdProtect::protectIf(origName(), protect());
}
string AstNode::nameProtect() const { return VIdProtect::protectIf(name(), protect()); }
string AstNode::origNameProtect() const { return VIdProtect::protectIf(origName(), protect()); }
string AstNode::shortName() const {
string pretty = name();
string::size_type pos;
while ((pos = pretty.find("__PVT__")) != string::npos) {
pretty.replace(pos, 7, "");
}
while ((pos = pretty.find("__PVT__")) != string::npos) pretty.replace(pos, 7, "");
return pretty;
}
string AstNode::dedotName(const string& namein) {
string pretty = namein;
string::size_type pos;
while ((pos = pretty.find("__DOT__")) != string::npos) {
pretty.replace(pos, 7, ".");
}
while ((pos = pretty.find("__DOT__")) != string::npos) pretty.replace(pos, 7, ".");
if (pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
return pretty;
}
@ -170,12 +163,8 @@ string AstNode::vcdName(const string& namein) {
// Dots are reserved for dots the user put in the name
string pretty = namein;
string::size_type pos;
while ((pos = pretty.find("__DOT__")) != string::npos) {
pretty.replace(pos, 7, " ");
}
while ((pos = pretty.find('.')) != string::npos) {
pretty.replace(pos, 1, " ");
}
while ((pos = pretty.find("__DOT__")) != string::npos) pretty.replace(pos, 7, " ");
while ((pos = pretty.find('.')) != string::npos) pretty.replace(pos, 1, " ");
// Now convert escaped special characters, etc
return prettyName(pretty);
}
@ -185,38 +174,38 @@ string AstNode::prettyName(const string& namein) {
string pretty;
pretty = "";
pretty.reserve(namein.length());
for (const char* pos = namein.c_str(); *pos; ) {
if (pos[0]=='-' && pos[1]=='>') { // ->
for (const char* pos = namein.c_str(); *pos;) {
if (pos[0] == '-' && pos[1] == '>') { // ->
pretty += ".";
pos += 2;
continue;
}
if (pos[0]=='_' && pos[1]=='_') { // Short-circuit
if (0==strncmp(pos, "__BRA__", 7)) {
if (pos[0] == '_' && pos[1] == '_') { // Short-circuit
if (0 == strncmp(pos, "__BRA__", 7)) {
pretty += "[";
pos += 7;
continue;
}
if (0==strncmp(pos, "__KET__", 7)) {
if (0 == strncmp(pos, "__KET__", 7)) {
pretty += "]";
pos += 7;
continue;
}
if (0==strncmp(pos, "__DOT__", 7)) {
if (0 == strncmp(pos, "__DOT__", 7)) {
pretty += ".";
pos += 7;
continue;
}
if (0==strncmp(pos, "__PVT__", 7)) {
if (0 == strncmp(pos, "__PVT__", 7)) {
pretty += "";
pos += 7;
continue;
}
if (pos[0]=='_' && pos[1]=='_' && pos[2]=='0'
&& isxdigit(pos[3]) && isxdigit(pos[4])) {
if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && isxdigit(pos[3])
&& isxdigit(pos[4])) {
char value = 0;
value += 16*(isdigit(pos[3]) ? (pos[3]-'0') : (tolower(pos[3])-'a'+10));
value += (isdigit(pos[4]) ? (pos[4]-'0') : (tolower(pos[4])-'a'+10));
value += 16 * (isdigit(pos[3]) ? (pos[3] - '0') : (tolower(pos[3]) - 'a' + 10));
value += (isdigit(pos[4]) ? (pos[4] - '0') : (tolower(pos[4]) - 'a' + 10));
pretty += value;
pos += 5;
continue;
@ -226,37 +215,37 @@ string AstNode::prettyName(const string& namein) {
pretty += pos[0];
++pos;
}
if (pretty[0]=='T' && pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
if (pretty[0]=='T' && pretty.substr(0, 5) == "TOP->") pretty.replace(0, 5, "");
if (pretty[0] == 'T' && pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
if (pretty[0] == 'T' && pretty.substr(0, 5) == "TOP->") pretty.replace(0, 5, "");
return pretty;
}
string AstNode::prettyTypeName() const {
if (name()=="") return typeName();
return string(typeName())+" '"+prettyName()+"'";
if (name() == "") return typeName();
return string(typeName()) + " '" + prettyName() + "'";
}
//######################################################################
// Insertion
inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next) {
inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next){
#ifdef VL_DEBUG
// Called on all major tree changers.
// Only for use for those really nasty bugs relating to internals
// Note this may be null.
//if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "
// <<prefix<<": "<<cvtToHex(this)<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
//if (debug()) {
// 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: ");
// if (next||1) this->dumpTreeAndNext(cout, prefix);
// else this->dumpTree(cout, prefix);
// this->checkTree();
// v3Global.rootp()->checkTree();
//}
// Called on all major tree changers.
// Only for use for those really nasty bugs relating to internals
// Note this may be null.
// if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "
// <<prefix<<": "<<cvtToHex(this)<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
// if (debug()) {
// 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: ");
// if (next||1) this->dumpTreeAndNext(cout, prefix);
// else this->dumpTree(cout, prefix);
// this->checkTree();
// v3Global.rootp()->checkTree();
//}
#endif
}
@ -276,8 +265,9 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
UDEBUGONLY(UASSERT_OBJ(!oldtailp->m_nextp, nodep,
"Node had next, but headtail says it shouldn't"););
} else {
// Though inefficient, we are occasionally passed a addNext in the middle of a list.
while (oldtailp->m_nextp != NULL) oldtailp = oldtailp->m_nextp;
// Though inefficient, we are occasionally passed an
// addNext in the middle of a list.
while (oldtailp->m_nextp) oldtailp = oldtailp->m_nextp;
}
}
// Link it in
@ -328,15 +318,15 @@ void AstNode::addNextHere(AstNode* newp) {
AstNode* oldheadtailp = this->m_headtailp;
// (!oldheadtailp) // this was&is middle of list
// (oldheadtailp==this && !oldnext)// this was head AND tail (one node long list)
// (oldheadtailp && oldnextp) // this was&is head of list of not just one node, not tail
// (oldheadtailp && !oldnextp) // this was tail of list, might also
// (oldheadtailp && oldnextp) // this was&is head of list of not just one node, not
// tail (oldheadtailp && !oldnextp) // this was tail of list, might also
// be head of one-node list
//
newp->m_headtailp = NULL; // Not at head any longer
addlastp->m_headtailp = NULL; // Presume middle of list
// newp might happen to be head/tail after all, if so will be set again below
if (oldheadtailp) { // else in middle of list, no change
if (oldheadtailp==this) { // this was one node
if (oldheadtailp == this) { // this was one node
this->m_headtailp = addlastp; // Was head/tail, now a tail
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or NULL)
} else if (!oldnextp) { // this was tail
@ -404,26 +394,38 @@ void AstNode::setOp4p(AstNode* newp) {
void AstNode::addOp1p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp1p");
if (!m_op1p) { op1p(newp); }
else { m_op1p->addNext(newp); }
if (!m_op1p) {
op1p(newp);
} else {
m_op1p->addNext(newp);
}
}
void AstNode::addOp2p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp2p");
if (!m_op2p) { op2p(newp); }
else { m_op2p->addNext(newp); }
if (!m_op2p) {
op2p(newp);
} else {
m_op2p->addNext(newp);
}
}
void AstNode::addOp3p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp3p");
if (!m_op3p) { op3p(newp); }
else { m_op3p->addNext(newp); }
if (!m_op3p) {
op3p(newp);
} else {
m_op3p->addNext(newp);
}
}
void AstNode::addOp4p(AstNode* newp) {
UASSERT(newp, "Null item passed to addOp4p");
if (!m_op4p) { op4p(newp); }
else { m_op4p->addNext(newp); }
if (!m_op4p) {
op4p(newp);
} else {
m_op4p->addNext(newp);
}
}
void AstNode::replaceWith(AstNode* newp) {
@ -435,13 +437,13 @@ void AstNode::replaceWith(AstNode* newp) {
}
void AstNRelinker::dump(std::ostream& str) const {
str<<" BK="<<reinterpret_cast<uint32_t*>(m_backp);
str<<" ITER="<<reinterpret_cast<uint32_t*>(m_iterpp);
str<<" CHG="<<(m_chg==RELINK_NEXT?"[NEXT] ":"");
str<<(m_chg==RELINK_OP1?"[OP1] ":"");
str<<(m_chg==RELINK_OP2?"[OP2] ":"");
str<<(m_chg==RELINK_OP3?"[OP3] ":"");
str<<(m_chg==RELINK_OP4?"[OP4] ":"");
str << " BK=" << reinterpret_cast<uint32_t*>(m_backp);
str << " ITER=" << reinterpret_cast<uint32_t*>(m_iterpp);
str << " CHG=" << (m_chg == RELINK_NEXT ? "[NEXT] " : "");
str << (m_chg == RELINK_OP1 ? "[OP1] " : "");
str << (m_chg == RELINK_OP2 ? "[OP2] " : "");
str << (m_chg == RELINK_OP3 ? "[OP3] " : "");
str << (m_chg == RELINK_OP4 ? "[OP4] " : "");
}
AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
@ -452,17 +454,24 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
AstNode* backp = oldp->m_backp;
if (linkerp) {
linkerp->m_oldp = oldp;
linkerp->m_backp = backp;
linkerp->m_backp = backp;
linkerp->m_iterpp = oldp->m_iterpp;
if (backp->m_nextp == oldp) linkerp->m_chg = AstNRelinker::RELINK_NEXT;
else if (backp->m_op1p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP1;
else if (backp->m_op2p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP2;
else if (backp->m_op3p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP3;
else if (backp->m_op4p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP4;
else oldp->v3fatalSrc("Unlink of node with back not pointing to it.");
if (backp->m_nextp == oldp) {
linkerp->m_chg = AstNRelinker::RELINK_NEXT;
} else if (backp->m_op1p == oldp) {
linkerp->m_chg = AstNRelinker::RELINK_OP1;
} else if (backp->m_op2p == oldp) {
linkerp->m_chg = AstNRelinker::RELINK_OP2;
} else if (backp->m_op3p == oldp) {
linkerp->m_chg = AstNRelinker::RELINK_OP3;
} else if (backp->m_op4p == oldp) {
linkerp->m_chg = AstNRelinker::RELINK_OP4;
} else {
oldp->v3fatalSrc("Unlink of node with back not pointing to it.");
}
}
if (backp->m_nextp== oldp) {
backp->m_nextp= NULL;
if (backp->m_nextp == oldp) {
backp->m_nextp = NULL;
// Old list gets truncated
// New list becomes a list upon itself
// Most common case is unlinking a entire operand tree
@ -477,12 +486,17 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
// Create new head/tail of extracted list
oldp->m_headtailp = oldtailp;
oldp->m_headtailp->m_headtailp = oldp;
} else if (backp->m_op1p == oldp) {
backp->m_op1p = NULL;
} else if (backp->m_op2p == oldp) {
backp->m_op2p = NULL;
} else if (backp->m_op3p == oldp) {
backp->m_op3p = NULL;
} else if (backp->m_op4p == oldp) {
backp->m_op4p = NULL;
} else {
this->v3fatalSrc("Unlink of node with back not pointing to it.");
}
else if (backp->m_op1p == oldp) backp->m_op1p = NULL;
else if (backp->m_op2p == oldp) backp->m_op2p = NULL;
else if (backp->m_op3p == oldp) backp->m_op3p = NULL;
else if (backp->m_op4p == oldp) backp->m_op4p = NULL;
else this->v3fatalSrc("Unlink of node with back not pointing to it.");
// Relink
oldp->m_backp = NULL;
// Iterator fixup
@ -500,32 +514,44 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
AstNode* backp = oldp->m_backp;
if (linkerp) {
linkerp->m_oldp = oldp;
linkerp->m_backp = backp;
linkerp->m_backp = backp;
linkerp->m_iterpp = oldp->m_iterpp;
if (backp->m_nextp == oldp) linkerp->m_chg = AstNRelinker::RELINK_NEXT;
else if (backp->m_op1p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP1;
else if (backp->m_op2p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP2;
else if (backp->m_op3p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP3;
else if (backp->m_op4p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP4;
else this->v3fatalSrc("Unlink of node with back not pointing to it.");
if (backp->m_nextp == oldp) {
linkerp->m_chg = AstNRelinker::RELINK_NEXT;
} else if (backp->m_op1p == oldp) {
linkerp->m_chg = AstNRelinker::RELINK_OP1;
} else if (backp->m_op2p == oldp) {
linkerp->m_chg = AstNRelinker::RELINK_OP2;
} else if (backp->m_op3p == oldp) {
linkerp->m_chg = AstNRelinker::RELINK_OP3;
} else if (backp->m_op4p == oldp) {
linkerp->m_chg = AstNRelinker::RELINK_OP4;
} else {
this->v3fatalSrc("Unlink of node with back not pointing to it.");
}
}
if (backp->m_nextp== oldp) {
if (backp->m_nextp == oldp) {
// This node gets removed from middle (or tail) of list
// Not head, since then oldp wouldn't be a next of backp...
backp->m_nextp= oldp->m_nextp;
backp->m_nextp = oldp->m_nextp;
if (backp->m_nextp) backp->m_nextp->m_backp = backp;
// If it was a tail, back becomes new tail
if (oldp->m_headtailp) {
backp->m_headtailp = oldp->m_headtailp;
backp->m_headtailp->m_headtailp = backp;
}
}
else {
if (backp->m_op1p == oldp) backp->m_op1p = oldp->m_nextp;
else if (backp->m_op2p == oldp) backp->m_op2p = oldp->m_nextp;
else if (backp->m_op3p == oldp) backp->m_op3p = oldp->m_nextp;
else if (backp->m_op4p == oldp) backp->m_op4p = oldp->m_nextp;
else this->v3fatalSrc("Unlink of node with back not pointing to it.");
} else {
if (backp->m_op1p == oldp) {
backp->m_op1p = oldp->m_nextp;
} else if (backp->m_op2p == oldp) {
backp->m_op2p = oldp->m_nextp;
} else if (backp->m_op3p == oldp) {
backp->m_op3p = oldp->m_nextp;
} else if (backp->m_op4p == oldp) {
backp->m_op4p = oldp->m_nextp;
} else {
this->v3fatalSrc("Unlink of node with back not pointing to it.");
}
if (oldp->m_nextp) {
AstNode* newheadp = oldp->m_nextp;
newheadp->m_backp = backp;
@ -545,13 +571,19 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
}
void AstNode::relink(AstNRelinker* linkerp) {
if (debug()>8) { UINFO(0," EDIT: relink: "); dumpPtrs(); }
if (debug() > 8) {
UINFO(0, " EDIT: relink: ");
dumpPtrs();
}
AstNode* newp = this;
UASSERT(linkerp && linkerp->m_backp, "Need non-empty linker");
UASSERT(!newp->backp(), "New node already linked?");
newp->editCountInc();
if (debug()>8) { linkerp->dump(cout); cout<<endl; }
if (debug() > 8) {
linkerp->dump(cout);
cout << endl;
}
AstNode* backp = linkerp->m_backp;
this->debugTreeChange("-relinkNew: ", __LINE__, true);
@ -563,9 +595,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
case AstNRelinker::RELINK_OP2: relinkOneLink(backp->m_op2p /*ref*/, newp); break;
case AstNRelinker::RELINK_OP3: relinkOneLink(backp->m_op3p /*ref*/, newp); break;
case AstNRelinker::RELINK_OP4: relinkOneLink(backp->m_op4p /*ref*/, newp); break;
default:
this->v3fatalSrc("Relink of node without any link to change.");
break;
default: this->v3fatalSrc("Relink of node without any link to change."); break;
}
// Relink
newp->m_backp = backp;
@ -595,10 +625,10 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set
// Insert the whole old list following the new node's list.
// Thus a unlink without next, followed by relink, gives the same list.
AstNode* newlistlastp = newp->m_headtailp;
UASSERT_OBJ(!(newlistlastp->m_nextp && newlistlastp!=newp), newp,
UASSERT_OBJ(!(newlistlastp->m_nextp && newlistlastp != newp), newp,
"Headtailp tail isn't at the tail");
AstNode* oldlistlastp = pointpr->m_headtailp;
UASSERT_OBJ(!(oldlistlastp->m_nextp && oldlistlastp!=pointpr), newp,
UASSERT_OBJ(!(oldlistlastp->m_nextp && oldlistlastp != pointpr), newp,
"Old headtailp tail isn't at the tail");
// Next links
newlistlastp->m_nextp = pointpr;
@ -650,7 +680,7 @@ AstNode* AstNode::cloneTreeIterList() {
AstNode* newheadp = NULL;
AstNode* newtailp = NULL;
// Audited to make sure this is never NULL
for (AstNode* oldp = this; oldp; oldp=oldp->m_nextp) {
for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) {
AstNode* newp = oldp->cloneTreeIter();
newp->m_headtailp = NULL;
newp->m_backp = newtailp;
@ -701,7 +731,7 @@ void AstNode::deleteNode() {
#else
!v3Global.opt.debugLeak()
#endif
) {
) {
delete this;
}
// Else leak massively, so each pointer is unique
@ -711,7 +741,7 @@ void AstNode::deleteNode() {
void AstNode::deleteTreeIter() {
// private: Delete list of nodes. Publicly call deleteTree() instead.
// Audited to make sure this is never NULL
for (AstNode* nodep=this, *nnextp; nodep; nodep=nnextp) {
for (AstNode *nodep = this, *nnextp; nodep; nodep = nnextp) {
nnextp = nodep->m_nextp;
// MUST be depth first!
if (nodep->m_op1p) nodep->m_op1p->deleteTreeIter();
@ -789,26 +819,25 @@ void AstNode::iterateAndNext(AstNVisitor& v) {
// there's no lower level reason yet though the back must exist.
AstNode* nodep = this;
#ifdef VL_DEBUG // Otherwise too hot of a function for debug
UASSERT_OBJ(!(nodep && !nodep->m_backp), nodep,
"iterateAndNext node has no back");
UASSERT_OBJ(!(nodep && !nodep->m_backp), nodep, "iterateAndNext node has no back");
#endif
if (nodep) ASTNODE_PREFETCH(nodep->m_nextp);
while (nodep) { // effectively: if (!this) return; // Callers rely on this
while (nodep) { // effectively: if (!this) return; // Callers rely on this
if (nodep->m_nextp) ASTNODE_PREFETCH(nodep->m_nextp->m_nextp);
AstNode* niterp = nodep; // This address may get stomped via m_iterpp if the node is edited
AstNode* niterp = nodep; // Pointer may get stomped via m_iterpp if the node is edited
// Desirable check, but many places where multiple iterations are OK
// UASSERT_OBJ(!niterp->m_iterpp, niterp, "IterateAndNext under iterateAndNext may miss edits");
// Optimization note: Doing PREFETCH_RW on m_iterpp is a net even
// UASSERT_OBJ(!niterp->m_iterpp, niterp, "IterateAndNext under iterateAndNext may miss
// edits"); Optimization note: Doing PREFETCH_RW on m_iterpp is a net even
// cppcheck-suppress nullPointer
niterp->m_iterpp = &niterp;
niterp->accept(v);
// accept may do a replaceNode and change niterp on us...
// niterp maybe NULL, so need cast if printing
//if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<cvtToHex(nodep)
// if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<cvtToHex(nodep)
// <<" now into "<<cvtToHex(niterp)<<endl);
if (!niterp) return; // Perhaps node deleted inside accept
niterp->m_iterpp = NULL;
if (VL_UNLIKELY(niterp!=nodep)) { // Edited node inside accept
if (VL_UNLIKELY(niterp != nodep)) { // Edited node inside accept
nodep = niterp;
} else { // Unchanged node, just continue loop
nodep = niterp->m_nextp;
@ -822,8 +851,11 @@ void AstNode::iterateListBackwards(AstNVisitor& v) {
while (nodep) {
// Edits not supported: nodep->m_iterpp = &nodep;
nodep->accept(v);
if (nodep->backp()->m_nextp == nodep) nodep = nodep->backp();
else nodep = NULL; // else: backp points up the tree.
if (nodep->backp()->m_nextp == nodep) {
nodep = nodep->backp();
} else {
nodep = NULL;
} // else: backp points up the tree.
}
}
@ -861,7 +893,8 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
// track, then delete it on completion
AstBegin* tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep);
{
VL_DO_DANGLING(tempp->stmtsp()->accept(v), nodep); // nodep to null as may be replaced
VL_DO_DANGLING(tempp->stmtsp()->accept(v),
nodep); // nodep to null as may be replaced
}
nodep = tempp->stmtsp()->unlinkFrBackWithNext();
VL_DO_DANGLING(tempp->deleteTree(), tempp);
@ -869,11 +902,17 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
// Use back to determine who's pointing at us (IE assume new node
// grafts into same place as old one)
AstNode** nextnodepp = NULL;
if (this->m_backp->m_op1p == this) nextnodepp = &(this->m_backp->m_op1p);
else if (this->m_backp->m_op2p == this) nextnodepp = &(this->m_backp->m_op2p);
else if (this->m_backp->m_op3p == this) nextnodepp = &(this->m_backp->m_op3p);
else if (this->m_backp->m_op4p == this) nextnodepp = &(this->m_backp->m_op4p);
else if (this->m_backp->m_nextp == this) nextnodepp = &(this->m_backp->m_nextp);
if (this->m_backp->m_op1p == this) {
nextnodepp = &(this->m_backp->m_op1p);
} else if (this->m_backp->m_op2p == this) {
nextnodepp = &(this->m_backp->m_op2p);
} else if (this->m_backp->m_op3p == this) {
nextnodepp = &(this->m_backp->m_op3p);
} else if (this->m_backp->m_op4p == this) {
nextnodepp = &(this->m_backp->m_op4p);
} else if (this->m_backp->m_nextp == this) {
nextnodepp = &(this->m_backp->m_nextp);
}
UASSERT_OBJ(nextnodepp, this, "Node's back doesn't point to forward to node itself");
{
VL_DO_DANGLING(nodep->accept(v), nodep); // nodep to null as may be replaced
@ -887,10 +926,8 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
void AstNode::cloneRelinkTree() {
// private: Cleanup clone() operation on whole tree. Publicly call cloneTree() instead.
for (AstNode* nodep=this; nodep; nodep = nodep->m_nextp) {
if (m_dtypep && m_dtypep->clonep()) {
m_dtypep = m_dtypep->clonep();
}
for (AstNode* nodep = this; nodep; nodep = nodep->m_nextp) {
if (m_dtypep && m_dtypep->clonep()) m_dtypep = m_dtypep->clonep();
nodep->cloneRelink();
if (nodep->m_op1p) nodep->m_op1p->cloneRelinkTree();
if (nodep->m_op2p) nodep->m_op2p->cloneRelinkTree();
@ -912,37 +949,34 @@ bool AstNode::gateTreeIter() const {
return true;
}
bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p,
bool ignNext, bool gateOnly) {
bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext,
bool gateOnly) {
// private: Return true if the two trees are identical
if (!node1p && !node2p) return true;
if (!node1p || !node2p) return false;
if (node1p->type() != node2p->type()
|| node1p->dtypep() != node2p->dtypep()
|| !node1p->same(node2p)
|| (gateOnly && !node1p->isGateOptimizable())) {
if (node1p->type() != node2p->type() || node1p->dtypep() != node2p->dtypep()
|| !node1p->same(node2p) || (gateOnly && !node1p->isGateOptimizable())) {
return false;
}
return (sameTreeIter(node1p->m_op1p, node2p->m_op1p, false, gateOnly)
&& sameTreeIter(node1p->m_op2p, node2p->m_op2p, false, gateOnly)
&& sameTreeIter(node1p->m_op3p, node2p->m_op3p, false, gateOnly)
&& sameTreeIter(node1p->m_op4p, node2p->m_op4p, false, gateOnly)
&& (ignNext || sameTreeIter(node1p->m_nextp, node2p->m_nextp, false, gateOnly))
);
&& (ignNext || sameTreeIter(node1p->m_nextp, node2p->m_nextp, false, gateOnly)));
}
//======================================================================
// Static utilities
std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) {
return os<<std::hex<<std::setw(2)<<std::setfill('0')<<rhs.depth()
<<"_"<<std::setw(6)<<std::setfill('0')<<rhs.hshval();
return os << std::hex << std::setw(2) << std::setfill('0') << rhs.depth() << "_"
<< std::setw(6) << std::setfill('0') << rhs.hshval();
}
V3Hash::V3Hash(const string& name) {
uint32_t val = 0;
for (string::const_iterator it = name.begin(); it!=name.end(); ++it) {
val = val*31 + *it;
for (string::const_iterator it = name.begin(); it != name.end(); ++it) {
val = val * 31 + *it;
}
setBoth(1, val);
}
@ -955,7 +989,7 @@ void AstNode::checkTreeIter(AstNode* backp) {
UASSERT_OBJ(backp == this->backp(), this, "Back node inconsistent");
if (VN_IS(this, NodeTermop) || VN_IS(this, NodeVarRef)) {
// Termops have a short-circuited iterateChildren, so check usage
UASSERT_OBJ(!(op1p()||op2p()||op3p()||op4p()), this,
UASSERT_OBJ(!(op1p() || op2p() || op3p() || op4p()), this,
"Terminal operation with non-terminals");
}
if (m_op1p) m_op1p->checkTreeIterList(this);
@ -969,9 +1003,9 @@ void AstNode::checkTreeIterList(AstNode* backp) {
// Audited to make sure this is never NULL
AstNode* headp = this;
AstNode* tailp = this;
for (AstNode* nodep=headp; nodep; nodep=nodep->nextp()) {
for (AstNode* nodep = headp; nodep; nodep = nodep->nextp()) {
nodep->checkTreeIter(backp);
UASSERT_OBJ(headp==this || !nextp(), this,
UASSERT_OBJ(headp == this || !nextp(), this,
"Headtailp should be null in middle of lists");
tailp = nodep;
backp = nodep;
@ -993,12 +1027,14 @@ void AstNode::checkTree() {
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpGdb() { // For GDB only // LCOV_EXCL_LINE
dumpGdbHeader(); // LCOV_EXCL_LINE
cout<<" "; dump(cout); cout<<endl; // LCOV_EXCL_LINE
cout << " ";
dump(cout);
cout << endl; // LCOV_EXCL_LINE
}
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_LINE
dumpPtrs(cout); // LCOV_EXCL_LINE
cout<<" Fileline = "<<fileline()<<endl; // LCOV_EXCL_LINE
cout << " Fileline = " << fileline() << endl; // LCOV_EXCL_LINE
}
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE
@ -1007,7 +1043,8 @@ void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE
}
// cppcheck-suppress unusedFunction // Debug only
void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only // LCOV_EXCL_LINE
string filename = filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); // LCOV_EXCL_LINE
string filename
= filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); // LCOV_EXCL_LINE
v3Global.rootp()->dumpTreeFile(filename); // LCOV_EXCL_LINE
}
@ -1021,45 +1058,53 @@ void AstNode::checkIter() const {
}
void AstNode::dumpPtrs(std::ostream& os) const {
os<<"This="<<typeName()<<" "<<cvtToHex(this);
os<<" back="<<cvtToHex(backp());
if (nextp()) os<<" next="<<cvtToHex(nextp());
if (m_headtailp==this) os<<" headtail=this";
else os<<" headtail="<<cvtToHex(m_headtailp);
if (op1p()) os<<" op1p="<<cvtToHex(op1p());
if (op2p()) os<<" op2p="<<cvtToHex(op2p());
if (op3p()) os<<" op3p="<<cvtToHex(op3p());
if (op4p()) os<<" op4p="<<cvtToHex(op4p());
if (user1p()) os<<" user1p="<<cvtToHex(user1p());
if (user2p()) os<<" user2p="<<cvtToHex(user2p());
if (user3p()) os<<" user3p="<<cvtToHex(user3p());
if (user4p()) os<<" user4p="<<cvtToHex(user4p());
if (user5p()) os<<" user5p="<<cvtToHex(user5p());
if (m_iterpp) {
os<<" iterpp="<<cvtToHex(m_iterpp);
os<<"*="<<cvtToHex(*m_iterpp);
os << "This=" << typeName() << " " << cvtToHex(this);
os << " back=" << cvtToHex(backp());
if (nextp()) os << " next=" << cvtToHex(nextp());
if (m_headtailp == this) {
os << " headtail=this";
} else {
os << " headtail=" << cvtToHex(m_headtailp);
}
os<<endl;
if (op1p()) os << " op1p=" << cvtToHex(op1p());
if (op2p()) os << " op2p=" << cvtToHex(op2p());
if (op3p()) os << " op3p=" << cvtToHex(op3p());
if (op4p()) os << " op4p=" << cvtToHex(op4p());
if (user1p()) os << " user1p=" << cvtToHex(user1p());
if (user2p()) os << " user2p=" << cvtToHex(user2p());
if (user3p()) os << " user3p=" << cvtToHex(user3p());
if (user4p()) os << " user4p=" << cvtToHex(user4p());
if (user5p()) os << " user5p=" << cvtToHex(user5p());
if (m_iterpp) {
os << " iterpp=" << cvtToHex(m_iterpp);
os << "*=" << cvtToHex(*m_iterpp);
}
os << endl;
}
void AstNode::dumpTree(std::ostream& os, const string& indent, int maxDepth) const {
static int s_debugFileline = v3Global.opt.debugSrcLevel("fileline"); // --debugi-fileline 9
os<<indent<<" "<<this<<endl;
if (debug()>8) { os<<indent<<" "; dumpPtrs(os); }
if (s_debugFileline >= 9) {
os<<fileline()->warnContextSecondary();
os << indent << " " << this << endl;
if (debug() > 8) {
os << indent << " ";
dumpPtrs(os);
}
if (maxDepth==1) {
if (op1p()||op2p()||op3p()||op4p()) { os<<indent<<"1: ...(maxDepth)"<<endl; }
if (s_debugFileline >= 9) { os << fileline()->warnContextSecondary(); }
if (maxDepth == 1) {
if (op1p() || op2p() || op3p() || op4p()) { os << indent << "1: ...(maxDepth)" << endl; }
} else {
for (const AstNode* nodep=op1p(); nodep; nodep=nodep->nextp()) {
nodep->dumpTree(os, indent+"1:", maxDepth-1); }
for (const AstNode* nodep=op2p(); nodep; nodep=nodep->nextp()) {
nodep->dumpTree(os, indent+"2:", maxDepth-1); }
for (const AstNode* nodep=op3p(); nodep; nodep=nodep->nextp()) {
nodep->dumpTree(os, indent+"3:", maxDepth-1); }
for (const AstNode* nodep=op4p(); nodep; nodep=nodep->nextp()) {
nodep->dumpTree(os, indent+"4:", maxDepth-1); }
for (const AstNode* nodep = op1p(); nodep; nodep = nodep->nextp()) {
nodep->dumpTree(os, indent + "1:", maxDepth - 1);
}
for (const AstNode* nodep = op2p(); nodep; nodep = nodep->nextp()) {
nodep->dumpTree(os, indent + "2:", maxDepth - 1);
}
for (const AstNode* nodep = op3p(); nodep; nodep = nodep->nextp()) {
nodep->dumpTree(os, indent + "3:", maxDepth - 1);
}
for (const AstNode* nodep = op4p(); nodep; nodep = nodep->nextp()) {
nodep->dumpTree(os, indent + "4:", maxDepth - 1);
}
}
}
@ -1073,16 +1118,15 @@ void AstNode::dumpTreeAndNext(std::ostream& os, const string& indent, int maxDep
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
// Not const function as calls checkTree
if (doDump) {
{ // Write log & close
UINFO(2,"Dumping "<<filename<<endl);
const vl_unique_ptr<std::ofstream> logsp (V3File::new_ofstream(filename, append));
if (logsp->fail()) v3fatal("Can't write "<<filename);
*logsp<<"Verilator Tree Dump (format 0x3900) from <e"<<std::dec<<editCountLast()<<">";
*logsp<<" to <e"<<std::dec<<editCountGbl()<<">"<<endl;
if (editCountGbl()==editCountLast()
&& !(v3Global.opt.dumpTree()>=9)) {
*logsp<<endl;
*logsp<<"No changes since last dump!\n";
{ // Write log & close
UINFO(2, "Dumping " << filename << endl);
const vl_unique_ptr<std::ofstream> logsp(V3File::new_ofstream(filename, append));
if (logsp->fail()) v3fatal("Can't write " << filename);
*logsp << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast();
*logsp << "> to <e" << std::dec << editCountGbl() << ">" << endl;
if (editCountGbl() == editCountLast() && !(v3Global.opt.dumpTree() >= 9)) {
*logsp << endl;
*logsp << "No changes since last dump!\n";
} else {
dumpTree(*logsp);
}
@ -1100,7 +1144,9 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
}
void AstNode::v3errorEndFatal(std::ostringstream& str) const {
v3errorEnd(str); assert(0); VL_UNREACHABLE
v3errorEnd(str);
assert(0);
VL_UNREACHABLE
}
string AstNode::locationStr() const {
@ -1148,12 +1194,12 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
V3Error::v3errorEnd(str, locationStr());
} else {
std::ostringstream nsstr;
nsstr<<str.str();
nsstr << str.str();
if (debug()) {
nsstr<<endl;
nsstr<<"-node: ";
nsstr << endl;
nsstr << "-node: ";
const_cast<AstNode*>(this)->dump(nsstr);
nsstr<<endl;
nsstr << endl;
}
m_fileline->v3errorEnd(nsstr, locationStr());
}
@ -1164,8 +1210,7 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
void AstNode::dtypeChgSigned(bool flag) {
UASSERT_OBJ(dtypep(), this, "No dtype when changing to (un)signed");
dtypeChgWidthSigned(dtypep()->width(), dtypep()->widthMin(),
AstNumeric::fromBool(flag));
dtypeChgWidthSigned(dtypep()->width(), dtypep()->widthMin(), AstNumeric::fromBool(flag));
}
void AstNode::dtypeChgWidth(int width, int widthMin) {
UASSERT_OBJ(dtypep(), this,
@ -1178,9 +1223,9 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric) {
// We allow dtypep() to be null, as before/during widthing dtypes are not resolved
dtypeSetLogicUnsized(width, widthMin, numeric);
} else {
if (width==dtypep()->width()
&& widthMin==dtypep()->widthMin()
&& numeric==dtypep()->numeric()) return; // Correct already
if (width == dtypep()->width() && widthMin == dtypep()->widthMin()
&& numeric == dtypep()->numeric())
return; // Correct already
// FUTURE: We may be pointing at a two state data type, and this may
// convert it to logic. Since the AstVar remains correct, we
// work OK but this assumption may break in the future.
@ -1193,34 +1238,31 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric) {
AstNodeDType* AstNode::findBasicDType(AstBasicDTypeKwd kwd) const {
// For 'simple' types we use the global directory. These are all unsized.
// More advanced types land under the module/task/etc
return v3Global.rootp()->typeTablep()
->findBasicDType(fileline(), kwd);
return v3Global.rootp()->typeTablep()->findBasicDType(fileline(), kwd);
}
AstNodeDType* AstNode::findBitDType(int width, int widthMin, AstNumeric numeric) const {
return v3Global.rootp()->typeTablep()
->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, width, widthMin, numeric);
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT,
width, widthMin, numeric);
}
AstNodeDType* AstNode::findLogicDType(int width, int widthMin, AstNumeric numeric) const {
return v3Global.rootp()->typeTablep()
->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, width, widthMin, numeric);
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC,
width, widthMin, numeric);
}
AstNodeDType* AstNode::findLogicRangeDType(const VNumRange& range, int widthMin,
AstNumeric numeric) const {
return v3Global.rootp()->typeTablep()
->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, range, widthMin, numeric);
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC,
range, widthMin, numeric);
}
AstNodeDType* AstNode::findBitRangeDType(const VNumRange& range, int widthMin,
AstNumeric numeric) const {
return v3Global.rootp()->typeTablep()
->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, range, widthMin, numeric);
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT,
range, widthMin, numeric);
}
AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
return v3Global.rootp()->typeTablep()
->findInsertSameDType(nodep);
return v3Global.rootp()->typeTablep()->findInsertSameDType(nodep);
}
AstNodeDType* AstNode::findVoidDType() const {
return v3Global.rootp()->typeTablep()
->findVoidDType(fileline());
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
}
//######################################################################

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -42,14 +42,14 @@
class BeginState {
private:
// NODE STATE
//Entire netlist:
// Entire netlist:
// AstNodeFTask::user1 -> bool, 1=processed
AstUser1InUse m_inuser1;
bool m_anyFuncInBegin;
AstUser1InUse m_inuser1;
bool m_anyFuncInBegin;
public:
BeginState() {
m_anyFuncInBegin = false;
}
BeginState()
: m_anyFuncInBegin(false) {}
~BeginState() {}
void userMarkChanged(AstNode* nodep) {
nodep->user1(true);
@ -63,12 +63,12 @@ public:
class BeginVisitor : public AstNVisitor {
private:
// STATE
BeginState* m_statep; // Current global state
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
string m_namedScope; // Name of begin blocks above us
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_ifDepth; // Current if depth
BeginState* m_statep; // Current global state
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
string m_namedScope; // Name of begin blocks above us
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_ifDepth; // Current if depth
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -83,11 +83,11 @@ private:
m_modp = origModp;
}
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
UINFO(8," "<<nodep<<endl);
UINFO(8, " " << nodep << endl);
// Rename it
if (m_unnamedScope != "") {
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
UINFO(8," rename to "<<nodep->name()<<endl);
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
UINFO(8, " rename to " << nodep->name() << endl);
m_statep->userMarkChanged(nodep);
}
// BEGIN wrapping a function rename that function, but don't affect
@ -109,28 +109,34 @@ private:
}
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
// Begin blocks were only useful in variable creation, change names and delete
UINFO(8," "<<nodep<<endl);
UINFO(8, " " << nodep << endl);
string oldScope = m_namedScope;
string oldUnnamed = m_unnamedScope;
{
UINFO(8,"nname "<<m_namedScope<<endl);
UINFO(8, "nname " << m_namedScope << endl);
if (nodep->name() != "") { // Else unneeded unnamed block
// Create data for dotted variable resolution
string dottedname = nodep->name() + "__DOT__"; // So always found
string::size_type pos;
while ((pos=dottedname.find("__DOT__")) != string::npos) {
while ((pos = dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos+strlen("__DOT__"));
dottedname = dottedname.substr(pos + strlen("__DOT__"));
if (nodep->name() != "") {
if (m_namedScope=="") m_namedScope = ident;
else m_namedScope = m_namedScope + "__DOT__"+ident;
if (m_namedScope == "") {
m_namedScope = ident;
} else {
m_namedScope = m_namedScope + "__DOT__" + ident;
}
}
if (m_unnamedScope == "") {
m_unnamedScope = ident;
} else {
m_unnamedScope = m_unnamedScope + "__DOT__" + ident;
}
if (m_unnamedScope=="") m_unnamedScope = ident;
else m_unnamedScope = m_unnamedScope + "__DOT__"+ident;
// Create CellInline for dotted var resolution
if (!m_ftaskp) {
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
m_unnamedScope, "__BEGIN__");
AstCellInline* inlinep
= new AstCellInline(nodep->fileline(), m_unnamedScope, "__BEGIN__");
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
}
}
@ -147,7 +153,11 @@ private:
AstNode* addsp = NULL;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) { addsp = addsp->addNextNull(stmtsp); } else { addsp = stmtsp; }
if (addsp) {
addsp = addsp->addNextNull(stmtsp);
} else {
addsp = stmtsp;
}
}
if (addsp) {
nodep->replaceWith(addsp);
@ -159,12 +169,15 @@ private:
virtual void visit(AstVar* nodep) VL_OVERRIDE {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
m_statep->userMarkChanged(nodep);
// Move to module
nodep->unlinkFrBack();
if (m_ftaskp) m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func
else m_modp->addStmtp(nodep);
if (m_ftaskp) {
m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func
} else {
m_modp->addStmtp(nodep);
}
}
}
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
@ -175,17 +188,20 @@ private:
// Move to module
nodep->unlinkFrBack();
// Begins under funcs just move into the func
if (m_ftaskp) m_ftaskp->addStmtsp(nodep);
else m_modp->addStmtp(nodep);
if (m_ftaskp) {
m_ftaskp->addStmtsp(nodep);
} else {
m_modp->addStmtp(nodep);
}
}
}
virtual void visit(AstCell* nodep) VL_OVERRIDE {
UINFO(8," CELL "<<nodep<<endl);
UINFO(8, " CELL " << nodep << endl);
if (m_namedScope != "") {
m_statep->userMarkChanged(nodep);
// Rename it
nodep->name(m_namedScope+"__DOT__"+nodep->name());
UINFO(8," rename to "<<nodep->name()<<endl);
nodep->name(m_namedScope + "__DOT__" + nodep->name());
UINFO(8, " rename to " << nodep->name() << endl);
// Move to module
nodep->unlinkFrBack();
m_modp->addStmtp(nodep);
@ -193,10 +209,10 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
UINFO(9, " VARXREF "<<nodep<<endl);
UINFO(9, " VARXREF " << nodep << endl);
if (m_namedScope != "" && nodep->inlinedDots() == "") {
nodep->inlinedDots(m_namedScope);
UINFO(9, " rescope to "<<nodep<<endl);
UINFO(9, " rescope to " << nodep << endl);
}
}
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
@ -207,7 +223,7 @@ private:
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), string("__DOT__")+m_namedScope));
nodep->scopeAttrp(new AstText(nodep->fileline(), string("__DOT__") + m_namedScope));
if (afterp) nodep->scopeAttrp(afterp);
}
iterateChildren(nodep);
@ -218,14 +234,15 @@ private:
iterateChildren(nodep);
}
// VISITORS - LINT CHECK
virtual void visit(AstIf* nodep) VL_OVERRIDE { // Note not AstNodeIf; other types don't get covered
virtual void visit(AstIf* nodep) VL_OVERRIDE { // not AstNodeIf; other types not covered
// Check IFDEPTH warning - could be in other transform files if desire
int prevIfDepth = m_ifDepth;
if (m_ifDepth == -1 || v3Global.opt.ifDepth()<1) { // Turned off
if (m_ifDepth == -1 || v3Global.opt.ifDepth() < 1) { // Turned off
} else if (nodep->uniquePragma() || nodep->unique0Pragma() || nodep->priorityPragma()) {
m_ifDepth = -1;
} else if (++m_ifDepth > v3Global.opt.ifDepth()) {
nodep->v3warn(IFDEPTH,"Deep 'if' statement; suggest unique/priority to avoid slow logic");
nodep->v3warn(IFDEPTH,
"Deep 'if' statement; suggest unique/priority to avoid slow logic");
nodep->fileline()->modifyWarnOff(V3ErrorCode::IFDEPTH, true); // Warn only once
m_ifDepth = -1;
}
@ -258,14 +275,14 @@ private:
// VISITORS
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
if (nodep->taskp()->user1()) { // It was converted
UINFO(9, " relinkFTask "<<nodep<<endl);
UINFO(9, " relinkFTask " << nodep << endl);
nodep->name(nodep->taskp()->name());
}
iterateChildren(nodep);
}
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (nodep->varp()->user1()) { // It was converted
UINFO(9, " relinVarRef "<<nodep<<endl);
UINFO(9, " relinVarRef " << nodep << endl);
nodep->name(nodep->varp()->name());
}
iterateChildren(nodep);
@ -273,9 +290,9 @@ private:
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
// May have changed cell names
// TypeTable is always after all modules, so names are stable
UINFO(8," IFACEREFDTYPE "<<nodep<<endl);
UINFO(8, " IFACEREFDTYPE " << nodep << endl);
if (nodep->cellp()) nodep->cellName(nodep->cellp()->name());
UINFO(8," rename to "<<nodep<<endl);
UINFO(8, " rename to " << nodep << endl);
iterateChildren(nodep);
}
//--------------------
@ -283,9 +300,7 @@ private:
public:
// CONSTRUCTORS
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) {
iterate(nodep);
}
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) { iterate(nodep); }
virtual ~BeginRelinkVisitor() {}
};
@ -293,13 +308,11 @@ public:
// Task class functions
void V3Begin::debeginAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
{
BeginState state;
{ BeginVisitor bvisitor (nodep,&state); }
if (state.anyFuncInBegin()) {
BeginRelinkVisitor brvisitor (nodep,&state);
}
{ BeginVisitor bvisitor(nodep, &state); }
if (state.anyFuncInBegin()) { BeginRelinkVisitor brvisitor(nodep, &state); }
} // Destruct before checking
V3Global::dumpCheckGlobalTree("begin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -42,35 +42,35 @@ class BrokenTable : public AstNVisitor {
private:
// MEMBERS
// For each node, we keep if it exists or not.
typedef vl_unordered_map<const AstNode*,int> NodeMap; // Performance matters (when --debug)
typedef vl_unordered_map<const AstNode*, int> NodeMap; // Performance matters (when --debug)
static NodeMap s_nodes; // Set of all nodes that exist
// BITMASK
enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed
enum { FLAG_IN_TREE = 0x02 }; // Is in netlist tree
enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to
enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked
enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node
enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed
enum { FLAG_IN_TREE = 0x02 }; // Is in netlist tree
enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to
enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked
enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node
public:
// METHODS
static void deleted(const AstNode* nodep) {
// Called by operator delete on any node - only if VL_LEAK_CHECKS
if (debug()>=9) cout<<"-nodeDel: "<<cvtToHex(nodep)<<endl;
if (debug() >= 9) cout << "-nodeDel: " << cvtToHex(nodep) << endl;
NodeMap::iterator iter = s_nodes.find(nodep);
UASSERT_OBJ(!(iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED)),
UASSERT_OBJ(!(iter == s_nodes.end() || !(iter->second & FLAG_ALLOCATED)),
reinterpret_cast<const AstNode*>(nodep),
"Deleting AstNode object that was never tracked or already deleted");
if (iter!=s_nodes.end()) s_nodes.erase(iter);
if (iter != s_nodes.end()) s_nodes.erase(iter);
}
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 4
// GCC 4.4.* compiler warning bug, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39390
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
static void addNewed(const AstNode* nodep) {
// Called by operator new on any node - only if VL_LEAK_CHECKS
if (debug()>=9) cout<<"-nodeNew: "<<cvtToHex(nodep)<<endl;
if (debug() >= 9) cout << "-nodeNew: " << cvtToHex(nodep) << endl;
NodeMap::iterator iter = s_nodes.find(nodep);
UASSERT_OBJ(!(iter !=s_nodes.end() && (iter->second & FLAG_ALLOCATED)),
nodep, "Newing AstNode object that is already allocated");
UASSERT_OBJ(!(iter != s_nodes.end() && (iter->second & FLAG_ALLOCATED)), nodep,
"Newing AstNode object that is already allocated");
if (iter == s_nodes.end()) {
int flags = FLAG_ALLOCATED; // This int needed to appease GCC 4.1.2
s_nodes.insert(make_pair(nodep, flags));
@ -80,9 +80,9 @@ public:
// Called by BrokenCheckVisitor when each node entered/exited
if (!okIfLinkedTo(nodep)) return;
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter!=s_nodes.end()) {
if (iter != s_nodes.end()) {
iter->second &= ~FLAG_UNDER_NOW;
if (flag) iter->second |= FLAG_UNDER_NOW;
if (flag) iter->second |= FLAG_UNDER_NOW;
}
}
static void addInTree(AstNode* nodep, bool linkable) {
@ -103,7 +103,7 @@ public:
UASSERT_OBJ(!(iter->second & FLAG_IN_TREE), nodep,
"AstNode is already in tree at another location");
}
int or_flags = FLAG_IN_TREE | (linkable?FLAG_LINKABLE:0);
int or_flags = FLAG_IN_TREE | (linkable ? FLAG_LINKABLE : 0);
if (iter == s_nodes.end()) {
s_nodes.insert(make_pair(nodep, or_flags));
} else {
@ -149,12 +149,12 @@ public:
}
}
static void doneWithTree() {
for (int backs=0; backs<2; backs++) { // Those with backp() are probably under one leaking without
for (int backs = 0; backs < 2;
backs++) { // Those with backp() are probably under one leaking without
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
if ((it->second & FLAG_ALLOCATED)
&& !(it->second & FLAG_IN_TREE)
if ((it->second & FLAG_ALLOCATED) && !(it->second & FLAG_IN_TREE)
&& !(it->second & FLAG_LEAKED)
&& (it->first->backp() ? backs==1 : backs==0)) {
&& (it->first->backp() ? backs == 1 : backs == 0)) {
// Use only AstNode::dump instead of the virtual one, as there
// may be varp() and other cross links that are bad.
if (v3Global.opt.debugCheck()) {
@ -163,11 +163,12 @@ public:
// watch AstNode::s_editCntGbl==####
// run
// bt
std::cerr<<"%Error: LeakedNode"<<(it->first->backp()?"Back: ":": ");
AstNode* rawp = const_cast<AstNode*>
(static_cast<const AstNode*>(it->first));
std::cerr << "%Error: LeakedNode"
<< (it->first->backp() ? "Back: " : ": ");
AstNode* rawp
= const_cast<AstNode*>(static_cast<const AstNode*>(it->first));
rawp->AstNode::dump(std::cerr);
std::cerr<<endl;
std::cerr << endl;
V3Error::incErrors();
}
it->second |= FLAG_LEAKED;
@ -175,6 +176,7 @@ public:
}
}
}
public:
// CONSTRUCTORS
BrokenTable() {}
@ -213,9 +215,7 @@ private:
public:
// CONSTRUCTORS
explicit BrokenMarkVisitor(AstNetlist* nodep) {
iterate(nodep);
}
explicit BrokenMarkVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~BrokenMarkVisitor() {}
};
@ -226,27 +226,27 @@ class BrokenCheckVisitor : public AstNVisitor {
private:
void checkWidthMin(const AstNode* nodep) {
UASSERT_OBJ(nodep->width() == nodep->widthMin()
|| v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH,
|| v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH,
nodep, "Width != WidthMin");
}
void processAndIterate(AstNode* nodep) {
BrokenTable::setUnder(nodep, true);
const char* whyp = nodep->broken();
UASSERT_OBJ(!whyp, nodep,
"Broken link in node (or something without maybePointedTo): "<<whyp);
"Broken link in node (or something without maybePointedTo): " << whyp);
if (nodep->dtypep()) {
UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep,
"Broken link in node->dtypep() to "<<cvtToHex(nodep->dtypep()));
"Broken link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
UASSERT_OBJ(VN_IS(nodep->dtypep(), NodeDType), nodep,
"Non-dtype link in node->dtypep() to "<<cvtToHex(nodep->dtypep()));
"Non-dtype link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
}
if (v3Global.assertDTypesResolved()) {
if (nodep->hasDType()) {
UASSERT_OBJ(nodep->dtypep(), nodep,
"No dtype on node with hasDType(): "<<nodep->prettyTypeName());
"No dtype on node with hasDType(): " << nodep->prettyTypeName());
} else {
UASSERT_OBJ(!nodep->dtypep(), nodep,
"DType on node without hasDType(): "<<nodep->prettyTypeName());
"DType on node without hasDType(): " << nodep->prettyTypeName());
}
UASSERT_OBJ(!nodep->getChildDTypep(), nodep,
"childDTypep() non-null on node after should have removed");
@ -258,8 +258,7 @@ private:
}
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
processAndIterate(nodep);
UASSERT_OBJ(!(v3Global.assertDTypesResolved()
&& nodep->brokeLhsMustBeLvalue()
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
&& VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()),
nodep, "Assignment LHS is not an lvalue");
@ -268,11 +267,10 @@ private:
// Process not just iterate
processAndIterate(nodep);
}
public:
// CONSTRUCTORS
explicit BrokenCheckVisitor(AstNetlist* nodep) {
iterate(nodep);
}
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~BrokenCheckVisitor() {}
};
@ -280,27 +278,21 @@ public:
// Broken class functions
void V3Broken::brokenAll(AstNetlist* nodep) {
//UINFO(9,__FUNCTION__<<": "<<endl);
// UINFO(9, __FUNCTION__ << ": " << endl);
static bool inBroken = false;
if (VL_UNCOVERABLE(inBroken)) {
// A error called by broken can recurse back into broken; avoid this
UINFO(1,"Broken called under broken, skipping recursion.\n"); // LCOV_EXCL_LINE
UINFO(1, "Broken called under broken, skipping recursion.\n"); // LCOV_EXCL_LINE
} else {
inBroken = true;
BrokenTable::prepForTree();
BrokenMarkVisitor mvisitor (nodep);
BrokenCheckVisitor cvisitor (nodep);
BrokenMarkVisitor mvisitor(nodep);
BrokenCheckVisitor cvisitor(nodep);
BrokenTable::doneWithTree();
inBroken = false;
}
}
void V3Broken::addNewed(AstNode* nodep) {
BrokenTable::addNewed(nodep);
}
void V3Broken::deleted(AstNode* nodep) {
BrokenTable::deleted(nodep);
}
bool V3Broken::isAllocated(AstNode* nodep) {
return BrokenTable::isAllocated(nodep);
}
void V3Broken::addNewed(AstNode* nodep) { BrokenTable::addNewed(nodep); }
void V3Broken::deleted(AstNode* nodep) { BrokenTable::deleted(nodep); }
bool V3Broken::isAllocated(AstNode* nodep) { return BrokenTable::isAllocated(nodep); }

View File

@ -39,25 +39,24 @@
class V3CCtorsVisitor {
private:
string m_basename;
string m_argsp;
string m_callargsp;
AstNodeModule* m_modp; // Current module
AstCFunc* m_tlFuncp; // Top level function being built
AstCFunc* m_funcp; // Current function
int m_numStmts; // Number of statements output
int m_funcNum; // Function number being built
string m_basename;
string m_argsp;
string m_callargsp;
AstNodeModule* m_modp; // Current module
AstCFunc* m_tlFuncp; // Top level function being built
AstCFunc* m_funcp; // Current function
int m_numStmts; // Number of statements output
int m_funcNum; // Function number being built
public:
AstCFunc* builtFuncp() const { return m_tlFuncp; }
void add(AstNode* nodep) {
if (v3Global.opt.outputSplitCFuncs()
&& v3Global.opt.outputSplitCFuncs() < m_numStmts) {
if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) {
m_funcp = NULL;
}
if (!m_funcp) {
m_funcp = new AstCFunc(m_modp->fileline(),
m_basename+"_"+cvtToStr(++m_funcNum), NULL, "void");
m_funcp = new AstCFunc(m_modp->fileline(), m_basename + "_" + cvtToStr(++m_funcNum),
NULL, "void");
m_funcp->isStatic(false);
m_funcp->declPrivate(true);
m_funcp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
@ -75,9 +74,8 @@ public:
m_numStmts += 1;
}
V3CCtorsVisitor(AstNodeModule* nodep, const string& basename,
const string& argsp="", const string& callargsp="",
const string& stmt="") {
V3CCtorsVisitor(AstNodeModule* nodep, const string& basename, const string& argsp = "",
const string& callargsp = "", const string& stmt = "") {
m_basename = basename;
m_argsp = argsp;
m_callargsp = callargsp;
@ -89,13 +87,12 @@ public:
m_tlFuncp->isStatic(false);
m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
m_tlFuncp->argTypes(m_argsp);
if (stmt != "") {
m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
if (stmt != "") { m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); }
m_funcp = m_tlFuncp;
m_modp->addStmtp(m_tlFuncp);
}
~V3CCtorsVisitor() {}
private:
VL_UNCOPYABLE(V3CCtorsVisitor);
};
@ -122,15 +119,16 @@ void V3CCtors::evalAsserts() {
if (varp->isWide()) {
newp = new AstWordSel(
varp->fileline(), newp,
new AstConst(varp->fileline(), varp->widthWords()-1));
new AstConst(varp->fileline(), varp->widthWords() - 1));
}
uint64_t value = VL_MASK_Q(storedWidth) & ~VL_MASK_Q(lastWordWidth);
newp = new AstAnd(varp->fileline(), newp,
new AstConst(varp->fileline(), AstConst::WidthedValue(),
storedWidth, value));
AstNodeIf* ifp = new AstIf(varp->fileline(), newp,
new AstCStmt(varp->fileline(),
"Verilated::overWidthError(\""+varp->prettyName()+"\");"));
AstNodeIf* ifp = new AstIf(
varp->fileline(), newp,
new AstCStmt(varp->fileline(), "Verilated::overWidthError(\""
+ varp->prettyName() + "\");"));
ifp->branchPred(VBranchPred::BP_UNLIKELY);
newp = ifp;
funcp->addStmtsp(newp);
@ -142,10 +140,10 @@ void V3CCtors::evalAsserts() {
}
void V3CCtors::cctorsAll() {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
evalAsserts();
for (AstNodeModule* modp = v3Global.rootp()->modulesp();
modp; modp = VN_CAST(modp->nextp(), NodeModule)) {
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
modp = VN_CAST(modp->nextp(), NodeModule)) {
// Process each module in turn
AstCFunc* varResetFuncp;
{
@ -158,8 +156,7 @@ void V3CCtors::cctorsAll() {
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* varp = VN_CAST(np, Var)) {
if (!varp->isIfaceParent() && !varp->isIfaceRef()
&& !varp->noReset()) {
if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) {
var_reset.add(new AstCReset(varp->fileline(),
new AstVarRef(varp->fileline(), varp, true)));
}
@ -168,10 +165,8 @@ void V3CCtors::cctorsAll() {
}
if (v3Global.opt.coverage()) {
V3CCtorsVisitor configure_coverage(
modp, "_configure_coverage",
EmitCBaseVisitor::symClassVar() + ", bool first",
"vlSymsp, first",
"if (false && vlSymsp && first) {} // Prevent unused\n");
modp, "_configure_coverage", EmitCBaseVisitor::symClassVar() + ", bool first",
"vlSymsp, first", "if (false && vlSymsp && first) {} // Prevent unused\n");
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstCoverDecl* coverp = VN_CAST(np, CoverDecl)) {
AstNode* backp = coverp->backp();

View File

@ -45,9 +45,9 @@
#include <algorithm>
#include <cstdarg>
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
#define CASE_BARF 999999 // Magic width when non-constant
#define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
#define CASE_BARF 999999 // Magic width when non-constant
#define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree
//######################################################################
@ -64,8 +64,8 @@ private:
}
// Detect multiple defaults
bool hitDefault = false;
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
if (itemp->isDefault()) {
if (hitDefault) {
itemp->v3error("Multiple default statements in case statement.");
@ -78,8 +78,8 @@ private:
{
m_caseExprp = nodep;
iterate(nodep->exprp());
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
iterateAndNextNull(itemp->condsp());
}
m_caseExprp = NULL;
@ -89,16 +89,20 @@ private:
// See also neverItem
if (m_caseExprp && nodep->num().isFourState()) {
if (VN_IS(m_caseExprp, GenCase)) {
nodep->v3error("Use of x/? constant in generate case statement, (no such thing as 'generate casez')");
nodep->v3error("Use of x/? constant in generate case statement, "
"(no such thing as 'generate casez')");
} else if (VN_IS(m_caseExprp, Case) && VN_CAST(m_caseExprp, Case)->casex()) {
// Don't sweat it, we already complained about casex in general
} else if (VN_IS(m_caseExprp, Case) && (VN_CAST(m_caseExprp, Case)->casez()
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
} else if (VN_IS(m_caseExprp, Case)
&& (VN_CAST(m_caseExprp, Case)->casez()
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
if (nodep->num().isUnknown()) {
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, (perhaps intended ?/z in constant)");
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
"(perhaps intended ?/z in constant)");
}
} else {
nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, (perhaps intended casex/casez)");
nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, "
"(perhaps intended casex/casez)");
}
}
}
@ -121,17 +125,18 @@ private:
// NODE STATE
// Cleared each Case
// AstIf::user3() -> bool. Set true to indicate clone not needed
AstUser3InUse m_inuser3;
AstUser3InUse m_inuser3;
// STATE
VDouble0 m_statCaseFast; // Statistic tracking
VDouble0 m_statCaseSlow; // Statistic tracking
// Per-CASE
int m_caseWidth; // Width of valueItems
int m_caseItems; // Number of caseItem unique values
bool m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
AstNode* m_valueItem[1<<CASE_OVERLAP_WIDTH]; // For each possible value, the case branch we need
int m_caseWidth; // Width of valueItems
int m_caseItems; // Number of caseItem unique values
bool m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
// For each possible value, the case branch we need
AstNode* m_valueItem[1 << CASE_OVERLAP_WIDTH];
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -141,9 +146,9 @@ private:
bool opaque = false;
m_caseItems = 0;
m_caseNoOverlapsAllCovered = true;
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
if (icondp->width() > width) width = icondp->width();
if (icondp->isDouble()) opaque = true;
if (!VN_IS(icondp, Const)) width = CASE_BARF; // Can't parse; not a constant
@ -151,38 +156,39 @@ private:
}
}
m_caseWidth = width;
if (width==0 || width > CASE_OVERLAP_WIDTH || opaque) {
if (width == 0 || width > CASE_OVERLAP_WIDTH || opaque) {
m_caseNoOverlapsAllCovered = false;
return false; // Too wide for analysis
}
UINFO(8,"Simple case statement: "<<nodep<<endl);
UINFO(8, "Simple case statement: " << nodep << endl);
// Zero list of items for each value
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) m_valueItem[i] = NULL;
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) m_valueItem[i] = NULL;
// Now pick up the values for each assignment
// We can cheat and use uint32_t's because we only support narrow case's
bool bitched = false;
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
//if (debug()>=9) icondp->dumpTree(cout, " caseitem: ");
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
// if (debug() >= 9) icondp->dumpTree(cout, " caseitem: ");
AstConst* iconstp = VN_CAST(icondp, Const);
UASSERT_OBJ(iconstp, nodep, "above 'can't parse' should have caught this");
if (neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
} else {
V3Number nummask (itemp, iconstp->width());
V3Number nummask(itemp, iconstp->width());
nummask.opBitsNonX(iconstp->num());
uint32_t mask = nummask.toUInt();
V3Number numval (itemp, iconstp->width());
V3Number numval(itemp, iconstp->width());
numval.opBitsOne(iconstp->num());
uint32_t val = numval.toUInt();
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
uint32_t val = numval.toUInt();
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
if ((i & mask) == val) {
if (!m_valueItem[i]) {
m_valueItem[i] = itemp;
} else if (!itemp->ignoreOverlap() && !bitched) {
icondp->v3warn(CASEOVERLAP, "Case values overlap (example pattern 0x"
<<std::hex<<i<<")");
icondp->v3warn(CASEOVERLAP,
"Case values overlap (example pattern 0x"
<< std::hex << i << ")");
bitched = true;
m_caseNoOverlapsAllCovered = false;
}
@ -192,15 +198,16 @@ private:
}
// Defaults were moved to last in the caseitem list by V3LinkDot
if (itemp->isDefault()) { // Case statement's default... Fill the table
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
if (!m_valueItem[i]) m_valueItem[i] = itemp;
}
}
}
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
if (!m_valueItem[i]) {
nodep->v3warn(CASEINCOMPLETE, "Case values incompletely covered (example pattern 0x"
<<std::hex<<i<<")");
nodep->v3warn(CASEINCOMPLETE, "Case values incompletely covered "
"(example pattern 0x"
<< std::hex << i << ")");
m_caseNoOverlapsAllCovered = false;
return false;
}
@ -213,24 +220,23 @@ private:
// Convert valueItem from AstCaseItem* to the expression
// Not done earlier, as we may now have a NULL because it's just a ";" NOP branch
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
m_valueItem[i] = VN_CAST(m_valueItem[i], CaseItem)->bodysp();
}
return true; // All is fine
}
AstNode* replaceCaseFastRecurse(AstNode* cexprp, int msb, uint32_t upperValue) {
if (msb<0) {
if (msb < 0) {
// There's no space for a IF. We know upperValue is thus down to a specific
// exact value, so just return the tree value
// Note can't clone here, as we're going to check for equivalence above
return m_valueItem[upperValue];
}
else {
} else {
// Make left and right subtrees
// cexpr[msb:lsb] == 1
AstNode* tree0p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | 0);
AstNode* tree1p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | (1UL<<msb));
AstNode* tree0p = replaceCaseFastRecurse(cexprp, msb - 1, upperValue | 0);
AstNode* tree1p = replaceCaseFastRecurse(cexprp, msb - 1, upperValue | (1UL << msb));
if (tree0p == tree1p) {
// Same logic on both sides, so we can just return one of 'em
@ -238,11 +244,12 @@ private:
}
// We could have a "checkerboard" with A B A B, we can use the same IF on both edges
bool same = true;
for (uint32_t a=upperValue,
b=(upperValue|(1UL<<msb));
a < (upperValue|(1UL<<msb));
a++, b++) {
if (m_valueItem[a] != m_valueItem[b]) { same = false; break; }
for (uint32_t a = upperValue, b = (upperValue | (1UL << msb));
a < (upperValue | (1UL << msb)); a++, b++) {
if (m_valueItem[a] != m_valueItem[b]) {
same = false;
break;
}
}
if (same) {
VL_DO_DANGLING(tree1p->deleteTree(), tree1p);
@ -256,14 +263,12 @@ private:
if (tree1p && !tree1p->user3()) tree1p = tree1p->cloneTree(true);
// Alternate scheme if we ever do multiple bits at a time:
//V3Number nummask (cexprp, cexprp->width(), (1UL<<msb));
//AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
// V3Number nummask (cexprp, cexprp->width(), (1UL<<msb));
// AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
// new AstConst(cexprp->fileline(), nummask));
AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false),
msb, 1);
AstNode* eqp = new AstNeq(cexprp->fileline(),
new AstConst(cexprp->fileline(), 0),
and1p);
AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false), msb, 1);
AstNode* eqp
= new AstNeq(cexprp->fileline(), new AstConst(cexprp->fileline(), 0), and1p);
AstIf* ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
ifp->user3(1); // So we don't bother to clone it
return ifp;
@ -276,10 +281,10 @@ private:
// IF(msb-1, 01, 00))
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
if (debug()>=9) {
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
if (debug() >= 9) {
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
if (AstNode* itemp = m_valueItem[i]) {
UINFO(9,"Value "<<std::hex<<i<<" "<<itemp<<endl);
UINFO(9, "Value " << std::hex << i << " " << itemp << endl);
}
}
}
@ -288,15 +293,18 @@ private:
replaceCaseParallel(nodep, m_caseNoOverlapsAllCovered);
AstNode::user3ClearTree();
AstNode* ifrootp = replaceCaseFastRecurse(cexprp, m_caseWidth-1, 0UL);
AstNode* ifrootp = replaceCaseFastRecurse(cexprp, m_caseWidth - 1, 0UL);
// Case expressions can't be linked twice, so clone them
if (ifrootp && !ifrootp->user3()) ifrootp = ifrootp->cloneTree(true);
if (ifrootp) nodep->replaceWith(ifrootp);
else nodep->unlinkFrBack();
if (ifrootp) {
nodep->replaceWith(ifrootp);
} else {
nodep->unlinkFrBack();
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
VL_DO_DANGLING(cexprp->deleteTree(), cexprp);
if (debug()>=9) ifrootp->dumpTree(cout, " _simp: ");
if (debug() >= 9) ifrootp->dumpTree(cout, " _simp: ");
}
void replaceCaseComplicated(AstCase* nodep) {
@ -307,9 +315,10 @@ private:
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
// We'll do this in two stages. First stage, convert the conditions to
// the appropriate IF AND terms.
if (debug()>=9) nodep->dumpTree(cout, " _comp_IN: ");
if (debug() >= 9) nodep->dumpTree(cout, " _comp_IN: ");
bool hadDefault = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
if (!itemp->condsp()) {
// Default clause. Just make true, we'll optimize it away later
itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue()));
@ -318,7 +327,7 @@ private:
// Expressioned clause
AstNode* icondNextp = NULL;
AstNode* ifexprp = NULL; // If expression to test
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondNextp) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondNextp) {
icondNextp = icondp->nextp();
icondp->unlinkFrBack();
@ -326,7 +335,8 @@ private:
AstConst* iconstp = VN_CAST(icondp, Const);
if (iconstp && neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
VL_DO_DANGLING(icondp->deleteTree(), icondp); VL_DANGLING(iconstp);
VL_DO_DANGLING(icondp->deleteTree(), icondp);
VL_DANGLING(iconstp);
// For simplicity, make expression that is not equal, and let later
// optimizations remove it
condp = new AstConst(itemp->fileline(), AstConst::LogicFalse());
@ -336,16 +346,17 @@ private:
irangep->rhsp()->unlinkFrBack());
} else if (iconstp && iconstp->num().isFourState()
&& (nodep->casex() || nodep->casez() || nodep->caseInside())) {
V3Number nummask (itemp, iconstp->width());
V3Number nummask(itemp, iconstp->width());
nummask.opBitsNonX(iconstp->num());
V3Number numval (itemp, iconstp->width());
V3Number numval(itemp, iconstp->width());
numval.opBitsOne(iconstp->num());
AstNode* and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
new AstConst(itemp->fileline(), nummask));
AstNode* and2p = new AstAnd(itemp->fileline(),
new AstConst(itemp->fileline(), numval),
new AstConst(itemp->fileline(), nummask));
VL_DO_DANGLING(icondp->deleteTree(), icondp); VL_DANGLING(iconstp);
VL_DO_DANGLING(icondp->deleteTree(), icondp);
VL_DANGLING(iconstp);
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
} else {
// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
@ -367,11 +378,10 @@ private:
if (!hadDefault) {
// If there was no default, add a empty one, this greatly simplifies below code
// and constant propagation will just eliminate it for us later.
nodep->addItemsp(new AstCaseItem(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::LogicTrue()),
NULL));
nodep->addItemsp(new AstCaseItem(
nodep->fileline(), new AstConst(nodep->fileline(), AstConst::LogicTrue()), NULL));
}
if (debug()>=9) nodep->dumpTree(cout, " _comp_COND: ");
if (debug() >= 9) nodep->dumpTree(cout, " _comp_COND: ");
// Now build the IF statement tree
// The tree can be quite huge. Pull ever group of 8 out, and make a OR tree.
// This reduces the depth for the bottom elements, at the cost of
@ -382,46 +392,56 @@ private:
AstNode* grouprootp = NULL;
AstIf* groupnextp = NULL;
AstIf* itemnextp = NULL;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action.
if (istmtsp) istmtsp->unlinkFrBackWithNext();
// Expressioned clause
AstNode* ifexprp = itemp->condsp()->unlinkFrBack();
{ // Prepare for next group
{ // Prepare for next group
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
if (depth == 1) { // First group or starting new group
itemnextp = NULL;
AstIf* newp = new AstIf(itemp->fileline(),
ifexprp->cloneTree(true), NULL, NULL);
if (groupnextp) groupnextp->addElsesp(newp);
else grouprootp = newp;
AstIf* newp
= new AstIf(itemp->fileline(), ifexprp->cloneTree(true), NULL, NULL);
if (groupnextp) {
groupnextp->addElsesp(newp);
} else {
grouprootp = newp;
}
groupnextp = newp;
} else { // Continue group, modify if condition to OR in this new condition
AstNode* condp = groupnextp->condp()->unlinkFrBack();
groupnextp->condp(new AstOr(ifexprp->fileline(),
condp,
ifexprp->cloneTree(true)));
groupnextp->condp(
new AstOr(ifexprp->fileline(), condp, ifexprp->cloneTree(true)));
}
}
{ // Make the new lower IF and attach in the tree
AstNode* itemexprp = ifexprp; VL_DANGLING(ifexprp);
if (depth == (CASE_ENCODER_GROUP_DEPTH)) { // End of group - can skip the condition
{ // Make the new lower IF and attach in the tree
AstNode* itemexprp = ifexprp;
VL_DANGLING(ifexprp);
if (depth == CASE_ENCODER_GROUP_DEPTH) { // End of group - can skip the condition
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
}
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL);
if (itemnextp) itemnextp->addElsesp(newp);
else groupnextp->addIfsp(newp); // First in a new group
if (itemnextp) {
itemnextp->addElsesp(newp);
} else {
groupnextp->addIfsp(newp); // First in a new group
}
itemnextp = newp;
}
}
if (debug()>=9) nodep->dumpTree(cout, " _comp_TREE: ");
if (debug() >= 9) nodep->dumpTree(cout, " _comp_TREE: ");
// Handle any assertions
replaceCaseParallel(nodep, false);
// Replace the CASE... with IF...
if (debug()>=9 && grouprootp) grouprootp->dumpTree(cout, " _new: ");
if (grouprootp) nodep->replaceWith(grouprootp);
else nodep->unlinkFrBack();
if (debug() >= 9 && grouprootp) grouprootp->dumpTree(cout, " _new: ");
if (grouprootp) {
nodep->replaceWith(grouprootp);
} else {
nodep->unlinkFrBack();
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
@ -451,7 +471,7 @@ private:
virtual void visit(AstCase* nodep) VL_OVERRIDE {
V3Case::caseLint(nodep);
iterateChildren(nodep);
if (debug()>=9) nodep->dumpTree(cout, " case_old: ");
if (debug() >= 9) nodep->dumpTree(cout, " case_old: ");
if (isCaseTreeFast(nodep) && v3Global.opt.oCase()) {
// It's a simple priority encoder or complete statement
// we can make a tree of statements to avoid extra comparisons
@ -471,9 +491,7 @@ public:
m_caseWidth = 0;
m_caseItems = 0;
m_caseNoOverlapsAllCovered = false;
for (uint32_t i=0; i<(1UL<<CASE_OVERLAP_WIDTH); ++i) {
m_valueItem[i] = NULL;
}
for (uint32_t i = 0; i < (1UL << CASE_OVERLAP_WIDTH); ++i) m_valueItem[i] = NULL;
iterate(nodep);
}
virtual ~CaseVisitor() {
@ -486,13 +504,11 @@ public:
// Case class functions
void V3Case::caseAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
CaseVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ CaseVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("case", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Case::caseLint(AstNodeCase* nodep) {
UINFO(4,__FUNCTION__<<": "<<endl);
CaseLintVisitor visitor (nodep);
UINFO(4, __FUNCTION__ << ": " << endl);
CaseLintVisitor visitor(nodep);
}

View File

@ -55,7 +55,7 @@ private:
// NODE STATE
// Entire netlist:
// AstNode::user() // bool. Indicates node is of known size
AstUser1InUse m_inuser1;
AstUser1InUse m_inuser1;
// STATE
@ -63,26 +63,30 @@ private:
VL_DEBUG_FUNC; // Declare debug()
void insertCast(AstNode* nodep, int needsize) { // We'll insert ABOVE passed node
UINFO(4," NeedCast "<<nodep<<endl);
UINFO(4, " NeedCast " << nodep << endl);
AstNRelinker relinkHandle;
nodep->unlinkFrBack(&relinkHandle);
//
AstCCast* castp = new AstCCast(nodep->fileline(), nodep, needsize, nodep->widthMin());
relinkHandle.relink(castp);
//if (debug()>8) castp->dumpTree(cout, "-castins: ");
// if (debug() > 8) castp->dumpTree(cout, "-castins: ");
//
ensureLower32Cast(castp);
nodep->user1(1); // Now must be of known size
}
int castSize(AstNode* nodep) {
if (nodep->isQuad()) return VL_QUADSIZE;
else if (nodep->width() <= 8) return 8;
else if (nodep->width() <= 16) return 16;
else return VL_IDATASIZE;
if (nodep->isQuad()) {
return VL_QUADSIZE;
} else if (nodep->width() <= 8) {
return 8;
} else if (nodep->width() <= 16) {
return 16;
} else {
return VL_IDATASIZE;
}
}
void ensureCast(AstNode* nodep) {
if (castSize(nodep->backp()) != castSize(nodep)
|| !nodep->user1()) {
if (castSize(nodep->backp()) != castSize(nodep) || !nodep->user1()) {
insertCast(nodep, castSize(nodep->backp()));
}
}
@ -91,8 +95,7 @@ private:
// really needs to be CAST(uint64(CAST(uint32(x))).
// Otherwise a (uint64)(a>b) would return wrong value, as
// less than has nondeterministic signedness.
if (nodep->isQuad() && !nodep->lhsp()->isQuad()
&& !VN_IS(nodep->lhsp(), CCast)) {
if (nodep->isQuad() && !nodep->lhsp()->isQuad() && !VN_IS(nodep->lhsp(), CCast)) {
insertCast(nodep->lhsp(), VL_IDATASIZE);
}
}
@ -114,16 +117,13 @@ private:
}
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1()
| nodep->rhsp()->user1());
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
}
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1()
| nodep->rhsp()->user1()
| nodep->thsp()->user1());
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
@ -136,7 +136,7 @@ private:
virtual void visit(AstNegate* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1());
if (nodep->lhsp()->widthMin()==1) {
if (nodep->lhsp()->widthMin() == 1) {
// We want to avoid a GCC "converting of negative value" warning
// from our expansion of
// out = {32{a<b}} => out = - (a<b)
@ -146,11 +146,8 @@ private:
}
}
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (!nodep->lvalue()
&& !VN_IS(nodep->backp(), CCast)
&& VN_IS(nodep->backp(), NodeMath)
&& !VN_IS(nodep->backp(), ArraySel)
&& nodep->backp()->width()
if (!nodep->lvalue() && !VN_IS(nodep->backp(), CCast) && VN_IS(nodep->backp(), NodeMath)
&& !VN_IS(nodep->backp(), ArraySel) && nodep->backp()->width()
&& castSize(nodep) != castSize(nodep->varp())) {
// Cast vars to IData first, else below has upper bits wrongly set
// CData x=3; out = (QData)(x<<30);
@ -187,9 +184,7 @@ private:
public:
// CONSTRUCTORS
explicit CastVisitor(AstNetlist* nodep) {
iterate(nodep);
}
explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~CastVisitor() {}
};
@ -197,9 +192,7 @@ public:
// Cast class functions
void V3Cast::castAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
CastVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ CastVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("cast", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -40,7 +40,7 @@
#include <memory>
#include <vector>
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
//######################################################################
@ -53,18 +53,23 @@ public:
// Graph support classes
class CdcEitherVertex : public V3GraphVertex {
AstScope* m_scopep;
AstNode* m_nodep;
AstScope* m_scopep;
AstNode* m_nodep;
AstSenTree* m_srcDomainp;
AstSenTree* m_dstDomainp;
bool m_srcDomainSet:1;
bool m_dstDomainSet:1;
bool m_asyncPath:1;
bool m_srcDomainSet : 1;
bool m_dstDomainSet : 1;
bool m_asyncPath : 1;
public:
CdcEitherVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep)
: V3GraphVertex(graphp), m_scopep(scopep), m_nodep(nodep)
, m_srcDomainp(NULL), m_dstDomainp(NULL)
, m_srcDomainSet(false), m_dstDomainSet(false)
: V3GraphVertex(graphp)
, m_scopep(scopep)
, m_nodep(nodep)
, m_srcDomainp(NULL)
, m_dstDomainp(NULL)
, m_srcDomainSet(false)
, m_dstDomainSet(false)
, m_asyncPath(false) {}
virtual ~CdcEitherVertex() {}
// ACCESSORS
@ -85,18 +90,22 @@ public:
class CdcVarVertex : public CdcEitherVertex {
AstVarScope* m_varScp;
int m_cntAsyncRst;
bool m_fromFlop;
int m_cntAsyncRst;
bool m_fromFlop;
public:
CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: CdcEitherVertex(graphp, scopep, varScp)
, m_varScp(varScp), m_cntAsyncRst(0), m_fromFlop(false) {}
, m_varScp(varScp)
, m_cntAsyncRst(0)
, m_fromFlop(false) {}
virtual ~CdcVarVertex() {}
// ACCESSORS
AstVarScope* varScp() const { return m_varScp; }
virtual string name() const { return (cvtToHex(m_varScp)+" "+varScp()->name()); }
virtual string name() const { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
virtual string dotColor() const {
return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue"; }
return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue";
}
int cntAsyncRst() const { return m_cntAsyncRst; }
void cntAsyncRst(int flag) { m_cntAsyncRst = flag; }
bool fromFlop() const { return m_fromFlop; }
@ -104,19 +113,26 @@ public:
};
class CdcLogicVertex : public CdcEitherVertex {
bool m_hazard:1;
bool m_isFlop:1;
bool m_hazard : 1;
bool m_isFlop : 1;
public:
CdcLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstSenTree* sensenodep)
: CdcEitherVertex(graphp, scopep, nodep)
, m_hazard(false), m_isFlop(false)
{ srcDomainp(sensenodep); dstDomainp(sensenodep); }
, m_hazard(false)
, m_isFlop(false) {
srcDomainp(sensenodep);
dstDomainp(sensenodep);
}
virtual ~CdcLogicVertex() {}
// ACCESSORS
virtual string name() const { return (cvtToHex(nodep())+"@"+scopep()->prettyName()); }
virtual string name() const { return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); }
virtual string dotColor() const { return hazard() ? "black" : "yellow"; }
bool hazard() const { return m_hazard; }
void setHazard(AstNode* nodep) { m_hazard = true; nodep->user3(true); }
void setHazard(AstNode* nodep) {
m_hazard = true;
nodep->user3(true);
}
void clearHazard() { m_hazard = false; }
bool isFlop() const { return m_isFlop; }
void isFlop(bool flag) { m_isFlop = flag; }
@ -127,16 +143,19 @@ public:
class CdcDumpVisitor : public CdcBaseVisitor {
private:
// NODE STATE
//Entire netlist:
// Entire netlist:
// {statement}Node::user3 -> bool, indicating not hazard
std::ofstream* m_ofp; // Output file
string m_prefix;
string m_prefix;
virtual void visit(AstNode* nodep) VL_OVERRIDE {
*m_ofp<<m_prefix;
if (nodep->user3()) *m_ofp<<" %%";
else *m_ofp<<" ";
*m_ofp<<nodep->prettyTypeName()<<" "<<endl;
*m_ofp << m_prefix;
if (nodep->user3()) {
*m_ofp << " %%";
} else {
*m_ofp << " ";
}
*m_ofp << nodep->prettyTypeName() << " " << endl;
string lastPrefix = m_prefix;
m_prefix = lastPrefix + "1:";
iterateAndNextNull(nodep->op1p());
@ -163,19 +182,20 @@ public:
class CdcWidthVisitor : public CdcBaseVisitor {
private:
int m_maxLineno;
size_t m_maxFilenameLen;
int m_maxLineno;
size_t m_maxFilenameLen;
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
// Keeping line+filename lengths separate is much faster than calling ascii().length()
if (nodep->fileline()->lineno() >= m_maxLineno) {
m_maxLineno = nodep->fileline()->lineno()+1;
m_maxLineno = nodep->fileline()->lineno() + 1;
}
if (nodep->fileline()->filename().length() >= m_maxFilenameLen) {
m_maxFilenameLen = nodep->fileline()->filename().length()+1;
m_maxFilenameLen = nodep->fileline()->filename().length() + 1;
}
}
public:
// CONSTRUCTORS
explicit CdcWidthVisitor(AstNode* nodep) {
@ -201,32 +221,32 @@ public:
class CdcVisitor : public CdcBaseVisitor {
private:
// NODE STATE
//Entire netlist:
// Entire netlist:
// AstVarScope::user1p -> CdcVarVertex* for usage var, 0=not set yet
// AstVarScope::user2 -> bool Used in sensitivity list
// {statement}Node::user1p -> CdcLogicVertex* for this statement
// AstNode::user3 -> bool True indicates to print %% (via V3EmitV)
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
// STATE
V3Graph m_graph; // Scoreboard of var usages/dependencies
CdcLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored
AstScope* m_scopep; // Current scope being processed
AstNodeModule* m_modp; // Current module
AstSenTree* m_domainp; // Current sentree
bool m_inDly; // In delayed assign
int m_inSenItem; // Number of senitems
string m_ofFilename; // Output filename
std::ofstream* m_ofp; // Output file
uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices
int m_filelineWidth; // Characters in longest fileline
V3Graph m_graph; // Scoreboard of var usages/dependencies
CdcLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored
AstScope* m_scopep; // Current scope being processed
AstNodeModule* m_modp; // Current module
AstSenTree* m_domainp; // Current sentree
bool m_inDly; // In delayed assign
int m_inSenItem; // Number of senitems
string m_ofFilename; // Output filename
std::ofstream* m_ofp; // Output file
uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices
int m_filelineWidth; // Characters in longest fileline
// METHODS
void iterateNewStmt(AstNode* nodep) {
if (m_scopep) {
UINFO(4," STMT "<<nodep<<endl);
UINFO(4, " STMT " << nodep << endl);
m_logicVertexp = new CdcLogicVertex(&m_graph, m_scopep, nodep, m_domainp);
if (m_domainp && m_domainp->hasClocked()) { // To/from a flop
m_logicVertexp->isFlop(true);
@ -238,7 +258,7 @@ private:
iterateChildren(nodep);
m_logicVertexp = NULL;
if (0 && debug()>=9) {
if (0 && debug() >= 9) {
UINFO(9, "Trace Logic:\n");
nodep->dumpTree(cout, "-log1: ");
}
@ -248,15 +268,15 @@ private:
CdcVarVertex* makeVarVertex(AstVarScope* varscp) {
CdcVarVertex* vertexp = reinterpret_cast<CdcVarVertex*>(varscp->user1p());
if (!vertexp) {
UINFO(6,"New vertex "<<varscp<<endl);
UINFO(6, "New vertex " << varscp << endl);
vertexp = new CdcVarVertex(&m_graph, m_scopep, varscp);
varscp->user1p(vertexp);
if (varscp->varp()->isUsedClock()) {}
if (varscp->varp()->isPrimaryIO()) {
// Create IO vertex - note it's relative to the pointed to var, not where we are now
// This allows reporting to easily print the input statement
CdcLogicVertex* ioVertexp = new CdcLogicVertex(&m_graph, varscp->scopep(),
varscp->varp(), NULL);
// Create IO vertex - note it's relative to the pointed to var, not where we are
// now This allows reporting to easily print the input statement
CdcLogicVertex* ioVertexp
= new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), NULL);
if (varscp->varp()->isWritable()) {
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
} else {
@ -266,10 +286,10 @@ private:
}
if (m_inSenItem) {
varscp->user2(true); // It's like a clock...
// TODO: In the future we could mark it here and do normal clock tree glitch checks also
// TODO: In the future mark it here and do normal clock tree glitch checks also
} else if (varscp->user2()) { // It was detected in a sensitivity list earlier
// And now it's used as logic. So must be a reset.
vertexp->cntAsyncRst(vertexp->cntAsyncRst()+1);
vertexp->cntAsyncRst(vertexp->cntAsyncRst() + 1);
}
return vertexp;
}
@ -279,9 +299,9 @@ private:
nodep->v3warnCode(code, msg);
if (!told_file) {
told_file = 1;
std::cerr<<V3Error::msgPrefix()<<" See details in "<<m_ofFilename<<endl;
std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl;
}
*m_ofp<<"%Warning-"<<code.ascii()<<": "<<nodep->fileline()<<" "<<msg<<endl;
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << endl;
}
void setNodeHazard(AstNode* nodep) {
@ -291,28 +311,34 @@ private:
// an issue until we find a hitting flop.
// Furthermore, a module like a "Or" module would only get flagged
// once, even though the signals feeding it are radically different.
if (!m_domainp || m_domainp->hasCombo()) { // Source flop logic in a posedge block is OK for reset (not async though)
if (!m_domainp || m_domainp->hasCombo()) {
// Source flop logic in a posedge block is OK for reset (not async though)
if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) {
UINFO(8,"Set hazard "<<nodep<<endl);
UINFO(8, "Set hazard " << nodep << endl);
m_logicVertexp->setHazard(nodep);
}
}
}
string spaces(int level) { string out; while (level--) out += " "; return out; } // LCOV_EXCL_LINE
string spaces(int level) {
string out;
while (level--) out += " ";
return out;
} // LCOV_EXCL_LINE
string pad(unsigned column, const string& in) {
string out = in;
while (out.length()<column) out += ' ';
while (out.length() < column) out += ' ';
return out;
}
void analyze() {
UINFO(3,__FUNCTION__<<": "<<endl);
//if (debug()>6) m_graph.dump();
if (debug()>6) m_graph.dumpDotFilePrefixed("cdc_pre");
UINFO(3, __FUNCTION__ << ": " << endl);
// if (debug() > 6) m_graph.dump();
if (debug() > 6) m_graph.dumpDotFilePrefixed("cdc_pre");
//
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); // This will MAX across edge weights
m_graph.removeRedundantEdges(
&V3GraphEdge::followAlwaysTrue); // This will MAX across edge weights
//
m_graph.dumpDotFilePrefixed("cdc_simp");
//
@ -321,7 +347,7 @@ private:
int filelineWidth() {
if (!m_filelineWidth) {
CdcWidthVisitor visitor (v3Global.rootp());
CdcWidthVisitor visitor(v3Global.rootp());
m_filelineWidth = visitor.maxWidth();
}
return m_filelineWidth;
@ -334,15 +360,15 @@ private:
// Find all async reset wires, and trace backwards
// userClearVertices is very slow, so we use a generation count instead
m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
if (vvertexp->cntAsyncRst()) {
m_userGeneration++; // Effectively a userClearVertices()
UINFO(8, " Trace One async: "<<vvertexp<<endl);
UINFO(8, " Trace One async: " << vvertexp << endl);
// Twice, as we need to detect, then propagate
CdcEitherVertex* markp = traceAsyncRecurse(vvertexp, false);
if (markp) { // Mark is non-NULL if something bad on this path
UINFO(9, " Trace One bad! "<<vvertexp<<endl);
UINFO(9, " Trace One bad! " << vvertexp << endl);
m_userGeneration++; // Effectively a userClearVertices()
traceAsyncRecurse(vvertexp, true);
m_userGeneration++; // Effectively a userClearVertices()
@ -356,11 +382,11 @@ private:
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) {
// First pass: Return vertex of any hazardous stuff attached, or NULL if OK
// If first pass returns true, second pass calls asyncPath() on appropriate nodes
if (vertexp->user()>=m_userGeneration) return NULL; // Processed - prevent loop
if (vertexp->user() >= m_userGeneration) return NULL; // Processed - prevent loop
vertexp->user(m_userGeneration);
CdcEitherVertex* mark_outp = NULL;
UINFO(9," Trace: "<<vertexp<<endl);
UINFO(9, " Trace: " << vertexp << endl);
// Clear out in prep for marking next path
if (!mark) vertexp->asyncPath(false);
@ -369,8 +395,7 @@ private:
// Any logic considered bad, at the moment, anyhow
if (vvertexp->hazard() && !mark_outp) mark_outp = vvertexp;
// And keep tracing back so the user can understand what's up
}
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
} else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
if (mark) vvertexp->asyncPath(true);
// If primary I/O, it's ok here back
if (vvertexp->varScp()->varp()->isPrimaryInish()) {
@ -403,62 +428,60 @@ private:
void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) {
AstNode* nodep = vertexp->varScp();
*m_ofp<<"\n";
*m_ofp<<"\n";
*m_ofp << "\n";
*m_ofp << "\n";
CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many)
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
CdcEitherVertex* eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
if (!eToVertexp) targetp = eToVertexp;
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
if (vvertexp->isFlop() // IE the target flop that is upsetting us
&& edgep->weight() >= CDC_WEIGHT_ASYNC) { // And this signal feeds an async reset line
&& edgep->weight() >= CDC_WEIGHT_ASYNC) { // And var feeds an async reset line
targetp = eToVertexp;
//UINFO(9," targetasync "<<targetp->name()<<" "<<" from "<<vertexp->name()<<endl);
// UINFO(9," targetasync "<<targetp->name()<<" "<<" from
// "<<vertexp->name()<<endl);
break;
}
} // else it might be random logic that's not relevant
}
//UINFO(9," finalflop "<<targetp->name()<<" "<<targetp->nodep()->fileline()<<endl);
// UINFO(9," finalflop "<<targetp->name()<<" "<<targetp->nodep()->fileline()<<endl);
warnAndFile(markp->nodep(), V3ErrorCode::CDCRSTLOGIC,
"Logic in path that feeds async reset, via signal: "+nodep->prettyNameQ());
"Logic in path that feeds async reset, via signal: " + nodep->prettyNameQ());
dumpAsyncRecurse(targetp, "", " ", 0);
}
bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix,
const string& sep, int level) {
bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& sep,
int level) {
// level=0 is special, indicates to dump destination flop
// Return true if printed anything
// If mark, also mark the output even if nothing hazardous below
if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop
if (vertexp->user() >= m_userGeneration) return false; // Processed - prevent loop
vertexp->user(m_userGeneration);
if (!vertexp->asyncPath() && level!=0) return false; // Not part of path
if (!vertexp->asyncPath() && level != 0) return false; // Not part of path
// Other logic in the path
string cont = prefix+sep;
string cont = prefix + sep;
string nextsep = " ";
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level+1)) {
nextsep = " | ";
}
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level + 1)) nextsep = " | ";
}
// Dump single variable/logic block
// See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp)
AstNode* nodep = vertexp->nodep();
string front = pad(filelineWidth(), nodep->fileline()->ascii()+":")+" "+prefix+" +- ";
string front
= pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- ";
if (VN_IS(nodep, VarScope)) {
*m_ofp<<front<<"Variable: "<<nodep->prettyName()<<endl;
}
else {
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix+" +- ", filelineWidth(),
*m_ofp << front << "Variable: " << nodep->prettyName() << endl;
} else {
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix + " +- ", filelineWidth(),
vertexp->srcDomainp(), true);
if (debug()) {
CdcDumpVisitor visitor (nodep, m_ofp, front+"DBG: ");
}
if (debug()) { CdcDumpVisitor visitor(nodep, m_ofp, front + "DBG: "); }
}
nextsep = " | ";
if (level) *m_ofp<<V3OutFile::indentSpaces(filelineWidth())<<" "<<prefix<<nextsep<<"\n";
if (level)
*m_ofp << V3OutFile::indentSpaces(filelineWidth()) << " " << prefix << nextsep << "\n";
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
// Now that we've printed a path with this hazard, don't bother to print any more
@ -479,27 +502,27 @@ private:
// module. Disabling flattening though makes us consider each
// signal in it's own unique clock domain.
UINFO(3,__FUNCTION__<<": "<<endl);
UINFO(3, __FUNCTION__ << ": " << endl);
// Trace all sources and sinks
for (int traceDests=0; traceDests<2; ++traceDests) {
UINFO(9, " Trace Direction "<<(traceDests?"dst":"src")<<endl);
for (int traceDests = 0; traceDests < 2; ++traceDests) {
UINFO(9, " Trace Direction " << (traceDests ? "dst" : "src") << endl);
m_graph.userClearVertices(); // user1: bool - was analyzed
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
UINFO(9, " Trace One edge: "<<vvertexp<<endl);
UINFO(9, " Trace One edge: " << vvertexp << endl);
edgeDomainRecurse(vvertexp, traceDests, 0);
}
}
}
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc_edges.txt";
const vl_unique_ptr<std::ofstream> ofp (V3File::new_ofstream(filename));
if (ofp->fail()) v3fatal("Can't write "<<filename);
*ofp<<"Edge Report for "<<v3Global.opt.prefix()<<endl;
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc_edges.txt";
const vl_unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
if (ofp->fail()) v3fatal("Can't write " << filename);
*ofp << "Edge Report for " << v3Global.opt.prefix() << endl;
std::deque<string> report; // Sort output by name
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
AstVar* varp = vvertexp->varScp()->varp();
{
@ -511,46 +534,50 @@ private:
// Module name - doesn't work due to flattening having lost the original
// so we assume the modulename matches the filebasename
string fname = vvertexp->varScp()->fileline()->filebasename() + ":";
os<<" "<<std::setw(20)<<fname;
os<<" "<<std::setw(8)<<what;
os<<" "<<std::setw(40)<<vvertexp->varScp()->prettyName();
os<<" SRC=";
if (vvertexp->srcDomainp()) V3EmitV::verilogForTree(vvertexp->srcDomainp(), os);
os<<" DST=";
if (vvertexp->dstDomainp()) V3EmitV::verilogForTree(vvertexp->dstDomainp(), os);
os<<std::setw(0);
os<<endl;
os << " " << std::setw(20) << fname;
os << " " << std::setw(8) << what;
os << " " << std::setw(40) << vvertexp->varScp()->prettyName();
os << " SRC=";
if (vvertexp->srcDomainp()) {
V3EmitV::verilogForTree(vvertexp->srcDomainp(), os);
}
os << " DST=";
if (vvertexp->dstDomainp()) {
V3EmitV::verilogForTree(vvertexp->dstDomainp(), os);
}
os << std::setw(0);
os << endl;
report.push_back(os.str());
}
}
}
stable_sort(report.begin(), report.end());
for (std::deque<string>::iterator it = report.begin(); it!=report.end(); ++it) {
for (std::deque<string>::iterator it = report.begin(); it != report.end(); ++it) {
*ofp << *it;
}
}
void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) {
// Scan back to inputs/outputs, flops, and compute clock domain information
UINFO(8,spaces(level)<<" Tracein "<<vertexp<<endl);
if (vertexp->user()>=m_userGeneration) return; // Mid-Processed - prevent loop
UINFO(8, spaces(level) << " Tracein " << vertexp << endl);
if (vertexp->user() >= m_userGeneration) return; // Mid-Processed - prevent loop
vertexp->user(m_userGeneration);
// Variables from flops already are domained
if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) return; // Fully computed
if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) {
return;
} // Fully computed
typedef std::set<AstSenTree*> SenSet;
SenSet senouts; // List of all sensitivities for new signal
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
if (vvertexp) {} // Unused
}
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
} else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
// If primary I/O, give it domain of the input
AstVar* varp = vvertexp->varScp()->varp();
if (varp->isPrimaryIO() && varp->isNonOutput() && !traceDests) {
senouts.insert(
new AstSenTree(varp->fileline(),
new AstSenItem(varp->fileline(), AstSenItem::Combo())));
senouts.insert(new AstSenTree(
varp->fileline(), new AstSenItem(varp->fileline(), AstSenItem::Combo())));
}
}
@ -558,23 +585,24 @@ private:
if (traceDests) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
CdcEitherVertex* eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
edgeDomainRecurse(eToVertexp, traceDests, level+1);
edgeDomainRecurse(eToVertexp, traceDests, level + 1);
if (eToVertexp->dstDomainp()) senouts.insert(eToVertexp->dstDomainp());
}
} else {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
edgeDomainRecurse(eFromVertexp, traceDests, level+1);
edgeDomainRecurse(eFromVertexp, traceDests, level + 1);
if (eFromVertexp->srcDomainp()) senouts.insert(eFromVertexp->srcDomainp());
}
}
// Convert list of senses into one sense node
AstSenTree* senoutp = NULL;
bool senedited = false;
for (SenSet::iterator it=senouts.begin(); it!=senouts.end(); ++it) {
if (!senoutp) senoutp = *it;
else {
bool senedited = false;
for (SenSet::iterator it = senouts.begin(); it != senouts.end(); ++it) {
if (!senoutp) {
senoutp = *it;
} else {
if (!senedited) {
senedited = true;
senoutp = senoutp->cloneTree(true);
@ -583,22 +611,26 @@ private:
}
}
// If multiple domains need to do complicated optimizations
if (senedited) {
senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree);
}
if (senedited) { senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree); }
if (traceDests) {
vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that
vertexp->dstDomainp(senoutp);
if (debug()>=9) {
UINFO(9,spaces(level)+" Tracedst "<<vertexp);
if (senoutp) { V3EmitV::verilogForTree(senoutp, cout); cout<<endl; }
if (debug() >= 9) {
UINFO(9, spaces(level) + " Tracedst " << vertexp);
if (senoutp) {
V3EmitV::verilogForTree(senoutp, cout);
cout << endl;
}
}
} else {
vertexp->srcDomainSet(true); // Note it's set - domainp may be null, so can't use that
vertexp->srcDomainp(senoutp);
if (debug()>=9) {
UINFO(9,spaces(level)+" Tracesrc "<<vertexp);
if (senoutp) { V3EmitV::verilogForTree(senoutp, cout); cout<<endl; }
if (debug() >= 9) {
UINFO(9, spaces(level) + " Tracesrc " << vertexp);
if (senoutp) {
V3EmitV::verilogForTree(senoutp, cout);
cout << endl;
}
}
}
}
@ -613,7 +645,7 @@ private:
m_modp = origModp;
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
UINFO(4," SCOPE "<<nodep<<endl);
UINFO(4, " SCOPE " << nodep << endl);
m_scopep = nodep;
m_logicVertexp = NULL;
iterateChildren(nodep);
@ -621,10 +653,11 @@ private:
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
// Create required blocks and add to module
UINFO(4," BLOCK "<<nodep<<endl);
UINFO(4, " BLOCK " << nodep << endl);
AstNode::user2ClearTree();
m_domainp = nodep->sensesp();
if (!m_domainp || m_domainp->hasCombo() || m_domainp->hasClocked()) { // IE not hasSettle/hasInitial
if (!m_domainp || m_domainp->hasCombo()
|| m_domainp->hasClocked()) { // IE not hasSettle/hasInitial
iterateNewStmt(nodep);
}
m_domainp = NULL;
@ -636,7 +669,7 @@ private:
AstVarScope* varscp = nodep->varScopep();
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
CdcVarVertex* varvertexp = makeVarVertex(varscp);
UINFO(5," VARREF to "<<varscp<<endl);
UINFO(5, " VARREF to " << varscp << endl);
// We use weight of one for normal edges,
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
// When simplify we'll take the MAX weight
@ -649,10 +682,10 @@ private:
}
} else {
if (varvertexp->cntAsyncRst()) {
//UINFO(9," edgeasync "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
// UINFO(9," edgeasync "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
new V3GraphEdge(&m_graph, varvertexp, m_logicVertexp, CDC_WEIGHT_ASYNC);
} else {
//UINFO(9," edgena "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
// UINFO(9," edgena "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
new V3GraphEdge(&m_graph, varvertexp, m_logicVertexp, 1);
}
}
@ -670,38 +703,24 @@ private:
iterateChildren(nodep);
m_inSenItem = false;
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
iterateNewStmt(nodep);
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
// CDC doesn't care about public variables
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
iterateNewStmt(nodep);
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
// First handle the clock part will be handled in a minute by visit AstSenItem
// The logic gating term is dealt with as logic
iterateNewStmt(nodep);
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
iterateNewStmt(nodep);
}
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
iterateNewStmt(nodep);
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
// Math that shouldn't cause us to clear hazard
virtual void visit(AstConst*) VL_OVERRIDE {}
virtual void visit(AstReplicate* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstNot* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstReplicate* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstConcat* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNot* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstSel* nodep) VL_OVERRIDE {
if (!VN_IS(nodep->lsbp(), Const)) setNodeHazard(nodep);
iterateChildren(nodep);
@ -738,15 +757,16 @@ public:
m_filelineWidth = 0;
// Make report of all signal names and what clock edges they have
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc.txt";
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc.txt";
m_ofp = V3File::new_ofstream(filename);
if (m_ofp->fail()) v3fatal("Can't write "<<filename);
if (m_ofp->fail()) v3fatal("Can't write " << filename);
m_ofFilename = filename;
*m_ofp<<"CDC Report for "<<v3Global.opt.prefix()<<endl;
*m_ofp<<"Each dump below traces logic from inputs/source flops to destination flop(s).\n";
*m_ofp<<"First source logic is listed, then a variable that logic generates,\n";
*m_ofp<<"repeating recursively forwards to the destination flop(s).\n";
*m_ofp<<"%% Indicates the operator considered potentially hazardous.\n";
*m_ofp << "CDC Report for " << v3Global.opt.prefix() << endl;
*m_ofp
<< "Each dump below traces logic from inputs/source flops to destination flop(s).\n";
*m_ofp << "First source logic is listed, then a variable that logic generates,\n";
*m_ofp << "repeating recursively forwards to the destination flop(s).\n";
*m_ofp << "%% Indicates the operator considered potentially hazardous.\n";
iterate(nodep);
analyze();
@ -766,6 +786,6 @@ public:
// Cdc class functions
void V3Cdc::cdcAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
CdcVisitor visitor (nodep);
UINFO(2, __FUNCTION__ << ": " << endl);
CdcVisitor visitor(nodep);
}

View File

@ -43,12 +43,12 @@
class ChangedState {
public:
// STATE
AstNodeModule* m_topModp; // Top module
AstScope* m_scopetopp; // Scope under TOPSCOPE
AstCFunc* m_chgFuncp; // Change function we're building
AstCFunc* m_tlChgFuncp; // Top level change function we're building
int m_numStmts; // Number of statements added to m_chgFuncp
int m_funcNum; // Number of change functions emitted
AstNodeModule* m_topModp; // Top module
AstScope* m_scopetopp; // Scope under TOPSCOPE
AstCFunc* m_chgFuncp; // Change function we're building
AstCFunc* m_tlChgFuncp; // Top level change function we're building
int m_numStmts; // Number of statements added to m_chgFuncp
int m_funcNum; // Number of change functions emitted
ChangedState() {
m_topModp = NULL;
@ -67,9 +67,9 @@ public:
return;
}
if (!m_chgFuncp || v3Global.opt.outputSplitCFuncs() < m_numStmts) {
m_chgFuncp = new AstCFunc(m_scopetopp->fileline(),
"_change_request_" + cvtToStr(++m_funcNum),
m_scopetopp, "QData");
m_chgFuncp
= new AstCFunc(m_scopetopp->fileline(), "_change_request_" + cvtToStr(++m_funcNum),
m_scopetopp, "QData");
m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
m_chgFuncp->symProlog(true);
m_chgFuncp->declPrivate(true);
@ -89,9 +89,9 @@ public:
// we want and is similar to the logic already in use inside
// V3EmitC, however, it also means that verbose logging may
// miss to print change detect variables.
AstNode* newp = new AstCReturn(m_scopetopp->fileline(),
new AstLogOr(m_scopetopp->fileline(), callp,
returnp->lhsp()->unlinkFrBack()));
AstNode* newp = new AstCReturn(
m_scopetopp->fileline(),
new AstLogOr(m_scopetopp->fileline(), callp, returnp->lhsp()->unlinkFrBack()));
returnp->replaceWith(newp);
VL_DO_DANGLING(returnp->deleteTree(), returnp);
}
@ -106,57 +106,57 @@ public:
class ChangedInsertVisitor : public AstNVisitor {
private:
// STATE
ChangedState* m_statep; // Shared state across visitors
AstVarScope* m_vscp; // Original (non-change) variable we're change-detecting
AstVarScope* m_newvscp; // New (change detect) variable we're change-detecting
AstNode* m_varEqnp; // Original var's equation to get var value
AstNode* m_newLvEqnp; // New var's equation to read value
AstNode* m_newRvEqnp; // New var's equation to set value
uint32_t m_detects; // # detects created
ChangedState* m_statep; // Shared state across visitors
AstVarScope* m_vscp; // Original (non-change) variable we're change-detecting
AstVarScope* m_newvscp; // New (change detect) variable we're change-detecting
AstNode* m_varEqnp; // Original var's equation to get var value
AstNode* m_newLvEqnp; // New var's equation to read value
AstNode* m_newRvEqnp; // New var's equation to set value
uint32_t m_detects; // # detects created
// CONSTANTS
enum MiscConsts {
DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error
DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error
// Ok to increase this, but may result in much slower model
};
void newChangeDet() {
if (++m_detects > DETECTARRAY_MAX_INDEXES) {
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "
<<cvtToStr(DETECTARRAY_MAX_INDEXES)
<<" array indexes (probably with UNOPTFLAT warning suppressed): "
<<m_vscp->prettyName()<<endl
<<m_vscp->warnMore()
<<"... Could recompile with DETECTARRAY_MAX_INDEXES increased"<<endl);
m_vscp->v3warn(E_DETECTARRAY,
"Unsupported: Can't detect more than "
<< cvtToStr(DETECTARRAY_MAX_INDEXES)
<< " array indexes (probably with UNOPTFLAT warning suppressed): "
<< m_vscp->prettyName() << endl
<< m_vscp->warnMore()
<< "... Could recompile with DETECTARRAY_MAX_INDEXES increased"
<< endl);
return;
}
m_statep->maybeCreateChgFuncp();
AstChangeDet* changep = new AstChangeDet(m_vscp->fileline(),
m_varEqnp->cloneTree(true),
AstChangeDet* changep = new AstChangeDet(m_vscp->fileline(), m_varEqnp->cloneTree(true),
m_newRvEqnp->cloneTree(true), false);
m_statep->m_chgFuncp->addStmtsp(changep);
AstAssign* initp = new AstAssign(m_vscp->fileline(),
m_newLvEqnp->cloneTree(true),
AstAssign* initp = new AstAssign(m_vscp->fileline(), m_newLvEqnp->cloneTree(true),
m_varEqnp->cloneTree(true));
m_statep->m_chgFuncp->addFinalsp(initp);
EmitCBaseCounterVisitor visitor(initp);
m_statep->m_numStmts += visitor.count();
}
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE { //
newChangeDet();
}
virtual void visit(AstPackArrayDType* nodep) VL_OVERRIDE {
virtual void visit(AstPackArrayDType* nodep) VL_OVERRIDE { //
newChangeDet();
}
virtual void visit(AstUnpackArrayDType* nodep) VL_OVERRIDE {
for (int index=0; index < nodep->elementsConst(); ++index) {
for (int index = 0; index < nodep->elementsConst(); ++index) {
AstNode* origVEp = m_varEqnp;
AstNode* origNLEp = m_newLvEqnp;
AstNode* origNREp = m_newRvEqnp;
m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index);
m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index);
m_newLvEqnp = new AstArraySel(nodep->fileline(), m_newLvEqnp->cloneTree(true), index);
m_newRvEqnp = new AstArraySel(nodep->fileline(), m_newRvEqnp->cloneTree(true), index);
@ -166,7 +166,7 @@ private:
m_newLvEqnp->deleteTree();
m_newRvEqnp->deleteTree();
m_varEqnp = origVEp;
m_varEqnp = origVEp;
m_newLvEqnp = origNLEp;
m_newRvEqnp = origNREp;
}
@ -177,17 +177,18 @@ private:
} else {
if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-class-");
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
" (probably with UNOPTFLAT warning suppressed): "
<<m_vscp->varp()->prettyNameQ());
" (probably with UNOPTFLAT warning suppressed): "
<< m_vscp->varp()->prettyNameQ());
}
}
virtual void visit(AstNode* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-general-");
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
" (probably with UNOPTFLAT warning suppressed): "
<<m_vscp->varp()->prettyNameQ());
" (probably with UNOPTFLAT warning suppressed): "
<< m_vscp->varp()->prettyNameQ());
}
public:
// CONSTRUCTORS
ChangedInsertVisitor(AstVarScope* vscp, ChangedState* statep) {
@ -196,19 +197,19 @@ public:
m_detects = 0;
{
AstVar* varp = m_vscp->varp();
string newvarname = ("__Vchglast__"+m_vscp->scopep()->nameDotless()
+"__"+varp->shortName());
string newvarname
= ("__Vchglast__" + m_vscp->scopep()->nameDotless() + "__" + varp->shortName());
// Create: VARREF(_last)
// ASSIGN(VARREF(_last), VARREF(var))
// ...
// CHANGEDET(VARREF(_last), VARREF(var))
AstVar* newvarp = new AstVar(varp->fileline(), AstVarType::MODULETEMP,
newvarname, varp);
AstVar* newvarp
= new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
m_statep->m_topModp->addStmtp(newvarp);
m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp);
m_statep->m_scopetopp->addVarp(m_newvscp);
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true);
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false);
}
@ -229,41 +230,38 @@ private:
// NODE STATE
// Entire netlist:
// AstVarScope::user1() -> bool. True indicates processed
AstUser1InUse m_inuser1;
AstUser1InUse m_inuser1;
// STATE
ChangedState* m_statep; // Shared state across visitors
ChangedState* m_statep; // Shared state across visitors
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void genChangeDet(AstVarScope* vscp) {
vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: "<<vscp->prettyNameQ());
ChangedInsertVisitor visitor (vscp, m_statep);
vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: " << vscp->prettyNameQ());
ChangedInsertVisitor visitor(vscp, m_statep);
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
UINFO(4," MOD "<<nodep<<endl);
if (nodep->isTop()) {
m_statep->m_topModp = nodep;
}
UINFO(4, " MOD " << nodep << endl);
if (nodep->isTop()) m_statep->m_topModp = nodep;
iterateChildren(nodep);
}
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
UINFO(4," TS "<<nodep<<endl);
UINFO(4, " TS " << nodep << endl);
// Clearing
AstNode::user1ClearTree();
// Create the change detection function
AstScope* scopep = nodep->scopep();
UASSERT_OBJ(scopep, nodep,
"No scope found on top level, perhaps you have no statements?");
UASSERT_OBJ(scopep, nodep, "No scope found on top level, perhaps you have no statements?");
m_statep->m_scopetopp = scopep;
// Create a wrapper change detection function that calls each change detection function
m_statep->m_tlChgFuncp = new AstCFunc(nodep->fileline(),
"_change_request", scopep, "QData");
m_statep->m_tlChgFuncp
= new AstCFunc(nodep->fileline(), "_change_request", scopep, "QData");
m_statep->m_tlChgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
m_statep->m_tlChgFuncp->symProlog(true);
m_statep->m_tlChgFuncp->declPrivate(true);
@ -277,10 +275,8 @@ private:
}
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
if (nodep->isCircular()) {
UINFO(8," CIRC "<<nodep<<endl);
if (!nodep->user1SetOnce()) {
genChangeDet(nodep);
}
UINFO(8, " CIRC " << nodep << endl);
if (!nodep->user1SetOnce()) genChangeDet(nodep);
}
}
//--------------------
@ -300,10 +296,10 @@ public:
// Changed class functions
void V3Changed::changedAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
{
ChangedState state;
ChangedVisitor visitor (nodep, &state);
ChangedVisitor visitor(nodep, &state);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -43,9 +43,9 @@ private:
// AstNode::user() -> CleanState. For this node, 0==UNKNOWN
// AstNode::user2() -> bool. True indicates widthMin has been propagated
// AstNodeDType::user3() -> AstNodeDType*. Alternative node with C size
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
// TYPES
enum CleanState { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
@ -57,10 +57,14 @@ private:
VL_DEBUG_FUNC; // Declare debug()
// Width resetting
int cppWidth(AstNode* nodep) {
if (nodep->width() <= VL_IDATASIZE) return VL_IDATASIZE;
else if (nodep->width() <= VL_QUADSIZE) return VL_QUADSIZE;
else return nodep->widthWords() * VL_EDATASIZE;
int cppWidth(AstNode* nodep) {
if (nodep->width() <= VL_IDATASIZE) {
return VL_IDATASIZE;
} else if (nodep->width() <= VL_QUADSIZE) {
return VL_QUADSIZE;
} else {
return nodep->widthWords() * VL_EDATASIZE;
}
}
void setCppWidth(AstNode* nodep) {
nodep->user2(true); // Don't resize it again
@ -82,7 +86,8 @@ private:
}
void computeCppWidth(AstNode* nodep) {
if (!nodep->user2() && nodep->hasDType()) {
if (VN_IS(nodep, Var) || VN_IS(nodep, NodeDType) // Don't want to change variable widths!
if (VN_IS(nodep, Var)
|| VN_IS(nodep, NodeDType) // Don't want to change variable widths!
|| VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays
|| VN_IS(nodep->dtypep()->skipRefp(), DynArrayDType)
|| VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType)
@ -96,39 +101,33 @@ private:
}
// Store the clean state in the userp on each node
void setCleanState(AstNode* nodep, CleanState clean) {
nodep->user1(clean);
}
CleanState getCleanState(AstNode* nodep) {
return static_cast<CleanState>(nodep->user1());
}
void setCleanState(AstNode* nodep, CleanState clean) { nodep->user1(clean); }
CleanState getCleanState(AstNode* nodep) { return static_cast<CleanState>(nodep->user1()); }
bool isClean(AstNode* nodep) {
CleanState clstate = getCleanState(nodep);
if (clstate==CS_CLEAN) return true;
if (clstate==CS_DIRTY) return false;
nodep->v3fatalSrc("Unknown clean state on node: "+nodep->prettyTypeName());
if (clstate == CS_CLEAN) return true;
if (clstate == CS_DIRTY) return false;
nodep->v3fatalSrc("Unknown clean state on node: " + nodep->prettyTypeName());
return false;
}
void setClean(AstNode* nodep, bool isClean) {
computeCppWidth(nodep); // Just to be sure it's in widthMin
bool wholeUint = (nodep->widthMin() == VL_IDATASIZE
|| nodep->widthMin() == VL_QUADSIZE
bool wholeUint = (nodep->widthMin() == VL_IDATASIZE || nodep->widthMin() == VL_QUADSIZE
|| (nodep->widthMin() % VL_EDATASIZE) == 0);
setCleanState(nodep, ((isClean || wholeUint) ? CS_CLEAN : CS_DIRTY));
}
// Operate on nodes
void insertClean(AstNode* nodep) { // We'll insert ABOVE passed node
UINFO(4," NeedClean "<<nodep<<endl);
UINFO(4, " NeedClean " << nodep << endl);
AstNRelinker relinkHandle;
nodep->unlinkFrBack(&relinkHandle);
//
computeCppWidth(nodep);
V3Number mask (nodep, cppWidth(nodep));
V3Number mask(nodep, cppWidth(nodep));
mask.setMask(nodep->widthMin());
AstNode* cleanp = new AstAnd(nodep->fileline(),
new AstConst(nodep->fileline(), mask),
nodep);
AstNode* cleanp
= new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), mask), nodep);
cleanp->dtypeFrom(nodep); // Otherwise the AND normally picks LHS
relinkHandle.relink(cleanp);
}
@ -138,7 +137,7 @@ private:
}
void ensureCleanAndNext(AstNode* nodep) {
// Editing list, careful looping!
for (AstNode* exprp = nodep; exprp; ) {
for (AstNode* exprp = nodep; exprp;) {
AstNode* nextp = exprp->nextp();
ensureClean(exprp);
exprp = nextp;
@ -149,27 +148,17 @@ private:
void operandBiop(AstNodeBiop* nodep) {
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanLhs()) {
ensureClean(nodep->lhsp());
}
if (nodep->cleanRhs()) {
ensureClean(nodep->rhsp());
}
//no setClean.. must do it in each user routine.
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
// no setClean.. must do it in each user routine.
}
void operandTriop(AstNodeTriop* nodep) {
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanLhs()) {
ensureClean(nodep->lhsp());
}
if (nodep->cleanRhs()) {
ensureClean(nodep->rhsp());
}
if (nodep->cleanThs()) {
ensureClean(nodep->thsp());
}
//no setClean.. must do it in each user routine.
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
if (nodep->cleanThs()) ensureClean(nodep->thsp());
// no setClean.. must do it in each user routine.
}
// VISITORS
@ -184,9 +173,7 @@ private:
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanLhs()) {
ensureClean(nodep->lhsp());
}
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
@ -213,14 +200,12 @@ private:
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanRhs()) {
ensureClean(nodep->rhsp());
}
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
}
virtual void visit(AstText* nodep) VL_OVERRIDE {
virtual void visit(AstText* nodep) VL_OVERRIDE { //
setClean(nodep, true);
}
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
virtual void visit(AstScopeName* nodep) VL_OVERRIDE { //
setClean(nodep, true);
}
virtual void visit(AstCNew* nodep) VL_OVERRIDE {
@ -236,9 +221,7 @@ private:
computeCppWidth(nodep);
setClean(nodep, false);
// We always clean, as we don't trust those pesky users.
if (!VN_IS(nodep->backp(), And)) {
insertClean(nodep);
}
if (!VN_IS(nodep->backp(), And)) insertClean(nodep);
ensureCleanAndNext(nodep->bodysp());
}
virtual void visit(AstTraceDecl* nodep) VL_OVERRIDE {
@ -316,9 +299,7 @@ public:
// Clean class functions
void V3Clean::cleanAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
CleanVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ CleanVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("clean", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -46,22 +46,22 @@ private:
// NODE STATE
// Cleared each Module:
// AstVarScope::user1p() -> AstVarScope*. Temporary signal that was created.
AstUser1InUse m_inuser1;
AstUser1InUse m_inuser1;
// TYPES
enum { DOUBLE_OR_RATE = 10 }; // How many | per ||, Determined experimentally as best
// STATE
AstNodeModule* m_modp; // Current module
AstTopScope* m_topScopep; // Current top scope
AstScope* m_scopep; // Current scope
AstCFunc* m_evalFuncp; // Top eval function we are creating
AstCFunc* m_initFuncp; // Top initial function we are creating
AstCFunc* m_finalFuncp; // Top final function we are creating
AstCFunc* m_settleFuncp; // Top settlement function we are creating
AstSenTree* m_lastSenp; // Last sensitivity match, so we can detect duplicates.
AstIf* m_lastIfp; // Last sensitivity if active to add more under
AstMTaskBody* m_mtaskBodyp; // Current mtask body
AstNodeModule* m_modp; // Current module
AstTopScope* m_topScopep; // Current top scope
AstScope* m_scopep; // Current scope
AstCFunc* m_evalFuncp; // Top eval function we are creating
AstCFunc* m_initFuncp; // Top initial function we are creating
AstCFunc* m_finalFuncp; // Top final function we are creating
AstCFunc* m_settleFuncp; // Top settlement function we are creating
AstSenTree* m_lastSenp; // Last sensitivity match, so we can detect duplicates.
AstIf* m_lastIfp; // Last sensitivity if active to add more under
AstMTaskBody* m_mtaskBodyp; // Current mtask body
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -69,12 +69,14 @@ private:
AstVarScope* getCreateLastClk(AstVarScope* vscp) {
if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p());
AstVar* varp = vscp->varp();
if (!varp->width1()) varp->v3error("Unsupported: Clock edge on non-single bit signal: "
<<varp->prettyNameQ());
string newvarname = (string("__Vclklast__")
+vscp->scopep()->nameDotless()+"__"+varp->name());
AstVar* newvarp = new AstVar(vscp->fileline(),
AstVarType::MODULETEMP, newvarname, VFlagLogicPacked(), 1);
if (!varp->width1()) {
varp->v3error(
"Unsupported: Clock edge on non-single bit signal: " << varp->prettyNameQ());
}
string newvarname
= (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name());
AstVar* newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname,
VFlagLogicPacked(), 1);
newvarp->noReset(true); // Reset by below assign
m_modp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
@ -83,18 +85,16 @@ private:
// Add init
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false);
if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
AstNode* newinitp = new AstAssign(vscp->fileline(),
new AstVarRef(newvarp->fileline(), newvscp, true),
fromp);
AstNode* newinitp = new AstAssign(
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, true), fromp);
addToInitial(newinitp);
// At bottom, assign them
AstAssign* finalp
= new AstAssign(vscp->fileline(),
new AstVarRef(vscp->fileline(), newvscp, true),
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
new AstVarRef(vscp->fileline(), vscp, false));
m_evalFuncp->addFinalsp(finalp);
//
UINFO(4,"New Last: "<<newvscp<<endl);
UINFO(4, "New Last: " << newvscp << endl);
return newvscp;
}
AstNode* createSenItemEquation(AstSenItem* nodep) {
@ -106,49 +106,44 @@ private:
// HIGHEDGE: var
// LOWEDGE: ~var
AstNode* newp = NULL;
if (nodep->edgeType()==VEdgeType::ET_ILLEGAL) {
if (nodep->edgeType() == VEdgeType::ET_ILLEGAL) {
if (!v3Global.opt.bboxUnsup()) {
nodep->v3error("Unsupported: Complicated event expression in sensitive activity list");
nodep->v3error(
"Unsupported: Complicated event expression in sensitive activity list");
}
return NULL;
}
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
if (nodep->edgeType() == VEdgeType::ET_POSEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(nodep->fileline(),
new AstVarRef(nodep->fileline(),
nodep->varrefp()->varScopep(), false),
new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(),
lastVscp, false)));
newp = new AstAnd(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), lastVscp, false)));
} else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(nodep->fileline(),
new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(),
nodep->varrefp()->varScopep(), false)),
new AstVarRef(nodep->fileline(), lastVscp, false));
newp = new AstAnd(
nodep->fileline(),
new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false)),
new AstVarRef(nodep->fileline(), lastVscp, false));
} else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
newp = new AstXor(nodep->fileline(),
new AstVarRef(nodep->fileline(),
nodep->varrefp()->varScopep(), false),
new AstVarRef(nodep->fileline(), lastVscp, false));
newp = new AstXor(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
new AstVarRef(nodep->fileline(), lastVscp, false));
} else if (nodep->edgeType() == VEdgeType::ET_HIGHEDGE) {
newp = new AstVarRef(nodep->fileline(),
clkvscp, false);
newp = new AstVarRef(nodep->fileline(), clkvscp, false);
} else if (nodep->edgeType() == VEdgeType::ET_LOWEDGE) {
newp = new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(),
clkvscp, false));
newp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), clkvscp, false));
} else {
nodep->v3fatalSrc("Bad edge type");
}
return newp;
}
AstNode* createSenGateEquation(AstSenGate* nodep) {
AstNode* newp = new AstAnd(nodep->fileline(),
createSenseEquation(nodep->sensesp()),
AstNode* newp = new AstAnd(nodep->fileline(), createSenseEquation(nodep->sensesp()),
nodep->rhsp()->cloneTree(true));
return newp;
}
@ -186,12 +181,12 @@ private:
// VISITORS
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
UINFO(4," TOPSCOPE "<<nodep<<endl);
UINFO(4, " TOPSCOPE " << nodep << endl);
m_topScopep = nodep;
m_scopep = nodep->scopep();
UASSERT_OBJ(m_scopep, nodep,
"No scope found on top level, perhaps you have no statements?");
//VV***** We reset all user1p()
// VV***** We reset all user1p()
AstNode::user1ClearTree();
// Make top functions
{
@ -223,11 +218,10 @@ private:
funcp->isStatic(false);
funcp->entryPoint(true);
funcp->protect(false);
funcp->addInitsp(new AstCStmt
(nodep->fileline(),
EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
funcp->addInitsp(new AstCStmt(nodep->fileline(),
EmitCBaseVisitor::symTopAssign()+"\n"));
funcp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symClassVar()
+ " = this->__VlSymsp;\n"));
funcp->addInitsp(
new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign() + "\n"));
m_scopep->addActivep(funcp);
m_finalFuncp = funcp;
}
@ -245,13 +239,13 @@ private:
// Process the activates
iterateChildren(nodep);
// Done, clear so we can detect errors
UINFO(4," TOPSCOPEDONE "<<nodep<<endl);
UINFO(4, " TOPSCOPEDONE " << nodep << endl);
clearLastSen();
m_topScopep = NULL;
m_scopep = NULL;
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
//UINFO(4," MOD "<<nodep<<endl);
// UINFO(4, " MOD " << nodep << endl);
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
@ -260,7 +254,7 @@ private:
m_modp = origModp;
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
//UINFO(4," SCOPE "<<nodep<<endl);
// UINFO(4, " SCOPE " << nodep << endl);
m_scopep = nodep;
iterateChildren(nodep);
if (AstNode* movep = nodep->finalClksp()) {
@ -289,24 +283,21 @@ private:
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
//nodep->dumpTree(cout, "ct:");
//COVERTOGGLE(INC, ORIG, CHANGE) ->
// nodep->dumpTree(cout, "ct:");
// COVERTOGGLE(INC, ORIG, CHANGE) ->
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
AstNode* incp = nodep->incp()->unlinkFrBack();
AstNode* origp = nodep->origp()->unlinkFrBack();
AstNode* changep = nodep->changep()->unlinkFrBack();
AstIf* newp = new AstIf(nodep->fileline(),
new AstXor(nodep->fileline(),
origp,
changep),
AstIf* newp = new AstIf(nodep->fileline(), new AstXor(nodep->fileline(), origp, changep),
incp, NULL);
// We could add another IF to detect posedges, and only increment if so.
// It's another whole branch though versus a potential memory miss.
// We'll go with the miss.
newp->addIfsp(new AstAssign(nodep->fileline(),
changep->cloneTree(false),
origp->cloneTree(false)));
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
newp->addIfsp(
new AstAssign(nodep->fileline(), changep->cloneTree(false), origp->cloneTree(false)));
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
@ -321,7 +312,7 @@ private:
iterateChildren(nodep);
// Link to global function
if (nodep->formCallTree()) {
UINFO(4, " formCallTree "<<nodep<<endl);
UINFO(4, " formCallTree " << nodep << endl);
AstCCall* callp = new AstCCall(nodep->fileline(), nodep);
callp->argTypes("vlSymsp");
m_finalFuncp->addStmtsp(callp);
@ -333,13 +324,13 @@ private:
pushDeletep(nodep);
}
void addToEvalLoop(AstNode* stmtsp) {
m_evalFuncp->addStmtsp(stmtsp); // add to top level function
m_evalFuncp->addStmtsp(stmtsp); // add to top level function
}
void addToSettleLoop(AstNode* stmtsp) {
m_settleFuncp->addStmtsp(stmtsp); // add to top level function
m_settleFuncp->addStmtsp(stmtsp); // add to top level function
}
void addToInitial(AstNode* stmtsp) {
m_initFuncp->addStmtsp(stmtsp); // add to top level function
m_initFuncp->addStmtsp(stmtsp); // add to top level function
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
// Careful if adding variables here, ACTIVES can be under other ACTIVES
@ -350,13 +341,13 @@ private:
UASSERT_OBJ(!nodep->stmtsp(), nodep, "Non-empty lower active");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else if (m_mtaskBodyp) {
UINFO(4," TR ACTIVE "<<nodep<<endl);
UINFO(4, " TR ACTIVE " << nodep << endl);
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
if (nodep->hasClocked()) {
UASSERT_OBJ(!nodep->hasInitial(), nodep,
"Initial block should not have clock sensitivity");
if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) {
UINFO(4," sameSenseTree\n");
UINFO(4, " sameSenseTree\n");
} else {
clearLastSen();
m_lastSenp = nodep->sensesp();
@ -375,14 +366,14 @@ private:
}
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else {
UINFO(4," ACTIVE "<<nodep<<endl);
UINFO(4, " ACTIVE " << nodep << endl);
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
if (nodep->hasClocked()) {
// Remember the latest sensitivity so we can compare it next time
UASSERT_OBJ(!nodep->hasInitial(), nodep,
"Initial block should not have clock sensitivity");
if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) {
UINFO(4," sameSenseTree\n");
UINFO(4, " sameSenseTree\n");
} else {
clearLastSen();
m_lastSenp = nodep->sensesp();
@ -410,8 +401,7 @@ private:
}
}
virtual void visit(AstExecGraph* nodep) VL_OVERRIDE {
for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody);
m_mtaskBodyp;
for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody); m_mtaskBodyp;
m_mtaskBodyp = VN_CAST(m_mtaskBodyp->nextp(), MTaskBody)) {
clearLastSen();
iterate(m_mtaskBodyp);
@ -453,9 +443,7 @@ public:
// Clock class functions
void V3Clock::clockAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
ClockVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ ClockVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("clock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -75,22 +75,24 @@ class CombCallVisitor : CombBaseVisitor {
// Find all CCALLS of each CFUNC, so that we can later rename them
private:
// NODE STATE
typedef std::multimap<AstCFunc*,AstCCall*> CallMmap;
CallMmap m_callMmap; // Associative array of {function}{call}
typedef std::multimap<AstCFunc*, AstCCall*> CallMmap;
CallMmap m_callMmap; // Associative array of {function}{call}
// METHODS
public:
void replaceFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) {
if (oldfuncp==newfuncp) return;
if (oldfuncp == newfuncp) return;
if (newfuncp) {
UINFO(4, " Replace "<<oldfuncp<<" -WITH-> "<<newfuncp<<endl);
} else UINFO(4, " Remove "<<oldfuncp<<endl);
std::pair <CallMmap::iterator,CallMmap::iterator> eqrange
UINFO(4, " Replace " << oldfuncp << " -WITH-> " << newfuncp << endl);
} else {
UINFO(4, " Remove " << oldfuncp << endl);
}
std::pair<CallMmap::iterator, CallMmap::iterator> eqrange
= m_callMmap.equal_range(oldfuncp);
for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) {
CallMmap::iterator eqit = nextit++;
AstCCall* callp = eqit->second;
if (!callp->user3()) { // !already done
UINFO(4, " Called "<<callp<<endl);
UINFO(4, " Called " << callp << endl);
UASSERT_OBJ(callp->funcp() == oldfuncp, callp,
"Call list broken, points to call w/different func");
if (newfuncp) {
@ -108,27 +110,24 @@ public:
}
}
// METHODS
void addCall(AstCCall* nodep) {
m_callMmap.insert(make_pair(nodep->funcp(), nodep));
}
void addCall(AstCCall* nodep) { m_callMmap.insert(make_pair(nodep->funcp(), nodep)); }
void deleteCall(AstCCall* nodep) {
std::pair<CallMmap::iterator,CallMmap::iterator> eqrange
std::pair<CallMmap::iterator, CallMmap::iterator> eqrange
= m_callMmap.equal_range(nodep->funcp());
for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) {
CallMmap::iterator eqit = nextit++;
AstCCall* callp = eqit->second;
if (callp==nodep) {
if (callp == nodep) {
m_callMmap.erase(eqit);
return;
}
}
nodep->v3fatalSrc("deleteCall node not found in table");
}
private:
// VISITORS
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
addCall(nodep);
}
virtual void visit(AstCCall* nodep) VL_OVERRIDE { addCall(nodep); }
// Speed things up
virtual void visit(AstNodeAssign*) VL_OVERRIDE {}
virtual void visit(AstNodeMath*) VL_OVERRIDE {}
@ -154,11 +153,10 @@ private:
nodep->user3(true);
iterateChildren(nodep);
}
public:
// CONSTRUCTORS
explicit CombMarkVisitor(AstNode* nodep) {
iterate(nodep);
}
explicit CombMarkVisitor(AstNode* nodep) { iterate(nodep); }
virtual ~CombMarkVisitor() {}
};
@ -172,29 +170,30 @@ private:
// AstNodeStmt::user() -> bool. True if iterated already
// AstCFunc::user3p() -> AstCFunc*, If set, replace ccalls to this func with new func
// AstNodeStmt::user3() -> AstNode*. True if to ignore this cell
// AstNodeStmt::user4() -> V3Hashed::V3Hash. Hash value of this node (hash of 0 is illegal)
AstUser1InUse m_inuser1;
AstUser3InUse m_inuser3;
//AstUser4InUse part of V3Hashed
// AstNodeStmt::user4() -> V3Hashed::V3Hash. Hash value of this node (hash of 0 is
// illegal)
AstUser1InUse m_inuser1;
AstUser3InUse m_inuser3;
// AstUser4InUse part of V3Hashed
// STATE
typedef enum {STATE_IDLE, STATE_HASH, STATE_DUP} CombineState;
VDouble0 m_statCombs; // Statistic tracking
CombineState m_state; // Major state
AstNodeModule* m_modp; // Current module
AstCFunc* m_funcp; // Current function
V3Hash m_lowerHash; // Hash of the statement we're building
CombCallVisitor m_call; // Tracking of function call users
int m_modNFuncs; // Number of functions made
AstNode* m_walkLast1p; // Final node that is the same in duplicate list
AstNode* m_walkLast2p; // Final node that is the same in duplicate list
V3Hashed m_hashed; // Hash for every node in module
typedef enum { STATE_IDLE, STATE_HASH, STATE_DUP } CombineState;
VDouble0 m_statCombs; // Statistic tracking
CombineState m_state; // Major state
AstNodeModule* m_modp; // Current module
AstCFunc* m_funcp; // Current function
V3Hash m_lowerHash; // Hash of the statement we're building
CombCallVisitor m_call; // Tracking of function call users
int m_modNFuncs; // Number of functions made
AstNode* m_walkLast1p; // Final node that is the same in duplicate list
AstNode* m_walkLast2p; // Final node that is the same in duplicate list
V3Hashed m_hashed; // Hash for every node in module
// METHODS
void hashStatement(AstNode* nodep) {
// Compute hash on entire tree of this statement
m_hashed.hashAndInsert(nodep);
//UINFO(9," stmthash "<<hex<<nodep->user4()<<" "<<nodep<<endl);
// UINFO(9, " stmthash " << hex << nodep->user4() << " " << nodep << endl);
}
void hashFunctions(AstCFunc* nodep) {
// Compute hash of all statement trees in the function
@ -209,11 +208,9 @@ private:
for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
AstNode* node1p = it->second;
AstCFunc* oldfuncp = VN_CAST(node1p, CFunc);
if (oldfuncp
&& oldfuncp->emptyBody()
&& !oldfuncp->dontCombine()) {
UINFO(5," EmptyFunc "<<std::hex<<V3Hash(oldfuncp->user4p())
<<" "<<oldfuncp<<endl);
if (oldfuncp && oldfuncp->emptyBody() && !oldfuncp->dontCombine()) {
UINFO(5, " EmptyFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " "
<< oldfuncp << endl);
// Mark user3p on entire old tree, so we don't process it more
CombMarkVisitor visitor(oldfuncp);
m_call.replaceFunc(oldfuncp, NULL);
@ -231,7 +228,7 @@ private:
for (V3Hashed::iterator eqit = it; eqit != m_hashed.end(); ++eqit) {
AstNode* node2p = eqit->second;
if (!(eqit->first == hashval)) break;
if (node1p==node2p) continue; // Identical iterator
if (node1p == node2p) continue; // Identical iterator
if (node1p->user3p() || node2p->user3p()) continue; // Already merged
if (node1p->sameTree(node2p)) { // walk of tree has same comparison
// Replace AstCCall's that point here
@ -243,8 +240,10 @@ private:
}
}
void replaceFuncWFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) {
UINFO(5," DupFunc "<<std::hex<<V3Hash(newfuncp->user4p())<<" "<<newfuncp<<endl);
UINFO(5," and "<<std::hex<<V3Hash(oldfuncp->user4p())<<" "<<oldfuncp<<endl);
UINFO(5, " DupFunc " << std::hex << V3Hash(newfuncp->user4p()) << " " << newfuncp
<< endl);
UINFO(5, " and " << std::hex << V3Hash(oldfuncp->user4p()) << " " << oldfuncp
<< endl);
// Mark user3p on entire old tree, so we don't process it more
++m_statCombs;
CombMarkVisitor visitor(oldfuncp);
@ -254,12 +253,10 @@ private:
}
void replaceOnlyCallFunc(AstCCall* nodep) {
if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) {
//oldfuncp->dumpTree(cout, "MAYDEL: ");
if (nodep->nextp()==NULL
&& oldfuncp->initsp()==NULL
&& oldfuncp->stmtsp()==nodep
&& oldfuncp->finalsp()==NULL) {
UINFO(9," Function only has call "<<oldfuncp<<endl);
// oldfuncp->dumpTree(cout, "MAYDEL: ");
if (nodep->nextp() == NULL && oldfuncp->initsp() == NULL && oldfuncp->stmtsp() == nodep
&& oldfuncp->finalsp() == NULL) {
UINFO(9, " Function only has call " << oldfuncp << endl);
m_call.deleteCall(nodep);
CombMarkVisitor visitor(oldfuncp);
VL_DO_DANGLING(replaceFuncWFunc(oldfuncp, nodep->funcp()), nodep);
@ -269,18 +266,18 @@ private:
void walkDupCodeStart(AstNode* node1p) {
V3Hash hashval(node1p->user4p());
//UINFO(4," STMT "<<hashval<<" "<<node1p<<endl);
// UINFO(4," STMT " << hashval << " " << node1p << endl);
//
int bestDepth = 0; // Best substitution found in the search
AstNode* bestNode2p = NULL;
AstNode* bestLast1p = NULL;
AstNode* bestLast2p = NULL;
//
std::pair<V3Hashed::iterator,V3Hashed::iterator> eqrange
std::pair<V3Hashed::iterator, V3Hashed::iterator> eqrange
= m_hashed.mmap().equal_range(hashval);
for (V3Hashed::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) {
AstNode* node2p = eqit->second;
if (node1p==node2p) continue;
if (node1p == node2p) continue;
//
// We need to mark iteration to prevent matching code inside
// code (abab matching in ababab)
@ -288,8 +285,7 @@ private:
m_walkLast1p = NULL;
m_walkLast2p = NULL;
int depth = walkDupCodeNext(node1p, node2p, 1);
if (depth>COMBINE_MIN_STATEMENTS
&& depth>bestDepth) {
if (depth > COMBINE_MIN_STATEMENTS && depth > bestDepth) {
bestDepth = depth;
bestNode2p = node2p;
bestLast1p = m_walkLast1p;
@ -298,11 +294,15 @@ private:
}
if (bestDepth) {
// Found a replacement
UINFO(5," Duplicate of depth "<<bestDepth<<endl);
UINFO(5," DupFunc "<<" "<<node1p<<endl);
UINFO(5," and "<<" "<<bestNode2p<<endl);
UINFO(5," Through "<<" "<<bestLast1p<<endl);
UINFO(5," and "<<" "<<bestLast2p<<endl);
UINFO(5, " Duplicate of depth " << bestDepth << endl);
UINFO(5, " DupFunc "
<< " " << node1p << endl);
UINFO(5, " and "
<< " " << bestNode2p << endl);
UINFO(5, " Through "
<< " " << bestLast1p << endl);
UINFO(5, " and "
<< " " << bestLast2p << endl);
//
walkReplace(node1p, bestNode2p, bestLast1p, bestLast2p);
}
@ -314,32 +314,28 @@ private:
if (node1p->user3p() || node2p->user3p()) return 0; // Already merged
if (!m_hashed.sameNodes(node1p, node2p)) return 0; // walk of tree has same comparison
V3Hash hashval(node1p->user4p());
//UINFO(9," wdup1 "<<level<<" "<<V3Hash(node1p->user4p())<<" "<<node1p<<endl);
//UINFO(9," wdup2 "<<level<<" "<<V3Hash(node2p->user4p())<<" "<<node2p<<endl);
// UINFO(9, " wdup1 "<<level<<" "<<V3Hash(node1p->user4p())<<" "<<node1p<<endl);
// UINFO(9, " wdup2 "<<level<<" "<<V3Hash(node2p->user4p())<<" "<<node2p<<endl);
m_walkLast1p = node1p;
m_walkLast2p = node2p;
node1p->user1(true);
node2p->user1(true);
if (node1p->nextp() && node2p->nextp()) {
return hashval.depth()+walkDupCodeNext(node1p->nextp(), node2p->nextp(), level+1);
return hashval.depth() + walkDupCodeNext(node1p->nextp(), node2p->nextp(), level + 1);
}
return hashval.depth();
}
void walkReplace(AstNode* node1p, AstNode* node2p,
AstNode* last1p, AstNode* last2p) { // Final node in linked list, maybe null if all statements to be grabbed
void walkReplace(AstNode* node1p, AstNode* node2p, AstNode* last1p,
AstNode* last2p) { // Final node in linked list, maybe null if all statements
// to be grabbed
// Make new function
string oldname = m_funcp->name();
string::size_type pos;
if ((pos = oldname.find("_common")) != string::npos) {
oldname.erase(pos);
}
if ((pos = oldname.find("__")) != string::npos) {
oldname.erase(pos);
}
if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos);
if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos);
AstCFunc* newfuncp = new AstCFunc(node1p->fileline(),
oldname+"_common"+cvtToStr(++m_modNFuncs),
NULL);
oldname + "_common" + cvtToStr(++m_modNFuncs), NULL);
m_modp->addStmtp(newfuncp);
// Create calls
AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp);
@ -347,21 +343,29 @@ private:
// Grab statement bodies
AstNRelinker relink1Handle;
AstNRelinker relink2Handle;
for (AstNode* nextp, *walkp = node1p; 1; walkp = nextp) {
for (AstNode *nextp, *walkp = node1p; 1; walkp = nextp) {
nextp = walkp->nextp();
if (walkp==node1p) walkp->unlinkFrBack(&relink1Handle);
else { walkp->unlinkFrBack(); node1p->addNext(walkp); }
if (walkp==last1p) break;
if (walkp == node1p) {
walkp->unlinkFrBack(&relink1Handle);
} else {
walkp->unlinkFrBack();
node1p->addNext(walkp);
}
if (walkp == last1p) break;
}
for (AstNode* nextp, *walkp = node2p; 1; walkp = nextp) {
for (AstNode *nextp, *walkp = node2p; 1; walkp = nextp) {
nextp = walkp->nextp();
if (walkp==node2p) walkp->unlinkFrBack(&relink2Handle);
else { walkp->unlinkFrBack(); node2p->addNext(walkp); }
if (walkp==last2p) break;
if (walkp == node2p) {
walkp->unlinkFrBack(&relink2Handle);
} else {
walkp->unlinkFrBack();
node2p->addNext(walkp);
}
if (walkp == last2p) break;
}
// Move node1 statements to new function
newfuncp->addStmtsp(node1p);
//newfuncp->dumpTree(cout, " newfunctree: ");
// newfuncp->dumpTree(cout, " newfunctree: ");
// Mark node2 statements as dead
CombMarkVisitor visitor(node2p);
pushDeletep(node2p); // Delete later
@ -383,13 +387,13 @@ private:
// Track all callers of each function
m_call.main(nodep);
//
//In V3Hashed AstNode::user4ClearTree(); // user4p() used on entire tree
// In V3Hashed AstNode::user4ClearTree(); // user4p() used on entire tree
// Iterate modules backwards, in bottom-up order.
// Required so that a module instantiating another can benefit from collapsing.
iterateChildrenBackwards(nodep);
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
UINFO(4," MOD "<<nodep<<endl);
UINFO(4, " MOD " << nodep << endl);
m_modp = nodep;
m_modNFuncs = 0;
m_walkLast2p = NULL;
@ -398,17 +402,11 @@ private:
m_state = STATE_HASH;
iterateChildren(nodep);
m_state = STATE_IDLE;
if (debug()>=9) {
m_hashed.dumpFilePrefixed("combine");
}
if (debug() >= 9) m_hashed.dumpFilePrefixed("combine");
// Walk the hashes removing empty functions
if (emptyFunctionDeletion()) {
walkEmptyFuncs();
}
if (emptyFunctionDeletion()) walkEmptyFuncs();
// Walk the hashes looking for duplicate functions
if (duplicateFunctionCombine()) {
walkDupFuncs();
}
if (duplicateFunctionCombine()) walkDupFuncs();
// Walk the statements looking for large replicated code sections
if (statementCombine()) {
m_state = STATE_DUP;
@ -435,8 +433,7 @@ private:
}
if (m_state == STATE_HASH && m_funcp) {
hashStatement(nodep);
}
else if (m_state == STATE_DUP && m_funcp) {
} else if (m_state == STATE_DUP && m_funcp) {
walkDupCodeStart(nodep);
}
}
@ -459,7 +456,7 @@ public:
m_walkLast2p = NULL;
iterate(nodep);
}
virtual ~CombineVisitor() {
virtual ~CombineVisitor() { //
V3Stats::addStat("Optimizations, Combined CFuncs", m_statCombs);
}
};
@ -468,9 +465,7 @@ public:
// Combine class functions
void V3Combine::combineAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
CombineVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ CombineVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("combine", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -327,12 +327,12 @@ public:
inline void applyIgnores(FileLine* filelinep) {
// HOT routine, called each parsed token line of this filename
if (m_lastIgnore.lineno != filelinep->lineno()) {
// UINFO(9," ApplyIgnores for "<<filelinep->ascii()<<endl);
// UINFO(9, " ApplyIgnores for " << filelinep->ascii() << endl);
// Process all on/offs for lines up to and including the current line
int curlineno = filelinep->lastLineno();
for (; m_lastIgnore.it != m_ignLines.end(); ++m_lastIgnore.it) {
if (m_lastIgnore.it->m_lineno > curlineno) break;
// UINFO(9," Hit "<<*m_lastIt<<endl);
// UINFO(9, " Hit " << *m_lastIt << endl);
filelinep->warnOn(m_lastIgnore.it->m_code, m_lastIgnore.it->m_on);
}
if (0 && debug() >= 9) {

File diff suppressed because it is too large Load Diff

View File

@ -63,9 +63,7 @@ private:
public:
// CONSTRUCTORS
explicit DeadModVisitor(AstNodeModule* nodep) {
iterate(nodep);
}
explicit DeadModVisitor(AstNodeModule* nodep) { iterate(nodep); }
virtual ~DeadModVisitor() {}
};
@ -80,52 +78,46 @@ private:
// AstVar::user1() -> int. Count of number of references
// AstVarScope::user1() -> int. Count of number of references
// AstNodeDType::user1() -> int. Count of number of references
AstUser1InUse m_inuser1;
AstUser1InUse m_inuser1;
// TYPES
typedef std::multimap<AstVarScope*,AstNodeAssign*> AssignMap;
typedef std::multimap<AstVarScope*, AstNodeAssign*> AssignMap;
// STATE
AstNodeModule* m_modp; // Current module
std::vector<AstVar*> m_varsp; // List of all encountered to avoid another loop through tree
std::vector<AstNode*> m_dtypesp; // List of all encountered to avoid another loop through tree
std::vector<AstVarScope*> m_vscsp; // List of all encountered to avoid another loop through tree
std::vector<AstScope*> m_scopesp; // List of all encountered to avoid another loop through tree
std::vector<AstCell*> m_cellsp; // List of all encountered to avoid another loop through tree
std::vector<AstClass*> m_classesp; // List of all encountered to avoid another loop through tree
AssignMap m_assignMap; // List of all simple assignments for each variable
bool m_elimUserVars; // Allow removal of user's vars
bool m_elimDTypes; // Allow removal of DTypes
bool m_elimScopes; // Allow removal of Scopes
bool m_elimCells; // Allow removal of Cells
bool m_sideEffect; // Side effects discovered in assign RHS
AstNodeModule* m_modp; // Current module
// List of all encountered to avoid another loop through tree
std::vector<AstVar*> m_varsp;
std::vector<AstNode*> m_dtypesp;
std::vector<AstVarScope*> m_vscsp;
std::vector<AstScope*> m_scopesp;
std::vector<AstCell*> m_cellsp;
std::vector<AstClass*> m_classesp;
AssignMap m_assignMap; // List of all simple assignments for each variable
bool m_elimUserVars; // Allow removal of user's vars
bool m_elimDTypes; // Allow removal of DTypes
bool m_elimScopes; // Allow removal of Scopes
bool m_elimCells; // Allow removal of Cells
bool m_sideEffect; // Side effects discovered in assign RHS
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void checkAll(AstNode* nodep) {
if (nodep != nodep->dtypep()) { // NodeDTypes reference themselves
if (AstNode* subnodep = nodep->dtypep()) {
subnodep->user1Inc();
}
}
if (AstNode* subnodep = nodep->getChildDTypep()) {
subnodep->user1Inc();
if (AstNode* subnodep = nodep->dtypep()) subnodep->user1Inc();
}
if (AstNode* subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
}
void checkDType(AstNodeDType* nodep) {
if (!nodep->generic() // Don't remove generic types
&& m_elimDTypes // dtypes stick around until post-widthing
&& !VN_IS(nodep, MemberDType) // Keep member names iff upper type exists
) {
) {
m_dtypesp.push_back(nodep);
}
if (AstNode* subnodep = nodep->virtRefDTypep()) {
subnodep->user1Inc();
}
if (AstNode* subnodep = nodep->virtRefDType2p()) {
subnodep->user1Inc();
}
if (AstNode* subnodep = nodep->virtRefDTypep()) subnodep->user1Inc();
if (AstNode* subnodep = nodep->virtRefDType2p()) subnodep->user1Inc();
}
// VISITORS
@ -177,20 +169,24 @@ private:
nodep->varScopep()->user1Inc();
nodep->varScopep()->varp()->user1Inc();
}
if (nodep->varp()) {
nodep->varp()->user1Inc();
}
if (nodep->varp()) nodep->varp()->user1Inc();
if (nodep->packagep()) {
if (m_elimCells) nodep->packagep(NULL);
else nodep->packagep()->user1Inc();
if (m_elimCells) {
nodep->packagep(NULL);
} else {
nodep->packagep()->user1Inc();
}
}
}
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->packagep()) {
if (m_elimCells) nodep->packagep(NULL);
else nodep->packagep()->user1Inc();
if (m_elimCells) {
nodep->packagep(NULL);
} else {
nodep->packagep()->user1Inc();
}
}
}
virtual void visit(AstMethodCall* nodep) VL_OVERRIDE {
@ -202,8 +198,11 @@ private:
checkDType(nodep);
checkAll(nodep);
if (nodep->packagep()) {
if (m_elimCells) nodep->packagep(NULL);
else nodep->packagep()->user1Inc();
if (m_elimCells) {
nodep->packagep(NULL);
} else {
nodep->packagep()->user1Inc();
}
}
}
virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE {
@ -211,12 +210,13 @@ private:
checkDType(nodep);
checkAll(nodep);
if (nodep->packagep()) {
if (m_elimCells) nodep->packagep(NULL);
else nodep->packagep()->user1Inc();
}
if (nodep->classp()) {
nodep->classp()->user1Inc();
if (m_elimCells) {
nodep->packagep(NULL);
} else {
nodep->packagep()->user1Inc();
}
}
if (nodep->classp()) nodep->classp()->user1Inc();
}
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
iterateChildren(nodep);
@ -227,8 +227,11 @@ private:
iterateChildren(nodep);
checkAll(nodep);
if (nodep->packagep()) {
if (m_elimCells) nodep->packagep(NULL);
else nodep->packagep()->user1Inc();
if (m_elimCells) {
nodep->packagep(NULL);
} else {
nodep->packagep()->user1Inc();
}
}
checkAll(nodep);
}
@ -263,17 +266,13 @@ private:
iterateChildren(nodep);
checkAll(nodep);
if (nodep->scopep()) nodep->scopep()->user1Inc();
if (mightElimVar(nodep->varp())) {
m_vscsp.push_back(nodep);
}
if (mightElimVar(nodep->varp())) m_vscsp.push_back(nodep);
}
virtual void visit(AstVar* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkAll(nodep);
if (nodep->isSigPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
if (mightElimVar(nodep)) {
m_varsp.push_back(nodep);
}
if (mightElimVar(nodep)) m_varsp.push_back(nodep);
}
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
// See if simple assignments to variables may be eliminated because
@ -306,14 +305,15 @@ private:
// Kill any unused modules
// V3LinkCells has a graph that is capable of this too, but we need to do it
// after we've done all the generate blocks
for (bool retry=true; retry; ) {
for (bool retry = true; retry;) {
retry = false;
AstNodeModule* nextmodp;
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=nextmodp) {
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp = nextmodp) {
nextmodp = VN_CAST(modp->nextp(), NodeModule);
if (modp->dead() || (modp->level()>2 && modp->user1()==0 && !modp->internal())) {
if (modp->dead()
|| (modp->level() > 2 && modp->user1() == 0 && !modp->internal())) {
// > 2 because L1 is the wrapper, L2 is the top user module
UINFO(4," Dead module "<<modp<<endl);
UINFO(4, " Dead module " << modp << endl);
// And its children may now be killable too; correct counts
// Recurse, as cells may not be directly under the module but in a generate
if (!modp->dead()) { // If was dead didn't increment user1's
@ -327,27 +327,23 @@ private:
}
bool mightElimVar(AstVar* nodep) {
return (!nodep->isSigPublic() // Can't elim publics!
&& !nodep->isIO()
&& !nodep->isClassMember()
&& !nodep->isIO() && !nodep->isClassMember()
&& ((nodep->isTemp() && !nodep->isTrace())
|| (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly())
|| m_elimUserVars)); // Post-Trace can kill most anything
}
void deadCheckScope() {
for (bool retry=true; retry; ) {
for (bool retry = true; retry;) {
retry = false;
for (std::vector<AstScope*>::iterator it = m_scopesp.begin();
it != m_scopesp.end();++it) {
for (std::vector<AstScope*>::iterator it = m_scopesp.begin(); it != m_scopesp.end();
++it) {
AstScope* scp = *it;
if (!scp)
continue;
if (!scp) continue;
if (scp->user1() == 0) {
UINFO(4, " Dead AstScope " << scp << endl);
scp->aboveScopep()->user1Inc(-1);
if (scp->dtypep()) {
scp->dtypep()->user1Inc(-1);
}
if (scp->dtypep()) scp->dtypep()->user1Inc(-1);
VL_DO_DANGLING(scp->unlinkFrBack()->deleteTree(), scp);
*it = NULL;
retry = true;
@ -357,7 +353,7 @@ private:
}
void deadCheckCells() {
for (std::vector<AstCell*>::iterator it = m_cellsp.begin(); it!=m_cellsp.end(); ++it) {
for (std::vector<AstCell*>::iterator it = m_cellsp.begin(); it != m_cellsp.end(); ++it) {
AstCell* cellp = *it;
if (cellp->user1() == 0 && !cellp->modp()->stmtsp()) {
cellp->modp()->user1Inc(-1);
@ -385,15 +381,15 @@ private:
void deadCheckVar() {
// Delete any unused varscopes
for (std::vector<AstVarScope*>::iterator it = m_vscsp.begin(); it!=m_vscsp.end(); ++it) {
for (std::vector<AstVarScope*>::iterator it = m_vscsp.begin(); it != m_vscsp.end(); ++it) {
AstVarScope* vscp = *it;
if (vscp->user1() == 0) {
UINFO(4," Dead "<<vscp<<endl);
std::pair<AssignMap::iterator,AssignMap::iterator> eqrange
UINFO(4, " Dead " << vscp << endl);
std::pair<AssignMap::iterator, AssignMap::iterator> eqrange
= m_assignMap.equal_range(vscp);
for (AssignMap::iterator itr = eqrange.first; itr != eqrange.second; ++itr) {
AstNodeAssign* assp = itr->second;
UINFO(4," Dead assign "<<assp<<endl);
UINFO(4, " Dead assign " << assp << endl);
assp->dtypep()->user1Inc(-1);
VL_DO_DANGLING(assp->unlinkFrBack()->deleteTree(), assp);
}
@ -402,40 +398,36 @@ private:
VL_DO_DANGLING(vscp->unlinkFrBack()->deleteTree(), vscp);
}
}
for (bool retry=true; retry; ) {
for (bool retry = true; retry;) {
retry = false;
for (std::vector<AstVar *>::iterator it = m_varsp.begin(); it != m_varsp.end();++it) {
for (std::vector<AstVar*>::iterator it = m_varsp.begin(); it != m_varsp.end(); ++it) {
AstVar* varp = *it;
if (!varp)
continue;
if (!varp) continue;
if (varp->user1() == 0) {
UINFO(4, " Dead " << varp << endl);
if (varp->dtypep()) {
varp->dtypep()->user1Inc(-1);
}
if (varp->dtypep()) varp->dtypep()->user1Inc(-1);
VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp);
*it = NULL;
retry = true;
}
}
}
for (std::vector<AstNode*>::iterator it = m_dtypesp.begin(); it != m_dtypesp.end();++it) {
for (std::vector<AstNode*>::iterator it = m_dtypesp.begin(); it != m_dtypesp.end(); ++it) {
if ((*it)->user1() == 0) {
AstNodeUOrStructDType *classp;
AstNodeUOrStructDType* classp;
// It's possible that there if a reference to each individual member, but
// not to the dtype itself. Check and don't remove the parent dtype if
// members are still alive.
if ((classp = VN_CAST((*it), NodeUOrStructDType))) {
bool cont = true;
for (AstMemberDType *memberp = classp->membersp();
memberp; memberp = VN_CAST(memberp->nextp(), MemberDType)) {
for (AstMemberDType* memberp = classp->membersp(); memberp;
memberp = VN_CAST(memberp->nextp(), MemberDType)) {
if (memberp->user1() != 0) {
cont = false;
break;
}
}
if (!cont)
continue;
if (!cont) continue;
}
VL_DO_DANGLING((*it)->unlinkFrBack()->deleteTree(), *it);
}
@ -444,8 +436,8 @@ private:
public:
// CONSTRUCTORS
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes,
bool elimScopes, bool elimCells) {
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes,
bool elimCells) {
m_modp = NULL;
m_elimCells = elimCells;
m_elimUserVars = elimUserVars;
@ -476,41 +468,32 @@ public:
// Dead class functions
void V3Dead::deadifyModules(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
DeadVisitor visitor (nodep, false, false, false, false);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor(nodep, false, false, false, false); } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadModules", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
DeadVisitor visitor (nodep, false, true, false, false);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor(nodep, false, true, false, false); } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypes", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
DeadVisitor visitor (nodep, false, true, true, false);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor(nodep, false, true, true, false); } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0,
v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Dead::deadifyAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
DeadVisitor visitor (nodep, true, true, false, true);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor(nodep, true, true, false, true); } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAll", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
DeadVisitor visitor (nodep, true, true, true, true);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor(nodep, true, true, true, true); } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -81,40 +81,41 @@ private:
// Cleared each scope/active:
// AstAssignDly::user3() -> AstVarScope*. __Vdlyvset__ created for this assign
// AstAlwaysPost::user3() -> AstVarScope*. __Vdlyvset__ last referenced in IF
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
AstUser4InUse m_inuser4;
AstUser5InUse m_inuser5;
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
AstUser4InUse m_inuser4;
AstUser5InUse m_inuser5;
enum VarUsage { VU_NONE=0, VU_DLY=1, VU_NONDLY=2 };
enum VarUsage { VU_NONE = 0, VU_DLY = 1, VU_NONDLY = 2 };
// STATE
AstActive* m_activep; // Current activate
AstCFunc* m_cfuncp; // Current public C Function
AstAssignDly* m_nextDlyp; // Next delayed assignment in a list of assignments
bool m_inDly; // True in delayed assignments
bool m_inLoop; // True in for loops
bool m_inInitial; // True in initial blocks
typedef std::map<std::pair<AstNodeModule*,string>,AstVar*> VarMap;
VarMap m_modVarMap; // Table of new var names created under module
VDouble0 m_statSharedSet; // Statistic tracking
typedef std::map<AstVarScope*,int> ScopeVecMap;
AstActive* m_activep; // Current activate
AstCFunc* m_cfuncp; // Current public C Function
AstAssignDly* m_nextDlyp; // Next delayed assignment in a list of assignments
bool m_inDly; // True in delayed assignments
bool m_inLoop; // True in for loops
bool m_inInitial; // True in initial blocks
typedef std::map<std::pair<AstNodeModule*, string>, AstVar*> VarMap;
VarMap m_modVarMap; // Table of new var names created under module
VDouble0 m_statSharedSet; // Statistic tracking
typedef std::map<AstVarScope*, int> ScopeVecMap;
ScopeVecMap m_scopeVecMap; // Next var number for each scope
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void markVarUsage(AstVarScope* nodep, uint32_t flags) {
//UINFO(4," MVU "<<flags<<" "<<nodep<<endl);
nodep->user5( nodep->user5() | flags );
// UINFO(4, " MVU " << flags << " " << nodep << endl);
nodep->user5(nodep->user5() | flags);
if ((nodep->user5() & VU_DLY) && (nodep->user5() & VU_NONDLY)) {
nodep->v3warn(BLKANDNBLK, "Unsupported: Blocked and non-blocking assignments to same variable: "
<<nodep->varp()->prettyNameQ());
nodep->v3warn(BLKANDNBLK,
"Unsupported: Blocked and non-blocking assignments to same variable: "
<< nodep->varp()->prettyNameQ());
}
}
AstVarScope* createVarSc(AstVarScope* oldvarscp, const string& name,
int width/*0==fromoldvar*/, AstNodeDType* newdtypep) {
int width /*0==fromoldvar*/, AstNodeDType* newdtypep) {
// Because we've already scoped it, we may need to add both the AstVar and the AstVarScope
UASSERT_OBJ(oldvarscp->scopep(), oldvarscp, "Var unscoped");
AstVar* varp;
@ -126,15 +127,14 @@ private:
varp = it->second;
} else {
if (newdtypep) {
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP,
name, newdtypep);
} else if (width==0) {
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP,
name, oldvarscp->varp());
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, newdtypep);
} else if (width == 0) {
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, name,
oldvarscp->varp());
varp->dtypeFrom(oldvarscp);
} else { // Used for vset and dimensions, so can zero init
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP,
name, VFlagBitPacked(), width);
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, name,
VFlagBitPacked(), width);
}
addmodp->addStmtp(varp);
m_modVarMap.insert(make_pair(make_pair(addmodp, name), varp));
@ -146,8 +146,8 @@ private:
}
AstActive* createActivePost(AstVarRef* varrefp) {
AstActive* newactp = new AstActive(varrefp->fileline(), "sequentdly",
m_activep->sensesp());
AstActive* newactp
= new AstActive(varrefp->fileline(), "sequentdly", m_activep->sensesp());
// Was addNext(), but addNextHere() avoids a linear search.
m_activep->addNextHere(newactp);
return newactp;
@ -159,18 +159,18 @@ private:
if (!varrefp->varp()->fileline()->warnIsOff(V3ErrorCode::MULTIDRIVEN)
&& !varrefp->varp()->user2()) {
varrefp->varp()->v3warn(
MULTIDRIVEN, "Signal has multiple driving blocks with different clocking: "
<<varrefp->varp()->prettyNameQ()<<endl
<<varrefp->warnOther()<<"... Location of first driving block"<<endl
<<varrefp->warnContextPrimary()<<endl
<<oldactivep->warnOther()<<"... Location of other driving block"<<endl
<<oldactivep->warnContextSecondary()
);
MULTIDRIVEN,
"Signal has multiple driving blocks with different clocking: "
<< varrefp->varp()->prettyNameQ() << endl
<< varrefp->warnOther() << "... Location of first driving block" << endl
<< varrefp->warnContextPrimary() << endl
<< oldactivep->warnOther() << "... Location of other driving block" << endl
<< oldactivep->warnContextSecondary());
varrefp->varp()->user2(true);
}
UINFO(4,"AssignDupDlyVar: "<<varrefp<<endl);
UINFO(4," Act: "<<m_activep<<endl);
UINFO(4," Act: "<<oldactivep<<endl);
UINFO(4, "AssignDupDlyVar: " << varrefp << endl);
UINFO(4, " Act: " << m_activep << endl);
UINFO(4, " Act: " << oldactivep << endl);
// Make a new sensitivity list, which is the combination of both blocks
AstNodeSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true);
AstNodeSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
@ -191,8 +191,8 @@ private:
// Return the new LHS for the assignment, Null = unlink
// Find selects
AstNode* newlhsp = NULL; // NULL = unlink old assign
AstSel* bitselp = NULL;
AstArraySel* arrayselp = NULL;
AstSel* bitselp = NULL;
AstArraySel* arrayselp = NULL;
if (VN_IS(lhsp, Sel)) {
bitselp = VN_CAST(lhsp, Sel);
arrayselp = VN_CAST(bitselp->fromp(), ArraySel);
@ -202,12 +202,12 @@ private:
UASSERT_OBJ(arrayselp, nodep, "No arraysel under bitsel?");
UASSERT_OBJ(!VN_IS(arrayselp->dtypep()->skipRefp(), UnpackArrayDType), nodep,
"ArraySel with unpacked arrays should have been removed in V3Slice");
UINFO(4,"AssignDlyArray: "<<nodep<<endl);
UINFO(4, "AssignDlyArray: " << nodep << endl);
//
//=== Dimensions: __Vdlyvdim__
std::deque<AstNode*> dimvalp; // Assignment value for each dimension of assignment
AstNode* dimselp = arrayselp;
for (; VN_IS(dimselp, ArraySel); dimselp=VN_CAST(dimselp, ArraySel)->fromp()) {
for (; VN_IS(dimselp, ArraySel); dimselp = VN_CAST(dimselp, ArraySel)->fromp()) {
AstNode* valp = VN_CAST(dimselp, ArraySel)->bitp()->unlinkFrBack();
dimvalp.push_front(valp);
}
@ -219,19 +219,17 @@ private:
int modVecNum = m_scopeVecMap[varrefp->varScopep()]++;
//
std::deque<AstNode*> dimreadps; // Read value for each dimension of assignment
for (unsigned dimension=0; dimension<dimvalp.size(); dimension++) {
for (unsigned dimension = 0; dimension < dimvalp.size(); dimension++) {
AstNode* dimp = dimvalp[dimension];
if (VN_IS(dimp, Const)) { // bit = const, can just use it
dimreadps.push_front(dimp);
} else {
string bitvarname = (string("__Vdlyvdim")+cvtToStr(dimension)
+"__"+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
AstVarScope* bitvscp = createVarSc(varrefp->varScopep(),
bitvarname, dimp->width(), NULL);
AstAssign* bitassignp
= new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), bitvscp, true),
dimp);
string bitvarname = (string("__Vdlyvdim") + cvtToStr(dimension) + "__"
+ oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
AstVarScope* bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), NULL);
AstAssign* bitassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), dimp);
nodep->addNextHere(bitassignp);
dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, false));
}
@ -241,15 +239,16 @@ private:
AstNode* bitreadp = NULL; // Code to read Vdlyvlsb
if (bitselp) {
AstNode* lsbvaluep = bitselp->lsbp()->unlinkFrBack();
if (VN_IS(bitselp->fromp(), Const)) { // vlsb = constant, can just push constant into where we use it
if (VN_IS(bitselp->fromp(), Const)) {
// vlsb = constant, can just push constant into where we use it
bitreadp = lsbvaluep;
} else {
string bitvarname = (string("__Vdlyvlsb__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
AstVarScope* bitvscp = createVarSc(varrefp->varScopep(),
bitvarname, lsbvaluep->width(), NULL);
AstAssign* bitassignp = new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), bitvscp, true),
lsbvaluep);
string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v"
+ cvtToStr(modVecNum));
AstVarScope* bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), NULL);
AstAssign* bitassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), lsbvaluep);
nodep->addNextHere(bitassignp);
bitreadp = new AstVarRef(nodep->fileline(), bitvscp, false);
}
@ -257,11 +256,14 @@ private:
//
//=== Value: __Vdlyvval__
AstNode* valreadp; // Code to read Vdlyvval
if (VN_IS(nodep->rhsp(), Const)) { // vval = constant, can just push constant into where we use it
if (VN_IS(nodep->rhsp(), Const)) {
// vval = constant, can just push constant into where we use it
valreadp = nodep->rhsp()->unlinkFrBack();
} else {
string valvarname = (string("__Vdlyvval__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
AstVarScope* valvscp = createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
string valvarname
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
AstVarScope* valvscp
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
newlhsp = new AstVarRef(nodep->fileline(), valvscp, true);
valreadp = new AstVarRef(nodep->fileline(), valvscp, false);
}
@ -278,14 +280,14 @@ private:
setvscp = VN_CAST(nodep->user3p(), VarScope);
++m_statSharedSet;
} else { // Create new one
string setvarname = (string("__Vdlyvset__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
string setvarname
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, NULL);
setinitp = new AstAssignPre(nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, true),
new AstConst(nodep->fileline(), 0));
AstAssign* setassignp
= new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, true),
= new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, true),
new AstConst(nodep->fileline(), AstConst::LogicTrue()));
nodep->addNextHere(setassignp);
}
@ -299,7 +301,7 @@ private:
// in correctly ordered code - the last assignment must be last.
// It also has the nice side effect of assisting cache locality.
AstNode* selectsp = varrefp;
for (int dimension=int(dimreadps.size())-1; dimension>=0; --dimension) {
for (int dimension = int(dimreadps.size()) - 1; dimension >= 0; --dimension) {
selectsp = new AstArraySel(nodep->fileline(), selectsp, dimreadps[dimension]);
}
if (bitselp) {
@ -307,16 +309,16 @@ private:
bitselp->widthp()->cloneTree(false));
}
// Build "IF (changeit) ...
UINFO(9," For "<<setvscp<<endl);
UINFO(9," & "<<varrefp<<endl);
UINFO(9, " For " << setvscp << endl);
UINFO(9, " & " << varrefp << endl);
AstAlwaysPost* finalp = VN_CAST(varrefp->varScopep()->user4p(), AlwaysPost);
if (finalp) {
AstActive* oldactivep = VN_CAST(finalp->user2p(), Active);
checkActivePost(varrefp, oldactivep);
if (setinitp) oldactivep->addStmtsp(setinitp);
} else { // first time we've dealt with this memory
finalp = new AstAlwaysPost(nodep->fileline(), NULL/*sens*/, NULL/*body*/);
UINFO(9," Created "<<finalp<<endl);
finalp = new AstAlwaysPost(nodep->fileline(), NULL /*sens*/, NULL /*body*/);
UINFO(9, " Created " << finalp << endl);
AstActive* newactp = createActivePost(varrefp);
newactp->addStmtsp(finalp);
varrefp->varScopep()->user4p(finalp);
@ -332,9 +334,8 @@ private:
"Delayed assignment misoptimized; prev var found w/o associated IF");
} else {
postLogicp = new AstIf(nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, false),
NULL, NULL);
UINFO(9," Created "<<postLogicp<<endl);
new AstVarRef(nodep->fileline(), setvscp, false), NULL, NULL);
UINFO(9, " Created " << postLogicp << endl);
finalp->addBodysp(postLogicp);
finalp->user3p(setvscp); // Remember IF's vset variable
finalp->user4p(postLogicp); // and the associated IF, as we may be able to reuse it
@ -345,12 +346,12 @@ private:
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
//VV***** We reset all userp() on the netlist
// VV***** We reset all userp() on the netlist
m_modVarMap.clear();
iterateChildren(nodep);
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
UINFO(4," MOD "<<nodep<<endl);
UINFO(4, " MOD " << nodep << endl);
AstNode::user3ClearTree();
iterateChildren(nodep);
}
@ -363,28 +364,34 @@ private:
m_activep = nodep;
bool oldinit = m_inInitial;
m_inInitial = nodep->hasInitial();
AstNode::user3ClearTree(); // Two sets to same variable in different actives must use different vars.
AstNode::user3ClearTree(); // Two sets to same variable in different
// actives must use different vars.
iterateChildren(nodep);
m_inInitial = oldinit;
}
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
m_inDly = true;
m_nextDlyp = VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL.
if (m_cfuncp) nodep->v3error("Unsupported: Delayed assignment inside public function/task");
m_nextDlyp
= VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL.
if (m_cfuncp) {
nodep->v3error("Unsupported: Delayed assignment inside public function/task");
}
if (VN_IS(nodep->lhsp(), ArraySel)
|| (VN_IS(nodep->lhsp(), Sel)
&& VN_IS(VN_CAST(nodep->lhsp(), Sel)->fromp(), ArraySel))) {
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* newlhsp = createDlyArray(nodep, lhsp);
if (m_inLoop) nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for loops (non-delayed is ok - see docs)");
if (m_inLoop) {
nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for "
"loops (non-delayed is ok - see docs)");
}
if (newlhsp) {
nodep->lhsp(newlhsp);
} else {
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
VL_DO_DANGLING(lhsp->deleteTree(), lhsp);
}
else {
} else {
iterateChildren(nodep);
}
m_inDly = false;
@ -394,11 +401,12 @@ private:
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (!nodep->user2Inc()) { // Not done yet
if (m_inDly && nodep->lvalue()) {
UINFO(4,"AssignDlyVar: "<<nodep<<endl);
UINFO(4, "AssignDlyVar: " << nodep << endl);
markVarUsage(nodep->varScopep(), VU_DLY);
UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block");
if (!m_activep->hasClocked()) {
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active");
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should "
"have converted in V3Active");
}
AstVarScope* oldvscp = nodep->varScopep();
UASSERT_OBJ(oldvscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
@ -408,16 +416,14 @@ private:
checkActivePost(nodep, oldactivep);
}
if (!dlyvscp) { // First use of this delayed variable
string newvarname = (string("__Vdly__")+nodep->varp()->shortName());
string newvarname = (string("__Vdly__") + nodep->varp()->shortName());
dlyvscp = createVarSc(oldvscp, newvarname, 0, NULL);
AstNodeAssign* prep
= new AstAssignPre(nodep->fileline(),
new AstVarRef(nodep->fileline(), dlyvscp, true),
new AstVarRef(nodep->fileline(), oldvscp, false));
AstNodeAssign* postp
= new AstAssignPost(nodep->fileline(),
new AstVarRef(nodep->fileline(), oldvscp, true),
new AstVarRef(nodep->fileline(), dlyvscp, false));
AstNodeAssign* prep = new AstAssignPre(
nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true),
new AstVarRef(nodep->fileline(), oldvscp, false));
AstNodeAssign* postp = new AstAssignPost(
nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true),
new AstVarRef(nodep->fileline(), dlyvscp, false));
postp->lhsp()->user2(true); // Don't detect this assignment
oldvscp->user1p(dlyvscp); // So we can find it later
// Make new ACTIVE with identical sensitivity tree
@ -428,12 +434,12 @@ private:
}
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true);
newrefp->user2(true); // No reason to do it again
nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
else if (!m_inDly && nodep->lvalue()) {
//UINFO(9,"NBA "<<nodep<<endl);
nodep->replaceWith(newrefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (!m_inDly && nodep->lvalue()) {
// UINFO(9, "NBA " << nodep << endl);
if (!m_inInitial) {
UINFO(4,"AssignNDlyVar: "<<nodep<<endl);
UINFO(4, "AssignNDlyVar: " << nodep << endl);
markVarUsage(nodep->varScopep(), VU_NONDLY);
}
}
@ -441,7 +447,8 @@ private:
}
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE {
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin");
nodep->v3fatalSrc(
"For statements should have been converted to while statements in V3Begin");
}
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
bool oldloop = m_inLoop;
@ -474,9 +481,7 @@ public:
// Delayed class functions
void V3Delayed::delayedAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
DelayedVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ DelayedVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("delayed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -51,7 +51,7 @@ private:
void createDeepTemp(AstNode* nodep) {
UINFO(6, " Deep " << nodep << endl);
// if (debug()>=9) nodep->dumpTree(cout, "deep:");
// if (debug() >= 9) nodep->dumpTree(cout, "deep:");
string newvarname = (string("__Vdeeptemp") + cvtToStr(m_modp->varNumGetInc()));
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname,

View File

@ -258,7 +258,7 @@ private:
nodep->varScopep(NULL);
}
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
// UINFO(9," "<<nodep<<endl);
// UINFO(9, " " << nodep << endl);
iterateChildren(nodep);
// Convert the hierch name
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");

File diff suppressed because it is too large Load Diff

View File

@ -39,23 +39,32 @@ public:
V3OutCFile* ofp() const { return m_ofp; }
void puts(const string& str) { ofp()->puts(str); }
void putbs(const string& str) { ofp()->putbs(str); }
void putsDecoration(const string& str) { if (v3Global.opt.decoration()) puts(str); }
void putsDecoration(const string& str) {
if (v3Global.opt.decoration()) puts(str);
}
void putsQuoted(const string& str) { ofp()->putsQuoted(str); }
bool optSystemC() { return v3Global.opt.systemC(); }
static string protect(const string& name) { return VIdProtect::protectIf(name, true); }
static string protectIf(const string& name, bool doIt) {
return VIdProtect::protectIf(name, doIt); }
return VIdProtect::protectIf(name, doIt);
}
static string protectWordsIf(const string& name, bool doIt) {
return VIdProtect::protectWordsIf(name, doIt); }
return VIdProtect::protectWordsIf(name, doIt);
}
static string ifNoProtect(const string& in) { return v3Global.opt.protectIds() ? "" : in; }
static string symClassName() { return v3Global.opt.prefix()+"_"+protect("_Syms"); }
static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; }
static string symClassName() { return v3Global.opt.prefix() + "_" + protect("_Syms"); }
static string symClassVar() { return symClassName() + "* __restrict vlSymsp"; }
static string symTopAssign() {
return v3Global.opt.prefix()+"* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; }
return v3Global.opt.prefix() + "* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;";
}
static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) {
if (nodep->isConstructor()) return prefixNameProtect(modp);
else if (nodep->isDestructor()) return string("~") + prefixNameProtect(modp);
else return nodep->nameProtect();
if (nodep->isConstructor()) {
return prefixNameProtect(modp);
} else if (nodep->isDestructor()) {
return string("~") + prefixNameProtect(modp);
} else {
return nodep->nameProtect();
}
}
static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix
const AstNodeModule* modp = VN_CAST_CONST(nodep, NodeModule);
@ -79,15 +88,17 @@ public:
// Return argument list for given C function
string args = nodep->argTypes();
// Might be a user function with argument list.
for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) {
for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) {
if (const AstVar* portp = VN_CAST_CONST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) {
if (args != "") args+= ", ";
if (nodep->dpiImport() || nodep->dpiExportWrapper())
if (args != "") args += ", ";
if (nodep->dpiImport() || nodep->dpiExportWrapper()) {
args += portp->dpiArgType(true, false);
else if (nodep->funcPublic())
} else if (nodep->funcPublic()) {
args += portp->cPubArgType(true, false);
else args += portp->vlArgType(true, false, true);
} else {
args += portp->vlArgType(true, false, true);
}
}
}
}
@ -114,6 +125,7 @@ private:
m_count++;
iterateChildren(nodep);
}
public:
// CONSTRUCTORS
explicit EmitCBaseCounterVisitor(AstNode* nodep) {

View File

@ -35,8 +35,7 @@ class CMakeEmitter {
// STATIC FUNCTIONS
// Concatenate all strings in 'strs' with ' ' between them.
template<typename List>
static string cmake_list(const List& strs) {
template <typename List> static string cmake_list(const List& strs) {
string s;
if (strs.begin() != strs.end()) {
s.append("\"");
@ -56,16 +55,14 @@ class CMakeEmitter {
// "BOOL", "FILEPATH", "PATH", "STRING" or "INTERNAL" for a CACHE variable
// See https://cmake.org/cmake/help/latest/command/set.html
static void cmake_set_raw(std::ofstream& of, const string& name, const string& raw_value,
const string& cache_type = "", const string& docstring = "") {
const string& cache_type = "", const string& docstring = "") {
of << "set(" << name << " " << raw_value;
if (!cache_type.empty()) {
of << " CACHE " << cache_type << " \"" << docstring << "\"";
}
if (!cache_type.empty()) { of << " CACHE " << cache_type << " \"" << docstring << "\""; }
of << ")\n";
}
static void cmake_set(std::ofstream& of, const string& name, const string& value,
const string& cache_type = "", const string& docstring = "") {
const string& cache_type = "", const string& docstring = "") {
string raw_value = "\"" + value + "\"";
cmake_set_raw(of, name, raw_value, cache_type, docstring);
}
@ -80,22 +77,24 @@ class CMakeEmitter {
}
static void emitOverallCMake() {
const vl_unique_ptr<std::ofstream>
of (V3File::new_ofstream(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+".cmake"));
const vl_unique_ptr<std::ofstream> of(
V3File::new_ofstream(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".cmake"));
string name = v3Global.opt.prefix();
*of << "# Verilated -*- CMake -*-\n";
*of << "# DESCR" "IPTION: Verilator output: CMake include script with class lists\n";
*of << "# DESCR"
"IPTION: Verilator output: CMake include script with class lists\n";
*of << "#\n";
*of << "# This CMake script lists generated Verilated files, for including in higher level CMake scripts.\n";
*of << "# This CMake script lists generated Verilated files, for "
"including in higher level CMake scripts.\n";
*of << "# This file is meant to be consumed by the verilate() function,\n";
*of << "# which becomes available after executing `find_package(verilator).\n";
*of << "\n### Constants...\n";
cmake_set(*of, "PERL", deslash(V3Options::getenvPERL()),
"FILEPATH", "Perl executable (from $PERL)");
cmake_set(*of, "VERILATOR_ROOT", deslash(V3Options::getenvVERILATOR_ROOT()),
"PATH", "Path to Verilator kit (from $VERILATOR_ROOT)");
cmake_set(*of, "PERL", deslash(V3Options::getenvPERL()), "FILEPATH",
"Perl executable (from $PERL)");
cmake_set(*of, "VERILATOR_ROOT", deslash(V3Options::getenvVERILATOR_ROOT()), "PATH",
"Path to Verilator kit (from $VERILATOR_ROOT)");
*of << "\n### Compiler flags...\n";
@ -110,13 +109,19 @@ class CMakeEmitter {
*of << "# SystemC output mode? 0/1 (from --sc)\n";
cmake_set_raw(*of, name + "_SC", v3Global.opt.systemC() ? "1" : "0");
*of << "# Coverage output mode? 0/1 (from --coverage)\n";
cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage()?"1":"0");
cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage() ? "1" : "0");
*of << "# Threaded output mode? 0/1/N threads (from --threads)\n";
cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads()));
*of << "# VCD Tracing output mode? 0/1 (from --trace)\n";
cmake_set_raw(*of, name + "_TRACE_VCD", (v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD))?"1":"0");
cmake_set_raw(*of, name + "_TRACE_VCD",
(v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD))
? "1"
: "0");
*of << "# FST Tracing output mode? 0/1 (from --fst-trace)\n";
cmake_set_raw(*of, name + "_TRACE_FST", (v3Global.opt.trace() && (v3Global.opt.traceFormat() != TraceFormat::VCD)) ? "1":"0");
cmake_set_raw(*of, name + "_TRACE_FST",
(v3Global.opt.trace() && (v3Global.opt.traceFormat() != TraceFormat::VCD))
? "1"
: "0");
*of << "\n### Sources...\n";
std::vector<string> classes_fast, classes_slow, support_fast, support_slow, global;
@ -141,7 +146,7 @@ class CMakeEmitter {
}
global.push_back("${VERILATOR_ROOT}/include/verilated.cpp");
if (v3Global.dpi()) {
if (v3Global.dpi()) { //
global.push_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp");
}
if (v3Global.opt.vpi()) {
@ -154,21 +159,22 @@ class CMakeEmitter {
global.push_back("${VERILATOR_ROOT}/include/verilated_cov.cpp");
}
if (v3Global.opt.trace()) {
global.push_back("${VERILATOR_ROOT}/include/"
+ v3Global.opt.traceSourceBase() + "_c.cpp");
global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase()
+ "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3error("Unsupported: This trace format is not supported in SystemC, use VCD format.");
v3error("Unsupported: This trace format is not supported in SystemC, "
"use VCD format.");
}
global.push_back("${VERILATOR_ROOT}/include/"
+ v3Global.opt.traceSourceLang() + ".cpp");
global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang()
+ ".cpp");
}
}
if (v3Global.opt.mtasks()) {
global.push_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
}
if (!v3Global.opt.protectLib().empty()) {
global.push_back(v3Global.opt.makeDir()+"/"+v3Global.opt.protectLib()+".cpp");
global.push_back(v3Global.opt.makeDir() + "/" + v3Global.opt.protectLib() + ".cpp");
}
*of << "# Global classes, need linked once per executable\n";
@ -177,7 +183,8 @@ class CMakeEmitter {
cmake_set_raw(*of, name + "_CLASSES_SLOW", deslash(cmake_list(classes_slow)));
*of << "# Generated module classes, fast-path, compile with highest optimization\n";
cmake_set_raw(*of, name + "_CLASSES_FAST", deslash(cmake_list(classes_fast)));
*of << "# Generated support classes, non-fast-path, compile with low/medium optimization\n";
*of << "# Generated support classes, non-fast-path, compile with "
"low/medium optimization\n";
cmake_set_raw(*of, name + "_SUPPORT_SLOW", deslash(cmake_list(support_slow)));
*of << "# Generated support classes, fast-path, compile with highest optimization\n";
cmake_set_raw(*of, name + "_SUPPORT_FAST", deslash(cmake_list(support_fast)));
@ -188,14 +195,13 @@ class CMakeEmitter {
*of << "# User .cpp files (from .cpp's on Verilator command line)\n";
cmake_set_raw(*of, name + "_USER_CLASSES", deslash(cmake_list(v3Global.opt.cppFiles())));
}
public:
explicit CMakeEmitter() {
emitOverallCMake();
}
explicit CMakeEmitter() { emitOverallCMake(); }
virtual ~CMakeEmitter() {}
};
void V3EmitCMake::emit() {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
CMakeEmitter emitter;
}

View File

@ -27,87 +27,91 @@
class EmitMk {
public:
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void putMakeClassEntry(V3OutMkFile& of, const string& name) {
of.puts("\t"+V3Os::filenameNonDirExt(name)+" \\\n");
of.puts("\t" + V3Os::filenameNonDirExt(name) + " \\\n");
}
void emitClassMake() {
// Generate the makefile
V3OutMkFile of (v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_classes.mk");
V3OutMkFile of(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "_classes.mk");
of.putsHeader();
of.puts("# DESCR" "IPTION: Verilator output: Make include file with class lists\n");
of.puts("# DESCR"
"IPTION: Verilator output: Make include file with class lists\n");
of.puts("#\n");
of.puts("# This file lists generated Verilated files, for including in higher level makefiles.\n");
of.puts("# See "+v3Global.opt.prefix()+".mk"+" for the caller.\n");
of.puts("# This file lists generated Verilated files, for including "
"in higher level makefiles.\n");
of.puts("# See " + v3Global.opt.prefix() + ".mk" + " for the caller.\n");
of.puts("\n### Switches...\n");
of.puts("# C11 constructs required? 0/1 (from --threads or use of classes)\n");
of.puts("VM_C11 = " + cvtToStr(v3Global.needC11() || v3Global.opt.threads()) + "\n");
of.puts("# Coverage output mode? 0/1 (from --coverage)\n");
of.puts("VM_COVERAGE = "); of.puts(v3Global.opt.coverage()?"1":"0"); of.puts("\n");
of.puts("VM_COVERAGE = ");
of.puts(v3Global.opt.coverage() ? "1" : "0");
of.puts("\n");
of.puts("# Parallel builds? 0/1 (from --output-split)\n");
of.puts("VM_PARALLEL_BUILDS = ");
of.puts(v3Global.opt.outputSplit() ? "1" : "0"); of.puts("\n");
of.puts(v3Global.opt.outputSplit() ? "1" : "0");
of.puts("\n");
of.puts("# Threaded output mode? 0/1/N threads (from --threads)\n");
of.puts("VM_THREADS = "); of.puts(cvtToStr(v3Global.opt.threads())); of.puts("\n");
of.puts("VM_THREADS = ");
of.puts(cvtToStr(v3Global.opt.threads()));
of.puts("\n");
of.puts("# Tracing output mode? 0/1 (from --trace)\n");
of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace()?"1":"0"); of.puts("\n");
of.puts("VM_TRACE = ");
of.puts(v3Global.opt.trace() ? "1" : "0");
of.puts("\n");
of.puts("# Tracing threaded output mode? 0/1 (from --trace-fst-thread)\n");
of.puts("VM_TRACE_THREADED = "); of.puts(v3Global.opt.traceFormat().threaded()
?"1":"0"); of.puts("\n");
of.puts("VM_TRACE_THREADED = ");
of.puts(v3Global.opt.traceFormat().threaded() ? "1" : "0");
of.puts("\n");
of.puts("\n### Object file lists...\n");
for (int support=0; support<3; ++support) {
for (int slow=0; slow<2; ++slow) {
if (support==2) of.puts("# Global classes, need linked once per executable");
else if (support) of.puts("# Generated support classes");
else of.puts("# Generated module classes");
if (slow) of.puts(", non-fast-path, compile with low/medium optimization\n");
else of.puts(", fast-path, compile with highest optimization\n");
of.puts(support==2?"VM_GLOBAL":support==1?"VM_SUPPORT":"VM_CLASSES");
of.puts(slow?"_SLOW":"_FAST");
for (int support = 0; support < 3; ++support) {
for (int slow = 0; slow < 2; ++slow) {
if (support == 2) {
of.puts("# Global classes, need linked once per executable");
} else if (support) {
of.puts("# Generated support classes");
} else {
of.puts("# Generated module classes");
}
if (slow) {
of.puts(", non-fast-path, compile with low/medium optimization\n");
} else {
of.puts(", fast-path, compile with highest optimization\n");
}
of.puts(support == 2 ? "VM_GLOBAL" : support == 1 ? "VM_SUPPORT" : "VM_CLASSES");
of.puts(slow ? "_SLOW" : "_FAST");
of.puts(" += \\\n");
if (support==2 && !slow) {
if (support == 2 && !slow) {
putMakeClassEntry(of, "verilated.cpp");
if (v3Global.dpi()) {
putMakeClassEntry(of, "verilated_dpi.cpp");
}
if (v3Global.opt.vpi()) {
putMakeClassEntry(of, "verilated_vpi.cpp");
}
if (v3Global.opt.savable()) {
putMakeClassEntry(of, "verilated_save.cpp");
}
if (v3Global.opt.coverage()) {
putMakeClassEntry(of, "verilated_cov.cpp");
}
if (v3Global.dpi()) { putMakeClassEntry(of, "verilated_dpi.cpp"); }
if (v3Global.opt.vpi()) { putMakeClassEntry(of, "verilated_vpi.cpp"); }
if (v3Global.opt.savable()) { putMakeClassEntry(of, "verilated_save.cpp"); }
if (v3Global.opt.coverage()) { putMakeClassEntry(of, "verilated_cov.cpp"); }
if (v3Global.opt.trace()) {
putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3error("Unsupported: This trace format is not supported in SystemC, use VCD format.");
v3error("Unsupported: This trace format is not supported "
"in SystemC, use VCD format.");
} else {
putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp");
}
}
}
if (v3Global.opt.mtasks()) {
putMakeClassEntry(of, "verilated_threads.cpp");
}
}
else if (support==2 && slow) {
}
else {
for (AstNodeFile* nodep = v3Global.rootp()->filesp();
nodep; nodep = VN_CAST(nodep->nextp(), NodeFile)) {
if (v3Global.opt.mtasks()) { putMakeClassEntry(of, "verilated_threads.cpp"); }
} else if (support == 2 && slow) {
} else {
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
nodep = VN_CAST(nodep->nextp(), NodeFile)) {
AstCFile* cfilep = VN_CAST(nodep, CFile);
if (cfilep && cfilep->source()
&& cfilep->slow()==(slow!=0)
&& cfilep->support()==(support!=0)) {
if (cfilep && cfilep->source() && cfilep->slow() == (slow != 0)
&& cfilep->support() == (support != 0)) {
putMakeClassEntry(of, cfilep->name());
}
}
@ -122,55 +126,56 @@ public:
void emitOverallMake() {
// Generate the makefile
V3OutMkFile of (v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+".mk");
V3OutMkFile of(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".mk");
of.putsHeader();
of.puts("# DESCR" "IPTION: Verilator output: Makefile for building Verilated archive or executable\n");
of.puts("# DESCR"
"IPTION: Verilator output: "
"Makefile for building Verilated archive or executable\n");
of.puts("#\n");
of.puts("# Execute this makefile from the object directory:\n");
of.puts("# make -f "+v3Global.opt.prefix()+".mk"+"\n");
of.puts("# make -f " + v3Global.opt.prefix() + ".mk" + "\n");
of.puts("\n");
if (v3Global.opt.exe()) {
of.puts("default: "+v3Global.opt.exeName()+"\n");
of.puts("default: " + v3Global.opt.exeName() + "\n");
} else if (!v3Global.opt.protectLib().empty()) {
of.puts("default: lib"+v3Global.opt.protectLib()+"\n");
of.puts("default: lib" + v3Global.opt.protectLib() + "\n");
} else {
of.puts("default: "+v3Global.opt.prefix()+"__ALL.a\n");
of.puts("default: " + v3Global.opt.prefix() + "__ALL.a\n");
}
of.puts("\n### Constants...\n");
of.puts("# Perl executable (from $PERL)\n");
of.puts("PERL = "+V3Options::getenvPERL()+"\n");
of.puts("PERL = " + V3Options::getenvPERL() + "\n");
of.puts("# Path to Verilator kit (from $VERILATOR_ROOT)\n");
of.puts("VERILATOR_ROOT = "+V3Options::getenvVERILATOR_ROOT()+"\n");
of.puts("VERILATOR_ROOT = " + V3Options::getenvVERILATOR_ROOT() + "\n");
of.puts("# SystemC include directory with systemc.h (from $SYSTEMC_INCLUDE)\n");
of.puts(string("SYSTEMC_INCLUDE ?= ")+V3Options::getenvSYSTEMC_INCLUDE()+"\n");
of.puts(string("SYSTEMC_INCLUDE ?= ") + V3Options::getenvSYSTEMC_INCLUDE() + "\n");
of.puts("# SystemC library directory with libsystemc.a (from $SYSTEMC_LIBDIR)\n");
of.puts(string("SYSTEMC_LIBDIR ?= ")+V3Options::getenvSYSTEMC_LIBDIR()+"\n");
of.puts(string("SYSTEMC_LIBDIR ?= ") + V3Options::getenvSYSTEMC_LIBDIR() + "\n");
of.puts("\n### Switches...\n");
of.puts("# SystemC output mode? 0/1 (from --sc)\n");
of.puts(string("VM_SC = ")+((v3Global.opt.systemC())?"1":"0")+"\n");
of.puts(string("VM_SC = ") + ((v3Global.opt.systemC()) ? "1" : "0") + "\n");
of.puts("# Legacy or SystemC output mode? 0/1 (from --sc)\n");
of.puts(string("VM_SP_OR_SC = $(VM_SC)\n"));
of.puts("# Deprecated\n");
of.puts(string("VM_PCLI = ")+(v3Global.opt.systemC()?"0":"1")+"\n");
of.puts("# Deprecated: SystemC architecture to find link library path (from $SYSTEMC_ARCH)\n");
of.puts(string("VM_SC_TARGET_ARCH = ")+V3Options::getenvSYSTEMC_ARCH()+"\n");
of.puts(string("VM_PCLI = ") + (v3Global.opt.systemC() ? "0" : "1") + "\n");
of.puts(
"# Deprecated: SystemC architecture to find link library path (from $SYSTEMC_ARCH)\n");
of.puts(string("VM_SC_TARGET_ARCH = ") + V3Options::getenvSYSTEMC_ARCH() + "\n");
of.puts("\n### Vars...\n");
of.puts("# Design prefix (from --prefix)\n");
of.puts(string("VM_PREFIX = ")+v3Global.opt.prefix()+"\n");
of.puts(string("VM_PREFIX = ") + v3Global.opt.prefix() + "\n");
of.puts("# Module prefix (from --prefix)\n");
of.puts(string("VM_MODPREFIX = ")+v3Global.opt.modPrefix()+"\n");
of.puts(string("VM_MODPREFIX = ") + v3Global.opt.modPrefix() + "\n");
of.puts("# User CFLAGS (from -CFLAGS on Verilator command line)\n");
of.puts("VM_USER_CFLAGS = \\\n");
if (!v3Global.opt.protectLib().empty()) {
of.puts("\t-fPIC \\\n");
}
if (!v3Global.opt.protectLib().empty()) of.puts("\t-fPIC \\\n");
const V3StringList& cFlags = v3Global.opt.cFlags();
for (V3StringList::const_iterator it = cFlags.begin(); it != cFlags.end(); ++it) {
of.puts("\t"+*it+" \\\n");
of.puts("\t" + *it + " \\\n");
}
of.puts("\n");
@ -178,7 +183,7 @@ public:
of.puts("VM_USER_LDLIBS = \\\n");
const V3StringList& ldLibs = v3Global.opt.ldLibs();
for (V3StringList::const_iterator it = ldLibs.begin(); it != ldLibs.end(); ++it) {
of.puts("\t"+*it+" \\\n");
of.puts("\t" + *it + " \\\n");
}
of.puts("\n");
@ -188,7 +193,7 @@ public:
const V3StringSet& cppFiles = v3Global.opt.cppFiles();
for (V3StringSet::const_iterator it = cppFiles.begin(); it != cppFiles.end(); ++it) {
string cppfile = *it;
of.puts("\t"+V3Os::filenameNonExt(cppfile)+" \\\n");
of.puts("\t" + V3Os::filenameNonExt(cppfile) + " \\\n");
string dir = V3Os::filenameDir(cppfile);
dirs.insert(dir);
}
@ -196,14 +201,14 @@ public:
of.puts("# User .cpp directories (from .cpp's on Verilator command line)\n");
of.puts("VM_USER_DIR = \\\n");
for (V3StringSet::iterator it = dirs.begin(); it!=dirs.end(); ++it) {
of.puts("\t"+*it+" \\\n");
for (V3StringSet::iterator it = dirs.begin(); it != dirs.end(); ++it) {
of.puts("\t" + *it + " \\\n");
}
of.puts("\n");
of.puts("\n### Default rules...\n");
of.puts("# Include list of all generated classes\n");
of.puts("include "+v3Global.opt.prefix()+"_classes.mk\n");
of.puts("include " + v3Global.opt.prefix() + "_classes.mk\n");
of.puts("# Include global rules\n");
of.puts("include $(VERILATOR_ROOT)/include/verilated.mk\n");
@ -215,12 +220,13 @@ public:
string cppfile = *it;
string basename = V3Os::filenameNonExt(cppfile);
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
of.puts(basename+".o: "+cppfile+"\n");
of.puts(basename + ".o: " + cppfile + "\n");
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<\n");
}
of.puts("\n### Link rules... (from --exe)\n");
of.puts(v3Global.opt.exeName()+": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a\n");
of.puts(v3Global.opt.exeName()
+ ": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a\n");
of.puts("\t$(LINK) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ $(LIBS) $(SC_LIBS)\n");
of.puts("\n");
}
@ -229,18 +235,20 @@ public:
of.puts("\n### Library rules... (from --protect-lib)\n");
of.puts("# Using -fPIC objects for both static and dynamic libraries "
"(which appears to work)\n");
of.puts(v3Global.opt.protectLibName(false)+": $(VK_OBJS) $(VK_GLOBAL_OBJS)\n");
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o "+
v3Global.opt.protectLib()+".o "+v3Global.opt.protectLib()+".cpp\n");
of.puts("\tar rc $@ $^ "+v3Global.opt.protectLib()+".o\n");
of.puts(v3Global.opt.protectLibName(false) + ": $(VK_OBJS) $(VK_GLOBAL_OBJS)\n");
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o "
+ v3Global.opt.protectLib() + ".o " + v3Global.opt.protectLib() + ".cpp\n");
of.puts("\tar rc $@ $^ " + v3Global.opt.protectLib() + ".o\n");
of.puts("\n");
of.puts(v3Global.opt.protectLibName(true)+": $(VM_PREFIX)__ALL.a $(VK_GLOBAL_OBJS)\n");
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ "+v3Global.opt.protectLib()+".cpp $^\n");
of.puts(v3Global.opt.protectLibName(true)
+ ": $(VM_PREFIX)__ALL.a $(VK_GLOBAL_OBJS)\n");
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ "
+ v3Global.opt.protectLib() + ".cpp $^\n");
of.puts("\n");
of.puts("lib"+v3Global.opt.protectLib()+": "+v3Global.opt.protectLibName(false)+
" "+v3Global.opt.protectLibName(true)+"\n");
of.puts("lib" + v3Global.opt.protectLib() + ": " + v3Global.opt.protectLibName(false)
+ " " + v3Global.opt.protectLibName(true) + "\n");
}
of.puts("\n");
@ -259,6 +267,6 @@ public:
// Gate class functions
void V3EmitMk::emitmk() {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
EmitMk emitter;
}

View File

@ -32,7 +32,7 @@
class EmitVBaseVisitor : public EmitCBaseVisitor {
// MEMBERS
bool m_suppressSemi;
bool m_suppressSemi;
AstSenTree* m_sensesp;
// METHODS
@ -53,20 +53,19 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstNetlist* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
iterateChildren(nodep);
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
}
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
putfs(nodep, nodep->isFunction() ? "function":"task");
putfs(nodep, nodep->isFunction() ? "function" : "task");
puts(" ");
puts(nodep->prettyName());
puts(";\n");
putqs(nodep, "begin\n"); // Only putfs the first time for each visitor; later for same node is putqs
// Only putfs the first time for each visitor; later for same node is putqs
putqs(nodep, "begin\n");
iterateAndNextNull(nodep->stmtsp());
putqs(nodep, "end\n");
}
@ -75,7 +74,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
if (nodep->name() == "") {
putbs("begin\n");
} else {
putbs("begin : "+nodep->name()+"\n");
putbs("begin : " + nodep->name() + "\n");
}
iterateChildren(nodep);
puts("end\n");
@ -92,23 +91,31 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
putfs(nodep, "always ");
if (m_sensesp) iterateAndNextNull(m_sensesp); // In active
else iterateAndNextNull(nodep->sensesp());
if (m_sensesp) {
iterateAndNextNull(m_sensesp);
} // In active
else {
iterateAndNextNull(nodep->sensesp());
}
putbs(" begin\n");
iterateAndNextNull(nodep->bodysp());
putqs(nodep, "end\n");
}
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
putfs(nodep, "/*verilator public_flat_rw ");
if (m_sensesp) iterateAndNextNull(m_sensesp); // In active
else iterateAndNextNull(nodep->sensesp());
if (m_sensesp) {
iterateAndNextNull(m_sensesp);
} // In active
else {
iterateAndNextNull(nodep->sensesp());
}
putqs(nodep, " ");
iterateAndNextNull(nodep->bodysp());
putqs(nodep, "*/\n");
}
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->lhsp());
putfs(nodep, " "+nodep->verilogKwd()+" ");
putfs(nodep, " " + nodep->verilogKwd() + " ");
iterateAndNextNull(nodep->rhsp());
if (!m_suppressSemi) puts(";\n");
}
@ -139,7 +146,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
// AstSenItem is called for dumping in isolation by V3Order
putfs(nodep, "@(");
for (AstNode* expp=nodep->sensesp(); expp; expp = expp->nextp()) {
for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) {
iterate(expp);
if (expp->nextp()) putqs(expp->nextp(), " or ");
}
@ -178,13 +185,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstCaseItem* nodep) VL_OVERRIDE {
if (nodep->condsp()) {
iterateAndNextNull(nodep->condsp());
} else putbs("default");
} else {
putbs("default");
}
putfs(nodep, ": begin ");
iterateAndNextNull(nodep->bodysp());
putqs(nodep, "end\n");
}
virtual void visit(AstComment* nodep) VL_OVERRIDE {
puts(string("// ")+nodep->name()+"\n");
puts(string("// ") + nodep->name() + "\n");
iterateChildren(nodep);
}
virtual void visit(AstContinue* nodep) VL_OVERRIDE {
@ -195,20 +204,23 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstCoverInc*) VL_OVERRIDE {} // N/A
virtual void visit(AstCoverToggle*) VL_OVERRIDE {} // N/A
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp,
const string& text, AstNode* exprsp) {
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text,
AstNode* exprsp) {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
if (fileOrStrgp) { iterateAndNextNull(fileOrStrgp); putbs(","); }
if (fileOrStrgp) {
iterateAndNextNull(fileOrStrgp);
putbs(",");
}
putsQuoted(text);
for (AstNode* expp=exprsp; expp; expp = expp->nextp()) {
for (AstNode* expp = exprsp; expp; expp = expp->nextp()) {
puts(",");
iterateAndNextNull(expp);
}
puts(");\n");
}
virtual void visit(AstDisable* nodep) VL_OVERRIDE {
putbs("disable "+nodep->name()+";\n");
putbs("disable " + nodep->name() + ";\n");
}
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
@ -251,10 +263,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts(");\n");
}
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
putbs("disable "+cvtToHex(nodep->labelp())+";\n");
putbs("disable " + cvtToHex(nodep->labelp()) + ";\n");
}
virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE {
putbs("begin : "+cvtToHex(nodep)+"\n");
putbs("begin : " + cvtToHex(nodep) + "\n");
if (nodep->stmtsp()) iterateAndNextNull(nodep->stmtsp());
puts("end\n");
}
@ -264,8 +276,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep());
putbs(",");
if (nodep->memp()) iterateAndNextNull(nodep->memp());
if (nodep->lsbp()) { putbs(","); iterateAndNextNull(nodep->lsbp()); }
if (nodep->msbp()) { putbs(","); iterateAndNextNull(nodep->msbp()); }
if (nodep->lsbp()) {
putbs(",");
iterateAndNextNull(nodep->lsbp());
}
if (nodep->msbp()) {
putbs(",");
iterateAndNextNull(nodep->msbp());
}
puts(");\n");
}
virtual void visit(AstSysFuncAsTask* nodep) VL_OVERRIDE {
@ -340,12 +358,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->lhsp());
puts(";\n");
}
virtual void visit(AstStop* nodep) VL_OVERRIDE {
putfs(nodep, "$stop;\n");
}
virtual void visit(AstFinish* nodep) VL_OVERRIDE {
putfs(nodep, "$finish;\n");
}
virtual void visit(AstStop* nodep) VL_OVERRIDE { putfs(nodep, "$stop;\n"); }
virtual void visit(AstFinish* nodep) VL_OVERRIDE { putfs(nodep, "$finish;\n"); }
virtual void visit(AstNodeSimpleText* nodep) VL_OVERRIDE {
if (nodep->tracking() || m_trackText) {
puts(nodep->text());
@ -360,8 +374,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
if (nodep->commas() && childp->nextp()) puts(", ");
}
}
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
}
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {}
virtual void visit(AstCStmt* nodep) VL_OVERRIDE {
putfs(nodep, "$_CSTMT(");
iterateAndNextNull(nodep->bodysp());
@ -384,8 +397,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
// Operators
virtual void emitVerilogFormat(AstNode* nodep, const string& format,
AstNode* lhsp=NULL, AstNode* rhsp=NULL, AstNode* thsp=NULL) {
virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = NULL,
AstNode* rhsp = NULL, AstNode* thsp = NULL) {
// Look at emitVerilog() format for term/uni/dual/triops,
// and write out appropriate text.
// %f Potential fileline-if-change and line break
@ -397,16 +410,18 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
bool inPct = false;
putbs("");
for (string::const_iterator pos = format.begin(); pos != format.end(); ++pos) {
if (pos[0]=='%') {
if (pos[0] == '%') {
inPct = true;
} else if (!inPct) { // Normal text
string s; s+=pos[0]; puts(s);
string s;
s += pos[0];
puts(s);
} else { // Format character
inPct = false;
switch (*pos) {
case '%': puts("%"); break;
case 'f': putfs(nodep, ""); break;
case 'k': putbs(""); break;
case '%': puts("%"); break;
case 'f': putfs(nodep, ""); break;
case 'k': putbs(""); break;
case 'l': {
UASSERT_OBJ(lhsp, nodep, "emitVerilog() references undef node");
iterateAndNextNull(lhsp);
@ -427,9 +442,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->dtypep());
break;
}
default:
nodep->v3fatalSrc("Unknown emitVerilog format code: %"<<pos[0]);
break;
default: nodep->v3fatalSrc("Unknown emitVerilog format code: %" << pos[0]); break;
}
}
}
@ -445,7 +458,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp());
}
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(), nodep->thsp());
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(),
nodep->thsp());
}
virtual void visit(AstAttrOf* nodep) VL_OVERRIDE {
putfs(nodep, "$_ATTROF(");
@ -460,8 +474,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep, "`{");
int comma = 0;
const AstInitArray::KeyItemMap& mapr = nodep->map();
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin();
it != mapr.end(); ++it) {
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
if (comma++) putbs(", ");
puts(cvtToStr(it->first));
puts(":");
@ -472,23 +485,31 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
putbs("(");
iterateAndNextNull(nodep->condp()); putfs(nodep, " ? ");
iterateAndNextNull(nodep->expr1p()); putbs(" : ");
iterateAndNextNull(nodep->expr2p()); puts(")");
iterateAndNextNull(nodep->condp());
putfs(nodep, " ? ");
iterateAndNextNull(nodep->expr1p());
putbs(" : ");
iterateAndNextNull(nodep->expr2p());
puts(")");
}
virtual void visit(AstRange* nodep) VL_OVERRIDE {
puts("[");
if (VN_IS(nodep->msbp(), Const) && VN_IS(nodep->lsbp(), Const)) {
// Looks nicer if we print [1:0] rather than [32'sh1:32sh0]
puts(cvtToStr(VN_CAST(nodep->leftp(), Const)->toSInt())); puts(":");
puts(cvtToStr(VN_CAST(nodep->rightp(), Const)->toSInt())); puts("]");
puts(cvtToStr(VN_CAST(nodep->leftp(), Const)->toSInt()));
puts(":");
puts(cvtToStr(VN_CAST(nodep->rightp(), Const)->toSInt()));
puts("]");
} else {
iterateAndNextNull(nodep->leftp()); puts(":");
iterateAndNextNull(nodep->rightp()); puts("]");
iterateAndNextNull(nodep->leftp());
puts(":");
iterateAndNextNull(nodep->rightp());
puts("]");
}
}
virtual void visit(AstSel* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->fromp()); puts("[");
iterateAndNextNull(nodep->fromp());
puts("[");
if (VN_IS(nodep->lsbp(), Const)) {
if (nodep->widthp()->isOne()) {
if (VN_IS(nodep->lsbp(), Const)) {
@ -498,14 +519,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
} else {
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()
+ VN_CAST(nodep->widthp(), Const)->toSInt()
- 1));
+ VN_CAST(nodep->widthp(), Const)->toSInt() - 1));
puts(":");
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()));
}
} else {
iterateAndNextNull(nodep->lsbp()); putfs(nodep, "+:");
iterateAndNextNull(nodep->widthp()); puts("]");
iterateAndNextNull(nodep->lsbp());
putfs(nodep, "+:");
iterateAndNextNull(nodep->widthp());
puts("]");
}
puts("]");
}
@ -515,15 +537,23 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
putfs(nodep, "typedef ");
iterateAndNextNull(nodep->dtypep()); puts(" ");
iterateAndNextNull(nodep->dtypep());
puts(" ");
puts(nodep->prettyName());
puts(";\n");
}
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
if (nodep->isSigned()) putfs(nodep, "signed ");
putfs(nodep, nodep->prettyName());
if (nodep->rangep()) { puts(" "); iterateAndNextNull(nodep->rangep()); puts(" "); }
else if (nodep->isRanged()) { puts(" ["); puts(cvtToStr(nodep->msb())); puts(":0] "); }
if (nodep->rangep()) {
puts(" ");
iterateAndNextNull(nodep->rangep());
puts(" ");
} else if (nodep->isRanged()) {
puts(" [");
puts(cvtToStr(nodep->msb()));
puts(":0] ");
}
}
virtual void visit(AstConstDType* nodep) VL_OVERRIDE {
putfs(nodep, "const ");
@ -534,7 +564,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
iterateAndNextNull(nodep->rangep());
}
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
puts(nodep->verilogKwd()+" ");
puts(nodep->verilogKwd() + " ");
if (nodep->packed()) puts("packed ");
puts("\n");
iterateAndNextNull(nodep->membersp());
@ -547,16 +577,18 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts("}");
}
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
if (nodep->dotted()!="") {
putfs(nodep, nodep->dotted()); puts("."); puts(nodep->prettyName());
} else { putfs(nodep, nodep->prettyName()); }
if (nodep->dotted() != "") {
putfs(nodep, nodep->dotted());
puts(".");
puts(nodep->prettyName());
} else {
putfs(nodep, nodep->prettyName());
}
puts("(");
iterateAndNextNull(nodep->pinsp());
puts(")");
}
virtual void visit(AstArg* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->exprp());
}
virtual void visit(AstArg* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->exprp()); }
// Terminals
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (nodep->varScopep()) {
@ -576,18 +608,19 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
// Just iterate
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstTopScope* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstScope* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstVar* nodep) VL_OVERRIDE {
putfs(nodep, nodep->verilogKwd());
puts(" ");
iterate(nodep->dtypep()); puts(" ");
iterate(nodep->dtypep());
puts(" ");
puts(nodep->prettyName());
if (!m_suppressVarSemi) puts(";\n"); else puts("\n");
if (!m_suppressVarSemi) {
puts(";\n");
} else {
puts("\n");
}
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
m_sensesp = nodep->sensesp();
@ -603,15 +636,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstCell*) VL_OVERRIDE {} // Handled outside the Visit class
// Default
virtual void visit(AstNode* nodep) VL_OVERRIDE {
puts(string("\n???? // ")+nodep->prettyTypeName()+"\n");
puts(string("\n???? // ") + nodep->prettyTypeName() + "\n");
iterateChildren(nodep);
// Not v3fatalSrc so we keep processing
nodep->v3error("Internal: Unknown node type reached emitter: "<<nodep->prettyTypeName());
nodep->v3error("Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
}
public:
bool m_suppressVarSemi; // Suppress emitting semicolon for AstVars
explicit EmitVBaseVisitor(AstSenTree* domainp=NULL) {
bool m_suppressVarSemi; // Suppress emitting semicolon for AstVars
explicit EmitVBaseVisitor(AstSenTree* domainp = NULL) {
// Domain for printing one a ALWAYS under a ACTIVE
m_suppressSemi = false;
m_suppressVarSemi = false;
@ -625,17 +658,18 @@ public:
class EmitVFileVisitor : public EmitVBaseVisitor {
// MEMBERS
V3OutFile* m_ofp;
V3OutFile* m_ofp;
// METHODS
V3OutFile* ofp() const { return m_ofp; }
V3OutFile* ofp() const { return m_ofp; }
virtual void puts(const string& str) { ofp()->puts(str); }
virtual void putbs(const string& str) { ofp()->putbs(str); }
virtual void putfs(AstNode*, const string& str) { putbs(str); }
virtual void putqs(AstNode*, const string& str) { putbs(str); }
virtual void putsNoTracking(const string& str) { ofp()->putsNoTracking(str); }
public:
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText=false,
bool suppressVarSemi=false) {
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText = false,
bool suppressVarSemi = false) {
m_ofp = ofp;
m_trackText = trackText;
m_suppressVarSemi = suppressVarSemi;
@ -649,13 +683,14 @@ public:
class EmitVStreamVisitor : public EmitVBaseVisitor {
// MEMBERS
std::ostream& m_os;
std::ostream& m_os;
// METHODS
virtual void putsNoTracking(const string& str) { m_os<<str; }
virtual void putsNoTracking(const string& str) { m_os << str; }
virtual void puts(const string& str) { putsNoTracking(str); }
virtual void putbs(const string& str) { puts(str); }
virtual void putfs(AstNode*, const string& str) { putbs(str); }
virtual void putqs(AstNode*, const string& str) { putbs(str); }
public:
EmitVStreamVisitor(AstNode* nodep, std::ostream& os)
: m_os(os) {
@ -668,37 +703,41 @@ public:
// Emit to a stream (perhaps stringstream)
class EmitVPrefixedFormatter : public V3OutFormatter {
std::ostream& m_os;
string m_prefix; // What to print at beginning of each line
int m_flWidth; // Padding of fileline
int m_column; // Rough location; need just zero or non-zero
FileLine* m_prefixFl;
std::ostream& m_os;
string m_prefix; // What to print at beginning of each line
int m_flWidth; // Padding of fileline
int m_column; // Rough location; need just zero or non-zero
FileLine* m_prefixFl;
// METHODS
virtual void putcOutput(char chr) {
if (chr == '\n') {
m_column = 0;
m_os<<chr;
m_os << chr;
} else {
if (m_column == 0) {
m_column = 10;
m_os<<m_prefixFl->ascii()+":";
m_os<<V3OutFile::indentSpaces(m_flWidth-(m_prefixFl->ascii().length()+1));
m_os<<" ";
m_os<<m_prefix;
m_os << m_prefixFl->ascii() + ":";
m_os << V3OutFile::indentSpaces(m_flWidth - (m_prefixFl->ascii().length() + 1));
m_os << " ";
m_os << m_prefix;
}
m_column++;
m_os<<chr;
m_os << chr;
}
}
public:
void prefixFl(FileLine* fl) { m_prefixFl = fl; }
FileLine* prefixFl() const { return m_prefixFl; }
int column() const { return m_column; }
EmitVPrefixedFormatter(std::ostream& os, const string& prefix, int flWidth)
: V3OutFormatter("__STREAM", V3OutFormatter::LA_VERILOG)
, m_os(os), m_prefix(prefix), m_flWidth(flWidth) {
, m_os(os)
, m_prefix(prefix)
, m_flWidth(flWidth) {
m_column = 0;
m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of NULL to avoid NULL checks
m_prefixFl = v3Global.rootp()
->fileline(); // NETLIST's fileline instead of NULL to avoid NULL checks
}
virtual ~EmitVPrefixedFormatter() {
if (m_column) puts("\n");
@ -707,7 +746,8 @@ public:
class EmitVPrefixedVisitor : public EmitVBaseVisitor {
// MEMBERS
EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the inheritance is another unused V3OutFormatter)
EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the
// inheritance is another unused V3OutFormatter)
// METHODS
virtual void putsNoTracking(const string& str) { m_formatter.putsNoTracking(str); }
virtual void puts(const string& str) { m_formatter.puts(str); }
@ -728,7 +768,8 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
public:
EmitVPrefixedVisitor(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth,
AstSenTree* domainp, bool user3mark)
: EmitVBaseVisitor(domainp), m_formatter(os, prefix, flWidth) {
: EmitVBaseVisitor(domainp)
, m_formatter(os, prefix, flWidth) {
if (user3mark) { AstUser3InUse::check(); }
iterate(nodep);
}
@ -739,13 +780,14 @@ public:
// EmitV class functions
void V3EmitV::emitv() {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
if (true) {
// All-in-one file
V3OutVFile of (v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__Vout.v");
V3OutVFile of(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__Vout.v");
of.putsHeader();
of.puts("# DESCR" "IPTION: Verilator output: Verilog representation of internal tree for debug\n");
EmitVFileVisitor visitor (v3Global.rootp(), &of);
of.puts("# DESCR"
"IPTION: Verilator output: Verilog representation of internal tree for debug\n");
EmitVFileVisitor visitor(v3Global.rootp(), &of);
} else {
// Process each module in turn
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
@ -758,24 +800,22 @@ void V3EmitV::emitv() {
}
}
void V3EmitV::verilogForTree(AstNode* nodep, std::ostream& os) {
EmitVStreamVisitor(nodep, os);
}
void V3EmitV::verilogForTree(AstNode* nodep, std::ostream& os) { EmitVStreamVisitor(nodep, os); }
void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os,
const string& prefix, int flWidth,
AstSenTree* domainp, bool user3mark) {
void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix,
int flWidth, AstSenTree* domainp, bool user3mark) {
EmitVPrefixedVisitor(nodep, os, prefix, flWidth, domainp, user3mark);
}
void V3EmitV::emitvFiles() {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
for (AstNodeFile* filep = v3Global.rootp()->filesp(); filep;
filep = VN_CAST(filep->nextp(), NodeFile)) {
AstVFile* vfilep = VN_CAST(filep, VFile);
if (vfilep && vfilep->tblockp()) {
V3OutVFile of(vfilep->name());
of.puts("// DESCR" "IPTION: Verilator generated Verilog\n");
of.puts("// DESCR"
"IPTION: Verilator generated Verilog\n");
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true);
}
}

View File

@ -33,18 +33,18 @@
class EmitXmlFileVisitor : public AstNVisitor {
// NODE STATE
//Entire netlist:
// Entire netlist:
// AstNode::user1 -> uint64_t, number to connect crossrefs
// MEMBERS
V3OutFile* m_ofp;
uint64_t m_id;
V3OutFile* m_ofp;
uint64_t m_id;
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// Outfile methods
V3OutFile* ofp() const { return m_ofp; }
V3OutFile* ofp() const { return m_ofp; }
virtual void puts(const string& str) { ofp()->puts(str); }
virtual void putbs(const string& str) { ofp()->putbs(str); }
virtual void putfs(AstNode*, const string& str) { putbs(str); }
@ -62,29 +62,42 @@ class EmitXmlFileVisitor : public AstNVisitor {
// XML methods
void outputId(AstNode* nodep) {
if (!nodep->user1()) { nodep->user1(++m_id); }
puts("\""+cvtToStr(nodep->user1())+"\"");
puts("\"" + cvtToStr(nodep->user1()) + "\"");
}
void outputTag(AstNode* nodep, string tag) {
if (tag=="") tag = VString::downcase(nodep->typeName());
puts("<"+tag+" "+nodep->fileline()->xml());
puts(" "+nodep->fileline()->xmlDetailedLocation());
if (VN_IS(nodep, NodeDType)) { puts(" id="); outputId(nodep); }
if (nodep->name()!="") { puts(" name="); putsQuoted(nodep->prettyName()); }
if (nodep->tag()!="") { puts(" tag="); putsQuoted(nodep->tag()); }
if (tag == "") tag = VString::downcase(nodep->typeName());
puts("<" + tag + " " + nodep->fileline()->xml());
puts(" " + nodep->fileline()->xmlDetailedLocation());
if (VN_IS(nodep, NodeDType)) {
puts(" id=");
outputId(nodep);
}
if (nodep->name() != "") {
puts(" name=");
putsQuoted(nodep->prettyName());
}
if (nodep->tag() != "") {
puts(" tag=");
putsQuoted(nodep->tag());
}
if (AstNodeDType* dtp = VN_CAST(nodep, NodeDType)) {
if (dtp->subDTypep()) {
puts(" sub_dtype_id="); outputId(dtp->subDTypep()->skipRefp());
puts(" sub_dtype_id=");
outputId(dtp->subDTypep()->skipRefp());
}
} else {
if (nodep->dtypep()) { puts(" dtype_id="); outputId(nodep->dtypep()->skipRefp()); }
if (nodep->dtypep()) {
puts(" dtype_id=");
outputId(nodep->dtypep()->skipRefp());
}
}
}
void outputChildrenEnd(AstNode* nodep, string tag) {
if (tag=="") tag = VString::downcase(nodep->typeName());
if (tag == "") tag = VString::downcase(nodep->typeName());
if (nodep->op1p() || nodep->op2p() || nodep->op3p() || nodep->op4p()) {
puts(">\n");
iterateChildren(nodep);
puts("</"+tag+">\n");
puts("</" + tag + ">\n");
} else {
puts("/>\n");
}
@ -97,8 +110,10 @@ class EmitXmlFileVisitor : public AstNVisitor {
}
virtual void visit(AstCell* nodep) VL_OVERRIDE {
outputTag(nodep, "instance"); // IEEE: vpiInstance
puts(" defName="); putsQuoted(nodep->modName()); // IEEE vpiDefName
puts(" origName="); putsQuoted(nodep->origName());
puts(" defName=");
putsQuoted(nodep->modName()); // IEEE vpiDefName
puts(" origName=");
putsQuoted(nodep->origName());
outputChildrenEnd(nodep, "instance");
}
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
@ -108,8 +123,10 @@ class EmitXmlFileVisitor : public AstNVisitor {
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" origName="); putsQuoted(nodep->origName());
if (nodep->level()==1 || nodep->level()==2) // ==2 because we don't add wrapper when in XML mode
puts(" origName=");
putsQuoted(nodep->origName());
if (nodep->level() == 1
|| nodep->level() == 2) // ==2 because we don't add wrapper when in XML mode
puts(" topModule=\"1\""); // IEEE vpiTopModule
if (nodep->modPublic()) puts(" public=\"true\"");
outputChildrenEnd(nodep, "");
@ -120,13 +137,16 @@ class EmitXmlFileVisitor : public AstNVisitor {
string vt = nodep->dtypep()->name();
outputTag(nodep, "");
if (nodep->isIO()) {
puts(" dir="); putsQuoted(kw);
puts(" vartype="); putsQuoted(!vt.empty()
? vt : typ == AstVarType::PORT ? "port" : "unknown");
puts(" dir=");
putsQuoted(kw);
puts(" vartype=");
putsQuoted(!vt.empty() ? vt : typ == AstVarType::PORT ? "port" : "unknown");
} else {
puts(" vartype="); putsQuoted(!vt.empty() ? vt : kw);
puts(" vartype=");
putsQuoted(!vt.empty() ? vt : kw);
}
puts(" origName="); putsQuoted(nodep->origName());
puts(" origName=");
putsQuoted(nodep->origName());
// Attributes
if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES)
puts(" clocker=\"true\"");
@ -137,8 +157,10 @@ class EmitXmlFileVisitor : public AstNVisitor {
if (nodep->isSigPublic()) puts(" public=\"true\"");
if (nodep->isSigUserRdPublic()) puts(" public_flat_rd=\"true\"");
if (nodep->isSigUserRWPublic()) puts(" public_flat_rw=\"true\"");
if (nodep->isGParam()) puts(" param=\"true\"");
else if (nodep->isParam()) puts(" localparam=\"true\"");
if (nodep->isGParam())
puts(" param=\"true\"");
else if (nodep->isParam())
puts(" localparam=\"true\"");
if (nodep->attrScBv()) puts(" sc_bv=\"true\"");
if (nodep->attrScClocked()) puts(" sc_clock=\"true\"");
if (nodep->attrSFormat()) puts(" sformat=\"true\"");
@ -148,27 +170,29 @@ class EmitXmlFileVisitor : public AstNVisitor {
// What we call a pin in verilator is a port in the IEEE spec.
outputTag(nodep, "port"); // IEEE: vpiPort
if (nodep->modVarp()->isIO()) {
puts(" direction=\""+nodep->modVarp()->direction().xmlKwd()+"\"");
puts(" direction=\"" + nodep->modVarp()->direction().xmlKwd() + "\"");
}
puts(" portIndex=\""+cvtToStr(nodep->pinNum())+"\""); // IEEE: vpiPortIndex
puts(" portIndex=\"" + cvtToStr(nodep->pinNum()) + "\""); // IEEE: vpiPortIndex
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
outputChildrenEnd(nodep, "port");
}
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" edgeType=\""+cvtToStr(nodep->edgeType().ascii())+"\""); // IEEE vpiTopModule
puts(" edgeType=\"" + cvtToStr(nodep->edgeType().ascii()) + "\""); // IEEE vpiTopModule
outputChildrenEnd(nodep, "");
}
virtual void visit(AstModportVarRef* nodep) VL_OVERRIDE {
// Dump direction for Modport references
string kw = nodep->direction().xmlKwd();
outputTag(nodep, "");
puts(" direction="); putsQuoted(kw);
puts(" direction=");
putsQuoted(kw);
outputChildrenEnd(nodep, "");
}
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" dotted="); putsQuoted(nodep->dotted());
puts(" dotted=");
putsQuoted(nodep->dotted());
outputChildrenEnd(nodep, "");
}
@ -176,8 +200,8 @@ class EmitXmlFileVisitor : public AstNVisitor {
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
outputTag(nodep, "basicdtype");
if (nodep->isRanged()) {
puts(" left=\""+cvtToStr(nodep->left())+"\"");
puts(" right=\""+cvtToStr(nodep->right())+"\"");
puts(" left=\"" + cvtToStr(nodep->left()) + "\"");
puts(" right=\"" + cvtToStr(nodep->right()) + "\"");
}
puts("/>\n");
}
@ -185,29 +209,36 @@ class EmitXmlFileVisitor : public AstNVisitor {
string mpn;
outputTag(nodep, "");
if (nodep->isModport()) mpn = nodep->modportName();
puts(" modportname="); putsQuoted(mpn);
puts(" modportname=");
putsQuoted(mpn);
outputChildrenEnd(nodep, "");
}
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" displaytype="); putsQuoted(nodep->verilogKwd());
puts(" displaytype=");
putsQuoted(nodep->verilogKwd());
outputChildrenEnd(nodep, "");
}
virtual void visit(AstElabDisplay* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" displaytype="); putsQuoted(nodep->verilogKwd());
puts(" displaytype=");
putsQuoted(nodep->verilogKwd());
outputChildrenEnd(nodep, "");
}
virtual void visit(AstExtend* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" width="); putsQuoted(cvtToStr(nodep->width()));
puts(" widthminv="); putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
puts(" width=");
putsQuoted(cvtToStr(nodep->width()));
puts(" widthminv=");
putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
outputChildrenEnd(nodep, "");
}
virtual void visit(AstExtendS* nodep) VL_OVERRIDE {
outputTag(nodep, "");
puts(" width="); putsQuoted(cvtToStr(nodep->width()));
puts(" widthminv="); putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
puts(" width=");
putsQuoted(cvtToStr(nodep->width()));
puts(" widthminv=");
putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
outputChildrenEnd(nodep, "");
}
@ -216,6 +247,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
outputTag(nodep, "");
outputChildrenEnd(nodep, "");
}
public:
EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp) {
m_ofp = ofp;
@ -246,8 +278,7 @@ private:
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
// Only list modules and interfaces
// Assumes modules and interfaces list is already sorted level wise
if (!nodep->dead()
&& (VN_IS(nodep, Module) || VN_IS(nodep, Iface))
if (!nodep->dead() && (VN_IS(nodep, Module) || VN_IS(nodep, Iface))
&& m_modulesCovered.insert(nodep->fileline()->filename()).second) {
m_nodeModules.push_front(nodep->fileline());
}
@ -260,18 +291,19 @@ private:
public:
// CONSTRUCTORS
ModuleFilesXmlVisitor(AstNetlist* nodep, std::ostream& os)
: m_os(os), m_modulesCovered(), m_nodeModules() {
: m_os(os)
, m_modulesCovered()
, m_nodeModules() {
// Operate on whole netlist
nodep->accept(*this);
// Xml output
m_os<<"<module_files>\n";
for (std::deque<FileLine*>::iterator it = m_nodeModules.begin();
it != m_nodeModules.end(); ++it) {
m_os<<"<file id=\""<<(*it)->filenameLetters()
<<"\" filename=\""<<(*it)->filename()
<<"\" language=\""<<(*it)->language().ascii()<<"\"/>\n";
m_os << "<module_files>\n";
for (std::deque<FileLine*>::iterator it = m_nodeModules.begin(); it != m_nodeModules.end();
++it) {
m_os << "<file id=\"" << (*it)->filenameLetters() << "\" filename=\""
<< (*it)->filename() << "\" language=\"" << (*it)->language().ascii() << "\"/>\n";
}
m_os<<"</module_files>\n";
m_os << "</module_files>\n";
}
virtual ~ModuleFilesXmlVisitor() {}
};
@ -292,42 +324,38 @@ private:
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
if (nodep->level() >= 0
&& nodep->level() <=2 ) { // ==2 because we don't add wrapper when in XML mode
m_os<<"<cells>\n";
m_os<<"<cell "<<nodep->fileline()->xml()
<<" "<<nodep->fileline()->xmlDetailedLocation()
<<" name=\""<<nodep->name()<<"\""
<<" submodname=\""<<nodep->name()<<"\""
<<" hier=\""<<nodep->name()<<"\"";
&& nodep->level() <= 2) { // ==2 because we don't add wrapper when in XML mode
m_os << "<cells>\n";
m_os << "<cell " << nodep->fileline()->xml() << " "
<< nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\""
<< " submodname=\"" << nodep->name() << "\""
<< " hier=\"" << nodep->name() << "\"";
m_hier = nodep->name() + ".";
m_hasChildren = false;
iterateChildren(nodep);
if (m_hasChildren) {
m_os<<"</cell>\n";
m_os << "</cell>\n";
} else {
m_os<<"/>\n";
m_os << "/>\n";
}
m_os<<"</cells>\n";
m_os << "</cells>\n";
}
}
virtual void visit(AstCell* nodep) VL_OVERRIDE {
if (nodep->modp()->dead()) {
return;
}
if (!m_hasChildren) m_os<<">\n";
m_os<<"<cell "<<nodep->fileline()->xml()
<<" "<<nodep->fileline()->xmlDetailedLocation()
<<" name=\""<<nodep->name()<<"\""
<<" submodname=\""<<nodep->modName()<<"\""
<<" hier=\""<<m_hier+nodep->name()<<"\"";
if (nodep->modp()->dead()) { return; }
if (!m_hasChildren) m_os << ">\n";
m_os << "<cell " << nodep->fileline()->xml() << " "
<< nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\""
<< " submodname=\"" << nodep->modName() << "\""
<< " hier=\"" << m_hier + nodep->name() << "\"";
std::string hier = m_hier;
m_hier += nodep->name() + ".";
m_hasChildren = false;
iterateChildren(nodep->modp());
if (m_hasChildren) {
m_os<<"</cell>\n";
m_os << "</cell>\n";
} else {
m_os<<"/>\n";
m_os << "/>\n";
}
m_hier = hier;
m_hasChildren = true;
@ -338,7 +366,9 @@ private:
public:
// CONSTRUCTORS
HierCellsXmlVisitor(AstNetlist* nodep, std::ostream& os)
: m_os(os), m_hier(""), m_hasChildren(false) {
: m_os(os)
, m_hier("")
, m_hasChildren(false) {
// Operate on whole netlist
nodep->accept(*this);
}
@ -349,14 +379,15 @@ public:
// EmitXml class functions
void V3EmitXml::emitxml() {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
// All-in-one file
string filename = (v3Global.opt.xmlOutput().empty()
? v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+".xml"
: v3Global.opt.xmlOutput());
? v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".xml"
: v3Global.opt.xmlOutput());
V3OutXmlFile of(filename);
of.putsHeader();
of.puts("<!-- DESCR" "IPTION: Verilator output: XML representation of netlist -->\n");
of.puts("<!-- DESCR"
"IPTION: Verilator output: XML representation of netlist -->\n");
of.puts("<verilator_xml>\n");
{
std::stringstream sstr;
@ -365,10 +396,10 @@ void V3EmitXml::emitxml() {
}
{
std::stringstream sstr;
ModuleFilesXmlVisitor moduleFilesVisitor (v3Global.rootp(), sstr);
HierCellsXmlVisitor cellsVisitor (v3Global.rootp(), sstr);
ModuleFilesXmlVisitor moduleFilesVisitor(v3Global.rootp(), sstr);
HierCellsXmlVisitor cellsVisitor(v3Global.rootp(), sstr);
of.puts(sstr.str());
}
EmitXmlFileVisitor visitor (v3Global.rootp(), &of);
EmitXmlFileVisitor visitor(v3Global.rootp(), &of);
of.puts("</verilator_xml>\n");
}

View File

@ -14,12 +14,14 @@
//
//*************************************************************************
// clang-format off
#include "V3Error.h"
#ifndef _V3ERROR_NO_GLOBAL_
# include "V3Ast.h"
# include "V3Global.h"
# include "V3Stats.h"
#endif
// clang-format on
#include <cstdarg>
@ -43,7 +45,7 @@ V3Error::MessagesSet V3Error::s_messages;
V3Error::ErrorExitCb V3Error::s_errorExitCb = NULL;
struct v3errorIniter {
v3errorIniter() { V3Error::init(); }
v3errorIniter() { V3Error::init(); }
};
v3errorIniter v3errorInit;
@ -52,10 +54,11 @@ v3errorIniter v3errorInit;
V3ErrorCode::V3ErrorCode(const char* msgp) {
// Return error encoding for given string, or ERROR, which is a bad code
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = V3ErrorCode(codei);
if (0 == VL_STRCASECMP(msgp, code.ascii())) {
m_e = code; return;
m_e = code;
return;
}
}
m_e = V3ErrorCode::EC_ERROR;
@ -65,7 +68,7 @@ V3ErrorCode::V3ErrorCode(const char* msgp) {
// V3Error class functions
void V3Error::init() {
for (int i=0; i<V3ErrorCode::_ENUM_MAX; i++) {
for (int i = 0; i < V3ErrorCode::_ENUM_MAX; i++) {
s_describedEachWarn[i] = false;
s_pretendError[i] = V3ErrorCode(i).pretendError();
}
@ -77,18 +80,19 @@ void V3Error::init() {
string V3Error::lineStr(const char* filename, int lineno) {
std::ostringstream out;
const char* fnslashp = strrchr(filename, '/');
if (fnslashp) filename = fnslashp+1;
out<<filename<<":"<<std::dec<<lineno<<":";
if (fnslashp) filename = fnslashp + 1;
out << filename << ":" << std::dec << lineno << ":";
const char* const spaces = " ";
size_t numsp = out.str().length(); if (numsp>20) numsp = 20;
out<<(spaces + numsp);
size_t numsp = out.str().length();
if (numsp > 20) numsp = 20;
out << (spaces + numsp);
return out.str();
}
void V3Error::incErrors() {
s_errCount++;
if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse
v3fatalExit("Exiting due to too many errors encountered; --error-limit="
v3fatalExit("Exiting due to too many errors encountered; --error-limit=" //
<< errorCount() << endl);
}
}
@ -96,8 +100,8 @@ void V3Error::incErrors() {
void V3Error::abortIfWarnings() {
bool exwarn = warnFatal() && warnCount();
if (errorCount() && exwarn) {
v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s), "
<< warnCount() << " warning(s)\n");
v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s), " //
<< warnCount() << " warning(s)\n");
} else if (errorCount()) {
v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s)\n");
} else if (exwarn) {
@ -106,30 +110,49 @@ void V3Error::abortIfWarnings() {
}
bool V3Error::isError(V3ErrorCode code, bool supp) {
if (supp) return false;
else if (code == V3ErrorCode::USERINFO) return false;
else if (code == V3ErrorCode::EC_INFO) return false;
else if (code == V3ErrorCode::EC_FATAL) return true;
else if (code == V3ErrorCode::EC_FATALEXIT) return true;
else if (code == V3ErrorCode::EC_FATALSRC) return true;
else if (code == V3ErrorCode::EC_ERROR) return true;
else if (code < V3ErrorCode::EC_FIRST_WARN
|| s_pretendError[code]) return true;
else return false;
if (supp) {
return false;
} else if (code == V3ErrorCode::USERINFO) {
return false;
} else if (code == V3ErrorCode::EC_INFO) {
return false;
} else if (code == V3ErrorCode::EC_FATAL) {
return true;
} else if (code == V3ErrorCode::EC_FATALEXIT) {
return true;
} else if (code == V3ErrorCode::EC_FATALSRC) {
return true;
} else if (code == V3ErrorCode::EC_ERROR) {
return true;
} else if (code < V3ErrorCode::EC_FIRST_WARN || s_pretendError[code]) {
return true;
} else {
return false;
}
}
string V3Error::msgPrefix() {
V3ErrorCode code = s_errorCode;
bool supp = s_errorSuppressed;
if (supp) return "-arning-suppressed: ";
else if (code == V3ErrorCode::USERINFO) return "-Info: ";
else if (code == V3ErrorCode::EC_INFO) return "-Info: ";
else if (code == V3ErrorCode::EC_FATAL) return "%Error: ";
else if (code == V3ErrorCode::EC_FATALEXIT) return "%Error: ";
else if (code == V3ErrorCode::EC_FATALSRC) return "%Error: Internal Error: ";
else if (code == V3ErrorCode::EC_ERROR) return "%Error: ";
else if (isError(code, supp)) return "%Error-"+string(code.ascii())+": ";
else return "%Warning-"+string(code.ascii())+": ";
if (supp) {
return "-arning-suppressed: ";
} else if (code == V3ErrorCode::USERINFO) {
return "-Info: ";
} else if (code == V3ErrorCode::EC_INFO) {
return "-Info: ";
} else if (code == V3ErrorCode::EC_FATAL) {
return "%Error: ";
} else if (code == V3ErrorCode::EC_FATALEXIT) {
return "%Error: ";
} else if (code == V3ErrorCode::EC_FATALSRC) {
return "%Error: Internal Error: ";
} else if (code == V3ErrorCode::EC_ERROR) {
return "%Error: ";
} else if (isError(code, supp)) {
return "%Error-" + string(code.ascii()) + ": ";
} else {
return "%Warning-" + string(code.ascii()) + ": ";
}
}
//======================================================================
@ -137,7 +160,7 @@ string V3Error::msgPrefix() {
void V3Error::vlAbort() {
if (V3Error::debugDefault()) {
std::cerr<<msgPrefix()<<"Aborting since under --debug"<<endl;
std::cerr << msgPrefix() << "Aborting since under --debug" << endl;
abort();
} else {
exit(1);
@ -148,31 +171,30 @@ void V3Error::vlAbort() {
// Global Functions
void V3Error::suppressThisWarning() {
if (s_errorCode>=V3ErrorCode::EC_MIN) {
if (s_errorCode >= V3ErrorCode::EC_MIN) {
#ifndef _V3ERROR_NO_GLOBAL_
V3Stats::addStatSum(string("Warnings, Suppressed ")+s_errorCode.ascii(), 1);
V3Stats::addStatSum(string("Warnings, Suppressed ") + s_errorCode.ascii(), 1);
#endif
s_errorSuppressed = true;
}
}
string V3Error::warnMore() {
return string(msgPrefix().size(), ' ');
}
string V3Error::warnMore() { return string(msgPrefix().size(), ' '); }
void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
#if defined(__COVERITY__) || defined(__cppcheck__)
if (s_errorCode==V3ErrorCode::EC_FATAL) __coverity_panic__(x);
if (s_errorCode == V3ErrorCode::EC_FATAL) __coverity_panic__(x);
#endif
// Skip suppressed messages
if (s_errorSuppressed
// On debug, show only non default-off warning to prevent pages of warnings
&& (!debug() || s_errorCode.defaultsOff())) return;
string msg = msgPrefix()+sstr.str();
&& (!debug() || s_errorCode.defaultsOff()))
return;
string msg = msgPrefix() + sstr.str();
if (s_errorSuppressed) { // If suppressed print only first line to reduce verbosity
string::size_type pos;
if ((pos = msg.find('\n')) != string::npos) {
msg.erase(pos, msg.length()-pos);
msg.erase(pos, msg.length() - pos);
msg += "...";
}
}
@ -180,15 +202,13 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
{
msg += '\n'; // Trailing newlines generally not put on messages so add
string::size_type pos;
while ((pos = msg.find("\n\n")) != string::npos) {
msg.erase(pos+1, 1);
}
while ((pos = msg.find("\n\n")) != string::npos) msg.erase(pos + 1, 1);
}
// Suppress duplicate messages
if (s_messages.find(msg) != s_messages.end()) return;
s_messages.insert(msg);
if (!locationStr.empty()) {
string locationMsg = warnMore()+locationStr+"\n";
string locationMsg = warnMore() + locationStr + "\n";
size_t pos = msg.find("\n");
msg.insert(pos + 1, locationMsg);
}
@ -199,44 +219,49 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
#else
true
#endif
) {
) {
std::cerr << msg;
}
if (!s_errorSuppressed && !(s_errorCode==V3ErrorCode::EC_INFO
|| s_errorCode==V3ErrorCode::USERINFO)) {
if (!s_describedEachWarn[s_errorCode]
&& !s_pretendError[s_errorCode]) {
if (!s_errorSuppressed
&& !(s_errorCode == V3ErrorCode::EC_INFO || s_errorCode == V3ErrorCode::USERINFO)) {
if (!s_describedEachWarn[s_errorCode] && !s_pretendError[s_errorCode]) {
s_describedEachWarn[s_errorCode] = true;
if (s_errorCode>=V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) {
std::cerr<<warnMore()<<"... Use \"/* verilator lint_off "<<s_errorCode.ascii()
<<" */\" and lint_on around source to disable this message."<<endl;
if (s_errorCode >= V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) {
std::cerr << warnMore() << "... Use \"/* verilator lint_off "
<< s_errorCode.ascii()
<< " */\" and lint_on around source to disable this message." << endl;
s_describedWarnings = true;
}
if (s_errorCode.dangerous()) {
std::cerr<<warnMore()<<"*** See the manual before disabling this,"<<endl;
std::cerr<<warnMore()<<"else you may end up with different sim results."<<endl;
std::cerr << warnMore() << "*** See the manual before disabling this," << endl;
std::cerr << warnMore() << "else you may end up with different sim results."
<< endl;
}
}
// If first warning is not the user's fault (internal/unsupported) then give the website
// Not later warnings, as a internal may be caused by an earlier problem
if (s_tellManual == 0) {
if (s_errorCode.mentionManual()
|| sstr.str().find("Unsupported") != string::npos) {
if (s_errorCode.mentionManual() || sstr.str().find("Unsupported") != string::npos) {
s_tellManual = 1;
} else {
s_tellManual = 2;
}
}
if (isError(s_errorCode, s_errorSuppressed)) incErrors();
else incWarnings();
if (s_errorCode == V3ErrorCode::EC_FATAL
|| s_errorCode == V3ErrorCode::EC_FATALEXIT
if (isError(s_errorCode, s_errorSuppressed)) {
incErrors();
} else {
incWarnings();
}
if (s_errorCode == V3ErrorCode::EC_FATAL || s_errorCode == V3ErrorCode::EC_FATALEXIT
|| s_errorCode == V3ErrorCode::EC_FATALSRC) {
static bool inFatal = false;
if (!inFatal) {
inFatal = true;
if (s_tellManual==1) {
std::cerr<<warnMore()<<"... See the manual and https://verilator.org for more assistance."<<endl;
if (s_tellManual == 1) {
std::cerr
<< warnMore()
<< "... See the manual and https://verilator.org for more assistance."
<< endl;
s_tellManual = 2;
}
#ifndef _V3ERROR_NO_GLOBAL_
@ -250,8 +275,7 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
}
vlAbort();
}
else if (isError(s_errorCode, s_errorSuppressed)) {
} else if (isError(s_errorCode, s_errorSuppressed)) {
// We don't dump tree on any error because a Visitor may be in middle of
// a tree cleanup and cause a false broken problem.
if (s_errorExitCb) s_errorExitCb();

View File

@ -34,6 +34,7 @@
class V3ErrorCode {
public:
// clang-format off
enum en {
EC_MIN=0, // Keep first
//
@ -121,14 +122,19 @@ public:
_ENUM_MAX
// ***Add new elements below also***
};
// clang-format on
enum en m_e;
inline V3ErrorCode() : m_e(EC_MIN) {}
inline V3ErrorCode()
: m_e(EC_MIN) {}
// cppcheck-suppress noExplicitConstructor
inline V3ErrorCode(en _e) : m_e(_e) {}
inline V3ErrorCode(en _e)
: m_e(_e) {}
explicit V3ErrorCode(const char* msgp); // Matching code or ERROR
explicit inline V3ErrorCode(int _e) : m_e(static_cast<en>(_e)) {}
explicit inline V3ErrorCode(int _e)
: m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; }
const char* ascii() const {
// clang-format off
const char* names[] = {
// Leading spaces indicate it can't be disabled.
" MIN", " INFO", " FATAL", " FATALEXIT", " FATALSRC", " ERROR",
@ -159,50 +165,37 @@ public:
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
" MAX"
};
// clang-format on
return names[m_e];
}
// Warnings that default to off
bool defaultsOff() const { return ( m_e==IMPERFECTSCH || styleError()); }
bool defaultsOff() const { return (m_e == IMPERFECTSCH || styleError()); }
// Warnings that warn about nasty side effects
bool dangerous() const { return ( m_e==COMBDLY ); }
bool dangerous() const { return (m_e == COMBDLY); }
// Warnings we'll present to the user as errors
// Later -Werror- options may make more of these.
bool pretendError() const { return ( m_e==ASSIGNIN || m_e==BLKANDNBLK
|| m_e==BLKLOOPINIT
|| m_e==CONTASSREG
|| m_e==IMPURE
|| m_e==PROCASSWIRE); }
bool pretendError() const {
return (m_e == ASSIGNIN || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG
|| m_e == IMPURE || m_e == PROCASSWIRE);
}
// Warnings to mention manual
bool mentionManual() const { return ( m_e==EC_FATALSRC || m_e==SYMRSVDWORD
|| pretendError() ); }
bool mentionManual() const {
return (m_e == EC_FATALSRC || m_e == SYMRSVDWORD || pretendError());
}
// Warnings that are lint only
bool lintError() const { return ( m_e==ALWCOMBORDER
|| m_e==BSSPACE
|| m_e==CASEINCOMPLETE || m_e==CASEOVERLAP
|| m_e==CASEWITHX || m_e==CASEX
|| m_e==CMPCONST
|| m_e==COLONPLUS
|| m_e==ENDLABEL
|| m_e==IMPLICIT
|| m_e==LITENDIAN
|| m_e==PINMISSING
|| m_e==REALCVT
|| m_e==UNSIGNED
|| m_e==WIDTH); }
bool lintError() const {
return (m_e == ALWCOMBORDER || m_e == BSSPACE || m_e == CASEINCOMPLETE
|| m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CMPCONST
|| m_e == COLONPLUS || m_e == ENDLABEL || m_e == IMPLICIT || m_e == LITENDIAN
|| m_e == PINMISSING || m_e == REALCVT || m_e == UNSIGNED || m_e == WIDTH);
}
// Warnings that are style only
bool styleError() const { return ( m_e==ASSIGNDLY // More than style, but for backward compatibility
|| m_e==BLKSEQ
|| m_e==DEFPARAM
|| m_e==DECLFILENAME
|| m_e==IMPORTSTAR
|| m_e==INCABSPATH
|| m_e==PINCONNECTEMPTY
|| m_e==PINNOCONNECT
|| m_e==SYNCASYNCNET
|| m_e==UNDRIVEN
|| m_e==UNUSED
|| m_e==VARHIDDEN ); }
bool styleError() const {
return (m_e == ASSIGNDLY // More than style, but for backward compatibility
|| m_e == BLKSEQ || m_e == DEFPARAM || m_e == DECLFILENAME || m_e == IMPORTSTAR
|| m_e == INCABSPATH || m_e == PINCONNECTEMPTY || m_e == PINNOCONNECT
|| m_e == SYNCASYNCNET || m_e == UNDRIVEN || m_e == UNUSED || m_e == VARHIDDEN);
}
};
inline bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) {
return lhs.m_e == rhs.m_e;
@ -221,28 +214,32 @@ class V3Error {
typedef std::set<string> MessagesSet;
typedef void (*ErrorExitCb)(void);
private:
static bool s_describedWarnings; // Told user how to disable warns
static bool s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; // Told user specifics about this warning
static bool s_pretendError[V3ErrorCode::_ENUM_MAX]; // Pretend this warning is an error
static int s_debugDefault; // Option: --debugi Default debugging level
static int s_errorLimit; // Option: --error-limit Number of errors before exit
static bool s_warnFatal; // Option: --warnFatal Warnings are fatal
static int s_errCount; // Error count
static int s_warnCount; // Warning count
static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable
static std::ostringstream s_errorStr; // Error string being formed
static V3ErrorCode s_errorCode; // Error string being formed will abort
static bool s_errorContexted; // Error being formed got context
static bool s_errorSuppressed; // Error being formed should be suppressed
static MessagesSet s_messages; // What errors we've outputted
static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping
private:
static bool s_describedWarnings; // Told user how to disable warns
static bool
s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; // Told user specifics about this warning
static bool s_pretendError[V3ErrorCode::_ENUM_MAX]; // Pretend this warning is an error
static int s_debugDefault; // Option: --debugi Default debugging level
static int s_errorLimit; // Option: --error-limit Number of errors before exit
static bool s_warnFatal; // Option: --warnFatal Warnings are fatal
static int s_errCount; // Error count
static int s_warnCount; // Warning count
static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable
static std::ostringstream s_errorStr; // Error string being formed
static V3ErrorCode s_errorCode; // Error string being formed will abort
static bool s_errorContexted; // Error being formed got context
static bool s_errorSuppressed; // Error being formed should be suppressed
static MessagesSet s_messages; // What errors we've outputted
static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping
enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors
enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors
V3Error() { std::cerr<<("Static class"); abort(); }
V3Error() {
std::cerr << ("Static class");
abort();
}
public:
public:
// CONSTRUCTORS
// ACCESSORS
static void debugDefault(int level) { s_debugDefault = level; }
@ -254,14 +251,16 @@ class V3Error {
static string msgPrefix(); // returns %Error/%Warn
static int errorCount() { return s_errCount; }
static int warnCount() { return s_warnCount; }
static int errorOrWarnCount() { return errorCount()+warnCount(); }
static int errorOrWarnCount() { return errorCount() + warnCount(); }
static bool errorContexted() { return s_errorContexted; }
static void errorContexted(bool flag) { s_errorContexted = flag; }
// METHODS
static void incErrors();
static void incWarnings() { s_warnCount++; }
static void init();
static void abortIfErrors() { if (errorCount()) abortIfWarnings(); }
static void abortIfErrors() {
if (errorCount()) abortIfWarnings();
}
static void abortIfWarnings();
static void suppressThisWarning(); // Suppress next %Warn if user has it off
static void pretendError(V3ErrorCode code, bool flag) { s_pretendError[code] = flag; }
@ -273,77 +272,109 @@ class V3Error {
// When printing an error/warning, print prefix for multiline message
static string warnMore();
/// When building an error, don't show context info
static string warnContextNone() { V3Error::errorContexted(true); return ""; }
static string warnContextNone() {
V3Error::errorContexted(true);
return "";
}
// Internals for v3error()/v3fatal() macros only
// Error end takes the string stream to output, be careful to seek() as needed
static void v3errorPrep(V3ErrorCode code) {
s_errorStr.str(""); s_errorCode = code;
s_errorContexted = false; s_errorSuppressed = false; }
s_errorStr.str("");
s_errorCode = code;
s_errorContexted = false;
s_errorSuppressed = false;
}
static std::ostringstream& v3errorStr() { return s_errorStr; }
static void vlAbort();
static void v3errorEnd(std::ostringstream& sstr, const string& locationStr = ""); // static, but often overridden in classes.
// static, but often overridden in classes.
static void v3errorEnd(std::ostringstream& sstr, const string& locationStr = "");
};
// Global versions, so that if the class doesn't define a operator, we get the functions anyways.
inline int debug() { return V3Error::debugDefault(); }
inline void v3errorEnd(std::ostringstream& sstr) { V3Error::v3errorEnd(sstr); }
inline void v3errorEndFatal(std::ostringstream& sstr) {
V3Error::v3errorEnd(sstr); assert(0); VL_UNREACHABLE }
V3Error::v3errorEnd(sstr);
assert(0);
VL_UNREACHABLE
}
// Theses allow errors using << operators: v3error("foo"<<"bar");
// Careful, you can't put () around msg, as you would in most macro definitions
// Note the commas are the comma operator, not separating arguments. These are needed to ensure
// evaluation order as otherwise we couldn't ensure v3errorPrep is called first.
#define v3warnCode(code,msg) \
v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
#define v3warnCodeFatal(code,msg) \
v3errorEndFatal((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), \
V3Error::v3errorStr()));
#define v3warn(code,msg) v3warnCode(V3ErrorCode::code, msg)
#define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg)
#define v3warnCode(code, msg) \
v3errorEnd( \
(V3Error::v3errorPrep(code), (V3Error::v3errorStr() << msg), V3Error::v3errorStr()));
#define v3warnCodeFatal(code, msg) \
v3errorEndFatal( \
(V3Error::v3errorPrep(code), (V3Error::v3errorStr() << msg), V3Error::v3errorStr()));
#define v3warn(code, msg) v3warnCode(V3ErrorCode::code, msg)
#define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg)
#define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg)
#define v3fatal(msg) v3warnCodeFatal(V3ErrorCode::EC_FATAL, msg)
// Use this instead of fatal() if message gets suppressed with --quiet-exit
#define v3fatalExit(msg) v3warnCodeFatal(V3ErrorCode::EC_FATALEXIT, msg)
// Use this instead of fatal() to mention the source code line.
#define v3fatalSrc(msg) v3warnCodeFatal(V3ErrorCode::EC_FATALSRC, __FILE__<<":"<<std::dec<<__LINE__<<": "<<msg)
#define v3fatalSrc(msg) \
v3warnCodeFatal(V3ErrorCode::EC_FATALSRC, \
__FILE__ << ":" << std::dec << __LINE__ << ": " << msg)
// Use this when normal v3fatal is called in static method that overrides fileline.
#define v3fatalStatic(msg) \
::v3errorEndFatal((V3Error::v3errorPrep(V3ErrorCode::EC_FATAL), \
(V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
(V3Error::v3errorStr() << msg), V3Error::v3errorStr()));
#define UINFO(level, stmsg) \
{ if (VL_UNCOVERABLE(debug() >= (level))) { \
cout << "- " << V3Error::lineStr(__FILE__, __LINE__) << stmsg; } }
{ \
if (VL_UNCOVERABLE(debug() >= (level))) { \
cout << "- " << V3Error::lineStr(__FILE__, __LINE__) << stmsg; \
} \
}
#define UINFONL(level, stmsg) \
{ if (VL_UNCOVERABLE(debug() >= (level))) { cout << stmsg; } }
{ \
if (VL_UNCOVERABLE(debug() >= (level))) { cout << stmsg; } \
}
#ifdef VL_DEBUG
# define UDEBUGONLY(stmts) \
#define UDEBUGONLY(stmts) \
{ stmts }
#else
# define UDEBUGONLY(stmts) \
{ if (false) { stmts } }
#define UDEBUGONLY(stmts) \
{ \
if (false) { stmts } \
}
#endif
// Assertion without object, generally UOBJASSERT preferred
#define UASSERT(condition,stmsg) \
do { if (VL_UNCOVERABLE(!(condition))) { v3fatalSrc(stmsg); }} while (false)
#define UASSERT(condition, stmsg) \
do { \
if (VL_UNCOVERABLE(!(condition))) { v3fatalSrc(stmsg); } \
} while (false)
// Assertion with object
#define UASSERT_OBJ(condition,obj,stmsg) \
do { if (VL_UNCOVERABLE(!(condition))) { (obj)->v3fatalSrc(stmsg); }} while (false)
#define UASSERT_OBJ(condition, obj, stmsg) \
do { \
if (VL_UNCOVERABLE(!(condition))) { (obj)->v3fatalSrc(stmsg); } \
} while (false)
// For use in V3Ast static functions only
#define UASSERT_STATIC(condition,stmsg) \
do { if (VL_UNCOVERABLE(!(condition))) { \
std::cerr<<"Internal Error: "<<__FILE__<<":"<<std::dec<<__LINE__ \
<<":"<<(stmsg)<<std::endl; abort(); } } while (false)
#define UASSERT_STATIC(condition, stmsg) \
do { \
if (VL_UNCOVERABLE(!(condition))) { \
std::cerr << "Internal Error: " << __FILE__ << ":" << std::dec << __LINE__ << ":" \
<< (stmsg) << std::endl; \
abort(); \
} \
} while (false)
// Check self test values for expected value. Safe from side-effects.
// Type argument can be removed when go to C++11 (use auto).
#define UASSERT_SELFTEST(Type,got,exp) \
do { Type g = (got); Type e = (exp); \
UASSERT(g==e, "Self-test failed '" #got "==" #exp "'"" got=" \
<<g<<" expected="<<e); } while(false)
#define UASSERT_SELFTEST(Type, got, exp) \
do { \
Type g = (got); \
Type e = (exp); \
UASSERT(g == e, "Self-test failed '" #got "==" #exp "'" \
" got=" \
<< g << " expected=" << e); \
} while (false)
#define V3ERROR_NA \
do { \
@ -361,7 +392,7 @@ inline void v3errorEndFatal(std::ostringstream& sstr) {
/// Verilator so that --debugi-<srcfile> will work to control UINFOs in
/// that class:
#define VL_DEBUG_FUNC \
static int debug() { \
static int debug() { \
static int level = -1; \
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__); \
return level; \

View File

@ -42,10 +42,10 @@ class ExpandVisitor : public AstNVisitor {
private:
// NODE STATE
// AstNode::user1() -> bool. Processed
AstUser1InUse m_inuser1;
AstUser1InUse m_inuser1;
// STATE
AstNode* m_stmtp; // Current statement
AstNode* m_stmtp; // Current statement
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -60,7 +60,7 @@ private:
if (nodep->isWide()) {
return V3Number(nodep, VL_EDATASIZE, VL_MASK_E(nodep->widthMin()));
} else {
V3Number mask (nodep, longOrQuadWidth(nodep));
V3Number mask(nodep, longOrQuadWidth(nodep));
mask.setMask(nodep->widthMin());
return mask;
}
@ -80,10 +80,8 @@ private:
}
AstNode* newWordAssign(AstNodeAssign* placep, int word, AstNode* lhsp, AstNode* rhsp) {
AstAssign* newp = new AstAssign(placep->fileline(),
new AstWordSel(placep->fileline(),
lhsp->cloneTree(true),
new AstConst(placep->fileline(),
word)),
new AstWordSel(placep->fileline(), lhsp->cloneTree(true),
new AstConst(placep->fileline(), word)),
rhsp);
return newp;
}
@ -109,24 +107,20 @@ private:
// Get the specified word number from a wide array
// Or, if it's a long/quad, do appropriate conversion to wide
// Concat may pass negative word numbers, that means it wants a zero
if (nodep->isWide() && word>=0 && word<nodep->widthWords()) {
return new AstWordSel(nodep->fileline(),
nodep->cloneTree(true),
if (nodep->isWide() && word >= 0 && word < nodep->widthWords()) {
return new AstWordSel(nodep->fileline(), nodep->cloneTree(true),
new AstConst(nodep->fileline(), word));
} else if (nodep->isQuad() && word == 0) {
AstNode* quadfromp = nodep->cloneTree(true);
quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(),
AstNumeric::UNSIGNED);
return new AstCCast(nodep->fileline(),
quadfromp,
VL_EDATASIZE);
} else if (nodep->isQuad() && word==1) {
return new AstCCast(nodep->fileline(), quadfromp, VL_EDATASIZE);
} else if (nodep->isQuad() && word == 1) {
AstNode* quadfromp = nodep->cloneTree(true);
quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(),
AstNumeric::UNSIGNED);
return new AstCCast(nodep->fileline(),
new AstShiftR(nodep->fileline(),
quadfromp,
new AstShiftR(nodep->fileline(), quadfromp,
new AstConst(nodep->fileline(), VL_EDATASIZE),
VL_EDATASIZE),
VL_EDATASIZE);
@ -146,22 +140,14 @@ private:
int othword = word - shift / VL_EDATASIZE;
AstNode* llowp = newAstWordSelClone(lhsp, othword);
if (int loffset = VL_BITBIT_E(shift)) {
AstNode* lhip = newAstWordSelClone(lhsp, othword-1);
AstNode* lhip = newAstWordSelClone(lhsp, othword - 1);
int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword
newp = new AstOr
(fl,
new AstAnd(fl,
new AstConst(fl, AstConst::SizedEData(), VL_MASK_E(loffset)),
new AstShiftR(fl,
lhip,
new AstConst(fl, nbitsonright),
VL_EDATASIZE)),
new AstAnd(fl,
new AstConst(fl, AstConst::SizedEData(), ~VL_MASK_E(loffset)),
new AstShiftL(fl,
llowp,
new AstConst(fl, loffset),
VL_EDATASIZE)));
newp = new AstOr(
fl,
new AstAnd(fl, new AstConst(fl, AstConst::SizedEData(), VL_MASK_E(loffset)),
new AstShiftR(fl, lhip, new AstConst(fl, nbitsonright), VL_EDATASIZE)),
new AstAnd(fl, new AstConst(fl, AstConst::SizedEData(), ~VL_MASK_E(loffset)),
new AstShiftL(fl, llowp, new AstConst(fl, loffset), VL_EDATASIZE)));
} else {
newp = llowp;
}
@ -174,15 +160,13 @@ private:
return new AstConst(lsbp->fileline(),
wordAdder + VL_BITWORD_E(VN_CAST(lsbp, Const)->toUInt()));
} else {
AstNode* shiftp = new AstShiftR(lsbp->fileline(),
lsbp->cloneTree(true),
new AstConst(lsbp->fileline(), VL_EDATASIZE_LOG2),
VL_EDATASIZE);
AstNode* shiftp
= new AstShiftR(lsbp->fileline(), lsbp->cloneTree(true),
new AstConst(lsbp->fileline(), VL_EDATASIZE_LOG2), VL_EDATASIZE);
if (wordAdder != 0) {
shiftp = new AstAdd(lsbp->fileline(),
// This is indexing a arraysel, so a 32 bit constant is fine
new AstConst(lsbp->fileline(), wordAdder),
shiftp);
new AstConst(lsbp->fileline(), wordAdder), shiftp);
}
return shiftp;
}
@ -193,7 +177,7 @@ private:
// If there's a CONDBOUND safety to keep arrays in bounds,
// we're going to AND it to a value that always fits inside a
// word, so we don't need it.
//if (VN_IS(nodep, CondBound) && VN_IS(VN_CAST(nodep, CondBound)->lhsp(), Lte)) {
// if (VN_IS(nodep, CondBound) && VN_IS(VN_CAST(nodep, CondBound)->lhsp(), Lte)) {
// nodep = VN_CAST(nodep, CondBound)->rhsp();
//}
return nodep;
@ -202,11 +186,9 @@ private:
AstNode* newSelBitBit(AstNode* lsbp) {
// Return equation to get the VL_BITBIT of a constant or non-constant
if (VN_IS(lsbp, Const)) {
return new AstConst(lsbp->fileline(),
VL_BITBIT_E(VN_CAST(lsbp, Const)->toUInt()));
return new AstConst(lsbp->fileline(), VL_BITBIT_E(VN_CAST(lsbp, Const)->toUInt()));
} else {
return new AstAnd(lsbp->fileline(),
new AstConst(lsbp->fileline(), VL_EDATASIZE - 1),
return new AstAnd(lsbp->fileline(), new AstConst(lsbp->fileline(), VL_EDATASIZE - 1),
dropCondBound(lsbp)->cloneTree(true));
}
}
@ -214,89 +196,89 @@ private:
//====================
bool expandWide(AstNodeAssign* nodep, AstConst* rhsp) {
UINFO(8," Wordize ASSIGN(CONST) "<<nodep<<endl);
UINFO(8, " Wordize ASSIGN(CONST) " << nodep << endl);
// -> {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}}
if (rhsp->num().isFourState()) {
rhsp->v3error("Unsupported: 4-state numbers in this context");
}
for (int w=0; w<nodep->widthWords(); w++) {
addWordAssign(nodep, w, new AstConst(nodep->fileline(),
AstConst::SizedEData(),
rhsp->num().edataWord(w)));
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(
nodep, w,
new AstConst(nodep->fileline(), AstConst::SizedEData(), rhsp->num().edataWord(w)));
}
return true;
}
//-------- Uniops
bool expandWide(AstNodeAssign* nodep, AstVarRef* rhsp) {
UINFO(8," Wordize ASSIGN(VARREF) "<<nodep<<endl);
for (int w=0; w<nodep->widthWords(); w++) {
UINFO(8, " Wordize ASSIGN(VARREF) " << nodep << endl);
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(nodep, w, newAstWordSelClone(rhsp, w));
}
return true;
}
bool expandWide(AstNodeAssign* nodep, AstArraySel* rhsp) {
UINFO(8," Wordize ASSIGN(ARRAYSEL) "<<nodep<<endl);
UINFO(8, " Wordize ASSIGN(ARRAYSEL) " << nodep << endl);
UASSERT_OBJ(!VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType), nodep,
"ArraySel with unpacked arrays should have been removed in V3Slice");
for (int w=0; w<nodep->widthWords(); w++) {
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(nodep, w, newAstWordSelClone(rhsp, w));
}
return true;
}
bool expandWide(AstNodeAssign* nodep, AstNot* rhsp) {
UINFO(8," Wordize ASSIGN(NOT) "<<nodep<<endl);
UINFO(8, " Wordize ASSIGN(NOT) " << nodep << endl);
// -> {for each_word{ ASSIGN(WORDSEL(wide,#),NOT(WORDSEL(lhs,#))) }}
for (int w=0; w<nodep->widthWords(); w++) {
addWordAssign(nodep, w, new AstNot(rhsp->fileline(),
newAstWordSelClone(rhsp->lhsp(), w)));
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(nodep, w,
new AstNot(rhsp->fileline(), newAstWordSelClone(rhsp->lhsp(), w)));
}
return true;
}
//-------- Biops
bool expandWide(AstNodeAssign* nodep, AstAnd* rhsp) {
UINFO(8," Wordize ASSIGN(AND) "<<nodep<<endl);
for (int w=0; w<nodep->widthWords(); w++) {
addWordAssign(nodep, w, new AstAnd(nodep->fileline(),
newAstWordSelClone(rhsp->lhsp(), w),
newAstWordSelClone(rhsp->rhsp(), w)));
UINFO(8, " Wordize ASSIGN(AND) " << nodep << endl);
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(nodep, w,
new AstAnd(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w),
newAstWordSelClone(rhsp->rhsp(), w)));
}
return true;
}
bool expandWide(AstNodeAssign* nodep, AstOr* rhsp) {
UINFO(8," Wordize ASSIGN(OR) "<<nodep<<endl);
for (int w=0; w<nodep->widthWords(); w++) {
addWordAssign(nodep, w, new AstOr(nodep->fileline(),
newAstWordSelClone(rhsp->lhsp(), w),
newAstWordSelClone(rhsp->rhsp(), w)));
UINFO(8, " Wordize ASSIGN(OR) " << nodep << endl);
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(nodep, w,
new AstOr(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w),
newAstWordSelClone(rhsp->rhsp(), w)));
}
return true;
}
bool expandWide(AstNodeAssign* nodep, AstXor* rhsp) {
UINFO(8," Wordize ASSIGN(XOR) "<<nodep<<endl);
for (int w=0; w<nodep->widthWords(); w++) {
addWordAssign(nodep, w, new AstXor(nodep->fileline(),
newAstWordSelClone(rhsp->lhsp(), w),
newAstWordSelClone(rhsp->rhsp(), w)));
UINFO(8, " Wordize ASSIGN(XOR) " << nodep << endl);
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(nodep, w,
new AstXor(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w),
newAstWordSelClone(rhsp->rhsp(), w)));
}
return true;
}
bool expandWide(AstNodeAssign* nodep, AstXnor* rhsp) {
UINFO(8," Wordize ASSIGN(XNOR) "<<nodep<<endl);
for (int w=0; w<nodep->widthWords(); w++) {
addWordAssign(nodep, w, new AstXnor(nodep->fileline(),
newAstWordSelClone(rhsp->lhsp(), w),
newAstWordSelClone(rhsp->rhsp(), w)));
UINFO(8, " Wordize ASSIGN(XNOR) " << nodep << endl);
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(nodep, w,
new AstXnor(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w),
newAstWordSelClone(rhsp->rhsp(), w)));
}
return true;
}
//-------- Triops
bool expandWide(AstNodeAssign* nodep, AstNodeCond* rhsp) {
UINFO(8," Wordize ASSIGN(COND) "<<nodep<<endl);
for (int w=0; w<nodep->widthWords(); w++) {
addWordAssign(nodep, w, new AstCond(nodep->fileline(),
rhsp->condp()->cloneTree(true),
newAstWordSelClone(rhsp->expr1p(), w),
newAstWordSelClone(rhsp->expr2p(), w)));
UINFO(8, " Wordize ASSIGN(COND) " << nodep << endl);
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(nodep, w,
new AstCond(nodep->fileline(), rhsp->condp()->cloneTree(true),
newAstWordSelClone(rhsp->expr1p(), w),
newAstWordSelClone(rhsp->expr2p(), w)));
}
return true;
}
@ -316,7 +298,7 @@ private:
} else if (lhsp->isWide()) {
nodep->v3fatalSrc("extending larger thing into smaller?");
} else {
UINFO(8," EXTEND(q<-l) "<<nodep<<endl);
UINFO(8, " EXTEND(q<-l) " << nodep << endl);
newp = new AstCCast(nodep->fileline(), lhsp, nodep);
}
} else { // Long
@ -328,12 +310,12 @@ private:
}
}
bool expandWide(AstNodeAssign* nodep, AstExtend* rhsp) {
UINFO(8," Wordize ASSIGN(EXTEND) "<<nodep<<endl);
UINFO(8, " Wordize ASSIGN(EXTEND) " << nodep << endl);
int w = 0;
for (w=0; w<rhsp->lhsp()->widthWords(); w++) {
for (w = 0; w < rhsp->lhsp()->widthWords(); w++) {
addWordAssign(nodep, w, newAstWordSelClone(rhsp->lhsp(), w));
}
for (; w<nodep->widthWords(); w++) {
for (; w < nodep->widthWords(); w++) {
addWordAssign(nodep, w, new AstConst(rhsp->fileline(), AstConst::SizedEData(), 0));
}
return true;
@ -345,33 +327,29 @@ private:
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
UASSERT_OBJ(nodep->widthMin() == nodep->widthConst(), nodep, "Width mismatch");
if (VN_IS(nodep->backp(), NodeAssign)
&& nodep==VN_CAST(nodep->backp(), NodeAssign)->lhsp()) {
&& nodep == VN_CAST(nodep->backp(), NodeAssign)->lhsp()) {
// Sel is an LHS assignment select
} else if (nodep->isWide()) {
// See under ASSIGN(WIDE)
}
else if (nodep->fromp()->isWide()) {
UINFO(8," SEL(wide) "<<nodep<<endl);
} else if (nodep->fromp()->isWide()) {
UINFO(8, " SEL(wide) " << nodep << endl);
// Selection amounts
// Check for constant shifts & save some constification work later.
// Grab lowest bit(s)
AstNode* lowwordp = new AstWordSel(nodep->fromp()->fileline(),
nodep->fromp()->cloneTree(true),
newSelBitWord(nodep->lsbp(), 0));
AstNode* lowwordp
= new AstWordSel(nodep->fromp()->fileline(), nodep->fromp()->cloneTree(true),
newSelBitWord(nodep->lsbp(), 0));
if (nodep->isQuad() && !lowwordp->isQuad()) {
lowwordp = new AstCCast(nodep->fileline(), lowwordp, nodep);
}
AstNode* lowp = new AstShiftR(nodep->fileline(),
lowwordp,
newSelBitBit(nodep->lsbp()),
AstNode* lowp = new AstShiftR(nodep->fileline(), lowwordp, newSelBitBit(nodep->lsbp()),
nodep->width());
// If > 1 bit, we might be crossing the word boundary
AstNode* midp = NULL;
V3Number zero (nodep, longOrQuadWidth(nodep));
V3Number zero(nodep, longOrQuadWidth(nodep));
if (nodep->widthConst() > 1) {
AstNode* midwordp = // SEL(from,[1+wordnum])
new AstWordSel(nodep->fromp()->fileline(),
nodep->fromp()->cloneTree(true),
new AstWordSel(nodep->fromp()->fileline(), nodep->fromp()->cloneTree(true),
newSelBitWord(nodep->lsbp(), 1));
if (nodep->isQuad() && !midwordp->isQuad()) {
midwordp = new AstCCast(nodep->fileline(), midwordp, nodep);
@ -380,23 +358,19 @@ private:
// get shifted << by 32 bits
// else we need to form the lower word, so we << by 31 or less
// nbitsfromlow <= (lsb==0) ? 64-bitbit(lsb) : 32-bitbit(lsb)
AstNode* midshiftp = new AstSub(nodep->lsbp()->fileline(),
new AstConst(nodep->lsbp()->fileline(),
VL_EDATASIZE),
newSelBitBit(nodep->lsbp()));
AstNode* midshiftp
= new AstSub(nodep->lsbp()->fileline(),
new AstConst(nodep->lsbp()->fileline(), VL_EDATASIZE),
newSelBitBit(nodep->lsbp()));
if (nodep->isQuad()) {
midshiftp =
new AstCond(nodep->fileline(),
new AstEq(nodep->fileline(),
new AstConst(nodep->fileline(), 0),
newSelBitBit(nodep->lsbp())),
new AstConst(nodep->lsbp()->fileline(), VL_EDATASIZE),
midshiftp);
midshiftp = new AstCond(
nodep->fileline(),
new AstEq(nodep->fileline(), new AstConst(nodep->fileline(), 0),
newSelBitBit(nodep->lsbp())),
new AstConst(nodep->lsbp()->fileline(), VL_EDATASIZE), midshiftp);
}
AstNode* midmayp = new AstShiftL(nodep->fileline(),
midwordp,
midshiftp,
nodep->width());
AstNode* midmayp
= new AstShiftL(nodep->fileline(), midwordp, midshiftp, nodep->width());
if (nodep->isQuad()) {
midp = midmayp; // Always grab from two words
} else {
@ -404,35 +378,30 @@ private:
new AstEq(nodep->fileline(),
new AstConst(nodep->fileline(), 0),
newSelBitBit(nodep->lsbp())),
new AstConst(nodep->fileline(), zero),
midmayp);
new AstConst(nodep->fileline(), zero), midmayp);
}
}
// If > 32 bits, we might be crossing the second word boundary
AstNode* hip = NULL;
if (nodep->widthConst() > VL_EDATASIZE) {
AstNode* hiwordp = // SEL(from,[2+wordnum])
new AstWordSel(nodep->fromp()->fileline(),
nodep->fromp()->cloneTree(true),
new AstWordSel(nodep->fromp()->fileline(), nodep->fromp()->cloneTree(true),
newSelBitWord(nodep->lsbp(), 2));
if (nodep->isQuad() && !hiwordp->isQuad()) {
hiwordp = new AstCCast(nodep->fileline(), hiwordp, nodep);
}
AstNode* himayp =
new AstShiftL(nodep->fileline(),
hiwordp,
// nbitsfromlow_and_mid <= 64-bitbit(lsb)
new AstSub(nodep->lsbp()->fileline(),
new AstConst(nodep->lsbp()->fileline(), 64),
newSelBitBit(nodep->lsbp())),
nodep->width());
AstNode* himayp
= new AstShiftL(nodep->fileline(), hiwordp,
// nbitsfromlow_and_mid <= 64-bitbit(lsb)
new AstSub(nodep->lsbp()->fileline(),
new AstConst(nodep->lsbp()->fileline(), 64),
newSelBitBit(nodep->lsbp())),
nodep->width());
// if (frombit==0) then ignore, else use it
hip = new AstCond(nodep->fileline(),
new AstEq(nodep->fileline(),
new AstConst(nodep->fileline(), 0),
new AstEq(nodep->fileline(), new AstConst(nodep->fileline(), 0),
newSelBitBit(nodep->lsbp())),
new AstConst(nodep->fileline(), zero),
himayp);
new AstConst(nodep->fileline(), zero), himayp);
}
AstNode* newp = lowp;
@ -440,18 +409,16 @@ private:
if (hip) newp = new AstOr(nodep->fileline(), hip, newp);
newp->dtypeFrom(nodep);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
else { // Long/Quad from Long/Quad
UINFO(8," SEL->SHIFT "<<nodep<<endl);
} else { // Long/Quad from Long/Quad
UINFO(8, " SEL->SHIFT " << nodep << endl);
AstNode* fromp = nodep->fromp()->unlinkFrBack();
AstNode* lsbp = nodep->lsbp()->unlinkFrBack();
if (nodep->isQuad() && !fromp->isQuad()) {
fromp = new AstCCast(nodep->fileline(), fromp, nodep);
}
AstNode* newp = new AstShiftR(nodep->fileline(),
fromp,
dropCondBound(lsbp),
fromp->width()); // {large}>>32 requires 64-bit shift operation; then cast
AstNode* newp = new AstShiftR(
nodep->fileline(), fromp, dropCondBound(lsbp),
fromp->width()); // {large}>>32 requires 64-bit shift operation; then cast
newp->dtypeFrom(fromp);
if (!nodep->isQuad() && fromp->isQuad()) {
newp = new AstCCast(newp->fileline(), newp, nodep);
@ -465,42 +432,35 @@ private:
UASSERT_OBJ(nodep->widthMin() == rhsp->widthConst(), nodep, "Width mismatch");
if (VN_IS(rhsp->lsbp(), Const) && VL_BITBIT_E(rhsp->lsbConst()) == 0) {
int lsb = rhsp->lsbConst();
UINFO(8," Wordize ASSIGN(SEL,align) "<<nodep<<endl);
for (int w=0; w<nodep->widthWords(); w++) {
UINFO(8, " Wordize ASSIGN(SEL,align) " << nodep << endl);
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(nodep, w, newAstWordSelClone(rhsp->fromp(), w + VL_BITWORD_E(lsb)));
}
return true;
} else {
UINFO(8," Wordize ASSIGN(EXTRACT,misalign) "<<nodep<<endl);
for (int w=0; w<nodep->widthWords(); w++) {
UINFO(8, " Wordize ASSIGN(EXTRACT,misalign) " << nodep << endl);
for (int w = 0; w < nodep->widthWords(); w++) {
// Grab lowest bits
AstNode* lowwordp = new AstWordSel(rhsp->fileline(),
rhsp->fromp()->cloneTree(true),
newSelBitWord(rhsp->lsbp(), w));
AstNode* lowp = new AstShiftR(rhsp->fileline(),
lowwordp,
newSelBitBit(rhsp->lsbp()),
VL_EDATASIZE);
AstNode* lowwordp
= new AstWordSel(rhsp->fileline(), rhsp->fromp()->cloneTree(true),
newSelBitWord(rhsp->lsbp(), w));
AstNode* lowp = new AstShiftR(rhsp->fileline(), lowwordp,
newSelBitBit(rhsp->lsbp()), VL_EDATASIZE);
// Upper bits
V3Number zero (nodep, VL_EDATASIZE, 0);
V3Number zero(nodep, VL_EDATASIZE, 0);
AstNode* midwordp = // SEL(from,[1+wordnum])
new AstWordSel(rhsp->fromp()->fileline(),
rhsp->fromp()->cloneTree(true),
newSelBitWord(rhsp->lsbp(), w+1));
AstNode* midshiftp = new AstSub(rhsp->lsbp()->fileline(),
new AstConst(rhsp->lsbp()->fileline(),
VL_EDATASIZE),
newSelBitBit(rhsp->lsbp()));
AstNode* midmayp = new AstShiftL(rhsp->fileline(),
midwordp,
midshiftp,
VL_EDATASIZE);
AstNode* midp = new AstCond(rhsp->fileline(),
new AstEq(rhsp->fileline(),
new AstConst(rhsp->fileline(), 0),
newSelBitBit(rhsp->lsbp())),
new AstConst(rhsp->fileline(), zero),
midmayp);
new AstWordSel(rhsp->fromp()->fileline(), rhsp->fromp()->cloneTree(true),
newSelBitWord(rhsp->lsbp(), w + 1));
AstNode* midshiftp = new AstSub(
rhsp->lsbp()->fileline(), new AstConst(rhsp->lsbp()->fileline(), VL_EDATASIZE),
newSelBitBit(rhsp->lsbp()));
AstNode* midmayp
= new AstShiftL(rhsp->fileline(), midwordp, midshiftp, VL_EDATASIZE);
AstNode* midp
= new AstCond(rhsp->fileline(),
new AstEq(rhsp->fileline(), new AstConst(rhsp->fileline(), 0),
newSelBitBit(rhsp->lsbp())),
new AstConst(rhsp->fileline(), zero), midmayp);
AstNode* newp = new AstOr(nodep->fileline(), midp, lowp);
addWordAssign(nodep, w, newp);
}
@ -524,99 +484,84 @@ private:
AstNode* destp = lhsp->fromp()->unlinkFrBack();
int lsb = lhsp->lsbConst();
int msb = lhsp->msbConst();
V3Number maskset (nodep, destp->widthMin());
for (int bit=lsb; bit<(msb+1); bit++) maskset.setBit(bit, 1);
V3Number maskold (nodep, destp->widthMin()); maskold.opNot(maskset);
V3Number maskset(nodep, destp->widthMin());
for (int bit = lsb; bit < (msb + 1); bit++) maskset.setBit(bit, 1);
V3Number maskold(nodep, destp->widthMin());
maskold.opNot(maskset);
if (destwide) {
UINFO(8," ASSIGNSEL(const,wide) "<<nodep<<endl);
for (int w=0; w<destp->widthWords(); w++) {
UINFO(8, " ASSIGNSEL(const,wide) " << nodep << endl);
for (int w = 0; w < destp->widthWords(); w++) {
if (w >= VL_BITWORD_E(lsb) && w <= VL_BITWORD_E(msb)) {
// else we would just be setting it to the same exact value
AstNode* oldvalp = newAstWordSelClone(destp, w);
fixCloneLvalue(oldvalp);
if (!ones) {
oldvalp = new AstAnd(lhsp->fileline(),
new AstConst(lhsp->fileline(),
AstConst::SizedEData(),
maskold.edataWord(w)),
oldvalp);
oldvalp
= new AstAnd(lhsp->fileline(),
new AstConst(lhsp->fileline(), AstConst::SizedEData(),
maskold.edataWord(w)),
oldvalp);
}
addWordAssign(nodep, w,
destp,
new AstOr(lhsp->fileline(),
oldvalp,
newWordGrabShift(lhsp->fileline(), w,
rhsp, lsb)));
addWordAssign(nodep, w, destp,
new AstOr(lhsp->fileline(), oldvalp,
newWordGrabShift(lhsp->fileline(), w, rhsp, lsb)));
}
}
VL_DO_DANGLING(rhsp->deleteTree(), rhsp);
VL_DO_DANGLING(destp->deleteTree(), destp);
} else {
UINFO(8," ASSIGNSEL(const,narrow) "<<nodep<<endl);
UINFO(8, " ASSIGNSEL(const,narrow) " << nodep << endl);
if (destp->isQuad() && !rhsp->isQuad()) {
rhsp = new AstCCast(nodep->fileline(), rhsp, nodep);
}
AstNode* oldvalp = destp->cloneTree(true);
fixCloneLvalue(oldvalp);
if (!ones) {
oldvalp = new AstAnd(lhsp->fileline(),
new AstConst(lhsp->fileline(), maskold),
oldvalp = new AstAnd(lhsp->fileline(), new AstConst(lhsp->fileline(), maskold),
oldvalp);
}
AstNode* newp
= new AstOr(lhsp->fileline(),
oldvalp,
new AstShiftL(lhsp->fileline(),
rhsp,
new AstConst(lhsp->fileline(), lsb),
destp->width()));
AstNode* newp = new AstOr(lhsp->fileline(), oldvalp,
new AstShiftL(lhsp->fileline(), rhsp,
new AstConst(lhsp->fileline(), lsb),
destp->width()));
newp = new AstAssign(nodep->fileline(), destp, newp);
insertBefore(nodep, newp);
}
return true;
}
else { // non-const RHS
if (destwide && lhsp->widthConst()==1) {
UINFO(8," ASSIGNSEL(varlsb,wide,1bit) "<<nodep<<endl);
} else { // non-const RHS
if (destwide && lhsp->widthConst() == 1) {
UINFO(8, " ASSIGNSEL(varlsb,wide,1bit) " << nodep << endl);
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* destp = lhsp->fromp()->unlinkFrBack();
AstNode* oldvalp = new AstWordSel(lhsp->fileline(),
destp->cloneTree(true),
AstNode* oldvalp = new AstWordSel(lhsp->fileline(), destp->cloneTree(true),
newSelBitWord(lhsp->lsbp(), 0));
fixCloneLvalue(oldvalp);
if (!ones) {
oldvalp = new AstAnd
(lhsp->fileline(),
new AstNot(lhsp->fileline(),
new AstShiftL
(lhsp->fileline(),
new AstConst(nodep->fileline(), 1),
// newSelBitBit may exceed the MSB of this variable.
// That's ok as we'd just AND with a larger value,
// but oldval would clip the upper bits to sanity
newSelBitBit(lhsp->lsbp()),
VL_EDATASIZE)),
oldvalp);
oldvalp = new AstAnd(
lhsp->fileline(),
new AstNot(
lhsp->fileline(),
new AstShiftL(lhsp->fileline(), new AstConst(nodep->fileline(), 1),
// newSelBitBit may exceed the MSB of this variable.
// That's ok as we'd just AND with a larger value,
// but oldval would clip the upper bits to sanity
newSelBitBit(lhsp->lsbp()), VL_EDATASIZE)),
oldvalp);
}
// Restrict the shift amount to 0-31, see bug804.
AstNode* shiftp = new AstAnd(nodep->fileline(), lhsp->lsbp()->cloneTree(true),
new AstConst(nodep->fileline(), VL_EDATASIZE - 1));
AstNode* newp = new AstOr(lhsp->fileline(),
oldvalp,
new AstShiftL(lhsp->fileline(),
rhsp,
shiftp,
VL_EDATASIZE));
newp = new AstAssign(nodep->fileline(),
new AstWordSel(nodep->fileline(),
destp,
newSelBitWord(lhsp->lsbp(), 0)),
newp);
AstNode* newp
= new AstOr(lhsp->fileline(), oldvalp,
new AstShiftL(lhsp->fileline(), rhsp, shiftp, VL_EDATASIZE));
newp = new AstAssign(
nodep->fileline(),
new AstWordSel(nodep->fileline(), destp, newSelBitWord(lhsp->lsbp(), 0)),
newp);
insertBefore(nodep, newp);
return true;
}
else if (destwide) {
UINFO(8," ASSIGNSEL(varlsb,wide) -- NoOp -- "<<nodep<<endl);
} else if (destwide) {
UINFO(8, " ASSIGNSEL(varlsb,wide) -- NoOp -- " << nodep << endl);
// For wide destp, we can either form a equation for every destination word,
// with the appropriate long equation of if it's being written or not.
// Or, we can use a LHS variable arraysel with
@ -628,38 +573,34 @@ private:
// Reconsider if we get subexpression elimination.
return false;
} else {
UINFO(8," ASSIGNSEL(varlsb,narrow) "<<nodep<<endl);
UINFO(8, " ASSIGNSEL(varlsb,narrow) " << nodep << endl);
// nodep->dumpTree(cout, "- old: ");
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* destp = lhsp->fromp()->unlinkFrBack();
AstNode* oldvalp = destp->cloneTree(true);
fixCloneLvalue(oldvalp);
V3Number maskwidth (nodep, destp->widthMin());
for (int bit=0; bit < lhsp->widthConst(); bit++) maskwidth.setBit(bit, 1);
V3Number maskwidth(nodep, destp->widthMin());
for (int bit = 0; bit < lhsp->widthConst(); bit++) maskwidth.setBit(bit, 1);
if (destp->isQuad() && !rhsp->isQuad()) {
rhsp = new AstCCast(nodep->fileline(), rhsp, nodep);
}
if (!ones) {
oldvalp = new AstAnd(lhsp->fileline(),
new AstNot(lhsp->fileline(),
new AstShiftL(lhsp->fileline(),
new AstConst(nodep->fileline(),
maskwidth),
lhsp->lsbp()->cloneTree(true),
destp->width())),
oldvalp);
oldvalp = new AstAnd(
lhsp->fileline(),
new AstNot(lhsp->fileline(),
new AstShiftL(lhsp->fileline(),
new AstConst(nodep->fileline(), maskwidth),
lhsp->lsbp()->cloneTree(true), destp->width())),
oldvalp);
}
AstNode* newp
= new AstOr(lhsp->fileline(),
oldvalp,
new AstShiftL(lhsp->fileline(),
rhsp,
lhsp->lsbp()->cloneTree(true),
destp->width()));
= new AstOr(lhsp->fileline(), oldvalp,
new AstShiftL(lhsp->fileline(), rhsp,
lhsp->lsbp()->cloneTree(true), destp->width()));
newp = new AstAssign(nodep->fileline(), destp, newp);
//newp->dumpTree(cout, "- new: ");
// newp->dumpTree(cout, "- new: ");
insertBefore(nodep, newp);
return true;
}
@ -672,7 +613,7 @@ private:
if (nodep->isWide()) {
// See under ASSIGN(WIDE)
} else {
UINFO(8," CONCAT "<<nodep<<endl);
UINFO(8, " CONCAT " << nodep << endl);
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
int rhsshift = rhsp->widthMin();
@ -683,28 +624,26 @@ private:
rhsp = new AstCCast(nodep->fileline(), rhsp, nodep);
}
AstNode* newp = new AstOr(nodep->fileline(),
new AstShiftL(nodep->fileline(),
lhsp,
new AstShiftL(nodep->fileline(), lhsp,
new AstConst(nodep->fileline(), rhsshift),
nodep->width()),
rhsp);
rhsp);
newp->dtypeFrom(nodep); // Unsigned
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
bool expandWide(AstNodeAssign* nodep, AstConcat* rhsp) {
UINFO(8," Wordize ASSIGN(CONCAT) "<<nodep<<endl);
UINFO(8, " Wordize ASSIGN(CONCAT) " << nodep << endl);
// Lhs or Rhs may be word, long, or quad.
// newAstWordSelClone nicely abstracts the difference.
int rhsshift = rhsp->rhsp()->widthMin();
// Sometimes doing the words backwards is preferable.
// When we have x={x,foo} backwards is better, when x={foo,x} forward is better
// However V3Subst tends to rip this up, so not worth optimizing now.
for (int w=0; w<rhsp->widthWords(); w++) {
for (int w = 0; w < rhsp->widthWords(); w++) {
addWordAssign(nodep, w,
new AstOr(rhsp->fileline(),
newWordGrabShift(rhsp->fileline(), w,
rhsp->lhsp(), rhsshift),
newWordGrabShift(rhsp->fileline(), w, rhsp->lhsp(), rhsshift),
newAstWordSelClone(rhsp->rhsp(), w)));
}
return true;
@ -719,11 +658,11 @@ private:
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* newp;
int lhswidth = lhsp->widthMin();
if (lhswidth==1) {
UINFO(8," REPLICATE(w1) "<<nodep<<endl);
if (lhswidth == 1) {
UINFO(8, " REPLICATE(w1) " << nodep << endl);
newp = new AstNegate(nodep->fileline(), lhsp);
} else {
UINFO(8," REPLICATE "<<nodep<<endl);
UINFO(8, " REPLICATE " << nodep << endl);
const AstConst* constp = VN_CAST(nodep->rhsp(), Const);
UASSERT_OBJ(constp, nodep,
"Replication value isn't a constant. Checked earlier!");
@ -732,14 +671,13 @@ private:
lhsp = new AstCCast(nodep->fileline(), lhsp, nodep);
}
newp = lhsp->cloneTree(true);
for (unsigned repnum=1; repnum<times; repnum++) {
int rhsshift = repnum*lhswidth;
for (unsigned repnum = 1; repnum < times; repnum++) {
int rhsshift = repnum * lhswidth;
newp = new AstOr(nodep->fileline(),
new AstShiftL(nodep->fileline(),
lhsp->cloneTree(true),
new AstShiftL(nodep->fileline(), lhsp->cloneTree(true),
new AstConst(nodep->fileline(), rhsshift),
nodep->width()),
newp);
newp);
newp->dtypeFrom(nodep); // Unsigned
}
VL_DO_DANGLING(lhsp->deleteTree(), lhsp); // Never used
@ -749,25 +687,24 @@ private:
}
}
bool expandWide(AstNodeAssign* nodep, AstReplicate* rhsp) {
UINFO(8," Wordize ASSIGN(REPLICATE) "<<nodep<<endl);
UINFO(8, " Wordize ASSIGN(REPLICATE) " << nodep << endl);
AstNode* lhsp = rhsp->lhsp();
int lhswidth = lhsp->widthMin();
const AstConst* constp = VN_CAST(rhsp->rhsp(), Const);
UASSERT_OBJ(constp, rhsp, "Replication value isn't a constant. Checked earlier!");
uint32_t times = constp->toUInt();
for (int w=0; w<rhsp->widthWords(); w++) {
for (int w = 0; w < rhsp->widthWords(); w++) {
AstNode* newp;
if (lhswidth==1) {
if (lhswidth == 1) {
newp = new AstNegate(nodep->fileline(), lhsp->cloneTree(true));
newp->dtypeSetLogicSized(VL_EDATASIZE,
AstNumeric::UNSIGNED); // Replicate always unsigned
} else {
newp = newAstWordSelClone(lhsp, w);
for (unsigned repnum=1; repnum<times; repnum++) {
newp = new AstOr(nodep->fileline(),
newWordGrabShift(rhsp->fileline(), w, lhsp,
lhswidth*repnum),
newp);
for (unsigned repnum = 1; repnum < times; repnum++) {
newp = new AstOr(
nodep->fileline(),
newWordGrabShift(rhsp->fileline(), w, lhsp, lhswidth * repnum), newp);
}
}
addWordAssign(nodep, w, newp);
@ -778,14 +715,13 @@ private:
virtual void visit(AstChangeXor* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
UINFO(8," Wordize ChangeXor "<<nodep<<endl);
UINFO(8, " Wordize ChangeXor " << nodep << endl);
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
AstNode* newp = NULL;
for (int w=0; w<nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = new AstXor(nodep->fileline(),
newAstWordSelClone(nodep->lhsp(), w),
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = new AstXor(nodep->fileline(), newAstWordSelClone(nodep->lhsp(), w),
newAstWordSelClone(nodep->rhsp(), w));
newp = (newp==NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
}
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
@ -794,23 +730,21 @@ private:
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->lhsp()->isWide()) {
UINFO(8," Wordize EQ/NEQ "<<nodep<<endl);
UINFO(8, " Wordize EQ/NEQ " << nodep << endl);
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
AstNode* newp = NULL;
for (int w=0; w<nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = new AstXor(nodep->fileline(),
newAstWordSelClone(nodep->lhsp(), w),
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = new AstXor(nodep->fileline(), newAstWordSelClone(nodep->lhsp(), w),
newAstWordSelClone(nodep->rhsp(), w));
newp = (newp==NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
}
if (VN_IS(nodep, Neq)) {
newp = new AstNeq(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0),
newp);
newp
= new AstNeq(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), newp);
} else {
newp = new AstEq(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0),
newp);
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), newp);
}
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
@ -822,19 +756,18 @@ private:
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->lhsp()->isWide()) {
UINFO(8," Wordize REDOR "<<nodep<<endl);
UINFO(8, " Wordize REDOR " << nodep << endl);
// -> (0!={or{for each_word{WORDSEL(lhs,#)}}}
AstNode* newp = NULL;
for (int w=0; w<nodep->lhsp()->widthWords(); w++) {
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
newp = (newp==NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
}
newp = new AstNeq(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0),
newp);
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), newp);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
} else {
UINFO(8," REDOR->EQ "<<nodep<<endl);
UINFO(8, " REDOR->EQ " << nodep << endl);
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* newp = new AstNeq(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
@ -847,12 +780,12 @@ private:
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->lhsp()->isWide()) {
UINFO(8," Wordize REDAND "<<nodep<<endl);
UINFO(8, " Wordize REDAND " << nodep << endl);
// -> (0!={and{for each_word{WORDSEL(lhs,#)}}}
AstNode* newp = NULL;
for (int w=0; w<nodep->lhsp()->widthWords(); w++) {
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
if (w==nodep->lhsp()->widthWords()-1) {
if (w == nodep->lhsp()->widthWords() - 1) {
// Rather than doing a (slowish) ==##, we OR in the
// bits that aren't part of the mask
eqp = new AstOr(nodep->fileline(),
@ -861,18 +794,17 @@ private:
// cppcheck-suppress memleak
eqp);
}
newp = (newp==NULL) ? eqp : (new AstAnd(nodep->fileline(), newp, eqp));
newp = (newp == NULL) ? eqp : (new AstAnd(nodep->fileline(), newp, eqp));
}
newp = new AstEq(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::SizedEData(),
~VL_MASK_E(0)), newp);
newp = new AstEq(
nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::SizedEData(), ~VL_MASK_E(0)), newp);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
} else {
UINFO(8," REDAND->EQ "<<nodep<<endl);
UINFO(8, " REDAND->EQ " << nodep << endl);
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* newp = new AstEq(nodep->fileline(),
new AstConst(nodep->fileline(), wordMask(lhsp)),
lhsp);
new AstConst(nodep->fileline(), wordMask(lhsp)), lhsp);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
}
@ -880,15 +812,15 @@ private:
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (nodep->lhsp()->isWide()) {
UINFO(8," Wordize REDXOR "<<nodep<<endl);
UINFO(8, " Wordize REDXOR " << nodep << endl);
// -> (0!={redxor{for each_word{XOR(WORDSEL(lhs,#))}}}
AstNode* newp = NULL;
for (int w=0; w<nodep->lhsp()->widthWords(); w++) {
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
newp = (newp==NULL) ? eqp : (new AstXor(nodep->fileline(), newp, eqp));
newp = (newp == NULL) ? eqp : (new AstXor(nodep->fileline(), newp, eqp));
}
newp = new AstRedXor(nodep->fileline(), newp);
UINFO(8," Wordize REDXORnew "<<newp<<endl);
UINFO(8, " Wordize REDXORnew " << newp << endl);
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
}
// We don't reduce non-wide XORs, as its more efficient to use a temp register,
@ -910,8 +842,7 @@ private:
m_stmtp = nodep;
iterateChildren(nodep);
bool did = false;
if (nodep->isWide() && ((VN_IS(nodep->lhsp(), VarRef)
|| VN_IS(nodep->lhsp(), ArraySel)))
if (nodep->isWide() && ((VN_IS(nodep->lhsp(), VarRef) || VN_IS(nodep->lhsp(), ArraySel)))
&& !AstVar::scVarRecurse(nodep->lhsp()) // Need special function for SC
&& !AstVar::scVarRecurse(nodep->rhsp())) {
if (AstConst* rhsp = VN_CAST(nodep->rhsp(), Const)) {
@ -943,9 +874,7 @@ private:
did = expandLhs(nodep, lhsp);
}
// Cleanup common code
if (did) {
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
if (did) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
m_stmtp = NULL;
}
@ -969,9 +898,7 @@ public:
// Expand class functions
void V3Expand::expandAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
ExpandVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ ExpandVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("expand", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

File diff suppressed because it is too large Load Diff

View File

@ -40,11 +40,11 @@ public:
static std::ifstream* new_ifstream_nodepend(const string& filename) {
return new std::ifstream(filename.c_str());
}
static std::ofstream* new_ofstream(const string& filename, bool append=false) {
static std::ofstream* new_ofstream(const string& filename, bool append = false) {
addTgtDepend(filename);
return new_ofstream_nodepend(filename, append);
}
static std::ofstream* new_ofstream_nodepend(const string& filename, bool append=false) {
static std::ofstream* new_ofstream_nodepend(const string& filename, bool append = false) {
createMakeDirFor(filename);
if (append) {
return new std::ofstream(filename.c_str(), std::ios::app);
@ -86,6 +86,7 @@ private:
// CONSTRUCTORS
VL_UNCOPYABLE(VInFilter);
public:
explicit VInFilter(const string& command);
~VInFilter();
@ -100,12 +101,9 @@ public:
class V3OutFormatter {
// TYPES
enum MiscConsts {
MAXSPACE = 80}; // After this indent, stop indenting more
enum MiscConsts { MAXSPACE = 80 }; // After this indent, stop indenting more
public:
enum AlignClass {
AL_AUTO = 0,
AL_STATIC = 1};
enum AlignClass { AL_AUTO = 0, AL_STATIC = 1 };
enum Language {
LA_C = 0,
LA_VERILOG = 1,
@ -115,17 +113,17 @@ public:
private:
// MEMBERS
string m_filename;
Language m_lang; // Indenting Verilog code
int m_blockIndent; // Characters per block indent
int m_commaWidth; // Width after which to break at ,'s
int m_lineno;
int m_column;
int m_nobreak; // Basic operator or begin paren, don't break next
bool m_prependIndent;
int m_indentLevel; // Current {} indentation
string m_filename;
Language m_lang; // Indenting Verilog code
int m_blockIndent; // Characters per block indent
int m_commaWidth; // Width after which to break at ,'s
int m_lineno;
int m_column;
int m_nobreak; // Basic operator or begin paren, don't break next
bool m_prependIndent;
int m_indentLevel; // Current {} indentation
std::stack<int> m_parenVec; // Stack of columns where last ( was
int m_bracketLevel; // Intenting = { block, indicates number of {'s seen.
int m_bracketLevel; // Intenting = { block, indicates number of {'s seen.
int endLevels(const char* strg);
void putcNoTracking(char chr);
@ -146,18 +144,26 @@ public:
void putsQuoted(const string& strg);
void putBreak(); // Print linebreak if line is too wide
void putBreakExpr(); // Print linebreak in expression if line is too wide
void putbs(const char* strg) { putBreakExpr(); puts(strg); }
void putbs(const string& strg) { putBreakExpr(); puts(strg); }
void putbs(const char* strg) {
putBreakExpr();
puts(strg);
}
void putbs(const string& strg) {
putBreakExpr();
puts(strg);
}
bool exceededWidth() const { return m_column > m_commaWidth; }
bool tokenStart(const char* cp, const char* cmp);
bool tokenEnd(const char* cp);
void indentInc() { m_indentLevel += m_blockIndent; }
void indentDec() {
m_indentLevel -= m_blockIndent;
UASSERT(m_indentLevel>=0, ": "<<m_filename<<": Underflow of indentation");
UASSERT(m_indentLevel >= 0, ": " << m_filename << ": Underflow of indentation");
}
void blockInc() { m_parenVec.push(m_indentLevel + m_blockIndent); }
void blockDec() { if (!m_parenVec.empty()) m_parenVec.pop(); }
void blockDec() {
if (!m_parenVec.empty()) m_parenVec.pop();
}
// STATIC METHODS
static const string indentSpaces(int num);
// Add escaped characters to strings
@ -172,11 +178,13 @@ public:
class V3OutFile : public V3OutFormatter {
// MEMBERS
FILE* m_fp;
FILE* m_fp;
public:
V3OutFile(const string& filename, V3OutFormatter::Language lang);
virtual ~V3OutFile();
void putsForceIncs();
private:
// CALLBACKS
virtual void putcOutput(char chr) { fputc(chr, m_fp); }
@ -213,7 +221,8 @@ public:
class V3OutScFile : public V3OutCFile {
public:
explicit V3OutScFile(const string& filename) : V3OutCFile(filename) {}
explicit V3OutScFile(const string& filename)
: V3OutCFile(filename) {}
virtual ~V3OutScFile() {}
virtual void putsHeader() { puts("// Verilated -*- SystemC -*-\n"); }
virtual void putsIntTopInclude() {
@ -262,9 +271,9 @@ public:
// METHODS
// Rename to a new encoded string (unless earlier passthru'ed)
static string protect(const string& old) { return protectIf(old, true); }
static string protectIf(const string& old, bool doIt=true);
static string protectIf(const string& old, bool doIt = true);
// Rename words to a new encoded string
static string protectWordsIf(const string& old, bool doIt=true);
static string protectWordsIf(const string& old, bool doIt = true);
// Write map of renames to output file
static void writeMapFile(const string& filename);
};

View File

@ -17,6 +17,7 @@
#include "config_build.h"
#include "verilatedos.h"
// clang-format off
#include "V3Error.h"
#include "V3FileLine.h"
#include "V3String.h"
@ -27,6 +28,7 @@
# include "V3Config.h"
# include "V3File.h"
#endif
// clang-format on
#include <algorithm>
#include <cstdarg>
@ -39,11 +41,11 @@
const string FileLineSingleton::filenameLetters(int fileno) {
const int size = 1 + (64 / 4); // Each letter retires more than 4 bits of a > 64 bit number
char out[size];
char* op = out+size-1;
char* op = out + size - 1;
*--op = '\0'; // We build backwards
int num = fileno;
do {
*--op = 'a'+num%26;
*--op = 'a' + num % 26;
num /= 26;
} while (num);
return op;
@ -70,13 +72,13 @@ int FileLineSingleton::nameToNumber(const string& filename) {
//! Support XML output
//! Experimental. Updated to also put out the language.
void FileLineSingleton::fileNameNumMapDumpXml(std::ostream& os) {
os<<"<files>\n";
os << "<files>\n";
for (FileNameNumMap::const_iterator it = m_namemap.begin(); it != m_namemap.end(); ++it) {
os<<"<file id=\""<<filenameLetters(it->second)
<<"\" filename=\""<<V3OutFormatter::quoteNameControls(it->first, V3OutFormatter::LA_XML)
<<"\" language=\""<<numberToLang(it->second).ascii()<<"\"/>\n";
os << "<file id=\"" << filenameLetters(it->second) << "\" filename=\""
<< V3OutFormatter::quoteNameControls(it->first, V3OutFormatter::LA_XML)
<< "\" language=\"" << numberToLang(it->second).ascii() << "\"/>\n";
}
os<<"</files>\n";
os << "</files>\n";
}
//######################################################################
@ -95,17 +97,18 @@ void VFileContent::pushText(const string& text) {
}
// Any leftover text is stored on largest line (might be "")
string leftover = m_lines.back() + text; m_lines.pop_back();
string leftover = m_lines.back() + text;
m_lines.pop_back();
// Insert line-by-line
string::size_type line_start = 0;
while (true) {
string::size_type line_end = leftover.find('\n', line_start);
if (line_end != string::npos) {
string oneline (leftover, line_start, line_end-line_start+1);
string oneline(leftover, line_start, line_end - line_start + 1);
m_lines.push_back(oneline); // Keeps newline
UINFO(9, "PushStream[ct"<<m_id<<"+"<<(m_lines.size()-1)<<"]: "<<oneline);
line_start = line_end+1;
UINFO(9, "PushStream[ct" << m_id << "+" << (m_lines.size() - 1) << "]: " << oneline);
line_start = line_end + 1;
} else {
break;
}
@ -119,18 +122,22 @@ string VFileContent::getLine(int lineno) const {
// cppcheck-suppress negativeContainerIndex
if (VL_UNCOVERABLE(lineno < 0 || lineno >= (int)m_lines.size())) {
if (debug() || v3Global.opt.debugCheck()) {
return ("%Error-internal-contents-bad-ct"+cvtToStr(m_id)
+"-ln"+cvtToStr(lineno));
} else return "";
return ("%Error-internal-contents-bad-ct" + cvtToStr(m_id) + "-ln" + cvtToStr(lineno));
} else {
return "";
}
}
string text = m_lines[lineno];
UINFO(9, "Get Stream[ct"<<m_id<<"+"<<lineno<<"]: "<<text);
UINFO(9, "Get Stream[ct" << m_id << "+" << lineno << "]: " << text);
return text;
}
std::ostream& operator<<(std::ostream& os, VFileContent* contentp) {
if (!contentp) os <<"ct0";
else os <<contentp->ascii();
if (!contentp) {
os << "ct0";
} else {
os << contentp->ascii();
}
return os;
}
@ -149,7 +156,7 @@ FileLine::FileLine(FileLine::EmptySecret) {
m_parent = NULL;
m_warnOn = 0;
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = V3ErrorCode(codei);
warnOff(code, code.defaultsOff());
}
@ -161,18 +168,17 @@ void FileLine::newContent() {
}
const string FileLine::xmlDetailedLocation() const {
return "loc=\"" +
cvtToStr(filenameLetters()) + "," +
cvtToStr(firstLineno()) + "," +
cvtToStr(firstColumn()) + "," +
cvtToStr(lastLineno()) + "," +
cvtToStr(lastColumn()) + "\"";
return "loc=\"" + cvtToStr(filenameLetters()) + "," + cvtToStr(firstLineno()) + ","
+ cvtToStr(firstColumn()) + "," + cvtToStr(lastLineno()) + "," + cvtToStr(lastColumn())
+ "\"";
}
string FileLine::lineDirectiveStrg(int enterExit) const {
char numbuf[20]; sprintf(numbuf, "%d", lastLineno());
char levelbuf[20]; sprintf(levelbuf, "%d", enterExit);
return (string("`line ")+numbuf+" \""+filename()+"\" "+levelbuf+"\n");
char numbuf[20];
sprintf(numbuf, "%d", lastLineno());
char levelbuf[20];
sprintf(levelbuf, "%d", enterExit);
return (string("`line ") + numbuf + " \"" + filename() + "\" " + levelbuf + "\n");
}
void FileLine::lineDirective(const char* textp, int& enterExitRef) {
@ -183,7 +189,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) {
// Skip `line
while (*textp && isspace(*textp)) textp++;
while (*textp && !isspace(*textp)) textp++;
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
while (*textp && (isspace(*textp) || *textp == '"')) textp++;
// Grab linenumber
bool fail = false;
@ -191,22 +197,26 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) {
while (*textp && !isspace(*textp)) textp++;
if (isdigit(*ln)) {
lineno(atoi(ln));
} else fail = true;
} else {
fail = true;
}
while (*textp && (isspace(*textp))) textp++;
if (*textp != '"') fail = true;
while (*textp && (isspace(*textp) || *textp == '"')) textp++;
// Grab filename
const char* fn = textp;
while (*textp && !(isspace(*textp) || *textp=='"')) textp++;
while (*textp && !(isspace(*textp) || *textp == '"')) textp++;
if (textp != fn) {
string strfn = fn;
strfn = strfn.substr(0, textp-fn);
strfn = strfn.substr(0, textp - fn);
filename(strfn);
} else fail = true;
} else {
fail = true;
}
// Grab level
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
while (*textp && (isspace(*textp) || *textp == '"')) textp++;
if (isdigit(*textp)) {
enterExitRef = atoi(textp);
if (enterExitRef >= 3) fail = true;
@ -219,7 +229,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) {
v3error("`line was not properly formed with '`line number \"filename\" level'\n");
}
//printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str());
// printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str());
}
void FileLine::forwardToken(const char* textp, size_t size, bool trackLines) {
@ -254,50 +264,46 @@ FileLine* FileLine::copyOrSameFileLine() {
const string FileLine::filebasename() const {
string name = filename();
string::size_type pos;
if ((pos = name.rfind('/')) != string::npos) {
name.erase(0, pos+1);
}
if ((pos = name.rfind('/')) != string::npos) name.erase(0, pos + 1);
return name;
}
const string FileLine::filebasenameNoExt() const {
string name = filebasename();
string::size_type pos;
if ((pos = name.find('.')) != string::npos) {
name = name.substr(0, pos);
}
if ((pos = name.find('.')) != string::npos) name = name.substr(0, pos);
return name;
}
const string FileLine::profileFuncname() const {
// Return string that is OK as a function name - for profiling
string name = filebasenameNoExt();
string name = filebasenameNoExt();
string::size_type pos;
while ((pos = name.find_first_not_of("abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_"))
while ((pos = name.find_first_not_of(
"abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_"))
!= string::npos) {
name.replace(pos, 1, "_");
}
name += "__l"+cvtToStr(lastLineno());
name += "__l" + cvtToStr(lastLineno());
return name;
}
string FileLine::asciiLineCol() const {
return (cvtToStr(firstLineno())+"-"+cvtToStr(lastLineno())
+":"+cvtToStr(firstColumn())+"-"+cvtToStr(lastColumn())
+"["+(m_contentp ? m_contentp->ascii() : "ct0")
+"+"+cvtToStr(m_contentLineno)+"]");
return (cvtToStr(firstLineno()) + "-" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn())
+ "-" + cvtToStr(lastColumn()) + "[" + (m_contentp ? m_contentp->ascii() : "ct0") + "+"
+ cvtToStr(m_contentLineno) + "]");
}
string FileLine::ascii() const {
// For most errors especially in the parser the lastLineno is more accurate than firstLineno
return filename() + ":" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn());
}
std::ostream& operator<<(std::ostream& os, FileLine* fileline) {
os <<fileline->ascii()<<": "<<std::hex;
return(os);
os << fileline->ascii() << ": " << std::hex;
return (os);
}
bool FileLine::warnOff(const string& msg, bool flag) {
V3ErrorCode code (msg.c_str());
V3ErrorCode code(msg.c_str());
if (code < V3ErrorCode::EC_FIRST_WARN) {
return false;
#ifndef _V3ERROR_NO_GLOBAL_
@ -312,14 +318,14 @@ bool FileLine::warnOff(const string& msg, bool flag) {
}
void FileLine::warnLintOff(bool flag) {
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = V3ErrorCode(codei);
if (code.lintError()) warnOff(code, flag);
}
}
void FileLine::warnStyleOff(bool flag) {
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = V3ErrorCode(codei);
if (code.styleError()) warnOff(code, flag);
}
@ -329,15 +335,16 @@ bool FileLine::warnIsOff(V3ErrorCode code) const {
if (!m_warnOn.test(code)) return true;
if (!defaultFileLine().m_warnOn.test(code)) return true; // Global overrides local
// UNOPTFLAT implies UNOPT
if (code==V3ErrorCode::UNOPT && !m_warnOn.test(V3ErrorCode::UNOPTFLAT)) return true;
if ((code.lintError() || code.styleError())
&& !m_warnOn.test(V3ErrorCode::I_LINT)) return true;
if (code == V3ErrorCode::UNOPT && !m_warnOn.test(V3ErrorCode::UNOPTFLAT)) return true;
if ((code.lintError() || code.styleError()) && !m_warnOn.test(V3ErrorCode::I_LINT)) {
return true;
}
return false;
}
void FileLine::modifyStateInherit(const FileLine* fromp) {
// Any warnings that are off in "from", become off in "this".
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = V3ErrorCode(codei);
if (fromp->warnIsOff(code)) { warnOff(code, true); }
}
@ -345,31 +352,33 @@ void FileLine::modifyStateInherit(const FileLine* fromp) {
void FileLine::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
std::ostringstream nsstr;
if (lastLineno()) nsstr<<this;
if (lastLineno()) nsstr << this;
nsstr << sstr.str();
nsstr << endl;
std::ostringstream lstr;
if (!locationStr.empty()) {
lstr<<std::setw(ascii().length())<<" "<<": "<<locationStr;
lstr << std::setw(ascii().length()) << " "
<< ": " << locationStr;
}
if (warnIsOff(V3Error::errorCode())
|| V3Config::waive(this, V3Error::errorCode(), sstr.str())) {
V3Error::suppressThisWarning();
} else if (!V3Error::errorContexted()) {
nsstr << warnContextPrimary();
}
else if (!V3Error::errorContexted()) nsstr<<warnContextPrimary();
V3Error::v3errorEnd(nsstr, lstr.str());
}
string FileLine::warnMore() const {
if (lastLineno()) {
return V3Error::warnMore()+string(ascii().size(), ' ')+": ";
return V3Error::warnMore() + string(ascii().size(), ' ') + ": ";
} else {
return V3Error::warnMore();
}
}
string FileLine::warnOther() const {
if (lastLineno()) {
return V3Error::warnMore()+ascii()+": ";
return V3Error::warnMore() + ascii() + ": ";
} else {
return V3Error::warnMore();
}
@ -405,8 +414,7 @@ string FileLine::warnContext(bool secondary) const {
if (!sourceLine.empty() && sourceLine.length() < SHOW_SOURCE_MAX_LENGTH
&& sourceLine.length() >= static_cast<size_t>(lastColumn() - 1)) {
string linestr = cvtToStr(firstLineno());
while (linestr.size() < 5)
linestr = ' ' + linestr;
while (linestr.size() < 5) linestr = ' ' + linestr;
out += linestr + " | " + sourceLine + "\n";
out += std::string(linestr.size(), ' ') + " | ";
out += string((firstColumn() - 1), ' ') + '^';
@ -458,7 +466,7 @@ void FileLine::deleteAllRemaining() {
// only when leak checking we'll track them all and cleanup.
while (true) {
FileLineCheckSet::iterator it = fileLineLeakChecks.begin();
if (it==fileLineLeakChecks.end()) break;
if (it == fileLineLeakChecks.end()) break;
delete *it;
// Operator delete will remove the iterated object from the list.
// Eventually the list will be empty and terminate the loop.

View File

@ -39,22 +39,27 @@ class FileLine;
//! source file (each with its own unique filename number).
class FileLineSingleton {
// TYPES
typedef std::map<string,int> FileNameNumMap;
typedef std::map<string,V3LangCode> FileLangNumMap;
typedef std::map<string, int> FileNameNumMap;
typedef std::map<string, V3LangCode> FileLangNumMap;
// MEMBERS
FileNameNumMap m_namemap; // filenameno for each filename
std::deque<string> m_names; // filename text for each filenameno
FileNameNumMap m_namemap; // filenameno for each filename
std::deque<string> m_names; // filename text for each filenameno
std::deque<V3LangCode> m_languages; // language for each filenameno
// CONSTRUCTORS
FileLineSingleton() { }
~FileLineSingleton() { }
FileLineSingleton() {}
~FileLineSingleton() {}
protected:
friend class FileLine;
int nameToNumber(const string& filename);
const string numberToName(int filenameno) const { return m_names[filenameno]; }
const V3LangCode numberToLang(int filenameno) const { return m_languages[filenameno]; }
void numberToLang(int filenameno, const V3LangCode& l) { m_languages[filenameno] = l; }
void clear() { m_namemap.clear(); m_names.clear(); m_languages.clear(); }
void clear() {
m_namemap.clear();
m_names.clear();
m_languages.clear();
}
void fileNameNumMapDumpXml(std::ostream& os);
static const string filenameLetters(int fileno);
};
@ -65,12 +70,15 @@ class VFileContent {
int m_id; // Content ID number
std::deque<string> m_lines; // Source text lines
public:
VFileContent() { static int s_id = 0; m_id = ++s_id; }
~VFileContent() { }
VFileContent() {
static int s_id = 0;
m_id = ++s_id;
}
~VFileContent() {}
// METHODS
void pushText(const string& text); // Add arbitrary text (need not be line-by-line)
string getLine(int lineno) const;
string ascii() const { return "ct"+cvtToStr(m_id); }
string ascii() const { return "ct" + cvtToStr(m_id); }
static int debug();
};
std::ostream& operator<<(std::ostream& os, VFileContent* contentp);
@ -104,6 +112,7 @@ protected:
friend class V3PreLex;
friend class V3PreProcImp;
friend class V3PreShellImp;
private:
// CONSTRUCTORS
static FileLineSingleton& singleton() {
@ -114,6 +123,7 @@ private:
static FileLine* defFilelinep = new FileLine(FileLine::EmptySecret());
return *defFilelinep;
}
public:
explicit FileLine(const string& filename)
: m_firstLineno(0)
@ -139,24 +149,33 @@ public:
explicit FileLine(EmptySecret);
FileLine* copyOrSameFileLine();
static void deleteAllRemaining();
~FileLine() { }
~FileLine() {}
#ifdef VL_LEAK_CHECKS
static void* operator new(size_t size);
static void operator delete(void* obj, size_t size);
#endif
// METHODS
void newContent();
void lineno(int num) { m_firstLineno = num; m_lastLineno = num;
m_firstColumn = m_lastColumn = 1; }
void lineno(int num) {
m_firstLineno = num;
m_lastLineno = num;
m_firstColumn = m_lastColumn = 1;
}
void language(V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); }
void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); }
void parent(FileLine* fileline) { m_parent = fileline; }
void lineDirective(const char* textp, int& enterExitRef);
void linenoInc() { m_lastLineno++; m_lastColumn = 1; m_contentLineno++; }
void startToken() { m_firstLineno = m_lastLineno;
m_firstColumn = m_lastColumn; }
void linenoInc() {
m_lastLineno++;
m_lastColumn = 1;
m_contentLineno++;
}
void startToken() {
m_firstLineno = m_lastLineno;
m_firstColumn = m_lastColumn;
}
// Advance last line/column based on given text
void forwardToken(const char* textp, size_t size, bool trackLines=true);
void forwardToken(const char* textp, size_t size, bool trackLines = true);
int firstLineno() const { return m_firstLineno; }
int firstColumn() const { return m_firstColumn; }
int lastLineno() const { return m_lastLineno; }
@ -172,13 +191,16 @@ public:
string ascii() const;
string asciiLineCol() const;
const string filename() const { return singleton().numberToName(m_filenameno); }
bool filenameIsGlobal() const { return (filename() == commandLineFilename()
|| filename() == builtInFilename()); }
bool filenameIsGlobal() const {
return (filename() == commandLineFilename() || filename() == builtInFilename());
}
const string filenameLetters() const { return singleton().filenameLetters(m_filenameno); }
const string filebasename() const;
const string filebasenameNoExt() const;
const string profileFuncname() const;
const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lastLineno())+"\""; }
const string xml() const {
return "fl=\"" + filenameLetters() + cvtToStr(lastLineno()) + "\"";
}
const string xmlDetailedLocation() const;
string lineDirectiveStrg(int enterExit) const;
@ -202,16 +224,15 @@ public:
// <command-line> and <built-in> match what GCC outputs
static string commandLineFilename() { return "<command-line>"; }
static string builtInFilename() { return "<built-in>"; }
static void globalWarnLintOff(bool flag) {
defaultFileLine().warnLintOff(flag); }
static void globalWarnStyleOff(bool flag) {
defaultFileLine().warnStyleOff(flag); }
static void globalWarnLintOff(bool flag) { defaultFileLine().warnLintOff(flag); }
static void globalWarnStyleOff(bool flag) { defaultFileLine().warnStyleOff(flag); }
static void globalWarnOff(V3ErrorCode code, bool flag) {
defaultFileLine().warnOff(code, flag); }
defaultFileLine().warnOff(code, flag);
}
static bool globalWarnOff(const string& code, bool flag) {
return defaultFileLine().warnOff(code, flag); }
static void fileNameNumMapDumpXml(std::ostream& os) {
singleton().fileNameNumMapDumpXml(os); }
return defaultFileLine().warnOff(code, flag);
}
static void fileNameNumMapDumpXml(std::ostream& os) { singleton().fileNameNumMapDumpXml(os); }
// METHODS - Called from netlist
// Merge warning disables from another fileline
@ -237,13 +258,11 @@ public:
/// Simplified information vs warnContextPrimary() to make dump clearer
string warnContextSecondary() const { return warnContext(true); }
bool operator==(const FileLine& rhs) const {
return (m_firstLineno == rhs.m_firstLineno
&& m_firstColumn == rhs.m_firstColumn
&& m_lastLineno == rhs.m_lastLineno
&& m_lastColumn == rhs.m_lastColumn
&& m_filenameno == rhs.m_filenameno
&& m_warnOn == rhs.m_warnOn);
return (m_firstLineno == rhs.m_firstLineno && m_firstColumn == rhs.m_firstColumn
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
&& m_filenameno == rhs.m_filenameno && m_warnOn == rhs.m_warnOn);
}
private:
void v3errorEndFatalGuts(std::ostringstream& str);
string warnContext(bool secondary) const;
@ -251,7 +270,9 @@ private:
std::ostream& operator<<(std::ostream& os, FileLine* fileline);
inline void FileLine::v3errorEndFatal(std::ostringstream& str) {
v3errorEnd(str); assert(0); VL_UNREACHABLE
v3errorEnd(str);
assert(0);
VL_UNREACHABLE
}
#endif // Guard

File diff suppressed because it is too large Load Diff

View File

@ -45,13 +45,13 @@ private:
// Cleared on top scope
// AstVarScope::user2() -> AstVarScope*. Signal replacing activation with
// AstVarRef::user3() -> bool. Signal is replaced activation (already done)
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
// STATE
AstActive* m_activep; // Inside activate statement
AstNodeModule* m_topModp; // Top module
AstScope* m_scopetopp; // Scope under TOPSCOPE
AstActive* m_activep; // Inside activate statement
AstNodeModule* m_topModp; // Top module
AstScope* m_scopetopp; // Scope under TOPSCOPE
// METHODS
AstVarScope* genInpClk(AstVarScope* vscp) {
@ -59,18 +59,19 @@ private:
return VN_CAST(vscp->user2p(), VarScope);
} else {
AstVar* varp = vscp->varp();
string newvarname = "__VinpClk__"+vscp->scopep()->nameDotless()+"__"+varp->name();
string newvarname
= "__VinpClk__" + vscp->scopep()->nameDotless() + "__" + varp->name();
// Create: VARREF(inpclk)
// ...
// ASSIGN(VARREF(inpclk), VARREF(var))
AstVar* newvarp = new AstVar(varp->fileline(),
AstVarType::MODULETEMP, newvarname, varp);
AstVar* newvarp
= new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
m_topModp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
m_scopetopp->addVarp(newvscp);
AstAssign* asninitp = new AstAssign(vscp->fileline(),
new AstVarRef(vscp->fileline(), newvscp, true),
new AstVarRef(vscp->fileline(), vscp, false));
AstAssign* asninitp
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
new AstVarRef(vscp->fileline(), vscp, false));
m_scopetopp->addFinalClkp(asninitp);
//
vscp->user2p(newvscp);
@ -96,7 +97,7 @@ private:
if (m_activep && !nodep->user3()) {
nodep->user3(true);
if (vscp->isCircular()) {
UINFO(8," VarActReplace "<<nodep<<endl);
UINFO(8, " VarActReplace " << nodep << endl);
// Replace with the new variable
AstVarScope* newvscp = genInpClk(vscp);
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
@ -112,9 +113,7 @@ private:
m_activep = NULL;
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateChildren(nodep); }
//-----
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
@ -138,13 +137,13 @@ private:
// NODE STATE
// Cleared on top scope
// AstVarScope::user() -> bool. Set when the var has been used as clock
AstUser1InUse m_inuser1;
AstUser1InUse m_inuser1;
// STATE
AstActive* m_activep; // Inside activate statement
bool m_tracingCall; // Iterating into a call to a cfunc
AstNodeAssign* m_assignp; // Inside assigndly statement
AstNodeModule* m_topModp; // Top module
AstActive* m_activep; // Inside activate statement
bool m_tracingCall; // Iterating into a call to a cfunc
AstNodeAssign* m_assignp; // Inside assigndly statement
AstNodeModule* m_topModp; // Top module
// VISITORS
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
@ -153,7 +152,7 @@ private:
{
// Make the new clock signals and replace any activate references
// See rename, it does some AstNode::userClearTree()'s
GenClkRenameVisitor visitor (nodep, m_topModp);
GenClkRenameVisitor visitor(nodep, m_topModp);
}
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
@ -188,24 +187,24 @@ private:
AstVarScope* vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
if (m_activep) {
UINFO(8," VarAct "<<nodep<<endl);
UINFO(8, " VarAct " << nodep << endl);
vscp->user1(true);
}
if (m_assignp && nodep->lvalue() && vscp->user1()) {
// Variable was previously used as a clock, and is now being set
// Thus a unordered generated clock...
UINFO(8," VarSetAct "<<nodep<<endl);
UINFO(8, " VarSetAct " << nodep << endl);
vscp->circular(true);
}
}
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
//UINFO(8,"ASS "<<nodep<<endl);
// UINFO(8, "ASS " << nodep << endl);
m_assignp = nodep;
iterateChildren(nodep);
m_assignp = NULL;
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
UINFO(8,"ACTIVE "<<nodep<<endl);
UINFO(8, "ACTIVE " << nodep << endl);
m_activep = nodep;
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
iterateChildren(nodep->sensesp()); // iterateAndNext?
@ -233,9 +232,7 @@ public:
// GenClk class functions
void V3GenClk::genClkAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
GenClkReadVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ GenClkReadVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("genclk", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -34,13 +34,17 @@ int V3Graph::debug() { return std::max(V3Error::debugDefault(), s_debug); }
// Vertices
V3GraphVertex::V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old)
: m_fanout(old.m_fanout), m_color(old.m_color), m_rank(old.m_rank) {
: m_fanout(old.m_fanout)
, m_color(old.m_color)
, m_rank(old.m_rank) {
m_userp = NULL;
verticesPushBack(graphp);
}
V3GraphVertex::V3GraphVertex(V3Graph* graphp)
: m_fanout(0), m_color(0), m_rank(0) {
: m_fanout(0)
, m_color(0)
, m_rank(0) {
m_userp = NULL;
verticesPushBack(graphp);
}
@ -68,13 +72,13 @@ void V3GraphVertex::unlinkDelete(V3Graph* graphp) {
// Unlink from vertex list
m_vertices.unlink(graphp->m_vertices, this);
// Delete
delete this; //this=NULL;
delete this; // this=NULL;
}
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()) {
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());
@ -84,13 +88,8 @@ void V3GraphVertex::rerouteEdges(V3Graph* graphp) {
unlinkEdges(graphp);
}
bool V3GraphVertex::inSize1() const {
return !inEmpty() && inBeginp()->inNextp()==NULL;
}
bool V3GraphVertex::outSize1() const {
return !outEmpty() && outBeginp()->outNextp()==NULL;
}
bool V3GraphVertex::inSize1() const { return !inEmpty() && !inBeginp()->inNextp(); }
bool V3GraphVertex::outSize1() const { return !outEmpty() && !outBeginp()->outNextp(); }
uint32_t V3GraphVertex::inHash() const {
// We want the same hash ignoring the order of edges.
@ -98,7 +97,7 @@ uint32_t V3GraphVertex::inHash() const {
// However with XOR multiple edges to the same source will cancel out,
// so we use ADD. (Generally call this only after removing duplicates though)
uint32_t hash = 0;
for (V3GraphEdge* edgep = this->inBeginp(); edgep; edgep=edgep->inNextp()) {
for (V3GraphEdge* edgep = this->inBeginp(); edgep; edgep = edgep->inNextp()) {
hash += cvtToHash(edgep->fromp());
}
return hash;
@ -106,14 +105,13 @@ uint32_t V3GraphVertex::inHash() const {
uint32_t V3GraphVertex::outHash() const {
uint32_t hash = 0;
for (V3GraphEdge* edgep = this->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = this->outBeginp(); edgep; edgep = edgep->outNextp()) {
hash += cvtToHash(edgep->top());
}
return hash;
}
V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way,
const V3GraphVertex* waywardp) {
V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, const 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.
@ -131,10 +129,10 @@ V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way,
void V3GraphVertex::v3errorEnd(std::ostringstream& str) const {
std::ostringstream nsstr;
nsstr<<str.str();
nsstr << str.str();
if (debug()) {
nsstr<<endl;
nsstr<<"-vertex: "<<this<<endl;
nsstr << endl;
nsstr << "-vertex: " << this << endl;
}
if (!fileline()) {
V3Error::v3errorEnd(nsstr);
@ -143,14 +141,16 @@ void V3GraphVertex::v3errorEnd(std::ostringstream& str) const {
}
}
void V3GraphVertex::v3errorEndFatal(std::ostringstream& str) const {
v3errorEnd(str); assert(0); VL_UNREACHABLE
v3errorEnd(str);
assert(0);
VL_UNREACHABLE
}
std::ostream& operator<<(std::ostream& os, V3GraphVertex* vertexp) {
os<<" VERTEX="<<vertexp->name();
if (vertexp->rank()) os<<" r"<<vertexp->rank();
if (vertexp->fanout()!=0.0) os<<" f"<<vertexp->fanout();
if (vertexp->color()) os<<" c"<<vertexp->color();
os << " VERTEX=" << vertexp->name();
if (vertexp->rank()) os << " r" << vertexp->rank();
if (vertexp->fanout() != 0.0) os << " f" << vertexp->fanout();
if (vertexp->color()) os << " c" << vertexp->color();
return os;
}
@ -158,8 +158,7 @@ std::ostream& operator<<(std::ostream& os, V3GraphVertex* vertexp) {
//######################################################################
// Edges
void V3GraphEdge::init(V3Graph* graphp,
V3GraphVertex* fromp, V3GraphVertex* top, int weight,
void V3GraphEdge::init(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight,
bool cutable) {
UASSERT(fromp, "Null from pointer");
UASSERT(top, "Null to pointer");
@ -174,7 +173,7 @@ void V3GraphEdge::init(V3Graph* graphp,
}
V3GraphEdge* V3GraphEdge::relinkFromp(V3GraphVertex* newFromp) {
V3GraphEdge *oldNxt = outNextp();
V3GraphEdge* oldNxt = outNextp();
m_outs.unlink(m_fromp->m_outs, this);
m_fromp = newFromp;
outPushBack();
@ -187,7 +186,7 @@ void V3GraphEdge::unlinkDelete() {
// Unlink to side
m_ins.unlink(m_top->m_ins, this);
// Delete
delete this; //this=NULL;
delete this; // this=NULL;
}
void V3GraphEdge::outPushBack() {
@ -210,14 +209,12 @@ V3Graph::V3Graph() {
verticesUnlink();
}
V3Graph::~V3Graph() {
clear();
}
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 (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; /*BELOW*/) {
V3GraphEdge* nextp = edgep->outNextp();
VL_DO_DANGLING(delete edgep, edgep);
@ -241,7 +238,7 @@ void V3Graph::userClearVertices() {
// 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()) {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
vertexp->user(0);
vertexp->userp(NULL); // Its a union, but might be different size than user()
}
@ -249,8 +246,8 @@ void V3Graph::userClearVertices() {
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()) {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
edgep->user(0);
edgep->userp(NULL); // Its a union, but might be different size than user()
}
@ -259,7 +256,7 @@ void V3Graph::userClearEdges() {
void V3Graph::clearColors() {
// Reset colors
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
vertexp->m_color = 0;
}
}
@ -268,72 +265,70 @@ void V3Graph::clearColors() {
// Dumping
void V3Graph::loopsMessageCb(V3GraphVertex* vertexp) {
vertexp->v3fatalSrc("Loops detected in graph: "<<vertexp);
vertexp->v3fatalSrc("Loops detected in graph: " << vertexp);
}
void V3Graph::loopsVertexCb(V3GraphVertex* vertexp) {
// Needed here as V3GraphVertex<< isn't defined until later in header
if (debug()) std::cerr<<"-Info-Loop: "<<cvtToHex(vertexp)<<" "<<vertexp<<endl;
if (debug()) std::cerr << "-Info-Loop: " << cvtToHex(vertexp) << " " << vertexp << endl;
}
void V3Graph::dump(std::ostream& os) {
// This generates a file used by graphviz, https://www.graphviz.org
os<<" Graph:\n";
os << " Graph:\n";
// Print vertices
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
os<<"\tNode: "<<vertexp->name();
if (vertexp->color()) os<<" color="<<vertexp->color();
os<<endl;
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
os << "\tNode: " << vertexp->name();
if (vertexp->color()) os << " color=" << vertexp->color();
os << endl;
// Print edges
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
dumpEdge(os, vertexp, edgep);
}
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
dumpEdge(os, vertexp, edgep);
}
}
}
void V3Graph::dumpEdge(std::ostream& os, V3GraphVertex* vertexp, V3GraphEdge* edgep) {
if (edgep->weight()
&& (edgep->fromp() == vertexp
|| edgep->top() == vertexp)) {
os<<"\t\t";
if (edgep->fromp() == vertexp) os << "-> "<<edgep->top()->name();
if (edgep->top() == vertexp) os << "<- "<<edgep->fromp()->name();
if (edgep->cutable()) os<<" [CUTABLE]";
os<<endl;
if (edgep->weight() && (edgep->fromp() == vertexp || edgep->top() == vertexp)) {
os << "\t\t";
if (edgep->fromp() == vertexp) os << "-> " << edgep->top()->name();
if (edgep->top() == vertexp) os << "<- " << edgep->fromp()->name();
if (edgep->cutable()) os << " [CUTABLE]";
os << endl;
}
}
void V3Graph::dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph) const {
if (v3Global.opt.dumpTree()) {
dumpDotFile(v3Global.debugFilename(nameComment)+".dot", colorAsSubgraph);
dumpDotFile(v3Global.debugFilename(nameComment) + ".dot", colorAsSubgraph);
}
}
//! Variant of dumpDotFilePrefixed without --dump option check
void V3Graph::dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph) const {
dumpDotFile(v3Global.debugFilename(nameComment)+".dot", colorAsSubgraph);
dumpDotFile(v3Global.debugFilename(nameComment) + ".dot", colorAsSubgraph);
}
void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
// This generates a file used by graphviz, https://www.graphviz.org
// "hardcoded" parameters:
const vl_unique_ptr<std::ofstream> logp (V3File::new_ofstream(filename));
if (logp->fail()) v3fatal("Can't write "<<filename);
const vl_unique_ptr<std::ofstream> logp(V3File::new_ofstream(filename));
if (logp->fail()) v3fatal("Can't write " << filename);
// Header
*logp<<"digraph v3graph {\n";
*logp<<"\tgraph\t[label=\""<<filename<<"\",\n";
*logp<<"\t\t labelloc=t, labeljust=l,\n";
*logp<<"\t\t //size="<<"\"7.5,10\","<<"\n";
*logp<<"\t\t rankdir="<<dotRankDir()<<"];\n";
*logp << "digraph v3graph {\n";
*logp << "\tgraph\t[label=\"" << filename << "\",\n";
*logp << "\t\t labelloc=t, labeljust=l,\n";
*logp << "\t\t //size=\"7.5,10\",\n";
*logp << "\t\t rankdir=" << dotRankDir() << "];\n";
// List of all possible subgraphs
typedef std::multimap<string,V3GraphVertex*> SubgraphMmap;
typedef std::multimap<string, V3GraphVertex*> SubgraphMmap;
SubgraphMmap subgraphs;
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
string vertexSubgraph
= (colorAsSubgraph && vertexp->color()) ? cvtToStr(vertexp->color()) : "";
subgraphs.insert(make_pair(vertexSubgraph, vertexp));
@ -341,7 +336,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
// We use a map here, as we don't want to corrupt anything (userp) in the graph,
// and we don't care if this is slow.
std::map<V3GraphVertex*,int> numMap;
std::map<V3GraphVertex*, int> numMap;
// Print vertices
int n = 0;
@ -351,42 +346,41 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
V3GraphVertex* vertexp = it->second;
numMap[vertexp] = n;
if (subgr != vertexSubgraph) {
if (subgr!="") *logp<<"\t};\n";
if (subgr != "") *logp << "\t};\n";
subgr = vertexSubgraph;
if (subgr!="") *logp<<"\tsubgraph cluster_"<<subgr<<" {\n";
if (subgr != "") *logp << "\tsubgraph cluster_" << subgr << " {\n";
}
if (subgr!="") *logp<<"\t";
*logp<<"\tn"<<vertexp->dotName()<<(n++)
<<"\t[fontsize=8 "
<<"label=\""<<(vertexp->name()!="" ? vertexp->name() : "\\N");
if (vertexp->rank()) *logp<<" r"<<vertexp->rank();
if (vertexp->fanout()!=0.0) *logp<<" f"<<vertexp->fanout();
if (vertexp->color()) *logp<<"\\n c"<<vertexp->color();
*logp<<"\"";
*logp<<", color="<<vertexp->dotColor();
if (vertexp->dotStyle()!="") *logp<<", style="<<vertexp->dotStyle();
if (vertexp->dotShape()!="") *logp<<", shape="<<vertexp->dotShape();
*logp<<"];\n";
if (subgr != "") *logp << "\t";
*logp << "\tn" << vertexp->dotName() << (n++) << "\t[fontsize=8 "
<< "label=\"" << (vertexp->name() != "" ? vertexp->name() : "\\N");
if (vertexp->rank()) *logp << " r" << vertexp->rank();
if (vertexp->fanout() != 0.0) *logp << " f" << vertexp->fanout();
if (vertexp->color()) *logp << "\\n c" << vertexp->color();
*logp << "\"";
*logp << ", color=" << vertexp->dotColor();
if (vertexp->dotStyle() != "") *logp << ", style=" << vertexp->dotStyle();
if (vertexp->dotShape() != "") *logp << ", shape=" << vertexp->dotShape();
*logp << "];\n";
}
if (subgr!="") *logp<<"\t};\n";
if (subgr != "") *logp << "\t};\n";
// Print edges
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (edgep->weight()) {
int fromVnum = numMap[edgep->fromp()];
int toVnum = numMap[edgep->top()];
*logp<<"\tn"<<edgep->fromp()->dotName()<<fromVnum
<<" -> n"<<edgep->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 following edges
*logp<<"];\n";
int toVnum = numMap[edgep->top()];
*logp << "\tn" << edgep->fromp()->dotName() << fromVnum << " -> n"
<< edgep->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
// following edges
*logp << "];\n";
}
}
}
@ -396,5 +390,5 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
*logp << "}\n";
logp->close();
cout << "dot -Tpdf -o ~/a.pdf "<<filename<<endl;
cout << "dot -Tpdf -o ~/a.pdf " << filename << endl;
}

View File

@ -32,19 +32,20 @@
class GraphAcycVertex : public V3GraphVertex {
// user() is used for various sub-algorithm pieces
V3GraphVertex* m_origVertexp; // Pointer to first vertex this represents
V3GraphVertex* m_origVertexp; // Pointer to first vertex this represents
protected:
friend class GraphAcyc;
V3ListEnt<GraphAcycVertex*> m_work; // List of vertices with optimization work left
uint32_t m_storedRank; // Rank held until commit to edge placement
bool m_onWorkList; // True if already on list of work to do
bool m_deleted; // True if deleted
V3ListEnt<GraphAcycVertex*> m_work; // List of vertices with optimization work left
uint32_t m_storedRank; // Rank held until commit to edge placement
bool m_onWorkList; // True if already on list of work to do
bool m_deleted; // True if deleted
public:
GraphAcycVertex(V3Graph* graphp, V3GraphVertex* origVertexp)
: V3GraphVertex(graphp), m_origVertexp(origVertexp)
, m_storedRank(0), m_onWorkList(false), m_deleted(false) {
}
: V3GraphVertex(graphp)
, m_origVertexp(origVertexp)
, m_storedRank(0)
, m_onWorkList(false)
, m_deleted(false) {}
virtual ~GraphAcycVertex() {}
V3GraphVertex* origVertexp() const { return m_origVertexp; }
void setDelete() { m_deleted = true; }
@ -60,25 +61,25 @@ class GraphAcycEdge : public V3GraphEdge {
// userp() is always used to point to the head original graph edge
private:
typedef std::list<V3GraphEdge*> OrigEdgeList; // List of orig edges, see also GraphAcyc's decl
V3GraphEdge* origEdgep() const {
V3GraphEdge* origEdgep() const {
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(userp());
if (!oEListp) v3fatalSrc("No original edge associated with acyc edge "<<this<<endl);
if (!oEListp) v3fatalSrc("No original edge associated with acyc edge " << this << endl);
return (oEListp->front());
}
public:
GraphAcycEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
int weight, bool cutable=false)
: V3GraphEdge(graphp, fromp, top, weight, cutable) {
}
GraphAcycEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight,
bool cutable = false)
: V3GraphEdge(graphp, fromp, top, weight, cutable) {}
virtual ~GraphAcycEdge() {}
// yellow=we might still cut it, else oldEdge: yellowGreen=made uncutable, red=uncutable
virtual string dotColor() const { return (cutable()?"yellow":origEdgep()->dotColor()); }
virtual string dotColor() const { return (cutable() ? "yellow" : origEdgep()->dotColor()); }
};
//--------------------------------------------------------------------
struct GraphAcycEdgeCmp {
inline bool operator() (const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const {
inline bool operator()(const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const {
if (lhsp->weight() > rhsp->weight()) return 1; // LHS goes first
if (lhsp->weight() < rhsp->weight()) return 0; // RHS goes first
return 0;
@ -90,7 +91,8 @@ struct GraphAcycEdgeCmp {
// CLASSES
class GraphAcyc {
private:
typedef std::list<V3GraphEdge*> OrigEdgeList; // List of orig edges, see also GraphAcycEdge's decl
typedef std::list<V3GraphEdge*>
OrigEdgeList; // List of orig edges, see also GraphAcycEdge's decl
// GRAPH USERS
// origGraph
// GraphVertex::user() GraphAycVerted* New graph node
@ -98,12 +100,12 @@ private:
// GraphEdge::user() OrigEdgeList* Old graph edges
// GraphVertex::user bool Detection of loops in simplifyDupIterate
// MEMBERS
V3Graph* m_origGraphp; // Original graph
V3Graph m_breakGraph; // Graph with only breakable edges represented
V3List<GraphAcycVertex*> m_work; // List of vertices with optimization work left
V3Graph* m_origGraphp; // Original graph
V3Graph m_breakGraph; // Graph with only breakable edges represented
V3List<GraphAcycVertex*> m_work; // List of vertices with optimization work left
std::vector<OrigEdgeList*> m_origEdgeDelp; // List of deletions to do when done
V3EdgeFuncP m_origEdgeFuncp; // Function that says we follow this edge (in original graph)
uint32_t m_placeStep; // Number that user() must be equal to to indicate processing
V3EdgeFuncP m_origEdgeFuncp; // Function that says we follow this edge (in original graph)
uint32_t m_placeStep; // Number that user() must be equal to to indicate processing
static int debug() { return V3Graph::debug(); }
@ -127,8 +129,8 @@ private:
}
V3GraphEdge* edgeFromEdge(V3GraphEdge* oldedgep, V3GraphVertex* fromp, V3GraphVertex* top) {
// Make new breakGraph edge, with old edge as a template
GraphAcycEdge* newEdgep = new GraphAcycEdge(&m_breakGraph, fromp, top,
oldedgep->weight(), oldedgep->cutable());
GraphAcycEdge* newEdgep = new GraphAcycEdge(&m_breakGraph, fromp, top, oldedgep->weight(),
oldedgep->cutable());
newEdgep->userp(oldedgep->userp()); // Keep pointer to OrigEdgeList
return newEdgep;
}
@ -153,16 +155,18 @@ private:
}
void cutOrigEdge(V3GraphEdge* breakEdgep, const char* why) {
// From the break edge, cut edges in original graph it represents
UINFO(8,why<<" CUT "<<breakEdgep->fromp()<<endl);
UINFO(8, why << " CUT " << breakEdgep->fromp() << endl);
breakEdgep->cut();
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(breakEdgep->userp());
if (!oEListp) v3fatalSrc("No original edge associated with cutting edge "
<<breakEdgep<<endl);
if (!oEListp) {
v3fatalSrc("No original edge associated with cutting edge " << breakEdgep << endl);
}
// The breakGraph edge may represent multiple real edges; cut them all
for (OrigEdgeList::iterator it = oEListp->begin(); it != oEListp->end(); ++it) {
V3GraphEdge* origEdgep = *it;
origEdgep->cut();
UINFO(8," "<<why<<" "<<origEdgep->fromp()<<" ->"<<origEdgep->top()<<endl);
UINFO(8,
" " << why << " " << origEdgep->fromp() << " ->" << origEdgep->top() << endl);
}
}
// Work Queue
@ -178,7 +182,9 @@ private:
void workPop() {
GraphAcycVertex* avertexp = workBeginp();
avertexp->m_onWorkList = false;
avertexp->m_work.unlink(m_work, avertexp); }
avertexp->m_work.unlink(m_work, avertexp);
}
public:
// CONSTRUCTORS
GraphAcyc(V3Graph* origGraphp, V3EdgeFuncP edgeFuncp) {
@ -205,8 +211,8 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) {
// For each old node, make a new graph node for optimization
origGraphp->userClearVertices();
origGraphp->userClearEdges();
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp();
overtexp; overtexp = overtexp->verticesNextp()) {
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); overtexp;
overtexp = overtexp->verticesNextp()) {
if (overtexp->color()) {
GraphAcycVertex* avertexp = new GraphAcycVertex(&m_breakGraph, overtexp);
overtexp->userp(avertexp); // Stash so can look up later
@ -214,8 +220,8 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) {
}
// Build edges between logic vertices
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp();
overtexp; overtexp = overtexp->verticesNextp()) {
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); overtexp;
overtexp = overtexp->verticesNextp()) {
if (overtexp->color()) {
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(overtexp->userp());
buildGraphIterate(overtexp, avertexp);
@ -225,15 +231,15 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) {
void GraphAcyc::buildGraphIterate(V3GraphVertex* overtexp, GraphAcycVertex* avertexp) {
// Make new edges
for (V3GraphEdge* edgep = overtexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = overtexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (origFollowEdge(edgep)) { // not cut
V3GraphVertex* toVertexp = edgep->top();
if (toVertexp->color()) {
GraphAcycVertex* toAVertexp = static_cast<GraphAcycVertex*>(toVertexp->userp());
// Replicate the old edge into the new graph
// There may be multiple edges between same pairs of vertices
V3GraphEdge* breakEdgep = new GraphAcycEdge
(&m_breakGraph, avertexp, toAVertexp, edgep->weight(), edgep->cutable());
V3GraphEdge* breakEdgep = new GraphAcycEdge(&m_breakGraph, avertexp, toAVertexp,
edgep->weight(), edgep->cutable());
addOrigEdgep(breakEdgep, edgep); // So can find original edge
}
}
@ -242,8 +248,8 @@ void GraphAcyc::buildGraphIterate(V3GraphVertex* overtexp, GraphAcycVertex* aver
void GraphAcyc::simplify(bool allowCut) {
// Add all nodes to list of work to do
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp();
vertexp; vertexp = vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
workPush(vertexp);
}
// Optimize till everything finished
@ -267,7 +273,8 @@ void GraphAcyc::simplify(bool allowCut) {
void GraphAcyc::deleteMarked() {
// Delete nodes marked for removal
for (V3GraphVertex* nextp, *vertexp = m_breakGraph.verticesBeginp(); vertexp; vertexp=nextp) {
for (V3GraphVertex *nextp, *vertexp = m_breakGraph.verticesBeginp(); vertexp;
vertexp = nextp) {
nextp = vertexp->verticesNextp();
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(vertexp);
if (avertexp->isDelete()) {
@ -281,18 +288,18 @@ void GraphAcyc::simplifyNone(GraphAcycVertex* avertexp) {
// Likewise, vertices with no outputs
if (avertexp->isDelete()) return;
if (avertexp->inEmpty() || avertexp->outEmpty()) {
UINFO(9," SimplifyNoneRemove "<<avertexp<<endl);
UINFO(9, " SimplifyNoneRemove " << avertexp << endl);
avertexp->setDelete(); // Mark so we won't delete it twice
// Remove edges
while (V3GraphEdge* edgep = avertexp->outBeginp()) {
V3GraphVertex* otherVertexp = edgep->top();
//UINFO(9," out "<<otherVertexp<<endl);
// UINFO(9, " out " << otherVertexp << endl);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
workPush(otherVertexp);
}
while (V3GraphEdge* edgep = avertexp->inBeginp()) {
V3GraphVertex* otherVertexp = edgep->fromp();
//UINFO(9," in "<<otherVertexp<<endl);
// UINFO(9, " in " << otherVertexp << endl);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
workPush(otherVertexp);
}
@ -309,23 +316,25 @@ void GraphAcyc::simplifyOne(GraphAcycVertex* avertexp) {
V3GraphVertex* outVertexp = outEdgep->top();
// The in and out may be the same node; we'll make a loop
// The in OR out may be THIS node; we can't delete it then.
if (inVertexp!=avertexp && outVertexp!=avertexp) {
UINFO(9," SimplifyOneRemove "<<avertexp<<endl);
if (inVertexp != avertexp && outVertexp != avertexp) {
UINFO(9, " SimplifyOneRemove " << avertexp << endl);
avertexp->setDelete(); // Mark so we won't delete it twice
// Make a new edge connecting the two vertices directly
// If both are breakable, we pick the one with less weight, else it's arbitrary
// We can forget about the origEdge list for the "non-selected" set of edges,
// as we need to break only one set or the other set of edges, not both.
// (This is why we must give preference to the cutable set.)
V3GraphEdge* templateEdgep = ( (inEdgep->cutable()
&& (!outEdgep->cutable()
|| inEdgep->weight()<outEdgep->weight() ))
? inEdgep : outEdgep);
V3GraphEdge* templateEdgep
= ((inEdgep->cutable()
&& (!outEdgep->cutable() || inEdgep->weight() < outEdgep->weight()))
? inEdgep
: outEdgep);
// cppcheck-suppress leakReturnValNotUsed
edgeFromEdge(templateEdgep, inVertexp, outVertexp);
// Remove old edge
VL_DO_DANGLING(inEdgep->unlinkDelete(), inEdgep);
VL_DO_DANGLING(outEdgep->unlinkDelete(), outEdgep); VL_DANGLING(templateEdgep);
VL_DO_DANGLING(outEdgep->unlinkDelete(), outEdgep);
VL_DANGLING(templateEdgep);
workPush(inVertexp);
workPush(outVertexp);
}
@ -340,16 +349,17 @@ void GraphAcyc::simplifyOut(GraphAcycVertex* avertexp) {
V3GraphEdge* outEdgep = avertexp->outBeginp();
if (!outEdgep->cutable()) {
V3GraphVertex* outVertexp = outEdgep->top();
UINFO(9," SimplifyOutRemove "<<avertexp<<endl);
UINFO(9, " SimplifyOutRemove " << avertexp << endl);
avertexp->setDelete(); // Mark so we won't delete it twice
for (V3GraphEdge* nextp, *inEdgep = avertexp->inBeginp(); inEdgep; inEdgep=nextp) {
for (V3GraphEdge *nextp, *inEdgep = avertexp->inBeginp(); inEdgep; inEdgep = nextp) {
nextp = inEdgep->inNextp();
V3GraphVertex* inVertexp = inEdgep->fromp();
if (inVertexp == avertexp) {
if (debug()) v3error("Non-cutable edge forms a loop, vertex="<<avertexp);
if (debug()) v3error("Non-cutable edge forms a loop, vertex=" << avertexp);
v3error("Circular logic when ordering code (non-cutable edge loop)");
m_origGraphp->reportLoops(&V3GraphEdge::followNotCutable,
avertexp->origVertexp()); // calls OrderGraph::loopsVertexCb
m_origGraphp->reportLoops(
&V3GraphEdge::followNotCutable,
avertexp->origVertexp()); // calls OrderGraph::loopsVertexCb
// Things are unlikely to end well at this point,
// but we'll try something to get to further errors...
inEdgep->cutable(true);
@ -372,11 +382,11 @@ void GraphAcyc::simplifyDup(GraphAcycVertex* avertexp) {
// Remove redundant edges
if (avertexp->isDelete()) return;
// Clear marks
for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
edgep->top()->userp(NULL);
}
// Mark edges and detect duplications
for (V3GraphEdge* nextp, *edgep = avertexp->outBeginp(); edgep; edgep=nextp) {
for (V3GraphEdge *nextp, *edgep = avertexp->outBeginp(); edgep; edgep = nextp) {
nextp = edgep->outNextp();
V3GraphVertex* outVertexp = edgep->top();
V3GraphEdge* prevEdgep = static_cast<V3GraphEdge*>(outVertexp->userp());
@ -384,16 +394,16 @@ void GraphAcyc::simplifyDup(GraphAcycVertex* avertexp) {
if (!prevEdgep->cutable()) {
// !cutable duplicates prev !cutable: we can ignore it, redundant
// cutable duplicates prev !cutable: know it's not a relevant loop, ignore it
UINFO(8," DelDupEdge "<<avertexp<<" -> "<<edgep->top()<<endl);
UINFO(8, " DelDupEdge " << avertexp << " -> " << edgep->top() << endl);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
} else if (!edgep->cutable()) {
// !cutable duplicates prev cutable: delete the earlier cutable
UINFO(8," DelDupPrev "<<avertexp<<" -> "<<prevEdgep->top()<<endl);
UINFO(8, " DelDupPrev " << avertexp << " -> " << prevEdgep->top() << endl);
VL_DO_DANGLING(prevEdgep->unlinkDelete(), prevEdgep);
outVertexp->userp(edgep);
} else {
// cutable duplicates prev cutable: combine weights
UINFO(8," DelDupComb "<<avertexp<<" -> "<<edgep->top()<<endl);
UINFO(8, " DelDupComb " << avertexp << " -> " << edgep->top() << endl);
prevEdgep->weight(prevEdgep->weight() + edgep->weight());
addOrigEdgep(prevEdgep, edgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
@ -410,9 +420,9 @@ void GraphAcyc::simplifyDup(GraphAcycVertex* avertexp) {
void GraphAcyc::cutBasic(GraphAcycVertex* avertexp) {
// Detect and cleanup any loops from node to itself
if (avertexp->isDelete()) return;
for (V3GraphEdge* nextp, *edgep = avertexp->outBeginp(); edgep; edgep=nextp) {
for (V3GraphEdge *nextp, *edgep = avertexp->outBeginp(); edgep; edgep = nextp) {
nextp = edgep->outNextp();
if (edgep->cutable() && edgep->top()==avertexp) {
if (edgep->cutable() && edgep->top() == avertexp) {
cutOrigEdge(edgep, " Cut Basic");
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
workPush(avertexp);
@ -424,14 +434,14 @@ void GraphAcyc::cutBackward(GraphAcycVertex* avertexp) {
// If a cutable edge is from A->B, and there's a non-cutable edge B->A, then must cut!
if (avertexp->isDelete()) return;
// Clear marks
for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
edgep->top()->user(false);
}
for (V3GraphEdge* edgep = avertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
for (V3GraphEdge* edgep = avertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
if (!edgep->cutable()) edgep->fromp()->user(true);
}
// Detect duplications
for (V3GraphEdge* nextp, *edgep = avertexp->outBeginp(); edgep; edgep=nextp) {
for (V3GraphEdge *nextp, *edgep = avertexp->outBeginp(); edgep; edgep = nextp) {
nextp = edgep->outNextp();
if (edgep->cutable() && edgep->top()->user()) {
cutOrigEdge(edgep, " Cut A->B->A");
@ -446,25 +456,22 @@ void GraphAcyc::place() {
// Make a list of all cutable edges in the graph
int numEdges = 0;
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp();
vertexp; vertexp = vertexp->verticesNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
if (edgep->weight() && edgep->cutable()) {
numEdges++;
}
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (edgep->weight() && edgep->cutable()) ++numEdges;
}
}
UINFO(4, " Cutable edges = "<<numEdges<<endl);
UINFO(4, " Cutable edges = " << numEdges << endl);
std::vector<V3GraphEdge*> edges; // List of all edges to be processed
edges.reserve(numEdges+1); // Make the vector properly sized right off the bat -- faster than reallocating
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp();
vertexp; vertexp = vertexp->verticesNextp()) {
// Make the vector properly sized right off the bat -- faster than reallocating
edges.reserve(numEdges + 1);
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
vertexp->user(0); // Clear in prep of next step
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
if (edgep->weight() && edgep->cutable()) {
edges.push_back(edgep);
}
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (edgep->weight() && edgep->cutable()) edges.push_back(edgep);
}
}
@ -473,7 +480,7 @@ void GraphAcyc::place() {
// Process each edge in weighted order
m_placeStep = 10;
for (std::vector<V3GraphEdge*>::iterator it = edges.begin(); it!=edges.end(); ++it) {
for (std::vector<V3GraphEdge*>::iterator it = edges.begin(); it != edges.end(); ++it) {
V3GraphEdge* edgep = (*it);
placeTryEdge(edgep);
}
@ -482,22 +489,21 @@ void GraphAcyc::place() {
void GraphAcyc::placeTryEdge(V3GraphEdge* edgep) {
// Try to make this edge uncutable
m_placeStep++;
UINFO(8, " PlaceEdge s"<<m_placeStep<<" w"<<edgep->weight()<<" "<<edgep->fromp()<<endl);
UINFO(8, " PlaceEdge s" << m_placeStep << " w" << edgep->weight() << " " << edgep->fromp()
<< endl);
// Make the edge uncutable so we detect it in placement
edgep->cutable(false);
// Vertex::m_user begin: number indicates this edge was completed
// Try to assign ranks, presuming this edge is in place
// If we come across user()==placestep, we've detected a loop and must back out
bool loop = placeIterate(static_cast<GraphAcycVertex*>(edgep->top()),
edgep->fromp()->rank()+1);
bool loop
= placeIterate(static_cast<GraphAcycVertex*>(edgep->top()), edgep->fromp()->rank() + 1);
if (!loop) {
// No loop, we can keep it as uncutable
// Commit the new ranks we calculated
// Just cleanup the list. If this is slow, we can add another set of
// user counters to avoid cleaning up the list.
while (workBeginp()) {
workPop();
}
while (workBeginp()) workPop();
} else {
// Adding this edge would cause a loop, kill it
edgep->cutable(true); // So graph still looks pretty
@ -526,9 +532,9 @@ bool GraphAcyc::placeIterate(GraphAcycVertex* vertexp, uint32_t currentRank) {
}
vertexp->rank(currentRank);
// Follow all edges and increase their ranks
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (edgep->weight() && !edgep->cutable()) {
if (placeIterate(static_cast<GraphAcycVertex*>(edgep->top()), currentRank+1)) {
if (placeIterate(static_cast<GraphAcycVertex*>(edgep->top()), currentRank + 1)) {
// We don't need to reset user(); we'll use a different placeStep for the next edge
return true; // Loop detected
}
@ -551,33 +557,33 @@ void GraphAcyc::main() {
// edges (and thus can't represent loops - if we did the unbreakable
// marking right, anyways)
buildGraph(m_origGraphp);
if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_pre");
if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_pre");
// Perform simple optimizations before any cuttings
simplify(false);
if (debug()>=5) m_breakGraph.dumpDotFilePrefixed("acyc_simp");
if (debug() >= 5) m_breakGraph.dumpDotFilePrefixed("acyc_simp");
UINFO(4, " Cutting trivial loops\n");
simplify(true);
if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_mid");
if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_mid");
UINFO(4, " Ranking\n");
m_breakGraph.rank(&V3GraphEdge::followNotCutable);
if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_rank");
if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_rank");
UINFO(4, " Placement\n");
place();
if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_place");
if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_place");
UINFO(4, " Final Ranking\n");
// Only needed to assert there are no loops in completed graph
m_breakGraph.rank(&V3GraphEdge::followAlwaysTrue);
if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_done");
if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_done");
}
void V3Graph::acyclic(V3EdgeFuncP edgeFuncp) {
UINFO(4, "Acyclic\n");
GraphAcyc acyc (this, edgeFuncp);
GraphAcyc acyc(this, edgeFuncp);
acyc.main();
UINFO(4, "Acyclic done\n");
}

View File

@ -36,15 +36,15 @@ void V3Graph::deleteCutableOnlyEdges() {
// Vertex::m_user begin: indicates can be deleted
// Pass 1, mark those. Don't delete now, as we don't want to rip out whole trees
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
vertexp->user(true);
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
if (!edgep->cutable()) {
vertexp->user(false); // Can't delete it
break;
}
}
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (!edgep->cutable()) {
vertexp->user(false); // Can't delete it
break;
@ -54,10 +54,10 @@ void V3Graph::deleteCutableOnlyEdges() {
// Pass 2, delete those marked
// Rather than doing a delete() we set the weight to 0 which disconnects the edge.
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
if (vertexp->user()) {
//UINFO(7,"Disconnect "<<vertexp->name()<<endl);
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
// UINFO(7, "Disconnect " << vertexp->name() << endl);
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
edgep->cut();
}
}
@ -71,21 +71,21 @@ void V3Graph::deleteCutableOnlyEdges() {
// Algorithms - weakly connected components
class GraphRemoveRedundant : GraphAlg<> {
bool m_sumWeights; ///< Sum, rather then maximize weights
bool m_sumWeights; ///< Sum, rather then maximize weights
private:
void main() {
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
vertexIterate(vertexp);
}
}
void vertexIterate(V3GraphVertex* vertexp) {
// Clear marks
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
edgep->top()->userp(NULL);
}
// Mark edges and detect duplications
for (V3GraphEdge* nextp, *edgep = vertexp->outBeginp(); edgep; edgep=nextp) {
for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep = nextp) {
nextp = edgep->outNextp();
if (followEdge(edgep)) {
V3GraphVertex* outVertexp = edgep->top();
@ -100,7 +100,8 @@ private:
saveOld = true; // old !cutable more important than new
} else {
saveOld = true;
if (!m_sumWeights && (prevEdgep->weight() < edgep->weight())) { // Keep max weight
if (!m_sumWeights
&& (prevEdgep->weight() < edgep->weight())) { // Keep max weight
prevEdgep->weight(edgep->weight());
}
}
@ -116,9 +117,11 @@ private:
}
}
}
public:
GraphRemoveRedundant(V3Graph* graphp, V3EdgeFuncP edgeFuncp, bool sumWeights)
: GraphAlg<>(graphp, edgeFuncp), m_sumWeights(sumWeights) {
: GraphAlg<>(graphp, edgeFuncp)
, m_sumWeights(sumWeights) {
main();
}
~GraphRemoveRedundant() {}
@ -141,33 +144,26 @@ public:
: GraphAlg<>(graphp, NULL) {}
void go() {
GraphPathChecker checker(m_graphp);
for (V3GraphVertex* vxp = m_graphp->verticesBeginp();
vxp; vxp = vxp->verticesNextp()) {
for (V3GraphVertex* vxp = m_graphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
V3GraphEdge* deletep = NULL;
for (V3GraphEdge* edgep = vxp->outBeginp();
edgep; edgep = edgep->outNextp()) {
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (deletep) VL_DO_CLEAR(deletep->unlinkDelete(), deletep = NULL);
// It should be safe to modify the graph, despite using
// the GraphPathChecker, as none of the modifications will
// change what can be reached from what, nor should they
// change the rank or CP of any node.
if (checker.isTransitiveEdge(edgep)) {
deletep = edgep;
}
}
if (deletep) {
VL_DO_DANGLING(deletep->unlinkDelete(), deletep);
if (checker.isTransitiveEdge(edgep)) deletep = edgep;
}
if (deletep) VL_DO_DANGLING(deletep->unlinkDelete(), deletep);
}
}
private:
VL_DEBUG_FUNC; // Declare debug()
VL_UNCOPYABLE(GraphAlgRemoveTransitiveEdges);
};
void V3Graph::removeTransitiveEdges() {
GraphAlgRemoveTransitiveEdges(this).go();
}
void V3Graph::removeTransitiveEdges() { GraphAlgRemoveTransitiveEdges(this).go(); }
//######################################################################
//######################################################################
@ -180,9 +176,9 @@ private:
m_graphp->clearColors();
// Color graph
uint32_t currentColor = 0;
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
vertexp; vertexp=vertexp->verticesNextp()) {
currentColor ++;
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
currentColor++;
vertexIterate(vertexp, currentColor);
}
}
@ -192,17 +188,14 @@ private:
// then visit each of its edges, giving them the same color
if (vertexp->color()) return; // Already colored it
vertexp->color(currentColor);
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
if (followEdge(edgep)) {
vertexIterate(edgep->top(), currentColor);
}
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (followEdge(edgep)) vertexIterate(edgep->top(), currentColor);
}
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
if (followEdge(edgep)) {
vertexIterate(edgep->fromp(), currentColor);
}
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
if (followEdge(edgep)) vertexIterate(edgep->fromp(), currentColor);
}
}
public:
GraphAlgWeakly(V3Graph* graphp, V3EdgeFuncP edgeFuncp)
: GraphAlg<>(graphp, edgeFuncp) {
@ -211,9 +204,7 @@ public:
~GraphAlgWeakly() {}
};
void V3Graph::weaklyConnected(V3EdgeFuncP edgeFuncp) {
GraphAlgWeakly(this, edgeFuncp);
}
void V3Graph::weaklyConnected(V3EdgeFuncP edgeFuncp) { GraphAlgWeakly(this, edgeFuncp); }
//######################################################################
//######################################################################
@ -231,14 +222,14 @@ private:
// Vertex::color // Output subtree number (fully processed)
// Clear info
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
vertexp->color(0);
vertexp->user(0);
}
// Color graph
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
if (!vertexp->user()) {
m_currentDfs++;
vertexIterate(vertexp);
@ -246,10 +237,10 @@ private:
}
// If there's a single vertex of a color, it doesn't need a subgraph
// This simplifies the consumer's code, and reduces graph debugging clutter
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
bool onecolor = true;
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (followEdge(edgep)) {
if (vertexp->color() == edgep->top()->color()) {
onecolor = false;
@ -265,7 +256,7 @@ private:
uint32_t thisDfsNum = m_currentDfs++;
vertexp->user(thisDfsNum);
vertexp->color(0);
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (followEdge(edgep)) {
V3GraphVertex* top = edgep->top();
if (!top->user()) { // Dest not computed yet
@ -291,6 +282,7 @@ private:
m_callTrace.push_back(vertexp);
}
}
public:
GraphAlgStrongly(V3Graph* graphp, V3EdgeFuncP edgeFuncp)
: GraphAlg<>(graphp, edgeFuncp) {
@ -300,9 +292,7 @@ public:
~GraphAlgStrongly() {}
};
void V3Graph::stronglyConnected(V3EdgeFuncP edgeFuncp) {
GraphAlgStrongly(this, edgeFuncp);
}
void V3Graph::stronglyConnected(V3EdgeFuncP edgeFuncp) { GraphAlgStrongly(this, edgeFuncp); }
//######################################################################
//######################################################################
@ -314,16 +304,14 @@ private:
// Rank each vertex, ignoring cutable edges
// Vertex::m_user begin: 1 indicates processing, 2 indicates completed
// Clear existing ranks
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
vertexp->rank(0);
vertexp->user(0);
}
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
vertexp; vertexp=vertexp->verticesNextp()) {
if (!vertexp->user()) {
vertexIterate(vertexp, 1);
}
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
if (!vertexp->user()) { vertexIterate(vertexp, 1); }
}
}
@ -339,13 +327,14 @@ private:
if (vertexp->rank() >= currentRank) return; // Already processed it
vertexp->user(1);
vertexp->rank(currentRank);
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (followEdge(edgep)) {
vertexIterate(edgep->top(), currentRank + vertexp->rankAdder());
}
}
vertexp->user(2);
}
public:
GraphAlgRank(V3Graph* graphp, V3EdgeFuncP edgeFuncp)
: GraphAlg<>(graphp, edgeFuncp) {
@ -354,13 +343,9 @@ public:
~GraphAlgRank() {}
};
void V3Graph::rank() {
GraphAlgRank(this, &V3GraphEdge::followAlwaysTrue);
}
void V3Graph::rank() { GraphAlgRank(this, &V3GraphEdge::followAlwaysTrue); }
void V3Graph::rank(V3EdgeFuncP edgeFuncp) {
GraphAlgRank(this, edgeFuncp);
}
void V3Graph::rank(V3EdgeFuncP edgeFuncp) { GraphAlgRank(this, edgeFuncp); }
//######################################################################
//######################################################################
@ -389,7 +374,7 @@ private:
m_callTrace[currentRank++] = vertexp;
if (vertexp->user() == 1) {
for (unsigned i=0; i<currentRank; i++) {
for (unsigned i = 0; i < currentRank; i++) { //
m_graphp->loopsVertexCb(m_callTrace[i]);
}
m_done = true;
@ -397,13 +382,12 @@ private:
}
if (vertexp->user() == 2) return; // Already processed it
vertexp->user(1);
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
if (followEdge(edgep)) {
vertexIterate(edgep->top(), currentRank);
}
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (followEdge(edgep)) vertexIterate(edgep->top(), currentRank);
}
vertexp->user(2);
}
public:
GraphAlgRLoops(V3Graph* graphp, V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp)
: GraphAlg<>(graphp, edgeFuncp) {
@ -417,7 +401,6 @@ void V3Graph::reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) {
GraphAlgRLoops(this, edgeFuncp, vertexp);
}
//######################################################################
//######################################################################
// Algorithms - subtrees
@ -434,14 +417,12 @@ private:
newVertexp = vertexp->clone(m_loopGraphp);
vertexp->userp(newVertexp);
for (V3GraphEdge* edgep = vertexp->outBeginp();
edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (followEdge(edgep)) {
V3GraphEdge* newEdgep = static_cast<V3GraphEdge*>(edgep->userp());
if (!newEdgep) {
V3GraphVertex* newTop = vertexIterateAll(edgep->top());
newEdgep = edgep->clone(m_loopGraphp, newVertexp,
newTop);
newEdgep = edgep->clone(m_loopGraphp, newVertexp, newTop);
edgep->userp(newEdgep);
}
}
@ -451,21 +432,21 @@ private:
}
public:
GraphAlgSubtrees(V3Graph* graphp, V3Graph* loopGraphp,
V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp)
: GraphAlg<>(graphp, edgeFuncp), m_loopGraphp(loopGraphp) {
GraphAlgSubtrees(V3Graph* graphp, V3Graph* loopGraphp, V3EdgeFuncP edgeFuncp,
V3GraphVertex* vertexp)
: GraphAlg<>(graphp, edgeFuncp)
, m_loopGraphp(loopGraphp) {
// Vertex::m_userp - New vertex if we have seen this vertex already
// Edge::m_userp - New edge if we have seen this edge already
m_graphp->userClearVertices();
m_graphp->userClearEdges();
(void) vertexIterateAll(vertexp);
(void)vertexIterateAll(vertexp);
}
~GraphAlgSubtrees() {}
};
//! Report the entire connected graph with a loop or loops
void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp,
V3Graph* loopGraphp) {
void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, V3Graph* loopGraphp) {
GraphAlgSubtrees(this, loopGraphp, edgeFuncp, vertexp);
}
@ -474,7 +455,7 @@ void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp,
// Algorithms - make non cutable
void V3Graph::makeEdgesNonCutable(V3EdgeFuncP edgeFuncp) {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
// Only need one direction, we'll always see the other at some point...
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
if (edgep->cutable() && edgep->weight() && (edgeFuncp)(edgep)) {
@ -489,12 +470,12 @@ void V3Graph::makeEdgesNonCutable(V3EdgeFuncP edgeFuncp) {
// Algorithms - sorting
struct GraphSortVertexCmp {
inline bool operator() (const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const {
inline bool operator()(const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const {
return lhsp->sortCmp(rhsp) < 0;
}
};
struct GraphSortEdgeCmp {
inline bool operator() (const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const {
inline bool operator()(const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const {
return lhsp->sortCmp(rhsp) < 0;
}
};
@ -502,12 +483,12 @@ struct GraphSortEdgeCmp {
void V3Graph::sortVertices() {
// Sort list of vertices by rank, then fanout
std::vector<V3GraphVertex*> vertices;
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
vertices.push_back(vertexp);
}
std::stable_sort(vertices.begin(), vertices.end(), GraphSortVertexCmp());
this->verticesUnlink();
for (std::vector<V3GraphVertex*>::iterator it = vertices.begin(); it!=vertices.end(); ++it) {
for (std::vector<V3GraphVertex*>::iterator it = vertices.begin(); it != vertices.end(); ++it) {
(*it)->verticesPushBack(this);
}
}
@ -515,7 +496,7 @@ void V3Graph::sortVertices() {
void V3Graph::sortEdges() {
// Sort edges by rank then fanout of node they point to
std::vector<V3GraphEdge*> edges;
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
// Make a vector
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
edges.push_back(edgep);
@ -527,7 +508,8 @@ void V3Graph::sortEdges() {
// We know the vector contains all of the edges that were
// there originally (didn't delete or add)
vertexp->outUnlink();
for (std::vector<V3GraphEdge*>::const_iterator it = edges.begin(); it!=edges.end(); ++it) {
for (std::vector<V3GraphEdge*>::const_iterator it = edges.begin(); it != edges.end();
++it) {
(*it)->outPushBack();
}
// Prep for next
@ -544,7 +526,7 @@ void V3Graph::sortEdges() {
// (Results in better dcache packing.)
void V3Graph::order() {
UINFO(2,"Order:\n");
UINFO(2, "Order:\n");
// Compute rankings again
rank(&V3GraphEdge::followAlwaysTrue);
@ -555,10 +537,8 @@ void V3Graph::orderPreRanked() {
// Compute fanouts
// Vertex::m_user begin: 1 indicates processing, 2 indicates completed
userClearVertices();
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
if (!vertexp->user()) {
orderDFSIterate(vertexp);
}
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
if (!vertexp->user()) orderDFSIterate(vertexp);
}
// Sort list of vertices by rank, then fanout. Fanout is a bit of a
@ -581,7 +561,7 @@ double V3Graph::orderDFSIterate(V3GraphVertex* vertexp) {
}
// Just count inbound edges
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
if (edgep->weight()) fanout ++;
if (edgep->weight()) ++fanout;
}
vertexp->fanout(fanout);
vertexp->user(2);

View File

@ -38,9 +38,7 @@ protected:
// Utilities
void dump() {
if (debug()>=9) {
m_graph.dumpDotFilePrefixed("v3graphtest_"+name());
}
if (debug() >= 9) m_graph.dumpDotFilePrefixed("v3graphtest_" + name());
}
public:
@ -56,9 +54,11 @@ public:
class V3GraphTestVertex : public V3GraphVertex {
string m_name;
public:
V3GraphTestVertex(V3Graph* graphp, const string& name)
: V3GraphVertex(graphp), m_name(name) {}
: V3GraphVertex(graphp)
, m_name(name) {}
virtual ~V3GraphTestVertex() {}
// ACCESSORS
virtual string name() const { return m_name; }
@ -84,13 +84,13 @@ public:
V3Graph* gp = &m_graph;
// Verify we break edges at a good point
// A simple alg would make 3 breaks, below only requires b->i to break
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*");
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a");
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b");
V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1");
V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2");
V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3");
V3GraphTestVertex* q = new V3GraphTestVarVertex(gp, "q");
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*");
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a");
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b");
V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1");
V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2");
V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3");
V3GraphTestVertex* q = new V3GraphTestVarVertex(gp, "q");
new V3GraphEdge(gp, i, a, 2, true);
new V3GraphEdge(gp, a, b, 2, true);
new V3GraphEdge(gp, b, g1, 2, true);
@ -106,11 +106,11 @@ public:
gp->stronglyConnected(&V3GraphEdge::followAlwaysTrue);
dump();
UASSERT(i->color()!=a->color() && a->color() != g2->color() && g2->color() != q->color(),
UASSERT(i->color() != a->color() && a->color() != g2->color() && g2->color() != q->color(),
"SelfTest: Separate colors not assigned");
UASSERT(a->color()==b->color() && a->color()==g1->color(),
UASSERT(a->color() == b->color() && a->color() == g1->color(),
"SelfTest: Strongly connected nodes not colored together");
UASSERT(g2->color()==g3->color(),
UASSERT(g2->color() == g3->color(),
"SelfTest: Strongly connected nodes not colored together");
}
};
@ -122,12 +122,12 @@ public:
V3Graph* gp = &m_graph;
// Verify we break edges at a good point
// A simple alg would make 3 breaks, below only requires b->i to break
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*");
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a");
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b");
V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1");
V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2");
V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3");
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*");
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a");
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b");
V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1");
V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2");
V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3");
new V3GraphEdge(gp, i, a, 2, true);
new V3GraphEdge(gp, a, b, 2, true);
new V3GraphEdge(gp, b, g1, 2, true);
@ -149,20 +149,20 @@ public:
virtual void runTest() {
V3Graph* gp = &m_graph;
V3GraphTestVertex* clk = new V3GraphTestVarVertex(gp, "$clk");
V3GraphTestVertex* clk = new V3GraphTestVarVertex(gp, "$clk");
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "$a");
V3GraphTestVertex* a_dly = new V3GraphTestVarVertex(gp, "$a_dly");
V3GraphTestVertex* a_dlyblk= new V3GraphTestVarVertex(gp, "$a_dlyblk");
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "$b");
V3GraphTestVertex* b_dly = new V3GraphTestVarVertex(gp, "$b_dly");
V3GraphTestVertex* b_dlyblk= new V3GraphTestVarVertex(gp, "$b_dlyblk");
V3GraphTestVertex* c = new V3GraphTestVarVertex(gp, "$c");
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "$i");
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "$a");
V3GraphTestVertex* a_dly = new V3GraphTestVarVertex(gp, "$a_dly");
V3GraphTestVertex* a_dlyblk = new V3GraphTestVarVertex(gp, "$a_dlyblk");
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "$b");
V3GraphTestVertex* b_dly = new V3GraphTestVarVertex(gp, "$b_dly");
V3GraphTestVertex* b_dlyblk = new V3GraphTestVarVertex(gp, "$b_dlyblk");
V3GraphTestVertex* c = new V3GraphTestVarVertex(gp, "$c");
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "$i");
V3GraphTestVertex* ap = new V3GraphTestVarVertex(gp, "$a_pre");
V3GraphTestVertex* bp = new V3GraphTestVarVertex(gp, "$b_pre");
V3GraphTestVertex* cp = new V3GraphTestVarVertex(gp, "$c_pre");
V3GraphTestVertex* ap = new V3GraphTestVarVertex(gp, "$a_pre");
V3GraphTestVertex* bp = new V3GraphTestVarVertex(gp, "$b_pre");
V3GraphTestVertex* cp = new V3GraphTestVarVertex(gp, "$c_pre");
V3GraphTestVertex* n;
@ -177,26 +177,27 @@ public:
// Desired order between different _DLY blocks so we can elim temporaries
// implemented by cutable "pre" signal dependencies
n = new V3GraphTestVertex(gp, "*INPUTS*"); {
n = new V3GraphTestVertex(gp, "*INPUTS*");
{
new V3GraphEdge(gp, n, clk, 2);
new V3GraphEdge(gp, n, i, 2);
}
V3GraphTestVertex* posedge = n = new V3GraphTestVertex(gp, "*posedge clk*"); {
new V3GraphEdge(gp, clk, n, 2);
}
V3GraphTestVertex* posedge = n = new V3GraphTestVertex(gp, "*posedge clk*");
{ new V3GraphEdge(gp, clk, n, 2); }
// AssignPre's VarRefs on LHS: generate special BLK
// normal: VarRefs on LHS: generate normal
// underSBlock: VarRefs on RHS: consume 'pre' (required to save cutable tests)
n = new V3GraphTestVertex(gp, "a_dly<PRE=a"); {
n = new V3GraphTestVertex(gp, "a_dly<PRE=a");
{
new V3GraphEdge(gp, n, a_dlyblk, 2); // Block ordering
new V3GraphEdge(gp, n, a_dly, 2);
new V3GraphEdge(gp, ap, n, 2, true); // DESIRED delayed ordering (inp is required)
new V3GraphEdge(gp, posedge, n, 2);
}
n = new V3GraphTestVertex(gp, "b_dly<PRE=b"); {
n = new V3GraphTestVertex(gp, "b_dly<PRE=b");
{
new V3GraphEdge(gp, n, b_dlyblk, 2); // Block ordering
new V3GraphEdge(gp, n, b_dly, 2);
new V3GraphEdge(gp, bp, n, 2, true); // DESIRED delayed ordering
@ -207,7 +208,8 @@ public:
// normal: VarRefs on LHS: generate normal
// underSBlock: VarRefs on RHS: generate 'pre' signals (cutable)
// SenItems: consume CLOCK dependency
n = new V3GraphTestVertex(gp, "a_dly<=b|c"); {
n = new V3GraphTestVertex(gp, "a_dly<=b|c");
{
new V3GraphEdge(gp, a_dlyblk, n, 2); // Block ordering in
new V3GraphEdge(gp, n, a_dly, 2);
// Note we don't include ap as we're generating a_dly
@ -215,7 +217,8 @@ public:
new V3GraphEdge(gp, n, cp, 2); // DESIRED delayed usage
new V3GraphEdge(gp, posedge, n, 2);
}
n = new V3GraphTestVertex(gp, "b_dly<=a"); {
n = new V3GraphTestVertex(gp, "b_dly<=a");
{
new V3GraphEdge(gp, b_dlyblk, n, 2); // Block ordering in
new V3GraphEdge(gp, n, b_dly, 2);
new V3GraphEdge(gp, n, ap, 2); // DESIRED delayed usage
@ -225,12 +228,14 @@ public:
// AssignPost's
// normal: VarRefs on LHS: generate normal
// underSBlock: VarRefs on RHS: consume normal
n = new V3GraphTestVertex(gp, "a=POST=a_dly"); {
n = new V3GraphTestVertex(gp, "a=POST=a_dly");
{
new V3GraphEdge(gp, n, a, 3);
new V3GraphEdge(gp, a_dly, n, 3);
new V3GraphEdge(gp, posedge, n, 2);
}
n = new V3GraphTestVertex(gp, "b=POST=b_dly"); {
n = new V3GraphTestVertex(gp, "b=POST=b_dly");
{
new V3GraphEdge(gp, n, b, 3);
new V3GraphEdge(gp, b_dly, n, 3);
new V3GraphEdge(gp, posedge, n, 2);
@ -258,9 +263,12 @@ public:
//======================================================================
class DfaTestVertex : public DfaVertex {
string m_name;
string m_name;
public:
DfaTestVertex(DfaGraph* graphp, const string& name) : DfaVertex(graphp), m_name(name) {}
DfaTestVertex(DfaGraph* graphp, const string& name)
: DfaVertex(graphp)
, m_name(name) {}
virtual ~DfaTestVertex() {}
// ACCESSORS
virtual string name() const { return m_name; }
@ -274,29 +282,31 @@ public:
DfaGraph* gp = &m_graph;
// NFA Pattern for ( (LR) | (L*R)) Z
DfaTestVertex* st = new DfaTestVertex(gp, "*START*"); st->start(true);
DfaTestVertex* sl = new DfaTestVertex(gp, "sL");
DfaTestVertex* srs = new DfaTestVertex(gp, "sR*");
DfaTestVertex* sls = new DfaTestVertex(gp, "sL*");
DfaTestVertex* sr = new DfaTestVertex(gp, "sR");
DfaTestVertex* sz = new DfaTestVertex(gp, "sZ");
DfaTestVertex* sac = new DfaTestVertex(gp, "*ACCEPT*"); sac->accepting(true);
DfaTestVertex* st = new DfaTestVertex(gp, "*START*");
st->start(true);
DfaTestVertex* sl = new DfaTestVertex(gp, "sL");
DfaTestVertex* srs = new DfaTestVertex(gp, "sR*");
DfaTestVertex* sls = new DfaTestVertex(gp, "sL*");
DfaTestVertex* sr = new DfaTestVertex(gp, "sR");
DfaTestVertex* sz = new DfaTestVertex(gp, "sZ");
DfaTestVertex* sac = new DfaTestVertex(gp, "*ACCEPT*");
sac->accepting(true);
VNUser L = VNUser::fromInt(0xaa);
VNUser R = VNUser::fromInt(0xbb);
VNUser Z = VNUser::fromInt(0xcc);
new DfaEdge(gp, st, sl, DfaEdge::EPSILON());
new DfaEdge(gp, sl, srs, L);
new DfaEdge(gp, st, sl, DfaEdge::EPSILON());
new DfaEdge(gp, sl, srs, L);
new DfaEdge(gp, srs, srs, R);
new DfaEdge(gp, srs, sz, Z);
new DfaEdge(gp, sz, sac, DfaEdge::EPSILON());
new DfaEdge(gp, srs, sz, Z);
new DfaEdge(gp, sz, sac, DfaEdge::EPSILON());
new DfaEdge(gp, st, sls, DfaEdge::EPSILON());
new DfaEdge(gp, st, sls, DfaEdge::EPSILON());
new DfaEdge(gp, sls, sls, L);
new DfaEdge(gp, sls, sr, R);
new DfaEdge(gp, sr, sz, Z);
new DfaEdge(gp, sz, sac, DfaEdge::EPSILON());
new DfaEdge(gp, sls, sr, R);
new DfaEdge(gp, sr, sz, Z);
new DfaEdge(gp, sz, sac, DfaEdge::EPSILON());
dump();
gp->nfaToDfa();
@ -335,18 +345,22 @@ public:
}
};
// clang-format off
#ifdef GRAPH_IMPORT
# include "graph_export.cpp"
#endif
// clang-format on
//======================================================================
void V3Graph::selfTest() {
// Execute all of the tests
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
// clang-format off
{ V3GraphTestStrong test; test.run(); }
{ V3GraphTestAcyc test; test.run(); }
{ V3GraphTestVars test; test.run(); }
{ V3GraphTestDfa test; test.run(); }
{ V3GraphTestImport test; test.run(); }
// clang-format on
}

View File

@ -43,11 +43,11 @@ private:
// NODE STATE
// Entire netlist:
// AstNodeStmt::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal)
//AstUser4InUse in V3Hashed.h
// AstUser4InUse in V3Hashed.h
// STATE
V3Hash m_lowerHash; // Hash of the statement we're building
bool m_cacheInUser4; // Use user4 to cache each V3Hash?
V3Hash m_lowerHash; // Hash of the statement we're building
bool m_cacheInUser4; // Use user4 to cache each V3Hash?
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -55,10 +55,12 @@ private:
void nodeHashIterate(AstNode* nodep) {
V3Hash thisHash;
if (!m_cacheInUser4 || !nodep->user4()) {
UASSERT_OBJ(!(VN_IS(nodep->backp(), CFunc)
&& !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))), nodep,
"Node "<<nodep->prettyTypeName()
<<" in statement position but not marked stmt (node under function)");
UASSERT_OBJ(
!(VN_IS(nodep->backp(), CFunc)
&& !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))),
nodep,
"Node " << nodep->prettyTypeName()
<< " in statement position but not marked stmt (node under function)");
V3Hash oldHash = m_lowerHash;
{
m_lowerHash = nodep->sameHash();
@ -66,20 +68,19 @@ private:
"sameHash function undefined (returns 0) for node under CFunc.");
// For identical nodes, the type should be the same thus
// dtypep should be the same too
m_lowerHash = V3Hash(m_lowerHash, V3Hash(nodep->type()<<6,
V3Hash(nodep->dtypep())));
m_lowerHash
= V3Hash(m_lowerHash, V3Hash(nodep->type() << 6, V3Hash(nodep->dtypep())));
// Now update m_lowerHash for our children's (and next children) contributions
iterateChildren(nodep);
// Store the hash value
nodep->user4(m_lowerHash.fullValue());
//UINFO(9, " hashnode "<<m_lowerHash<<" "<<nodep<<endl);
// UINFO(9, " hashnode "<<m_lowerHash<<" "<<nodep<<endl);
}
thisHash = m_lowerHash;
m_lowerHash = oldHash;
}
// Update what will become the above node's hash
m_lowerHash += m_cacheInUser4
? V3Hashed::nodeHash(nodep) : thisHash;
m_lowerHash += m_cacheInUser4 ? V3Hashed::nodeHash(nodep) : thisHash;
}
//--------------------
@ -120,10 +121,8 @@ V3Hashed::iterator V3Hashed::hashAndInsert(AstNode* nodep) {
}
void V3Hashed::hash(AstNode* nodep) {
UINFO(8," hashI "<<nodep<<endl);
if (!nodep->user4p()) {
HashedVisitor visitor (nodep);
}
UINFO(8, " hashI " << nodep << endl);
if (!nodep->user4p()) { HashedVisitor visitor(nodep); }
}
bool V3Hashed::sameNodes(AstNode* node1p, AstNode* node2p) {
@ -135,7 +134,7 @@ bool V3Hashed::sameNodes(AstNode* node1p, AstNode* node2p) {
void V3Hashed::erase(iterator it) {
AstNode* nodep = iteratorNodep(it);
UINFO(8," erase "<<nodep<<endl);
UINFO(8, " erase " << nodep << endl);
UASSERT_OBJ(nodep->user4p(), nodep, "Called removeNode on non-hashed node");
m_hashMmap.erase(it);
nodep->user4p(NULL); // So we don't allow removeNode again
@ -149,24 +148,22 @@ void V3Hashed::check() {
}
void V3Hashed::dumpFilePrefixed(const string& nameComment, bool tree) {
if (v3Global.opt.dumpTree()) {
dumpFile(v3Global.debugFilename(nameComment)+".hash", tree);
}
if (v3Global.opt.dumpTree()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree);
}
void V3Hashed::dumpFile(const string& filename, bool tree) {
const vl_unique_ptr<std::ofstream> logp (V3File::new_ofstream(filename));
if (logp->fail()) v3fatal("Can't write "<<filename);
const vl_unique_ptr<std::ofstream> logp(V3File::new_ofstream(filename));
if (logp->fail()) v3fatal("Can't write " << filename);
std::map<int,int> dist;
std::map<int, int> dist;
V3Hash lasthash;
int num_in_bucket = 0;
for (HashMmap::iterator it=begin(); 1; ++it) {
if (it==end() || lasthash != it->first) {
if (it!=end()) lasthash = it->first;
for (HashMmap::iterator it = begin(); 1; ++it) {
if (it == end() || lasthash != it->first) {
if (it != end()) lasthash = it->first;
if (num_in_bucket) {
if (dist.find(num_in_bucket)==dist.end()) {
if (dist.find(num_in_bucket) == dist.end()) {
dist.insert(make_pair(num_in_bucket, 1));
} else {
++dist[num_in_bucket];
@ -174,22 +171,23 @@ void V3Hashed::dumpFile(const string& filename, bool tree) {
}
num_in_bucket = 0;
}
if (it==end()) break;
if (it == end()) break;
num_in_bucket++;
}
*logp <<"\n*** STATS:\n"<<endl;
*logp<<" #InBucket Occurrences\n";
for (std::map<int,int>::iterator it=dist.begin(); it!=dist.end(); ++it) {
*logp<<" "<<std::setw(9)<<it->first<<" "<<std::setw(12)<<it->second<<endl;
*logp << "\n*** STATS:\n" << endl;
*logp << " #InBucket Occurrences\n";
for (std::map<int, int>::iterator it = dist.begin(); it != dist.end(); ++it) {
*logp << " " << std::setw(9) << it->first << " " << std::setw(12) << it->second
<< endl;
}
*logp <<"\n*** Dump:\n"<<endl;
for (HashMmap::iterator it=begin(); it!=end(); ++it) {
*logp << "\n*** Dump:\n" << endl;
for (HashMmap::iterator it = begin(); it != end(); ++it) {
if (lasthash != it->first) {
lasthash = it->first;
*logp <<" "<<it->first<<endl;
*logp << " " << it->first << endl;
}
*logp <<"\t"<<it->second<<endl;
*logp << "\t" << it->second << endl;
// Dumping the entire tree may make nearly N^2 sized dumps,
// because the nodes under this one may also be in the hash table!
if (tree) it->second->dumpTree(*logp, " ");
@ -197,14 +195,13 @@ void V3Hashed::dumpFile(const string& filename, bool tree) {
}
V3Hashed::iterator V3Hashed::findDuplicate(AstNode* nodep, V3HashedUserSame* checkp) {
UINFO(8," findD "<<nodep<<endl);
UINFO(8, " findD " << nodep << endl);
UASSERT_OBJ(nodep->user4p(), nodep, "Called findDuplicate on non-hashed node");
std::pair<HashMmap::iterator,HashMmap::iterator> eqrange
std::pair<HashMmap::iterator, HashMmap::iterator> eqrange
= mmap().equal_range(nodeHash(nodep));
for (HashMmap::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) {
AstNode* node2p = eqit->second;
if (nodep != node2p
&& (!checkp || checkp->isSame(nodep, node2p))
if (nodep != node2p && (!checkp || checkp->isSame(nodep, node2p))
&& sameNodes(nodep, node2p)) {
return eqit;
}

View File

@ -127,11 +127,10 @@ private:
}
virtual void visit(AstPragma* nodep) VL_OVERRIDE {
if (nodep->pragType() == AstPragmaType::INLINE_MODULE) {
// UINFO(0,"PRAG MARK "<<m_modp<<endl);
// UINFO(0, "PRAG MARK " << m_modp << endl);
if (!m_modp) {
nodep->v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE
} else if (m_modp->user2() == CIL_MAYBE
|| m_modp->user2() == CIL_NOTSOFT) {
} else if (m_modp->user2() == CIL_MAYBE || m_modp->user2() == CIL_NOTSOFT) {
m_modp->user2(CIL_USER);
}
// Remove so don't propagate to upper cell...
@ -199,14 +198,13 @@ private:
// If a mod*#refs is < this # nodes, can inline it
bool doit = ((allowed == CIL_USER)
|| ((allowed == CIL_MAYBE)
&& (refs == 1
|| statements < INLINE_MODS_SMALLER
&& (refs == 1 || statements < INLINE_MODS_SMALLER
|| v3Global.opt.inlineMult() < 1
|| refs * statements < v3Global.opt.inlineMult())));
// Packages aren't really "under" anything so they confuse this algorithm
if (VN_IS(modp, Package)) doit = false;
UINFO(4, " Inline=" << doit << " Possible=" << allowed << " Refs=" << refs
<< " Stmts=" << statements << " " << modp << endl);
<< " Stmts=" << statements << " " << modp << endl);
modp->user1(doit);
}
}
@ -247,9 +245,7 @@ private:
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstCell* nodep) VL_OVERRIDE {
nodep->user4p(nodep->clonep());
}
virtual void visit(AstCell* nodep) VL_OVERRIDE { nodep->user4p(nodep->clonep()); }
//--------------------
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
@ -328,36 +324,30 @@ private:
// remove the change detection on the output variable.
UINFO(9, "public pin assign: " << exprvarrefp << endl);
UASSERT_OBJ(!nodep->isNonOutput(), nodep, "Outputs only - inputs use AssignAlias");
m_modp->addStmtp(
new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false)));
m_modp->addStmtp(new AstAssignW(
nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false)));
} else if (nodep->isSigPublic() && VN_IS(nodep->dtypep(), UnpackArrayDType)) {
// Public variable at this end and it is an unpacked array. We need to assign
// instead of aliased, because otherwise it will pass V3Slice and invalid
// code will be emitted.
UINFO(9, "assign to public and unpacked: " << nodep << endl);
m_modp->addStmtp(
new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false)));
m_modp->addStmtp(new AstAssignW(
nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false)));
} else if (nodep->isIfaceRef()) {
m_modp->addStmtp(
new AstAssignVarScope(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(),
exprvarrefp->varp(), false)));
m_modp->addStmtp(new AstAssignVarScope(
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
AstNode* nodebp = exprvarrefp->varp();
nodep->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep->fileline());
} else {
// Do to inlining child's variable now within the same
// module, so a AstVarRef not AstVarXRef below
m_modp->addStmtp(
new AstAssignAlias(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(),
exprvarrefp->varp(), false)));
m_modp->addStmtp(new AstAssignAlias(
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
AstNode* nodebp = exprvarrefp->varp();
nodep->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep->fileline());
@ -406,7 +396,8 @@ private:
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (nodep->varp()->user2p() // It's being converted to an alias.
&& !nodep->varp()->user3()
&& !VN_IS(nodep->backp(), AssignAlias)) { // Don't constant propagate aliases (we just made)
// Don't constant propagate aliases (we just made)
&& !VN_IS(nodep->backp(), AssignAlias)) {
AstConst* exprconstp = VN_CAST(nodep->varp()->user2p(), Const);
AstVarRef* exprvarrefp = VN_CAST(nodep->varp()->user2p(), VarRef);
if (exprconstp) {
@ -551,10 +542,10 @@ private:
}
// Clone original module
if (debug() >= 9) { nodep->dumpTree(cout, "inlcell:"); }
// if (debug()>=9) { nodep->modp()->dumpTree(cout,"oldmod:"); }
if (debug() >= 9) nodep->dumpTree(cout, "inlcell:");
// if (debug() >= 9) nodep->modp()->dumpTree(cout, "oldmod:");
AstNodeModule* newmodp = nodep->modp()->cloneTree(false);
if (debug() >= 9) { newmodp->dumpTree(cout, "newmod:"); }
if (debug() >= 9) newmodp->dumpTree(cout, "newmod:");
// Clear var markings and find cell cross references
AstNode::user2ClearTree();
AstNode::user4ClearTree();
@ -575,8 +566,9 @@ private:
UASSERT_OBJ(pinNewVarp, pinOldVarp, "Cloning failed");
AstNode* connectRefp = pinp->exprp();
UASSERT_OBJ(VN_IS(connectRefp, Const) || VN_IS(connectRefp, VarRef), pinp,
"Unknown interconnect type; pinReconnectSimple should have cleared up");
UASSERT_OBJ(
VN_IS(connectRefp, Const) || VN_IS(connectRefp, VarRef), pinp,
"Unknown interconnect type; pinReconnectSimple should have cleared up");
V3Inst::checkOutputShort(pinp);
// Propagate any attributes across the interconnect
@ -624,7 +616,7 @@ public:
m_modp = NULL;
iterate(nodep);
}
virtual ~InlineVisitor() {
virtual ~InlineVisitor() { //
V3Stats::addStat("Optimizations, Inlined cells", m_statCells);
}
};
@ -668,8 +660,7 @@ private:
if (!irdtp) continue;
AstCell* cellp;
if ((cellp = VN_CAST(fromVarp->user1p(), Cell))
|| (cellp = irdtp->cellp())) {
if ((cellp = VN_CAST(fromVarp->user1p(), Cell)) || (cellp = irdtp->cellp())) {
varp->user1p(cellp);
string alias = m_scope + "__DOT__" + pinp->name();
cellp->addIntfRefp(new AstIntfRef(pinp->fileline(), alias));

View File

@ -41,19 +41,19 @@ private:
// NODE STATE
// Cleared each Cell:
// AstPin::user1p() -> bool. True if created assignment already
AstUser1InUse m_inuser1;
AstUser1InUse m_inuser1;
// STATE
AstCell* m_cellp; // Current cell
AstCell* m_cellp; // Current cell
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstCell* nodep) VL_OVERRIDE {
UINFO(4," CELL "<<nodep<<endl);
UINFO(4, " CELL " << nodep << endl);
m_cellp = nodep;
//VV***** We reset user1p() on each cell!!!
// VV***** We reset user1p() on each cell!!!
AstNode::user1ClearTree();
iterateChildren(nodep);
m_cellp = NULL;
@ -61,13 +61,13 @@ private:
virtual void visit(AstPin* nodep) VL_OVERRIDE {
// PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input)
// or ASSIGNW(expr,VARXREF(p)) (if sub's output)
UINFO(4," PIN "<<nodep<<endl);
UINFO(4, " PIN " << nodep << endl);
if (!nodep->user1()) {
// Simplify it
V3Inst::pinReconnectSimple(nodep, m_cellp, false);
}
if (!nodep->exprp()) return; // No-connect
if (debug()>=9) nodep->dumpTree(cout, " Pin_oldb: ");
if (debug() >= 9) nodep->dumpTree(cout, " Pin_oldb: ");
V3Inst::checkOutputShort(nodep);
// Use user1p on the PIN to indicate we created an assign for this pin
if (!nodep->user1SetOnce()) {
@ -78,27 +78,28 @@ private:
if (nodep->modVarp()->isInoutish()) {
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
} else if (nodep->modVarp()->isWritable()) {
AstNode* rhsp = new AstVarXRef(exprp->fileline(),
nodep->modVarp(), m_cellp->name(), false);
AstNode* rhsp
= new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
AstAssignW* assp = new AstAssignW(exprp->fileline(), exprp, rhsp);
m_cellp->addNextHere(assp);
} else if (nodep->modVarp()->isNonOutput()) {
// Don't bother moving constants now,
// we'll be pushing the const down to the cell soon enough.
AstNode* assp = new AstAssignW
(exprp->fileline(),
new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true),
exprp);
AstNode* assp = new AstAssignW(
exprp->fileline(),
new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true),
exprp);
m_cellp->addNextHere(assp);
if (debug()>=9) assp->dumpTree(cout, " _new: ");
if (debug() >= 9) assp->dumpTree(cout, " _new: ");
} else if (nodep->modVarp()->isIfaceRef()
|| (VN_IS(nodep->modVarp()->subDTypep(), UnpackArrayDType)
&& VN_IS(VN_CAST(nodep->modVarp()->subDTypep(),
UnpackArrayDType)->subDTypep(), IfaceRefDType))) {
&& VN_IS(VN_CAST(nodep->modVarp()->subDTypep(), UnpackArrayDType)
->subDTypep(),
IfaceRefDType))) {
// Create an AstAssignVarScope for Vars to Cells so we can
// link with their scope later
AstNode* lhsp = new AstVarXRef(exprp->fileline(),
nodep->modVarp(), m_cellp->name(), false);
AstNode* lhsp
= new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
const AstVarRef* refp = VN_CAST(exprp, VarRef);
const AstVarXRef* xrefp = VN_CAST(exprp, VarXRef);
UASSERT_OBJ(refp || xrefp, exprp,
@ -117,7 +118,8 @@ private:
virtual void visit(AstUdpTable* nodep) VL_OVERRIDE {
if (!v3Global.opt.bboxUnsup()) {
// If we support primitives, update V3Undriven to remove special case
nodep->v3error("Unsupported: Verilog 1995 UDP Tables. Use --bbox-unsup to ignore tables.");
nodep->v3error("Unsupported: Verilog 1995 UDP Tables. "
"Use --bbox-unsup to ignore tables.");
}
}
@ -145,15 +147,15 @@ class InstDeModVarVisitor : public AstNVisitor {
// Expand all module variables, and save names for later reference
private:
// STATE
typedef std::map<string,AstVar*> VarNameMap;
VarNameMap m_modVarNameMap; // Per module, name of cloned variables
typedef std::map<string, AstVar*> VarNameMap;
VarNameMap m_modVarNameMap; // Per module, name of cloned variables
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstVar* nodep) VL_OVERRIDE {
if (VN_IS(nodep->dtypep(), IfaceRefDType)) {
UINFO(8," dm-1-VAR "<<nodep<<endl);
UINFO(8, " dm-1-VAR " << nodep << endl);
insert(nodep);
}
iterateChildren(nodep);
@ -164,7 +166,7 @@ private:
public:
// METHODS
void insert(AstVar* nodep) {
UINFO(8," dmINSERT "<<nodep<<endl);
UINFO(8, " dmINSERT " << nodep << endl);
m_modVarNameMap.insert(make_pair(nodep->name(), nodep));
}
AstVar* find(const string& name) {
@ -176,15 +178,17 @@ public:
}
}
void dump() {
for (VarNameMap::iterator it=m_modVarNameMap.begin(); it!=m_modVarNameMap.end(); ++it) {
cout<<"-namemap: "<<it->first<<" -> "<<it->second<<endl;
for (VarNameMap::iterator it = m_modVarNameMap.begin(); it != m_modVarNameMap.end();
++it) {
cout << "-namemap: " << it->first << " -> " << it->second << endl;
}
}
public:
// CONSTRUCTORS
explicit InstDeModVarVisitor() {}
void main(AstNodeModule* nodep) {
UINFO(8," dmMODULE "<<nodep<<endl);
UINFO(8, " dmMODULE " << nodep << endl);
m_modVarNameMap.clear();
iterate(nodep);
}
@ -197,11 +201,11 @@ class InstDeVisitor : public AstNVisitor {
// Find all cells with arrays, and convert to non-arrayed
private:
// STATE
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
int m_instSelNum; // Current instantiation count 0..N-1
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
int m_instSelNum; // Current instantiation count 0..N-1
InstDeModVarVisitor m_deModVars; // State of variables for current cell module
typedef std::map<string,AstVar*> VarNameMap;
typedef std::map<string, AstVar*> VarNameMap;
VL_DEBUG_FUNC; // Declare debug()
@ -209,12 +213,12 @@ private:
virtual void visit(AstVar* nodep) VL_OVERRIDE {
if (VN_IS(nodep->dtypep(), UnpackArrayDType)
&& VN_IS(VN_CAST(nodep->dtypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) {
UINFO(8," dv-vec-VAR "<<nodep<<endl);
UINFO(8, " dv-vec-VAR " << nodep << endl);
AstUnpackArrayDType* arrdtype = VN_CAST(nodep->dtypep(), UnpackArrayDType);
AstNode* prevp = NULL;
for (int i = arrdtype->lsb(); i <= arrdtype->msb(); ++i) {
string varNewName = nodep->name() + "__BRA__" + cvtToStr(i) + "__KET__";
UINFO(8,"VAR name insert "<<varNewName<<" "<<nodep<<endl);
UINFO(8, "VAR name insert " << varNewName << " " << nodep << endl);
if (!m_deModVars.find(varNewName)) {
AstIfaceRefDType* ifaceRefp
= VN_CAST(arrdtype->subDTypep(), IfaceRefDType)->cloneTree(false);
@ -234,13 +238,16 @@ private:
}
}
if (prevp) nodep->addNextHere(prevp);
if (prevp && debug()==9) { prevp->dumpTree(cout, "newintf: "); cout << endl; }
if (prevp && debug() == 9) {
prevp->dumpTree(cout, "newintf: ");
cout << endl;
}
}
iterateChildren(nodep);
}
virtual void visit(AstCell* nodep) VL_OVERRIDE {
UINFO(4," CELL "<<nodep<<endl);
UINFO(4, " CELL " << nodep << endl);
// Find submodule vars
UASSERT_OBJ(nodep->modp(), nodep, "Unlinked");
m_deModVars.main(nodep->modp());
@ -249,14 +256,14 @@ private:
m_cellRangep = nodep->rangep();
AstVar* ifaceVarp = VN_CAST(nodep->nextp(), Var);
bool isIface = ifaceVarp
&& VN_IS(ifaceVarp->dtypep(), UnpackArrayDType)
&& VN_IS(VN_CAST(ifaceVarp->dtypep(),
UnpackArrayDType)->subDTypep(), IfaceRefDType);
bool isIface = ifaceVarp && VN_IS(ifaceVarp->dtypep(), UnpackArrayDType)
&& VN_IS(VN_CAST(ifaceVarp->dtypep(), UnpackArrayDType)->subDTypep(),
IfaceRefDType);
// Make all of the required clones
for (int i = 0; i < m_cellRangep->elementsConst(); i++) {
m_instSelNum = m_cellRangep->littleEndian() ? (m_cellRangep->elementsConst() - 1 - i) : i;
m_instSelNum
= m_cellRangep->littleEndian() ? (m_cellRangep->elementsConst() - 1 - i) : i;
int instNum = m_cellRangep->lsbConst() + i;
AstCell* newp = nodep->cloneTree(false);
@ -266,15 +273,16 @@ private:
// Somewhat illogically, we need to rename the original name of the cell too.
// as that is the name users expect for dotting
// The spec says we add [x], but that won't work in C...
newp->name(newp->name()+"__BRA__"+cvtToStr(instNum)+"__KET__");
newp->origName(newp->origName()+"__BRA__"+cvtToStr(instNum)+"__KET__");
UINFO(8," CELL loop "<<newp<<endl);
newp->name(newp->name() + "__BRA__" + cvtToStr(instNum) + "__KET__");
newp->origName(newp->origName() + "__BRA__" + cvtToStr(instNum) + "__KET__");
UINFO(8, " CELL loop " << newp << endl);
// If this AstCell is actually an interface instantiation, also clone the IfaceRef
// within the same parent module as the cell
if (isIface) {
AstUnpackArrayDType* arrdtype = VN_CAST(ifaceVarp->dtypep(), UnpackArrayDType);
AstIfaceRefDType* origIfaceRefp = VN_CAST(arrdtype->subDTypep(), IfaceRefDType);
AstIfaceRefDType* origIfaceRefp
= VN_CAST(arrdtype->subDTypep(), IfaceRefDType);
origIfaceRefp->cellp(NULL);
AstVar* varNewp = ifaceVarp->cloneTree(false);
AstIfaceRefDType* ifaceRefp
@ -283,14 +291,21 @@ private:
ifaceRefp->cellp(newp);
ifaceRefp->cellName(newp->name());
varNewp->name(varNewp->name() + "__BRA__" + cvtToStr(instNum) + "__KET__");
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(instNum) + "__KET__");
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(instNum)
+ "__KET__");
varNewp->dtypep(ifaceRefp);
newp->addNextHere(varNewp);
if (debug()==9) { varNewp->dumpTree(cout, "newintf: "); cout << endl; }
if (debug() == 9) {
varNewp->dumpTree(cout, "newintf: ");
cout << endl;
}
}
// Fixup pins
iterateAndNextNull(newp->pinsp());
if (debug()==9) { newp->dumpTree(cout, "newcell: "); cout<<endl; }
if (debug() == 9) {
newp->dumpTree(cout, "newcell: ");
cout << endl;
}
}
// Done. Delete original
@ -299,7 +314,8 @@ private:
ifaceVarp->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(ifaceVarp), ifaceVarp);
}
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else {
m_cellRangep = NULL;
iterateChildren(nodep);
@ -310,66 +326,66 @@ private:
// Any non-direct pins need reconnection with a part-select
if (!nodep->exprp()) return; // No-connect
if (m_cellRangep) {
UINFO(4," PIN "<<nodep<<endl);
UINFO(4, " PIN " << nodep << endl);
int pinwidth = nodep->modVarp()->width();
int expwidth = nodep->exprp()->width();
std::pair<uint32_t,uint32_t> pinDim = nodep->modVarp()->dtypep()->dimensions(false);
std::pair<uint32_t,uint32_t> expDim = nodep->exprp()->dtypep()->dimensions(false);
UINFO(4," PINVAR "<<nodep->modVarp()<<endl);
UINFO(4," EXP "<<nodep->exprp()<<endl);
UINFO(4," pinwidth ew="<<expwidth<<" pw="<<pinwidth
<<" ed="<<expDim.first<<","<<expDim.second
<<" pd="<<pinDim.first<<","<<pinDim.second<<endl);
if (expDim.first == pinDim.first && expDim.second == pinDim.second+1) {
std::pair<uint32_t, uint32_t> pinDim = nodep->modVarp()->dtypep()->dimensions(false);
std::pair<uint32_t, uint32_t> expDim = nodep->exprp()->dtypep()->dimensions(false);
UINFO(4, " PINVAR " << nodep->modVarp() << endl);
UINFO(4, " EXP " << nodep->exprp() << endl);
UINFO(4, " pinwidth ew=" << expwidth << " pw=" << pinwidth << " ed=" << expDim.first
<< "," << expDim.second << " pd=" << pinDim.first << ","
<< pinDim.second << endl);
if (expDim.first == pinDim.first && expDim.second == pinDim.second + 1) {
// Connection to array, where array dimensions match the instant dimension
AstRange* rangep = VN_CAST(nodep->exprp()->dtypep(), UnpackArrayDType)->rangep();
int arraySelNum = rangep->littleEndian()
? (rangep->elementsConst() - 1 - m_instSelNum) : m_instSelNum;
? (rangep->elementsConst() - 1 - m_instSelNum)
: m_instSelNum;
AstNode* exprp = nodep->exprp()->unlinkFrBack();
exprp = new AstArraySel(exprp->fileline(), exprp, arraySelNum);
nodep->exprp(exprp);
} else if (expwidth == pinwidth) {
// NOP: Arrayed instants: widths match so connect to each instance
} else if (expwidth == pinwidth*m_cellRangep->elementsConst()) {
} else if (expwidth == pinwidth * m_cellRangep->elementsConst()) {
// Arrayed instants: one bit for each of the instants (each
// assign is 1 pinwidth wide)
if (m_cellRangep->littleEndian()) {
nodep->exprp()->v3warn(
LITENDIAN,
"Little endian cell range connecting to vector: MSB < LSB of cell range: "
<<m_cellRangep->lsbConst()<<":"<<m_cellRangep->msbConst());
<< m_cellRangep->lsbConst() << ":" << m_cellRangep->msbConst());
}
AstNode* exprp = nodep->exprp()->unlinkFrBack();
bool inputPin = nodep->modVarp()->isNonOutput();
if (!inputPin && !VN_IS(exprp, VarRef)
&& !VN_IS(exprp, Concat) // V3Const will collapse the SEL with the one we're about to make
&& !VN_IS(exprp, Sel)) { // V3Const will collapse the SEL with the one we're about to make
nodep->v3error("Unsupported: Per-bit array instantiations with output connections to non-wires.");
if (!inputPin
&& !VN_IS(exprp, VarRef)
// V3Const will collapse the SEL with the one we're about to make
&& !VN_IS(exprp, Concat) && !VN_IS(exprp, Sel)) {
nodep->v3error("Unsupported: Per-bit array instantiations with output "
"connections to non-wires.");
// Note spec allows more complicated matches such as slices and such
}
exprp = new AstSel(exprp->fileline(), exprp,
pinwidth*m_instSelNum,
pinwidth);
exprp = new AstSel(exprp->fileline(), exprp, pinwidth * m_instSelNum, pinwidth);
nodep->exprp(exprp);
} else {
nodep->v3fatalSrc("Width mismatch; V3Width should have errored out.");
}
} else if (AstArraySel* arrselp = VN_CAST(nodep->exprp(), ArraySel)) {
if (AstUnpackArrayDType* arrp = VN_CAST(arrselp->lhsp()->dtypep(), UnpackArrayDType)) {
if (!VN_IS(arrp->subDTypep(), IfaceRefDType))
return;
if (!VN_IS(arrp->subDTypep(), IfaceRefDType)) return;
V3Const::constifyParamsEdit(arrselp->rhsp());
const AstConst* constp = VN_CAST(arrselp->rhsp(), Const);
if (!constp) {
nodep->v3error("Unsupported: Non-constant index when passing interface to module");
nodep->v3error(
"Unsupported: Non-constant index when passing interface to module");
return;
}
string index = AstNode::encodeNumber(constp->toSInt());
AstVarRef* varrefp = VN_CAST(arrselp->lhsp(), VarRef);
AstVarXRef* newp = new AstVarXRef(nodep->fileline(),
varrefp->name()+"__BRA__"+index+"__KET__",
"", true);
AstVarXRef* newp = new AstVarXRef(
nodep->fileline(), varrefp->name() + "__BRA__" + index + "__KET__", "", true);
newp->dtypep(nodep->modVarp()->dtypep());
newp->packagep(varrefp->packagep());
arrselp->addNextHere(newp);
@ -378,8 +394,7 @@ private:
} else {
AstVar* pinVarp = nodep->modVarp();
AstUnpackArrayDType* pinArrp = VN_CAST(pinVarp->dtypep(), UnpackArrayDType);
if (!pinArrp || !VN_IS(pinArrp->subDTypep(), IfaceRefDType))
return;
if (!pinArrp || !VN_IS(pinArrp->subDTypep(), IfaceRefDType)) return;
AstNode* prevp = NULL;
AstNode* prevPinp = NULL;
// Clone the var referenced by the pin, and clone each var referenced by the varref
@ -406,9 +421,9 @@ private:
}
}
if (!varNewp) {
if (debug()>=9) m_deModVars.dump();
if (debug() >= 9) m_deModVars.dump();
nodep->v3fatalSrc("Module dearray failed for "
<<AstNode::prettyNameQ(varNewName));
<< AstNode::prettyNameQ(varNewName));
}
// But clone the pin for each module instance
@ -464,21 +479,22 @@ private:
static AstNode* extendOrSel(FileLine* fl, AstNode* rhsp, AstNode* cmpWidthp) {
if (cmpWidthp->width() > rhsp->width()) {
rhsp = (rhsp->isSigned()
? static_cast<AstNode*>(new AstExtendS(fl, rhsp))
: static_cast<AstNode*>(new AstExtend (fl, rhsp)));
rhsp->dtypeFrom(cmpWidthp); // Need proper widthMin, which may differ from AstSel created above
rhsp = (rhsp->isSigned() ? static_cast<AstNode*>(new AstExtendS(fl, rhsp))
: static_cast<AstNode*>(new AstExtend(fl, rhsp)));
// Need proper widthMin, which may differ from AstSel created above
rhsp->dtypeFrom(cmpWidthp);
} else if (cmpWidthp->width() < rhsp->width()) {
rhsp = new AstSel(fl, rhsp, 0, cmpWidthp->width());
rhsp->dtypeFrom(cmpWidthp); // Need proper widthMin, which may differ from AstSel created above
// Need proper widthMin, which may differ from AstSel created above
rhsp->dtypeFrom(cmpWidthp);
}
// else don't change dtype, as might be e.g. array of something
return rhsp;
}
public:
static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp,
bool forTristate, bool alwaysCvt) {
static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate,
bool alwaysCvt) {
// If a pin connection is "simple" leave it as-is
// Else create a intermediate wire to perform the interconnect
// Return the new assignment, if one was made
@ -504,40 +520,33 @@ public:
AstAssignW* assignp = NULL;
if (connectRefp) connBasicp = VN_CAST(connectRefp->varp()->dtypep(), BasicDType);
//
if (!alwaysCvt
&& connectRefp
&& connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
if (!alwaysCvt && connectRefp && connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
&& !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types
// Done. Same data type
} else if (!alwaysCvt
&& connectRefp
&& connectRefp->varp()->isIfaceRef()) {
} else if (!alwaysCvt && connectRefp && connectRefp->varp()->isIfaceRef()) {
// Done. Interface
} else if (!alwaysCvt
&& connectXRefp
&& connectXRefp->varp()
} else if (!alwaysCvt && connectXRefp && connectXRefp->varp()
&& connectXRefp->varp()->isIfaceRef()) {
} else if (!alwaysCvt
&& connBasicp
&& pinBasicp
} else if (!alwaysCvt && connBasicp && pinBasicp
&& connBasicp->width() == pinBasicp->width()
&& connBasicp->lsb() == pinBasicp->lsb()
&& !connectRefp->varp()->isSc() // Need the signal as a 'shell' to convert types
&& !connectRefp->varp()
->isSc() // Need the signal as a 'shell' to convert types
&& connBasicp->width() == pinVarp->width()) {
// Done. One to one interconnect won't need a temporary variable.
} else if (!alwaysCvt && !forTristate && VN_IS(pinp->exprp(), Const)) {
// Done. Constant.
} else {
// Make a new temp wire
//if (1||debug()>=9) { pinp->dumpTree(cout, "-in_pin:"); }
// if (1 || debug() >= 9) { pinp->dumpTree(cout, "-in_pin:"); }
V3Inst::checkOutputShort(pinp);
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
string newvarname = (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
// Prevent name conflict if both tri & non-tri add signals
+(forTristate?"t":"")
+"__"+cellp->name()+"__"+pinp->name());
AstVar* newvarp = new AstVar(pinVarp->fileline(),
AstVarType::MODULETEMP, newvarname, pinVarp);
string newvarname
= (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
// Prevent name conflict if both tri & non-tri add signals
+ (forTristate ? "t" : "") + "__" + cellp->name() + "__" + pinp->name());
AstVar* newvarp
= new AstVar(pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
// Important to add statement next to cell, in case there is a
// generate with same named cell
cellp->addNextHere(newvarp);
@ -547,8 +556,8 @@ public:
} else if (pinVarp->isWritable()) {
// See also V3Inst
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
UINFO(5,"pinRecon width "<<pinVarp->width()<<" >? "
<<rhsp->width()<<" >? "<<pinexprp->width()<<endl);
UINFO(5, "pinRecon width " << pinVarp->width() << " >? " << rhsp->width() << " >? "
<< pinexprp->width() << endl);
rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp);
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, true));
AstNode* rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp);
@ -556,13 +565,12 @@ public:
} else {
// V3 width should have range/extended to make the widths correct
assignp = new AstAssignW(pinp->fileline(),
new AstVarRef(pinp->fileline(), newvarp, true),
pinexprp);
new AstVarRef(pinp->fileline(), newvarp, true), pinexprp);
pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, false));
}
if (assignp) cellp->addNextHere(assignp);
//if (debug()) { pinp->dumpTree(cout, "- out:"); }
//if (debug()) { assignp->dumpTree(cout, "- aout:"); }
// if (debug()) { pinp->dumpTree(cout, "- out:"); }
// if (debug()) { assignp->dumpTree(cout, "- aout:"); }
}
return assignp;
}
@ -571,20 +579,19 @@ public:
//######################################################################
// Inst class functions
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp,
bool forTristate, bool alwaysCvt) {
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate,
bool alwaysCvt) {
return InstStatic::pinReconnectSimple(pinp, cellp, forTristate, alwaysCvt);
}
void V3Inst::checkOutputShort(AstPin* nodep) {
if (nodep->modVarp()->direction() == VDirection::OUTPUT) {
if (VN_IS(nodep->exprp(), Const)
|| VN_IS(nodep->exprp(), Extend)
if (VN_IS(nodep->exprp(), Const) || VN_IS(nodep->exprp(), Extend)
|| (VN_IS(nodep->exprp(), Concat)
&& (VN_IS(VN_CAST(nodep->exprp(), Concat)->lhsp(), Const)))) {
// Uses v3warn for error, as might be found multiple times
nodep->v3warn(E_PORTSHORT, "Output port is connected to a constant pin,"
" electrical short");
" electrical short");
}
}
}
@ -593,17 +600,13 @@ void V3Inst::checkOutputShort(AstPin* nodep) {
// Inst class visitor
void V3Inst::instAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
InstVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ InstVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("inst", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Inst::dearrayAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
InstDeVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ InstDeVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("dearray", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}

View File

@ -42,7 +42,7 @@
class LifeState {
// NODE STATE
// See below
AstUser1InUse m_inuser1;
AstUser1InUse m_inuser1;
// STATE
public:
@ -56,8 +56,8 @@ public:
~LifeState() {
V3Stats::addStatSum("Optimizations, Lifetime assign deletions", m_statAssnDel);
V3Stats::addStatSum("Optimizations, Lifetime constant prop", m_statAssnCon);
for (std::vector<AstNode*>::iterator it = m_unlinkps.begin();
it != m_unlinkps.end(); ++it) {
for (std::vector<AstNode*>::iterator it = m_unlinkps.begin(); it != m_unlinkps.end();
++it) {
(*it)->unlinkFrBack();
(*it)->deleteTree();
}
@ -70,10 +70,12 @@ public:
// Structure for each variable encountered
class LifeVarEntry {
AstNodeAssign* m_assignp; // Last assignment to this varscope, NULL if no longer relevant
AstConst* m_constp; // Known constant value
bool m_setBeforeUse; // First access was a set (and thus block above may have a set that can be deleted
bool m_everSet; // Was ever assigned (and thus above block may not preserve constant propagation)
AstNodeAssign* m_assignp; // Last assignment to this varscope, NULL if no longer relevant
AstConst* m_constp; // Known constant value
// First access was a set (and thus block above may have a set that can be deleted
bool m_setBeforeUse;
// Was ever assigned (and thus above block may not preserve constant propagation)
bool m_everSet;
inline void init(bool setBeforeUse) {
m_assignp = NULL;
@ -81,19 +83,23 @@ class LifeVarEntry {
m_setBeforeUse = setBeforeUse;
m_everSet = false;
}
public:
class SIMPLEASSIGN {};
class COMPLEXASSIGN {};
class CONSUMED {};
LifeVarEntry(SIMPLEASSIGN, AstNodeAssign* assp) {
init(true); simpleAssign(assp);
init(true);
simpleAssign(assp);
}
explicit LifeVarEntry(COMPLEXASSIGN) {
init(false); complexAssign();
init(false);
complexAssign();
}
explicit LifeVarEntry(CONSUMED) {
init(false); consumed();
init(false);
consumed();
}
~LifeVarEntry() {}
inline void simpleAssign(AstNodeAssign* assp) { // New simple A=.... assignment
@ -127,9 +133,9 @@ class LifeBlock {
// LIFE MAP
// For each basic block, we'll make a new map of what variables that if/else is changing
typedef std::map<AstVarScope*, LifeVarEntry> LifeMap;
LifeMap m_map; // Current active lifetime map for current scope
LifeBlock* m_aboveLifep; // Upper life, or NULL
LifeState* m_statep; // Current global state
LifeMap m_map; // Current active lifetime map for current scope
LifeBlock* m_aboveLifep; // Upper life, or NULL
LifeState* m_statep; // Current global state
VL_DEBUG_FUNC; // Declare debug()
@ -148,11 +154,11 @@ public:
// we just don't optimize any public sigs
// Check the var entry, and remove if appropriate
if (AstNode* oldassp = entp->assignp()) {
UINFO(7," PREV: "<<oldassp<<endl);
UINFO(7, " PREV: " << oldassp << endl);
// Redundant assignment, in same level block
// Don't delete it now as it will confuse iteration since it maybe WAY
// above our current iteration point.
if (debug()>4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK ");
if (debug() > 4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK ");
entp->complexAssign();
VL_DO_DANGLING(m_statep->pushUnlinkDeletep(oldassp), oldassp);
++m_statep->m_statAssnDel;
@ -161,8 +167,8 @@ public:
}
void simpleAssign(AstVarScope* nodep, AstNodeAssign* assp) {
// Do we have a old assignment we can nuke?
UINFO(4," ASSIGNof: "<<nodep<<endl);
UINFO(7," new: "<<assp<<endl);
UINFO(4, " ASSIGNof: " << nodep << endl);
UINFO(7, " new: " << assp << endl);
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
checkRemoveAssign(it);
@ -170,10 +176,10 @@ public:
} else {
m_map.insert(make_pair(nodep, LifeVarEntry(LifeVarEntry::SIMPLEASSIGN(), assp)));
}
//lifeDump();
// lifeDump();
}
void complexAssign(AstVarScope* nodep) {
UINFO(4," clearof: "<<nodep<<endl);
UINFO(4, " clearof: " << nodep << endl);
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
it->second.complexAssign();
@ -189,14 +195,14 @@ public:
if (!varrefp->varp()->isSigPublic()) {
// Aha, variable is constant; substitute in.
// We'll later constant propagate
UINFO(4," replaceconst: "<<varrefp<<endl);
UINFO(4, " replaceconst: " << varrefp << endl);
varrefp->replaceWith(constp->cloneTree(false));
VL_DO_DANGLING(varrefp->deleteTree(), varrefp);
++m_statep->m_statAssnCon;
return; // **DONE, no longer a var reference**
}
}
UINFO(4," usage: "<<nodep<<endl);
UINFO(4, " usage: " << nodep << endl);
it->second.consumed();
} else {
m_map.insert(make_pair(nodep, LifeVarEntry(LifeVarEntry::CONSUMED())));
@ -205,7 +211,7 @@ public:
void complexAssignFind(AstVarScope* nodep) {
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
UINFO(4," casfind: "<<it->first<<endl);
UINFO(4, " casfind: " << it->first << endl);
it->second.complexAssign();
} else {
m_map.insert(make_pair(nodep, LifeVarEntry(LifeVarEntry::COMPLEXASSIGN())));
@ -222,7 +228,7 @@ public:
void lifeToAbove() {
// Any varrefs under a if/else branch affect statements outside and after the if/else
if (!m_aboveLifep) v3fatalSrc("Pushing life when already at the top level");
for (LifeMap::iterator it = m_map.begin(); it!=m_map.end(); ++it) {
for (LifeMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
AstVarScope* nodep = it->first;
m_aboveLifep->complexAssignFind(nodep);
if (it->second.everSet()) {
@ -236,36 +242,33 @@ public:
}
void dualBranch(LifeBlock* life1p, LifeBlock* life2p) {
// Find any common sets on both branches of IF and propagate upwards
//life1p->lifeDump();
//life2p->lifeDump();
// life1p->lifeDump();
// life2p->lifeDump();
AstNode::user1ClearTree(); // user1p() used on entire tree
for (LifeMap::iterator it = life1p->m_map.begin(); it!=life1p->m_map.end(); ++it) {
for (LifeMap::iterator it = life1p->m_map.begin(); it != life1p->m_map.end(); ++it) {
// When the if branch sets a var before it's used, mark that variable
if (it->second.setBeforeUse()) it->first->user1(1);
}
for (LifeMap::iterator it = life2p->m_map.begin(); it!=life2p->m_map.end(); ++it) {
for (LifeMap::iterator it = life2p->m_map.begin(); it != life2p->m_map.end(); ++it) {
// When the else branch sets a var before it's used
AstVarScope* nodep = it->first;
if (it->second.setBeforeUse() && nodep->user1()) {
// Both branches set the var, we can remove the assignment before the IF.
UINFO(4,"DUALBRANCH "<<nodep<<endl);
UINFO(4, "DUALBRANCH " << nodep << endl);
LifeMap::iterator itab = m_map.find(nodep);
if (itab != m_map.end()) {
checkRemoveAssign(itab);
}
if (itab != m_map.end()) checkRemoveAssign(itab);
}
}
//this->lifeDump();
// this->lifeDump();
}
// DEBUG
void lifeDump() {
UINFO(5, " LifeMap:"<<endl);
for (LifeMap::iterator it = m_map.begin(); it!=m_map.end(); ++it) {
UINFO(5, " Ent: "
<<(it->second.setBeforeUse()?"[F] ":" ")
<<it->first<<endl);
if (it->second.assignp()) {
UINFO(5, " Ass: "<<it->second.assignp()<<endl);
UINFO(5, " LifeMap:" << endl);
for (LifeMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
UINFO(5, " Ent: " << (it->second.setBeforeUse() ? "[F] " : " ") << it->first
<< endl);
if (it->second.assignp()) { //
UINFO(5, " Ass: " << it->second.assignp() << endl);
}
}
}
@ -277,16 +280,16 @@ public:
class LifeVisitor : public AstNVisitor {
private:
// STATE
LifeState* m_statep; // Current state
bool m_sideEffect; // Side effects discovered in assign RHS
bool m_noopt; // Disable optimization of variables in this block
bool m_tracingCall; // Iterating into a CCall to a CFunc
LifeState* m_statep; // Current state
bool m_sideEffect; // Side effects discovered in assign RHS
bool m_noopt; // Disable optimization of variables in this block
bool m_tracingCall; // Iterating into a CCall to a CFunc
// LIFE MAP
// For each basic block, we'll make a new map of what variables that if/else is changing
typedef std::map<AstVarScope*, LifeVarEntry> LifeMap;
// cppcheck-suppress memleak // cppcheck bug - it is deleted
LifeBlock* m_lifep; // Current active lifetime map for current scope
LifeBlock* m_lifep; // Current active lifetime map for current scope
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -333,11 +336,11 @@ private:
//---- Track control flow changes
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
UINFO(4," IF "<<nodep<<endl);
UINFO(4, " IF " << nodep << endl);
// Condition is part of PREVIOUS block
iterateAndNextNull(nodep->condp());
LifeBlock* prevLifep = m_lifep;
LifeBlock* ifLifep = new LifeBlock(prevLifep, m_statep);
LifeBlock* ifLifep = new LifeBlock(prevLifep, m_statep);
LifeBlock* elseLifep = new LifeBlock(prevLifep, m_statep);
{
m_lifep = ifLifep;
@ -348,7 +351,7 @@ private:
iterateAndNextNull(nodep->elsesp());
}
m_lifep = prevLifep;
UINFO(4," join "<<endl);
UINFO(4, " join " << endl);
// Find sets on both flows
m_lifep->dualBranch(ifLifep, elseLifep);
// For the next assignments, clear any variables that were read or written in the block
@ -380,7 +383,7 @@ private:
iterateAndNextNull(nodep->incsp());
}
m_lifep = prevLifep;
UINFO(4," joinfor"<<endl);
UINFO(4, " joinfor" << endl);
// For the next assignments, clear any variables that were read or written in the block
condLifep->lifeToAbove();
bodyLifep->lifeToAbove();
@ -401,22 +404,23 @@ private:
m_lifep = prevLifep;
m_noopt = prev_noopt;
}
UINFO(4," joinjump"<<endl);
UINFO(4, " joinjump" << endl);
// For the next assignments, clear any variables that were read or written in the block
bodyLifep->lifeToAbove();
VL_DO_DANGLING(delete bodyLifep, bodyLifep);
}
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
//UINFO(4," CCALL "<<nodep<<endl);
// UINFO(4, " CCALL " << nodep << endl);
iterateChildren(nodep);
// Enter the function and trace it
if (!nodep->funcp()->entryPoint()) { // else is non-inline or public function we optimize separately
// else is non-inline or public function we optimize separately
if (!nodep->funcp()->entryPoint()) {
m_tracingCall = true;
iterate(nodep->funcp());
}
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
//UINFO(4," CFUNC "<<nodep<<endl);
// UINFO(4, " CFUNC " << nodep << endl);
if (!m_tracingCall && !nodep->entryPoint()) return;
m_tracingCall = false;
if (nodep->dpiImport() && !nodep->pure()) {
@ -439,7 +443,7 @@ private:
public:
// CONSTRUCTORS
LifeVisitor(AstNode* nodep, LifeState* statep) {
UINFO(4," LifeVisitor on "<<nodep<<endl);
UINFO(4, " LifeVisitor on " << nodep << endl);
m_statep = statep;
m_sideEffect = false;
m_noopt = false;
@ -463,26 +467,26 @@ class LifeTopVisitor : public AstNVisitor {
// finding code within.
private:
// STATE
LifeState* m_statep; // Current state
LifeState* m_statep; // Current state
// VISITORS
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
if (nodep->entryPoint()) {
// Usage model 1: Simulate all C code, doing lifetime analysis
LifeVisitor visitor (nodep, m_statep);
LifeVisitor visitor(nodep, m_statep);
}
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
// Usage model 2: Cleanup basic blocks
LifeVisitor visitor (nodep, m_statep);
LifeVisitor visitor(nodep, m_statep);
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
// Usage model 2: Cleanup basic blocks
LifeVisitor visitor (nodep, m_statep);
LifeVisitor visitor(nodep, m_statep);
}
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
// Usage model 2: Cleanup basic blocks
LifeVisitor visitor (nodep, m_statep);
LifeVisitor visitor(nodep, m_statep);
}
virtual void visit(AstVar*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
@ -502,10 +506,10 @@ public:
// Life class functions
void V3Life::lifeAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
{
LifeState state;
LifeTopVisitor visitor (nodep, &state);
LifeTopVisitor visitor(nodep, &state);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("life", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -43,7 +43,7 @@
class LifePostElimVisitor : public AstNVisitor {
private:
bool m_tracingCall; // Iterating into a CCall to a CFunc
bool m_tracingCall; // Iterating into a CCall to a CFunc
// NODE STATE
// INPUT:
@ -58,7 +58,7 @@ private:
AstVarScope* vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
if (AstVarScope* newvscp = reinterpret_cast<AstVarScope*>(vscp->user4p())) {
UINFO(9, " Replace "<<nodep<<" to "<<newvscp<<endl);
UINFO(9, " Replace " << nodep << " to " << newvscp << endl);
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
nodep->replaceWith(newrefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
@ -105,11 +105,15 @@ public:
struct LifeLocation {
const ExecMTask* mtaskp;
uint32_t sequence;
public:
LifeLocation() : mtaskp(NULL), sequence(0) {}
LifeLocation()
: mtaskp(NULL)
, sequence(0) {}
LifeLocation(const ExecMTask* mtaskp_, uint32_t sequence_)
: mtaskp(mtaskp_), sequence(sequence_) {}
bool operator< (const LifeLocation& b) const {
: mtaskp(mtaskp_)
, sequence(sequence_) {}
bool operator<(const LifeLocation& b) const {
unsigned a_id = mtaskp ? mtaskp->id() : 0;
unsigned b_id = b.mtaskp ? b.mtaskp->id() : 0;
if (a_id < b_id) { return true; }
@ -121,9 +125,11 @@ public:
struct LifePostLocation {
LifeLocation loc;
AstAssignPost* nodep;
LifePostLocation() : nodep(NULL) {}
LifePostLocation()
: nodep(NULL) {}
LifePostLocation(LifeLocation loc_, AstAssignPost* nodep_)
: loc(loc_), nodep(nodep_) {}
: loc(loc_)
, nodep(nodep_) {}
};
//######################################################################
@ -134,27 +140,27 @@ private:
// NODE STATE
// Cleared on entire tree
// AstVarScope::user4() -> AstVarScope*: Passed to LifePostElim to substitute this var
AstUser4InUse m_inuser4;
AstUser4InUse m_inuser4;
// STATE
uint32_t m_sequence; // Sequence number of assigns/varrefs,
uint32_t m_sequence; // Sequence number of assigns/varrefs,
// // local to the current MTask.
const ExecMTask* m_execMTaskp; // Current ExecMTask being processed,
const ExecMTask* m_execMTaskp; // Current ExecMTask being processed,
// // or NULL for serial code.
VDouble0 m_statAssnDel; // Statistic tracking
bool m_tracingCall; // Currently tracing a CCall to a CFunc
VDouble0 m_statAssnDel; // Statistic tracking
bool m_tracingCall; // Currently tracing a CCall to a CFunc
// Map each varscope to one or more locations where it's accessed.
// These maps will not include any ASSIGNPOST accesses:
typedef vl_unordered_map<const AstVarScope*, std::set<LifeLocation> > LocMap;
LocMap m_reads; // VarScope read locations
LocMap m_writes; // VarScope write locations
LocMap m_reads; // VarScope read locations
LocMap m_writes; // VarScope write locations
// Map each dly var to its AstAssignPost* node and the location thereof
typedef vl_unordered_map<const AstVarScope*, LifePostLocation> PostLocMap;
PostLocMap m_assignposts; // AssignPost dly var locations
PostLocMap m_assignposts; // AssignPost dly var locations
const V3Graph* m_mtasksGraphp; // Mtask tracking graph
const V3Graph* m_mtasksGraphp; // Mtask tracking graph
vl_unique_ptr<GraphPathChecker> m_checker;
// METHODS
@ -164,8 +170,7 @@ private:
if (a.mtaskp == b.mtaskp) return a.sequence < b.sequence;
return m_checker->pathExistsFrom(a.mtaskp, b.mtaskp);
}
bool outsideCriticalArea(LifeLocation loc,
const std::set<LifeLocation>& dlyVarAssigns,
bool outsideCriticalArea(LifeLocation loc, const std::set<LifeLocation>& dlyVarAssigns,
LifeLocation assignPostLoc) {
// If loc is before all of dlyVarAssigns, return true.
// ("Before" means certain to be ordered before them at execution time.)
@ -189,8 +194,7 @@ private:
return true;
}
void squashAssignposts() {
for (PostLocMap::iterator it = m_assignposts.begin();
it != m_assignposts.end(); ++it) {
for (PostLocMap::iterator it = m_assignposts.begin(); it != m_assignposts.end(); ++it) {
LifePostLocation* app = &it->second;
AstVarRef* lhsp = VN_CAST(app->nodep->lhsp(), VarRef); // original var
AstVarRef* rhsp = VN_CAST(app->nodep->rhsp(), VarRef); // dly var
@ -246,7 +250,7 @@ private:
if (!canScrunch) continue;
// Delete and mark so LifePostElimVisitor will get it
UINFO(4," DELETE "<<app->nodep<<endl);
UINFO(4, " DELETE " << app->nodep << endl);
dlyVarp->user4p(origVarp);
VL_DO_DANGLING(app->nodep->unlinkFrBack()->deleteTree(), app->nodep);
++m_statAssnDel;
@ -262,8 +266,7 @@ private:
iterateChildren(nodep);
if (v3Global.opt.mtasks()) {
UASSERT_OBJ(m_mtasksGraphp, nodep,
"Should have initted m_mtasksGraphp by now");
UASSERT_OBJ(m_mtasksGraphp, nodep, "Should have initted m_mtasksGraphp by now");
m_checker.reset(new GraphPathChecker(m_mtasksGraphp));
} else {
UASSERT_OBJ(!m_mtasksGraphp, nodep,
@ -277,7 +280,7 @@ private:
squashAssignposts();
// Replace any node4p varscopes with the new scope
LifePostElimVisitor visitor (nodep);
LifePostElimVisitor visitor(nodep);
}
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
// Consumption/generation of a variable,
@ -325,8 +328,8 @@ private:
virtual void visit(AstExecGraph* nodep) VL_OVERRIDE {
// Treat the ExecGraph like a call to each mtask body
m_mtasksGraphp = nodep->depGraphp();
for (V3GraphVertex* mtaskVxp = m_mtasksGraphp->verticesBeginp();
mtaskVxp; mtaskVxp = mtaskVxp->verticesNextp()) {
for (V3GraphVertex* mtaskVxp = m_mtasksGraphp->verticesBeginp(); mtaskVxp;
mtaskVxp = mtaskVxp->verticesNextp()) {
ExecMTask* mtaskp = dynamic_cast<ExecMTask*>(mtaskVxp);
m_execMTaskp = mtaskp;
m_sequence = 0;
@ -361,10 +364,8 @@ public:
// LifePost class functions
void V3LifePost::lifepostAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
// Mark redundant AssignPost
{
LifePostDlyVisitor visitor(nodep);
} // Destruct before checking
{ LifePostDlyVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("life_post", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -51,16 +51,18 @@ public:
class LinkCellsVertex : public V3GraphVertex {
AstNodeModule* m_modp;
public:
LinkCellsVertex(V3Graph* graphp, AstNodeModule* modp)
: V3GraphVertex(graphp), m_modp(modp) {}
: V3GraphVertex(graphp)
, m_modp(modp) {}
virtual ~LinkCellsVertex() {}
AstNodeModule* modp() const { return m_modp; }
virtual string name() const { return modp()->name(); }
virtual FileLine* fileline() const { return modp()->fileline(); }
// Recursive modules get space for maximum recursion
virtual uint32_t rankAdder() const {
return m_modp->recursiveClone() ? (1+v3Global.opt.moduleRecursionDepth()) : 1;
return m_modp->recursiveClone() ? (1 + v3Global.opt.moduleRecursionDepth()) : 1;
}
};
@ -74,10 +76,12 @@ public:
void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) {
if (LinkCellsVertex* vvertexp = dynamic_cast<LinkCellsVertex*>(vertexp)) {
vvertexp->modp()->v3error("Unsupported: Recursive multiple modules (module instantiates something leading back to itself): "
<<vvertexp->modp()->prettyNameQ()<<endl
<<V3Error::warnMore()
<<"... note: self-recursion (module instantiating itself directly) is supported.");
vvertexp->modp()->v3error(
"Unsupported: Recursive multiple modules (module instantiates "
"something leading back to itself): "
<< vvertexp->modp()->prettyNameQ() << endl
<< V3Error::warnMore()
<< "... note: self-recursion (module instantiating itself directly) is supported.");
V3Error::abortIfErrors();
} else { // Everything should match above, but...
v3fatalSrc("Recursive instantiations");
@ -97,19 +101,19 @@ private:
// AstCell::user2() // bool clone renaming completed
// Allocated across all readFiles in V3Global::readFiles:
// AstNode::user4p() // VSymEnt* Package and typedef symbol names
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
// STATE
VInFilter* m_filterp; // Parser filter
V3ParseSym* m_parseSymp; // Parser symbol table
VInFilter* m_filterp; // Parser filter
V3ParseSym* m_parseSymp; // Parser symbol table
// Below state needs to be preserved between each module call.
AstNodeModule* m_modp; // Current module
VSymGraph m_mods; // Symbol table of all module names
LinkCellsGraph m_graph; // Linked graph of all cell interconnects
LibraryVertex* m_libVertexp; // Vertex at root of all libraries
V3GraphVertex* m_topVertexp; // Vertex of top module
AstNodeModule* m_modp; // Current module
VSymGraph m_mods; // Symbol table of all module names
LinkCellsGraph m_graph; // Linked graph of all cell interconnects
LibraryVertex* m_libVertexp; // Vertex at root of all libraries
V3GraphVertex* m_topVertexp; // Vertex of top module
vl_unordered_set<string> m_declfnWarned; // Files we issued DECLFILENAME on
VL_DEBUG_FUNC; // Declare debug()
@ -117,16 +121,17 @@ private:
// METHODS
V3GraphVertex* vertex(AstNodeModule* nodep) {
// Return corresponding vertex for this module
if (!nodep->user1p()) {
nodep->user1p(new LinkCellsVertex(&m_graph, nodep));
}
if (!nodep->user1p()) nodep->user1p(new LinkCellsVertex(&m_graph, nodep));
return (nodep->user1u().toGraphVertex());
}
AstNodeModule* findModuleSym(const string& modName) {
VSymEnt* foundp = m_mods.rootp()->findIdFallback(modName);
if (!foundp) return NULL;
else return VN_CAST(foundp->nodep(), NodeModule);
if (!foundp) {
return NULL;
} else {
return VN_CAST(foundp->nodep(), NodeModule);
}
}
AstNodeModule* resolveModule(AstNode* nodep, const string& modName) {
@ -136,7 +141,7 @@ private:
// If file not found, make AstNotFoundModule, rather than error out.
// We'll throw the error when we know the module will really be needed.
string prettyName = AstNode::prettyName(modName);
V3Parse parser (v3Global.rootp(), m_filterp, m_parseSymp);
V3Parse parser(v3Global.rootp(), m_filterp, m_parseSymp);
// true below -> other simulators treat modules in link-found files as library cells
parser.parseFile(nodep->fileline(), prettyName, true, "");
V3Error::abortIfErrors();
@ -147,7 +152,7 @@ private:
if (!modp) {
// This shouldn't throw a message as parseFile will create
// a AstNotFoundModule for us
nodep->v3error("Can't resolve module reference: '"<<prettyName<<"'");
nodep->v3error("Can't resolve module reference: '" << prettyName << "'");
}
}
return modp;
@ -162,11 +167,11 @@ private:
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
m_graph.dumpDotFilePrefixed("linkcells");
m_graph.rank();
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (LinkCellsVertex* vvertexp = dynamic_cast<LinkCellsVertex*>(itp)) {
// +1 so we leave level 1 for the new wrapper we'll make in a moment
AstNodeModule* modp = vvertexp->modp();
modp->level(vvertexp->rank()+1);
modp->level(vvertexp->rank() + 1);
if (vvertexp == m_topVertexp && modp->level() != 2) {
AstNodeModule* abovep = NULL;
if (V3GraphEdge* edgep = vvertexp->inBeginp()) {
@ -175,15 +180,16 @@ private:
abovep = eFromVertexp->modp();
}
}
v3error("Specified --top-module '"<<v3Global.opt.topModule()
<<"' isn't at the top level, it's under another cell '"
<<(abovep ? abovep->prettyName() : "UNKNOWN")<<"'");
v3error("Specified --top-module '"
<< v3Global.opt.topModule()
<< "' isn't at the top level, it's under another cell '"
<< (abovep ? abovep->prettyName() : "UNKNOWN") << "'");
}
}
}
if (v3Global.opt.topModule()!=""
&& !m_topVertexp) {
v3error("Specified --top-module '"<<v3Global.opt.topModule()<<"' was not found in design.");
if (v3Global.opt.topModule() != "" && !m_topVertexp) {
v3error("Specified --top-module '" << v3Global.opt.topModule()
<< "' was not found in design.");
}
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
@ -200,9 +206,9 @@ private:
if (m_declfnWarned.find(nodep->fileline()->filename()) == m_declfnWarned.end()) {
m_declfnWarned.insert(nodep->fileline()->filename());
nodep->v3warn(DECLFILENAME, "Filename '"
<< nodep->fileline()->filebasenameNoExt()
<< "' does not match " << nodep->typeName()
<< " name: " << nodep->prettyNameQ());
<< nodep->fileline()->filebasenameNoExt()
<< "' does not match " << nodep->typeName()
<< " name: " << nodep->prettyNameQ());
}
}
if (VN_IS(nodep, Iface) || VN_IS(nodep, Package)) {
@ -215,7 +221,7 @@ private:
nodep->inLibrary(false); // Safer to make sure it doesn't disappear
}
if (v3Global.opt.topModule() == "" ? nodep->inLibrary() // Library cells are lower
: !topMatch) { // Any non-specified module is lower
: !topMatch) { // Any non-specified module is lower
// Put under a fake vertex so that the graph ranking won't indicate
// this is a top level module
if (!m_libVertexp) m_libVertexp = new LibraryVertex(&m_graph);
@ -230,7 +236,7 @@ private:
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
// Cell: Resolve its filename. If necessary, parse it.
UINFO(4,"Link IfaceRef: "<<nodep<<endl);
UINFO(4, "Link IfaceRef: " << nodep << endl);
// Use findIdUpward instead of findIdFlat; it doesn't matter for now
// but we might support modules-under-modules someday.
AstNodeModule* modp = resolveModule(nodep, nodep->ifaceName());
@ -241,7 +247,7 @@ private:
if (!nodep->cellp()) nodep->ifacep(VN_CAST(modp, Iface));
} else if (VN_IS(modp, NotFoundModule)) { // Will error out later
} else {
nodep->v3error("Non-interface used as an interface: "<<nodep->prettyNameQ());
nodep->v3error("Non-interface used as an interface: " << nodep->prettyNameQ());
}
}
// Note cannot do modport resolution here; modports are allowed underneath generates
@ -260,7 +266,7 @@ private:
// TODO this doesn't allow bind to dotted hier names, that would require
// this move to post param, which would mean we do not auto-read modules
// and means we cannot compute module levels until later.
UINFO(4,"Link Bind: "<<nodep<<endl);
UINFO(4, "Link Bind: " << nodep << endl);
AstNodeModule* modp = resolveModule(nodep, nodep->name());
if (modp) {
AstNode* cellsp = nodep->cellsp()->unlinkFrBackWithNext();
@ -268,7 +274,8 @@ private:
AstNodeModule* oldModp = m_modp;
{
m_modp = modp;
modp->addStmtp(cellsp); // Important that this adds to end, as next iterate assumes does all cells
// Important that this adds to end, as next iterate assumes does all cells
modp->addStmtp(cellsp);
iterateAndNextNull(cellsp);
}
m_modp = oldModp;
@ -281,19 +288,18 @@ private:
// Execute only once. Complication is that cloning may result in
// user1 being set (for pre-clone) so check if user1() matches the
// m_mod, if 0 never did it, if !=, it is an unprocessed clone
bool cloned = (nodep->user1p() && nodep->user1p()!=m_modp);
if (nodep->user1p()==m_modp) return; // AstBind and AstNodeModule may call a cell twice
bool cloned = (nodep->user1p() && nodep->user1p() != m_modp);
if (nodep->user1p() == m_modp) return; // AstBind and AstNodeModule may call a cell twice
nodep->user1p(m_modp);
//
if (!nodep->modp() || cloned) {
UINFO(4,"Link Cell: "<<nodep<<endl);
UINFO(4, "Link Cell: " << nodep << endl);
// Use findIdFallback instead of findIdFlat; it doesn't matter for now
// but we might support modules-under-modules someday.
AstNodeModule* cellmodp = resolveModule(nodep, nodep->modName());
if (cellmodp) {
if (cellmodp == m_modp
|| cellmodp->user2p() == m_modp) {
UINFO(1,"Self-recursive module "<<cellmodp<<endl);
if (cellmodp == m_modp || cellmodp->user2p() == m_modp) {
UINFO(1, "Self-recursive module " << cellmodp << endl);
cellmodp->recursive(true);
nodep->recursive(true);
if (!cellmodp->recursiveClone()) {
@ -307,27 +313,25 @@ private:
AstNodeModule* otherModp = VN_CAST(cellmodp->user2p(), NodeModule);
if (!otherModp) {
otherModp = cellmodp->cloneTree(false);
otherModp->name(otherModp->name()+"__Vrcm");
otherModp->name(otherModp->name() + "__Vrcm");
otherModp->user1p(NULL); // Need new vertex
otherModp->user2p(cellmodp);
otherModp->recursiveClone(true);
// user1 etc will retain its pre-clone value
cellmodp->user2p(otherModp);
v3Global.rootp()->addModulep(otherModp);
new V3GraphEdge(&m_graph, vertex(cellmodp),
vertex(otherModp), 1, false);
new V3GraphEdge(&m_graph, vertex(cellmodp), vertex(otherModp), 1,
false);
}
cellmodp = otherModp;
nodep->modp(cellmodp);
}
else {
} else {
// In the Vrcm, which needs to point back to Vrcm flavor
// The cell already has the correct resolution (to Vrcm)
nodep->modp(cellmodp);
// We don't create a V3GraphEdge (as it would be circular)
}
}
else { // Non-recursive
} else { // Non-recursive
// Track module depths, so can sort list from parent down to children
nodep->modp(cellmodp);
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(cellmodp), 1, false);
@ -336,19 +340,17 @@ private:
}
// Remove AstCell(AstPin("",NULL)), it's a side effect of how we parse "()"
// the empty middle is identical to the empty rule that must find pins in "(,)".
if (nodep->pinsp() && !nodep->pinsp()->nextp()
&& nodep->pinsp()->name() == ""
if (nodep->pinsp() && !nodep->pinsp()->nextp() && nodep->pinsp()->name() == ""
&& !nodep->pinsp()->exprp()) {
pushDeletep(nodep->pinsp()->unlinkFrBackWithNext());
}
if (nodep->paramsp() && !nodep->paramsp()->nextp()
&& nodep->paramsp()->name() == ""
if (nodep->paramsp() && !nodep->paramsp()->nextp() && nodep->paramsp()->name() == ""
&& !nodep->paramsp()->exprp()) {
pushDeletep(nodep->paramsp()->unlinkFrBackWithNext());
}
// Convert .* to list of pins
bool pinStar = false;
for (AstPin* nextp, *pinp = nodep->pinsp(); pinp; pinp=nextp) {
for (AstPin *nextp, *pinp = nodep->pinsp(); pinp; pinp = nextp) {
nextp = VN_CAST(pinp->nextp(), Pin);
if (pinp->dotStar()) {
if (pinStar) pinp->v3error("Duplicate .* in a cell");
@ -358,40 +360,41 @@ private:
}
}
// Convert unnamed pins to pin number based assignments
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
if (pinp->name()=="") pinp->name("__pinNumber"+cvtToStr(pinp->pinNum()));
for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
if (pinp->name() == "") pinp->name("__pinNumber" + cvtToStr(pinp->pinNum()));
}
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
pinp->param(true);
if (pinp->name()=="") pinp->name("__paramNumber"+cvtToStr(pinp->pinNum()));
if (pinp->name() == "") pinp->name("__paramNumber" + cvtToStr(pinp->pinNum()));
}
if (nodep->modp()) {
nodep->modName(nodep->modp()->name());
// Note what pins exist
vl_unordered_set<string> ports; // Symbol table of all connected port names
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
if (pinp->name()=="") pinp->v3error("Connect by position is illegal in .* connected cells");
for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
if (pinp->name() == "")
pinp->v3error("Connect by position is illegal in .* connected cells");
if (!pinp->exprp()) {
if (pinp->name().substr(0, 11) == "__pinNumber") {
pinp->v3warn(PINNOCONNECT, "Cell pin is not connected: "
<<pinp->prettyNameQ());
pinp->v3warn(PINNOCONNECT,
"Cell pin is not connected: " << pinp->prettyNameQ());
} else {
pinp->v3warn(PINCONNECTEMPTY,
"Cell pin connected by name with empty reference: "
<<pinp->prettyNameQ());
<< pinp->prettyNameQ());
}
}
ports.insert(pinp->name());
}
// We search ports, rather than in/out declarations as they aren't resolved yet,
// and it's easier to do it now than in V3LinkDot when we'd need to repeat steps.
for (AstNode* portnodep = nodep->modp()->stmtsp();
portnodep; portnodep=portnodep->nextp()) {
for (AstNode* portnodep = nodep->modp()->stmtsp(); portnodep;
portnodep = portnodep->nextp()) {
if (const AstPort* portp = VN_CAST(portnodep, Port)) {
if (ports.find(portp->name()) == ports.end()
&& ports.find("__pinNumber"+cvtToStr(portp->pinNum())) == ports.end()) {
&& ports.find("__pinNumber" + cvtToStr(portp->pinNum())) == ports.end()) {
if (pinStar) {
UINFO(9," need .* PORT "<<portp<<endl);
UINFO(9, " need .* PORT " << portp << endl);
// Create any not already connected
AstPin* newp = new AstPin(nodep->fileline(), 0, portp->name(),
new AstParseRef(nodep->fileline(),
@ -400,8 +403,8 @@ private:
newp->svImplicit(true);
nodep->addPinsp(newp);
} else { // warn on the CELL that needs it, not the port
nodep->v3warn(PINMISSING, "Cell has missing pin: "
<<portp->prettyNameQ());
nodep->v3warn(PINMISSING,
"Cell has missing pin: " << portp->prettyNameQ());
AstPin* newp = new AstPin(nodep->fileline(), 0, portp->name(), NULL);
nodep->addPinsp(newp);
}
@ -413,8 +416,9 @@ private:
// Cell really is the parent's instantiation of an interface, not a normal module
// Make sure we have a variable to refer to this cell, so can <ifacename>.<innermember>
// in the same way that a child does. Rename though to avoid conflict with cell.
// This is quite similar to how classes work; when unpacked classes are better supported
// may remap interfaces to be more like a class.
// This is quite similar to how classes work; when unpacked
// classes are better supported may remap interfaces to be more
// like a class.
if (!nodep->hasIfaceVar()) {
string varName = nodep->name() + "__Viftop"; // V3LinkDot looks for this naming
AstIfaceRefDType* idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(),
@ -425,8 +429,8 @@ private:
AstVar* varp;
if (nodep->rangep()) {
AstNodeArrayDType* arrp
= new AstUnpackArrayDType(nodep->fileline(), VFlagChildDType(),
idtypep, nodep->rangep()->cloneTree(true));
= new AstUnpackArrayDType(nodep->fileline(), VFlagChildDType(), idtypep,
nodep->rangep()->cloneTree(true));
varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName,
VFlagChildDType(), arrp);
} else {
@ -438,10 +442,8 @@ private:
nodep->hasIfaceVar(true);
}
}
if (nodep->modp()) {
iterateChildren(nodep);
}
UINFO(4," Link Cell done: "<<nodep<<endl);
if (nodep->modp()) { iterateChildren(nodep); }
UINFO(4, " Link Cell done: " << nodep << endl);
}
// Accelerate the recursion
@ -452,17 +454,18 @@ private:
// METHODS
void readModNames() {
// Look at all modules, and store pointers to all module names
for (AstNodeModule* nextp,* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nextp) {
for (AstNodeModule *nextp, *nodep = v3Global.rootp()->modulesp(); nodep; nodep = nextp) {
nextp = VN_CAST(nodep->nextp(), NodeModule);
AstNodeModule* foundp = findModuleSym(nodep->name());
if (foundp && foundp != nodep) {
if (!(foundp->fileline()->warnIsOff(V3ErrorCode::MODDUP)
|| nodep->fileline()->warnIsOff(V3ErrorCode::MODDUP))) {
nodep->v3warn(MODDUP, "Duplicate declaration of module: "
<<nodep->prettyNameQ()<<endl
<<nodep->warnContextPrimary()<<endl
<<foundp->warnOther()<<"... Location of original declaration"<<endl
<<foundp->warnContextSecondary());
<< nodep->prettyNameQ() << endl
<< nodep->warnContextPrimary() << endl
<< foundp->warnOther()
<< "... Location of original declaration" << endl
<< foundp->warnContextSecondary());
}
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
@ -470,7 +473,7 @@ private:
m_mods.rootp()->insert(nodep->name(), new VSymEnt(&m_mods, nodep));
}
}
//if (debug()>=9) m_mods.dump(cout, "-syms: ");
// if (debug() >= 9) m_mods.dump(cout, "-syms: ");
}
public:
@ -491,6 +494,6 @@ public:
// Link class functions
void V3LinkCells::link(AstNetlist* nodep, VInFilter* filterp, V3ParseSym* parseSymp) {
UINFO(4,__FUNCTION__<<": "<<endl);
LinkCellsVisitor visitor (nodep, filterp, parseSymp);
UINFO(4, __FUNCTION__ << ": " << endl);
LinkCellsVisitor visitor(nodep, filterp, parseSymp);
}

File diff suppressed because it is too large Load Diff

View File

@ -41,35 +41,37 @@ private:
typedef std::vector<AstBegin*> BeginStack;
// STATE
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
AstWhile* m_loopp; // Current loop
bool m_loopInc; // In loop increment
int m_modRepeatNum; // Repeat counter
BeginStack m_beginStack; // All begin blocks above current node
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
AstWhile* m_loopp; // Current loop
bool m_loopInc; // In loop increment
int m_modRepeatNum; // Repeat counter
BeginStack m_beginStack; // All begin blocks above current node
// METHODS
VL_DEBUG_FUNC; // Declare debug()
AstJumpLabel* findAddLabel(AstNode* nodep, bool endOfIter) {
// Put label under given node, and if WHILE optionally at end of iteration
UINFO(4,"Create label for "<<nodep<<endl);
UINFO(4, "Create label for " << nodep << endl);
if (VN_IS(nodep, JumpLabel)) return VN_CAST(nodep, JumpLabel); // Done
AstNode* underp = NULL;
bool under_and_next = true;
if (VN_IS(nodep, Begin)) underp = VN_CAST(nodep, Begin)->stmtsp();
else if (VN_IS(nodep, NodeFTask)) underp = VN_CAST(nodep, NodeFTask)->stmtsp();
else if (VN_IS(nodep, While)) {
bool under_and_next = true;
if (VN_IS(nodep, Begin)) {
underp = VN_CAST(nodep, Begin)->stmtsp();
} else if (VN_IS(nodep, NodeFTask)) {
underp = VN_CAST(nodep, NodeFTask)->stmtsp();
} else if (VN_IS(nodep, While)) {
if (endOfIter) {
// Note we jump to end of bodysp; a FOR loop has its
// increment under incsp() which we don't skip
underp = VN_CAST(nodep, While)->bodysp();
} else {
underp = nodep; under_and_next = false; // IE we skip the entire while
underp = nodep;
under_and_next = false; // IE we skip the entire while
}
}
else {
} else {
nodep->v3fatalSrc("Unknown jump point for break/disable/continue");
return NULL;
}
@ -78,7 +80,7 @@ private:
// see t_func_return test.
while (underp && VN_IS(underp, Var)) underp = underp->nextp();
UASSERT_OBJ(underp, nodep, "Break/disable/continue not under expected statement");
UINFO(5," Underpoint is "<<underp<<endl);
UINFO(5, " Underpoint is " << underp << endl);
if (VN_IS(underp, JumpLabel)) {
return VN_CAST(underp, JumpLabel);
@ -86,17 +88,18 @@ private:
AstJumpLabel* labelp = new AstJumpLabel(nodep->fileline(), NULL);
AstNRelinker repHandle;
if (under_and_next) underp->unlinkFrBackWithNext(&repHandle);
else underp->unlinkFrBack(&repHandle);
if (under_and_next) {
underp->unlinkFrBackWithNext(&repHandle);
} else {
underp->unlinkFrBack(&repHandle);
}
repHandle.relink(labelp);
labelp->addStmtsp(underp);
// Keep any AstVars under the function not under the new JumpLabel
for (AstNode* nextp, *varp=underp; varp; varp = nextp) {
for (AstNode *nextp, *varp = underp; varp; varp = nextp) {
nextp = varp->nextp();
if (VN_IS(varp, Var)) {
labelp->addPrev(varp->unlinkFrBack());
}
if (VN_IS(varp, Var)) labelp->addPrev(varp->unlinkFrBack());
}
return labelp;
}
@ -121,7 +124,7 @@ private:
m_ftaskp = NULL;
}
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
UINFO(8," "<<nodep<<endl);
UINFO(8, " " << nodep << endl);
m_beginStack.push_back(nodep);
iterateChildren(nodep);
m_beginStack.pop_back();
@ -131,29 +134,24 @@ private:
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
// Note var can be signed or unsigned based on original number.
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
string name = string("__Vrepeat")+cvtToStr(m_modRepeatNum++);
string name = string("__Vrepeat") + cvtToStr(m_modRepeatNum++);
// Spec says value is integral, if negative is ignored
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
nodep->findSigned32DType());
varp->usedLoopIdx(true);
m_modp->addStmtp(varp);
AstNode* initsp = new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, true),
countp);
AstNode* decp = new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, true),
new AstSub(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, false),
new AstConst(nodep->fileline(), 1)));
new AstVarRef(nodep->fileline(), varp, true), countp);
AstNode* decp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
new AstConst(nodep->fileline(), 1)));
AstNode* zerosp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0);
AstNode* condp = new AstGtS(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, false),
zerosp);
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
AstNode* newp = new AstWhile(nodep->fileline(),
condp,
bodysp,
decp);
AstNode* condp
= new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false), zerosp);
AstNode* bodysp = nodep->bodysp();
if (bodysp) bodysp->unlinkFrBackWithNext();
AstNode* newp = new AstWhile(nodep->fileline(), condp, bodysp, decp);
initsp = initsp->addNext(newp);
newp = initsp;
nodep->replaceWith(newp);
@ -178,67 +176,73 @@ private:
AstFunc* funcp = VN_CAST(m_ftaskp, Func);
if (!m_ftaskp) {
nodep->v3error("Return isn't underneath a task or function");
} else if (funcp && !nodep->lhsp()) {
} else if (funcp && !nodep->lhsp()) {
nodep->v3error("Return underneath a function should have return value");
} else if (!funcp && nodep->lhsp()) {
} else if (!funcp && nodep->lhsp()) {
nodep->v3error("Return underneath a task shouldn't have return value");
} else {
if (funcp && nodep->lhsp()) {
// Set output variable to return value
nodep->addPrev(new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(),
VN_CAST(funcp->fvarp(), Var), true),
nodep->lhsp()->unlinkFrBackWithNext()));
nodep->addPrev(new AstAssign(
nodep->fileline(),
new AstVarRef(nodep->fileline(), VN_CAST(funcp->fvarp(), Var), true),
nodep->lhsp()->unlinkFrBackWithNext()));
}
// Jump to the end of the function call
AstJumpLabel* labelp = findAddLabel(m_ftaskp, false);
nodep->addPrev(new AstJumpGo(nodep->fileline(), labelp));
}
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstBreak* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (!m_loopp) { nodep->v3error("break isn't underneath a loop"); }
else {
if (!m_loopp) {
nodep->v3error("break isn't underneath a loop");
} else {
// Jump to the end of the loop
AstJumpLabel* labelp = findAddLabel(m_loopp, false);
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
}
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstContinue* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (!m_loopp) { nodep->v3error("continue isn't underneath a loop"); }
else {
if (!m_loopp) {
nodep->v3error("continue isn't underneath a loop");
} else {
// Jump to the end of this iteration
// If a "for" loop then need to still do the post-loop increment
AstJumpLabel* labelp = findAddLabel(m_loopp, true);
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
}
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstDisable* nodep) VL_OVERRIDE {
UINFO(8," DISABLE "<<nodep<<endl);
UINFO(8, " DISABLE " << nodep << endl);
iterateChildren(nodep);
AstBegin* beginp = NULL;
for (BeginStack::reverse_iterator it = m_beginStack.rbegin();
it != m_beginStack.rend(); ++it) {
UINFO(9," UNDERBLK "<<*it<<endl);
for (BeginStack::reverse_iterator it = m_beginStack.rbegin(); it != m_beginStack.rend();
++it) {
UINFO(9, " UNDERBLK " << *it << endl);
if ((*it)->name() == nodep->name()) {
beginp = *it;
break;
}
}
//if (debug()>=9) { UINFO(0,"\n"); beginp->dumpTree(cout, " labeli: "); }
if (!beginp) { nodep->v3error("disable isn't underneath a begin with name: "
<<nodep->prettyNameQ()); }
else {
// if (debug() >= 9) { UINFO(0, "\n"); beginp->dumpTree(cout, " labeli: "); }
if (!beginp) {
nodep->v3error("disable isn't underneath a begin with name: " << nodep->prettyNameQ());
} else {
// Jump to the end of the named begin
AstJumpLabel* labelp = findAddLabel(beginp, false);
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
}
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
//if (debug()>=9) { UINFO(0,"\n"); beginp->dumpTree(cout, " labelo: "); }
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
// if (debug() >= 9) { UINFO(0, "\n"); beginp->dumpTree(cout, " labelo: "); }
}
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (m_loopInc && nodep->varp()) nodep->varp()->usedLoopIdx(true);
@ -263,9 +267,7 @@ public:
// Task class functions
void V3LinkJump::linkJump(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
LinkJumpVisitor bvisitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ LinkJumpVisitor bvisitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("link", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -35,7 +35,7 @@
// Levelizing class functions
struct CmpLevel {
inline bool operator() (const AstNodeModule* lhsp, const AstNodeModule* rhsp) const {
inline bool operator()(const AstNodeModule* lhsp, const AstNodeModule* rhsp) const {
return lhsp->level() < rhsp->level();
}
};
@ -43,7 +43,7 @@ struct CmpLevel {
void V3LinkLevel::modSortByLevel() {
// Sort modules by levels, root down to lowest children
// Calculate levels again in case we added modules
UINFO(2,"modSortByLevel()\n");
UINFO(2, "modSortByLevel()\n");
// level() was computed for us in V3LinkCells
@ -60,20 +60,21 @@ void V3LinkLevel::modSortByLevel() {
AstNode* secp = tops[1]; // Complain about second one, as first often intended
if (!secp->fileline()->warnIsOff(V3ErrorCode::MULTITOP)) {
secp->v3warn(MULTITOP, "Multiple top level modules\n"
<<secp->warnMore()
<<"... Suggest see manual; fix the duplicates, or use --top-module to select top."
<<V3Error::warnContextNone());
<< secp->warnMore()
<< "... Suggest see manual; fix the duplicates, or use "
"--top-module to select top."
<< V3Error::warnContextNone());
for (ModVec::const_iterator it = tops.begin(); it != tops.end(); ++it) {
AstNode* alsop = *it;
std::cout<<secp->warnMore()<<"... Top module "<<alsop->prettyNameQ()<<endl
<<alsop->warnContextSecondary();
std::cout << secp->warnMore() << "... Top module " << alsop->prettyNameQ() << endl
<< alsop->warnContextSecondary();
}
}
}
// Reorder the netlist's modules to have modules in level sorted order
stable_sort(mods.begin(), mods.end(), CmpLevel()); // Sort the vector
UINFO(9,"modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666
UINFO(9, "modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666
for (ModVec::const_iterator it = mods.begin(); it != mods.end(); ++it) {
AstNodeModule* nodep = *it;
nodep->clearIter(); // Because we didn't iterate to find the node
@ -85,7 +86,7 @@ void V3LinkLevel::modSortByLevel() {
AstNodeModule* nodep = *it;
v3Global.rootp()->addModulep(nodep);
}
UINFO(9,"modSortByLevel() done\n"); // Comment required for gcc4.6.3 / bug666
UINFO(9, "modSortByLevel() done\n"); // Comment required for gcc4.6.3 / bug666
V3Global::dumpCheckGlobalTree("cells", false, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
@ -93,11 +94,11 @@ void V3LinkLevel::modSortByLevel() {
// Wrapping
void V3LinkLevel::wrapTop(AstNetlist* rootp) {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
// We do ONLY the top module
AstNodeModule* oldmodp = rootp->modulesp();
if (!oldmodp) { // Later V3LinkDot will warn
UINFO(1,"No module found to wrap\n");
UINFO(1, "No module found to wrap\n");
return;
}
AstNodeModule* newmodp = new AstModule(oldmodp->fileline(), string("TOP"));
@ -115,15 +116,13 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) {
// Instantiate all packages under the top wrapper
// This way all later SCOPE based optimizations can ignore packages
for (AstNodeModule* modp = rootp->modulesp(); modp; modp=VN_CAST(modp->nextp(), NodeModule)) {
for (AstNodeModule* modp = rootp->modulesp(); modp;
modp = VN_CAST(modp->nextp(), NodeModule)) {
if (VN_IS(modp, Package)) {
AstCell* cellp = new AstCell(modp->fileline(),
modp->fileline(),
AstCell* cellp = new AstCell(modp->fileline(), modp->fileline(),
// Could add __03a__03a="::" to prevent conflict
// with module names/"v"
modp->name(),
modp->name(),
NULL, NULL, NULL);
modp->name(), modp->name(), NULL, NULL, NULL);
cellp->modp(modp);
newmodp->addStmtp(cellp);
}
@ -142,13 +141,12 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
NameSet dupNames;
// For all modules, skipping over new top
for (AstNodeModule* oldmodp = VN_CAST(rootp->modulesp()->nextp(), NodeModule);
oldmodp && oldmodp->level() <= 2;
oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
oldmodp && oldmodp->level() <= 2; oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
if (AstVar* oldvarp = VN_CAST(subnodep, Var)) {
if (oldvarp->isIO()) {
if (ioNames.find(oldvarp->name()) != ioNames.end()) {
//UINFO(8, "Multitop dup I/O found: "<<oldvarp<<endl);
// UINFO(8, "Multitop dup I/O found: " << oldvarp << endl);
dupNames.insert(oldvarp->name());
} else {
ioNames.insert(oldvarp->name());
@ -160,29 +158,26 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
// For all modules, skipping over new top
for (AstNodeModule* oldmodp = VN_CAST(rootp->modulesp()->nextp(), NodeModule);
oldmodp && oldmodp->level() <= 2;
oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
oldmodp && oldmodp->level() <= 2; oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
if (VN_IS(oldmodp, Package)) continue;
// Add instance
UINFO(5,"LOOP "<<oldmodp<<endl);
AstCell* cellp = new AstCell(newmodp->fileline(),
newmodp->fileline(),
(!v3Global.opt.l2Name().empty()
? v3Global.opt.l2Name() : oldmodp->name()),
oldmodp->name(),
NULL, NULL, NULL);
UINFO(5, "LOOP " << oldmodp << endl);
AstCell* cellp = new AstCell(
newmodp->fileline(), newmodp->fileline(),
(!v3Global.opt.l2Name().empty() ? v3Global.opt.l2Name() : oldmodp->name()),
oldmodp->name(), NULL, NULL, NULL);
cellp->modp(oldmodp);
newmodp->addStmtp(cellp);
// Add pins
for (AstNode* subnodep=oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
if (AstVar* oldvarp = VN_CAST(subnodep, Var)) {
UINFO(8,"VARWRAP "<<oldvarp<<endl);
UINFO(8, "VARWRAP " << oldvarp << endl);
if (oldvarp->isIO()) {
string name = oldvarp->name();
if (dupNames.find(name) != dupNames.end()) {
// __02E=. while __DOT__ looks nicer but will break V3LinkDot
name = oldmodp->name()+"__02E"+name;
name = oldmodp->name() + "__02E" + name;
}
AstVar* varp = oldvarp->cloneTree(false);
@ -196,7 +191,7 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
}
if (varp->direction().isRefOrConstRef()) {
varp->v3error("Unsupported: ref/const ref as primary input/output: "
<<varp->prettyNameQ());
<< varp->prettyNameQ());
}
if (varp->isIO() && v3Global.opt.systemC()) {
varp->sc(true);
@ -205,9 +200,9 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
varp->trace(false);
}
AstPin* pinp = new AstPin(oldvarp->fileline(), 0, varp->name(),
new AstVarRef(varp->fileline(),
varp, oldvarp->isWritable()));
AstPin* pinp
= new AstPin(oldvarp->fileline(), 0, varp->name(),
new AstVarRef(varp->fileline(), varp, oldvarp->isWritable()));
// Skip length and width comp; we know it's a direct assignment
pinp->modVarp(oldvarp);
cellp->addPinsp(pinp);

View File

@ -41,24 +41,24 @@ private:
// Cleared on netlist
// AstNode::user1() -> bool. True if processed
// AstNode::user2() -> bool. True if fileline recomputed
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
// TYPES
typedef std::map<std::pair<void*,string>,AstTypedef*> ImplTypedefMap;
typedef std::map<std::pair<void*, string>, AstTypedef*> ImplTypedefMap;
typedef std::set<FileLine*> FileLineSet;
// STATE
AstVar* m_varp; // Variable we're under
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
FileLineSet m_filelines; // Filelines that have been seen
bool m_inAlways; // Inside an always
bool m_inGenerate; // Inside a generate
bool m_needStart; // Need start marker on lower AstParse
AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current task
AstNodeDType* m_dtypep; // Current data type
AstVar* m_varp; // Variable we're under
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
FileLineSet m_filelines; // Filelines that have been seen
bool m_inAlways; // Inside an always
bool m_inGenerate; // Inside a generate
bool m_needStart; // Need start marker on lower AstParse
AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current task
AstNodeDType* m_dtypep; // Current data type
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -84,8 +84,11 @@ private:
// Create a name for the enum, to aid debug and tracing
// This name is not guaranteed to be globally unique (due to later parameterization)
string above;
if (m_modp && VN_IS(m_modp, Package)) above = m_modp->name()+"::";
else if (m_modp) above = m_modp->name()+".";
if (m_modp && VN_IS(m_modp, Package)) {
above = m_modp->name() + "::";
} else if (m_modp) {
above = m_modp->name() + ".";
}
return above + typedefp->name();
}
return "";
@ -115,16 +118,14 @@ private:
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
if (!nodep->user1SetOnce()) { // Process only once.
cleanFileline(nodep);
UINFO(5," "<<nodep<<endl);
UINFO(5, " " << nodep << endl);
AstNodeModule* upperValueModp = m_valueModp;
m_valueModp = NULL;
iterateChildren(nodep);
m_valueModp = upperValueModp;
}
}
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
visitIterateNodeDType(nodep);
}
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { visitIterateNodeDType(nodep); }
virtual void visit(AstEnumDType* nodep) VL_OVERRIDE {
if (nodep->name() == "") {
nodep->name(nameFromTypedef(nodep)); // Might still remain ""
@ -142,7 +143,7 @@ private:
cleanFileline(nodep);
iterateChildren(nodep);
if (nodep->rangep()) {
if (!VN_IS(nodep->rangep()->msbp(), Const)
if (!VN_IS(nodep->rangep()->msbp(), Const) //
|| !VN_IS(nodep->rangep()->lsbp(), Const)) {
nodep->v3error("Enum ranges must be integral, per spec");
}
@ -151,18 +152,19 @@ private:
int increment = (msb > lsb) ? -1 : 1;
int offset_from_init = 0;
AstNode* addp = NULL;
for (int i=msb; i!=(lsb+increment); i+=increment, offset_from_init++) {
for (int i = msb; i != (lsb + increment); i += increment, offset_from_init++) {
string name = nodep->name() + cvtToStr(i);
AstNode* valuep = NULL;
if (nodep->valuep()) valuep = new AstAdd
(nodep->fileline(),
nodep->valuep()->cloneTree(true),
new AstConst(nodep->fileline(),
AstConst::Unsized32(),
offset_from_init));
if (nodep->valuep())
valuep = new AstAdd(
nodep->fileline(), nodep->valuep()->cloneTree(true),
new AstConst(nodep->fileline(), AstConst::Unsized32(), offset_from_init));
AstNode* newp = new AstEnumItem(nodep->fileline(), name, NULL, valuep);
if (addp) addp = addp->addNextNull(newp);
else addp = newp;
if (addp) {
addp = addp->addNextNull(newp);
} else {
addp = newp;
}
}
nodep->replaceWith(addp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
@ -175,15 +177,15 @@ private:
// It's a parameter type. Use a different node type for this.
AstNodeDType* dtypep = VN_CAST(nodep->valuep(), NodeDType);
if (!dtypep) {
nodep->v3error("Parameter type's initial value isn't a type: "
<<nodep->prettyNameQ());
nodep->v3error(
"Parameter type's initial value isn't a type: " << nodep->prettyNameQ());
nodep->unlinkFrBack();
} else {
dtypep->unlinkFrBack();
AstNode* newp = new AstParamTypeDType(nodep->fileline(),
nodep->varType(), nodep->name(),
VFlagChildDType(), dtypep);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
AstNode* newp = new AstParamTypeDType(nodep->fileline(), nodep->varType(),
nodep->name(), VFlagChildDType(), dtypep);
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
return;
}
@ -195,18 +197,15 @@ private:
switch (nodep->varType()) {
case AstVarType::VAR:
case AstVarType::PORT:
case AstVarType::WIRE:
nodep->sigUserRWPublic(true);
break;
case AstVarType::WIRE: nodep->sigUserRWPublic(true); break;
default: break;
}
}
// We used modTrace before leveling, and we may now
// want to turn it off now that we know the levelizations
if (v3Global.opt.traceDepth()
&& m_modp
&& (m_modp->level()-1) > v3Global.opt.traceDepth()) {
if (v3Global.opt.traceDepth() && m_modp
&& (m_modp->level() - 1) > v3Global.opt.traceDepth()) {
m_modp->modTrace(false);
nodep->trace(false);
}
@ -237,15 +236,13 @@ private:
// Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it
FileLine* newfl = new FileLine(fl);
newfl->warnOff(V3ErrorCode::PROCASSWIRE, true);
nodep->addNextHere
(new AstInitial
(newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true),
nodep->valuep()->unlinkFrBack())));
nodep->addNextHere(new AstInitial(
newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true),
nodep->valuep()->unlinkFrBack())));
} // 3. Under blocks, it's an initial value to be under an assign
else {
nodep->addNextHere
(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true),
nodep->valuep()->unlinkFrBack()));
nodep->addNextHere(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true),
nodep->valuep()->unlinkFrBack()));
}
}
if (nodep->isIfaceRef() && !nodep->isIfaceParent()) {
@ -253,7 +250,9 @@ private:
// haven't made additional ones for interconnect yet, so assert is simple
// What breaks later is we don't have a Scope/Cell representing
// the interface to attach to
if (m_modp->level()<=2) nodep->v3error("Unsupported: Interfaced port on top level module");
if (m_modp->level() <= 2) {
nodep->v3error("Unsupported: Interfaced port on top level module");
}
}
}
@ -265,69 +264,61 @@ private:
UASSERT_OBJ(typep, nodep, "Attribute not attached to typedef");
typep->attrPublic(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
} else if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
nodep->v3warn(DEPRECATED, "sc_clock is deprecated and will be removed");
m_varp->attrScClocked(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_CLOCK_ENABLE) {
} else if (nodep->attrType() == AstAttrType::VAR_CLOCK_ENABLE) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->attrClockEn(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
} else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->sigUserRWPublic(true); m_varp->sigModPublic(true);
m_varp->sigUserRWPublic(true);
m_varp->sigModPublic(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
} else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->sigUserRWPublic(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RD) {
} else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RD) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->sigUserRdPublic(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RW) {
} else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RW) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->sigUserRWPublic(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
} else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->attrIsolateAssign(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_SFORMAT) {
} else if (nodep->attrType() == AstAttrType::VAR_SFORMAT) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->attrSFormat(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_SPLIT_VAR) {
} else if (nodep->attrType() == AstAttrType::VAR_SPLIT_VAR) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
if (!VN_IS(m_modp, Module)) {
m_varp->v3warn(SPLITVAR, m_varp->prettyNameQ() << " has split_var metacomment, "
"but will not be split because it is not declared in a module.");
m_varp->v3warn(
SPLITVAR,
m_varp->prettyNameQ()
<< " has split_var metacomment, "
"but will not be split because it is not declared in a module.");
} else {
m_varp->attrSplitVar(true);
}
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_SC_BV) {
} else if (nodep->attrType() == AstAttrType::VAR_SC_BV) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->attrScBv(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_CLOCKER) {
} else if (nodep->attrType() == AstAttrType::VAR_CLOCKER) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->attrClocker(VVarAttrClocker::CLOCKER_YES);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
else if (nodep->attrType() == AstAttrType::VAR_NO_CLOCKER) {
} else if (nodep->attrType() == AstAttrType::VAR_NO_CLOCKER) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->attrClocker(VVarAttrClocker::CLOCKER_NO);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
@ -351,36 +342,38 @@ private:
virtual void visit(AstDefImplicitDType* nodep) VL_OVERRIDE {
cleanFileline(nodep);
UINFO(8," DEFIMPLICIT "<<nodep<<endl);
UINFO(8, " DEFIMPLICIT " << nodep << endl);
// Must remember what names we've already created, and combine duplicates
// so that for "var enum {...} a,b" a & b will share a common typedef
// Unique name space under each containerp() so that an addition of
// a new type won't change every verilated module.
AstTypedef* defp = NULL;
ImplTypedefMap::iterator it = m_implTypedef.find(make_pair(nodep->containerp(), nodep->name()));
ImplTypedefMap::iterator it
= m_implTypedef.find(make_pair(nodep->containerp(), nodep->name()));
if (it != m_implTypedef.end()) {
defp = it->second;
} else {
// Definition must be inserted right after the variable (etc) that needed it
// AstVar, AstTypedef, AstNodeFTask are common containers
AstNode* backp = nodep->backp();
for (; backp; backp=backp->backp()) {
if (VN_IS(backp, Var)) break;
else if (VN_IS(backp, Typedef)) break;
else if (VN_IS(backp, NodeFTask)) break;
for (; backp; backp = backp->backp()) {
if (VN_IS(backp, Var) || VN_IS(backp, Typedef) || VN_IS(backp, NodeFTask)) break;
}
UASSERT_OBJ(backp, nodep,
"Implicit enum/struct type created under unexpected node type");
AstNodeDType* dtypep = nodep->childDTypep(); dtypep->unlinkFrBack();
if (VN_IS(backp, Typedef)) { // A typedef doesn't need us to make yet another level of typedefing
AstNodeDType* dtypep = nodep->childDTypep();
dtypep->unlinkFrBack();
if (VN_IS(backp, Typedef)) {
// A typedef doesn't need us to make yet another level of typedefing
// For typedefs just remove the AstRefDType level of abstraction
nodep->replaceWith(dtypep);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return;
} else {
defp = new AstTypedef(nodep->fileline(), nodep->name(), NULL,
VFlagChildDType(), dtypep);
m_implTypedef.insert(make_pair(make_pair(nodep->containerp(), defp->name()), defp));
defp = new AstTypedef(nodep->fileline(), nodep->name(), NULL, VFlagChildDType(),
dtypep);
m_implTypedef.insert(
make_pair(make_pair(nodep->containerp(), defp->name()), defp));
backp->addNextHere(defp);
}
}
@ -391,19 +384,22 @@ private:
virtual void visit(AstForeach* nodep) VL_OVERRIDE {
// FOREACH(array,loopvars,body)
// -> BEGIN(declare vars, loopa=lowest; WHILE(loopa<=highest, ... body))
//nodep->dumpTree(cout, "-foreach-old:");
// nodep->dumpTree(cout, "-foreach-old:");
AstNode* newp = nodep->bodysp()->unlinkFrBackWithNext();
AstNode* arrayp = nodep->arrayp();
int dimension = 1;
// Must do innermost (last) variable first
AstNode* firstVarsp = nodep->varsp()->unlinkFrBackWithNext();
AstNode* lastVarsp = firstVarsp;
while (lastVarsp->nextp()) { lastVarsp = lastVarsp->nextp(); dimension++; }
for (AstNode* varsp = lastVarsp; varsp; varsp=varsp->backp()) {
UINFO(9,"foreachVar "<<varsp<<endl);
while (lastVarsp->nextp()) {
lastVarsp = lastVarsp->nextp();
dimension++;
}
for (AstNode* varsp = lastVarsp; varsp; varsp = varsp->backp()) {
UINFO(9, "foreachVar " << varsp << endl);
FileLine* fl = varsp->fileline();
AstNode* varp = new AstVar(fl, AstVarType::BLOCKTEMP,
varsp->name(), nodep->findSigned32DType());
AstNode* varp
= new AstVar(fl, AstVarType::BLOCKTEMP, varsp->name(), nodep->findSigned32DType());
// These will be the left and right dimensions and size of the array:
AstNode* leftp = new AstAttrOf(fl, AstAttrType::DIM_LEFT,
new AstVarRef(fl, arrayp->name(), false),
@ -416,19 +412,16 @@ private:
new AstConst(fl, dimension));
AstNode* stmtsp = varp;
// Assign left-dimension into the loop var:
stmtsp->addNext(new AstAssign
(fl, new AstVarRef(fl, varp->name(), true), leftp));
stmtsp->addNext(new AstAssign(fl, new AstVarRef(fl, varp->name(), true), leftp));
// This will turn into a constant bool for static arrays
AstNode* notemptyp = new AstGt(fl, sizep, new AstConst(fl, 0));
// This will turn into a bool constant, indicating whether
// we count the loop variable up or down:
AstNode* countupp = new AstLte(fl, leftp->cloneTree(true),
rightp->cloneTree(true));
AstNode* countupp = new AstLte(fl, leftp->cloneTree(true), rightp->cloneTree(true));
AstNode* comparep = new AstCond(
fl, countupp->cloneTree(true),
// Left increments up to right
new AstLte(fl, new AstVarRef(fl, varp->name(), false),
rightp->cloneTree(true)),
new AstLte(fl, new AstVarRef(fl, varp->name(), false), rightp->cloneTree(true)),
// Left decrements down to right
new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp));
// This will reduce to comparep for static arrays
@ -436,16 +429,15 @@ private:
AstNode* incp = new AstAssign(
fl, new AstVarRef(fl, varp->name(), true),
new AstAdd(fl, new AstVarRef(fl, varp->name(), false),
new AstCond(fl, countupp,
new AstConst(fl, 1),
new AstConst(fl, -1))));
new AstCond(fl, countupp, new AstConst(fl, 1), new AstConst(fl, -1))));
stmtsp->addNext(new AstWhile(fl, condp, newp, incp));
newp = new AstBegin(nodep->fileline(), "", stmtsp, false, true);
dimension--;
}
//newp->dumpTree(cout, "-foreach-new:");
// newp->dumpTree(cout, "-foreach-new:");
VL_DO_DANGLING(firstVarsp->deleteTree(), firstVarsp);
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
@ -472,23 +464,15 @@ private:
iterateChildren(nodep);
m_valueModp = upperValueModp;
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
visitIterateNoValueMod(nodep);
}
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
visitIterateNoValueMod(nodep);
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); }
virtual void visit(AstFinal* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); }
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
m_inAlways = true;
visitIterateNoValueMod(nodep);
m_inAlways = false;
}
virtual void visit(AstCover* nodep) VL_OVERRIDE {
visitIterateNoValueMod(nodep);
}
virtual void visit(AstRestrict* nodep) VL_OVERRIDE {
visitIterateNoValueMod(nodep);
}
virtual void visit(AstCover* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); }
virtual void visit(AstRestrict* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); }
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
V3Config::applyCoverageBlock(m_modp, nodep);
@ -502,10 +486,8 @@ private:
// It's not FOR(BEGIN(...)) but we earlier changed it to BEGIN(FOR(...))
if (nodep->genforp() && nodep->name() == "") {
nodep->name("genblk");
}
else if (nodep->generate() && nodep->name() == ""
&& (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf))
&& !nestedIf) {
} else if (nodep->generate() && nodep->name() == ""
&& (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf)) && !nestedIf) {
nodep->name("genblk");
}
iterateChildren(nodep);
@ -542,9 +524,7 @@ public:
// Link class functions
void V3LinkParse::linkParse(AstNetlist* rootp) {
UINFO(4,__FUNCTION__<<": "<<endl);
{
LinkParseVisitor visitor(rootp);
} // Destruct before checking
UINFO(4, __FUNCTION__ << ": " << endl);
{ LinkParseVisitor visitor(rootp); } // Destruct before checking
V3Global::dumpCheckGlobalTree("linkparse", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}

View File

@ -64,7 +64,7 @@ private:
// TODO: could move to V3LinkParse to get them out of the way of elaboration
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
// Module: Create sim table for entire module and iterate
UINFO(8,"MODULE "<<nodep<<endl);
UINFO(8, "MODULE " << nodep << endl);
if (nodep->dead()) return;
AstNodeModule* origModp = m_modp;
int origSenitemCvtNum = m_senitemCvtNum;
@ -110,9 +110,7 @@ private:
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
// VarRef: Resolve its reference
if (nodep->varp()) {
nodep->varp()->usedParam(true);
}
if (nodep->varp()) { nodep->varp()->usedParam(true); }
iterateChildren(nodep);
}
@ -123,9 +121,7 @@ private:
m_ftaskp = nodep;
iterateChildren(nodep);
m_ftaskp = NULL;
if (nodep->dpiExport()) {
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
}
if (nodep->dpiExport()) { nodep->scopeNamep(new AstScopeName(nodep->fileline())); }
}
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
iterateChildren(nodep);
@ -142,34 +138,29 @@ private:
// This is a bit unfortunate as we haven't done width resolution
// and any width errors will look a bit odd, but it works.
AstNode* sensp = nodep->sensp();
if (sensp
&& !VN_IS(sensp, NodeVarRef)
&& !VN_IS(sensp, Const)) {
if (sensp && !VN_IS(sensp, NodeVarRef) && !VN_IS(sensp, Const)) {
// Make a new temp wire
string newvarname = "__Vsenitemexpr"+cvtToStr(++m_senitemCvtNum);
AstVar* newvarp = new AstVar(sensp->fileline(),
AstVarType::MODULETEMP, newvarname,
string newvarname = "__Vsenitemexpr" + cvtToStr(++m_senitemCvtNum);
AstVar* newvarp = new AstVar(sensp->fileline(), AstVarType::MODULETEMP, newvarname,
VFlagLogicPacked(), 1);
// We can't just add under the module, because we may be
// inside a generate, begin, etc.
// We know a SenItem should be under a SenTree/Always etc,
// we we'll just hunt upwards
AstNode* addwherep = nodep; // Add to this element's next
while (VN_IS(addwherep, SenItem)
|| VN_IS(addwherep, SenTree)) {
while (VN_IS(addwherep, SenItem) || VN_IS(addwherep, SenTree)) {
addwherep = addwherep->backp();
}
if (!VN_IS(addwherep, Always)) { // Assertion perhaps?
sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under some complicated block");
sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under "
"some complicated block");
addwherep = m_modp;
}
addwherep->addNext(newvarp);
sensp->replaceWith(new AstVarRef(sensp->fileline(), newvarp, false));
AstAssignW* assignp = new AstAssignW
(sensp->fileline(),
new AstVarRef(sensp->fileline(), newvarp, true),
sensp);
AstAssignW* assignp = new AstAssignW(
sensp->fileline(), new AstVarRef(sensp->fileline(), newvarp, true), sensp);
addwherep->addNext(assignp);
}
} else { // Old V1995 sensitivity list; we'll probably mostly ignore
@ -178,18 +169,21 @@ private:
did = 0;
if (AstNodeSel* selp = VN_CAST(nodep->sensp(), NodeSel)) {
AstNode* fromp = selp->fromp()->unlinkFrBack();
selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp);
selp->replaceWith(fromp);
VL_DO_DANGLING(selp->deleteTree(), selp);
did = 1;
}
// NodeSel doesn't include AstSel....
if (AstSel* selp = VN_CAST(nodep->sensp(), Sel)) {
AstNode* fromp = selp->fromp()->unlinkFrBack();
selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp);
selp->replaceWith(fromp);
VL_DO_DANGLING(selp->deleteTree(), selp);
did = 1;
}
if (AstNodePreSel* selp = VN_CAST(nodep->sensp(), NodePreSel)) {
AstNode* fromp = selp->lhsp()->unlinkFrBack();
selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp);
selp->replaceWith(fromp);
VL_DO_DANGLING(selp->deleteTree(), selp);
did = 1;
}
}
@ -213,10 +207,12 @@ private:
// So we replicate it in another node
// Note that V3Param knows not to replace AstVarRef's under AstAttrOf's
AstNode* basefromp = AstArraySel::baseFromp(nodep);
if (AstNodeVarRef* varrefp = VN_CAST(basefromp, NodeVarRef)) { // Maybe varxref - so need to clone
if (AstNodeVarRef* varrefp
= VN_CAST(basefromp, NodeVarRef)) { // Maybe varxref - so need to clone
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
varrefp->cloneTree(false)));
} else if (AstUnlinkedRef* uvxrp = VN_CAST(basefromp, UnlinkedRef)) { // Maybe unlinked - so need to clone
} else if (AstUnlinkedRef* uvxrp
= VN_CAST(basefromp, UnlinkedRef)) { // Maybe unlinked - so need to clone
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
uvxrp->cloneTree(false)));
} else if (AstMemberSel* fromp = VN_CAST(basefromp, MemberSel)) {
@ -227,11 +223,11 @@ private:
fromp->cloneTree(false)));
} else if (VN_IS(basefromp, Replicate)) {
// From {...}[...] syntax in IEEE 2017
if (basefromp) { UINFO(1," Related node: "<<basefromp<<endl); }
if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); }
nodep->v3error("Unsupported: Select of concatenation");
nodep = NULL;
} else {
if (basefromp) { UINFO(1," Related node: "<<basefromp<<endl); }
if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); }
nodep->v3fatalSrc("Illegal bit select; no signal/member being extracted from");
}
}
@ -253,20 +249,21 @@ private:
if (nodep->pragType() == AstPragmaType::PUBLIC_MODULE) {
UASSERT_OBJ(m_modp, nodep, "PUBLIC_MODULE not under a module");
m_modp->modPublic(true);
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) {
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) {
UASSERT_OBJ(m_ftaskp, nodep, "PUBLIC_TASK not under a task");
m_ftaskp->taskPublic(true);
m_modp->modPublic(true); // Need to get to the task...
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) {
if (!v3Global.opt.coverageLine()) { // No need for block statements; may optimize better without
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) {
if (!v3Global.opt.coverageLine()) { // No need for block statements; may optimize
// better without
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
}
else {
} else {
iterateChildren(nodep);
}
}
@ -278,10 +275,10 @@ private:
string fmt;
for (string::const_iterator it = format.begin(); it != format.end(); ++it) {
char ch = *it;
if (!inPct && ch=='%') {
if (!inPct && ch == '%') {
inPct = true;
fmt = ch;
} else if (inPct && (isdigit(ch) || ch=='.' || ch=='-')) {
} else if (inPct && (isdigit(ch) || ch == '.' || ch == '-')) {
fmt += ch;
} else if (inPct) {
inPct = false;
@ -290,15 +287,21 @@ private:
case '%': // %% - just output a %
break;
case 'm': // %m - auto insert "name"
if (isScan) { nodep->v3error("Unsupported: %m in $fscanf"); fmt = ""; }
if (isScan) {
nodep->v3error("Unsupported: %m in $fscanf");
fmt = "";
}
break;
case 'l': // %l - auto insert "library"
if (isScan) { nodep->v3error("Unsupported: %l in $fscanf"); fmt = ""; }
if (isScan) {
nodep->v3error("Unsupported: %l in $fscanf");
fmt = "";
}
if (m_modp) fmt = VString::quotePercent(m_modp->prettyName());
break;
default: // Most operators, just move to next argument
if (!V3Number::displayedFmtLegal(ch)) {
nodep->v3error("Unknown $display-like format code: '%"<<ch<<"'");
nodep->v3error("Unknown $display-like format code: '%" << ch << "'");
} else {
if (!argp) {
nodep->v3error("Missing arguments for $display-like format");
@ -322,10 +325,10 @@ private:
skipCount--;
continue;
}
AstConst *constp = VN_CAST(argp, Const);
AstConst* constp = VN_CAST(argp, Const);
bool isFromString = (constp) ? constp->num().isFromString() : false;
if (isFromString) {
int numchars = argp->dtypep()->width()/8;
int numchars = argp->dtypep()->width() / 8;
string str(numchars, ' ');
// now scan for % operators
bool inpercent = false;
@ -338,23 +341,18 @@ private:
} else if (inpercent) {
inpercent = 0;
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.':
inpercent = true;
break;
case '%':
break;
case '0' ... '9':
case '.': inpercent = true; break;
case '%': break;
default:
if (V3Number::displayedFmtLegal(c)) {
skipCount++;
}
if (V3Number::displayedFmtLegal(c)) { skipCount++; }
}
}
}
newFormat.append(str);
AstNode *nextp = argp->nextp();
argp->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(argp), argp);
AstNode* nextp = argp->nextp();
argp->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(argp), argp);
argp = nextp;
} else {
newFormat.append("%?"); // V3Width to figure it out
@ -366,7 +364,9 @@ private:
}
void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) {
if (!filep) nodep->v3error("Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable");
if (!filep) {
nodep->v3error("Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable");
}
if (filep && filep->varp()) filep->varp()->attrFileDescr(true);
}
@ -402,7 +402,8 @@ private:
iterateChildren(nodep);
// Cleanup old-school displays without format arguments
if (!nodep->hasFormat()) {
UASSERT_OBJ(nodep->text()=="", nodep, "Non-format $sformatf should have \"\" format");
UASSERT_OBJ(nodep->text() == "", nodep,
"Non-format $sformatf should have \"\" format");
if (VN_IS(nodep->exprsp(), Const)
&& VN_CAST(nodep->exprsp(), Const)->num().isFromString()) {
AstConst* fmtp = VN_CAST(nodep->exprsp()->unlinkFrBack(), Const);
@ -421,14 +422,14 @@ private:
}
virtual void visit(AstUdpTable* nodep) VL_OVERRIDE {
UINFO(5,"UDPTABLE "<<nodep<<endl);
UINFO(5, "UDPTABLE " << nodep << endl);
if (!v3Global.opt.bboxUnsup()) {
// We don't warn until V3Inst, so that UDPs that are in libraries and
// never used won't result in any warnings.
} else {
// Massive hack, just tie off all outputs so our analysis can proceed
AstVar* varoutp = NULL;
for (AstNode* stmtp = m_modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
for (AstNode* stmtp = m_modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* varp = VN_CAST(stmtp, Var)) {
if (varp->isReadOnly()) {
} else if (varp->isWritable()) {
@ -438,16 +439,15 @@ private:
varoutp = varp;
// Tie off
m_modp->addStmtp(new AstAssignW(
varp->fileline(),
new AstVarRef(varp->fileline(), varp, true),
new AstConst(varp->fileline(),
AstConst::LogicFalse())));
varp->fileline(), new AstVarRef(varp->fileline(), varp, true),
new AstConst(varp->fileline(), AstConst::LogicFalse())));
} else {
varp->v3error("Only inputs and outputs are allowed in udp modules");
}
}
}
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
}
@ -531,7 +531,7 @@ public:
// Link class functions
void V3LinkResolve::linkResolve(AstNetlist* rootp) {
UINFO(4,__FUNCTION__<<": "<<endl);
UINFO(4, __FUNCTION__ << ": " << endl);
{
LinkResolveVisitor visitor(rootp);
LinkBotupVisitor visitorb(rootp);

File diff suppressed because it is too large Load Diff

View File

@ -39,22 +39,27 @@ class AstNode;
class V3Number {
// Large 4-state number handling
int m_width; // Width as specified/calculated.
bool m_sized:1; // True if the user specified the width, else we track it.
bool m_signed:1; // True if signed value
bool m_double:1; // True if double real value
bool m_isString:1; // True if string
bool m_fromString:1; // True if from string literal
bool m_autoExtend:1; // True if SystemVerilog extend-to-any-width
FileLine* m_fileline;
AstNode* m_nodep; // Parent node
std::vector<uint32_t> m_value; // The Value, with bit 0 being in bit 0 of this vector (unless X/Z)
int m_width; // Width as specified/calculated.
bool m_sized : 1; // True if the user specified the width, else we track it.
bool m_signed : 1; // True if signed value
bool m_double : 1; // True if double real value
bool m_isString : 1; // True if string
bool m_fromString : 1; // True if from string literal
bool m_autoExtend : 1; // True if SystemVerilog extend-to-any-width
FileLine* m_fileline;
AstNode* m_nodep; // Parent node
std::vector<uint32_t> m_value; // Value, with bit 0 in bit 0 of this vector (unless X/Z)
std::vector<uint32_t> m_valueX; // Each bit is true if it's X or Z, 10=z, 11=x
string m_stringVal; // If isString, the value of the string
string m_stringVal; // If isString, the value of the string
// METHODS
V3Number& setSingleBits(char value);
V3Number& setString(const string& str) { m_isString = true; m_stringVal = str; return *this; }
V3Number& setString(const string& str) {
m_isString = true;
m_stringVal = str;
return *this;
}
void opCleanThis(bool warnOnTruncation = false);
public:
void nodep(AstNode* nodep) { setNames(nodep); }
FileLine* fileline() const { return m_fileline; }
@ -64,79 +69,87 @@ public:
V3Number& setLongS(vlsint32_t value);
V3Number& setDouble(double value);
void setBit(int bit, char value) { // Note must be pre-zeroed!
if (bit>=m_width) return;
uint32_t mask = (1UL<<(bit&31));
if (value=='0' || value==0) {
m_value [bit/32] &= ~mask;
m_valueX[bit/32] &= ~mask;
} else if (value=='1'|| value==1) {
m_value [bit/32] |= mask;
m_valueX[bit/32] &= ~mask;
} else if (value=='z'|| value==2) {
m_value [bit/32] &= ~mask;
m_valueX[bit/32] |= mask;
if (bit >= m_width) return;
uint32_t mask = (1UL << (bit & 31));
if (value == '0' || value == 0) {
m_value[bit / 32] &= ~mask;
m_valueX[bit / 32] &= ~mask;
} else if (value == '1' || value == 1) {
m_value[bit / 32] |= mask;
m_valueX[bit / 32] &= ~mask;
} else if (value == 'z' || value == 2) {
m_value[bit / 32] &= ~mask;
m_valueX[bit / 32] |= mask;
} else { // X
m_value [bit/32] |= mask;
m_valueX[bit/32] |= mask;
m_value[bit / 32] |= mask;
m_valueX[bit / 32] |= mask;
}
}
private:
char bitIs(int bit) const {
if (bit>=m_width || bit<0) {
if (bit >= m_width || bit < 0) {
// We never sign extend
return '0';
}
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); }
return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0)
| ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]);
}
char bitIsExtend(int bit, int lbits) const {
// lbits usually = width, but for C optimizations width=32_bits, lbits = 32_or_less
if (bit<0) return '0';
UASSERT(lbits<=m_width, "Extend of wrong size");
if (bit>=lbits) {
bit = lbits ? lbits-1 : 0;
if (bit < 0) return '0';
UASSERT(lbits <= m_width, "Extend of wrong size");
if (bit >= lbits) {
bit = lbits ? lbits - 1 : 0;
// We do sign extend
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] );
return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0)
| ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]);
}
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); }
return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0)
| ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]);
}
bool bitIs0(int bit) const {
if (bit<0) return false;
if (bit>=m_width) return !bitIsXZ(m_width-1);
return ( (m_value[bit/32] & (1UL<<(bit&31)))==0
&& !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
if (bit < 0) return false;
if (bit >= m_width) return !bitIsXZ(m_width - 1);
return ((m_value[bit / 32] & (1UL << (bit & 31))) == 0
&& !(m_valueX[bit / 32] & (1UL << (bit & 31))));
}
bool bitIs1(int bit) const {
if (bit<0) return false;
if (bit>=m_width) return false;
return ( (m_value[bit/32] & (1UL<<(bit&31)))
&& !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
if (bit < 0) return false;
if (bit >= m_width) return false;
return ((m_value[bit / 32] & (1UL << (bit & 31)))
&& !(m_valueX[bit / 32] & (1UL << (bit & 31))));
}
bool bitIs1Extend(int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIs1Extend(m_width-1);
return ( (m_value[bit/32] & (1UL<<(bit&31)))
&& !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
if (bit < 0) return false;
if (bit >= m_width) return bitIs1Extend(m_width - 1);
return ((m_value[bit / 32] & (1UL << (bit & 31)))
&& !(m_valueX[bit / 32] & (1UL << (bit & 31))));
}
bool bitIsX(int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIsZ(m_width-1);
return ( (m_value[bit/32] & (1UL<<(bit&31)))
&& (m_valueX[bit/32] & (1UL<<(bit&31))) ); }
if (bit < 0) return false;
if (bit >= m_width) return bitIsZ(m_width - 1);
return ((m_value[bit / 32] & (1UL << (bit & 31)))
&& (m_valueX[bit / 32] & (1UL << (bit & 31))));
}
bool bitIsXZ(int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIsXZ(m_width-1);
return ( (m_valueX[bit/32] & (1UL<<(bit&31))));
if (bit < 0) return false;
if (bit >= m_width) return bitIsXZ(m_width - 1);
return ((m_valueX[bit / 32] & (1UL << (bit & 31))));
}
bool bitIsZ(int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIsZ(m_width-1);
return ( (~m_value[bit/32] & (1UL<<(bit&31)))
&& (m_valueX[bit/32] & (1UL<<(bit&31))) ); }
if (bit < 0) return false;
if (bit >= m_width) return bitIsZ(m_width - 1);
return ((~m_value[bit / 32] & (1UL << (bit & 31)))
&& (m_valueX[bit / 32] & (1UL << (bit & 31))));
}
uint32_t bitsValue(int lsb, int nbits) const {
uint32_t v = 0;
for (int bitn=0; bitn<nbits; bitn++) { v |= (bitIs1(lsb+bitn)<<bitn); }
for (int bitn = 0; bitn < nbits; bitn++) { v |= (bitIs1(lsb + bitn) << bitn); }
return v;
}
int words() const { return ((width()+31)/32); }
int words() const { return ((width() + 31) / 32); }
uint32_t hiWordMask() const { return VL_MASK_I(width()); }
V3Number& opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool is_modulus);
@ -145,8 +158,10 @@ public:
// CONSTRUCTORS
explicit V3Number(AstNode* nodep) { init(nodep, 1); }
V3Number(AstNode* nodep, int width) { init(nodep, width); } // 0=unsized
V3Number(AstNode* nodep, int width, uint32_t value, bool sized=true) {
init(nodep, width, sized); m_value[0] = value; opCleanThis();
V3Number(AstNode* nodep, int width, uint32_t value, bool sized = true) {
init(nodep, width, sized);
m_value[0] = value;
opCleanThis();
}
// Create from a verilog 32'hxxxx number.
V3Number(AstNode* nodep, const char* sourcep) { V3NumberCreate(nodep, sourcep, NULL); }
@ -155,7 +170,10 @@ public:
class VerilogStringLiteral {}; // For creator type-overload selection
V3Number(VerilogStringLiteral, AstNode* nodep, const string& str);
class String {};
V3Number(String, AstNode* nodep, const string& value) { init(nodep, 0); setString(value); }
V3Number(String, AstNode* nodep, const string& value) {
init(nodep, 0);
setString(value);
}
explicit V3Number(const V3Number* nump, int width = 1) {
init(NULL, width);
m_fileline = nump->fileline();
@ -169,7 +187,7 @@ public:
private:
void V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl);
void init(AstNode* nodep, int swidth, bool sized=true) {
void init(AstNode* nodep, int swidth, bool sized = true) {
setNames(nodep);
m_signed = false;
m_double = false;
@ -177,23 +195,27 @@ private:
m_autoExtend = false;
m_fromString = false;
width(swidth, sized);
for (int i=0; i<words(); i++) m_value[i] = m_valueX[i] = 0;
for (int i = 0; i < words(); i++) m_value[i] = m_valueX[i] = 0;
}
void setNames(AstNode* nodep);
static string displayPad(size_t fmtsize, char pad, bool left, const string& in);
string displayed(FileLine* fl, const string& vformat) const;
string displayed(const string& vformat) const {
return displayed(m_fileline, vformat);
}
string displayed(const string& vformat) const { return displayed(m_fileline, vformat); }
public:
void v3errorEnd(std::ostringstream& sstr) const;
void width(int width, bool sized=true) {
void width(int width, bool sized = true) {
// Set width. Only set m_width here, as we need to tweak vector size
if (width) { m_sized = sized; m_width = width; }
else { m_sized = false; m_width = 1; }
if (VL_UNLIKELY(m_value.size() < (unsigned)(words()+1))) {
m_value.resize(words()+1);
m_valueX.resize(words()+1);
if (width) {
m_sized = sized;
m_width = width;
} else {
m_sized = false;
m_width = 1;
}
if (VL_UNLIKELY(m_value.size() < (unsigned)(words() + 1))) {
m_value.resize(words() + 1);
m_valueX.resize(words() + 1);
}
}
@ -206,7 +228,7 @@ public:
V3Number& setMask(int nbits); // IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc
// ACCESSORS
string ascii(bool prefixed=true, bool cleanVerilog=false) const;
string ascii(bool prefixed = true, bool cleanVerilog = false) const;
string displayed(AstNode* nodep, const string& vformat) const;
static bool displayedFmtLegal(char format); // Is this a valid format letter?
int width() const { return m_width; }
@ -214,26 +236,35 @@ public:
bool sized() const { return m_sized; }
bool autoExtend() const { return m_autoExtend; }
bool isFromString() const { return m_fromString; }
bool isSigned() const { return m_signed; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
bool isDouble() const { return m_double; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
void isDouble(bool flag) { m_double = flag; } // Only if have 64 bit value loaded, and want to indicate it's real
// Only correct for parsing of numbers from strings, otherwise not used
// (use AstConst::isSigned())
bool isSigned() const { return m_signed; }
// Only correct for parsing of numbers from strings, otherwise not used
// (use AstConst::isSigned())
bool isDouble() const { return m_double; }
// Only if have 64 bit value loaded, and want to indicate it's real
void isDouble(bool flag) { m_double = flag; }
bool isString() const { return m_isString; }
void isString(bool flag) { m_isString = flag; }
bool isNegative() const { return bitIs1(width()-1); }
void isString(bool flag) { m_isString = flag; }
bool isNegative() const { return bitIs1(width() - 1); }
bool isFourState() const;
bool hasZ() const {
for(int i=0;i<words();i++) { if ((~m_value[i]) & m_valueX[i]) return true; }
for (int i = 0; i < words(); i++) {
if ((~m_value[i]) & m_valueX[i]) return true;
}
return false;
}
bool isAllZ() const {
for(int i=0;i<width();i++) { if (!bitIsZ(i)) return false; }
for (int i = 0; i < width(); i++) {
if (!bitIsZ(i)) return false;
}
return true;
}
bool isEqZero() const;
bool isNeqZero() const;
bool isBitsZero(int msb, int lsb) const;
bool isEqOne() const;
bool isEqAllOnes(int optwidth=0) const;
bool isEqAllOnes(int optwidth = 0) const;
bool isCaseEq(const V3Number& rhs) const; // operator==
bool isLt(const V3Number& rhs) const; // operator<
bool isLtXZ(const V3Number& rhs) const; // operator< with XZ compared
@ -252,7 +283,8 @@ public:
uint32_t edataWord(int eword) const;
uint8_t dataByte(int byte) const;
uint32_t countOnes() const;
uint32_t mostSetBitP1() const; // Highest bit set plus one, IE for 16 return 5, for 0 return 0.
uint32_t
mostSetBitP1() const; // Highest bit set plus one, IE for 16 return 5, for 0 return 0.
// Operators
bool operator<(const V3Number& rhs) const { return isLtXZ(rhs); }
@ -261,127 +293,131 @@ public:
static int log2b(uint32_t num);
typedef V3Number& (*UniopFuncp)(V3Number&);
typedef V3Number& (*BiopFuncp) (V3Number&, V3Number&);
typedef V3Number& (*BiopFuncp)(V3Number&, V3Number&);
// MATH
// "this" is the output, as we need the output width before some computations
V3Number& isTrue (const V3Number& lhs);
V3Number& isTrue(const V3Number& lhs);
V3Number& opBitsNonX(const V3Number& lhs); // 0/1->1, X/Z->0
V3Number& opBitsOne (const V3Number& lhs); // 1->1, 0/X/Z->0
V3Number& opBitsXZ (const V3Number& lhs); // 0/1->0, X/Z->1
V3Number& opBitsZ (const V3Number& lhs); // Z->1, 0/1/X->0
V3Number& opBitsOne(const V3Number& lhs); // 1->1, 0/X/Z->0
V3Number& opBitsXZ(const V3Number& lhs); // 0/1->0, X/Z->1
V3Number& opBitsZ(const V3Number& lhs); // Z->1, 0/1/X->0
V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1
//
V3Number& opAssign (const V3Number& lhs);
V3Number& opAssign(const V3Number& lhs);
V3Number& opAssignNonXZ(const V3Number& lhs, bool ignoreXZ = true);
V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension
V3Number& opExtendS(const V3Number& lhs, uint32_t lbits); // Sign extension
V3Number& opExtendXZ(const V3Number& lhs, uint32_t lbits); // X/Z extension
V3Number& opRedOr (const V3Number& lhs);
V3Number& opRedAnd (const V3Number& lhs);
V3Number& opRedXor (const V3Number& lhs);
V3Number& opRedXnor (const V3Number& lhs);
V3Number& opRedOr(const V3Number& lhs);
V3Number& opRedAnd(const V3Number& lhs);
V3Number& opRedXor(const V3Number& lhs);
V3Number& opRedXnor(const V3Number& lhs);
V3Number& opCountOnes(const V3Number& lhs);
V3Number& opIsUnknown(const V3Number& lhs);
V3Number& opOneHot (const V3Number& lhs);
V3Number& opOneHot0 (const V3Number& lhs);
V3Number& opCLog2 (const V3Number& lhs);
V3Number& opClean (const V3Number& lhs, uint32_t bits);
V3Number& opConcat (const V3Number& lhs, const V3Number& rhs);
V3Number& opLenN (const V3Number& lhs);
V3Number& opRepl (const V3Number& lhs, const V3Number& rhs);
V3Number& opRepl (const V3Number& lhs, uint32_t rhsval);
V3Number& opStreamL (const V3Number& lhs, const V3Number& rhs);
V3Number& opSel (const V3Number& lhs, const V3Number& msb, const V3Number& lsb);
V3Number& opSel (const V3Number& lhs, uint32_t msbval, uint32_t lsbval);
V3Number& opSelInto (const V3Number& lhs, const V3Number& lsb, int width);
V3Number& opSelInto (const V3Number& lhs, int lsbval, int width);
V3Number& opOneHot(const V3Number& lhs);
V3Number& opOneHot0(const V3Number& lhs);
V3Number& opCLog2(const V3Number& lhs);
V3Number& opClean(const V3Number& lhs, uint32_t bits);
V3Number& opConcat(const V3Number& lhs, const V3Number& rhs);
V3Number& opLenN(const V3Number& lhs);
V3Number& opRepl(const V3Number& lhs, const V3Number& rhs);
V3Number& opRepl(const V3Number& lhs, uint32_t rhsval);
V3Number& opStreamL(const V3Number& lhs, const V3Number& rhs);
V3Number& opSel(const V3Number& lhs, const V3Number& msb, const V3Number& lsb);
V3Number& opSel(const V3Number& lhs, uint32_t msbval, uint32_t lsbval);
V3Number& opSelInto(const V3Number& lhs, const V3Number& lsb, int width);
V3Number& opSelInto(const V3Number& lhs, int lsbval, int width);
V3Number& opToLowerN(const V3Number& lhs);
V3Number& opToUpperN(const V3Number& lhs);
V3Number& opCond (const V3Number& lhs, const V3Number& if1s, const V3Number& if0s);
V3Number& opCaseEq (const V3Number& lhs, const V3Number& rhs);
V3Number& opCaseNeq (const V3Number& lhs, const V3Number& rhs);
V3Number& opWildEq (const V3Number& lhs, const V3Number& rhs);
V3Number& opWildNeq (const V3Number& lhs, const V3Number& rhs);
V3Number& opBufIf1 (const V3Number& ens, const V3Number& if1s);
V3Number& opCond(const V3Number& lhs, const V3Number& if1s, const V3Number& if0s);
V3Number& opCaseEq(const V3Number& lhs, const V3Number& rhs);
V3Number& opCaseNeq(const V3Number& lhs, const V3Number& rhs);
V3Number& opWildEq(const V3Number& lhs, const V3Number& rhs);
V3Number& opWildNeq(const V3Number& lhs, const V3Number& rhs);
V3Number& opBufIf1(const V3Number& ens, const V3Number& if1s);
// "standard" math
V3Number& opNot (const V3Number& lhs);
V3Number& opLogNot (const V3Number& lhs);
V3Number& opLogAnd (const V3Number& lhs, const V3Number& rhs);
V3Number& opLogOr (const V3Number& lhs, const V3Number& rhs);
V3Number& opLogEq (const V3Number& lhs, const V3Number& rhs);
V3Number& opLogIf (const V3Number& lhs, const V3Number& rhs);
V3Number& opAbsS (const V3Number& lhs);
V3Number& opNegate (const V3Number& lhs);
V3Number& opAdd (const V3Number& lhs, const V3Number& rhs);
V3Number& opSub (const V3Number& lhs, const V3Number& rhs);
V3Number& opMul (const V3Number& lhs, const V3Number& rhs);
V3Number& opMulS (const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opDiv (const V3Number& lhs, const V3Number& rhs);
V3Number& opDivS (const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opModDiv (const V3Number& lhs, const V3Number& rhs);
V3Number& opModDivS (const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opPow (const V3Number& lhs, const V3Number& rhs, bool lsign=false, bool rsign=false);
V3Number& opPowSU (const V3Number& lhs, const V3Number& rhs); // Signed lhs, unsigned rhs
V3Number& opPowSS (const V3Number& lhs, const V3Number& rhs); // Signed lhs, signed rhs
V3Number& opPowUS (const V3Number& lhs, const V3Number& rhs); // Unsigned lhs, signed rhs
V3Number& opAnd (const V3Number& lhs, const V3Number& rhs);
V3Number& opNot(const V3Number& lhs);
V3Number& opLogNot(const V3Number& lhs);
V3Number& opLogAnd(const V3Number& lhs, const V3Number& rhs);
V3Number& opLogOr(const V3Number& lhs, const V3Number& rhs);
V3Number& opLogEq(const V3Number& lhs, const V3Number& rhs);
V3Number& opLogIf(const V3Number& lhs, const V3Number& rhs);
V3Number& opAbsS(const V3Number& lhs);
V3Number& opNegate(const V3Number& lhs);
V3Number& opAdd(const V3Number& lhs, const V3Number& rhs);
V3Number& opSub(const V3Number& lhs, const V3Number& rhs);
V3Number& opMul(const V3Number& lhs, const V3Number& rhs);
V3Number& opMulS(const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opDiv(const V3Number& lhs, const V3Number& rhs);
V3Number& opDivS(const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opModDiv(const V3Number& lhs, const V3Number& rhs);
V3Number& opModDivS(const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opPow(const V3Number& lhs, const V3Number& rhs, bool lsign = false,
bool rsign = false);
V3Number& opPowSU(const V3Number& lhs, const V3Number& rhs); // Signed lhs, unsigned rhs
V3Number& opPowSS(const V3Number& lhs, const V3Number& rhs); // Signed lhs, signed rhs
V3Number& opPowUS(const V3Number& lhs, const V3Number& rhs); // Unsigned lhs, signed rhs
V3Number& opAnd(const V3Number& lhs, const V3Number& rhs);
V3Number& opChangeXor(const V3Number& lhs, const V3Number& rhs);
V3Number& opXor (const V3Number& lhs, const V3Number& rhs);
V3Number& opXnor (const V3Number& lhs, const V3Number& rhs);
V3Number& opOr (const V3Number& lhs, const V3Number& rhs);
V3Number& opRotR (const V3Number& lhs, const V3Number& rhs);
V3Number& opRotL (const V3Number& lhs, const V3Number& rhs);
V3Number& opShiftR (const V3Number& lhs, const V3Number& rhs);
V3Number& opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_t lbits); // Arithmetic w/carry
V3Number& opShiftL (const V3Number& lhs, const V3Number& rhs);
V3Number& opXor(const V3Number& lhs, const V3Number& rhs);
V3Number& opXnor(const V3Number& lhs, const V3Number& rhs);
V3Number& opOr(const V3Number& lhs, const V3Number& rhs);
V3Number& opRotR(const V3Number& lhs, const V3Number& rhs);
V3Number& opRotL(const V3Number& lhs, const V3Number& rhs);
V3Number& opShiftR(const V3Number& lhs, const V3Number& rhs);
V3Number& opShiftRS(const V3Number& lhs, const V3Number& rhs, // Arithmetic w/carry
uint32_t lbits);
V3Number& opShiftL(const V3Number& lhs, const V3Number& rhs);
// Comparisons
V3Number& opEq (const V3Number& lhs, const V3Number& rhs);
V3Number& opNeq (const V3Number& lhs, const V3Number& rhs);
V3Number& opGt (const V3Number& lhs, const V3Number& rhs);
V3Number& opGtS (const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opGte (const V3Number& lhs, const V3Number& rhs);
V3Number& opGteS (const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opLt (const V3Number& lhs, const V3Number& rhs);
V3Number& opLtS (const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opLte (const V3Number& lhs, const V3Number& rhs);
V3Number& opLteS (const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opEq(const V3Number& lhs, const V3Number& rhs);
V3Number& opNeq(const V3Number& lhs, const V3Number& rhs);
V3Number& opGt(const V3Number& lhs, const V3Number& rhs);
V3Number& opGtS(const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opGte(const V3Number& lhs, const V3Number& rhs);
V3Number& opGteS(const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opLt(const V3Number& lhs, const V3Number& rhs);
V3Number& opLtS(const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opLte(const V3Number& lhs, const V3Number& rhs);
V3Number& opLteS(const V3Number& lhs, const V3Number& rhs); // Signed
// "D" - double (aka real) math
V3Number& opIToRD (const V3Number& lhs);
V3Number& opRToIS (const V3Number& lhs);
V3Number& opIToRD(const V3Number& lhs);
V3Number& opRToIS(const V3Number& lhs);
V3Number& opRToIRoundS(const V3Number& lhs);
V3Number& opRealToBits(const V3Number& lhs);
V3Number& opBitsToRealD(const V3Number& lhs);
V3Number& opNegateD (const V3Number& lhs);
V3Number& opAddD (const V3Number& lhs, const V3Number& rhs);
V3Number& opSubD (const V3Number& lhs, const V3Number& rhs);
V3Number& opMulD (const V3Number& lhs, const V3Number& rhs);
V3Number& opDivD (const V3Number& lhs, const V3Number& rhs);
V3Number& opPowD (const V3Number& lhs, const V3Number& rhs);
V3Number& opNegateD(const V3Number& lhs);
V3Number& opAddD(const V3Number& lhs, const V3Number& rhs);
V3Number& opSubD(const V3Number& lhs, const V3Number& rhs);
V3Number& opMulD(const V3Number& lhs, const V3Number& rhs);
V3Number& opDivD(const V3Number& lhs, const V3Number& rhs);
V3Number& opPowD(const V3Number& lhs, const V3Number& rhs);
// Comparisons
V3Number& opEqD (const V3Number& lhs, const V3Number& rhs);
V3Number& opNeqD (const V3Number& lhs, const V3Number& rhs);
V3Number& opGtD (const V3Number& lhs, const V3Number& rhs);
V3Number& opGteD (const V3Number& lhs, const V3Number& rhs);
V3Number& opLtD (const V3Number& lhs, const V3Number& rhs);
V3Number& opLteD (const V3Number& lhs, const V3Number& rhs);
V3Number& opEqD(const V3Number& lhs, const V3Number& rhs);
V3Number& opNeqD(const V3Number& lhs, const V3Number& rhs);
V3Number& opGtD(const V3Number& lhs, const V3Number& rhs);
V3Number& opGteD(const V3Number& lhs, const V3Number& rhs);
V3Number& opLtD(const V3Number& lhs, const V3Number& rhs);
V3Number& opLteD(const V3Number& lhs, const V3Number& rhs);
// "N" - string operations
V3Number& opAtoN (const V3Number& lhs, int base);
V3Number& opPutcN (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
V3Number& opGetcN (const V3Number& lhs, const V3Number& rhs);
V3Number& opSubstrN (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
V3Number& opCompareNN(const V3Number& lhs,const V3Number& rhs, bool ignoreCase);
V3Number& opConcatN (const V3Number& lhs, const V3Number& rhs);
V3Number& opReplN (const V3Number& lhs, const V3Number& rhs);
V3Number& opReplN (const V3Number& lhs, uint32_t rhsval);
V3Number& opEqN (const V3Number& lhs, const V3Number& rhs);
V3Number& opNeqN (const V3Number& lhs, const V3Number& rhs);
V3Number& opGtN (const V3Number& lhs, const V3Number& rhs);
V3Number& opGteN (const V3Number& lhs, const V3Number& rhs);
V3Number& opLtN (const V3Number& lhs, const V3Number& rhs);
V3Number& opLteN (const V3Number& lhs, const V3Number& rhs);
V3Number& opAtoN(const V3Number& lhs, int base);
V3Number& opPutcN(const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
V3Number& opGetcN(const V3Number& lhs, const V3Number& rhs);
V3Number& opSubstrN(const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
V3Number& opCompareNN(const V3Number& lhs, const V3Number& rhs, bool ignoreCase);
V3Number& opConcatN(const V3Number& lhs, const V3Number& rhs);
V3Number& opReplN(const V3Number& lhs, const V3Number& rhs);
V3Number& opReplN(const V3Number& lhs, uint32_t rhsval);
V3Number& opEqN(const V3Number& lhs, const V3Number& rhs);
V3Number& opNeqN(const V3Number& lhs, const V3Number& rhs);
V3Number& opGtN(const V3Number& lhs, const V3Number& rhs);
V3Number& opGteN(const V3Number& lhs, const V3Number& rhs);
V3Number& opLtN(const V3Number& lhs, const V3Number& rhs);
V3Number& opLteN(const V3Number& lhs, const V3Number& rhs);
};
inline std::ostream& operator<<(std::ostream& os, const V3Number& rhs) { return os<<rhs.ascii(); }
inline std::ostream& operator<<(std::ostream& os, const V3Number& rhs) {
return os << rhs.ascii();
}
#endif // Guard

File diff suppressed because it is too large Load Diff

View File

@ -74,41 +74,42 @@ private:
// // (0=not processed, 1=iterated, but no number,
// // 65+ parameter numbered)
// AstCell::user5p() // string* Generate portion of hierarchical name
AstUser4InUse m_inuser4;
AstUser5InUse m_inuser5;
AstUser4InUse m_inuser4;
AstUser5InUse m_inuser5;
// User1/2/3 used by constant function simulations
// TYPES
typedef std::deque<std::pair<AstIfaceRefDType*,AstIfaceRefDType*> > IfaceRefRefs; // Note may have duplicate entries
// Note may have duplicate entries
typedef std::deque<std::pair<AstIfaceRefDType*, AstIfaceRefDType*> > IfaceRefRefs;
// STATE
typedef std::map<AstNode*,AstNode*> CloneMap;
typedef std::map<AstNode*, AstNode*> CloneMap;
struct ModInfo {
AstNodeModule* m_modp; // Module with specified name
CloneMap m_cloneMap; // Map of old-varp -> new cloned varp
AstNodeModule* m_modp; // Module with specified name
CloneMap m_cloneMap; // Map of old-varp -> new cloned varp
explicit ModInfo(AstNodeModule* modp) { m_modp = modp; }
};
typedef std::map<string,ModInfo> ModNameMap;
ModNameMap m_modNameMap; // Hash of created module flavors by name
typedef std::map<string, ModInfo> ModNameMap;
ModNameMap m_modNameMap; // Hash of created module flavors by name
typedef std::map<string,string> LongMap;
LongMap m_longMap; // Hash of very long names to unique identity number
int m_longId;
typedef std::map<string, string> LongMap;
LongMap m_longMap; // Hash of very long names to unique identity number
int m_longId;
typedef std::pair<int,string> ValueMapValue;
typedef std::map<V3Hash,ValueMapValue> ValueMap;
ValueMap m_valueMap; // Hash of node hash to (param value, name)
int m_nextValue; // Next value to use in m_valueMap
typedef std::pair<int, string> ValueMapValue;
typedef std::map<V3Hash, ValueMapValue> ValueMap;
ValueMap m_valueMap; // Hash of node hash to (param value, name)
int m_nextValue; // Next value to use in m_valueMap
typedef std::multimap<int,AstNodeModule*> LevelModMap;
LevelModMap m_todoModps; // Modules left to process
typedef std::multimap<int, AstNodeModule*> LevelModMap;
LevelModMap m_todoModps; // Modules left to process
typedef std::deque<AstCell*> CellList;
CellList m_cellps; // Cells left to process (in this module)
CellList m_cellps; // Cells left to process (in this module)
AstNodeModule* m_modp; // Current module being processed
string m_unlinkedTxt; // Text for AstUnlinkedRef
string m_unlinkedTxt; // Text for AstUnlinkedRef
UnrollStateful m_unroller; // Loop unroller
@ -118,32 +119,32 @@ private:
VL_DEBUG_FUNC; // Declare debug()
void makeSmallNames(AstNodeModule* modp) {
std::vector<int> usedLetter; usedLetter.resize(256);
std::vector<int> usedLetter;
usedLetter.resize(256);
// Pass 1, assign first letter to each gparam's name
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* varp = VN_CAST(stmtp, Var)) {
if (varp->isGParam()||varp->isIfaceRef()) {
if (varp->isGParam() || varp->isIfaceRef()) {
char ch = varp->name()[0];
ch = toupper(ch); if (ch<'A' || ch>'Z') ch='Z';
varp->user4(usedLetter[static_cast<int>(ch)]*256 + ch);
ch = toupper(ch);
if (ch < 'A' || ch > 'Z') ch = 'Z';
varp->user4(usedLetter[static_cast<int>(ch)] * 256 + ch);
usedLetter[static_cast<int>(ch)]++;
}
} else if (AstParamTypeDType* typep = VN_CAST(stmtp, ParamTypeDType)) {
char ch = 'T';
typep->user4(usedLetter[static_cast<int>(ch)]*256 + ch);
typep->user4(usedLetter[static_cast<int>(ch)] * 256 + ch);
usedLetter[static_cast<int>(ch)]++;
}
}
}
string paramSmallName(AstNodeModule* modp, AstNode* varp) {
if (varp->user4()<=1) {
makeSmallNames(modp);
}
int index = varp->user4()/256;
char ch = varp->user4()&255;
if (varp->user4() <= 1) makeSmallNames(modp);
int index = varp->user4() / 256;
char ch = varp->user4() & 255;
string st = cvtToStr(ch);
while (index) {
st += cvtToStr(char((index%25)+'A'));
st += cvtToStr(char((index % 25) + 'A'));
index /= 26;
}
return st;
@ -155,19 +156,17 @@ private:
key = ifrtp->cellp()->modp()->name();
} else if (ifrtp->ifacep()) {
key = ifrtp->ifacep()->name();
} else {
} else {
nodep->v3fatalSrc("Can't parameterize interface without module name");
}
} else if (AstBasicDType* bdtp = VN_CAST(nodep, BasicDType)) {
if (bdtp->isRanged()) {
key += "["+cvtToStr(bdtp->left())+":"+cvtToStr(bdtp->right())+"]";
key += "[" + cvtToStr(bdtp->left()) + ":" + cvtToStr(bdtp->right()) + "]";
}
}
V3Hash hash = V3Hashed::uncachedHash(nodep);
// Force hash collisions -- for testing only
if (VL_UNLIKELY(v3Global.opt.debugCollision())) {
hash = V3Hash();
}
if (VL_UNLIKELY(v3Global.opt.debugCollision())) hash = V3Hash();
int num;
ValueMap::iterator it = m_valueMap.find(hash);
if (it != m_valueMap.end() && it->second.second == key) {
@ -176,20 +175,20 @@ private:
num = m_nextValue++;
m_valueMap[hash] = make_pair(num, key);
}
return string("z")+cvtToStr(num);
return string("z") + cvtToStr(num);
}
void collectPins(CloneMap* clonemapp, AstNodeModule* modp) {
// Grab all I/O so we can remap our pins later
for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* varp = VN_CAST(stmtp, Var)) {
if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
// Cloning saved a pointer to the new node for us, so just follow that link.
AstVar* oldvarp = varp->clonep();
//UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp<<" -> 0x"<<(uint32_t)varp<<endl);
// UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp
// <<" -> 0x"<<(uint32_t)varp<<endl);
clonemapp->insert(make_pair(oldvarp, varp));
}
}
else if (AstParamTypeDType* ptp = VN_CAST(stmtp, ParamTypeDType)) {
} else if (AstParamTypeDType* ptp = VN_CAST(stmtp, ParamTypeDType)) {
if (ptp->isGParam()) {
AstParamTypeDType* oldptp = ptp->clonep();
clonemapp->insert(make_pair(oldptp, ptp));
@ -198,22 +197,20 @@ private:
}
}
void relinkPins(CloneMap* clonemapp, AstPin* startpinp) {
for (AstPin* pinp = startpinp; pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
for (AstPin* pinp = startpinp; pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
if (pinp->modVarp()) {
// Find it in the clone structure
//UINFO(8,"Clone find 0x"<<hex<<(uint32_t)pinp->modVarp()<<endl);
// UINFO(8,"Clone find 0x"<<hex<<(uint32_t)pinp->modVarp()<<endl);
CloneMap::iterator cloneiter = clonemapp->find(pinp->modVarp());
UASSERT_OBJ(cloneiter != clonemapp->end(), pinp,
"Couldn't find pin in clone list");
pinp->modVarp(VN_CAST(cloneiter->second, Var));
}
else if (pinp->modPTypep()) {
} else if (pinp->modPTypep()) {
CloneMap::iterator cloneiter = clonemapp->find(pinp->modPTypep());
UASSERT_OBJ(cloneiter != clonemapp->end(), pinp,
"Couldn't find pin in clone list");
pinp->modPTypep(VN_CAST(cloneiter->second, ParamTypeDType));
}
else {
} else {
pinp->v3fatalSrc("Not linked?");
}
}
@ -227,30 +224,31 @@ private:
LevelModMap::iterator itm = m_todoModps.begin();
AstNodeModule* nodep = itm->second;
m_todoModps.erase(itm);
if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it again
if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it
// again
m_modp = nodep;
UINFO(4," MOD "<<nodep<<endl);
UINFO(4, " MOD " << nodep << endl);
if (m_modp->hierName().empty()) m_modp->hierName(m_modp->origName());
iterateChildren(nodep);
// Note above iterate may add to m_todoModps
//
// Process interface cells, then non-interface which may ref an interface cell
for (int nonIf=0; nonIf<2; ++nonIf) {
for (CellList::iterator it=m_cellps.begin(); it!=m_cellps.end(); ++it) {
for (int nonIf = 0; nonIf < 2; ++nonIf) {
for (CellList::iterator it = m_cellps.begin(); it != m_cellps.end(); ++it) {
AstCell* cellp = *it;
if ((nonIf==0 && VN_IS(cellp->modp(), Iface))
|| (nonIf==1 && !VN_IS(cellp->modp(), Iface))) {
string fullName (m_modp->hierName());
if (string* genHierNamep = (string *) cellp->user5p()) {
if ((nonIf == 0 && VN_IS(cellp->modp(), Iface))
|| (nonIf == 1 && !VN_IS(cellp->modp(), Iface))) {
string fullName(m_modp->hierName());
if (string* genHierNamep = (string*)cellp->user5p()) {
fullName += *genHierNamep;
}
visitCell(cellp, fullName);
}
}
}
for (CellList::iterator it=m_cellps.begin(); it!=m_cellps.end(); ++it) {
for (CellList::iterator it = m_cellps.begin(); it != m_cellps.end(); ++it) {
AstCell* cellp = *it;
if (string* genHierNamep = (string *) cellp->user5p()) {
if (string* genHierNamep = (string*)cellp->user5p()) {
cellp->user5p(NULL);
VL_DO_DANGLING(delete genHierNamep, genHierNamep);
}
@ -268,9 +266,10 @@ private:
}
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
if (nodep->dead()) {
UINFO(4," MOD-dead. "<<nodep<<endl); // Marked by LinkDot
UINFO(4, " MOD-dead. " << nodep << endl); // Marked by LinkDot
} else if (nodep->recursiveClone()) {
UINFO(4," MOD-recursive-dead. "<<nodep<<endl); // Fake, made for recursive elimination
// Fake, made for recursive elimination
UINFO(4, " MOD-recursive-dead. " << nodep << endl);
nodep->dead(true); // So Dead checks won't count references to it
} else if (nodep->level() <= 2 // Haven't added top yet, so level 2 is the top
|| VN_IS(nodep, Package)) { // Likewise haven't done wrapTopPackages yet
@ -279,9 +278,10 @@ private:
m_generateHierName = "";
visitModules();
} else if (nodep->user5()) {
UINFO(4," MOD-done "<<nodep<<endl); // Already did it
UINFO(4, " MOD-done " << nodep << endl); // Already did it
} else {
UINFO(4," MOD-dead? "<<nodep<<endl); // Should have been done by now, if not dead
// Should have been done by now, if not dead
UINFO(4, " MOD-dead? " << nodep << endl);
}
}
virtual void visit(AstCell* nodep) VL_OVERRIDE {
@ -298,20 +298,18 @@ private:
if (nodep->isParam()) {
if (!nodep->valuep()) {
nodep->v3error("Parameter without initial value is never given value"
<<" (IEEE 1800-2017 6.20.1): "
<<nodep->prettyNameQ());
<< " (IEEE 1800-2017 6.20.1): " << nodep->prettyNameQ());
} else {
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
if (!VN_IS(nodep->valuep(), Const)) { // Complex init, like an array
// Make a new INITIAL to set the value.
// This allows the normal array/struct handling code to properly
// initialize the parameter.
nodep->addNext(
new AstInitial(nodep->fileline(),
new AstAssign(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
nodep->valuep()->cloneTree(true))));
nodep->addNext(new AstInitial(
nodep->fileline(),
new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
nodep->valuep()->cloneTree(true))));
}
}
}
@ -325,11 +323,11 @@ private:
for (; candp; candp = candp->nextp()) {
if (nodep->name() == candp->name()) {
if (AstVar* varp = VN_CAST(candp, Var)) {
UINFO(9,"Found interface parameter: "<<varp<<endl);
UINFO(9, "Found interface parameter: " << varp << endl);
nodep->varp(varp);
return true;
} else if (AstPin* pinp = VN_CAST(candp, Pin)) {
UINFO(9,"Found interface parameter: "<<pinp<<endl);
UINFO(9, "Found interface parameter: " << pinp << endl);
UASSERT_OBJ(pinp->exprp(), pinp, "Interface parameter pin missing expression");
VL_DO_DANGLING(nodep->replaceWith(pinp->exprp()->cloneTree(false)), nodep);
return true;
@ -345,11 +343,10 @@ private:
AstNode* backp = nodep;
while ((backp = backp->backp())) {
if (VN_IS(backp, NodeModule)) {
UINFO(9,"Hit module boundary, done looking for interface"<<endl);
UINFO(9, "Hit module boundary, done looking for interface" << endl);
break;
}
if (VN_IS(backp, Var)
&& VN_CAST(backp, Var)->isIfaceRef()
if (VN_IS(backp, Var) && VN_CAST(backp, Var)->isIfaceRef()
&& VN_CAST(backp, Var)->childDTypep()
&& (VN_CAST(VN_CAST(backp, Var)->childDTypep(), IfaceRefDType)
|| (VN_CAST(VN_CAST(backp, Var)->childDTypep(), UnpackArrayDType)
@ -364,8 +361,8 @@ private:
// Interfaces passed in on the port map have ifaces
if (AstIface* ifacep = ifacerefp->ifacep()) {
if (dotted == backp->name()) {
UINFO(9,"Iface matching scope: "<<ifacep<<endl);
if (ifaceParamReplace(nodep, ifacep->stmtsp())) {
UINFO(9, "Iface matching scope: " << ifacep << endl);
if (ifaceParamReplace(nodep, ifacep->stmtsp())) { //
return;
}
}
@ -373,8 +370,8 @@ private:
// Interfaces declared in this module have cells
else if (AstCell* cellp = ifacerefp->cellp()) {
if (dotted == cellp->name()) {
UINFO(9,"Iface matching scope: "<<cellp<<endl);
if (ifaceParamReplace(nodep, cellp->paramsp())) {
UINFO(9, "Iface matching scope: " << cellp << endl);
if (ifaceParamReplace(nodep, cellp->paramsp())) { //
return;
}
}
@ -414,21 +411,21 @@ private:
size_t pos = m_unlinkedTxt.find(replacestr);
if (pos == string::npos) {
nodep->v3error("Could not find array index in unlinked text: '"
<<m_unlinkedTxt<<"' for node: "<<nodep);
<< m_unlinkedTxt << "' for node: " << nodep);
return;
}
m_unlinkedTxt.replace(pos, replacestr.length(),
nodep->name()+"__BRA__"+index+"__KET__");
nodep->name() + "__BRA__" + index + "__KET__");
} else {
nodep->v3error("Could not expand constant selection inside dotted reference: "
<<nodep->selp()->prettyNameQ());
<< nodep->selp()->prettyNameQ());
return;
}
}
// Generate Statements
virtual void visit(AstGenIf* nodep) VL_OVERRIDE {
UINFO(9," GENIF "<<nodep<<endl);
UINFO(9, " GENIF " << nodep << endl);
iterateAndNextNull(nodep->condp());
// We suppress errors when widthing params since short-circuiting in
// the conditional evaluation may mean these error can never occur. We
@ -437,9 +434,7 @@ private:
// NOT recurse the body.
V3Const::constifyGenerateParamsEdit(nodep->condp()); // condp may change
if (const AstConst* constp = VN_CAST(nodep->condp(), Const)) {
AstNode* keepp = (constp->isZero()
? nodep->elsesp()
: nodep->ifsp());
AstNode* keepp = (constp->isZero() ? nodep->elsesp() : nodep->ifsp());
if (keepp) {
keepp->unlinkFrBackWithNext();
nodep->replaceWith(keepp);
@ -463,8 +458,8 @@ private:
UASSERT_OBJ(forp, nodep, "Non-GENFOR under generate-for BEGIN");
// We should have a GENFOR under here. We will be replacing the begin,
// so process here rather than at the generate to avoid iteration problems
UINFO(9," BEGIN "<<nodep<<endl);
UINFO(9," GENFOR "<<forp<<endl);
UINFO(9, " BEGIN " << nodep << endl);
UINFO(9, " GENFOR " << forp << endl);
V3Width::widthParamsEdit(forp); // Param typed widthing will NOT recurse the body
// Outer wrapper around generate used to hold genvar, and to ensure genvar
// doesn't conflict in V3LinkDot resolution with other genvars
@ -494,7 +489,7 @@ private:
nodep->v3fatalSrc("GENFOR should have been wrapped in BEGIN");
}
virtual void visit(AstGenCase* nodep) VL_OVERRIDE {
UINFO(9," GENCASE "<<nodep<<endl);
UINFO(9, " GENCASE " << nodep << endl);
AstNode* keepp = NULL;
iterateAndNextNull(nodep->exprp());
V3Case::caseLint(nodep);
@ -503,9 +498,9 @@ private:
V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change
AstConst* exprp = VN_CAST(nodep->exprp(), Const);
// Constify
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* ep = itemp->condsp(); ep; ) {
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* ep = itemp->condsp(); ep;) {
AstNode* nextp = ep->nextp(); // May edit list
iterateAndNextNull(ep);
VL_DO_DANGLING(V3Const::constifyParamsEdit(ep), ep); // ep may change
@ -513,16 +508,14 @@ private:
}
}
// Item match
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) {
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
if (!itemp->isDefault()) {
for (AstNode* ep = itemp->condsp(); ep; ep=ep->nextp()) {
for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) {
if (const AstConst* ccondp = VN_CAST(ep, Const)) {
V3Number match (nodep, 1);
V3Number match(nodep, 1);
match.opEq(ccondp->num(), exprp->num());
if (!keepp && match.isNeqZero()) {
keepp = itemp->bodysp();
}
if (!keepp && match.isNeqZero()) keepp = itemp->bodysp();
} else {
itemp->v3error("Generate Case item does not evaluate to constant");
}
@ -530,8 +523,8 @@ private:
}
}
// Else default match
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) {
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
if (itemp->isDefault()) {
if (!keepp) keepp = itemp->bodysp();
}
@ -540,8 +533,9 @@ private:
if (keepp) {
keepp->unlinkFrBackWithNext();
nodep->replaceWith(keepp);
} else {
nodep->unlinkFrBack();
}
else nodep->unlinkFrBack();
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
@ -569,9 +563,9 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
// We always run this, even if no parameters, as need to look for interfaces,
// and remove any recursive references
{
UINFO(4,"De-parameterize: "<<nodep<<endl);
UINFO(4, "De-parameterize: " << nodep << endl);
// Create new module name with _'s between the constants
if (debug()>=10) nodep->dumpTree(cout, "-cell: ");
if (debug() >= 10) nodep->dumpTree(cout, "-cell: ");
// Evaluate all module constants
V3Const::constifyParamsEdit(nodep);
AstNodeModule* srcModp = nodep->modp();
@ -579,18 +573,19 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
// Make sure constification worked
// Must be a separate loop, as constant conversion may have changed some pointers.
//if (debug()) nodep->dumpTree(cout, "-cel2: ");
// if (debug()) nodep->dumpTree(cout, "-cel2: ");
string longname = srcModp->name();
bool any_overrides = false;
if (nodep->recursive()) any_overrides = true; // Must always clone __Vrcm (recursive modules)
// Must always clone __Vrcm (recursive modules)
if (nodep->recursive()) any_overrides = true;
longname += "_";
if (debug()>8) nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: ");
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
if (debug() > 8) nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: ");
for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
if (!pinp->exprp()) continue; // No-connect
if (AstVar* modvarp = pinp->modVarp()) {
if (!modvarp->isGParam()) {
pinp->v3error("Attempted parameter setting of non-parameter: Param "
<<pinp->prettyNameQ()<<" of "<<nodep->prettyNameQ());
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
} else if (VN_IS(pinp->exprp(), InitArray)
&& VN_IS(modvarp->subDTypep(), UnpackArrayDType)) {
// Array assigned to array
@ -601,21 +596,19 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
AstConst* exprp = VN_CAST(pinp->exprp(), Const);
AstConst* origp = VN_CAST(modvarp->valuep(), Const);
if (!exprp) {
//if (debug()) pinp->dumpTree(cout, "error:");
// if (debug()) pinp->dumpTree(cout, "error:");
pinp->v3error("Can't convert defparam value to constant: Param "
<<pinp->prettyNameQ()<<" of "<<nodep->prettyNameQ());
pinp->exprp()->replaceWith(
new AstConst(pinp->fileline(),
AstConst::WidthedValue(), modvarp->width(), 0));
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
pinp->exprp()->replaceWith(new AstConst(
pinp->fileline(), AstConst::WidthedValue(), modvarp->width(), 0));
} else if (origp && exprp->sameTree(origp)) {
// Setting parameter to its default value. Just ignore it.
// This prevents making additional modules, and makes coverage more
// obvious as it won't show up under a unique module page name.
} else if (exprp->num().isDouble()
|| exprp->num().isString()
|| exprp->num().isFourState()) {
longname += ("_" + paramSmallName(srcModp, modvarp)
+ paramValueNumber(exprp));
} else if (exprp->num().isDouble() || exprp->num().isString()
|| exprp->num().isFourState()) {
longname
+= ("_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp));
any_overrides = true;
} else {
longname += ("_" + paramSmallName(srcModp, modvarp)
@ -628,75 +621,92 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
AstNodeDType* origp = modvarp->subDTypep();
if (!exprp) {
pinp->v3error("Parameter type pin value isn't a type: Param "
<<pinp->prettyNameQ()<<" of "<<nodep->prettyNameQ());
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
} else if (!origp) {
pinp->v3error("Parameter type variable isn't a type: Param "
<<modvarp->prettyNameQ());
<< modvarp->prettyNameQ());
} else {
UINFO(9,"Parameter type assignment expr="<<exprp<<" to "<<origp<<endl);
UINFO(9,
"Parameter type assignment expr=" << exprp << " to " << origp << endl);
if (exprp->sameTree(origp)) {
// Setting parameter to its default value. Just ignore it.
// This prevents making additional modules, and makes coverage more
// obvious as it won't show up under a unique module page name.
} else {
V3Const::constifyParamsEdit(exprp);
longname += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp);
longname
+= "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp);
any_overrides = true;
}
}
} else {
pinp->v3error("Parameter not found in sub-module: Param "
<<pinp->prettyNameQ()<<" of "<<nodep->prettyNameQ());
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
}
}
IfaceRefRefs ifaceRefRefs;
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
AstVar* modvarp = pinp->modVarp();
if (modvarp->isIfaceRef()) {
AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType);
if (!portIrefp && VN_IS(modvarp->subDTypep(), UnpackArrayDType)) {
portIrefp = VN_CAST(VN_CAST(modvarp->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType);
portIrefp
= VN_CAST(VN_CAST(modvarp->subDTypep(), UnpackArrayDType)->subDTypep(),
IfaceRefDType);
}
AstIfaceRefDType* pinIrefp = NULL;
AstNode* exprp = pinp->exprp();
if (exprp
&& VN_IS(exprp, VarRef)
&& VN_CAST(exprp, VarRef)->varp()
if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp()
&& VN_CAST(exprp, VarRef)->varp()->subDTypep()
&& VN_IS(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType)) {
pinIrefp = VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType);
} else if (exprp
&& exprp->op1p()
&& VN_IS(exprp->op1p(), VarRef)
} else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef)
&& VN_CAST(exprp->op1p(), VarRef)->varp()
&& VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()
&& VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType)
&& VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep()
&& VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) {
pinIrefp = VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType);
} else if (exprp
&& VN_IS(exprp, VarRef)
&& VN_CAST(exprp, VarRef)->varp()
&& VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
UnpackArrayDType)
&& VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
UnpackArrayDType)
->subDTypep()
&& VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
UnpackArrayDType)
->subDTypep(),
IfaceRefDType)) {
pinIrefp = VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
UnpackArrayDType)
->subDTypep(),
IfaceRefDType);
} else if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp()
&& VN_CAST(exprp, VarRef)->varp()->subDTypep()
&& VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)
&& VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep()
&& VN_CAST(VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) {
pinIrefp = VN_CAST(VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType);
&& VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(),
UnpackArrayDType)
&& VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(),
UnpackArrayDType)
->subDTypep()
&& VN_CAST(VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(),
UnpackArrayDType)
->subDTypep(),
IfaceRefDType)) {
pinIrefp = VN_CAST(
VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)
->subDTypep(),
IfaceRefDType);
}
UINFO(9," portIfaceRef "<<portIrefp<<endl);
UINFO(9, " portIfaceRef " << portIrefp << endl);
if (!portIrefp) {
pinp->v3error("Interface port "<<modvarp->prettyNameQ()
<<" is not an interface " << modvarp);
pinp->v3error("Interface port " << modvarp->prettyNameQ()
<< " is not an interface " << modvarp);
} else if (!pinIrefp) {
pinp->v3error("Interface port "<<modvarp->prettyNameQ()
<<" is not connected to interface/modport pin expression");
pinp->v3error("Interface port "
<< modvarp->prettyNameQ()
<< " is not connected to interface/modport pin expression");
} else {
UINFO(9," pinIfaceRef "<<pinIrefp<<endl);
UINFO(9, " pinIfaceRef " << pinIrefp << endl);
if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) {
UINFO(9," IfaceRefDType needs reconnect "<<pinIrefp<<endl);
UINFO(9, " IfaceRefDType needs reconnect " << pinIrefp << endl);
longname += ("_" + paramSmallName(srcModp, pinp->modVarp())
+ paramValueNumber(pinIrefp));
any_overrides = true;
@ -704,11 +714,11 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
if (portIrefp->ifacep() != pinIrefp->ifacep()
// Might be different only due to param cloning, so check names too
&& portIrefp->ifaceName() != pinIrefp->ifaceName()) {
pinp->v3error("Port "<<pinp->prettyNameQ()<<" expects "
<<AstNode::prettyNameQ(portIrefp->ifaceName())
<<" interface but pin connects "
<<AstNode::prettyNameQ(pinIrefp->ifaceName())
<<" interface");
pinp->v3error("Port " << pinp->prettyNameQ() << " expects "
<< AstNode::prettyNameQ(portIrefp->ifaceName())
<< " interface but pin connects "
<< AstNode::prettyNameQ(pinIrefp->ifaceName())
<< " interface");
}
}
}
@ -716,23 +726,24 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
}
if (!any_overrides) {
UINFO(8,"Cell parameters all match original values, skipping expansion.\n");
UINFO(8, "Cell parameters all match original values, skipping expansion.\n");
} else {
// If the name is very long, we don't want to overwhelm the filename limit
// We don't do this always, as it aids debugability to have intuitive naming.
// TODO can use new V3Name hash replacement instead of this
string newname = longname;
if (longname.length()>30) {
if (longname.length() > 30) {
LongMap::iterator iter = m_longMap.find(longname);
if (iter != m_longMap.end()) {
newname = iter->second;
} else {
newname = srcModp->name();
newname += "__pi"+cvtToStr(++m_longId); // We use all upper case above, so lower here can't conflict
// We use all upper case above, so lower here can't conflict
newname += "__pi" + cvtToStr(++m_longId);
m_longMap.insert(make_pair(longname, newname));
}
}
UINFO(4,"Name: "<<srcModp->name()<<"->"<<longname<<"->"<<newname<<endl);
UINFO(4, "Name: " << srcModp->name() << "->" << longname << "->" << newname << endl);
//
// Already made this flavor?
@ -750,11 +761,11 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
cellmodp->recursiveClone(false);
nodep->recursive(false);
// Recursion may need level cleanups
if (cellmodp->level() <= m_modp->level()) cellmodp->level(m_modp->level()+1);
if (cellmodp->level() <= m_modp->level()) cellmodp->level(m_modp->level() + 1);
if ((cellmodp->level() - srcModp->level())
>= (v3Global.opt.moduleRecursionDepth() - 2)) {
nodep->v3error("Exceeded maximum --module-recursion-depth of "
<<v3Global.opt.moduleRecursionDepth());
<< v3Global.opt.moduleRecursionDepth());
}
// Keep tree sorted by level
AstNodeModule* insertp = srcModp;
@ -767,7 +778,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
m_modNameMap.insert(make_pair(cellmodp->name(), ModInfo(cellmodp)));
iter = m_modNameMap.find(newname);
CloneMap* clonemapp = &(iter->second.m_cloneMap);
UINFO(4," De-parameterize to new: "<<cellmodp<<endl);
UINFO(4, " De-parameterize to new: " << cellmodp << endl);
// Grab all I/O so we can remap our pins later
// Note we allow multiple users of a parameterized model,
@ -777,23 +788,23 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
relinkPins(clonemapp, nodep->paramsp());
// Fix any interface references
for (IfaceRefRefs::iterator it=ifaceRefRefs.begin();
it!=ifaceRefRefs.end(); ++it) {
for (IfaceRefRefs::iterator it = ifaceRefRefs.begin(); it != ifaceRefRefs.end();
++it) {
AstIfaceRefDType* portIrefp = it->first;
AstIfaceRefDType* pinIrefp = it->second;
AstIfaceRefDType* cloneIrefp = portIrefp->clonep();
UINFO(8," IfaceOld "<<portIrefp<<endl);
UINFO(8," IfaceTo "<<pinIrefp<<endl);
UINFO(8, " IfaceOld " << portIrefp << endl);
UINFO(8, " IfaceTo " << pinIrefp << endl);
UASSERT_OBJ(cloneIrefp, portIrefp,
"parameter clone didn't hit AstIfaceRefDType");
UINFO(8," IfaceClo "<<cloneIrefp<<endl);
UINFO(8, " IfaceClo " << cloneIrefp << endl);
cloneIrefp->ifacep(pinIrefp->ifaceViaCellp());
UINFO(8," IfaceNew "<<cloneIrefp<<endl);
UINFO(8, " IfaceNew " << cloneIrefp << endl);
}
// Assign parameters to the constants specified
// DOES clone() so must be finished with module clonep() before here
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
if (pinp->exprp()) {
if (AstVar* modvarp = pinp->modVarp()) {
AstNode* newp = pinp->exprp(); // Const or InitArray
@ -801,8 +812,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree();
// Set this parameter to value requested by cell
modvarp->valuep(newp->cloneTree(false));
}
else if (AstParamTypeDType* modptp = pinp->modPTypep()) {
} else if (AstParamTypeDType* modptp = pinp->modPTypep()) {
AstNodeDType* dtypep = VN_CAST(pinp->exprp(), NodeDType);
UASSERT_OBJ(dtypep, pinp, "unlinked param dtype");
if (modptp->childDTypep()) {
@ -817,7 +827,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
}
} else {
UINFO(4," De-parameterize to old: "<<cellmodp<<endl);
UINFO(4, " De-parameterize to old: " << cellmodp << endl);
}
// Have child use this module instead.
@ -827,15 +837,16 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
// We need to relink the pins to the new module
CloneMap* clonemapp = &(iter->second.m_cloneMap);
relinkPins(clonemapp, nodep->pinsp());
UINFO(8," Done with "<<cellmodp<<endl);
UINFO(8, " Done with " << cellmodp << endl);
} // if any_overrides
nodep->recursive(false);
// Delete the parameters from the cell; they're not relevant any longer.
if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
UINFO(8," Done with "<<nodep<<endl);
//if (debug()>=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
UINFO(8, " Done with " << nodep << endl);
// if (debug() >= 10)
// v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
}
// Now remember to process the child module at the end of the module
@ -846,9 +857,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
// Param class functions
void V3Param::param(AstNetlist* rootp) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
ParamVisitor visitor (rootp);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ ParamVisitor visitor(rootp); } // Destruct before checking
V3Global::dumpCheckGlobalTree("param", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}

View File

@ -14,7 +14,6 @@
//
//*************************************************************************
#include "V3Ast.h" // This must be before V3ParseBison.cpp, as we don't want #defines to conflict
//======================================================================
@ -27,7 +26,7 @@
int V3ParseImp::bisonParse() {
// Use --debugi-bison 9 to enable this
if (PARSEP->debugBison()>=9) yydebug = 1;
if (PARSEP->debugBison() >= 9) yydebug = 1;
return yyparse();
}
@ -36,8 +35,8 @@ const char* V3ParseImp::tokenName(int token) {
static const char** nameTablep = NULL;
if (!nameTablep) {
int size;
for (size = 0; yytname[size]; ++size) ;
nameTablep = new const char* [size];
for (size = 0; yytname[size]; ++size) {}
nameTablep = new const char*[size];
// Workaround bug in bison's which have '!' in yytname but not token values
int iout = 0;
for (int i = 0; yytname[i]; ++i) {
@ -46,9 +45,11 @@ const char* V3ParseImp::tokenName(int token) {
}
}
if (token >= 255) {
return nameTablep[token-255];
return nameTablep[token - 255];
} else {
static char ch[2]; ch[0] = token; ch[1] = '\0';
static char ch[2];
ch[0] = token;
ch[1] = '\0';
return ch;
}
#else
@ -76,18 +77,20 @@ void V3ParseGrammar::argWrapList(AstNodeFTaskRef* nodep) {
}
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) {
return new AstAssignW(fileline, new AstVarRef(fileline, name, true),
new AstConst(fileline, AstConst::StringToParse(),
(value ? "'1" : "'0")));
return new AstAssignW(
fileline, new AstVarRef(fileline, name, true),
new AstConst(fileline, AstConst::StringToParse(), (value ? "'1" : "'0")));
}
AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {
// Remove any UnsizedRange's from list
for (AstNodeRange* nodep = nrangep, *nextp; nodep; nodep = nextp) {
for (AstNodeRange *nodep = nrangep, *nextp; nodep; nodep = nextp) {
nextp = VN_CAST(nodep->nextp(), NodeRange);
if (!VN_IS(nodep, Range)) {
nodep->v3error("Unsupported or syntax error: Unsized range in cell or other declaration");
nodep->unlinkFrBack(); VL_DO_DANGLING(nodep->deleteTree(), nodep);
nodep->v3error(
"Unsupported or syntax error: Unsized range in cell or other declaration");
nodep->unlinkFrBack();
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
if (nrangep && nrangep->nextp()) {
@ -98,8 +101,8 @@ AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {
return VN_CAST(nrangep, Range);
}
AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep,
AstNodeRange* nrangep, bool isPacked) {
AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nrangep,
bool isPacked) {
// Split RANGE0-RANGE1-RANGE2
// into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3), RANGE), RANGE)
AstNodeDType* arrayp = basep;
@ -110,26 +113,26 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep,
if (prevp) nrangep->unlinkFrBack();
AstRange* rangep = VN_CAST(nrangep, Range);
if (rangep && isPacked) {
arrayp = new AstPackArrayDType
(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
arrayp
= new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
} else if (VN_IS(nrangep, QueueRange)) {
arrayp = new AstQueueDType
(nrangep->fileline(), VFlagChildDType(), arrayp, NULL);
} else if (rangep && (VN_IS(rangep->leftp(), Unbounded)
|| VN_IS(rangep->rightp(), Unbounded))) {
arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp, NULL);
} else if (rangep
&& (VN_IS(rangep->leftp(), Unbounded)
|| VN_IS(rangep->rightp(), Unbounded))) {
arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp,
rangep->rightp()->cloneTree(true));
} else if (rangep) {
arrayp = new AstUnpackArrayDType
(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
arrayp = new AstUnpackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp,
rangep);
} else if (VN_IS(nrangep, UnsizedRange)) {
arrayp = new AstUnsizedArrayDType
(nrangep->fileline(), VFlagChildDType(), arrayp);
arrayp = new AstUnsizedArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp);
} else if (VN_IS(nrangep, AssocRange)) {
AstAssocRange* arangep = VN_CAST(nrangep, AssocRange);
AstNodeDType* keyp = arangep->keyDTypep(); keyp->unlinkFrBack();
arrayp = new AstAssocArrayDType
(nrangep->fileline(), VFlagChildDType(), arrayp, keyp);
AstNodeDType* keyp = arangep->keyDTypep();
keyp->unlinkFrBack();
arrayp
= new AstAssocArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp, keyp);
} else {
UASSERT_OBJ(0, nrangep, "Expected range or unsized range");
}
@ -142,10 +145,9 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep,
AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
AstNodeRange* arrayp, AstNode* attrsp) {
AstNodeDType* dtypep = GRAMMARP->m_varDTypep;
UINFO(5," creVar "<<name<<" decl="<<GRAMMARP->m_varDecl
<<" io="<<GRAMMARP->m_varIO<<" dt="<<(dtypep?"set":"")<<endl);
if (GRAMMARP->m_varIO == VDirection::NONE
&& GRAMMARP->m_varDecl == AstVarType::PORT) {
UINFO(5, " creVar " << name << " decl=" << GRAMMARP->m_varDecl << " io="
<< GRAMMARP->m_varIO << " dt=" << (dtypep ? "set" : "") << endl);
if (GRAMMARP->m_varIO == VDirection::NONE && GRAMMARP->m_varDecl == AstVarType::PORT) {
// Just a port list with variable name (not v2k format); AstPort already created
if (dtypep) fileline->v3error("Unsupported: Ranges ignored in port-lists");
return NULL;
@ -159,7 +161,8 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
} else { // May make new variables with same type, so clone
dtypep = dtypep->cloneTree(false);
}
//UINFO(0,"CREVAR "<<fileline->ascii()<<" decl="<<GRAMMARP->m_varDecl.ascii()<<" io="<<GRAMMARP->m_varIO.ascii()<<endl);
// UINFO(0,"CREVAR "<<fileline->ascii()<<" decl="<<GRAMMARP->m_varDecl.ascii()<<"
// io="<<GRAMMARP->m_varIO.ascii()<<endl);
AstVarType type = GRAMMARP->m_varDecl;
if (type == AstVarType::UNKNOWN) {
if (GRAMMARP->m_varIO.isAny()) {
@ -169,7 +172,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
}
}
if (type == AstVarType::GENVAR) {
if (arrayp) fileline->v3error("Genvars may not be arrayed: "<<name);
if (arrayp) fileline->v3error("Genvars may not be arrayed: " << name);
}
// Split RANGE0-RANGE1-RANGE2 into
@ -202,9 +205,13 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
// We need to autosize parameters and integers separately
//
// Propagate from current module tracing state
if (nodep->isGenVar()) nodep->trace(false);
else if (nodep->isParam() && !v3Global.opt.traceParams()) nodep->trace(false);
else nodep->trace(allTracingOn(nodep->fileline()));
if (nodep->isGenVar()) {
nodep->trace(false);
} else if (nodep->isParam() && !v3Global.opt.traceParams()) {
nodep->trace(false);
} else {
nodep->trace(allTracingOn(nodep->fileline()));
}
// Remember the last variable created, so we can attach attributes to it in later parsing
GRAMMARP->m_varAttrp = nodep;
@ -222,7 +229,7 @@ string V3ParseGrammar::deQuote(FileLine* fileline, string text) {
for (string::const_iterator cp = text.begin(); cp != text.end(); ++cp) {
if (quoted) {
if (isdigit(*cp)) {
octal_val = octal_val*8 + (*cp-'0');
octal_val = octal_val * 8 + (*cp - '0');
if (++octal_digits == 3) {
octal_digits = 0;
quoted = false;
@ -238,29 +245,33 @@ string V3ParseGrammar::deQuote(FileLine* fileline, string text) {
continue;
}
quoted = false;
if (*cp == 'n') newtext += '\n';
else if (*cp == 'a') newtext += '\a'; // SystemVerilog 3.1
else if (*cp == 'f') newtext += '\f'; // SystemVerilog 3.1
else if (*cp == 'r') newtext += '\r';
else if (*cp == 't') newtext += '\t';
else if (*cp == 'v') newtext += '\v'; // SystemVerilog 3.1
else if (*cp == 'x' && isxdigit(cp[1]) && isxdigit(cp[2])) { // SystemVerilog 3.1
#define vl_decodexdigit(c) ((isdigit(c)?((c)-'0'):(tolower((c))-'a'+10)))
newtext += (char)(16*vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2]));
if (*cp == 'n') {
newtext += '\n';
} else if (*cp == 'a') {
newtext += '\a'; // SystemVerilog 3.1
} else if (*cp == 'f') {
newtext += '\f'; // SystemVerilog 3.1
} else if (*cp == 'r') {
newtext += '\r';
} else if (*cp == 't') {
newtext += '\t';
} else if (*cp == 'v') {
newtext += '\v'; // SystemVerilog 3.1
} else if (*cp == 'x' && isxdigit(cp[1])
&& isxdigit(cp[2])) { // SystemVerilog 3.1
#define vl_decodexdigit(c) ((isdigit(c) ? ((c) - '0') : (tolower((c)) - 'a' + 10)))
newtext += (char)(16 * vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2]));
cp += 2;
}
else if (isalnum(*cp)) {
fileline->v3error("Unknown escape sequence: \\"<<*cp);
} else if (isalnum(*cp)) {
fileline->v3error("Unknown escape sequence: \\" << *cp);
break;
}
else newtext += *cp;
} else
newtext += *cp;
}
}
else if (*cp == '\\') {
} else if (*cp == '\\') {
quoted = true;
octal_digits = 0;
}
else if (*cp != '"') {
} else if (*cp != '"') {
newtext += *cp;
}
}

View File

@ -41,9 +41,9 @@
//======================================================================
// Globals
V3ParseImp* V3ParseImp::s_parsep = NULL;
V3ParseImp* V3ParseImp::s_parsep = NULL;
int V3ParseSym::s_anonNum = 0;
int V3ParseSym::s_anonNum = 0;
extern void yyerror(const char*);
extern void yyerrorf(const char* format, ...);
@ -63,7 +63,10 @@ V3ParseImp::~V3ParseImp() {
lexDestroy();
parserClear();
if (debug()>=9) { UINFO(0,"~V3ParseImp\n"); symp()->dump(cout, "-vpi: "); }
if (debug() >= 9) {
UINFO(0, "~V3ParseImp\n");
symp()->dump(cout, "-vpi: ");
}
}
//######################################################################
@ -73,7 +76,7 @@ void V3ParseImp::ppline(const char* textp) {
// Handle `line directive
FileLine* prevFl = copyOrSameFileLine();
int enterExit;
fileline()->lineDirective(textp, enterExit/*ref*/);
fileline()->lineDirective(textp, enterExit /*ref*/);
if (enterExit == 1) { // Enter
fileline()->parent(prevFl);
} else if (enterExit == 2) { // Exit
@ -83,9 +86,7 @@ void V3ParseImp::ppline(const char* textp) {
}
}
void V3ParseImp::verilatorCmtLintSave() {
m_lintState.push_back(*parsep()->fileline());
}
void V3ParseImp::verilatorCmtLintSave() { m_lintState.push_back(*parsep()->fileline()); }
void V3ParseImp::verilatorCmtLintRestore() {
if (m_lintState.empty()) {
@ -117,16 +118,10 @@ void V3ParseImp::verilatorCmtBad(const char* textp) {
if (cmtparse.substr(0, strlen("/*verilator")) == "/*verilator") {
cmtparse.replace(0, strlen("/*verilator"), "");
}
while (isspace(cmtparse[0])) {
cmtparse.replace(0, 1, "");
}
while (isspace(cmtparse[0])) cmtparse.replace(0, 1, "");
string cmtname;
for (int i = 0; isalnum(cmtparse[i]); i++) {
cmtname += cmtparse[i];
}
if (!parsep()->optFuture(cmtname)) {
yyerrorf("Unknown verilator comment: %s", textp);
}
for (int i = 0; isalnum(cmtparse[i]); i++) { cmtname += cmtparse[i]; }
if (!parsep()->optFuture(cmtname)) yyerrorf("Unknown verilator comment: %s", textp);
}
void V3ParseImp::errorPreprocDirective(const char* textp) {
@ -140,8 +135,9 @@ void V3ParseImp::errorPreprocDirective(const char* textp) {
}
V3PreShell::candidateDefines(&speller);
string suggest = speller.bestCandidateMsg(textp);
fileline()->v3error("Define or directive not defined: '"<<textp<<"'\n"
<<(suggest.empty() ? "" : fileline()->warnMore()+suggest));
fileline()->v3error("Define or directive not defined: '"
<< textp << "'\n"
<< (suggest.empty() ? "" : fileline()->warnMore() + suggest));
}
void V3ParseImp::tag(const char* text) {
@ -154,19 +150,22 @@ void V3ParseImp::tag(const char* text) {
}
double V3ParseImp::parseDouble(const char* textp, size_t length, bool* successp) {
char* strgp = new char[length+1];
char* strgp = new char[length + 1];
char* dp = strgp;
if (successp) *successp = true;
for (const char* sp = textp; sp < (textp+length); ++sp) {
for (const char* sp = textp; sp < (textp + length); ++sp) {
if (*sp != '_') *dp++ = *sp;
}
*dp++ = '\0';
char* endp = strgp;
double d = strtod(strgp, &endp);
size_t parsed_len = endp-strgp;
size_t parsed_len = endp - strgp;
if (parsed_len != strlen(strgp)) {
if (successp) *successp = false;
else yyerrorf("Syntax error parsing real: %s", strgp);
if (successp) {
*successp = false;
} else {
yyerrorf("Syntax error parsing real: %s", strgp);
}
}
VL_DO_DANGLING(delete[] strgp, strgp);
return d;
@ -179,20 +178,21 @@ size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) {
size_t got = 0;
while (got < max_size // Haven't got enough
&& !m_ppBuffers.empty()) { // And something buffered
string front = m_ppBuffers.front(); m_ppBuffers.pop_front();
string front = m_ppBuffers.front();
m_ppBuffers.pop_front();
size_t len = front.length();
if (len > (max_size-got)) { // Front string too big
string remainder = front.substr(max_size-got);
front = front.substr(0, max_size-got);
if (len > (max_size - got)) { // Front string too big
string remainder = front.substr(max_size - got);
front = front.substr(0, max_size - got);
m_ppBuffers.push_front(remainder); // Put back remainder for next time
len = (max_size-got);
len = (max_size - got);
}
memcpy(buf+got, front.c_str(), len);
memcpy(buf + got, front.c_str(), len);
got += len;
}
if (debug()>=9) {
if (debug() >= 9) {
string out = string(buf, got);
cout<<" inputToLex got="<<got<<" '"<<out<<"'"<<endl;
cout << " inputToLex got=" << got << " '" << out << "'" << endl;
}
// Note returns 0 at EOF
return got;
@ -203,11 +203,15 @@ void V3ParseImp::preprocDumps(std::ostream& os) {
V3PreShell::dumpDefines(os);
} else {
bool noblanks = v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine();
for (std::deque<string>::iterator it = m_ppBuffers.begin(); it!=m_ppBuffers.end(); ++it) {
for (std::deque<string>::iterator it = m_ppBuffers.begin(); it != m_ppBuffers.end();
++it) {
if (noblanks) {
bool blank = true;
for (string::iterator its = it->begin(); its != it->end(); ++its) {
if (!isspace(*its) && *its!='\n') { blank = false; break; }
if (!isspace(*its) && *its != '\n') {
blank = false;
break;
}
}
if (blank) continue;
}
@ -220,7 +224,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
const string& errmsg) { // "" for no error, make fake node
string modname = V3Os::filenameNonExt(modfilename);
UINFO(2,__FUNCTION__<<": "<<modname<<(inLibrary?" [LIB]":"")<<endl);
UINFO(2, __FUNCTION__ << ": " << modname << (inLibrary ? " [LIB]" : "") << endl);
m_fileline = new FileLine(fileline);
m_fileline->newContent();
m_inLibrary = inLibrary;
@ -237,7 +241,8 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
if (v3Global.opt.preprocOnly() || v3Global.opt.keepTempFiles()) {
// Create output file with all the preprocessor output we buffered up
string vppfilename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_"+modname+".vpp";
string vppfilename
= v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "_" + modname + ".vpp";
std::ofstream* ofp = NULL;
std::ostream* osp;
if (v3Global.opt.preprocOnly()) {
@ -246,7 +251,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
osp = ofp = V3File::new_ofstream(vppfilename);
}
if (osp->fail()) {
fileline->v3error("Cannot write preprocessor output: "+vppfilename);
fileline->v3error("Cannot write preprocessor output: " + vppfilename);
return;
} else {
preprocDumps(*osp);
@ -267,7 +272,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
void V3ParseImp::lexFile(const string& modname) {
// Prepare for lexing
UINFO(3,"Lexing "<<modname<<endl);
UINFO(3, "Lexing " << modname << endl);
s_parsep = this;
fileline()->warnResetDefault(); // Reenable warnings on each file
lexDestroy(); // Restart from clean slate.
@ -283,7 +288,7 @@ void V3ParseImp::lexFile(const string& modname) {
V3Parse::V3Parse(AstNetlist* rootp, VInFilter* filterp, V3ParseSym* symp) {
m_impp = new V3ParseImp(rootp, filterp, symp);
}
V3Parse::~V3Parse() {
V3Parse::~V3Parse() { //
VL_DO_CLEAR(delete m_impp, m_impp = NULL);
}
void V3Parse::parseFile(FileLine* fileline, const string& modname, bool inLibrary,

View File

@ -45,49 +45,49 @@ typedef enum { iprop_NONE, iprop_CONTEXT, iprop_PURE } V3ImportProperty;
// We can't use bison's %union as we want to pass the fileline with all tokens
struct V3ParseBisonYYSType {
FileLine* fl;
AstNode* scp; // Symbol table scope for future lookups
int token; // Read token, aka tok
FileLine* fl;
AstNode* scp; // Symbol table scope for future lookups
int token; // Read token, aka tok
union {
V3Number* nump;
string* strp;
int cint;
double cdouble;
bool cbool;
V3UniqState uniqstate;
VSignedState signstate;
V3Number* nump;
string* strp;
int cint;
double cdouble;
bool cbool;
V3UniqState uniqstate;
VSignedState signstate;
V3ImportProperty iprop;
V3ErrorCode::en errcodeen;
AstAttrType::en attrtypeen;
AstNode* nodep;
AstNode* nodep;
AstBasicDType* bdtypep;
AstBegin* beginp;
AstCase* casep;
AstCaseItem* caseitemp;
AstCell* cellp;
AstClass* classp;
AstConst* constp;
AstBasicDType* bdtypep;
AstBegin* beginp;
AstCase* casep;
AstCaseItem* caseitemp;
AstCell* cellp;
AstClass* classp;
AstConst* constp;
AstMemberDType* memberp;
AstNodeModule* modulep;
AstNodeModule* modulep;
AstNodeUOrStructDType* uorstructp;
AstNodeDType* dtypep;
AstNodeFTask* ftaskp;
AstNodeDType* dtypep;
AstNodeFTask* ftaskp;
AstNodeFTaskRef* ftaskrefp;
AstNodeRange* rangep;
AstNodeRange* rangep;
AstNodeSenItem* senitemp;
AstNodeVarRef* varnodep;
AstPackage* packagep;
AstPackageRef* packagerefp;
AstParseRef* parserefp;
AstPatMember* patmemberp;
AstPattern* patternp;
AstPin* pinp;
AstRefDType* refdtypep;
AstSenTree* sentreep;
AstVar* varp;
AstVarRef* varrefp;
AstNodeVarRef* varnodep;
AstPackage* packagep;
AstPackageRef* packagerefp;
AstParseRef* parserefp;
AstPatMember* patmemberp;
AstPattern* patternp;
AstPin* pinp;
AstRefDType* refdtypep;
AstSenTree* sentreep;
AstVar* varp;
AstVarRef* varrefp;
};
};
@ -97,33 +97,33 @@ struct V3ParseBisonYYSType {
class V3ParseImp {
// MEMBERS
AstNetlist* m_rootp; // Root of the design
VInFilter* m_filterp; // Reading filter
V3ParseSym* m_symp; // Symbol table
AstNetlist* m_rootp; // Root of the design
VInFilter* m_filterp; // Reading filter
V3ParseSym* m_symp; // Symbol table
V3Lexer* m_lexerp; // Current FlexLexer
static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based
FileLine* m_fileline; // Filename/linenumber currently active
V3Lexer* m_lexerp; // Current FlexLexer
static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based
FileLine* m_fileline; // Filename/linenumber currently active
bool m_inCellDefine; // Inside a `celldefine
bool m_inLibrary; // Currently reading a library vs. regular file
int m_inBeginKwd; // Inside a `begin_keywords
int m_lastVerilogState; // Last LEX state in `begin_keywords
bool m_inCellDefine; // Inside a `celldefine
bool m_inLibrary; // Currently reading a library vs. regular file
int m_inBeginKwd; // Inside a `begin_keywords
int m_lastVerilogState; // Last LEX state in `begin_keywords
VOptionBool m_unconnectedDrive; // Last unconnected drive
int m_prevLexToken; // previous parsed token (for lexer)
bool m_ahead; // aheadval is valid
V3ParseBisonYYSType m_aheadVal; // ahead token value
int m_prevLexToken; // previous parsed token (for lexer)
bool m_ahead; // aheadval is valid
V3ParseBisonYYSType m_aheadVal; // ahead token value
V3ParseBisonYYSType m_curBisonVal; // current token for error reporting
V3ParseBisonYYSType m_prevBisonVal; // previous token for error reporting
V3ParseBisonYYSType m_prevBisonVal; // previous token for error reporting
std::deque<string*> m_stringps; // Created strings for later cleanup
std::deque<V3Number*> m_numberps; // Created numbers for later cleanup
std::deque<FileLine> m_lintState; // Current lint state for save/restore
std::deque<string> m_ppBuffers; // Preprocessor->lex buffer of characters to process
std::deque<string*> m_stringps; // Created strings for later cleanup
std::deque<V3Number*> m_numberps; // Created numbers for later cleanup
std::deque<FileLine> m_lintState; // Current lint state for save/restore
std::deque<string> m_ppBuffers; // Preprocessor->lex buffer of characters to process
string m_tag; // Contents (if any) of current verilator tag
AstNode* m_tagNodep; // Points to the node to set to m_tag or NULL to not set.
string m_tag; // Contents (if any) of current verilator tag
AstNode* m_tagNodep; // Points to the node to set to m_tag or NULL to not set.
public:
// Note these are an exception to using the filename as the debug type
static int debugBison() {
@ -151,12 +151,21 @@ public:
void errorPreprocDirective(const char* textp);
void tag(const char* text);
void tagNodep(AstNode* nodep) { m_tagNodep = nodep; }
AstNode* tagNodep() const { return m_tagNodep;}
AstNode* tagNodep() const { return m_tagNodep; }
static double parseDouble(const char* text, size_t length, bool* successp = NULL);
void pushBeginKeywords(int state) { m_inBeginKwd++; m_lastVerilogState = state; }
void pushBeginKeywords(int state) {
m_inBeginKwd++;
m_lastVerilogState = state;
}
bool popBeginKeywords() {
if (m_inBeginKwd) { m_inBeginKwd--; return true; } else return false; }
if (m_inBeginKwd) {
m_inBeginKwd--;
return true;
} else {
return false;
}
}
int lastVerilogState() const { return m_lastVerilogState; }
static const char* tokenName(int tok);
@ -204,7 +213,7 @@ public:
void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; }
// Interactions with parser
int bisonParse();
int bisonParse();
// Interactions with lexer
void lexNew();
@ -222,7 +231,9 @@ public:
public:
// CONSTRUCTORS
V3ParseImp(AstNetlist* rootp, VInFilter* filterp, V3ParseSym* parserSymp)
: m_rootp(rootp), m_filterp(filterp), m_symp(parserSymp) {
: m_rootp(rootp)
, m_filterp(filterp)
, m_symp(parserSymp) {
m_fileline = NULL;
m_lexerp = NULL;
m_inCellDefine = false;

File diff suppressed because it is too large Load Diff

View File

@ -353,7 +353,7 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
// become a stale invalid pointer.
//
VPreStream* streamp = curStreamp();
if (debug()>=10) {
if (debug() >= 10) {
cout<<"- pp:inputToLex ITL s="<<max_size<<" bs="<<streamp->m_buffers.size()<<endl;
dumpStack();
}
@ -394,7 +394,7 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
if (again) goto again;
}
}
if (debug()>=10) { cout<<"- pp::inputToLex got="<<got<<" '"<<string(buf, got)<<"'"<<endl; }
if (debug() >= 10) { cout<<"- pp::inputToLex got="<<got<<" '"<<string(buf, got)<<"'"<<endl; }
return got;
}

File diff suppressed because it is too large Load Diff

View File

@ -42,17 +42,17 @@ class PremitAssignVisitor : public AstNVisitor {
private:
// NODE STATE
// AstVar::user4() // bool; occurs on LHS of current assignment
AstUser4InUse m_inuser4;
AstUser4InUse m_inuser4;
// STATE
bool m_noopt; // Disable optimization of variables in this block
bool m_noopt; // Disable optimization of variables in this block
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
//AstNode::user4ClearTree(); // Implied by AstUser4InUse
// AstNode::user4ClearTree(); // Implied by AstUser4InUse
// LHS first as fewer varrefs
iterateAndNextNull(nodep->lhsp());
// Now find vars marked as lhs
@ -64,7 +64,7 @@ private:
nodep->varp()->user4(true);
} else {
if (nodep->varp()->user4()) {
if (!m_noopt) UINFO(4, "Block has LHS+RHS var: "<<nodep<<endl);
if (!m_noopt) UINFO(4, "Block has LHS+RHS var: " << nodep << endl);
m_noopt = true;
}
}
@ -74,7 +74,7 @@ private:
public:
// CONSTRUCTORS
explicit PremitAssignVisitor(AstNodeAssign* nodep) {
UINFO(4," PremitAssignVisitor on "<<nodep<<endl);
UINFO(4, " PremitAssignVisitor on " << nodep << endl);
m_noopt = false;
iterate(nodep);
}
@ -92,23 +92,22 @@ private:
// AstShiftL::user2() -> bool. True if converted to conditional
// AstShiftR::user2() -> bool. True if converted to conditional
// *::user4() -> See PremitAssignVisitor
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
// STATE
AstNodeModule* m_modp; // Current module
AstCFunc* m_funcp; // Current block
AstNode* m_stmtp; // Current statement
AstWhile* m_inWhilep; // Inside while loop, special statement additions
AstTraceInc* m_inTracep; // Inside while loop, special statement additions
bool m_assignLhs; // Inside assignment lhs, don't breakup extracts
AstNodeModule* m_modp; // Current module
AstCFunc* m_funcp; // Current block
AstNode* m_stmtp; // Current statement
AstWhile* m_inWhilep; // Inside while loop, special statement additions
AstTraceInc* m_inTracep; // Inside while loop, special statement additions
bool m_assignLhs; // Inside assignment lhs, don't breakup extracts
// METHODS
VL_DEBUG_FUNC; // Declare debug()
bool assignNoTemp(AstNodeAssign* nodep) {
return (VN_IS(nodep->lhsp(), VarRef)
&& !AstVar::scVarRecurse(nodep->lhsp())
return (VN_IS(nodep->lhsp(), VarRef) && !AstVar::scVarRecurse(nodep->lhsp())
&& VN_IS(nodep->rhsp(), Const));
}
void checkNode(AstNode* nodep) {
@ -119,24 +118,22 @@ private:
// ARRAYSEL(*here*, ...) (No wides can be in any argument but first,
// so we don't check which arg is wide)
// ASSIGN(x, SEL*HERE*(ARRAYSEL()...) (m_assignLhs==true handles this.)
//UINFO(9, " Check: "<<nodep<<endl);
//UINFO(9, " Detail stmtp="<<(m_stmtp?"Y":"N")<<" U="<<(nodep->user1()?"Y":"N")<<" IW="<<(nodep->isWide()?"Y":"N")<<endl);
if (m_stmtp
&& !nodep->user1()) { // Not already done
// UINFO(9, " Check: " << nodep << endl);
// UINFO(9, " Detail stmtp=" << (m_stmtp?"Y":"N") << " U=" << (nodep->user1()?"Y":"N")
// << " IW=" << (nodep->isWide()?"Y":"N") << endl);
if (m_stmtp && !nodep->user1()) { // Not already done
if (nodep->isWide()) {
if (m_assignLhs) {
} else if (nodep->firstAbovep()
&& VN_IS(nodep->firstAbovep(), NodeAssign)
} else if (nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), NodeAssign)
&& assignNoTemp(VN_CAST(nodep->firstAbovep(), NodeAssign))) {
// Not much point if it's just a direct assignment to a constant
} else if (VN_IS(nodep->backp(), Sel)
&& VN_CAST(nodep->backp(), Sel)->widthp() == nodep) {
// AstSel::width must remain a constant
} else if (nodep->firstAbovep()
&& VN_IS(nodep->firstAbovep(), ArraySel)) {
} else if (nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), ArraySel)) {
// ArraySel's are pointer refs, ignore
} else {
UINFO(4,"Cre Temp: "<<nodep<<endl);
UINFO(4, "Cre Temp: " << nodep << endl);
createDeepTemp(nodep, false);
}
}
@ -144,9 +141,9 @@ private:
}
AstVar* getBlockTemp(AstNode* nodep) {
string newvarname = (string("__Vtemp")+cvtToStr(m_modp->varNumGetInc()));
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname,
nodep->dtypep());
string newvarname = (string("__Vtemp") + cvtToStr(m_modp->varNumGetInc()));
AstVar* varp
= new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep());
m_funcp->addInitsp(varp);
return varp;
}
@ -171,7 +168,7 @@ private:
}
void createDeepTemp(AstNode* nodep, bool noSubst) {
if (debug()>8) nodep->dumpTree(cout, "deepin:");
if (debug() > 8) nodep->dumpTree(cout, "deepin:");
AstNRelinker linker;
nodep->unlinkFrBack(&linker);
@ -183,16 +180,15 @@ private:
linker.relink(newp);
// Put assignment before the referencing statement
AstAssign* assp = new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), varp, true),
nodep);
new AstVarRef(nodep->fileline(), varp, true), nodep);
insertBeforeStmt(assp);
if (debug()>8) assp->dumpTree(cout, "deepou:");
if (debug() > 8) assp->dumpTree(cout, "deepou:");
nodep->user1(true); // Don't add another assignment
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
UINFO(4," MOD "<<nodep<<endl);
UINFO(4, " MOD " << nodep << endl);
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
@ -211,7 +207,7 @@ private:
if (m_funcp) m_stmtp = nodep;
}
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
UINFO(4," WHILE "<<nodep<<endl);
UINFO(4, " WHILE " << nodep << endl);
startStatement(nodep);
iterateAndNextNull(nodep->precondsp());
startStatement(nodep);
@ -229,7 +225,7 @@ private:
bool noopt = PremitAssignVisitor(nodep).noOpt();
if (noopt && !nodep->user1()) {
// Need to do this even if not wide, as e.g. a select may be on a wide operator
UINFO(4,"Deep temp for LHS/RHS\n");
UINFO(4, "Deep temp for LHS/RHS\n");
createDeepTemp(nodep->rhsp(), false);
}
}
@ -244,7 +240,7 @@ private:
iterateChildren(nodep);
return;
}
UINFO(4," STMT "<<nodep<<endl);
UINFO(4, " STMT " << nodep << endl);
startStatement(nodep);
iterateChildren(nodep);
m_stmtp = NULL;
@ -259,29 +255,30 @@ private:
void visitShift(AstNodeBiop* nodep) {
// Shifts of > 32/64 bits in C++ will wrap-around and generate non-0s
if (!nodep->user2SetOnce()) {
UINFO(4," ShiftFix "<<nodep<<endl);
UINFO(4, " ShiftFix " << nodep << endl);
const AstConst* shiftp = VN_CAST(nodep->rhsp(), Const);
if (shiftp && shiftp->num().mostSetBitP1() > 32) {
shiftp->v3error("Unsupported: Shifting of by over 32-bit number isn't supported."
<<" (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
shiftp->v3error(
"Unsupported: Shifting of by over 32-bit number isn't supported."
<< " (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
}
if (nodep->widthMin() <= 64 // Else we'll use large operators which work right
// C operator's width must be < maximum shift which is based on Verilog width
&& nodep->width() < (1LL<<nodep->rhsp()->widthMin())) {
// C operator's width must be < maximum shift which is
// based on Verilog width
&& nodep->width() < (1LL << nodep->rhsp()->widthMin())) {
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
AstNode* constzerop;
int m1value = nodep->widthMin()-1; // Constant of width-1; not changing dtype width
int m1value
= nodep->widthMin() - 1; // Constant of width-1; not changing dtype width
if (nodep->signedFlavor()) {
// Then over shifting gives the sign bit, not all zeros
// Note *NOT* clean output -- just like normal shift!
// Create equivalent of VL_SIGNONES_(node_width)
constzerop = new AstNegate(nodep->fileline(),
new AstShiftR(nodep->fileline(),
nodep->lhsp()->cloneTree(false),
new AstConst(nodep->fileline(),
m1value),
nodep->width()));
constzerop = new AstNegate(
nodep->fileline(),
new AstShiftR(nodep->fileline(), nodep->lhsp()->cloneTree(false),
new AstConst(nodep->fileline(), m1value), nodep->width()));
} else {
constzerop = new AstConst(nodep->fileline(), AstConst::WidthedValue(),
nodep->width(), 0);
@ -291,43 +288,39 @@ private:
AstNode* constwidthp = new AstConst(nodep->fileline(), AstConst::WidthedValue(),
nodep->rhsp()->widthMin(), m1value);
constwidthp->dtypeFrom(nodep->rhsp()); // unsigned
AstCond* newp =
new AstCond(nodep->fileline(),
new AstGte(nodep->fileline(),
constwidthp,
nodep->rhsp()->cloneTree(false)),
nodep,
constzerop);
AstCond* newp = new AstCond(
nodep->fileline(),
new AstGte(nodep->fileline(), constwidthp, nodep->rhsp()->cloneTree(false)),
nodep, constzerop);
replaceHandle.relink(newp);
}
}
iterateChildren(nodep); checkNode(nodep);
}
virtual void visit(AstShiftL* nodep) VL_OVERRIDE {
visitShift(nodep);
}
virtual void visit(AstShiftR* nodep) VL_OVERRIDE {
visitShift(nodep);
}
virtual void visit(AstShiftRS* nodep) VL_OVERRIDE {
visitShift(nodep);
iterateChildren(nodep);
checkNode(nodep);
}
virtual void visit(AstShiftL* nodep) VL_OVERRIDE { visitShift(nodep); }
virtual void visit(AstShiftR* nodep) VL_OVERRIDE { visitShift(nodep); }
virtual void visit(AstShiftRS* nodep) VL_OVERRIDE { visitShift(nodep); }
// Operators
virtual void visit(AstNodeTermop* nodep) VL_OVERRIDE {
iterateChildren(nodep); checkNode(nodep);
iterateChildren(nodep);
checkNode(nodep);
}
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
iterateChildren(nodep); checkNode(nodep);
iterateChildren(nodep);
checkNode(nodep);
}
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
iterateChildren(nodep); checkNode(nodep);
iterateChildren(nodep);
checkNode(nodep);
}
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
iterateChildren(nodep); checkNode(nodep);
iterateChildren(nodep);
checkNode(nodep);
}
virtual void visit(AstSel* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->fromp());
{ // Only the 'from' is part of the assignment LHS
{ // Only the 'from' is part of the assignment LHS
bool prevAssign = m_assignLhs;
m_assignLhs = false;
iterateAndNextNull(nodep->lsbp());
@ -338,7 +331,7 @@ private:
}
virtual void visit(AstArraySel* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->fromp());
{ // Only the 'from' is part of the assignment LHS
{ // Only the 'from' is part of the assignment LHS
bool prevAssign = m_assignLhs;
m_assignLhs = false;
iterateAndNextNull(nodep->bitp());
@ -348,7 +341,7 @@ private:
}
virtual void visit(AstAssocSel* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->fromp());
{ // Only the 'from' is part of the assignment LHS
{ // Only the 'from' is part of the assignment LHS
bool prevAssign = m_assignLhs;
m_assignLhs = false;
iterateAndNextNull(nodep->bitp());
@ -362,8 +355,7 @@ private:
}
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (nodep->expr1p()->isWide()
&& !VN_IS(nodep->condp(), Const)
if (nodep->expr1p()->isWide() && !VN_IS(nodep->condp(), Const)
&& !VN_IS(nodep->condp(), VarRef)) {
// We're going to need the expression several times in the expanded code,
// so might as well make it a common expression
@ -380,12 +372,11 @@ private:
if (v3Global.opt.autoflush()) {
AstNode* searchp = nodep->nextp();
while (searchp && VN_IS(searchp, Comment)) searchp = searchp->nextp();
if (searchp
&& VN_IS(searchp, Display)
if (searchp && VN_IS(searchp, Display)
&& nodep->filep()->sameGateTree(VN_CAST(searchp, Display)->filep())) {
// There's another display next; we can just wait to flush
} else {
UINFO(4,"Autoflush "<<nodep<<endl);
UINFO(4, "Autoflush " << nodep << endl);
nodep->addNextHere(new AstFFlush(nodep->fileline(),
AstNode::cloneTreeNull(nodep->filep(), true)));
}
@ -395,9 +386,8 @@ private:
iterateChildren(nodep);
// Any strings sent to a display must be var of string data type,
// to avoid passing a pointer to a temporary.
for (AstNode* expp=nodep->exprsp(); expp; expp = expp->nextp()) {
if (expp->dtypep()->basicp()
&& expp->dtypep()->basicp()->isString()
for (AstNode* expp = nodep->exprsp(); expp; expp = expp->nextp()) {
if (expp->dtypep()->basicp() && expp->dtypep()->basicp()->isString()
&& !VN_IS(expp, VarRef)) {
createDeepTemp(expp, true);
}
@ -430,9 +420,7 @@ public:
// Premit class functions
void V3Premit::premitAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
PremitVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ PremitVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("premit", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -26,50 +26,49 @@
#include <list>
//######################################################################
// ProtectLib top-level visitor
class ProtectVisitor : public AstNVisitor {
private:
AstVFile* m_vfilep; // DPI-enabled Verilog wrapper
AstCFile* m_cfilep; // C implementation of DPI functions
private:
AstVFile* m_vfilep; // DPI-enabled Verilog wrapper
AstCFile* m_cfilep; // C implementation of DPI functions
// Verilog text blocks
AstTextBlock* m_modPortsp; // Module port list
AstTextBlock* m_comboPortsp; // Combo function port list
AstTextBlock* m_seqPortsp; // Sequential function port list
AstTextBlock* m_modPortsp; // Module port list
AstTextBlock* m_comboPortsp; // Combo function port list
AstTextBlock* m_seqPortsp; // Sequential function port list
AstTextBlock* m_comboIgnorePortsp; // Combo ignore function port list
AstTextBlock* m_comboDeclsp; // Combo signal declaration list
AstTextBlock* m_seqDeclsp; // Sequential signal declaration list
AstTextBlock* m_tmpDeclsp; // Temporary signal declaration list
AstTextBlock* m_hashValuep; // CPP hash value
AstTextBlock* m_comboParamsp; // Combo function parameter list
AstTextBlock* m_clkSensp; // Clock sensitivity list
AstTextBlock* m_comboIgnoreParamsp; // Combo ignore parameter list
AstTextBlock* m_seqParamsp; // Sequential parameter list
AstTextBlock* m_nbAssignsp; // Non-blocking assignment list
AstTextBlock* m_seqAssignsp; // Sequential assignment list
AstTextBlock* m_comboAssignsp; // Combo assignment list
AstTextBlock* m_comboDeclsp; // Combo signal declaration list
AstTextBlock* m_seqDeclsp; // Sequential signal declaration list
AstTextBlock* m_tmpDeclsp; // Temporary signal declaration list
AstTextBlock* m_hashValuep; // CPP hash value
AstTextBlock* m_comboParamsp; // Combo function parameter list
AstTextBlock* m_clkSensp; // Clock sensitivity list
AstTextBlock* m_comboIgnoreParamsp; // Combo ignore parameter list
AstTextBlock* m_seqParamsp; // Sequential parameter list
AstTextBlock* m_nbAssignsp; // Non-blocking assignment list
AstTextBlock* m_seqAssignsp; // Sequential assignment list
AstTextBlock* m_comboAssignsp; // Combo assignment list
// C text blocks
AstTextBlock* m_cHashValuep; // CPP hash value
AstTextBlock* m_cComboParamsp; // Combo function parameter list
AstTextBlock* m_cComboInsp; // Combo input copy list
AstTextBlock* m_cComboOutsp; // Combo output copy list
AstTextBlock* m_cSeqParamsp; // Sequential parameter list
AstTextBlock* m_cSeqClksp; // Sequential clock copy list
AstTextBlock* m_cSeqOutsp; // Sequential output copy list
AstTextBlock* m_cIgnoreParamsp; // Combo ignore parameter list
AstTextBlock* m_cHashValuep; // CPP hash value
AstTextBlock* m_cComboParamsp; // Combo function parameter list
AstTextBlock* m_cComboInsp; // Combo input copy list
AstTextBlock* m_cComboOutsp; // Combo output copy list
AstTextBlock* m_cSeqParamsp; // Sequential parameter list
AstTextBlock* m_cSeqClksp; // Sequential clock copy list
AstTextBlock* m_cSeqOutsp; // Sequential output copy list
AstTextBlock* m_cIgnoreParamsp; // Combo ignore parameter list
string m_libName;
string m_topName;
bool m_foundTop; // Have seen the top module
bool m_foundTop; // Have seen the top module
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
m_vfilep = new AstVFile(nodep->fileline(),
v3Global.opt.makeDir()+"/"+m_libName+".sv");
m_vfilep
= new AstVFile(nodep->fileline(), v3Global.opt.makeDir() + "/" + m_libName + ".sv");
nodep->addFilesp(m_vfilep);
m_cfilep = new AstCFile(nodep->fileline(),
v3Global.opt.makeDir()+"/"+m_libName+".cpp");
m_cfilep
= new AstCFile(nodep->fileline(), v3Global.opt.makeDir() + "/" + m_libName + ".cpp");
nodep->addFilesp(m_cfilep);
iterateChildren(nodep);
}
@ -87,8 +86,8 @@ class ProtectVisitor : public AstNVisitor {
iterateChildren(nodep);
V3Hash hash = V3Hashed::uncachedHash(m_cfilep);
m_hashValuep->addText(fl, cvtToStr(hash.fullValue())+";\n");
m_cHashValuep->addText(fl, cvtToStr(hash.fullValue())+"U;\n");
m_hashValuep->addText(fl, cvtToStr(hash.fullValue()) + ";\n");
m_cHashValuep->addText(fl, cvtToStr(hash.fullValue()) + "U;\n");
m_foundTop = true;
}
@ -127,47 +126,55 @@ class ProtectVisitor : public AstNVisitor {
// Comments
AstTextBlock* txtp = new AstTextBlock(fl);
addComment(txtp, fl, "Wrapper module for DPI protected library");
addComment(txtp, fl, "This module requires lib"+m_libName+
".a or lib"+m_libName+".so to work");
addComment(txtp, fl, "See instructions in your simulator for how"
addComment(txtp, fl,
"This module requires lib" + m_libName + ".a or lib" + m_libName
+ ".so to work");
addComment(txtp, fl,
"See instructions in your simulator for how"
" to use DPI libraries\n");
// Module declaration
m_modPortsp = new AstTextBlock(fl, "module "+m_libName+" (\n", false, true);
m_modPortsp = new AstTextBlock(fl, "module " + m_libName + " (\n", false, true);
txtp->addNodep(m_modPortsp);
txtp->addText(fl, ");\n\n");
// DPI declarations
hashComment(txtp, fl);
txtp->addText(fl, "import \"DPI-C\" function void "+
m_libName+"_protectlib_check_hash(int protectlib_hash__V);\n\n");
txtp->addText(fl, "import \"DPI-C\" function void " + m_libName
+ "_protectlib_check_hash(int protectlib_hash__V);\n\n");
initialComment(txtp, fl);
txtp->addText(fl, "import \"DPI-C\" function chandle "+
m_libName+"_protectlib_create(string scope__V);\n\n");
txtp->addText(fl, "import \"DPI-C\" function chandle " + m_libName
+ "_protectlib_create(string scope__V);\n\n");
comboComment(txtp, fl);
m_comboPortsp = new AstTextBlock(fl, "import \"DPI-C\" function longint "+
m_libName+"_protectlib_combo_update "
"(\n", false, true);
m_comboPortsp = new AstTextBlock(fl,
"import \"DPI-C\" function longint " + m_libName
+ "_protectlib_combo_update "
"(\n",
false, true);
m_comboPortsp->addText(fl, "chandle handle__V\n");
txtp->addNodep(m_comboPortsp);
txtp->addText(fl, ");\n\n");
seqComment(txtp, fl);
m_seqPortsp = new AstTextBlock(fl, "import \"DPI-C\" function longint "+
m_libName+"_protectlib_seq_update"
"(\n", false, true);
m_seqPortsp = new AstTextBlock(fl,
"import \"DPI-C\" function longint " + m_libName
+ "_protectlib_seq_update"
"(\n",
false, true);
m_seqPortsp->addText(fl, "chandle handle__V\n");
txtp->addNodep(m_seqPortsp);
txtp->addText(fl, ");\n\n");
comboIgnoreComment(txtp, fl);
m_comboIgnorePortsp = new AstTextBlock(fl, "import \"DPI-C\" function void "+
m_libName+"_protectlib_combo_ignore"
"(\n", false, true);
m_comboIgnorePortsp = new AstTextBlock(fl,
"import \"DPI-C\" function void " + m_libName
+ "_protectlib_combo_ignore"
"(\n",
false, true);
m_comboIgnorePortsp->addText(fl, "chandle handle__V\n");
txtp->addNodep(m_comboIgnorePortsp);
txtp->addText(fl, ");\n\n");
finalComment(txtp, fl);
txtp->addText(fl, "import \"DPI-C\" function void "+
m_libName+"_protectlib_final(chandle handle__V);\n\n");
txtp->addText(fl, "import \"DPI-C\" function void " + m_libName
+ "_protectlib_final(chandle handle__V);\n\n");
// Local variables
txtp->addText(fl, "chandle handle__V;\n\n");
@ -189,16 +196,18 @@ class ProtectVisitor : public AstNVisitor {
// Initial
txtp->addText(fl, "initial begin\n");
txtp->addText(fl, m_libName+"_protectlib_check_hash(protectlib_hash__V);\n");
txtp->addText(fl, "handle__V = "+m_libName+"_protectlib_create"
"($sformatf(\"%m\"));\n");
txtp->addText(fl, m_libName + "_protectlib_check_hash(protectlib_hash__V);\n");
txtp->addText(fl, "handle__V = " + m_libName
+ "_protectlib_create"
"($sformatf(\"%m\"));\n");
txtp->addText(fl, "end\n\n");
// Combinatorial process
addComment(txtp, fl, "Combinatorialy evaluate changes to inputs");
m_comboParamsp = new AstTextBlock(fl, "always @(*) begin\n"
"last_combo_seqnum__V = "+
m_libName+"_protectlib_combo_update(\n",
m_comboParamsp = new AstTextBlock(fl,
"always @(*) begin\n"
"last_combo_seqnum__V = "
+ m_libName + "_protectlib_combo_update(\n",
false, true);
m_comboParamsp->addText(fl, "handle__V\n");
txtp->addNodep(m_comboParamsp);
@ -210,14 +219,13 @@ class ProtectVisitor : public AstNVisitor {
m_clkSensp = new AstTextBlock(fl, "always @(", false, true);
txtp->addNodep(m_clkSensp);
txtp->addText(fl, ") begin\n");
m_comboIgnoreParamsp = new AstTextBlock(fl, m_libName+"_protectlib_combo_ignore(\n",
false, true);
m_comboIgnoreParamsp
= new AstTextBlock(fl, m_libName + "_protectlib_combo_ignore(\n", false, true);
m_comboIgnoreParamsp->addText(fl, "handle__V\n");
txtp->addNodep(m_comboIgnoreParamsp);
txtp->addText(fl, ");\n");
m_seqParamsp = new AstTextBlock(fl, "last_seq_seqnum__V <= "+m_libName+
"_protectlib_seq_update(\n",
false, true);
m_seqParamsp = new AstTextBlock(
fl, "last_seq_seqnum__V <= " + m_libName + "_protectlib_seq_update(\n", false, true);
m_seqParamsp->addText(fl, "handle__V\n");
txtp->addNodep(m_seqParamsp);
txtp->addText(fl, ");\n");
@ -229,7 +237,7 @@ class ProtectVisitor : public AstNVisitor {
addComment(txtp, fl, "Select between combinatorial and sequential results");
txtp->addText(fl, "always @(*) begin\n");
m_seqAssignsp = new AstTextBlock(fl, "if (last_seq_seqnum__V > "
"last_combo_seqnum__V) begin\n");
"last_combo_seqnum__V) begin\n");
txtp->addNodep(m_seqAssignsp);
m_comboAssignsp = new AstTextBlock(fl, "end else begin\n");
txtp->addNodep(m_comboAssignsp);
@ -237,15 +245,17 @@ class ProtectVisitor : public AstNVisitor {
txtp->addText(fl, "end\n\n");
// Final
txtp->addText(fl, "final "+m_libName+"_protectlib_final(handle__V);\n\n");
txtp->addText(fl, "final " + m_libName + "_protectlib_final(handle__V);\n\n");
txtp->addText(fl, "endmodule\n");
m_vfilep->tblockp(txtp);
}
void castPtr(FileLine* fl, AstTextBlock* txtp) {
txtp->addText(fl, m_topName+"_container* handlep__V = "
"static_cast<"+m_topName+"_container*>(vhandlep__V);\n");
txtp->addText(fl, m_topName
+ "_container* handlep__V = "
"static_cast<"
+ m_topName + "_container*>(vhandlep__V);\n");
}
void createCppFile(FileLine* fl) {
@ -254,18 +264,18 @@ class ProtectVisitor : public AstNVisitor {
addComment(txtp, fl, "Wrapper functions for DPI protected library\n");
// Includes
txtp->addText(fl, "#include \""+m_topName+".h\"\n");
txtp->addText(fl, "#include \"" + m_topName + ".h\"\n");
txtp->addText(fl, "#include \"verilated_dpi.h\"\n\n");
txtp->addText(fl, "#include <cstdio>\n");
txtp->addText(fl, "#include <cstdlib>\n\n");
// Verilated module plus sequence number
addComment(txtp, fl, "Container class to house verilated object and sequence number");
txtp->addText(fl, "class "+m_topName+"_container: public "+m_topName+" {\n");
txtp->addText(fl, "class " + m_topName + "_container: public " + m_topName + " {\n");
txtp->addText(fl, "public:\n");
txtp->addText(fl, "long long m_seqnum;\n");
txtp->addText(fl, m_topName+"_container(const char* scopep__V):\n");
txtp->addText(fl, m_topName+"(scopep__V) {}\n");
txtp->addText(fl, m_topName + "_container(const char* scopep__V):\n");
txtp->addText(fl, m_topName + "(scopep__V) {}\n");
txtp->addText(fl, "};\n\n");
// Extern C
@ -273,31 +283,32 @@ class ProtectVisitor : public AstNVisitor {
// Hash check
hashComment(txtp, fl);
txtp->addText(fl, "void "+m_libName+"_protectlib_check_hash"
"(int protectlib_hash__V) {\n");
txtp->addText(fl, "void " + m_libName
+ "_protectlib_check_hash"
"(int protectlib_hash__V) {\n");
m_cHashValuep = new AstTextBlock(fl, "int expected_hash__V = ");
txtp->addNodep(m_cHashValuep);
txtp->addText(fl, "if (protectlib_hash__V != expected_hash__V) {\n");
txtp->addText(fl, "fprintf(stderr, \"%%Error: cannot use "+m_libName+" library, "
"Verliog (%u) and library (%u) hash values do not "
"agree\\n\", protectlib_hash__V, expected_hash__V);\n");
txtp->addText(fl, "fprintf(stderr, \"%%Error: cannot use " + m_libName
+ " library, "
"Verliog (%u) and library (%u) hash values do not "
"agree\\n\", protectlib_hash__V, expected_hash__V);\n");
txtp->addText(fl, "exit(EXIT_FAILURE);\n");
txtp->addText(fl, "}\n");
txtp->addText(fl, "}\n\n");
// Initial
initialComment(txtp, fl);
txtp->addText(fl, "void* "+m_libName+"_protectlib_create"
" (const char* scopep__V) {\n");
txtp->addText(fl, m_topName+"_container* handlep__V = "
"new "+m_topName+"_container(scopep__V);\n");
txtp->addText(fl, "void* " + m_libName + "_protectlib_create(const char* scopep__V) {\n");
txtp->addText(fl, m_topName + "_container* handlep__V = new " + m_topName
+ "_container(scopep__V);\n");
txtp->addText(fl, "return handlep__V;\n");
txtp->addText(fl, "}\n\n");
// Updates
comboComment(txtp, fl);
m_cComboParamsp = new AstTextBlock(fl, "long long "+m_libName+"_protectlib_combo_update(\n",
false, true);
m_cComboParamsp = new AstTextBlock(
fl, "long long " + m_libName + "_protectlib_combo_update(\n", false, true);
m_cComboParamsp->addText(fl, "void* vhandlep__V\n");
txtp->addNodep(m_cComboParamsp);
txtp->addText(fl, ")\n");
@ -310,8 +321,8 @@ class ProtectVisitor : public AstNVisitor {
txtp->addText(fl, "}\n\n");
seqComment(txtp, fl);
m_cSeqParamsp = new AstTextBlock(fl, "long long "+m_libName+"_protectlib_seq_update(\n",
false, true);
m_cSeqParamsp = new AstTextBlock(
fl, "long long " + m_libName + "_protectlib_seq_update(\n", false, true);
m_cSeqParamsp->addText(fl, "void* vhandlep__V\n");
txtp->addNodep(m_cSeqParamsp);
txtp->addText(fl, ")\n");
@ -324,8 +335,8 @@ class ProtectVisitor : public AstNVisitor {
txtp->addText(fl, "}\n\n");
comboIgnoreComment(txtp, fl);
m_cIgnoreParamsp = new AstTextBlock(fl, "void "+m_libName+"_protectlib_combo_ignore(\n",
false, true);
m_cIgnoreParamsp = new AstTextBlock(
fl, "void " + m_libName + "_protectlib_combo_ignore(\n", false, true);
m_cIgnoreParamsp->addText(fl, "void* vhandlep__V\n");
txtp->addNodep(m_cIgnoreParamsp);
txtp->addText(fl, ")\n");
@ -333,7 +344,7 @@ class ProtectVisitor : public AstNVisitor {
// Final
finalComment(txtp, fl);
txtp->addText(fl, "void "+m_libName+"_protectlib_final(void* vhandlep__V) {\n");
txtp->addText(fl, "void " + m_libName + "_protectlib_final(void* vhandlep__V) {\n");
castPtr(fl, txtp);
txtp->addText(fl, "handlep__V->final();\n");
txtp->addText(fl, "delete handlep__V;\n");
@ -346,11 +357,11 @@ class ProtectVisitor : public AstNVisitor {
virtual void visit(AstVar* nodep) VL_OVERRIDE {
if (!nodep->isIO()) return;
if (VN_IS(nodep->dtypep(), UnpackArrayDType)) {
nodep->v3error("Unsupported: unpacked arrays with protect-lib on "<<nodep->prettyNameQ());
nodep->v3error("Unsupported: unpacked arrays with protect-lib on "
<< nodep->prettyNameQ());
}
if (nodep->direction() == VDirection::INPUT) {
if (nodep->isUsedClock()
|| nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
if (nodep->isUsedClock() || nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
handleClock(nodep);
} else {
handleDataInput(nodep);
@ -358,8 +369,8 @@ class ProtectVisitor : public AstNVisitor {
} else if (nodep->direction() == VDirection::OUTPUT) {
handleOutput(nodep);
} else {
nodep->v3error("Unsupported: protect-lib port direction: "<<
nodep->direction().ascii());
nodep->v3error(
"Unsupported: protect-lib port direction: " << nodep->direction().ascii());
}
}
@ -369,18 +380,18 @@ class ProtectVisitor : public AstNVisitor {
string frstmt;
bool useSetWSvlv = V3Task::dpiToInternalFrStmt(varp, varp->name(), frstmt);
if (useSetWSvlv) {
return frstmt+" handlep__V->"+varp->name()+", "+varp->name()+");\n";
return frstmt + " handlep__V->" + varp->name() + ", " + varp->name() + ");\n";
}
return "handlep__V->"+varp->name()+" = "+frstmt+";\n";
return "handlep__V->" + varp->name() + " = " + frstmt + ";\n";
}
void handleClock(AstVar* varp) {
FileLine* fl = varp->fileline();
handleInput(varp);
m_seqPortsp->addNodep(varp->cloneTree(false));
m_seqParamsp->addText(fl, varp->name()+"\n");
m_clkSensp->addText(fl, "edge("+varp->name()+")");
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
m_seqParamsp->addText(fl, varp->name() + "\n");
m_clkSensp->addText(fl, "edge(" + varp->name() + ")");
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
m_cSeqClksp->addText(fl, cInputConnection(varp));
}
@ -388,61 +399,76 @@ class ProtectVisitor : public AstNVisitor {
FileLine* fl = varp->fileline();
handleInput(varp);
m_comboPortsp->addNodep(varp->cloneTree(false));
m_comboParamsp->addText(fl, varp->name()+"\n");
m_comboParamsp->addText(fl, varp->name() + "\n");
m_comboIgnorePortsp->addNodep(varp->cloneTree(false));
m_comboIgnoreParamsp->addText(fl, varp->name()+"\n");
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
m_comboIgnoreParamsp->addText(fl, varp->name() + "\n");
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
m_cComboInsp->addText(fl, cInputConnection(varp));
m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
}
void handleInput(AstVar* varp) {
m_modPortsp->addNodep(varp->cloneTree(false));
}
void handleInput(AstVar* varp) { m_modPortsp->addNodep(varp->cloneTree(false)); }
void handleOutput(AstVar* varp) {
FileLine* fl = varp->fileline();
m_modPortsp->addNodep(varp->cloneTree(false));
m_comboPortsp->addNodep(varp->cloneTree(false));
m_comboParamsp->addText(fl, varp->name()+"_combo__V\n");
m_comboParamsp->addText(fl, varp->name() + "_combo__V\n");
m_seqPortsp->addNodep(varp->cloneTree(false));
m_seqParamsp->addText(fl, varp->name()+"_tmp__V\n");
m_seqParamsp->addText(fl, varp->name() + "_tmp__V\n");
AstNodeDType* comboDtypep = varp->dtypep()->cloneTree(false);
m_comboDeclsp->addNodep(comboDtypep);
m_comboDeclsp->addText(fl, " "+varp->name()+"_combo__V;\n");
m_comboDeclsp->addText(fl, " " + varp->name() + "_combo__V;\n");
AstNodeDType* seqDtypep = varp->dtypep()->cloneTree(false);
m_seqDeclsp->addNodep(seqDtypep);
m_seqDeclsp->addText(fl, " "+varp->name()+"_seq__V;\n");
m_seqDeclsp->addText(fl, " " + varp->name() + "_seq__V;\n");
AstNodeDType* tmpDtypep = varp->dtypep()->cloneTree(false);
m_tmpDeclsp->addNodep(tmpDtypep);
m_tmpDeclsp->addText(fl, " "+varp->name()+"_tmp__V;\n");
m_tmpDeclsp->addText(fl, " " + varp->name() + "_tmp__V;\n");
m_nbAssignsp->addText(fl, varp->name()+"_seq__V <= "+varp->name()+"_tmp__V;\n");
m_seqAssignsp->addText(fl, varp->name()+" = "+varp->name()+"_seq__V;\n");
m_comboAssignsp->addText(fl, varp->name()+" = "+varp->name()+"_combo__V;\n");
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
m_nbAssignsp->addText(fl, varp->name() + "_seq__V <= " + varp->name() + "_tmp__V;\n");
m_seqAssignsp->addText(fl, varp->name() + " = " + varp->name() + "_seq__V;\n");
m_comboAssignsp->addText(fl, varp->name() + " = " + varp->name() + "_combo__V;\n");
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
m_cComboOutsp->addText(fl,
V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->"));
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
m_cSeqOutsp->addText(fl, V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->"));
}
public:
explicit ProtectVisitor(AstNode* nodep):
m_vfilep(NULL), m_cfilep(NULL), m_modPortsp(NULL),
m_comboPortsp(NULL), m_seqPortsp(NULL), m_comboIgnorePortsp(NULL), m_comboDeclsp(NULL),
m_seqDeclsp(NULL), m_tmpDeclsp(NULL), m_hashValuep(NULL),
m_comboParamsp(NULL),
m_clkSensp(NULL),
m_comboIgnoreParamsp(NULL), m_seqParamsp(NULL), m_nbAssignsp(NULL), m_seqAssignsp(NULL),
m_comboAssignsp(NULL), m_cHashValuep(NULL), m_cComboParamsp(NULL), m_cComboInsp(NULL),
m_cComboOutsp(NULL), m_cSeqParamsp(NULL), m_cSeqClksp(NULL), m_cSeqOutsp(NULL),
m_cIgnoreParamsp(NULL), m_libName(v3Global.opt.protectLib()),
m_topName(v3Global.opt.prefix()), m_foundTop(false)
{
public:
explicit ProtectVisitor(AstNode* nodep)
: m_vfilep(NULL)
, m_cfilep(NULL)
, m_modPortsp(NULL)
, m_comboPortsp(NULL)
, m_seqPortsp(NULL)
, m_comboIgnorePortsp(NULL)
, m_comboDeclsp(NULL)
, m_seqDeclsp(NULL)
, m_tmpDeclsp(NULL)
, m_hashValuep(NULL)
, m_comboParamsp(NULL)
, m_clkSensp(NULL)
, m_comboIgnoreParamsp(NULL)
, m_seqParamsp(NULL)
, m_nbAssignsp(NULL)
, m_seqAssignsp(NULL)
, m_comboAssignsp(NULL)
, m_cHashValuep(NULL)
, m_cComboParamsp(NULL)
, m_cComboInsp(NULL)
, m_cComboOutsp(NULL)
, m_cSeqParamsp(NULL)
, m_cSeqClksp(NULL)
, m_cSeqOutsp(NULL)
, m_cIgnoreParamsp(NULL)
, m_libName(v3Global.opt.protectLib())
, m_topName(v3Global.opt.prefix())
, m_foundTop(false) {
iterate(nodep);
}
};

View File

@ -43,8 +43,8 @@ private:
// NODE STATE
// AstVar::user1p -> AstVarScope replacement for this variable
// AstTask::user2p -> AstTask*. Replacement task
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
// TYPES
typedef vl_unordered_map<AstNodeModule*, AstScope*> PackageScopeMap;
@ -53,26 +53,25 @@ private:
typedef std::set<std::pair<AstVarRef*, AstScope*> > VarRefScopeSet;
// STATE, inside processing a single module
AstNodeModule* m_modp; // Current module
AstScope* m_scopep; // Current scope we are building
AstNodeModule* m_modp; // Current module
AstScope* m_scopep; // Current scope we are building
// STATE, for passing down one level of hierarchy (may need save/restore)
AstCell* m_aboveCellp; // Cell that instantiates this module
AstScope* m_aboveScopep; // Scope that instantiates this scope
AstCell* m_aboveCellp; // Cell that instantiates this module
AstScope* m_aboveScopep; // Scope that instantiates this scope
PackageScopeMap m_packageScopes; // Scopes for each package
VarScopeMap m_varScopes; // Varscopes created for each scope and var
VarRefScopeSet m_varRefScopes; // Varrefs-in-scopes needing fixup when done
PackageScopeMap m_packageScopes; // Scopes for each package
VarScopeMap m_varScopes; // Varscopes created for each scope and var
VarRefScopeSet m_varRefScopes; // Varrefs-in-scopes needing fixup when done
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void cleanupVarRefs() {
for (VarRefScopeSet::iterator it = m_varRefScopes.begin();
it!=m_varRefScopes.end(); ++it) {
for (VarRefScopeSet::iterator it = m_varRefScopes.begin(); it != m_varRefScopes.end();
++it) {
AstVarRef* nodep = it->first;
AstScope* scopep = it->second;
if (nodep->packagep()
&& !nodep->varp()->isClassMember()) {
if (nodep->packagep() && !nodep->varp()->isClassMember()) {
PackageScopeMap::iterator it2 = m_packageScopes.find(nodep->packagep());
UASSERT_OBJ(it2 != m_packageScopes.end(), nodep, "Can't locate package scope");
scopep = it2->second;
@ -87,7 +86,10 @@ private:
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
AstNodeModule* modp = nodep->topModulep();
if (!modp) { nodep->v3error("No top level module found"); return; }
if (!modp) {
nodep->v3error("No top level module found");
return;
}
// Operate starting at the top of the hierarchy
m_aboveCellp = NULL;
m_aboveScopep = NULL;
@ -97,22 +99,25 @@ private:
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
// Create required blocks and add to module
string scopename;
if (!m_aboveScopep) scopename = "TOP";
else scopename = m_aboveScopep->name()+"."+m_aboveCellp->name();
if (!m_aboveScopep) {
scopename = "TOP";
} else {
scopename = m_aboveScopep->name() + "." + m_aboveCellp->name();
}
UINFO(4," MOD AT "<<scopename<<" "<<nodep<<endl);
UINFO(4, " MOD AT " << scopename << " " << nodep << endl);
AstNode::user1ClearTree();
m_scopep = new AstScope((m_aboveCellp ? static_cast<AstNode*>(m_aboveCellp)
: static_cast<AstNode*>(nodep))
->fileline(),
nodep, scopename, m_aboveScopep, m_aboveCellp);
m_scopep = new AstScope(
(m_aboveCellp ? static_cast<AstNode*>(m_aboveCellp) : static_cast<AstNode*>(nodep))
->fileline(),
nodep, scopename, m_aboveScopep, m_aboveCellp);
if (VN_IS(nodep, Package)) {
m_packageScopes.insert(make_pair(VN_CAST(nodep, Package), m_scopep));
}
// Now for each child cell, iterate the module this cell points to
for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp=cellnextp->nextp()) {
for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp = cellnextp->nextp()) {
if (AstCell* cellp = VN_CAST(cellnextp, Cell)) {
AstScope* oldScopep = m_scopep;
AstCell* oldAbCellp = m_aboveCellp;
@ -132,7 +137,7 @@ private:
}
// Create scope for the current usage of this module
UINFO(4," back AT "<<scopename<<" "<<nodep<<endl);
UINFO(4, " back AT " << scopename << " " << nodep << endl);
AstNode::user1ClearTree();
m_modp = nodep;
if (m_modp->isTop()) {
@ -168,8 +173,8 @@ private:
AstNode* abovep = (m_aboveCellp ? static_cast<AstNode*>(m_aboveCellp)
: static_cast<AstNode*>(nodep));
m_scopep = new AstScope(abovep->fileline(),
m_modp, scopename, m_aboveScopep, m_aboveCellp);
m_scopep
= new AstScope(abovep->fileline(), m_modp, scopename, m_aboveScopep, m_aboveCellp);
// Create scope for the current usage of this cell
AstNode::user1ClearTree();
nodep->addMembersp(m_scopep);
@ -181,7 +186,7 @@ private:
m_aboveCellp = oldAbCellp;
m_aboveScopep = oldAbScopep;
}
virtual void visit(AstCellInline* nodep) VL_OVERRIDE {
virtual void visit(AstCellInline* nodep) VL_OVERRIDE { //
nodep->scopep(m_scopep);
}
virtual void visit(AstActive* nodep) VL_OVERRIDE {
@ -189,7 +194,7 @@ private:
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
UINFO(4, " Move " << nodep << endl);
AstInitial* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
@ -197,7 +202,7 @@ private:
}
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
UINFO(4, " Move " << nodep << endl);
AstFinal* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
@ -205,7 +210,7 @@ private:
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
UINFO(4, " Move " << nodep << endl);
AstNode* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
@ -213,7 +218,7 @@ private:
}
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE {
// Copy under the scope but don't recurse
UINFO(4," Move "<<nodep<<endl);
UINFO(4, " Move " << nodep << endl);
AstNode* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
@ -221,7 +226,7 @@ private:
}
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
UINFO(4, " Move " << nodep << endl);
AstNode* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
@ -229,7 +234,7 @@ private:
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
UINFO(4, " Move " << nodep << endl);
AstNode* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
@ -237,7 +242,7 @@ private:
}
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
UINFO(4, " Move " << nodep << endl);
AstNode* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
@ -245,7 +250,7 @@ private:
}
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
UINFO(4, " Move " << nodep << endl);
AstNode* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
@ -253,7 +258,7 @@ private:
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
// Add to list of blocks under this scope
UINFO(4," CFUNC "<<nodep<<endl);
UINFO(4, " CFUNC " << nodep << endl);
AstCFunc* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
@ -263,7 +268,7 @@ private:
}
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
// Add to list of blocks under this scope
UINFO(4," FTASK "<<nodep<<endl);
UINFO(4, " FTASK " << nodep << endl);
AstNodeFTask* clonep;
if (nodep->classMethod()) {
// Only one scope will be created, so avoid pointless cloning
@ -281,7 +286,7 @@ private:
// Make new scope variable
if (!nodep->user1p()) {
AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep);
UINFO(6," New scope "<<varscp<<endl);
UINFO(6, " New scope " << varscp << endl);
if (m_aboveCellp && !m_aboveCellp->isTrace()) varscp->trace(false);
nodep->user1p(varscp);
if (v3Global.opt.isClocker(varscp->prettyName())) {
@ -307,10 +312,10 @@ private:
// So push to a list and post-correct
m_varRefScopes.insert(make_pair(nodep, m_scopep));
}
}
}
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
// If there's a %m in the display text, we add a special node that will contain the name()
string prefix = string("__DOT__")+m_scopep->name();
string prefix = string("__DOT__") + m_scopep->name();
// TOP and above will be the user's name().
// Note 'TOP.' is stripped by scopePrettyName
// To keep correct visual order, must add before other Text's
@ -375,36 +380,16 @@ private:
}
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
virtual void visit(AstFinal* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
virtual void visit(AstAlways* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
// The crossrefs are dealt with in V3LinkDot
@ -412,17 +397,17 @@ private:
}
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
// The crossrefs are dealt with in V3LinkDot
UINFO(9," Old pkg-taskref "<<nodep<<endl);
UINFO(9, " Old pkg-taskref " << nodep << endl);
if (nodep->packagep()) {
// Point to the clone
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked");
AstNodeFTask* newp = VN_CAST(nodep->taskp()->user2p(), NodeFTask);
UASSERT_OBJ(newp, nodep, "No clone for package function");
nodep->taskp(newp);
UINFO(9," New pkg-taskref "<<nodep<<endl);
UINFO(9, " New pkg-taskref " << nodep << endl);
} else if (!VN_IS(nodep, MethodCall)) {
nodep->taskp(NULL);
UINFO(9," New pkg-taskref "<<nodep<<endl);
UINFO(9, " New pkg-taskref " << nodep << endl);
}
iterateChildren(nodep);
}
@ -448,10 +433,10 @@ public:
// Scope class functions
void V3Scope::scopeAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
{
ScopeVisitor visitor (nodep);
ScopeCleanupVisitor cleanVisitor (nodep);
ScopeVisitor visitor(nodep);
ScopeCleanupVisitor cleanVisitor(nodep);
} // Destruct before checking
V3Global::dumpCheckGlobalTree("scope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -116,8 +116,9 @@ private:
// Don't grab SenTrees under Actives, only those that are global (under Scope directly)
iterateChildren(nodep);
}
virtual void visit(AstSenTree* nodep) VL_OVERRIDE { m_trees.add(nodep); }
virtual void visit(AstSenTree* nodep) VL_OVERRIDE { //
m_trees.add(nodep);
}
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }

View File

@ -89,21 +89,21 @@ private:
// STATE
// Major mode
bool m_checkOnly; ///< Checking only (no simulation) mode
bool m_scoped; ///< Running with AstVarScopes instead of AstVars
bool m_params; ///< Doing parameter propagation
bool m_checkOnly; ///< Checking only (no simulation) mode
bool m_scoped; ///< Running with AstVarScopes instead of AstVars
bool m_params; ///< Doing parameter propagation
// Checking:
string m_whyNotOptimizable; ///< String explaining why not optimizable or NULL to optimize
AstNode* m_whyNotNodep; ///< First node not optimizable
bool m_anyAssignDly; ///< True if found a delayed assignment
bool m_anyAssignComb; ///< True if found a non-delayed assignment
bool m_inDlyAssign; ///< Under delayed assignment
int m_instrCount; ///< Number of nodes
int m_dataCount; ///< Bytes of data
AstJumpGo* m_jumpp; ///< Jump label we're branching from
string m_whyNotOptimizable; ///< String explaining why not optimizable or NULL to optimize
AstNode* m_whyNotNodep; ///< First node not optimizable
bool m_anyAssignDly; ///< True if found a delayed assignment
bool m_anyAssignComb; ///< True if found a non-delayed assignment
bool m_inDlyAssign; ///< Under delayed assignment
int m_instrCount; ///< Number of nodes
int m_dataCount; ///< Bytes of data
AstJumpGo* m_jumpp; ///< Jump label we're branching from
// Simulating:
ConstPile m_constFreeps; ///< List of all AstConst* free and not in use
ConstPile m_constAllps; ///< List of all AstConst* free and in use
ConstPile m_constFreeps; ///< List of all AstConst* free and not in use
ConstPile m_constAllps; ///< List of all AstConst* free and in use
std::deque<SimStackNode*> m_callStack; ///< Call stack for verbose error messages
// Cleanup
@ -116,35 +116,35 @@ private:
// Potentially very slow, intended for debugging
string prettyNumber(const V3Number* nump, AstNodeDType* dtypep) {
if (AstRefDType* refdtypep = VN_CAST(dtypep, RefDType)) {
if (AstRefDType* refdtypep = VN_CAST(dtypep, RefDType)) { //
dtypep = refdtypep->skipRefp();
}
if (AstStructDType* stp = VN_CAST(dtypep, StructDType)) {
if (stp->packed()) {
std::ostringstream out;
out<<"'{";
for (AstMemberDType* itemp = stp->membersp();
itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
out << "'{";
for (AstMemberDType* itemp = stp->membersp(); itemp;
itemp = VN_CAST(itemp->nextp(), MemberDType)) {
int width = itemp->width();
int lsb = itemp->lsb();
int msb = lsb + width - 1;
V3Number fieldNum(nump, width);
fieldNum.opSel(*nump, msb, lsb);
out<<itemp->name()<<": ";
out << itemp->name() << ": ";
if (AstNodeDType* childTypep = itemp->subDTypep()) {
out<<prettyNumber(&fieldNum, childTypep);
out << prettyNumber(&fieldNum, childTypep);
} else {
out<<fieldNum;
out << fieldNum;
}
if (itemp->nextp()) out<<", ";
if (itemp->nextp()) out << ", ";
}
out<<"}";
out << "}";
return out.str();
}
} else if (AstPackArrayDType* arrayp = VN_CAST(dtypep, PackArrayDType)) {
if (AstNodeDType* childTypep = arrayp->subDTypep()) {
std::ostringstream out;
out<<"[";
out << "[";
int arrayElements = arrayp->elementsConst();
for (int element = 0; element < arrayElements; ++element) {
int width = childTypep->width();
@ -153,10 +153,10 @@ private:
V3Number fieldNum(nump, width);
fieldNum.opSel(*nump, msb, lsb);
int arrayElem = arrayp->lsb() + element;
out<<arrayElem<<" = "<<prettyNumber(&fieldNum, childTypep);
if (element < arrayElements - 1) out<<", ";
out << arrayElem << " = " << prettyNumber(&fieldNum, childTypep);
if (element < arrayElements - 1) out << ", ";
}
out<<"]";
out << "]";
return out.str();
}
}
@ -168,32 +168,31 @@ public:
/// Call other-this function on all new *non-constant* var references
virtual void varRefCb(AstVarRef* nodep) {}
void clearOptimizable(AstNode* nodep/*null ok*/, const string& why) {
void clearOptimizable(AstNode* nodep /*null ok*/, const string& why) {
// Something bad found. optimizable() will return false,
// and fetchConst should not be called or it may assert.
if (!m_whyNotNodep) {
m_whyNotNodep = nodep;
if (debug() >= 5) {
UINFO(0, "Clear optimizable: "<<why);
if (nodep) cout<<": "<<nodep;
cout<<endl;
UINFO(0, "Clear optimizable: " << why);
if (nodep) cout << ": " << nodep;
cout << endl;
}
m_whyNotOptimizable = why;
std::ostringstream stack;
for (std::deque<SimStackNode*>::iterator it = m_callStack.begin();
it != m_callStack.end(); ++it) {
AstFuncRef* funcp = (*it)->m_funcp;
stack<<"\n "<<funcp->fileline()
<<"... Called from "
<<funcp->prettyName()<<"() with parameters:";
stack << "\n " << funcp->fileline() << "... Called from "
<< funcp->prettyName() << "() with parameters:";
V3TaskConnects* tconnects = (*it)->m_tconnects;
for (V3TaskConnects::iterator conIt = tconnects->begin();
conIt != tconnects->end(); ++conIt) {
AstVar* portp = conIt->first;
AstNode* pinp = conIt->second->exprp();
AstNodeDType* dtypep = pinp->dtypep();
stack<<"\n "<<portp->prettyName(
)<<" = "<<prettyNumber(&fetchConst(pinp)->num(), dtypep);
stack << "\n " << portp->prettyName() << " = "
<< prettyNumber(&fetchConst(pinp)->num(), dtypep);
}
}
m_whyNotOptimizable += stack.str();
@ -216,11 +215,12 @@ private:
AstConst* constp;
AstNodeDType* dtypep = nodep->dtypep();
if (!m_constFreeps[dtypep].empty()) {
//UINFO(7, "Num Reuse "<<nodep->width()<<endl);
constp = m_constFreeps[dtypep].back(); m_constFreeps[dtypep].pop_back();
// UINFO(7, "Num Reuse " << nodep->width() << endl);
constp = m_constFreeps[dtypep].back();
m_constFreeps[dtypep].pop_back();
constp->num().nodep(nodep);
} else {
//UINFO(7, "Num New "<<nodep->width()<<endl);
// UINFO(7, "Num New " << nodep->width() << endl);
constp = new AstConst(nodep->fileline(), AstConst::DtypedValue(), nodep->dtypep(), 0);
m_constAllps[constp->dtypep()].push_back(constp);
}
@ -228,6 +228,7 @@ private:
constp->num().isString(nodep->isString());
return constp;
}
public:
void newValue(AstNode* nodep, const AstNode* valuep) {
if (const AstConst* constp = VN_CAST_CONST(valuep, Const)) {
@ -245,6 +246,7 @@ public:
setOutValue(nodep, newTrackedClone(const_cast<AstNode*>(valuep)));
}
}
private:
AstNode* newTrackedClone(AstNode* nodep) {
AstNode* newp = nodep->cloneTree(false);
@ -271,30 +273,26 @@ private:
return fetchOutConst(nodep);
}
}
public:
AstNode* fetchValueNull(AstNode* nodep) {
return nodep->user3p();
}
AstNode* fetchValueNull(AstNode* nodep) { return nodep->user3p(); }
private:
AstNode* fetchOutValueNull(AstNode* nodep) {
return nodep->user2p();
}
AstConst* fetchConstNull(AstNode* nodep) {
return VN_CAST(fetchValueNull(nodep), Const);
}
AstNode* fetchOutValueNull(AstNode* nodep) { return nodep->user2p(); }
AstConst* fetchConstNull(AstNode* nodep) { return VN_CAST(fetchValueNull(nodep), Const); }
AstConst* fetchOutConstNull(AstNode* nodep) {
return VN_CAST(fetchOutValueNull(nodep), Const);
}
AstNode* fetchValue(AstNode* nodep) {
AstNode* valuep = fetchValueNull(nodep);
UASSERT_OBJ(valuep, nodep, "No value found for node.");
//UINFO(9, " fetch val "<<*valuep<<" on "<<nodep<<endl);
// UINFO(9, " fetch val " << *valuep << " on " << nodep << endl);
return valuep;
}
AstConst* fetchConst(AstNode* nodep) {
AstConst* constp = fetchConstNull(nodep);
UASSERT_OBJ(constp, nodep, "No value found for node.");
//UINFO(9, " fetch num "<<*constp<<" on "<<nodep<<endl);
// UINFO(9, " fetch num " << *constp << " on " << nodep << endl);
return constp;
}
AstConst* fetchOutConst(AstNode* nodep) {
@ -302,6 +300,7 @@ private:
UASSERT_OBJ(constp, nodep, "No value found for node.");
return constp;
}
public:
V3Number* fetchNumberNull(AstNode* nodep) {
AstConst* constp = fetchConstNull(nodep);
@ -313,15 +312,16 @@ public:
if (constp) return &constp->num();
return NULL;
}
private:
void setValue(AstNode* nodep, const AstNode* valuep) {
UASSERT_OBJ(valuep, nodep, "Simulate setting null value");
UINFO(9, " set val "<<valuep->name()<<" on "<<nodep<<endl);
UINFO(9, " set val " << valuep->name() << " on " << nodep << endl);
nodep->user3p((void*)valuep);
}
void setOutValue(AstNode* nodep, const AstNode* valuep) {
UASSERT_OBJ(valuep, nodep, "Simulate setting null value");
UINFO(9, " set oval "<<valuep->name()<<" on "<<nodep<<endl);
UINFO(9, " set oval " << valuep->name() << " on " << nodep << endl);
nodep->user2p((void*)valuep);
}
@ -331,7 +331,7 @@ private:
m_dataCount += nodep->width();
}
if (!nodep->isPredictOptimizable()) {
//UINFO(9, " !predictopt "<<nodep<<endl);
// UINFO(9, " !predictopt " << nodep << endl);
clearOptimizable(nodep, "Isn't predictable");
}
}
@ -342,17 +342,21 @@ private:
if (optimizable()) {
// Hmm, what is this then?
// In production code, we'll just not optimize. It should be fixed though.
clearOptimizable(nodep, "Unknown node type, perhaps missing visitor in SimulateVisitor");
clearOptimizable(nodep,
"Unknown node type, perhaps missing visitor in SimulateVisitor");
#ifdef VL_DEBUG
UINFO(0, "Unknown node type in SimulateVisitor: "<<nodep->prettyTypeName()<<endl);
UINFO(0, "Unknown node type in SimulateVisitor: " << nodep->prettyTypeName() << endl);
#endif
}
}
AstNode* varOrScope(AstVarRef* nodep) {
AstNode* vscp;
if (m_scoped) vscp = nodep->varScopep();
else vscp = nodep->varp();
if (m_scoped) {
vscp = nodep->varScopep();
} else {
vscp = nodep->varp();
}
UASSERT_OBJ(vscp, nodep, "Not linked");
return vscp;
}
@ -420,10 +424,9 @@ private:
vscp->user1(vscp->user1() | VU_RV);
bool isConst = nodep->varp()->isParam() && nodep->varp()->valuep();
AstNode* valuep = isConst ? fetchValueNull(nodep->varp()->valuep()) : NULL;
if (isConst && valuep) { // Propagate PARAM constants for constant function analysis
if (!m_checkOnly && optimizable()) {
newValue(vscp, valuep);
}
if (isConst
&& valuep) { // Propagate PARAM constants for constant function analysis
if (!m_checkOnly && optimizable()) newValue(vscp, valuep);
} else {
if (m_checkOnly) varRefCb(nodep);
}
@ -437,9 +440,11 @@ private:
AstNode* valuep = fetchValueNull(vscp);
if (!valuep) {
if (m_params) {
clearOptimizable(nodep, "Language violation: reference to non-function-local variable");
clearOptimizable(
nodep, "Language violation: reference to non-function-local variable");
} else {
nodep->v3fatalSrc("Variable value should have been set before any visitor called.");
nodep->v3fatalSrc(
"Variable value should have been set before any visitor called.");
}
valuep = allocConst(nodep); // Any value; just so recover from error
}
@ -449,12 +454,20 @@ private:
}
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
if (jumpingOver(nodep)) return;
if (m_scoped) { badNodeType(nodep); return; }
else { clearOptimizable(nodep, "Language violation: Dotted hierarchical references not allowed in constant functions"); }
if (m_scoped) {
badNodeType(nodep);
return;
} else {
clearOptimizable(nodep, "Language violation: Dotted hierarchical references not "
"allowed in constant functions");
}
}
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
if (jumpingOver(nodep)) return;
if (!m_params) { badNodeType(nodep); return; }
if (!m_params) {
badNodeType(nodep);
return;
}
if (nodep->dpiImport()) {
clearOptimizable(nodep, "DPI import functions aren't simulatable");
}
@ -463,7 +476,7 @@ private:
}
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
if (jumpingOver(nodep)) return;
UINFO(5, " IF "<<nodep<<endl);
UINFO(5, " IF " << nodep << endl);
checkNodeInfo(nodep);
if (m_checkOnly) {
iterateChildren(nodep);
@ -480,15 +493,11 @@ private:
}
virtual void visit(AstConst* nodep) VL_OVERRIDE {
checkNodeInfo(nodep);
if (!m_checkOnly && optimizable()) {
newValue(nodep, nodep);
}
if (!m_checkOnly && optimizable()) newValue(nodep, nodep);
}
virtual void visit(AstInitArray* nodep) VL_OVERRIDE {
checkNodeInfo(nodep);
if (!m_checkOnly && optimizable()) {
newValue(nodep, nodep);
}
if (!m_checkOnly && optimizable()) newValue(nodep, nodep);
}
virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE {
checkNodeInfo(nodep);
@ -497,9 +506,7 @@ private:
AstNode* valuep = nodep->itemp()->valuep();
if (valuep) {
iterateAndNextNull(valuep);
if (optimizable()) {
newValue(nodep, fetchValue(valuep));
}
if (optimizable()) newValue(nodep, fetchValue(valuep));
} else {
clearOptimizable(nodep, "No value found for enum item");
}
@ -510,8 +517,7 @@ private:
checkNodeInfo(nodep);
iterateChildren(nodep);
if (!m_checkOnly && optimizable()) {
nodep->numberOperate(newConst(nodep)->num(),
fetchConst(nodep->lhsp())->num());
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num());
}
}
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
@ -519,8 +525,7 @@ private:
checkNodeInfo(nodep);
iterateChildren(nodep);
if (!m_checkOnly && optimizable()) {
nodep->numberOperate(newConst(nodep)->num(),
fetchConst(nodep->lhsp())->num(),
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(),
fetchConst(nodep->rhsp())->num());
}
}
@ -529,8 +534,7 @@ private:
checkNodeInfo(nodep);
iterateChildren(nodep);
if (!m_checkOnly && optimizable()) {
nodep->numberOperate(newConst(nodep)->num(),
fetchConst(nodep->lhsp())->num(),
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(),
fetchConst(nodep->rhsp())->num(),
fetchConst(nodep->thsp())->num());
}
@ -652,7 +656,7 @@ private:
}
uint32_t index = fetchConst(selp->bitp())->toUInt();
AstNode* valuep = newTrackedClone(fetchValue(nodep->rhsp()));
UINFO(9, " set val["<<index<<"] = "<<valuep<<endl);
UINFO(9, " set val[" << index << "] = " << valuep << endl);
// Values are in the "real" tree under the InitArray so can eventually extract it,
// Not in the usual setValue (pointed to by user2/3p)
initp->addIndexValuep(index, valuep);
@ -664,7 +668,7 @@ private:
AstVarRef* varrefp = NULL;
V3Number lsb(nodep);
iterateAndNextNull(nodep->rhsp()); // Value to assign
handleAssignSelRecurse(nodep, selp, varrefp/*ref*/, lsb/*ref*/, 0);
handleAssignSelRecurse(nodep, selp, varrefp /*ref*/, lsb /*ref*/, 0);
if (!m_checkOnly && optimizable()) {
UASSERT_OBJ(varrefp, nodep,
"Indicated optimizable, but no variable found on RHS of select");
@ -683,15 +687,12 @@ private:
outconstp->num().setAllBitsX();
}
}
outconstp->num().opSelInto(fetchConst(nodep->rhsp())->num(),
lsb,
selp->widthConst());
outconstp->num().opSelInto(fetchConst(nodep->rhsp())->num(), lsb, selp->widthConst());
assignOutValue(nodep, vscp, outconstp);
}
}
void handleAssignSelRecurse(AstNodeAssign* nodep, AstSel* selp,
AstVarRef*& outVarrefpRef, V3Number& lsbRef,
int depth) {
void handleAssignSelRecurse(AstNodeAssign* nodep, AstSel* selp, AstVarRef*& outVarrefpRef,
V3Number& lsbRef, int depth) {
// Recurse down to find final variable being set (outVarrefp), with
// lsb to be eventually set on lsbRef
checkNodeInfo(selp);
@ -702,7 +703,7 @@ private:
return; // And presumably still optimizable()
} else if (AstSel* subselp = VN_CAST(selp->lhsp(), Sel)) {
V3Number sublsb(nodep);
handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb/*ref*/, depth+1);
handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb /*ref*/, depth + 1);
if (optimizable()) {
lsbRef = sublsb;
lsbRef.opAdd(sublsb, fetchConst(selp->lsbp())->num());
@ -725,20 +726,22 @@ private:
}
if (AstSel* selp = VN_CAST(nodep->lhsp(), Sel)) {
if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; }
if (!m_params) {
clearOptimizable(nodep, "LHS has select");
return;
}
handleAssignSel(nodep, selp);
}
else if (AstArraySel* selp = VN_CAST(nodep->lhsp(), ArraySel)) {
if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; }
} else if (AstArraySel* selp = VN_CAST(nodep->lhsp(), ArraySel)) {
if (!m_params) {
clearOptimizable(nodep, "LHS has select");
return;
}
handleAssignArray(nodep, selp);
}
else if (!VN_IS(nodep->lhsp(), VarRef)) {
} else if (!VN_IS(nodep->lhsp(), VarRef)) {
clearOptimizable(nodep, "LHS isn't simple variable");
}
else if (m_checkOnly) {
} else if (m_checkOnly) {
iterateChildren(nodep);
}
else if (optimizable()) {
} else if (optimizable()) {
iterateAndNextNull(nodep->rhsp());
if (optimizable()) {
AstNode* vscp = varOrScope(VN_CAST(nodep->lhsp(), VarRef));
@ -756,7 +759,7 @@ private:
AstNode* itemp = initp->getIndexDefaultedValuep(offset);
if (!itemp) {
clearOptimizable(nodep, "Array initialization has too few elements, need element "
+cvtToStr(offset));
+ cvtToStr(offset));
} else {
setValue(nodep, itemp);
}
@ -770,15 +773,15 @@ private:
}
virtual void visit(AstNodeCase* nodep) VL_OVERRIDE {
if (jumpingOver(nodep)) return;
UINFO(5, " CASE "<<nodep<<endl);
UINFO(5, " CASE " << nodep << endl);
checkNodeInfo(nodep);
if (m_checkOnly) {
iterateChildren(nodep);
} else if (optimizable()) {
iterateAndNextNull(nodep->exprp());
bool hit = false;
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
if (!itemp->isDefault()) {
for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) {
if (hit) break;
@ -795,8 +798,8 @@ private:
}
}
// Else default match
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) {
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
if (hit) break;
if (!hit && itemp->isDefault()) {
iterateAndNextNull(itemp->bodysp());
@ -819,7 +822,7 @@ private:
if (jumpingOver(nodep)) return;
checkNodeInfo(nodep);
if (!m_checkOnly) {
UINFO(5, " JUMP GO "<<nodep<<endl);
UINFO(5, " JUMP GO " << nodep << endl);
m_jumpp = nodep;
}
}
@ -828,7 +831,7 @@ private:
checkNodeInfo(nodep);
iterateChildren(nodep);
if (m_jumpp && m_jumpp->labelp() == nodep) {
UINFO(5, " JUMP DONE "<<nodep<<endl);
UINFO(5, " JUMP DONE " << nodep << endl);
m_jumpp = NULL;
}
}
@ -836,15 +839,20 @@ private:
if (jumpingOver(nodep)) return;
if (m_params) { // This message seems better than an obscure $stop
// The spec says $stop is just ignored, it seems evil to ignore assertions
clearOptimizable(nodep, "$stop executed during function constification; maybe indicates assertion firing");
clearOptimizable(
nodep,
"$stop executed during function constification; maybe indicates assertion firing");
}
checkNodeInfo(nodep);
}
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE {
// Doing lots of Whiles is slow, so only for parameters
UINFO(5, " FOR "<<nodep<<endl);
if (!m_params) { badNodeType(nodep); return; }
UINFO(5, " FOR " << nodep << endl);
if (!m_params) {
badNodeType(nodep);
return;
}
checkNodeInfo(nodep);
if (m_checkOnly) {
iterateChildren(nodep);
@ -852,18 +860,18 @@ private:
int loops = 0;
iterateAndNextNull(nodep->initsp());
while (true) {
UINFO(5, " FOR-ITER "<<nodep<<endl);
UINFO(5, " FOR-ITER " << nodep << endl);
iterateAndNextNull(nodep->condp());
if (!optimizable()) break;
if (!fetchConst(nodep->condp())->num().isNeqZero()) {
if (!fetchConst(nodep->condp())->num().isNeqZero()) { //
break;
}
iterateAndNextNull(nodep->bodysp());
iterateAndNextNull(nodep->incsp());
if (loops++ > unrollCount()*16) {
if (loops++ > unrollCount() * 16) {
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an"
"infinite loop, or set --unroll-count above "
+ cvtToStr(unrollCount()));
"infinite loop, or set --unroll-count above "
+ cvtToStr(unrollCount()));
break;
}
}
@ -873,21 +881,24 @@ private:
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
// Doing lots of Whiles is slow, so only for parameters
if (jumpingOver(nodep)) return;
UINFO(5, " WHILE "<<nodep<<endl);
if (!m_params) { badNodeType(nodep); return; }
UINFO(5, " WHILE " << nodep << endl);
if (!m_params) {
badNodeType(nodep);
return;
}
checkNodeInfo(nodep);
if (m_checkOnly) {
iterateChildren(nodep);
} else if (optimizable()) {
int loops = 0;
while (true) {
UINFO(5, " WHILE-ITER "<<nodep<<endl);
UINFO(5, " WHILE-ITER " << nodep << endl);
iterateAndNextNull(nodep->precondsp());
if (jumpingOver(nodep)) break;
iterateAndNextNull(nodep->condp());
if (jumpingOver(nodep)) break;
if (!optimizable()) break;
if (!fetchConst(nodep->condp())->num().isNeqZero()) {
if (!fetchConst(nodep->condp())->num().isNeqZero()) { //
break;
}
iterateAndNextNull(nodep->bodysp());
@ -896,9 +907,11 @@ private:
if (jumpingOver(nodep)) break;
// Prep for next loop
if (loops++ > unrollCount()*16) {
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite"
" loop, or set --unroll-count above "+cvtToStr(unrollCount()));
if (loops++ > unrollCount() * 16) {
clearOptimizable(nodep,
"Loop unrolling took too long; probably this is an infinite"
" loop, or set --unroll-count above "
+ cvtToStr(unrollCount()));
break;
}
}
@ -908,12 +921,17 @@ private:
virtual void visit(AstFuncRef* nodep) VL_OVERRIDE {
if (jumpingOver(nodep)) return;
if (!optimizable()) return; // Accelerate
UINFO(5, " FUNCREF "<<nodep<<endl);
if (!m_params) { badNodeType(nodep); return; }
UINFO(5, " FUNCREF " << nodep << endl);
if (!m_params) {
badNodeType(nodep);
return;
}
AstNodeFTask* funcp = VN_CAST(nodep->taskp(), NodeFTask);
UASSERT_OBJ(funcp, nodep, "Not linked");
if (m_params) { V3Width::widthParamsEdit(funcp); } VL_DANGLING(funcp); // Make sure we've sized the function
funcp = VN_CAST(nodep->taskp(), NodeFTask); UASSERT_OBJ(funcp, nodep, "Not linked");
if (m_params) V3Width::widthParamsEdit(funcp);
VL_DANGLING(funcp); // Make sure we've sized the function
funcp = VN_CAST(nodep->taskp(), NodeFTask);
UASSERT_OBJ(funcp, nodep, "Not linked");
// Apply function call values to function
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
// Must do this in two steps, eval all params, then apply them
@ -923,7 +941,9 @@ private:
AstNode* pinp = it->second->exprp();
if (pinp) { // Else too few arguments in function call - ignore it
if (portp->isWritable()) {
clearOptimizable(portp, "Language violation: Outputs/refs not allowed in constant functions");
clearOptimizable(
portp,
"Language violation: Outputs/refs not allowed in constant functions");
return;
}
// Evaluate pin value
@ -935,9 +955,7 @@ private:
AstNode* pinp = it->second->exprp();
if (pinp) { // Else too few arguments in function call - ignore it
// Apply value to the function
if (!m_checkOnly && optimizable()) {
newValue(portp, fetchValue(pinp));
}
if (!m_checkOnly && optimizable()) newValue(portp, fetchValue(pinp));
}
}
SimStackNode stackNode(nodep, &tconnects);
@ -954,7 +972,10 @@ private:
virtual void visit(AstVar* nodep) VL_OVERRIDE {
if (jumpingOver(nodep)) return;
if (!m_params) { badNodeType(nodep); return; }
if (!m_params) {
badNodeType(nodep);
return;
}
}
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
@ -986,7 +1007,8 @@ private:
nextArgp = nextArgp->nextp();
AstConst* constp = fetchConstNull(argp);
if (!constp) {
clearOptimizable(nodep, "Argument for $display like statement is not constant");
clearOptimizable(
nodep, "Argument for $display like statement is not constant");
break;
}
string pformat = string("%") + pos[0];
@ -1051,6 +1073,7 @@ private:
iterate(nodep);
UASSERT_OBJ(!m_jumpp, m_jumpp, "JumpGo branched to label that wasn't found");
}
public:
// CONSTRUCTORS
SimulateVisitor() {
@ -1076,26 +1099,24 @@ public:
m_constFreeps = m_constAllps;
}
void mainTableCheck(AstNode* nodep) {
setMode(true/*scoped*/, true/*checking*/, false/*params*/);
setMode(true /*scoped*/, true /*checking*/, false /*params*/);
mainGuts(nodep);
}
void mainTableEmulate(AstNode* nodep) {
setMode(true/*scoped*/, false/*checking*/, false/*params*/);
setMode(true /*scoped*/, false /*checking*/, false /*params*/);
mainGuts(nodep);
}
void mainCheckTree(AstNode* nodep) {
setMode(false/*scoped*/, true/*checking*/, false/*params*/);
setMode(false /*scoped*/, true /*checking*/, false /*params*/);
mainGuts(nodep);
}
void mainParamEmulate(AstNode* nodep) {
setMode(false/*scoped*/, false/*checking*/, true/*params*/);
setMode(false /*scoped*/, false /*checking*/, true /*params*/);
mainGuts(nodep);
}
virtual ~SimulateVisitor() {
for (ConstPile::iterator it = m_constAllps.begin();
it != m_constAllps.end(); ++it) {
for (ConstDeque::iterator it2 = it->second.begin();
it2 != it->second.end(); ++it2) {
for (ConstPile::iterator it = m_constAllps.begin(); it != m_constAllps.end(); ++it) {
for (ConstDeque::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
delete (*it2);
}
}

View File

@ -52,11 +52,11 @@ class SliceVisitor : public AstNVisitor {
// AstNodeAssign::user1() -> bool. True if find is complete
// AstNodeUniop::user1() -> bool. True if find is complete
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
AstUser1InUse m_inuser1;
AstUser1InUse m_inuser1;
// STATE
AstNode* m_assignp; // Assignment we are under
bool m_assignError; // True if the current assign already has an error
AstNode* m_assignp; // Assignment we are under
bool m_assignError; // True if the current assign already has an error
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -66,54 +66,59 @@ class SliceVisitor : public AstNVisitor {
AstUnpackArrayDType* arrayp = VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType);
if (!arrayp) { // V3Width should have complained, but...
if (!m_assignError) {
nodep->v3error(nodep->prettyTypeName()
<<" is not an unpacked array, but is in an unpacked array context");
nodep->v3error(
nodep->prettyTypeName()
<< " is not an unpacked array, but is in an unpacked array context");
}
m_assignError = true;
return nodep->cloneTree(false); // Likely will cause downstream errors
}
if (arrayp->rangep()->elementsConst() != elements) {
if (!m_assignError) nodep->v3error("Slices of arrays in assignments have different unpacked dimensions, "
<<elements<<" versus "
<<arrayp->rangep()->elementsConst());
if (!m_assignError) {
nodep->v3error(
"Slices of arrays in assignments have different unpacked dimensions, "
<< elements << " versus " << arrayp->rangep()->elementsConst());
}
m_assignError = true;
elements = 1; offset = 0;
elements = 1;
offset = 0;
}
AstNode* newp;
if (AstInitArray* initp = VN_CAST(nodep, InitArray)) {
UINFO(9," cloneInitArray("<<elements<<","<<offset<<") "<<nodep<<endl);
UINFO(9, " cloneInitArray(" << elements << "," << offset << ") " << nodep << endl);
int leOffset = !arrayp->rangep()->littleEndian()
? arrayp->rangep()->elementsConst()-1-offset : offset;
? arrayp->rangep()->elementsConst() - 1 - offset
: offset;
AstNode* itemp = initp->getIndexDefaultedValuep(leOffset);
if (!itemp) {
nodep->v3error("Array initialization has too few elements, need element "<<offset);
nodep->v3error("Array initialization has too few elements, need element "
<< offset);
itemp = initp->initsp();
}
newp = itemp->cloneTree(false);
}
else if (AstNodeCond* snodep = VN_CAST(nodep, NodeCond)) {
UINFO(9," cloneCond("<<elements<<","<<offset<<") "<<nodep<<endl);
} else if (AstNodeCond* snodep = VN_CAST(nodep, NodeCond)) {
UINFO(9, " cloneCond(" << elements << "," << offset << ") " << nodep << endl);
return snodep->cloneType(snodep->condp()->cloneTree(false),
cloneAndSel(snodep->expr1p(), elements, offset),
cloneAndSel(snodep->expr2p(), elements, offset));
}
else if (AstSliceSel* snodep = VN_CAST(nodep, SliceSel)) {
UINFO(9," cloneSliceSel("<<elements<<","<<offset<<") "<<nodep<<endl);
} else if (AstSliceSel* snodep = VN_CAST(nodep, SliceSel)) {
UINFO(9, " cloneSliceSel(" << elements << "," << offset << ") " << nodep << endl);
int leOffset = (snodep->declRange().lo()
+ (!snodep->declRange().littleEndian()
? snodep->declRange().elements()-1-offset : offset));
? snodep->declRange().elements() - 1 - offset
: offset));
newp = new AstArraySel(nodep->fileline(), snodep->fromp()->cloneTree(false), leOffset);
}
else if (VN_IS(nodep, ArraySel)
|| VN_IS(nodep, NodeVarRef)
|| VN_IS(nodep, NodeSel)) {
UINFO(9," cloneSel("<<elements<<","<<offset<<") "<<nodep<<endl);
} else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel)) {
UINFO(9, " cloneSel(" << elements << "," << offset << ") " << nodep << endl);
int leOffset = !arrayp->rangep()->littleEndian()
? arrayp->rangep()->elementsConst()-1-offset : offset;
? arrayp->rangep()->elementsConst() - 1 - offset
: offset;
newp = new AstArraySel(nodep->fileline(), nodep->cloneTree(false), leOffset);
}
else {
if (!m_assignError) nodep->v3error(nodep->prettyTypeName()<<" unexpected in assignment to unpacked array");
} else {
if (!m_assignError) {
nodep->v3error(nodep->prettyTypeName()
<< " unexpected in assignment to unpacked array");
}
m_assignError = true;
newp = nodep->cloneTree(false); // Likely will cause downstream errors
}
@ -122,11 +127,13 @@ class SliceVisitor : public AstNVisitor {
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
// Called recursively on newly created assignments
if (!nodep->user1()
&& !VN_IS(nodep, AssignAlias)) {
if (!nodep->user1() && !VN_IS(nodep, AssignAlias)) {
nodep->user1(true);
m_assignError = false;
if (debug()>=9) { cout<<endl; nodep->dumpTree(cout, " Deslice-In: "); }
if (debug() >= 9) {
cout << endl;
nodep->dumpTree(cout, " Deslice-In: ");
}
AstNodeDType* dtp = nodep->lhsp()->dtypep()->skipRefp();
if (AstUnpackArrayDType* arrayp = VN_CAST(dtp, UnpackArrayDType)) {
// Left and right could have different msb/lsbs/endianness, but #elements is common
@ -136,13 +143,17 @@ class SliceVisitor : public AstNVisitor {
int elements = arrayp->rangep()->elementsConst();
for (int offset = 0; offset < elements; ++offset) {
AstNode* newp = nodep->cloneType // AstNodeAssign
(cloneAndSel(nodep->lhsp(), elements, offset),
cloneAndSel(nodep->rhsp(), elements, offset));
if (debug()>=9) { newp->dumpTree(cout, "-new "); }
(cloneAndSel(nodep->lhsp(), elements, offset),
cloneAndSel(nodep->rhsp(), elements, offset));
if (debug() >= 9) { newp->dumpTree(cout, "-new "); }
newlistp = AstNode::addNextNull(newlistp, newp);
}
if (debug()>=9) { cout<<endl; nodep->dumpTree(cout, " Deslice-Dn: "); }
nodep->replaceWith(newlistp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
if (debug() >= 9) {
cout << endl;
nodep->dumpTree(cout, " Deslice-Dn: ");
}
nodep->replaceWith(newlistp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
// Normal edit iterator will now iterate on all of the expansion assignments
// This will potentially call this function again to resolve next level of slicing
return;
@ -154,8 +165,7 @@ class SliceVisitor : public AstNVisitor {
}
virtual void visit(AstInitArray* nodep) VL_OVERRIDE {
UASSERT_OBJ(!m_assignp, nodep,
"Array initialization should have been removed earlier");
UASSERT_OBJ(!m_assignp, nodep, "Array initialization should have been removed earlier");
}
void expandBiOp(AstNodeBiop* nodep) {
@ -163,30 +173,31 @@ class SliceVisitor : public AstNVisitor {
nodep->user1(true);
// If it's an unpacked array, blow it up into comparing each element
AstNodeDType* fromDtp = nodep->lhsp()->dtypep()->skipRefp();
UINFO(9, " Bi-Eq/Neq expansion "<<nodep<<endl);
UINFO(9, " Bi-Eq/Neq expansion " << nodep << endl);
if (AstUnpackArrayDType* adtypep = VN_CAST(fromDtp, UnpackArrayDType)) {
AstNodeBiop* logp = NULL;
if (!VN_IS(nodep->lhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
nodep->lhsp()->v3error("Slice operator "<<nodep->lhsp()->prettyTypeName()
<<" on non-slicable (e.g. non-vector) left-hand-side operand");
}
else if (!VN_IS(nodep->rhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
nodep->rhsp()->v3error("Slice operator "<<nodep->rhsp()->prettyTypeName()
<<" on non-slicable (e.g. non-vector) right-hand-side operand");
}
else {
nodep->lhsp()->v3error(
"Slice operator "
<< nodep->lhsp()->prettyTypeName()
<< " on non-slicable (e.g. non-vector) left-hand-side operand");
} else if (!VN_IS(nodep->rhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
nodep->rhsp()->v3error(
"Slice operator "
<< nodep->rhsp()->prettyTypeName()
<< " on non-slicable (e.g. non-vector) right-hand-side operand");
} else {
for (int index = 0; index < adtypep->rangep()->elementsConst(); ++index) {
// EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1])
AstNodeBiop* clonep
= VN_CAST(nodep->cloneType
(new AstArraySel(nodep->fileline(),
nodep->lhsp()->cloneTree(false),
index),
new AstArraySel(nodep->fileline(),
nodep->rhsp()->cloneTree(false),
index)),
= VN_CAST(nodep->cloneType(
new AstArraySel(nodep->fileline(),
nodep->lhsp()->cloneTree(false), index),
new AstArraySel(nodep->fileline(),
nodep->rhsp()->cloneTree(false), index)),
NodeBiop);
if (!logp) logp = clonep;
if (!logp)
logp = clonep;
else {
switch (nodep->type()) {
case AstType::atEq: // FALLTHRU
@ -212,18 +223,10 @@ class SliceVisitor : public AstNVisitor {
iterateChildren(nodep);
}
}
virtual void visit(AstEq* nodep) VL_OVERRIDE {
expandBiOp(nodep);
}
virtual void visit(AstNeq* nodep) VL_OVERRIDE {
expandBiOp(nodep);
}
virtual void visit(AstEqCase* nodep) VL_OVERRIDE {
expandBiOp(nodep);
}
virtual void visit(AstNeqCase* nodep) VL_OVERRIDE {
expandBiOp(nodep);
}
virtual void visit(AstEq* nodep) VL_OVERRIDE { expandBiOp(nodep); }
virtual void visit(AstNeq* nodep) VL_OVERRIDE { expandBiOp(nodep); }
virtual void visit(AstEqCase* nodep) VL_OVERRIDE { expandBiOp(nodep); }
virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { expandBiOp(nodep); }
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
@ -241,9 +244,7 @@ public:
// Link class functions
void V3Slice::sliceAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
SliceVisitor visitor(nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ SliceVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("slice", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -97,18 +97,19 @@
// Support classes
class SplitNodeVertex : public V3GraphVertex {
AstNode* m_nodep;
AstNode* m_nodep;
protected:
SplitNodeVertex(V3Graph* graphp, AstNode* nodep)
: V3GraphVertex(graphp), m_nodep(nodep) {}
: V3GraphVertex(graphp)
, m_nodep(nodep) {}
virtual ~SplitNodeVertex() {}
// ACCESSORS
// Do not make accessor for nodep(), It may change due to
// reordering a lower block, but we don't repair it
virtual string name() const {
return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName();
}
virtual string name() const { return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName(); }
virtual FileLine* fileline() const { return nodep()->fileline(); }
public:
virtual AstNode* nodep() const { return m_nodep; }
};
@ -143,7 +144,7 @@ public:
SplitVarPostVertex(V3Graph* graphp, AstNode* nodep)
: SplitNodeVertex(graphp, nodep) {}
virtual ~SplitVarPostVertex() {}
virtual string name() const { return string("POST ")+SplitNodeVertex::name(); }
virtual string name() const { return string("POST ") + SplitNodeVertex::name(); }
virtual string dotColor() const { return "CadetBlue"; }
};
@ -155,11 +156,12 @@ class SplitEdge : public V3GraphEdge {
static uint32_t s_stepNum; // Global step number
protected:
enum { WEIGHT_NORMAL = 10 };
SplitEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
int weight, bool cutable=CUTABLE)
SplitEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight,
bool cutable = CUTABLE)
: V3GraphEdge(graphp, fromp, top, weight, cutable)
, m_ignoreInStep(0) {}
virtual ~SplitEdge() {}
public:
// Iterator for graph functions
static void incrementStep() { ++s_stepNum; }
@ -181,7 +183,7 @@ public:
return ignoreThisStep() ? "dotted" : V3GraphEdge::dotStyle();
}
};
uint32_t SplitEdge::s_stepNum = 0;
uint32_t SplitEdge::s_stepNum = 0;
class SplitPostEdge : public SplitEdge {
public:
@ -240,28 +242,26 @@ private:
// AstVarScope::user2p -> Var SplitNodeVertex* for delayed assignment var, 0=not set yet
// Ast*::user3p -> Statement SplitLogicVertex* (temporary only)
// Ast*::user4 -> Current ordering number (reorderBlock usage)
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
AstUser4InUse m_inuser4;
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
AstUser4InUse m_inuser4;
protected:
// TYPES
typedef std::vector<SplitLogicVertex*> VStack;
// STATE
string m_noReorderWhy; // Reason we can't reorder
VStack m_stmtStackps; // Current statements being tracked
SplitPliVertex* m_pliVertexp; // Element specifying PLI ordering
V3Graph m_graph; // Scoreboard of var usages/dependencies
bool m_inDly; // Inside ASSIGNDLY
VDouble0 m_statSplits; // Statistic tracking
string m_noReorderWhy; // Reason we can't reorder
VStack m_stmtStackps; // Current statements being tracked
SplitPliVertex* m_pliVertexp; // Element specifying PLI ordering
V3Graph m_graph; // Scoreboard of var usages/dependencies
bool m_inDly; // Inside ASSIGNDLY
VDouble0 m_statSplits; // Statistic tracking
// CONSTRUCTORS
public:
SplitReorderBaseVisitor() {
scoreboardClear();
}
SplitReorderBaseVisitor() { scoreboardClear(); }
virtual ~SplitReorderBaseVisitor() {
V3Stats::addStat("Optimizations, Split always", m_statSplits);
}
@ -271,7 +271,7 @@ protected:
VL_DEBUG_FUNC; // Declare debug()
void scoreboardClear() {
//VV***** We reset user1p() and user2p on each block!!!
// VV***** We reset user1p() and user2p on each block!!!
m_inDly = false;
m_graph.clear();
m_stmtStackps.clear();
@ -298,14 +298,14 @@ private:
}
}
void scoreboardPushStmt(AstNode* nodep) {
//UINFO(9," push "<<nodep<<endl);
// UINFO(9, " push " << nodep << endl);
SplitLogicVertex* vertexp = new SplitLogicVertex(&m_graph, nodep);
m_stmtStackps.push_back(vertexp);
UASSERT_OBJ(!nodep->user3p(), nodep, "user3p should not be used; cleared in processBlock");
nodep->user3p(vertexp);
}
void scoreboardPopStmt() {
//UINFO(9," pop"<<endl);
// UINFO(9, " pop" << endl);
if (m_stmtStackps.empty()) v3fatalSrc("Stack underflow");
m_stmtStackps.pop_back();
}
@ -313,7 +313,7 @@ private:
protected:
void scanBlock(AstNode* nodep) {
// Iterate across current block, making the scoreboard
for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) {
scoreboardPushStmt(nextp);
iterate(nextp);
scoreboardPopStmt();
@ -321,17 +321,15 @@ protected:
}
void pruneDepsOnInputs() {
for (V3GraphVertex* vertexp = m_graph.verticesBeginp();
vertexp; vertexp=vertexp->verticesNextp()) {
if (!vertexp->outBeginp()
&& dynamic_cast<SplitVarStdVertex*>(vertexp)) {
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
if (!vertexp->outBeginp() && dynamic_cast<SplitVarStdVertex*>(vertexp)) {
if (debug() >= 9) {
SplitVarStdVertex* stdp = static_cast<SplitVarStdVertex*>(vertexp);
UINFO(0, "Will prune deps on var "<<stdp->nodep()<<endl);
UINFO(0, "Will prune deps on var " << stdp->nodep() << endl);
stdp->nodep()->dumpTree(cout, "- ");
}
for (V3GraphEdge* edgep = vertexp->inBeginp();
edgep; edgep=edgep->inNextp()) {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
oedgep->setIgnoreThisStep();
}
@ -350,7 +348,7 @@ protected:
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
m_inDly = true;
UINFO(4," ASSIGNDLY "<<nodep<<endl);
UINFO(4, " ASSIGNDLY " << nodep << endl);
iterateChildren(nodep);
m_inDly = false;
}
@ -386,7 +384,7 @@ protected:
// SPEEDUP: We add duplicate edges, that should be fixed
if (m_inDly && nodep->lvalue()) {
UINFO(4," VARREFDLY: "<<nodep<<endl);
UINFO(4, " VARREFDLY: " << nodep << endl);
// Delayed variable is different from non-delayed variable
if (!vscp->user2p()) {
SplitVarPostVertex* vpostp = new SplitVarPostVertex(&m_graph, vscp);
@ -396,21 +394,21 @@ protected:
SplitVarPostVertex* vpostp
= reinterpret_cast<SplitVarPostVertex*>(vscp->user2p());
// Add edges
for (VStack::iterator it = m_stmtStackps.begin();
it != m_stmtStackps.end(); ++it) {
for (VStack::iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end();
++it) {
new SplitLVEdge(&m_graph, vpostp, *it);
}
} else { // Nondelayed assignment
if (nodep->lvalue()) {
// Non-delay; need to maintain existing ordering
// with all consumers of the signal
UINFO(4," VARREFLV: "<<nodep<<endl);
UINFO(4, " VARREFLV: " << nodep << endl);
for (VStack::iterator it = m_stmtStackps.begin();
it != m_stmtStackps.end(); ++it) {
new SplitLVEdge(&m_graph, vstdp, *it);
}
} else {
UINFO(4," VARREF: "<<nodep<<endl);
UINFO(4, " VARREF: " << nodep << endl);
makeRvalueEdges(vstdp);
}
}
@ -423,7 +421,7 @@ protected:
// This is overly pessimistic; we could treat jumps as barriers, and
// reorder everything between jumps/labels, however jumps are rare
// in always, so the performance gain probably isn't worth the work.
UINFO(9," NoReordering "<<nodep<<endl);
UINFO(9, " NoReordering " << nodep << endl);
m_noReorderWhy = "JumpGo";
iterateChildren(nodep);
}
@ -433,7 +431,7 @@ protected:
virtual void visit(AstNode* nodep) VL_OVERRIDE {
// **** SPECIAL default type that sets PLI_ORDERING
if (!m_stmtStackps.empty() && !nodep->isPure()) {
UINFO(9," NotSplittable "<<nodep<<endl);
UINFO(9, " NotSplittable " << nodep << endl);
scoreboardPli(nodep);
}
iterateChildren(nodep);
@ -446,9 +444,7 @@ private:
class ReorderVisitor : public SplitReorderBaseVisitor {
// CONSTRUCTORS
public:
explicit ReorderVisitor(AstNetlist* nodep) {
iterate(nodep);
}
explicit ReorderVisitor(AstNetlist* nodep) { iterate(nodep); }
virtual ~ReorderVisitor() {}
// METHODS
@ -461,18 +457,18 @@ protected:
void cleanupBlockGraph(AstNode* nodep) {
// Transform the graph into what we need
UINFO(5, "ReorderBlock "<<nodep<<endl);
UINFO(5, "ReorderBlock " << nodep << endl);
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
if (debug()>=9) {
if (debug() >= 9) {
m_graph.dumpDotFilePrefixed("reorderg_nodup", false);
//m_graph.dump(); cout<<endl;
// m_graph.dump(); cout<<endl;
}
// Mark all the logic for this step
// Vertex::m_user begin: true indicates logic for this step
m_graph.userClearVertices();
for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) {
SplitLogicVertex* vvertexp = reinterpret_cast<SplitLogicVertex*>(nextp->user3p());
vvertexp->user(true);
}
@ -484,16 +480,17 @@ protected:
// For reordering this single block only, mark all logic
// vertexes not involved with this step as unimportant
for (V3GraphVertex* vertexp = m_graph.verticesBeginp();
vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
if (SplitLogicVertex* vvertexp = dynamic_cast<SplitLogicVertex*>(vertexp)) {
if (!vvertexp->user()) {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep;
edgep = edgep->inNextp()) {
SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
oedgep->setIgnoreThisStep();
}
for (V3GraphEdge* edgep = vertexp->outBeginp();
edgep; edgep=edgep->outNextp()) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep;
edgep = edgep->outNextp()) {
SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
oedgep->setIgnoreThisStep();
}
@ -507,7 +504,7 @@ protected:
// Add hard orderings between all nodes of same color, in the order they appeared
vl_unordered_map<uint32_t, SplitLogicVertex*> lastOfColor;
for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) {
SplitLogicVertex* vvertexp = reinterpret_cast<SplitLogicVertex*>(nextp->user3p());
uint32_t color = vvertexp->color();
UASSERT_OBJ(color, nextp, "No node color assigned");
@ -520,20 +517,20 @@ protected:
// And a real ordering to get the statements into something reasonable
// We don't care if there's cutable violations here...
// Non-cutable violations should be impossible; as those edges are program-order
if (debug()>=9) m_graph.dumpDotFilePrefixed(string("splitg_preo"), false);
if (debug() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_preo"), false);
m_graph.acyclic(&SplitEdge::followCyclic);
m_graph.rank(&SplitEdge::followCyclic); // Or order(), but that's more expensive
if (debug()>=9) m_graph.dumpDotFilePrefixed(string("splitg_opt"), false);
if (debug() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_opt"), false);
}
void reorderBlock(AstNode* nodep) {
// Reorder statements in the completed graph
// Map the rank numbers into nodes they associate with
typedef std::multimap<uint32_t,AstNode*> RankNodeMap;
typedef std::multimap<uint32_t, AstNode*> RankNodeMap;
RankNodeMap rankMap;
int currOrder = 0; // Existing sequence number of assignment
for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) {
SplitLogicVertex* vvertexp = reinterpret_cast<SplitLogicVertex*>(nextp->user3p());
rankMap.insert(make_pair(vvertexp->rank(), nextp));
nextp->user4(++currOrder); // Record current ordering
@ -542,23 +539,28 @@ protected:
// Is the current ordering OK?
bool leaveAlone = true;
int newOrder = 0; // New sequence number of assignment
for (RankNodeMap::const_iterator it = rankMap.begin();
it != rankMap.end(); ++it) {
for (RankNodeMap::const_iterator it = rankMap.begin(); it != rankMap.end(); ++it) {
AstNode* nextp = it->second;
if (++newOrder != nextp->user4()) leaveAlone = false;
}
if (leaveAlone) {
UINFO(6," No changes\n");
UINFO(6, " No changes\n");
} else {
AstNRelinker replaceHandle; // Where to add the list
AstNode* newListp = NULL;
for (RankNodeMap::const_iterator it = rankMap.begin(); it != rankMap.end(); ++it) {
AstNode* nextp = it->second;
UINFO(6, " New order: "<<nextp<<endl);
if (nextp == nodep) nodep->unlinkFrBack(&replaceHandle);
else nextp->unlinkFrBack();
if (newListp) newListp = newListp->addNext(nextp);
else newListp = nextp;
UINFO(6, " New order: " << nextp << endl);
if (nextp == nodep) {
nodep->unlinkFrBack(&replaceHandle);
} else {
nextp->unlinkFrBack();
}
if (newListp) {
newListp = newListp->addNext(nextp);
} else {
newListp = nextp;
}
}
replaceHandle.relink(newListp);
}
@ -579,19 +581,19 @@ protected:
// Just one, so can't reorder. Just look for more blocks/statements.
iterate(nodep);
} else {
UINFO(9," processBlock "<<nodep<<endl);
UINFO(9, " processBlock " << nodep << endl);
// Process block and followers
scanBlock(nodep);
if (m_noReorderWhy != "") { // Jump or something nasty
UINFO(9," NoReorderBlock because "<<m_noReorderWhy<<endl);
UINFO(9, " NoReorderBlock because " << m_noReorderWhy << endl);
} else {
// Reorder statements in this block
cleanupBlockGraph(nodep);
reorderBlock(nodep);
// Delete old vertexes and edges only applying to this block
// First, walk back to first in list
while (firstp->backp()->nextp()==firstp) firstp = firstp->backp();
for (AstNode* nextp=firstp; nextp; nextp=nextp->nextp()) {
while (firstp->backp()->nextp() == firstp) firstp = firstp->backp();
for (AstNode* nextp = firstp; nextp; nextp = nextp->nextp()) {
SplitLogicVertex* vvertexp
= reinterpret_cast<SplitLogicVertex*>(nextp->user3p());
vvertexp->unlinkDelete(&m_graph);
@ -603,19 +605,20 @@ protected:
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
UINFO(4," ALW "<<nodep<<endl);
if (debug()>=9) nodep->dumpTree(cout, " alwIn:: ");
UINFO(4, " ALW " << nodep << endl);
if (debug() >= 9) nodep->dumpTree(cout, " alwIn:: ");
scoreboardClear();
processBlock(nodep->bodysp());
if (debug()>=9) nodep->dumpTree(cout, " alwOut: ");
if (debug() >= 9) nodep->dumpTree(cout, " alwOut: ");
}
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
UINFO(4," IF "<<nodep<<endl);
UINFO(4, " IF " << nodep << endl);
iterateAndNextNull(nodep->condp());
processBlock(nodep->ifsp());
processBlock(nodep->elsesp());
}
private:
VL_UNCOPYABLE(ReorderVisitor);
};
@ -638,9 +641,7 @@ class IfColorVisitor : public AstNVisitor {
public:
// Visit through *nodep and map each AstNodeIf within to the set of
// colors it will participate in. Also find the whole set of colors.
explicit IfColorVisitor(AstAlways* nodep) {
iterate(nodep);
}
explicit IfColorVisitor(AstAlways* nodep) { iterate(nodep); }
virtual ~IfColorVisitor() {}
// METHODS
@ -660,8 +661,7 @@ private:
UINFO(8, " SVL " << vertexp << " has color " << color << "\n");
// Record that all containing ifs have this color.
for (IfStack::const_iterator it = m_ifStack.begin();
it != m_ifStack.end(); ++it) {
for (IfStack::const_iterator it = m_ifStack.begin(); it != m_ifStack.end(); ++it) {
m_ifColors[*it].insert(color);
}
}
@ -700,9 +700,7 @@ public:
// EmitSplitVisitor visits through always block *nodep
// and generates its split blocks, writing the split blocks
// into *newBlocksp.
EmitSplitVisitor(AstAlways* nodep,
const IfColorVisitor* ifColorp,
AlwaysVec* newBlocksp)
EmitSplitVisitor(AstAlways* nodep, const IfColorVisitor* ifColorp, AlwaysVec* newBlocksp)
: m_origAlwaysp(nodep)
, m_ifColorp(ifColorp)
, m_newBlocksp(newBlocksp) {
@ -715,13 +713,11 @@ public:
void go() {
// Create a new always for each color
const ColorSet& colors = m_ifColorp->colors();
for (ColorSet::const_iterator color = colors.begin();
color != colors.end(); ++color) {
for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) {
// We don't need to clone m_origAlwaysp->sensesp() here;
// V3Activate already moved it to a parent node.
AstAlways* alwaysp =
new AstAlways(m_origAlwaysp->fileline(), VAlwaysKwd::ALWAYS,
NULL, NULL);
AstAlways* alwaysp
= new AstAlways(m_origAlwaysp->fileline(), VAlwaysKwd::ALWAYS, NULL, NULL);
// Put a placeholder node into stmtp to track our position.
// We'll strip these out after the blocks are fully cloned.
AstSplitPlaceholder* placeholderp = makePlaceholderp();
@ -769,16 +765,12 @@ protected:
typedef vl_unordered_map<uint32_t, AstNodeIf*> CloneMap;
CloneMap clones;
for (ColorSet::const_iterator color = colors.begin();
color != colors.end(); ++color) {
for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) {
// Clone this if into its set of split blocks
AstSplitPlaceholder* if_placeholderp = makePlaceholderp();
AstSplitPlaceholder* else_placeholderp = makePlaceholderp();
AstIf* clonep =
new AstIf(nodep->fileline(),
nodep->condp()->cloneTree(true),
if_placeholderp,
else_placeholderp);
AstIf* clonep = new AstIf(nodep->fileline(), nodep->condp()->cloneTree(true),
if_placeholderp, else_placeholderp);
AstIf* origp = VN_CAST(nodep, If);
if (origp) {
// Preserve pragmas from unique if's
@ -794,15 +786,13 @@ protected:
iterateAndNextNull(nodep->ifsp());
for (ColorSet::const_iterator color = colors.begin();
color != colors.end(); ++color) {
for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) {
m_addAfter[*color] = clones[*color]->elsesp();
}
iterateAndNextNull(nodep->elsesp());
for (ColorSet::const_iterator color = colors.begin();
color != colors.end(); ++color) {
for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) {
m_addAfter[*color] = clones[*color];
}
}
@ -817,17 +807,14 @@ class RemovePlaceholdersVisitor : public AstNVisitor {
public:
explicit RemovePlaceholdersVisitor(AstNode* nodep) {
iterate(nodep);
for (NodeSet::const_iterator it = m_removeSet.begin();
it != m_removeSet.end(); ++it) {
for (NodeSet::const_iterator it = m_removeSet.begin(); it != m_removeSet.end(); ++it) {
AstNode* np = *it;
np->unlinkFrBack(); // Without next
VL_DO_DANGLING(np->deleteTree(), np);
}
}
virtual ~RemovePlaceholdersVisitor() {}
virtual void visit(AstSplitPlaceholder* nodep) VL_OVERRIDE {
m_removeSet.insert(nodep);
}
virtual void visit(AstSplitPlaceholder* nodep) VL_OVERRIDE { m_removeSet.insert(nodep); }
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
private:
@ -854,11 +841,11 @@ public:
// Splice newly-split blocks into the tree. Remove placeholders
// from newly-split blocks. Delete the original always blocks
// that we're replacing.
for (ReplaceMap::iterator it = m_replaceBlocks.begin();
it != m_replaceBlocks.end(); ++it) {
for (ReplaceMap::iterator it = m_replaceBlocks.begin(); it != m_replaceBlocks.end();
++it) {
AstAlways* origp = it->first;
for (AlwaysVec::iterator addme = it->second.begin();
addme != it->second.end(); ++addme) {
for (AlwaysVec::iterator addme = it->second.begin(); addme != it->second.end();
++addme) {
origp->addNextHere(*addme);
RemovePlaceholdersVisitor removePlaceholders(*addme);
}
@ -876,9 +863,7 @@ protected:
// not rvalues in the if/else bodies.
for (VStack::const_iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end(); ++it) {
AstNodeIf* ifNodep = VN_CAST((*it)->nodep(), NodeIf);
if (ifNodep && (m_curIfConditional != ifNodep)) {
continue;
}
if (ifNodep && (m_curIfConditional != ifNodep)) continue;
new SplitRVEdge(&m_graph, *it, vstdp);
}
}
@ -899,8 +884,8 @@ protected:
// For any 'if' node whose deps have all been pruned
// (meaning, its conditional expression only looks at primary
// inputs) prune all edges that depend on the 'if'.
for (V3GraphVertex* vertexp = m_graph.verticesBeginp();
vertexp; vertexp=vertexp->verticesNextp()) {
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
SplitLogicVertex* logicp = dynamic_cast<SplitLogicVertex*>(vertexp);
if (!logicp) continue;
@ -908,8 +893,7 @@ protected:
if (!ifNodep) continue;
bool pruneMe = true;
for (V3GraphEdge* edgep = logicp->outBeginp();
edgep; edgep = edgep->outNextp()) {
for (V3GraphEdge* edgep = logicp->outBeginp(); edgep; edgep = edgep->outNextp()) {
SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
if (!oedgep->ignoreThisStep()) {
// This if conditional depends on something we can't
@ -921,8 +905,8 @@ protected:
if (debug() >= 9) {
V3GraphVertex* vxp = oedgep->top();
SplitNodeVertex* nvxp = dynamic_cast<SplitNodeVertex*>(vxp);
UINFO(0, "Cannot prune if-node due to edge "<<oedgep<<
" pointing to node "<<nvxp->nodep()<<endl);
UINFO(0, "Cannot prune if-node due to edge "
<< oedgep << " pointing to node " << nvxp->nodep() << endl);
nvxp->nodep()->dumpTree(cout, "- ");
}
@ -933,21 +917,20 @@ protected:
if (!pruneMe) continue;
// This if can be split; prune dependencies on it.
for (V3GraphEdge* edgep = logicp->inBeginp();
edgep; edgep = edgep->inNextp()) {
for (V3GraphEdge* edgep = logicp->inBeginp(); edgep; edgep = edgep->inNextp()) {
SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
oedgep->setIgnoreThisStep();
}
}
if (debug()>=9) m_graph.dumpDotFilePrefixed("splitg_nodup", false);
if (debug() >= 9) m_graph.dumpDotFilePrefixed("splitg_nodup", false);
// Weak coloring to determine what needs to remain grouped
// in a single always. This follows all edges excluding:
// - those we pruned above
// - PostEdges, which are done later
m_graph.weaklyConnected(&SplitEdge::followScoreboard);
if (debug()>=9) m_graph.dumpDotFilePrefixed("splitg_colored", false);
if (debug() >= 9) m_graph.dumpDotFilePrefixed("splitg_colored", false);
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
@ -957,13 +940,13 @@ protected:
if (m_noReorderWhy != "") {
// We saw a jump or something else rare that we don't handle.
UINFO(9," NoSplitBlock because "<<m_noReorderWhy<<endl);
UINFO(9, " NoSplitBlock because " << m_noReorderWhy << endl);
return;
}
// Look across the entire tree of if/else blocks in the always,
// and color regions that must be kept together.
UINFO(5, "SplitVisitor @ "<<nodep<<endl);
UINFO(5, "SplitVisitor @ " << nodep << endl);
colorAlwaysGraph();
// Map each AstNodeIf to the set of colors (split always blocks)
@ -978,19 +961,19 @@ protected:
// Visit through the original always block one more time,
// and emit the split always blocks into m_replaceBlocks:
EmitSplitVisitor emitSplit(nodep, &ifColor,
&(m_replaceBlocks[nodep]));
EmitSplitVisitor emitSplit(nodep, &ifColor, &(m_replaceBlocks[nodep]));
emitSplit.go();
}
}
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
UINFO(4," IF "<<nodep<<endl);
UINFO(4, " IF " << nodep << endl);
m_curIfConditional = nodep;
iterateAndNextNull(nodep->condp());
m_curIfConditional = NULL;
scanBlock(nodep->ifsp());
scanBlock(nodep->elsesp());
}
private:
VL_UNCOPYABLE(SplitVisitor);
};
@ -999,16 +982,12 @@ private:
// Split class functions
void V3Split::splitReorderAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
ReorderVisitor visitor(nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ ReorderVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("reorder", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Split::splitAlwaysAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
SplitVisitor visitor(nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ SplitVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("split", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -52,8 +52,7 @@ private:
// METHODS
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (nodep->lvalue() && !m_splitVscp
&& nodep->varp()->attrIsolateAssign()) {
if (nodep->lvalue() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) {
m_splitVscp = nodep->varScopep();
}
}
@ -76,16 +75,16 @@ public:
class SplitAsCleanVisitor : public SplitAsBaseVisitor {
private:
// STATE
AstVarScope* m_splitVscp; // Variable we want to split
bool m_modeMatch; // Remove matching Vscp, else non-matching
bool m_keepStmt; // Current Statement must be preserved
bool m_matches; // Statement below has matching lvalue reference
AstVarScope* m_splitVscp; // Variable we want to split
bool m_modeMatch; // Remove matching Vscp, else non-matching
bool m_keepStmt; // Current Statement must be preserved
bool m_matches; // Statement below has matching lvalue reference
// METHODS
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (nodep->lvalue()) {
if (nodep->varScopep()==m_splitVscp) {
UINFO(6," CL VAR "<<nodep<<endl);
if (nodep->varScopep() == m_splitVscp) {
UINFO(6, " CL VAR " << nodep << endl);
m_matches = true;
}
}
@ -95,7 +94,7 @@ private:
iterateChildren(nodep);
return;
}
UINFO(6," CL STMT "<<nodep<<endl);
UINFO(6, " CL STMT " << nodep << endl);
bool oldKeep = m_keepStmt;
{
m_matches = false;
@ -103,18 +102,18 @@ private:
iterateChildren(nodep);
if (m_keepStmt
|| (m_modeMatch ? m_matches : !m_matches)) {
UINFO(6," Keep STMT "<<nodep<<endl);
if (m_keepStmt || (m_modeMatch ? m_matches : !m_matches)) {
UINFO(6, " Keep STMT " << nodep << endl);
m_keepStmt = true;
} else {
UINFO(6," Delete STMT "<<nodep<<endl);
nodep->unlinkFrBack(); pushDeletep(nodep);
UINFO(6, " Delete STMT " << nodep << endl);
nodep->unlinkFrBack();
pushDeletep(nodep);
}
}
// If something below matches, the upper statement remains too.
m_keepStmt = oldKeep || m_keepStmt;
UINFO(9," upKeep="<<m_keepStmt<<" STMT "<<nodep<<endl);
UINFO(9, " upKeep=" << m_keepStmt << " STMT " << nodep << endl);
}
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
@ -123,7 +122,7 @@ public:
SplitAsCleanVisitor(AstAlways* nodep, AstVarScope* vscp, bool modeMatch) {
m_splitVscp = vscp;
m_modeMatch = modeMatch;
m_keepStmt = false;
m_keepStmt = false;
m_matches = false;
iterate(nodep);
}
@ -137,7 +136,7 @@ class SplitAsVisitor : public SplitAsBaseVisitor {
private:
// NODE STATE
// AstAlways::user() -> bool. True if already processed
AstUser1InUse m_inuser1;
AstUser1InUse m_inuser1;
// STATE
VDouble0 m_statSplits; // Statistic tracking
@ -145,20 +144,20 @@ private:
// METHODS
void splitAlways(AstAlways* nodep) {
UINFO(3,"Split "<<nodep<<endl);
UINFO(3," For "<<m_splitVscp<<endl);
if (debug()>=9) nodep->dumpTree(cout, "-in : ");
UINFO(3, "Split " << nodep << endl);
UINFO(3, " For " << m_splitVscp << endl);
if (debug() >= 9) nodep->dumpTree(cout, "-in : ");
// Duplicate it and link in
AstAlways* newp = nodep->cloneTree(false);
newp->user1(true); // So we don't clone it again
nodep->addNextHere(newp);
{ // Delete stuff we don't want in old
SplitAsCleanVisitor visitor (nodep, m_splitVscp, false);
if (debug()>=9) nodep->dumpTree(cout, "-out0: ");
{ // Delete stuff we don't want in old
SplitAsCleanVisitor visitor(nodep, m_splitVscp, false);
if (debug() >= 9) nodep->dumpTree(cout, "-out0: ");
}
{ // Delete stuff we don't want in new
SplitAsCleanVisitor visitor (newp, m_splitVscp, true);
if (debug()>=9) newp->dumpTree(cout, "-out1: ");
{ // Delete stuff we don't want in new
SplitAsCleanVisitor visitor(newp, m_splitVscp, true);
if (debug() >= 9) newp->dumpTree(cout, "-out1: ");
}
}
@ -168,13 +167,12 @@ private:
AstVarScope* lastSplitVscp = NULL;
while (!nodep->user1()) {
// Find any splittable variables
SplitAsFindVisitor visitor (nodep);
SplitAsFindVisitor visitor(nodep);
m_splitVscp = visitor.splitVscp();
if (m_splitVscp && m_splitVscp == lastSplitVscp) {
// We did this last time! Something's stuck!
nodep->v3fatalSrc("Infinite loop in isolate_assignments removal for: "
<<m_splitVscp->prettyNameQ())
m_splitVscp = NULL;
<< m_splitVscp->prettyNameQ());
}
lastSplitVscp = m_splitVscp;
// Now isolate the always
@ -207,9 +205,7 @@ public:
// SplitAs class functions
void V3SplitAs::splitAsAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
SplitAsVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ SplitAsVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("splitas", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -133,7 +133,7 @@ struct SplitVarImpl {
return new AstAssign(fileline, lhsp, rhsp);
} else {
return new AstAssignW(fileline, lhsp, rhsp);
}
}
}
static const char* const notSplitMsg;
@ -523,10 +523,10 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl {
iterate(argp);
if (reason) {
for (VarSet::iterator it = m_foundTargetVar.begin(),
it_end = m_foundTargetVar.end();
it_end = m_foundTargetVar.end();
it != it_end; ++it) {
argp->v3warn(SPLITVAR, (*it)->prettyNameQ()
<< notSplitMsg << reason << ".\n");
<< notSplitMsg << reason << ".\n");
m_refs.remove(*it);
}
}
@ -574,7 +574,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl {
m_refsForPackedSplit[m_modp].add(nodep);
}
virtual void visit(AstSel* nodep) VL_OVERRIDE {
if (VN_IS(nodep->fromp(), VarRef)) m_refsForPackedSplit[m_modp].add(nodep);
if (VN_IS(nodep->fromp(), VarRef)) m_refsForPackedSplit[m_modp].add(nodep);
iterateChildren(nodep);
}
virtual void visit(AstArraySel* nodep) VL_OVERRIDE {
@ -815,8 +815,10 @@ public:
if (dim.second < 1 || !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType))
reason = "it is not an unpacked array";
if (!reason) reason = cannotSplitVarCommonReason(nodep);
if (reason) UINFO(5, "Check " << nodep->prettyNameQ()
<< " cannot split because" << reason << ".\n");
if (reason) {
UINFO(5,
"Check " << nodep->prettyNameQ() << " cannot split because" << reason << ".\n");
}
return reason;
}
};
@ -900,7 +902,7 @@ class PackedVarRef {
std::vector<PackedVarRefEntry> vect;
vect.reserve(nodes.size());
for (vl_unordered_map<AstNode*, size_t>::const_iterator it = nodes.begin(),
it_end = nodes.end();
it_end = nodes.end();
it != it_end; ++it) {
vect.push_back(refs[it->second]);
}
@ -1047,11 +1049,13 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
PackedVarRefEntry(nodep, consts[0]->toSInt() + refit->second.basicp()->lsb(),
consts[1]->toUInt()),
vrefp->lvalue());
UINFO(5, varp->prettyName() << " [" << consts[0]->toSInt() << ":+"
<< consts[1]->toSInt() << "] lsb:" << refit->second.basicp()->lsb() << "\n");
UINFO(5, varp->prettyName()
<< " [" << consts[0]->toSInt() << ":+" << consts[1]->toSInt()
<< "] lsb:" << refit->second.basicp()->lsb() << "\n");
} else {
nodep->v3warn(SPLITVAR, vrefp->prettyNameQ() << notSplitMsg
<< "its bit range cannot be determined statically.");
nodep->v3warn(SPLITVAR, vrefp->prettyNameQ()
<< notSplitMsg
<< "its bit range cannot be determined statically.");
if (!consts[0]) {
UINFO(4, "LSB " << nodep->lsbp() << " is expected to be constant, but not\n");
}
@ -1076,7 +1080,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
const int msb = std::min(ref.msb(), var.msb());
const int bitwidth = msb + 1 - lsb;
UINFO(4, var.varp()->prettyNameQ() << "[" << msb << ":" << lsb << "] used for "
<< ref.nodep()->prettyNameQ() << '\n');
<< ref.nodep()->prettyNameQ() << '\n');
// LSB of varp is always 0. "lsb - var.lsb()" means this. see also SplitNewVar
AstSel* selp = new AstSel(ref.nodep()->fileline(), refp, lsb - var.lsb(), bitwidth);
return selp;
@ -1091,9 +1095,9 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
}
const bool in = portp->isReadOnly();
for (size_t i = 0; i < vars.size(); ++i) {
AstNode* rhsp = new AstSel(portp->fileline(),
new AstVarRef(portp->fileline(), portp, !in),
vars[i].lsb(), vars[i].bitwidth());
AstNode* rhsp
= new AstSel(portp->fileline(), new AstVarRef(portp->fileline(), portp, !in),
vars[i].lsb(), vars[i].bitwidth());
AstNode* lhsp = new AstVarRef(portp->fileline(), vars[i].varp(), in);
if (!in) std::swap(lhsp, rhsp);
AstNodeAssign* assignp = newAssign(portp->fileline(), lhsp, rhsp, portp);
@ -1117,8 +1121,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
= (left == right)
? varp->name() + "__BRA__" + AstNode::encodeNumber(left) + "__KET__"
: varp->name() + "__BRA__" + AstNode::encodeNumber(left)
+ AstNode::encodeName(":") + AstNode::encodeNumber(right)
+ "__KET__";
+ AstNode::encodeName(":") + AstNode::encodeNumber(right) + "__KET__";
AstBasicDType* dtypep;
switch (basicp->keyword()) {
@ -1226,9 +1229,8 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
new AstVarRef(varp->fileline(), vars[i].varp(), false),
rhsp);
}
varp->addNextHere(newAssign(varp->fileline(),
new AstVarRef(varp->fileline(), varp, true),
rhsp, varp));
varp->addNextHere(newAssign(
varp->fileline(), new AstVarRef(varp->fileline(), varp, true), rhsp, varp));
} else { // the original variable is not used anymore.
VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp);
}
@ -1274,8 +1276,9 @@ public:
} else {
reason = "its type is unknown";
}
if (reason) UINFO(5, "Check " << nodep->prettyNameQ()
<< " cannot split because" << reason << endl);
if (reason)
UINFO(5,
"Check " << nodep->prettyNameQ() << " cannot split because" << reason << endl);
return reason;
}
VL_DEBUG_FUNC; // Declare debug()

View File

@ -49,10 +49,10 @@ public:
class SubstVarWord {
protected:
// MEMBERS
AstNodeAssign* m_assignp; // Last assignment to each word of this var
int m_step; // Step number of last assignment
bool m_use; // True if each word was consumed
bool m_complex; // True if each word is complex
AstNodeAssign* m_assignp; // Last assignment to each word of this var
int m_step; // Step number of last assignment
bool m_use; // True if each word was consumed
bool m_complex; // True if each word is complex
friend class SubstVarEntry;
// METHODS
void clear() {
@ -68,10 +68,10 @@ protected:
class SubstVarEntry {
// MEMBERS
AstVar* m_varp; // Variable this tracks
bool m_wordAssign; // True if any word assignments
bool m_wordUse; // True if any individual word usage
SubstVarWord m_whole; // Data for whole vector used at once
AstVar* m_varp; // Variable this tracks
bool m_wordAssign; // True if any word assignments
bool m_wordUse; // True if any individual word usage
SubstVarWord m_whole; // Data for whole vector used at once
std::vector<SubstVarWord> m_words; // Data for every word, if multi word variable
int debug() { return SubstBaseVisitor::debug(); }
@ -83,20 +83,21 @@ public:
m_wordUse = false;
m_words.resize(varp->widthWords());
m_whole.clear();
for (int i=0; i<varp->widthWords(); i++) {
m_words[i].clear();
}
for (int i = 0; i < varp->widthWords(); i++) m_words[i].clear();
}
~SubstVarEntry() {}
private:
// METHODS
bool wordNumOk(int word) const {
return word < m_varp->widthWords();
}
bool wordNumOk(int word) const { return word < m_varp->widthWords(); }
AstNodeAssign* getWordAssignp(int word) const {
if (!wordNumOk(word)) return NULL;
else return m_words[word].m_assignp;
if (!wordNumOk(word)) {
return NULL;
} else {
return m_words[word].m_assignp;
}
}
public:
void assignWhole(int step, AstNodeAssign* assp) {
if (m_whole.m_assignp) m_whole.m_complex = true;
@ -104,8 +105,9 @@ public:
m_whole.m_step = step;
}
void assignWord(int step, int word, AstNodeAssign* assp) {
if (!wordNumOk(word) || getWordAssignp(word)
|| m_words[word].m_complex) m_whole.m_complex = true;
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) {
m_whole.m_complex = true;
}
m_wordAssign = true;
if (wordNumOk(word)) {
m_words[word].m_assignp = assp;
@ -113,13 +115,12 @@ public:
}
}
void assignWordComplex(int word) {
if (!wordNumOk(word) || getWordAssignp(word)
|| m_words[word].m_complex) m_whole.m_complex = true;
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) {
m_whole.m_complex = true;
}
m_words[word].m_complex = true;
}
void assignComplex() {
m_whole.m_complex = true;
}
void assignComplex() { m_whole.m_complex = true; }
void consumeWhole() { //==consumeComplex as we don't know the difference
m_whole.m_use = true;
}
@ -129,8 +130,7 @@ public:
}
// ACCESSORS
AstNode* substWhole(AstNode* errp) {
if (!m_varp->isWide()
&& !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) {
if (!m_varp->isWide() && !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) {
AstNodeAssign* assp = m_whole.m_assignp;
UASSERT_OBJ(assp, errp, "Reading whole that was never assigned");
return (assp->rhsp());
@ -138,7 +138,8 @@ public:
return NULL;
}
}
AstNode* substWord(AstNode* errp, int word) { // Return what to substitute given word number for
// Return what to substitute given word number for
AstNode* substWord(AstNode* errp, int word) {
if (!m_whole.m_complex && !m_whole.m_assignp && !m_words[word].m_complex) {
AstNodeAssign* assp = getWordAssignp(word);
UASSERT_OBJ(assp, errp, "Reading a word that was never assigned, or bad word #");
@ -147,14 +148,16 @@ public:
return NULL;
}
}
int getWholeStep() const {
return m_whole.m_step;
}
int getWholeStep() const { return m_whole.m_step; }
int getWordStep(int word) const {
if (!wordNumOk(word)) return 0; else return m_words[word].m_step;
if (!wordNumOk(word)) {
return 0;
} else {
return m_words[word].m_step;
}
}
void deleteAssign(AstNodeAssign* nodep) {
UINFO(5, "Delete "<<nodep<<endl);
UINFO(5, "Delete " << nodep << endl);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
void deleteUnusedAssign() {
@ -162,9 +165,9 @@ public:
if (!m_whole.m_use && !m_wordUse && m_whole.m_assignp) {
VL_DO_CLEAR(deleteAssign(m_whole.m_assignp), m_whole.m_assignp = NULL);
}
for (unsigned i=0; i<m_words.size(); i++) {
if (!m_whole.m_use && !m_words[i].m_use
&& m_words[i].m_assignp && !m_words[i].m_complex) {
for (unsigned i = 0; i < m_words.size(); i++) {
if (!m_whole.m_use && !m_words[i].m_use && m_words[i].m_assignp
&& !m_words[i].m_complex) {
VL_DO_CLEAR(deleteAssign(m_words[i].m_assignp), m_words[i].m_assignp = NULL);
}
}
@ -181,8 +184,8 @@ private:
// See SubstVisitor
//
// STATE
int m_origStep; // Step number where subst was recorded
bool m_ok; // No misassignments found
int m_origStep; // Step number where subst was recorded
bool m_ok; // No misassignments found
// METHODS
SubstVarEntry* findEntryp(AstVarRef* nodep) {
@ -197,7 +200,9 @@ private:
} else {
// A simple variable; needs checking.
if (m_origStep < nodep->varp()->user2()) {
if (m_ok) UINFO(9," RHS variable changed since subst recorded: "<<nodep<<endl);
if (m_ok) {
UINFO(9, " RHS variable changed since subst recorded: " << nodep << endl);
}
m_ok = false;
}
}
@ -208,7 +213,7 @@ private:
public:
// CONSTRUCTORS
SubstUseVisitor(AstNode* nodep, int origStep) {
UINFO(9, " SubstUseVisitor "<<origStep<<" "<<nodep<<endl);
UINFO(9, " SubstUseVisitor " << origStep << " " << nodep << endl);
m_ok = true;
m_origStep = origStep;
iterate(nodep);
@ -227,17 +232,19 @@ private:
// Passed to SubstUseVisitor
// AstVar::user1p -> SubstVar* for usage var, 0=not set yet
// AstVar::user2 -> int step number for last assignment, 0=not set yet
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
// STATE
std::vector<SubstVarEntry*> m_entryps; // Nodes to delete when we are finished
int m_ops; // Number of operators on assign rhs
int m_assignStep; // Assignment number to determine var lifetime
VDouble0 m_statSubsts; // Statistic tracking
std::vector<SubstVarEntry*> m_entryps; // Nodes to delete when we are finished
int m_ops; // Number of operators on assign rhs
int m_assignStep; // Assignment number to determine var lifetime
VDouble0 m_statSubsts; // Statistic tracking
enum { SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in
SUBST_MAX_OPS_NA = 9999 }; // Not allowed to substitute
enum {
SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in
SUBST_MAX_OPS_NA = 9999
}; // Not allowed to substitute
// METHODS
SubstVarEntry* getEntryp(AstVarRef* nodep) {
@ -251,57 +258,51 @@ private:
return entryp;
}
}
inline bool isSubstVar(AstVar* nodep) {
return nodep->isStatementTemp() && !nodep->noSubst();
}
inline bool isSubstVar(AstVar* nodep) { return nodep->isStatementTemp() && !nodep->noSubst(); }
// VISITORS
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
m_ops = 0;
m_assignStep++;
iterateAndNextNull(nodep->rhsp());
bool hit=false;
bool hit = false;
if (AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef)) {
if (isSubstVar(varrefp->varp())) {
SubstVarEntry* entryp = getEntryp(varrefp);
hit = true;
if (m_ops > SUBST_MAX_OPS_SUBST) {
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
UINFO(8, " ASSIGNtooDeep " << varrefp << endl);
entryp->assignComplex();
} else {
UINFO(8," ASSIGNwhole "<<varrefp<<endl);
UINFO(8, " ASSIGNwhole " << varrefp << endl);
entryp->assignWhole(m_assignStep, nodep);
}
}
}
else if (AstWordSel* wordp = VN_CAST(nodep->lhsp(), WordSel)) {
} else if (AstWordSel* wordp = VN_CAST(nodep->lhsp(), WordSel)) {
if (AstVarRef* varrefp = VN_CAST(wordp->lhsp(), VarRef)) {
if (VN_IS(wordp->rhsp(), Const)
&& isSubstVar(varrefp->varp())) {
if (VN_IS(wordp->rhsp(), Const) && isSubstVar(varrefp->varp())) {
int word = VN_CAST(wordp->rhsp(), Const)->toUInt();
SubstVarEntry* entryp = getEntryp(varrefp);
hit = true;
if (m_ops > SUBST_MAX_OPS_SUBST) {
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
UINFO(8, " ASSIGNtooDeep " << varrefp << endl);
entryp->assignWordComplex(word);
} else {
UINFO(8," ASSIGNword"<<word<<" "<<varrefp<<endl);
UINFO(8, " ASSIGNword" << word << " " << varrefp << endl);
entryp->assignWord(m_assignStep, word, nodep);
}
}
}
}
if (!hit) {
iterate(nodep->lhsp());
}
if (!hit) iterate(nodep->lhsp());
}
void replaceSubstEtc(AstNode* nodep, AstNode* substp) {
if (debug()>5) nodep->dumpTree(cout, " substw_old: ");
if (debug() > 5) nodep->dumpTree(cout, " substw_old: ");
AstNode* newp = substp->cloneTree(true);
if (!nodep->isQuad() && newp->isQuad()) {
newp = new AstCCast(newp->fileline(), newp, nodep);
}
if (debug()>5) newp->dumpTree(cout, " w_new: ");
if (debug() > 5) newp->dumpTree(cout, " w_new: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
++m_statSubsts;
@ -310,17 +311,15 @@ private:
iterate(nodep->rhsp());
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
AstConst* constp = VN_CAST(nodep->rhsp(), Const);
if (varrefp && isSubstVar(varrefp->varp())
&& !varrefp->lvalue()
&& constp) {
if (varrefp && isSubstVar(varrefp->varp()) && !varrefp->lvalue() && constp) {
// Nicely formed lvalues handled in NodeAssign
// Other lvalues handled as unknown mess in AstVarRef
int word = constp->toUInt();
UINFO(8," USEword"<<word<<" "<<varrefp<<endl);
UINFO(8, " USEword" << word << " " << varrefp << endl);
SubstVarEntry* entryp = getEntryp(varrefp);
if (AstNode* substp = entryp->substWord(nodep, word)) {
// Check that the RHS hasn't changed value since we recorded it.
SubstUseVisitor visitor (substp, entryp->getWordStep(word));
SubstUseVisitor visitor(substp, entryp->getWordStep(word));
if (visitor.ok()) {
VL_DO_DANGLING(replaceSubstEtc(nodep, substp), nodep);
} else {
@ -338,25 +337,25 @@ private:
if (nodep->lvalue()) {
m_assignStep++;
nodep->varp()->user2(m_assignStep);
UINFO(9, " ASSIGNstep u2="<<nodep->varp()->user2()<<" "<<nodep<<endl);
UINFO(9, " ASSIGNstep u2=" << nodep->varp()->user2() << " " << nodep << endl);
}
if (isSubstVar(nodep->varp())) {
SubstVarEntry* entryp = getEntryp(nodep);
if (nodep->lvalue()) {
UINFO(8," ASSIGNcpx "<<nodep<<endl);
UINFO(8, " ASSIGNcpx " << nodep << endl);
entryp->assignComplex();
} else if (AstNode* substp = entryp->substWhole(nodep)) {
// Check that the RHS hasn't changed value since we recorded it.
SubstUseVisitor visitor (substp, entryp->getWholeStep());
SubstUseVisitor visitor(substp, entryp->getWholeStep());
if (visitor.ok()) {
UINFO(8," USEwhole "<<nodep<<endl);
UINFO(8, " USEwhole " << nodep << endl);
VL_DO_DANGLING(replaceSubstEtc(nodep, substp), nodep);
} else {
UINFO(8," USEwholeButChg "<<nodep<<endl);
UINFO(8, " USEwholeButChg " << nodep << endl);
entryp->consumeWhole();
}
} else { // Consumed w/o substitute
UINFO(8," USEwtf "<<nodep<<endl);
UINFO(8, " USEwtf " << nodep << endl);
entryp->consumeWhole();
}
}
@ -365,11 +364,10 @@ private:
virtual void visit(AstConst*) VL_OVERRIDE {}
virtual void visit(AstNode* nodep) VL_OVERRIDE {
m_ops++;
if (!nodep->isSubstOptimizable()) {
m_ops = SUBST_MAX_OPS_NA;
}
if (!nodep->isSubstOptimizable()) m_ops = SUBST_MAX_OPS_NA;
iterateChildren(nodep);
}
public:
// CONSTRUCTORS
explicit SubstVisitor(AstNode* nodep) {
@ -381,8 +379,8 @@ public:
}
virtual ~SubstVisitor() {
V3Stats::addStat("Optimizations, Substituted temps", m_statSubsts);
for (std::vector<SubstVarEntry*>::iterator it = m_entryps.begin();
it != m_entryps.end(); ++it) {
for (std::vector<SubstVarEntry*>::iterator it = m_entryps.begin(); it != m_entryps.end();
++it) {
(*it)->deleteUnusedAssign();
delete (*it);
}
@ -393,9 +391,7 @@ public:
// Subst class functions
void V3Subst::substituteAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
SubstVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ SubstVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("subst", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -47,32 +47,33 @@
// Support classes
namespace V3TSP {
static unsigned edgeIdNext = 0;
static unsigned edgeIdNext = 0;
static void selfTestStates();
static void selfTestString();
static void selfTestStates();
static void selfTestString();
VL_DEBUG_FUNC; // Declare debug()
VL_DEBUG_FUNC; // Declare debug()
} // namespace V3TSP
// Vertex that tracks a per-vertex key
template <typename T_Key>
class TspVertexTmpl : public V3GraphVertex {
template <typename T_Key> class TspVertexTmpl : public V3GraphVertex {
private:
T_Key m_key;
public:
TspVertexTmpl(V3Graph* graphp, const T_Key& k)
: V3GraphVertex(graphp), m_key(k) {}
: V3GraphVertex(graphp)
, m_key(k) {}
virtual ~TspVertexTmpl() {}
const T_Key& key() const { return m_key; }
private:
VL_UNCOPYABLE(TspVertexTmpl);
};
// TspGraphTmpl represents a complete graph, templatized to work with
// different T_Key types.
template <typename T_Key>
class TspGraphTmpl : public V3Graph {
template <typename T_Key> class TspGraphTmpl : public V3Graph {
public:
// TYPES
typedef TspVertexTmpl<T_Key> Vertex;
@ -82,14 +83,15 @@ public:
VMap m_vertices; // T_Key to Vertex lookup map
// CONSTRUCTORS
TspGraphTmpl() : V3Graph() {}
TspGraphTmpl()
: V3Graph() {}
virtual ~TspGraphTmpl() {}
// METHODS
void addVertex(const T_Key &key) {
void addVertex(const T_Key& key) {
typename VMap::iterator itr = m_vertices.find(key);
UASSERT(itr == m_vertices.end(), "Vertex already exists with same key");
Vertex *v = new Vertex(this, key);
Vertex* v = new Vertex(this, key);
m_vertices[key] = v;
}
@ -118,9 +120,7 @@ public:
std::list<Vertex*> keysToVertexList(const std::vector<T_Key>& odds) {
std::list<Vertex*> vertices;
for(unsigned i = 0; i < odds.size(); ++i) {
vertices.push_back(findVertex(odds.at(i)));
}
for (unsigned i = 0; i < odds.size(); ++i) { vertices.push_back(findVertex(odds.at(i))); }
return vertices;
}
@ -132,7 +132,7 @@ public:
// CONSTRUCTORS
EdgeCmp() {}
// METHODS
bool operator() (const V3GraphEdge* ap, const V3GraphEdge* bp) {
bool operator()(const V3GraphEdge* ap, const V3GraphEdge* bp) {
int aCost = ap->weight();
int bCost = bp->weight();
// Sort first on cost, lowest cost edges first:
@ -141,13 +141,12 @@ public:
// Costs are equal. Compare edgeId's which should be unique.
return ap->user() < bp->user();
}
private:
VL_UNCOPYABLE(EdgeCmp);
};
static Vertex* castVertexp(V3GraphVertex* vxp) {
return dynamic_cast<Vertex*>(vxp);
}
static Vertex* castVertexp(V3GraphVertex* vxp) { return dynamic_cast<Vertex*>(vxp); }
// From *this, populate *mstp with the minimum spanning tree.
// *mstp must be initially empty.
@ -164,8 +163,7 @@ public:
PendingEdgeSet pendingEdges(cmp);
vluint32_t vertCount = 0;
for (V3GraphVertex* vxp = verticesBeginp();
vxp; vxp = vxp->verticesNextp()) {
for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
mstp->addVertex(castVertexp(vxp)->key());
vertCount++;
}
@ -174,8 +172,7 @@ public:
// all incident edges from this vertex go into a pending edge set.
Vertex* start_vertexp = castVertexp(verticesBeginp());
visited_set.insert(start_vertexp);
for (V3GraphEdge* edgep = start_vertexp->outBeginp();
edgep; edgep = edgep->outNextp()) {
for (V3GraphEdge* edgep = start_vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
pendingEdges.insert(edgep);
}
@ -198,9 +195,8 @@ public:
Vertex* neighborp = castVertexp(bestEdgep->top());
if (visited_set.find(neighborp) == visited_set.end()) {
int bestCost = bestEdgep->weight();
UINFO(6, "bestCost = "<<bestCost
<<" from "<<from_vertexp->key()
<<" to "<<neighborp->key()<<endl);
UINFO(6, "bestCost = " << bestCost << " from " << from_vertexp->key() << " to "
<< neighborp->key() << endl);
// Create the edge in our output MST graph
mstp->addEdge(from_vertexp->key(), neighborp->key(), bestCost);
@ -210,13 +206,13 @@ public:
visited_set.insert(neighborp);
// Update the pending edges with new edges
for (V3GraphEdge* edgep = neighborp->outBeginp();
edgep; edgep = edgep->outNextp()) {
for (V3GraphEdge* edgep = neighborp->outBeginp(); edgep;
edgep = edgep->outNextp()) {
pendingEdges.insert(edgep);
}
} else {
UINFO(6, "Discarding edge to already-visited neighbor "
<<neighborp->key()<<endl);
UINFO(6,
"Discarding edge to already-visited neighbor " << neighborp->key() << endl);
}
}
@ -226,8 +222,7 @@ public:
// Populate *outp with a minimal perfect matching of *this.
// *outp must be initially empty.
void perfectMatching(const std::vector<T_Key>& oddKeys,
TspGraphTmpl* outp) {
void perfectMatching(const std::vector<T_Key>& oddKeys, TspGraphTmpl* outp) {
UASSERT(outp->empty(), "Output graph must start empty");
std::list<Vertex*> odds = keysToVertexList(oddKeys);
@ -261,8 +256,7 @@ public:
PendingEdgeSet pendingEdges(cmp);
for (VertexListIt it = odds.begin(); it != odds.end(); ++it) {
for (V3GraphEdge* edgep = (*it)->outBeginp();
edgep; edgep = edgep->outNextp()) {
for (V3GraphEdge* edgep = (*it)->outBeginp(); edgep; edgep = edgep->outNextp()) {
pendingEdges.insert(edgep);
}
}
@ -270,8 +264,8 @@ public:
// Iterate over all edges, in order from low to high cost.
// For any edge whose ends are both odd-order vertices which
// haven't been matched yet, match them.
for (typename PendingEdgeSet::iterator it = pendingEdges.begin();
it != pendingEdges.end(); ++it) {
for (typename PendingEdgeSet::iterator it = pendingEdges.begin(); it != pendingEdges.end();
++it) {
Vertex* fromp = castVertexp((*it)->fromp());
Vertex* top = castVertexp((*it)->top());
if ((unmatchedOdds.find(fromp) != unmatchedOdds.end())
@ -298,49 +292,43 @@ public:
}
}
void findEulerTourRecurse(vl_unordered_set<unsigned>* markedEdgesp,
Vertex* startp,
void findEulerTourRecurse(vl_unordered_set<unsigned>* markedEdgesp, Vertex* startp,
std::vector<T_Key>* sortedOutp) {
Vertex* cur_vertexp = startp;
// Go on a random tour. Fun!
std::vector<Vertex*> tour;
do {
UINFO(6, "Adding "<<cur_vertexp->key()<<" to tour.\n");
UINFO(6, "Adding " << cur_vertexp->key() << " to tour.\n");
tour.push_back(cur_vertexp);
// Look for an arbitrary edge we've not yet marked
for (V3GraphEdge* edgep = cur_vertexp->outBeginp();
edgep; edgep = edgep->outNextp()) {
for (V3GraphEdge* edgep = cur_vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
vluint32_t edgeId = edgep->user();
if (markedEdgesp->end() == markedEdgesp->find(edgeId)) {
// This edge is not yet marked, so follow it.
markedEdgesp->insert(edgeId);
Vertex* neighborp = castVertexp(edgep->top());
UINFO(6, "following edge "<<edgeId
<<" from "<<cur_vertexp->key()
<<" to "<<neighborp->key()<<endl);
UINFO(6, "following edge " << edgeId << " from " << cur_vertexp->key()
<< " to " << neighborp->key() << endl);
cur_vertexp = neighborp;
goto found;
}
}
v3fatalSrc("No unmarked edges found in tour");
found:
;
found:;
} while (cur_vertexp != startp);
UINFO(6, "stopped, got back to start of tour @ "<<cur_vertexp->key()<<endl);
UINFO(6, "stopped, got back to start of tour @ " << cur_vertexp->key() << endl);
// Look for nodes on the tour that still have
// un-marked edges. If we find one, recurse.
for (typename std::vector<Vertex*>::iterator it = tour.begin();
it != tour.end(); ++it) {
for (typename std::vector<Vertex*>::iterator it = tour.begin(); it != tour.end(); ++it) {
Vertex* vxp = *it;
bool recursed;
do {
recursed = false;
// Look for an arbitrary edge at vxp we've not yet marked
for (V3GraphEdge* edgep = vxp->outBeginp();
edgep; edgep = edgep->outNextp()) {
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
vluint32_t edgeId = edgep->user();
if (markedEdgesp->end() == markedEdgesp->find(edgeId)) {
UINFO(6, "Recursing.\n");
@ -349,38 +337,36 @@ public:
goto recursed;
}
}
recursed:
;
recursed:;
} while (recursed);
sortedOutp->push_back(vxp->key());
}
UINFO(6, "Tour was: ");
for (typename std::vector<Vertex*>::iterator it = tour.begin();
it != tour.end(); ++it) {
for (typename std::vector<Vertex*>::iterator it = tour.begin(); it != tour.end(); ++it) {
Vertex* vxp = *it;
UINFONL(6, " "<<vxp->key());
UINFONL(6, " " << vxp->key());
}
UINFONL(6, "\n");
}
void dumpGraph(std::ostream& os, const string& nameComment) const {
// UINFO(0) as controlled by caller
os<<"At "<<nameComment<<", dumping graph. Keys:\n";
os << "At " << nameComment << ", dumping graph. Keys:\n";
for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
Vertex* tspvp = castVertexp(vxp);
os<<" "<<tspvp->key()<<endl;
os << " " << tspvp->key() << endl;
for (V3GraphEdge* edgep = tspvp->outBeginp(); edgep; edgep = edgep->outNextp()) {
Vertex* neighborp = castVertexp(edgep->top());
os<<" has edge "<<edgep->user()<<" to "<<neighborp->key()<<endl;
os << " has edge " << edgep->user() << " to " << neighborp->key() << endl;
}
}
}
void dumpGraphFilePrefixed(const string& nameComment) const {
if (v3Global.opt.dumpTree()) {
string filename = v3Global.debugFilename(nameComment)+".txt";
string filename = v3Global.debugFilename(nameComment) + ".txt";
const vl_unique_ptr<std::ofstream> logp(V3File::new_ofstream(filename));
if (logp->fail()) v3fatal("Can't write "<<filename);
if (logp->fail()) v3fatal("Can't write " << filename);
dumpGraph(*logp, nameComment);
}
}
@ -402,9 +388,7 @@ public:
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
degree++;
}
if (degree & 1) {
result.push_back(tspvp->key());
}
if (degree & 1) { result.push_back(tspvp->key()); }
}
return result;
}
@ -427,9 +411,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
// Make this TSP implementation work for graphs of size 0 or 1
// which, unfortunately, is a special case as the following
// code assumes >= 2 nodes.
if (states.empty()) {
return;
}
if (states.empty()) { return; }
if (states.size() == 1) {
resultp->push_back(*(states.begin()));
return;
@ -470,8 +452,8 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
// Discard duplicate nodes that the Euler tour might contain.
{
vl_unordered_set<const TspStateBase*> seen;
for (V3TSP::StateVec::iterator it = prelim_result.begin();
it != prelim_result.end(); ++it) {
for (V3TSP::StateVec::iterator it = prelim_result.begin(); it != prelim_result.end();
++it) {
const TspStateBase* elemp = *it;
if (seen.find(elemp) == seen.end()) {
seen.insert(elemp);
@ -492,7 +474,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
for (unsigned i = 0; i < resultp->size(); ++i) {
const TspStateBase* ap = (*resultp)[i];
const TspStateBase* bp
= (i+1 == resultp->size()) ? (*resultp)[0] : (*resultp)[i+1];
= (i + 1 == resultp->size()) ? (*resultp)[0] : (*resultp)[i + 1];
unsigned cost = ap->cost(bp);
if (cost > max_cost) {
max_cost = cost;
@ -508,12 +490,10 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
V3TSP::StateVec new_result;
unsigned i = max_cost_idx + 1;
UASSERT(i < resultp->size(), "Algorithm size error");
while(i != max_cost_idx) {
while (i != max_cost_idx) {
new_result.push_back((*resultp)[i]);
i++;
if (i >= resultp->size()) {
i = 0;
}
if (i >= resultp->size()) { i = 0; }
}
new_result.push_back((*resultp)[i]);
@ -527,17 +507,17 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
class TspTestState : public V3TSP::TspStateBase {
public:
TspTestState(unsigned xpos, unsigned ypos) :
m_xpos(xpos),
m_ypos(ypos),
m_serial(++m_serialNext) {}
TspTestState(unsigned xpos, unsigned ypos)
: m_xpos(xpos)
, m_ypos(ypos)
, m_serial(++m_serialNext) {}
~TspTestState() {}
virtual int cost(const TspStateBase* otherp) const {
return cost(dynamic_cast<const TspTestState*>(otherp));
}
static unsigned diff(unsigned a, unsigned b) {
if (a>b) return a-b;
return b-a;
if (a > b) return a - b;
return b - a;
}
virtual int cost(const TspTestState* otherp) const {
// For test purposes, each TspTestState is merely a point
@ -546,21 +526,16 @@ public:
unsigned xabs, yabs;
xabs = diff(otherp->m_xpos, m_xpos);
yabs = diff(otherp->m_ypos, m_ypos);
return lround(sqrt(xabs*xabs + yabs*yabs));
}
unsigned xpos() const {
return m_xpos;
}
unsigned ypos() const {
return m_ypos;
return lround(sqrt(xabs * xabs + yabs * yabs));
}
unsigned xpos() const { return m_xpos; }
unsigned ypos() const { return m_ypos; }
bool operator< (const TspStateBase& other) const {
return operator< (dynamic_cast<const TspTestState&>(other));
}
bool operator< (const TspTestState& other) const {
return m_serial < other.m_serial;
bool operator<(const TspStateBase& other) const {
return operator<(dynamic_cast<const TspTestState&>(other));
}
bool operator<(const TspTestState& other) const { return m_serial < other.m_serial; }
private:
unsigned m_xpos;
unsigned m_ypos;
@ -574,11 +549,11 @@ void V3TSP::selfTestStates() {
// Linear test -- coords all along the x-axis
{
V3TSP::StateVec states;
TspTestState s10(10,0);
TspTestState s60(60,0);
TspTestState s20(20,0);
TspTestState s100(100,0);
TspTestState s5(5,0);
TspTestState s10(10, 0);
TspTestState s60(60, 0);
TspTestState s20(20, 0);
TspTestState s100(100, 0);
TspTestState s5(5, 0);
states.push_back(&s10);
states.push_back(&s60);
states.push_back(&s20);
@ -595,12 +570,11 @@ void V3TSP::selfTestStates() {
expect.push_back(&s10);
expect.push_back(&s5);
if (VL_UNCOVERABLE(expect != result)) {
for (V3TSP::StateVec::iterator it = result.begin();
it != result.end(); ++it) {
for (V3TSP::StateVec::iterator it = result.begin(); it != result.end(); ++it) {
const TspTestState* statep = dynamic_cast<const TspTestState*>(*it);
cout<<statep->xpos()<<" ";
cout << statep->xpos() << " ";
}
cout<<endl;
cout << endl;
v3fatalSrc("TSP linear self-test fail. Result (above) did not match expectation.");
}
}
@ -609,13 +583,13 @@ void V3TSP::selfTestStates() {
// Test that tspSort() will rotate the list for minimum cost.
{
V3TSP::StateVec states;
TspTestState a(0,0);
TspTestState b(100,0);
TspTestState c(200,0);
TspTestState d(200,100);
TspTestState e(150,150);
TspTestState f(0,150);
TspTestState g(0,100);
TspTestState a(0, 0);
TspTestState b(100, 0);
TspTestState c(200, 0);
TspTestState d(200, 100);
TspTestState e(150, 150);
TspTestState f(0, 150);
TspTestState g(0, 100);
states.push_back(&a);
states.push_back(&b);
@ -638,13 +612,13 @@ void V3TSP::selfTestStates() {
expect.push_back(&e);
if (VL_UNCOVERABLE(expect != result)) {
for (V3TSP::StateVec::iterator it = result.begin();
it != result.end(); ++it) {
for (V3TSP::StateVec::iterator it = result.begin(); it != result.end(); ++it) {
const TspTestState* statep = dynamic_cast<const TspTestState*>(*it);
cout<<statep->xpos()<<","<<statep->ypos()<<" ";
cout << statep->xpos() << "," << statep->ypos() << " ";
}
cout<<endl;
v3fatalSrc("TSP 2d cycle=false self-test fail. Result (above) did not match expectation.");
cout << endl;
v3fatalSrc(
"TSP 2d cycle=false self-test fail. Result (above) did not match expectation.");
}
}
}
@ -687,9 +661,9 @@ void V3TSP::selfTestString() {
if (VL_UNCOVERABLE(expect != result)) {
for (std::vector<string>::const_iterator it = result.begin(); it != result.end(); ++it) {
cout<<*it<<" ";
cout << *it << " ";
}
cout<<endl;
cout << endl;
v3fatalSrc("TSP string self-test fail. Result (above) did not match expectation.");
}
}

View File

@ -38,8 +38,10 @@
// Table class functions
// CONFIG
static const double TABLE_MAX_BYTES = 1*1024*1024; // 1MB is max table size (better be lots of instructs to be worth it!)
static const double TABLE_TOTAL_BYTES = 64*1024*1024; // 64MB is close to max memory of some systems (256MB or so), so don't get out of control
// 1MB is max table size (better be lots of instructs to be worth it!)
static const double TABLE_MAX_BYTES = 1 * 1024 * 1024;
// 64MB is close to max memory of some systems (256MB or so), so don't get out of control
static const double TABLE_TOTAL_BYTES = 64 * 1024 * 1024;
static const double TABLE_SPACE_TIME_MULT = 8; // Worth 8 bytes of data to replace a instruction
static const int TABLE_MIN_NODE_COUNT = 32; // If < 32 instructions, not worth the effort
@ -52,12 +54,11 @@ class TableSimulateVisitor : public SimulateVisitor {
TableVisitor* m_cbthis; ///< Class for callback
public:
virtual void varRefCb(AstVarRef* nodep); ///< Call other-this function on all new var references
///< Call other-this function on all new var references
virtual void varRefCb(AstVarRef* nodep);
// CONSTRUCTORS
explicit TableSimulateVisitor(TableVisitor* cbthis) {
m_cbthis = cbthis;
}
explicit TableSimulateVisitor(TableVisitor* cbthis) { m_cbthis = cbthis; }
virtual ~TableSimulateVisitor() {}
};
@ -70,28 +71,28 @@ private:
// Cleared on each always/assignw
// STATE
double m_totalBytes; // Total bytes in tables created
VDouble0 m_statTablesCre; // Statistic tracking
double m_totalBytes; // Total bytes in tables created
VDouble0 m_statTablesCre; // Statistic tracking
// State cleared on each module
AstNodeModule* m_modp; // Current MODULE
int m_modTables; // Number of tables created in this module
AstNodeModule* m_modp; // Current MODULE
int m_modTables; // Number of tables created in this module
typedef std::deque<AstVarScope*> ModTableVector;
ModTableVector m_modTableVscs; // All tables created
// State cleared on each scope
AstScope* m_scopep; // Current SCOPE
AstScope* m_scopep; // Current SCOPE
// State cleared on each always/assignw
bool m_assignDly; // Consists of delayed assignments instead of normal assignments
int m_inWidth; // Input table width
int m_outWidth; // Output table width
bool m_assignDly; // Consists of delayed assignments instead of normal assignments
int m_inWidth; // Input table width
int m_outWidth; // Output table width
std::deque<AstVarScope*> m_inVarps; // Input variable list
std::deque<AstVarScope*> m_outVarps; // Output variable list
std::deque<bool> m_outNotSet; // True if output variable is not set at some point
std::deque<AstVarScope*> m_outVarps; // Output variable list
std::deque<bool> m_outNotSet; // True if output variable is not set at some point
// When creating a table
std::deque<AstVarScope*> m_tableVarps; // Table being created
std::deque<AstVarScope*> m_tableVarps; // Table being created
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -105,7 +106,7 @@ private:
m_outNotSet.clear();
// Collect stats
TableSimulateVisitor chkvis (this);
TableSimulateVisitor chkvis(this);
chkvis.mainTableCheck(nodep);
m_assignDly = chkvis.isAssignDly();
// Also sets m_inWidth
@ -115,12 +116,12 @@ private:
// Calc data storage in bytes
size_t chgWidth = m_outVarps.size(); // Width of one change-it-vector
if (chgWidth<8) chgWidth = 8;
if (chgWidth < 8) chgWidth = 8;
double space = (pow(static_cast<double>(2.0), static_cast<double>(m_inWidth))
* static_cast<double>(m_outWidth + chgWidth));
// Instruction count bytes (ok, it's space also not time :)
double bytesPerInst = 4;
double time = ((chkvis.instrCount()*bytesPerInst + chkvis.dataCount())
double time = ((chkvis.instrCount() * bytesPerInst + chkvis.dataCount())
+ 1); // +1 so won't div by zero
if (chkvis.instrCount() < TABLE_MIN_NODE_COUNT) {
chkvis.clearOptimizable(nodep, "Table has too few nodes involved");
@ -134,16 +135,15 @@ private:
if (m_totalBytes > TABLE_TOTAL_BYTES) {
chkvis.clearOptimizable(nodep, "Table out of memory");
}
if (!m_outWidth || !m_inWidth) {
chkvis.clearOptimizable(nodep, "Table has no outputs");
}
UINFO(4, " Test: Opt="<<(chkvis.optimizable()?"OK":"NO")
<<", Instrs="<<chkvis.instrCount()<<" Data="<<chkvis.dataCount()
<<" inw="<<m_inWidth<<" outw="<<m_outWidth
<<" Spacetime="<<(space/time)<<"("<<space<<"/"<<time<<")"
<<": "<<nodep<<endl);
if (!m_outWidth || !m_inWidth) { chkvis.clearOptimizable(nodep, "Table has no outputs"); }
UINFO(4, " Test: Opt=" << (chkvis.optimizable() ? "OK" : "NO")
<< ", Instrs=" << chkvis.instrCount()
<< " Data=" << chkvis.dataCount() << " inw=" << m_inWidth
<< " outw=" << m_outWidth << " Spacetime=" << (space / time) << "("
<< space << "/" << time << ")"
<< ": " << nodep << endl);
if (chkvis.optimizable()) {
UINFO(3, " Table Optimize spacetime="<<(space/time)<<" "<<nodep<<endl);
UINFO(3, " Table Optimize spacetime=" << (space / time) << " " << nodep << endl);
m_totalBytes += space;
}
return chkvis.optimizable();
@ -152,7 +152,7 @@ private:
public:
void simulateVarRefCb(AstVarRef* nodep) {
// Called by TableSimulateVisitor on each unique varref encountered
UINFO(9," SimVARREF "<<nodep<<endl);
UINFO(9, " SimVARREF " << nodep << endl);
AstVarScope* vscp = nodep->varScopep();
if (nodep->lvalue()) {
m_outWidth += nodep->varp()->dtypeSkipRefp()->widthTotalBytes();
@ -172,25 +172,21 @@ private:
++m_statTablesCre;
// Index into our table
AstVar* indexVarp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP,
"__Vtableidx" + cvtToStr(m_modTables),
VFlagBitPacked(), m_inWidth);
AstVar* indexVarp
= new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP,
"__Vtableidx" + cvtToStr(m_modTables), VFlagBitPacked(), m_inWidth);
m_modp->addStmtp(indexVarp);
AstVarScope* indexVscp = new AstVarScope(indexVarp->fileline(), m_scopep, indexVarp);
m_scopep->addVarp(indexVscp);
// Change it variable
FileLine* fl = nodep->fileline();
AstNodeArrayDType* dtypep
= new AstUnpackArrayDType(fl,
nodep->findBitDType(m_outVarps.size(),
m_outVarps.size(), AstNumeric::UNSIGNED),
new AstRange(fl, VL_MASK_I(m_inWidth), 0));
AstNodeArrayDType* dtypep = new AstUnpackArrayDType(
fl, nodep->findBitDType(m_outVarps.size(), m_outVarps.size(), AstNumeric::UNSIGNED),
new AstRange(fl, VL_MASK_I(m_inWidth), 0));
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
AstVar* chgVarp
= new AstVar(fl, AstVarType::MODULETEMP,
"__Vtablechg" + cvtToStr(m_modTables),
dtypep);
AstVar* chgVarp = new AstVar(fl, AstVarType::MODULETEMP,
"__Vtablechg" + cvtToStr(m_modTables), dtypep);
chgVarp->isConst(true);
chgVarp->valuep(new AstInitArray(nodep->fileline(), dtypep, NULL));
m_modp->addStmtp(chgVarp);
@ -215,7 +211,7 @@ private:
// Keep sensitivity list, but delete all else
nodeap->bodysp()->unlinkFrBackWithNext()->deleteTree();
nodeap->addStmtp(stmtsp);
if (debug()>=6) nodeap->dumpTree(cout, " table_new: ");
if (debug() >= 6) nodeap->dumpTree(cout, " table_new: ");
} else { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Creating table under unknown node type");
}
@ -226,23 +222,22 @@ private:
void createTableVars(AstNode* nodep) {
// Create table for each output
typedef std::map<string,int> NameCounts;
typedef std::map<string, int> NameCounts;
NameCounts namecounts;
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin();
it != m_outVarps.end(); ++it) {
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin(); it != m_outVarps.end();
++it) {
AstVarScope* outvscp = *it;
AstVar* outvarp = outvscp->varp();
FileLine* fl = nodep->fileline();
AstNodeArrayDType* dtypep
= new AstUnpackArrayDType(fl, outvarp->dtypep(),
new AstRange(fl, VL_MASK_I(m_inWidth), 0));
AstNodeArrayDType* dtypep = new AstUnpackArrayDType(
fl, outvarp->dtypep(), new AstRange(fl, VL_MASK_I(m_inWidth), 0));
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
string name = "__Vtable"+cvtToStr(m_modTables)+"_"+outvarp->name();
string name = "__Vtable" + cvtToStr(m_modTables) + "_" + outvarp->name();
NameCounts::iterator nit = namecounts.find(name);
if (nit != namecounts.end()) {
// Multiple scopes can have same var name. We could append the
// scope name but that is very long, so just deduplicate.
name += "__dedup"+cvtToStr(++nit->second);
name += "__dedup" + cvtToStr(++nit->second);
} else {
namecounts[name] = 0;
}
@ -261,18 +256,19 @@ private:
// Concat inputs into a single temp variable (inside always)
// First var in inVars becomes the LSB of the concat
AstNode* concatp = NULL;
for (std::deque<AstVarScope*>::iterator it = m_inVarps.begin(); it!=m_inVarps.end(); ++it) {
for (std::deque<AstVarScope*>::iterator it = m_inVarps.begin(); it != m_inVarps.end();
++it) {
AstVarScope* invscp = *it;
AstVarRef* refp = new AstVarRef(nodep->fileline(), invscp, false);
if (concatp) {
concatp = new AstConcat(nodep->fileline(), refp, concatp);
} else concatp = refp;
} else {
concatp = refp;
}
}
AstNode* stmtsp = new AstAssign
(nodep->fileline(),
new AstVarRef(nodep->fileline(), indexVscp, true),
concatp);
AstNode* stmtsp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), indexVscp, true), concatp);
return stmtsp;
}
@ -281,15 +277,15 @@ private:
// There may be a simulation path by which the output doesn't change value.
// We could bail on these cases, or we can have a "change it" boolean.
// We've chosen the latter route, since recirc is common in large FSMs.
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin();
it != m_outVarps.end(); ++it) {
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin(); it != m_outVarps.end();
++it) {
m_outNotSet.push_back(false);
}
uint32_t inValueNextInitArray = 0;
TableSimulateVisitor simvis (this);
for (uint32_t inValue=0; inValue <= VL_MASK_I(m_inWidth); inValue++) {
TableSimulateVisitor simvis(this);
for (uint32_t inValue = 0; inValue <= VL_MASK_I(m_inWidth); inValue++) {
// Make a new simulation structure so we can set new input values
UINFO(8," Simulating "<<std::hex<<inValue<<endl);
UINFO(8, " Simulating " << std::hex << inValue << endl);
// Above simulateVisitor clears user 3, so
// all outputs default to NULL to mean 'recirculating'.
@ -297,42 +293,42 @@ private:
// Set all inputs to the constant
uint32_t shift = 0;
for (std::deque<AstVarScope*>::iterator it = m_inVarps.begin();
it != m_inVarps.end(); ++it) {
for (std::deque<AstVarScope*>::iterator it = m_inVarps.begin(); it != m_inVarps.end();
++it) {
AstVarScope* invscp = *it;
// LSB is first variable, so extract it that way
AstConst cnst(invscp->fileline(), AstConst::WidthedValue(), invscp->width(),
VL_MASK_I(invscp->width()) & (inValue>>shift));
VL_MASK_I(invscp->width()) & (inValue >> shift));
simvis.newValue(invscp, &cnst);
shift += invscp->width();
// We're just using32 bit arithmetic, because there's no
// way the input table can be 2^32 bytes!
UASSERT_OBJ(shift <= 32, nodep, "shift overflow");
UINFO(8," Input "<<invscp->name()<<" = "<<cnst.name()<<endl);
UINFO(8, " Input " << invscp->name() << " = " << cnst.name() << endl);
}
// Simulate
simvis.mainTableEmulate(nodep);
UASSERT_OBJ(simvis.optimizable(), simvis.whyNotNodep(),
"Optimizable cleared, even though earlier test run said not: "
<<simvis.whyNotMessage());
<< simvis.whyNotMessage());
// If a output changed, add it to table
int outnum = 0;
V3Number outputChgMask (nodep, m_outVarps.size(), 0);
V3Number outputChgMask(nodep, m_outVarps.size(), 0);
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin();
it != m_outVarps.end(); ++it) {
AstVarScope* outvscp = *it;
V3Number* outnump = simvis.fetchOutNumberNull(outvscp);
AstNode* setp;
if (!outnump) {
UINFO(8," Output "<<outvscp->name()<<" never set\n");
UINFO(8, " Output " << outvscp->name() << " never set\n");
m_outNotSet[outnum] = true;
// Value in table is arbitrary, but we need something
setp = new AstConst(outvscp->fileline(),
AstConst::WidthedValue(), outvscp->width(), 0);
setp = new AstConst(outvscp->fileline(), AstConst::WidthedValue(),
outvscp->width(), 0);
} else {
UINFO(8," Output "<<outvscp->name()<<" = "<<*outnump<<endl);
UINFO(8, " Output " << outvscp->name() << " = " << *outnump << endl);
// m_tableVarps[inValue] = num;
// Mark changed bit, too
outputChgMask.setBit(outnum, 1);
@ -343,7 +339,7 @@ private:
outnum++;
}
{ // Set changed table
{ // Set changed table
UASSERT_OBJ(inValue == inValueNextInitArray, nodep,
"InitArray requires us to have the values in inValue order");
inValueNextInitArray++;
@ -359,7 +355,7 @@ private:
AstVar* var1p = vsc1p->varp();
for (std::deque<AstVarScope*>::iterator it = m_modTableVscs.begin();
it != m_modTableVscs.end(); ++it) {
AstVarScope* vsc2p= *it;
AstVarScope* vsc2p = *it;
AstVar* var2p = vsc2p->varp();
if (var1p->width() == var2p->width()
&& (var1p->dtypep()->arrayUnpackedElements()
@ -367,7 +363,7 @@ private:
const AstNode* init1p = VN_CAST(var1p->valuep(), InitArray);
const AstNode* init2p = VN_CAST(var2p->valuep(), InitArray);
if (init1p->sameGateTree(init2p)) {
UINFO(8," Duplicate table var "<<vsc2p<<" == "<<vsc1p<<endl);
UINFO(8, " Duplicate table var " << vsc2p << " == " << vsc1p << endl);
VL_DO_DANGLING(vsc1p->unlinkFrBack()->deleteTree(), vsc1p);
return vsc2p;
}
@ -377,31 +373,30 @@ private:
return vsc1p;
}
void createOutputAssigns(AstNode* nodep, AstNode* stmtsp,
AstVarScope* indexVscp, AstVarScope* chgVscp) {
void createOutputAssigns(AstNode* nodep, AstNode* stmtsp, AstVarScope* indexVscp,
AstVarScope* chgVscp) {
// We walk through the changemask table, and if all ones know
// the output is set on all branches and therefore eliminate the
// if. If all uses of the changemask disappear, dead code
// elimination will remove it for us.
// Set each output from array ref into our table
int outnum = 0;
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin();
it != m_outVarps.end(); ++it) {
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin(); it != m_outVarps.end();
++it) {
AstVarScope* outvscp = *it;
AstNode* alhsp = new AstVarRef(nodep->fileline(), outvscp, true);
AstNode* arhsp
= new AstArraySel(nodep->fileline(),
new AstVarRef(nodep->fileline(), m_tableVarps[outnum], false),
new AstVarRef(nodep->fileline(), indexVscp, false));
AstNode* arhsp = new AstArraySel(
nodep->fileline(), new AstVarRef(nodep->fileline(), m_tableVarps[outnum], false),
new AstVarRef(nodep->fileline(), indexVscp, false));
AstNode* outasnp
= (m_assignDly
? static_cast<AstNode*>(new AstAssignDly(nodep->fileline(), alhsp, arhsp))
: static_cast<AstNode*>(new AstAssign(nodep->fileline(), alhsp, arhsp)));
? static_cast<AstNode*>(new AstAssignDly(nodep->fileline(), alhsp, arhsp))
: static_cast<AstNode*>(new AstAssign(nodep->fileline(), alhsp, arhsp)));
AstNode* outsetp = outasnp;
// Is the value set in only some branches of the table?
if (m_outNotSet[outnum]) {
V3Number outputChgMask (nodep, m_outVarps.size(), 0);
V3Number outputChgMask(nodep, m_outVarps.size(), 0);
outputChgMask.setBit(outnum, 1);
outsetp = new AstIf(
nodep->fileline(),
@ -418,11 +413,8 @@ private:
}
}
// VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
iterateChildren(nodep);
}
virtual void visit(AstNetlist* nodep) VL_OVERRIDE { iterateChildren(nodep); }
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
AstNodeModule* origModp = m_modp;
int origModTables = m_modTables;
@ -438,13 +430,13 @@ private:
m_modTableVscs = origModTableVscs;
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
UINFO(4," SCOPE "<<nodep<<endl);
UINFO(4, " SCOPE " << nodep << endl);
m_scopep = nodep;
iterateChildren(nodep);
m_scopep = NULL;
}
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
UINFO(4," ALWAYS "<<nodep<<endl);
UINFO(4, " ALWAYS " << nodep << endl);
if (treeTest(nodep)) {
// Well, then, I'll be a memory hog.
VL_DO_DANGLING(createTable(nodep), nodep);
@ -470,7 +462,7 @@ public:
m_totalBytes = 0;
iterate(nodep);
}
virtual ~TableVisitor() {
virtual ~TableVisitor() { //
V3Stats::addStat("Optimizations, Tables created", m_statTablesCre);
}
};
@ -487,9 +479,7 @@ void TableSimulateVisitor::varRefCb(AstVarRef* nodep) {
// Table class functions
void V3Table::tableAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
TableVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ TableVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("table", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

File diff suppressed because it is too large Load Diff

View File

@ -551,7 +551,7 @@ private:
// Assign trace code, add to tree, return node for change tree or null
// Look for identical copies
uint32_t codePreassigned = 0;
// if (debug()>=9) nodep->dumpTree(cout, "- assnnode: ");
// if (debug() >= 9) nodep->dumpTree(cout, "- assnnode: ");
// Find non-duplicated node; note some nodep's maybe null, as they were deleted below
TraceTraceVertex* dupvertexp = vvertexp;
if (dupvertexp->duplicatep()) {

File diff suppressed because it is too large Load Diff

View File

@ -51,16 +51,12 @@ class UndrivenVarEntry {
public:
// CONSTRUCTORS
explicit UndrivenVarEntry(AstVar* varp) { // Construction for when a var is used
UINFO(9, "create "<<varp<<endl);
UINFO(9, "create " << varp << endl);
m_varp = varp;
m_wholeFlags.resize(FLAGS_PER_BIT);
for (int i = 0; i < FLAGS_PER_BIT; i++) {
m_wholeFlags[i] = false;
}
for (int i = 0; i < FLAGS_PER_BIT; i++) m_wholeFlags[i] = false;
m_bitFlags.resize(varp->width() * FLAGS_PER_BIT);
for (int i = 0; i < varp->width() * FLAGS_PER_BIT; i++) {
m_bitFlags[i] = false;
}
for (int i = 0; i < varp->width() * FLAGS_PER_BIT; i++) m_bitFlags[i] = false;
}
~UndrivenVarEntry() {}
@ -81,60 +77,63 @@ private:
bool prev = false;
int msb = 0;
// bit==-1 loops below; we do one extra iteration so end with prev=false
for (int bit=(m_bitFlags.size()/FLAGS_PER_BIT)-1; bit >= -1; --bit) {
if (bit>=0
for (int bit = (m_bitFlags.size() / FLAGS_PER_BIT) - 1; bit >= -1; --bit) {
if (bit >= 0
&& ((which == BN_UNUSED && !usedFlag(bit) && drivenFlag(bit))
|| (which == BN_UNDRIVEN && usedFlag(bit) && !drivenFlag(bit))
|| (which == BN_BOTH && !usedFlag(bit) && !drivenFlag(bit)))) {
if (!prev) { prev=true; msb = bit; }
if (!prev) {
prev = true;
msb = bit;
}
} else if (prev) {
AstBasicDType* bdtypep = m_varp->basicp();
int lsb = bit+1;
int lsb = bit + 1;
if (bits != "") bits += ",";
if (lsb==msb) {
bits += cvtToStr(lsb+bdtypep->lsb());
if (lsb == msb) {
bits += cvtToStr(lsb + bdtypep->lsb());
} else {
if (bdtypep->littleEndian()) {
bits += cvtToStr(lsb+bdtypep->lsb())+":"+cvtToStr(msb+bdtypep->lsb());
bits += cvtToStr(lsb + bdtypep->lsb()) + ":"
+ cvtToStr(msb + bdtypep->lsb());
} else {
bits += cvtToStr(msb+bdtypep->lsb())+":"+cvtToStr(lsb+bdtypep->lsb());
bits += cvtToStr(msb + bdtypep->lsb()) + ":"
+ cvtToStr(lsb + bdtypep->lsb());
}
}
prev = false;
}
}
return "["+bits+"]";
return "[" + bits + "]";
}
public:
void usedWhole() {
UINFO(9, "set u[*] "<<m_varp->name()<<endl);
UINFO(9, "set u[*] " << m_varp->name() << endl);
m_wholeFlags[FLAG_USED] = true;
}
void drivenWhole() {
UINFO(9, "set d[*] "<<m_varp->name()<<endl);
UINFO(9, "set d[*] " << m_varp->name() << endl);
m_wholeFlags[FLAG_DRIVEN] = true;
}
void usedBit(int bit, int width) {
UINFO(9, "set u["<<(bit+width-1)<<":"<<bit<<"] "<<m_varp->name()<<endl);
UINFO(9, "set u[" << (bit + width - 1) << ":" << bit << "] " << m_varp->name() << endl);
for (int i = 0; i < width; i++) {
if (bitNumOk(bit + i)) {
m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_USED] = true;
}
if (bitNumOk(bit + i)) m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_USED] = true;
}
}
void drivenBit(int bit, int width) {
UINFO(9, "set d["<<(bit+width-1)<<":"<<bit<<"] "<<m_varp->name()<<endl);
UINFO(9, "set d[" << (bit + width - 1) << ":" << bit << "] " << m_varp->name() << endl);
for (int i = 0; i < width; i++) {
if (bitNumOk(bit + i)) {
m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN] = true;
}
if (bitNumOk(bit + i)) m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN] = true;
}
}
bool isUsedNotDrivenBit(int bit, int width) const {
for (int i = 0; i < width; i++) {
if (bitNumOk(bit + i)
&& (m_wholeFlags[FLAG_USED] || m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_USED])
&& !(m_wholeFlags[FLAG_DRIVEN] || m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN]))
&& !(m_wholeFlags[FLAG_DRIVEN]
|| m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN]))
return true;
}
return false;
@ -183,39 +182,43 @@ public:
// UNDRIVEN is considered more serious - as is more likely a bug,
// thus undriven+unused bits get UNUSED warnings, as they're not as buggy.
if (!unusedMatch(nodep)) {
nodep->v3warn(UNUSED, "Signal is not driven, nor used: "
<<nodep->prettyNameQ());
nodep->v3warn(UNUSED,
"Signal is not driven, nor used: " << nodep->prettyNameQ());
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once
}
} else if (allD && !anyU) {
if (!unusedMatch(nodep)) {
nodep->v3warn(UNUSED, "Signal is not used: "<<nodep->prettyNameQ());
nodep->v3warn(UNUSED, "Signal is not used: " << nodep->prettyNameQ());
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once
}
} else if (!anyD && allU) {
nodep->v3warn(UNDRIVEN, "Signal is not driven: "<<nodep->prettyNameQ());
nodep->v3warn(UNDRIVEN, "Signal is not driven: " << nodep->prettyNameQ());
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true); // Warn only once
} else {
// Bits have different dispositions
bool setU=false; bool setD=false;
bool setU = false;
bool setD = false;
if (anynotDU && !unusedMatch(nodep)) {
nodep->v3warn(UNUSED, "Bits of signal are not driven, nor used: "
<<nodep->prettyNameQ()
<<bitNames(BN_BOTH));
<< nodep->prettyNameQ() << bitNames(BN_BOTH));
setU = true;
}
if (anyDnotU && !unusedMatch(nodep)) {
nodep->v3warn(UNUSED, "Bits of signal are not used: "<<nodep->prettyNameQ()
<<bitNames(BN_UNUSED));
nodep->v3warn(UNUSED, "Bits of signal are not used: " << nodep->prettyNameQ()
<< bitNames(BN_UNUSED));
setU = true;
}
if (anyUnotD) {
nodep->v3warn(UNDRIVEN, "Bits of signal are not driven: "<<nodep->prettyNameQ()
<<bitNames(BN_UNDRIVEN));
nodep->v3warn(UNDRIVEN, "Bits of signal are not driven: "
<< nodep->prettyNameQ() << bitNames(BN_UNDRIVEN));
setD = true;
}
if (setU) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once
if (setD) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true); // Warn only once
if (setU) { // Warn only once
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);
}
if (setD) { // Warn only once
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true);
}
}
}
}
@ -246,17 +249,21 @@ private:
VL_DEBUG_FUNC; // Declare debug()
UndrivenVarEntry* getEntryp(AstVar* nodep, int which_user) {
if (!(which_user==1 ? nodep->user1p() : nodep->user2p())) {
if (!(which_user == 1 ? nodep->user1p() : nodep->user2p())) {
UndrivenVarEntry* entryp = new UndrivenVarEntry(nodep);
//UINFO(9," Associate u="<<which_user<<" "<<cvtToHex(this)<<" "<<nodep->name()<<endl);
// UINFO(9," Associate u="<<which_user<<" "<<cvtToHex(this)<<" "<<nodep->name()<<endl);
m_entryps[which_user].push_back(entryp);
if (which_user==1) nodep->user1p(entryp);
else if (which_user==2) nodep->user2p(entryp);
else nodep->v3fatalSrc("Bad case");
if (which_user == 1) {
nodep->user1p(entryp);
} else if (which_user == 2) {
nodep->user2p(entryp);
} else {
nodep->v3fatalSrc("Bad case");
}
return entryp;
} else {
UndrivenVarEntry* entryp = reinterpret_cast<UndrivenVarEntry*>
(which_user==1 ? nodep->user1p() : nodep->user2p());
UndrivenVarEntry* entryp = reinterpret_cast<UndrivenVarEntry*>(
which_user == 1 ? nodep->user1p() : nodep->user2p());
return entryp;
}
}
@ -266,35 +273,33 @@ private:
if (!varp->isParam() && !varp->isGenVar() && !varp->isUsedLoopIdx()
&& !m_inBBox // We may have falsely considered a SysIgnore as a driver
&& !VN_IS(nodep, VarXRef) // Xrefs might point at two different instances
&& !varp->fileline()->warnIsOff(V3ErrorCode::ALWCOMBORDER)) { // Warn only once per variable
nodep->v3warn(ALWCOMBORDER, "Always_comb variable driven after use: "
<<nodep->prettyNameQ());
varp->fileline()->modifyWarnOff(V3ErrorCode::ALWCOMBORDER, true); // Complain just once for any usage
&& !varp->fileline()->warnIsOff(
V3ErrorCode::ALWCOMBORDER)) { // Warn only once per variable
nodep->v3warn(ALWCOMBORDER,
"Always_comb variable driven after use: " << nodep->prettyNameQ());
varp->fileline()->modifyWarnOff(V3ErrorCode::ALWCOMBORDER,
true); // Complain just once for any usage
}
}
// VISITORS
virtual void visit(AstVar* nodep) VL_OVERRIDE {
for (int usr=1; usr<(m_alwaysCombp?3:2); ++usr) {
for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) {
// For assigns and non-combo always, do just usr==1, to look
// for module-wide undriven etc.
// For non-combo always, run both usr==1 for above, and also
// usr==2 for always-only checks.
UndrivenVarEntry* entryp = getEntryp(nodep, usr);
if (nodep->isNonOutput()
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
if (nodep->isNonOutput() || nodep->isSigPublic() || nodep->isSigUserRWPublic()
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
entryp->drivenWhole();
}
if (nodep->isWritable()
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
if (nodep->isWritable() || nodep->isSigPublic() || nodep->isSigUserRWPublic()
|| nodep->isSigUserRdPublic()
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
entryp->usedWhole();
}
if (nodep->valuep()) {
entryp->drivenWhole();
}
if (nodep->valuep()) entryp->drivenWhole();
}
// Discover variables used in bit definitions, etc
iterateChildren(nodep);
@ -311,14 +316,14 @@ private:
AstNodeVarRef* varrefp = VN_CAST(nodep->fromp(), NodeVarRef);
AstConst* constp = VN_CAST(nodep->lsbp(), Const);
if (varrefp && constp && !constp->num().isFourState()) {
for (int usr=1; usr<(m_alwaysCombp?3:2); ++usr) {
for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) {
UndrivenVarEntry* entryp = getEntryp(varrefp->varp(), usr);
int lsb = constp->toUInt();
if (m_inBBox || varrefp->lvalue()) {
// Don't warn if already driven earlier as "a=0; if(a) a=1;" is fine.
if (usr==2 && m_alwaysCombp
if (usr == 2 && m_alwaysCombp
&& entryp->isUsedNotDrivenBit(lsb, nodep->width())) {
UINFO(9," Select. Entryp="<<cvtToHex(entryp)<<endl);
UINFO(9, " Select. Entryp=" << cvtToHex(entryp) << endl);
warnAlwCombOrder(varrefp);
}
entryp->drivenBit(lsb, nodep->width());
@ -335,25 +340,27 @@ private:
if (nodep->lvalue()
&& !VN_IS(nodep, VarXRef)) { // Ignore interface variables and similar ugly items
if (m_inProcAssign && !nodep->varp()->varType().isProcAssignable()
&& !nodep->varp()->isDeclTyped()
&& !nodep->varp()->isClassMember()
&& !nodep->varp()->isFuncLocal()) {
&& !nodep->varp()->isDeclTyped() //
&& !nodep->varp()->isClassMember() && !nodep->varp()->isFuncLocal()) {
nodep->v3warn(PROCASSWIRE, "Procedural assignment to wire, perhaps intended var"
<< " (IEEE 1800-2017 6.5): " << nodep->prettyNameQ());
<< " (IEEE 1800-2017 6.5): "
<< nodep->prettyNameQ());
}
if (m_inContAssign && !nodep->varp()->varType().isContAssignable()
&& !nodep->fileline()->language().systemVerilog()) {
nodep->v3warn(CONTASSREG, "Continuous assignment to reg, perhaps intended wire"
<< " (IEEE 1364-2005 6.1; Verilog only, legal in SV): "
<< nodep->prettyNameQ());
nodep->v3warn(CONTASSREG,
"Continuous assignment to reg, perhaps intended wire"
<< " (IEEE 1364-2005 6.1; Verilog only, legal in SV): "
<< nodep->prettyNameQ());
}
}
for (int usr=1; usr<(m_alwaysCombp?3:2); ++usr) {
for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) {
UndrivenVarEntry* entryp = getEntryp(nodep->varp(), usr);
bool fdrv = nodep->lvalue() && nodep->varp()->attrFileDescr(); // FD's are also being read from
bool fdrv = nodep->lvalue()
&& nodep->varp()->attrFileDescr(); // FD's are also being read from
if (m_inBBox || nodep->lvalue()) {
if (usr==2 && m_alwaysCombp && entryp->isUsedNotDrivenAny()) {
UINFO(9," Full bus. Entryp="<<cvtToHex(entryp)<<endl);
if (usr == 2 && m_alwaysCombp && entryp->isUsedNotDrivenAny()) {
UINFO(9, " Full bus. Entryp=" << cvtToHex(entryp) << endl);
warnAlwCombOrder(nodep);
}
entryp->drivenWhole();
@ -398,11 +405,14 @@ private:
AstAlways* prevAlwp = m_alwaysCombp;
{
AstNode::user2ClearTree();
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9," "<<nodep<<endl);
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) m_alwaysCombp = nodep;
else m_alwaysCombp = NULL;
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9, " " << nodep << endl);
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) {
m_alwaysCombp = nodep;
} else {
m_alwaysCombp = NULL;
}
iterateChildren(nodep);
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9," Done "<<nodep<<endl);
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9, " Done " << nodep << endl);
}
m_alwaysCombp = prevAlwp;
}
@ -456,6 +466,6 @@ public:
// Undriven class functions
void V3Undriven::undrivenAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
UndrivenVisitor visitor (nodep);
UINFO(2, __FUNCTION__ << ": " << endl);
UndrivenVisitor visitor(nodep);
}

View File

@ -49,15 +49,15 @@ private:
// AstSel::user() -> bool. Set true if already processed
// AstArraySel::user() -> bool. Set true if already processed
// AstNode::user2p() -> AstIf* Inserted if assignment for conditional
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
// STATE
AstNodeModule* m_modp; // Current module
bool m_constXCvt; // Convert X's
VDouble0 m_statUnkVars; // Statistic tracking
AstAssignW* m_assignwp; // Current assignment
AstAssignDly* m_assigndlyp; // Current assignment
AstNodeModule* m_modp; // Current module
bool m_constXCvt; // Convert X's
VDouble0 m_statUnkVars; // Statistic tracking
AstAssignW* m_assignwp; // Current assignment
AstAssignDly* m_assigndlyp; // Current assignment
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -81,7 +81,7 @@ private:
if (m_assignwp) {
// Wire assigns must become always statements to deal with insertion
// of multiple statements. Perhaps someday make all wassigns into always's?
UINFO(5," IM_WireRep "<<m_assignwp<<endl);
UINFO(5, " IM_WireRep " << m_assignwp << endl);
m_assignwp->convertToAlways();
VL_DO_CLEAR(pushDeletep(m_assignwp), m_assignwp = NULL);
}
@ -98,8 +98,7 @@ private:
AstNode* prep = nodep;
// Scan back to put the condlvalue above all selects (IE top of the lvalue)
while (VN_IS(prep->backp(), NodeSel)
|| VN_IS(prep->backp(), Sel)) {
while (VN_IS(prep->backp(), NodeSel) || VN_IS(prep->backp(), Sel)) {
prep = prep->backp();
}
FileLine* fl = nodep->fileline();
@ -111,30 +110,24 @@ private:
UASSERT_OBJ(!needDly, prep, "Should have already converted to non-delay");
AstNRelinker replaceHandle;
AstNode* earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle);
AstNode* newp = new AstLogAnd(condp->fileline(),
condp, earliercondp);
UINFO(4, "Edit BOUNDLVALUE "<<newp<<endl);
AstNode* newp = new AstLogAnd(condp->fileline(), condp, earliercondp);
UINFO(4, "Edit BOUNDLVALUE " << newp << endl);
replaceHandle.relink(newp);
}
else {
string name = (string("__Vlvbound")+cvtToStr(m_modp->varNumGetInc()));
AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name,
prep->dtypep());
} else {
string name = (string("__Vlvbound") + cvtToStr(m_modp->varNumGetInc()));
AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name, prep->dtypep());
m_modp->addStmtp(varp);
AstNode* abovep = prep->backp(); // Grab above point before lose it w/ next replace
prep->replaceWith(new AstVarRef(fl, varp, true));
AstIf* newp = new AstIf(fl, condp,
(needDly
? static_cast<AstNode*>
(new AstAssignDly(fl, prep,
new AstVarRef(fl, varp, false)))
: static_cast<AstNode*>
(new AstAssign(fl, prep,
new AstVarRef(fl, varp, false)))),
(needDly ? static_cast<AstNode*>(new AstAssignDly(
fl, prep, new AstVarRef(fl, varp, false)))
: static_cast<AstNode*>(new AstAssign(
fl, prep, new AstVarRef(fl, varp, false)))),
NULL);
newp->branchPred(VBranchPred::BP_LIKELY);
if (debug()>=9) newp->dumpTree(cout, " _new: ");
if (debug() >= 9) newp->dumpTree(cout, " _new: ");
abovep->addNextStmt(newp, abovep);
prep->user2p(newp); // Save so we may LogAnd it next time
}
@ -142,7 +135,7 @@ private:
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
UINFO(4," MOD "<<nodep<<endl);
UINFO(4, " MOD " << nodep << endl);
AstNodeModule* origModp = m_modp;
{
m_modp = nodep;
@ -173,7 +166,7 @@ private:
m_constXCvt = true;
}
void visitEqNeqCase(AstNodeBiop* nodep) {
UINFO(4," N/EQCASE->EQ "<<nodep<<endl);
UINFO(4, " N/EQCASE->EQ " << nodep << endl);
V3Const::constifyEdit(nodep->lhsp()); // lhsp may change
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
if (VN_IS(nodep->lhsp(), Const) && VN_IS(nodep->rhsp(), Const)) {
@ -187,14 +180,16 @@ private:
// If we got ==1'bx it can never be true (but 1'bx==1'bx can be!)
if (((VN_IS(lhsp, Const) && VN_CAST(lhsp, Const)->num().isFourState())
|| (VN_IS(rhsp, Const) && VN_CAST(rhsp, Const)->num().isFourState()))) {
newp = new AstConst(nodep->fileline(), AstConst::WidthedValue(),
1, (VN_IS(nodep, EqCase) ? 0 : 1));
newp = new AstConst(nodep->fileline(), AstConst::WidthedValue(), 1,
(VN_IS(nodep, EqCase) ? 0 : 1));
VL_DO_DANGLING(lhsp->deleteTree(), lhsp);
VL_DO_DANGLING(rhsp->deleteTree(), rhsp);
} else {
if (VN_IS(nodep, EqCase)) {
newp = new AstEq(nodep->fileline(), lhsp, rhsp);
} else { newp = new AstNeq(nodep->fileline(), lhsp, rhsp); }
} else {
newp = new AstNeq(nodep->fileline(), lhsp, rhsp);
}
}
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
@ -203,7 +198,7 @@ private:
}
}
void visitEqNeqWild(AstNodeBiop* nodep) {
UINFO(4," N/EQWILD->EQ "<<nodep<<endl);
UINFO(4, " N/EQWILD->EQ " << nodep << endl);
V3Const::constifyEdit(nodep->lhsp()); // lhsp may change
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
if (VN_IS(nodep->lhsp(), Const) && VN_IS(nodep->rhsp(), Const)) {
@ -215,21 +210,24 @@ private:
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* newp;
if (!VN_IS(rhsp, Const)) {
nodep->v3error("Unsupported: RHS of ==? or !=? must be constant to be synthesizable"); // Says spec.
nodep->v3error("Unsupported: RHS of ==? or !=? must be "
"constant to be synthesizable"); // Says spec.
// Replace with anything that won't cause more errors
newp = new AstEq(nodep->fileline(), lhsp, rhsp);
} else {
// X or Z's become mask, ala case statements.
V3Number nummask (rhsp, rhsp->width());
V3Number nummask(rhsp, rhsp->width());
nummask.opBitsNonX(VN_CAST(rhsp, Const)->num());
V3Number numval (rhsp, rhsp->width());
V3Number numval(rhsp, rhsp->width());
numval.opBitsOne(VN_CAST(rhsp, Const)->num());
AstNode* and1p = new AstAnd(nodep->fileline(), lhsp,
new AstConst(nodep->fileline(), nummask));
AstNode* and2p = new AstConst(nodep->fileline(), numval);
if (VN_IS(nodep, EqWild)) {
newp = new AstEq(nodep->fileline(), and1p, and2p);
} else { newp = new AstNeq(nodep->fileline(), and1p, and2p); }
newp = new AstEq(nodep->fileline(), and1p, and2p);
} else {
newp = new AstNeq(nodep->fileline(), and1p, and2p);
}
VL_DO_DANGLING(rhsp->deleteTree(), rhsp);
}
nodep->replaceWith(newp);
@ -239,42 +237,33 @@ private:
}
}
virtual void visit(AstEqCase* nodep) VL_OVERRIDE {
visitEqNeqCase(nodep);
}
virtual void visit(AstNeqCase* nodep) VL_OVERRIDE {
visitEqNeqCase(nodep);
}
virtual void visit(AstEqWild* nodep) VL_OVERRIDE {
visitEqNeqWild(nodep);
}
virtual void visit(AstNeqWild* nodep) VL_OVERRIDE {
visitEqNeqWild(nodep);
}
virtual void visit(AstEqCase* nodep) VL_OVERRIDE { visitEqNeqCase(nodep); }
virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { visitEqNeqCase(nodep); }
virtual void visit(AstEqWild* nodep) VL_OVERRIDE { visitEqNeqWild(nodep); }
virtual void visit(AstNeqWild* nodep) VL_OVERRIDE { visitEqNeqWild(nodep); }
virtual void visit(AstIsUnknown* nodep) VL_OVERRIDE {
iterateChildren(nodep);
// Ahh, we're two state, so this is easy
UINFO(4," ISUNKNOWN->0 "<<nodep<<endl);
UINFO(4, " ISUNKNOWN->0 " << nodep << endl);
AstConst* newp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstConst* nodep) VL_OVERRIDE {
if (m_constXCvt
&& nodep->num().isFourState()) {
UINFO(4," CONST4 "<<nodep<<endl);
if (debug()>=9) nodep->dumpTree(cout, " Const_old: ");
if (m_constXCvt && nodep->num().isFourState()) {
UINFO(4, " CONST4 " << nodep << endl);
if (debug() >= 9) nodep->dumpTree(cout, " Const_old: ");
// CONST(num) -> VARREF(newvarp)
// -> VAR(newvarp)
// -> INITIAL(VARREF(newvarp, OR(num_No_Xs,AND(random,num_1s_Where_X))
V3Number numb1 (nodep, nodep->width());
V3Number numb1(nodep, nodep->width());
numb1.opBitsOne(nodep->num());
V3Number numbx (nodep, nodep->width());
V3Number numbx(nodep, nodep->width());
numbx.opBitsXZ(nodep->num());
if (v3Global.opt.xAssign()!="unique") {
if (v3Global.opt.xAssign() != "unique") {
// All X bits just become 0; fastest simulation, but not nice
V3Number numnew (nodep, numb1.width());
if (v3Global.opt.xAssign()=="1") {
V3Number numnew(nodep, numb1.width());
if (v3Global.opt.xAssign() == "1") {
numnew.opOr(numb1, numbx);
} else {
numnew.opAssign(numb1);
@ -282,42 +271,36 @@ private:
AstConst* newp = new AstConst(nodep->fileline(), numnew);
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
UINFO(4," -> "<<newp<<endl);
UINFO(4, " -> " << newp << endl);
} else {
// Make a Vxrand variable
// We use the special XTEMP type so it doesn't break pure functions
UASSERT_OBJ(m_modp, nodep, "X number not under module");
string newvarname = (string("__Vxrand")
+cvtToStr(m_modp->varNumGetInc()));
AstVar* newvarp
= new AstVar(nodep->fileline(), AstVarType::XTEMP, newvarname,
VFlagLogicPacked(), nodep->width());
string newvarname = (string("__Vxrand") + cvtToStr(m_modp->varNumGetInc()));
AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::XTEMP, newvarname,
VFlagLogicPacked(), nodep->width());
++m_statUnkVars;
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, false);
replaceHandle.relink(newref1p); // Replace const with varref
AstInitial* newinitp
= new AstInitial(
nodep->fileline(),
new AstAssign(
nodep->fileline(),
new AstVarRef(nodep->fileline(), newvarp, true),
new AstOr(nodep->fileline(),
new AstConst(nodep->fileline(), numb1),
new AstAnd(nodep->fileline(),
new AstConst(nodep->fileline(), numbx),
new AstRand(nodep->fileline(),
nodep->dtypep(), true)))));
AstInitial* newinitp = new AstInitial(
nodep->fileline(),
new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), newvarp, true),
new AstOr(
nodep->fileline(), new AstConst(nodep->fileline(), numb1),
new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), numbx),
new AstRand(nodep->fileline(), nodep->dtypep(), true)))));
// Add inits in front of other statement.
// In the future, we should stuff the initp into the module's constructor.
AstNode* afterp = m_modp->stmtsp()->unlinkFrBackWithNext();
m_modp->addStmtp(newvarp);
m_modp->addStmtp(newinitp);
m_modp->addStmtp(afterp);
if (debug()>=9) newref1p->dumpTree(cout, " _new: ");
if (debug()>=9) newvarp->dumpTree(cout, " _new: ");
if (debug()>=9) newinitp->dumpTree(cout, " _new: ");
if (debug() >= 9) newref1p->dumpTree(cout, " _new: ");
if (debug() >= 9) newvarp->dumpTree(cout, " _new: ");
if (debug() >= 9) newinitp->dumpTree(cout, " _new: ");
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
@ -334,13 +317,12 @@ private:
}
// Find range of dtype we are selecting from
// Similar code in V3Const::warnSelect
int maxmsb = nodep->fromp()->dtypep()->width()-1;
if (debug()>=9) nodep->dumpTree(cout, "sel_old: ");
int maxmsb = nodep->fromp()->dtypep()->width() - 1;
if (debug() >= 9) nodep->dumpTree(cout, "sel_old: ");
// If (maxmsb >= selected), we're in bound
AstNode* condp = new AstGte(nodep->fileline(),
new AstConst(nodep->fileline(),
AstConst::WidthedValue(),
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
nodep->lsbp()->width(), maxmsb),
nodep->lsbp()->cloneTree(false));
// See if the condition is constant true (e.g. always in bound due to constant select)
@ -349,24 +331,20 @@ private:
if (condp->isOne()) {
// We don't need to add a conditional; we know the existing expression is ok
VL_DO_DANGLING(condp->deleteTree(), condp);
}
else if (!lvalue) {
} else if (!lvalue) {
// SEL(...) -> COND(LTE(bit<=maxmsb), ARRAYSEL(...), {width{1'bx}})
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
V3Number xnum (nodep, nodep->width());
V3Number xnum(nodep, nodep->width());
xnum.setAllBitsX();
AstNode* newp = new AstCondBound(nodep->fileline(),
condp,
nodep,
AstNode* newp = new AstCondBound(nodep->fileline(), condp, nodep,
new AstConst(nodep->fileline(), xnum));
if (debug()>=9) newp->dumpTree(cout, " _new: ");
if (debug() >= 9) newp->dumpTree(cout, " _new: ");
// Link in conditional
replaceHandle.relink(newp);
// Added X's, tristate them too
iterate(newp);
}
else { // lvalue
} else { // lvalue
replaceBoundLvalue(nodep, condp);
}
}
@ -378,7 +356,7 @@ private:
virtual void visit(AstArraySel* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (!nodep->user1SetOnce()) {
if (debug()==9) nodep->dumpTree(cout, "-in: ");
if (debug() == 9) nodep->dumpTree(cout, "-in: ");
// Guard against reading/writing past end of arrays
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
bool lvalue = false;
@ -396,57 +374,51 @@ private:
if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) {
declElements = adtypep->elementsConst();
} else {
nodep->v3error("Select from non-array "<<dtypep->prettyTypeName());
nodep->v3error("Select from non-array " << dtypep->prettyTypeName());
}
if (debug()>=9) nodep->dumpTree(cout, "arraysel_old: ");
if (debug() >= 9) nodep->dumpTree(cout, "arraysel_old: ");
// See if the condition is constant true
AstNode* condp = new AstGte(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
nodep->bitp()->width(), declElements-1),
nodep->bitp()->width(), declElements - 1),
nodep->bitp()->cloneTree(false));
// Note below has null backp(); the Edit function knows how to deal with that.
condp = V3Const::constifyEdit(condp);
if (condp->isOne()) {
// We don't need to add a conditional; we know the existing expression is ok
VL_DO_DANGLING(condp->deleteTree(), condp);
}
else if (!lvalue
// Making a scalar would break if we're making an array
&& !VN_IS(nodep->dtypep()->skipRefp(), NodeArrayDType)) {
} else if (!lvalue
// Making a scalar would break if we're making an array
&& !VN_IS(nodep->dtypep()->skipRefp(), NodeArrayDType)) {
// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
V3Number xnum (nodep, nodep->width());
V3Number xnum(nodep, nodep->width());
if (nodep->isString()) {
xnum = V3Number(V3Number::String(), nodep, "");
} else {
xnum.setAllBitsX();
}
AstNode* newp = new AstCondBound(nodep->fileline(),
condp, nodep,
AstNode* newp = new AstCondBound(nodep->fileline(), condp, nodep,
new AstConst(nodep->fileline(), xnum));
if (debug()>=9) newp->dumpTree(cout, " _new: ");
if (debug() >= 9) newp->dumpTree(cout, " _new: ");
// Link in conditional, can blow away temp xor
replaceHandle.relink(newp);
// Added X's, tristate them too
iterate(newp);
}
else if (!lvalue) { // Mid-multidimension read, just use zero
} else if (!lvalue) { // Mid-multidimension read, just use zero
// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
AstNRelinker replaceHandle;
AstNode* bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
AstNode* newp = new AstCondBound(bitp->fileline(),
condp, bitp,
new AstConst(bitp->fileline(),
AstConst::WidthedValue(),
bitp->width(), 0));
AstNode* newp = new AstCondBound(
bitp->fileline(), condp, bitp,
new AstConst(bitp->fileline(), AstConst::WidthedValue(), bitp->width(), 0));
// Added X's, tristate them too
if (debug()>=9) newp->dumpTree(cout, " _new: ");
if (debug() >= 9) newp->dumpTree(cout, " _new: ");
replaceHandle.relink(newp);
iterate(newp);
}
else { // lvalue
} else { // lvalue
replaceBoundLvalue(nodep, condp);
}
}
@ -463,7 +435,7 @@ public:
m_constXCvt = false;
iterate(nodep);
}
virtual ~UnknownVisitor() {
virtual ~UnknownVisitor() { //
V3Stats::addStat("Unknowns, variables created", m_statUnkVars);
}
};
@ -472,9 +444,7 @@ public:
// Unknown class functions
void V3Unknown::unknownAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
{
UnknownVisitor visitor (nodep);
} // Destruct before checking
UINFO(2, __FUNCTION__ << ": " << endl);
{ UnknownVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("unknown", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -43,35 +43,32 @@
class UnrollVisitor : public AstNVisitor {
private:
// STATE
AstVar* m_forVarp; // Iterator variable
AstVarScope* m_forVscp; // Iterator variable scope (NULL for generate pass)
AstConst* m_varValuep; // Current value of loop
AstNode* m_ignoreIncp; // Increment node to ignore
bool m_varModeCheck; // Just checking RHS assignments
bool m_varModeReplace; // Replacing varrefs
bool m_varAssignHit; // Assign var hit
bool m_generate; // Expand single generate For loop
string m_beginName; // What name to give begin iterations
VDouble0 m_statLoops; // Statistic tracking
VDouble0 m_statIters; // Statistic tracking
AstVar* m_forVarp; // Iterator variable
AstVarScope* m_forVscp; // Iterator variable scope (NULL for generate pass)
AstConst* m_varValuep; // Current value of loop
AstNode* m_ignoreIncp; // Increment node to ignore
bool m_varModeCheck; // Just checking RHS assignments
bool m_varModeReplace; // Replacing varrefs
bool m_varAssignHit; // Assign var hit
bool m_generate; // Expand single generate For loop
string m_beginName; // What name to give begin iterations
VDouble0 m_statLoops; // Statistic tracking
VDouble0 m_statIters; // Statistic tracking
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
bool cantUnroll(AstNode* nodep, const char* reason) {
if (m_generate) {
nodep->v3error("Unsupported: Can't unroll generate for; "<<reason);
}
UINFO(3," Can't Unroll: "<<reason<<" :"<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout, "-cant-");
V3Stats::addStatSum(string("Unrolling gave up, ")+reason, 1);
if (m_generate) nodep->v3error("Unsupported: Can't unroll generate for; " << reason);
UINFO(3, " Can't Unroll: " << reason << " :" << nodep << endl);
// if (debug() >= 9) nodep->dumpTree(cout, "-cant-");
V3Stats::addStatSum(string("Unrolling gave up, ") + reason, 1);
return false;
}
int unrollCount() {
return m_generate ? v3Global.opt.unrollCount()*16
: v3Global.opt.unrollCount();
return m_generate ? v3Global.opt.unrollCount() * 16 : v3Global.opt.unrollCount();
}
bool bodySizeOverRecurse(AstNode* nodep, int& bodySize, int bodyLimit) {
@ -88,24 +85,27 @@ private:
return bodySizeOverRecurse(nodep->nextp(), bodySize, bodyLimit);
}
bool forUnrollCheck(AstNode* nodep,
AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp)
AstNode* precondsp, AstNode* condp,
AstNode* incp, // Maybe under nodep or in bodysp
AstNode* bodysp) {
bool
forUnrollCheck(AstNode* nodep,
AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp)
AstNode* precondsp, AstNode* condp,
AstNode* incp, // Maybe under nodep or in bodysp
AstNode* bodysp) {
// To keep the IF levels low, we return as each test fails.
UINFO(4, " FOR Check "<<nodep<<endl);
if (initp) UINFO(6, " Init "<<initp<<endl);
if (precondsp) UINFO(6, " Pcon "<<precondsp<<endl);
if (condp) UINFO(6, " Cond "<<condp<<endl);
if (incp) UINFO(6, " Inc "<<incp<<endl);
UINFO(4, " FOR Check " << nodep << endl);
if (initp) UINFO(6, " Init " << initp << endl);
if (precondsp) UINFO(6, " Pcon " << precondsp << endl);
if (condp) UINFO(6, " Cond " << condp << endl);
if (incp) UINFO(6, " Inc " << incp << endl);
// Initial value check
AstAssign* initAssp = VN_CAST(initp, Assign);
if (!initAssp) return cantUnroll(nodep, "no initial assignment");
UASSERT_OBJ(!(initp->nextp() && initp->nextp()!=nodep), nodep,
UASSERT_OBJ(!(initp->nextp() && initp->nextp() != nodep), nodep,
"initial assignment shouldn't be a list");
if (!VN_IS(initAssp->lhsp(), VarRef)) return cantUnroll(nodep, "no initial assignment to simple variable");
if (!VN_IS(initAssp->lhsp(), VarRef)) {
return cantUnroll(nodep, "no initial assignment to simple variable");
}
//
// Condition check
UASSERT_OBJ(!condp->nextp(), nodep, "conditional shouldn't be a list");
@ -118,9 +118,9 @@ private:
m_forVarp = VN_CAST(initAssp->lhsp(), VarRef)->varp();
m_forVscp = VN_CAST(initAssp->lhsp(), VarRef)->varScopep();
if (VN_IS(nodep, GenFor) && !m_forVarp->isGenVar()) {
nodep->v3error("Non-genvar used in generate for: "<<m_forVarp->prettyNameQ()<<endl);
}
else if (!VN_IS(nodep, GenFor) && m_forVarp->isGenVar()) {
nodep->v3error("Non-genvar used in generate for: " //
<< m_forVarp->prettyNameQ() << endl);
} else if (!VN_IS(nodep, GenFor) && m_forVarp->isGenVar()) {
nodep->v3error("Genvar not legal in non-generate for (IEEE 1800-2017 27.4): "
<< m_forVarp->prettyNameQ() << endl
<< nodep->warnMore()
@ -148,28 +148,33 @@ private:
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
//
if (m_forVscp) { UINFO(8, " Loop Variable: "<<m_forVscp<<endl); }
else { UINFO(8, " Loop Variable: "<<m_forVarp<<endl); }
if (debug()>=9) nodep->dumpTree(cout, "- for: ");
if (m_forVscp) {
UINFO(8, " Loop Variable: " << m_forVscp << endl);
} else {
UINFO(8, " Loop Variable: " << m_forVarp << endl);
}
if (debug() >= 9) nodep->dumpTree(cout, "- for: ");
if (!m_generate) {
AstAssign *incpAssign = VN_CAST(incp, Assign);
if (!canSimulate(incpAssign->rhsp())) return cantUnroll(incp, "Unable to simulate increment");
AstAssign* incpAssign = VN_CAST(incp, Assign);
if (!canSimulate(incpAssign->rhsp())) {
return cantUnroll(incp, "Unable to simulate increment");
}
if (!canSimulate(condp)) return cantUnroll(condp, "Unable to simulate condition");
// Check whether to we actually want to try and unroll.
int loops;
if (!countLoops(initAssp, condp, incp, unrollCount(), loops))
if (!countLoops(initAssp, condp, incp, unrollCount(), loops)) {
return cantUnroll(nodep, "Unable to simulate loop");
}
// Less than 10 statements in the body?
int bodySize = 0;
int bodyLimit = v3Global.opt.unrollStmts();
if (loops>0) bodyLimit = v3Global.opt.unrollStmts() / loops;
if (bodySizeOverRecurse(precondsp, bodySize/*ref*/, bodyLimit)
|| bodySizeOverRecurse(bodysp, bodySize/*ref*/, bodyLimit)
|| bodySizeOverRecurse(incp, bodySize/*ref*/, bodyLimit)) {
if (loops > 0) bodyLimit = v3Global.opt.unrollStmts() / loops;
if (bodySizeOverRecurse(precondsp, bodySize /*ref*/, bodyLimit)
|| bodySizeOverRecurse(bodysp, bodySize /*ref*/, bodyLimit)
|| bodySizeOverRecurse(incp, bodySize /*ref*/, bodyLimit)) {
return cantUnroll(nodep, "too many statements");
}
}
@ -182,7 +187,7 @@ private:
return true;
}
bool canSimulate(AstNode *nodep) {
bool canSimulate(AstNode* nodep) {
SimulateVisitor simvis;
AstNode* clonep = nodep->cloneTree(true);
simvis.mainCheckTree(clonep);
@ -190,8 +195,8 @@ private:
return simvis.optimizable();
}
bool simulateTree(AstNode *nodep, const V3Number *loopValue,
AstNode *dtypep, V3Number &outNum) {
bool simulateTree(AstNode* nodep, const V3Number* loopValue, AstNode* dtypep,
V3Number& outNum) {
AstNode* clonep = nodep->cloneTree(true);
UASSERT_OBJ(clonep, nodep, "Failed to clone tree");
if (loopValue) {
@ -210,7 +215,7 @@ private:
simvis.mainParamEmulate(clonep);
if (!simvis.optimizable()) {
UINFO(3, "Unable to simulate" << endl);
if (debug()>=9) nodep->dumpTree(cout, "- _simtree: ");
if (debug() >= 9) nodep->dumpTree(cout, "- _simtree: ");
VL_DO_DANGLING(clonep->deleteTree(), clonep);
return false;
}
@ -223,7 +228,7 @@ private:
}
// Patch up datatype
if (dtypep) {
AstConst new_con (clonep->fileline(), *res);
AstConst new_con(clonep->fileline(), *res);
new_con.dtypeFrom(dtypep);
outNum = new_con.num();
VL_DO_DANGLING(clonep->deleteTree(), clonep);
@ -234,20 +239,18 @@ private:
return true;
}
bool countLoops(AstAssign *initp, AstNode *condp, AstNode *incp, int max, int &outLoopsr) {
bool countLoops(AstAssign* initp, AstNode* condp, AstNode* incp, int max, int& outLoopsr) {
outLoopsr = 0;
V3Number loopValue = V3Number(initp);
if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) {
if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) { //
return false;
}
while (true) {
V3Number res = V3Number(initp);
if (!simulateTree(condp, &loopValue, NULL, res)) {
if (!simulateTree(condp, &loopValue, NULL, res)) { //
return false;
}
if (!res.isEqOne()) {
break;
}
if (!res.isEqOne()) break;
outLoopsr++;
@ -258,21 +261,16 @@ private:
return false;
}
loopValue.opAssign(newLoopValue);
if (outLoopsr > max) {
return false;
}
if (outLoopsr > max) return false;
}
return true;
}
bool forUnroller(AstNode* nodep,
AstAssign* initp,
AstNode* condp,
AstNode* precondsp,
bool forUnroller(AstNode* nodep, AstAssign* initp, AstNode* condp, AstNode* precondsp,
AstNode* incp, AstNode* bodysp) {
UINFO(9, "forUnroller "<<nodep<<endl);
UINFO(9, "forUnroller " << nodep << endl);
V3Number loopValue = V3Number(nodep);
if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) {
if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) { //
return false;
}
AstNode* stmtsp = NULL;
@ -301,7 +299,7 @@ private:
if (stmtsp) {
int times = 0;
while (true) {
UINFO(8," Looping "<<loopValue<<endl);
UINFO(8, " Looping " << loopValue << endl);
V3Number res = V3Number(nodep);
if (!simulateTree(condp, &loopValue, NULL, res)) {
nodep->v3error("Loop unrolling failed.");
@ -309,8 +307,7 @@ private:
}
if (!res.isEqOne()) {
break; // Done with the loop
}
else {
} else {
// Replace iterator values with constant.
AstNode* oneloopp = stmtsp->cloneTree(true);
@ -318,8 +315,8 @@ private:
// Iteration requires a back, so put under temporary node
if (oneloopp) {
AstBegin* tempp = new AstBegin(oneloopp->fileline(),
"[EditWrapper]", oneloopp);
AstBegin* tempp
= new AstBegin(oneloopp->fileline(), "[EditWrapper]", oneloopp);
m_varModeReplace = true;
iterateAndNextNull(tempp->stmtsp());
m_varModeReplace = false;
@ -332,19 +329,23 @@ private:
oneloopp = new AstBegin(oneloopp->fileline(), nname, oneloopp, true);
}
VL_DO_CLEAR(pushDeletep(m_varValuep), m_varValuep = NULL);
if (newbodysp) newbodysp->addNext(oneloopp);
else newbodysp = oneloopp;
if (newbodysp) {
newbodysp->addNext(oneloopp);
} else {
newbodysp = oneloopp;
}
++m_statIters;
if (++times > unrollCount()*3) {
nodep->v3error("Loop unrolling took too long;"
" probably this is an infinite loop, or set --unroll-count above "
<<unrollCount());
if (++times > unrollCount() * 3) {
nodep->v3error(
"Loop unrolling took too long;"
" probably this is an infinite loop, or set --unroll-count above "
<< unrollCount());
break;
}
// loopValue += valInc
AstAssign *incpass = VN_CAST(incp, Assign);
AstAssign* incpass = VN_CAST(incp, Assign);
V3Number newLoopValue = V3Number(nodep);
if (!simulateTree(incpass->rhsp(), &loopValue, incpass, newLoopValue)) {
nodep->v3error("Loop unrolling failed");
@ -359,13 +360,16 @@ private:
initp = NULL;
}
// Replace the FOR()
if (newbodysp) nodep->replaceWith(newbodysp);
else nodep->unlinkFrBack();
if (newbodysp) {
nodep->replaceWith(newbodysp);
} else {
nodep->unlinkFrBack();
}
if (bodysp) { VL_DO_DANGLING(pushDeletep(bodysp), bodysp); }
if (precondsp) { VL_DO_DANGLING(pushDeletep(precondsp), precondsp); }
if (initp) { VL_DO_DANGLING(pushDeletep(initp), initp); }
if (incp && !incp->backp()) { VL_DO_DANGLING(pushDeletep(incp), incp); }
if (debug()>=9 && newbodysp) newbodysp->dumpTree(cout, "- _new: ");
if (debug() >= 9 && newbodysp) newbodysp->dumpTree(cout, "- _new: ");
return true;
}
@ -374,7 +378,9 @@ private:
if (m_varModeCheck || m_varModeReplace) {
} else {
// Constify before unroll call, as it may change what is underneath.
if (nodep->precondsp()) V3Const::constifyEdit(nodep->precondsp()); // precondsp may change
if (nodep->precondsp()) {
V3Const::constifyEdit(nodep->precondsp()); // precondsp may change
}
if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change
// Grab initial value
AstNode* initp = NULL; // Should be statement before the while.
@ -385,16 +391,17 @@ private:
AstNode* incp = NULL; // Should be last statement
if (nodep->incsp()) V3Const::constifyEdit(nodep->incsp());
// cppcheck-suppress duplicateCondition
if (nodep->incsp()) incp = nodep->incsp();
else {
if (nodep->incsp()) {
incp = nodep->incsp();
} else {
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
if (incp) VL_DO_DANGLING(V3Const::constifyEdit(incp), incp);
// Again, as may have changed
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
if (incp) { VL_DO_DANGLING(V3Const::constifyEdit(incp), incp); }
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed
}
// And check it
if (forUnrollCheck(nodep, initp,
nodep->precondsp(), nodep->condp(),
incp, nodep->bodysp())) {
if (forUnrollCheck(nodep, initp, nodep->precondsp(), nodep->condp(), incp,
nodep->bodysp())) {
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement
}
}
@ -418,9 +425,8 @@ private:
// condition, but they'll become while's which can be
// deleted by V3Const.
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
} else if (forUnrollCheck(nodep, nodep->initsp(),
NULL, nodep->condp(),
nodep->incsp(), nodep->bodysp())) {
} else if (forUnrollCheck(nodep, nodep->initsp(), NULL, nodep->condp(), nodep->incsp(),
nodep->bodysp())) {
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement
} else {
nodep->v3error("For loop doesn't have genvar index, or is malformed");
@ -436,17 +442,13 @@ private:
}
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
if (m_varModeCheck
&& nodep->varp() == m_forVarp
&& nodep->varScopep() == m_forVscp
if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp
&& nodep->lvalue()) {
UINFO(8," Itervar assigned to: "<<nodep<<endl);
UINFO(8, " Itervar assigned to: " << nodep << endl);
m_varAssignHit = true;
}
if (m_varModeReplace
&& nodep->varp() == m_forVarp
&& nodep->varScopep() == m_forVscp
if (m_varModeReplace && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp
&& !nodep->lvalue()) {
AstNode* newconstp = m_varValuep->cloneTree(false);
nodep->replaceWith(newconstp);
@ -492,20 +494,19 @@ public:
//######################################################################
// Unroll class functions
UnrollStateful::UnrollStateful() : m_unrollerp(new UnrollVisitor) { }
UnrollStateful::UnrollStateful()
: m_unrollerp(new UnrollVisitor) {}
UnrollStateful::~UnrollStateful() { delete m_unrollerp; }
void UnrollStateful::unrollGen(AstNodeFor* nodep, const string& beginName) {
UINFO(5,__FUNCTION__<<": "<<endl);
UINFO(5, __FUNCTION__ << ": " << endl);
m_unrollerp->process(nodep, true, beginName);
}
void UnrollStateful::unrollAll(AstNetlist* nodep) {
m_unrollerp->process(nodep, false, "");
}
void UnrollStateful::unrollAll(AstNetlist* nodep) { m_unrollerp->process(nodep, false, ""); }
void V3Unroll::unrollAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
UINFO(2, __FUNCTION__ << ": " << endl);
{
UnrollStateful unroller;
unroller.unrollAll(nodep);

File diff suppressed because it is too large Load Diff

View File

@ -120,13 +120,15 @@ private:
nodep->replaceWith(newp);
AstNode* oldp = nodep;
nodep = newp;
// if (debug()>4) oldp->dumpTree(cout, " fixConstSize_old: ");
// if (debug()>4) newp->dumpTree(cout, " _new: ");
// if (debug() > 4) oldp->dumpTree(cout, " fixConstSize_old: ");
// if (debug() > 4) newp->dumpTree(cout, " _new: ");
VL_DO_DANGLING(pushDeletep(oldp), oldp);
}
editDType(nodep);
}
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { visitIterateNodeDType(nodep); }
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { //
visitIterateNodeDType(nodep);
}
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return; // Process once
visitIterateNodeDType(nodep);

View File

@ -65,13 +65,16 @@ private:
AstNodeDType* m_errp; // Node that was found, for error reporting if not known type
AstNodeDType* m_dtypep; // Data type for the 'from' slice
VNumRange m_fromRange; // Numeric range bounds for the 'from' slice
FromData(AstNodeDType* errp, AstNodeDType* dtypep, const VNumRange& fromRange)
{ m_errp = errp; m_dtypep = dtypep; m_fromRange = fromRange; }
FromData(AstNodeDType* errp, AstNodeDType* dtypep, const VNumRange& fromRange) {
m_errp = errp;
m_dtypep = dtypep;
m_fromRange = fromRange;
}
~FromData() {}
};
FromData fromDataForArray(AstNode* nodep, AstNode* basefromp) {
// What is the data type and information for this SEL-ish's from()?
UINFO(9," fromData start ddtypep = "<<basefromp<<endl);
UINFO(9, " fromData start ddtypep = " << basefromp << endl);
VNumRange fromRange; // constructs to isRanged(false)
while (basefromp) {
if (VN_IS(basefromp, AttrOf)) {
@ -83,33 +86,29 @@ private:
UASSERT_OBJ(basefromp && basefromp->dtypep(), nodep, "Select with no from dtype");
AstNodeDType* ddtypep = basefromp->dtypep()->skipRefp();
AstNodeDType* errp = ddtypep;
UINFO(9," fromData.ddtypep = "<<ddtypep<<endl);
UINFO(9, " fromData.ddtypep = " << ddtypep << endl);
if (const AstNodeArrayDType* adtypep = VN_CAST(ddtypep, NodeArrayDType)) {
fromRange = adtypep->declRange();
}
else if (VN_IS(ddtypep, AssocArrayDType)) {
}
else if (VN_IS(ddtypep, DynArrayDType)) {
}
else if (VN_IS(ddtypep, QueueDType)) {
}
else if (const AstNodeUOrStructDType* adtypep = VN_CAST(ddtypep, NodeUOrStructDType)) {
} else if (VN_IS(ddtypep, AssocArrayDType)) {
} else if (VN_IS(ddtypep, DynArrayDType)) {
} else if (VN_IS(ddtypep, QueueDType)) {
} else if (const AstNodeUOrStructDType* adtypep = VN_CAST(ddtypep, NodeUOrStructDType)) {
fromRange = adtypep->declRange();
}
else if (AstBasicDType* adtypep = VN_CAST(ddtypep, BasicDType)) {
} else if (AstBasicDType* adtypep = VN_CAST(ddtypep, BasicDType)) {
if (adtypep->isString() && VN_IS(nodep, SelBit)) {
} else if (adtypep->isRanged()) {
UASSERT_OBJ(!(adtypep->rangep()
&& (!VN_IS(adtypep->rangep()->msbp(), Const)
|| !VN_IS(adtypep->rangep()->lsbp(), Const))),
nodep, "Non-constant variable range; errored earlier"); // in constifyParam(bfdtypep)
UASSERT_OBJ(
!(adtypep->rangep()
&& (!VN_IS(adtypep->rangep()->msbp(), Const)
|| !VN_IS(adtypep->rangep()->lsbp(), Const))),
nodep,
"Non-constant variable range; errored earlier"); // in constifyParam(bfdtypep)
fromRange = adtypep->declRange();
} else {
nodep->v3error("Illegal bit or array select; type does not have a bit range, or "
<< "bad dimension: data type is " << errp->prettyDTypeNameQ());
}
}
else {
} else {
nodep->v3error("Illegal bit or array select; type already selected, or bad dimension: "
<< "data type is " << errp->prettyDTypeNameQ());
}
@ -123,7 +122,7 @@ private:
return lhsp;
} else if (VN_IS(lhsp, Const)) {
// Optional vs just making add/sub below, but saves constification some work
V3Number num (lhsp, lhsp->width());
V3Number num(lhsp, lhsp->width());
num.opSub(VN_CAST(lhsp, Const)->num(), V3Number(lhsp, 32, rhs));
num.isSigned(lhsp->isSigned());
AstNode* newp = new AstConst(lhsp->fileline(), num);
@ -135,8 +134,9 @@ private:
newp->dtypeFrom(lhsp);
return newp;
} else { // rhs < 0;
AstNode* newp = new AstAdd(lhsp->fileline(), lhsp,
new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs));
AstNode* newp
= new AstAdd(lhsp->fileline(), lhsp,
new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs));
// We must make sure sub gets sign of original value, not from the constant
newp->dtypeFrom(lhsp);
return newp;
@ -145,9 +145,8 @@ private:
AstNode* newSubNeg(vlsint32_t lhs, AstNode* rhsp) {
// Return lhs-rhs
// We must make sure sub gets sign of original value
AstNode* newp = new AstSub(rhsp->fileline(),
new AstConst(rhsp->fileline(), AstConst::Unsized32(), lhs),
rhsp);
AstNode* newp = new AstSub(
rhsp->fileline(), new AstConst(rhsp->fileline(), AstConst::Unsized32(), lhs), rhsp);
newp->dtypeFrom(rhsp); // Important as AstSub default is lhs's sign
return newp;
}
@ -176,13 +175,13 @@ private:
AstNodeDType* sliceDType(AstPackArrayDType* nodep, int msb, int lsb) {
// Return slice needed for msb/lsb, either as original dtype or a new slice dtype
if (nodep->declRange().elements() == (msb-lsb+1) // Extracting whole of original array
if (nodep->declRange().elements() == (msb - lsb + 1) // Extracting whole of original array
&& nodep->declRange().lo() == lsb) {
return nodep;
} else {
// Need a slice data type, which is an array of the extracted
// type, but with (presumably) different size
VNumRange newRange (msb, lsb, nodep->declRange().littleEndian());
VNumRange newRange(msb, lsb, nodep->declRange().littleEndian());
AstNodeDType* vardtypep
= new AstPackArrayDType(nodep->fileline(),
nodep->subDTypep(), // Need to strip off array reference
@ -198,85 +197,78 @@ private:
virtual void visit(AstSelBit* nodep) VL_OVERRIDE {
// Select of a non-width specified part of an array, i.e. "array[2]"
// This select style has a lsb and msb (no user specified width)
UINFO(6,"SELBIT "<<nodep<<endl);
if (debug()>=9) nodep->backp()->dumpTree(cout, "--SELBT0: ");
UINFO(6, "SELBIT " << nodep << endl);
if (debug() >= 9) nodep->backp()->dumpTree(cout, "--SELBT0: ");
// lhsp/rhsp do not need to be constant
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); // bit we're extracting
if (debug()>=9) nodep->dumpTree(cout, "--SELBT2: ");
if (debug() >= 9) nodep->dumpTree(cout, "--SELBT2: ");
FromData fromdata = fromDataForArray(nodep, fromp);
AstNodeDType* ddtypep = fromdata.m_dtypep;
VNumRange fromRange = fromdata.m_fromRange;
UINFO(6," ddtypep "<<ddtypep<<endl);
UINFO(6, " ddtypep " << ddtypep << endl);
if (AstUnpackArrayDType* adtypep = VN_CAST(ddtypep, UnpackArrayDType)) {
// SELBIT(array, index) -> ARRAYSEL(array, index)
AstNode* subp = rhsp;
if (fromRange.lo()!=0 || fromRange.hi()<0) {
if (fromRange.lo() != 0 || fromRange.hi() < 0) {
subp = newSubNeg(subp, fromRange.lo());
}
AstArraySel* newp = new AstArraySel(nodep->fileline(),
fromp, subp);
AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, subp);
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {
// SELBIT(array, index) -> SEL(array, index*width-of-subindex, width-of-subindex)
AstNode* subp = rhsp;
if (fromRange.lo()!=0 || fromRange.hi()<0) {
if (fromRange.lo() != 0 || fromRange.hi() < 0) {
if (fromRange.littleEndian()) {
subp = newSubNeg(fromRange.hi(), subp);
} else {
subp = newSubNeg(subp, fromRange.lo());
}
}
UASSERT_OBJ(!(!fromRange.elements()
|| (adtypep->width() % fromRange.elements())!=0), adtypep,
"Array extraction with width miscomputed "
<<adtypep->width()<<"/"<<fromRange.elements());
UASSERT_OBJ(!(!fromRange.elements() || (adtypep->width() % fromRange.elements()) != 0),
adtypep,
"Array extraction with width miscomputed " << adtypep->width() << "/"
<< fromRange.elements());
int elwidth = adtypep->width() / fromRange.elements();
AstSel* newp
= new AstSel(nodep->fileline(),
fromp,
new AstMul(nodep->fileline(),
new AstConst(nodep->fileline(),
AstConst::Unsized32(), elwidth),
subp),
new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth));
AstSel* newp = new AstSel(
nodep->fileline(), fromp,
new AstMul(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth), subp),
new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth));
newp->declRange(fromRange);
newp->declElWidth(elwidth);
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else if (AstAssocArrayDType* adtypep = VN_CAST(ddtypep, AssocArrayDType)) {
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (AstAssocArrayDType* adtypep = VN_CAST(ddtypep, AssocArrayDType)) {
// SELBIT(array, index) -> ASSOCSEL(array, index)
AstNode* subp = rhsp;
AstAssocSel* newp = new AstAssocSel(nodep->fileline(),
fromp, subp);
AstAssocSel* newp = new AstAssocSel(nodep->fileline(), fromp, subp);
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else if (AstDynArrayDType* adtypep = VN_CAST(ddtypep, DynArrayDType)) {
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (AstDynArrayDType* adtypep = VN_CAST(ddtypep, DynArrayDType)) {
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
AstNode* subp = rhsp;
AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(),
fromp, "at", subp);
AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(), fromp, "at", subp);
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
if (debug()>=9) newp->dumpTree(cout, "--SELBTq: ");
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else if (AstQueueDType* adtypep = VN_CAST(ddtypep, QueueDType)) {
if (debug() >= 9) newp->dumpTree(cout, "--SELBTq: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (AstQueueDType* adtypep = VN_CAST(ddtypep, QueueDType)) {
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
AstNode* subp = rhsp;
AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(),
fromp, "at", subp);
AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(), fromp, "at", subp);
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
if (debug()>=9) newp->dumpTree(cout, "--SELBTq: ");
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) {
if (debug() >= 9) newp->dumpTree(cout, "--SELBTq: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) {
// SELBIT(string, index) -> GETC(string, index)
AstNodeVarRef* varrefp = VN_CAST(fromp, NodeVarRef);
if (!varrefp) nodep->v3error("Unsupported: String array operation on non-variable");
@ -291,29 +283,25 @@ private:
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (VN_IS(ddtypep, BasicDType)) {
// SELBIT(range, index) -> SEL(array, index, 1)
AstSel* newp = new AstSel(nodep->fileline(),
fromp,
newSubLsbOf(rhsp, fromRange),
AstSel* newp = new AstSel(nodep->fileline(), fromp, newSubLsbOf(rhsp, fromRange),
// Unsized so width from user
new AstConst(nodep->fileline(), AstConst::Unsized32(), 1));
newp->declRange(fromRange);
UINFO(6," new "<<newp<<endl);
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else if (VN_IS(ddtypep, NodeUOrStructDType)) { // A bit from the packed struct
UINFO(6, " new " << newp << endl);
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (VN_IS(ddtypep, NodeUOrStructDType)) { // A bit from the packed struct
// SELBIT(range, index) -> SEL(array, index, 1)
AstSel* newp = new AstSel(nodep->fileline(),
fromp,
newSubLsbOf(rhsp, fromRange),
AstSel* newp = new AstSel(nodep->fileline(), fromp, newSubLsbOf(rhsp, fromRange),
// Unsized so width from user
new AstConst(nodep->fileline(), AstConst::Unsized32(), 1));
newp->declRange(fromRange);
UINFO(6," new "<<newp<<endl);
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else { // NULL=bad extract, or unknown node type
UINFO(6, " new " << newp << endl);
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else { // NULL=bad extract, or unknown node type
nodep->v3error("Illegal bit or array select; type already selected, or bad dimension: "
<< "data type is" << fromdata.m_errp->prettyDTypeNameQ());
// How to recover? We'll strip a dimension.
@ -326,20 +314,22 @@ private:
// Select of a range specified part of an array, i.e. "array[2:3]"
// SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb)
// This select style has a (msb or lsb) and width
UINFO(6,"SELEXTRACT "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout, "--SELEX0: ");
UINFO(6, "SELEXTRACT " << nodep << endl);
// if (debug() >= 9) nodep->dumpTree(cout, "--SELEX0: ");
// Below 2 lines may change nodep->widthp()
V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
//if (debug()>=9) nodep->dumpTree(cout, "--SELEX3: ");
checkConstantOrReplace(nodep->lsbp(), "First value of [a:b] isn't a constant, maybe you want +: or -:");
checkConstantOrReplace(nodep->msbp(), "Second value of [a:b] isn't a constant, maybe you want +: or -:");
// if (debug() >= 9) nodep->dumpTree(cout, "--SELEX3: ");
checkConstantOrReplace(nodep->lsbp(),
"First value of [a:b] isn't a constant, maybe you want +: or -:");
checkConstantOrReplace(nodep->msbp(),
"Second value of [a:b] isn't a constant, maybe you want +: or -:");
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
AstNode* lsbp = nodep->thsp()->unlinkFrBack();
vlsint32_t msb = VN_CAST(msbp, Const)->toSInt();
vlsint32_t lsb = VN_CAST(lsbp, Const)->toSInt();
vlsint32_t elem = (msb>lsb) ? (msb-lsb+1) : (lsb-msb+1);
vlsint32_t elem = (msb > lsb) ? (msb - lsb + 1) : (lsb - msb + 1);
FromData fromdata = fromDataForArray(nodep, fromp);
AstNodeDType* ddtypep = fromdata.m_dtypep;
VNumRange fromRange = fromdata.m_fromRange;
@ -347,90 +337,101 @@ private:
// Slice extraction
if (fromRange.elements() == elem
&& fromRange.lo() == lsb) { // Extracting whole of original array
nodep->replaceWith(fromp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
nodep->replaceWith(fromp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (fromRange.elements() == 1) { // Extracting single element
AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, lsbp);
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else { // Slice
AstSliceSel* newp = new AstSliceSel(nodep->fileline(), fromp,
VNumRange(VNumRange::LeftRight(),
msb, lsb));
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
VNumRange(VNumRange::LeftRight(), msb, lsb));
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
}
else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {
} else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {
// SELEXTRACT(array, msb, lsb) -> SEL(array,
// lsb*width-of-subindex, width-of-subindex*(msb-lsb))
UASSERT_OBJ(!(!fromRange.elements()
|| (adtypep->width() % fromRange.elements())!=0), adtypep,
"Array extraction with width miscomputed "
<<adtypep->width()<<"/"<<fromRange.elements());
UASSERT_OBJ(!(!fromRange.elements() || (adtypep->width() % fromRange.elements()) != 0),
adtypep,
"Array extraction with width miscomputed " << adtypep->width() << "/"
<< fromRange.elements());
if (fromRange.littleEndian()) {
// Below code assumes big bit endian; just works out if we swap
int x = msb; msb = lsb; lsb = x;
int x = msb;
msb = lsb;
lsb = x;
}
if (lsb > msb) {
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["
<<lsb<<":"<<msb<<"]");
int x = msb; msb = lsb; lsb = x;
nodep->v3error("["
<< msb << ":" << lsb
<< "] Range extract has backward bit ordering, perhaps you wanted ["
<< lsb << ":" << msb << "]");
int x = msb;
msb = lsb;
lsb = x;
}
int elwidth = adtypep->width() / fromRange.elements();
AstSel* newp = new AstSel(nodep->fileline(),
fromp,
new AstMul(nodep->fileline(), newSubLsbOf(lsbp, fromRange),
new AstConst(nodep->fileline(),
AstConst::Unsized32(), elwidth)),
new AstConst(nodep->fileline(),
AstConst::Unsized32(), (msb-lsb+1)*elwidth));
AstSel* newp = new AstSel(
nodep->fileline(), fromp,
new AstMul(nodep->fileline(), newSubLsbOf(lsbp, fromRange),
new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth)),
new AstConst(nodep->fileline(), AstConst::Unsized32(), (msb - lsb + 1) * elwidth));
newp->declRange(fromRange);
newp->declElWidth(elwidth);
newp->dtypeFrom(sliceDType(adtypep, msb, lsb));
//if (debug()>=9) newp->dumpTree(cout, "--EXTBTn: ");
// if (debug() >= 9) newp->dumpTree(cout, "--EXTBTn: ");
UASSERT_OBJ(newp->widthMin() == newp->widthConst(), nodep, "Width mismatch");
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else if (VN_IS(ddtypep, BasicDType)) {
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (VN_IS(ddtypep, BasicDType)) {
if (fromRange.littleEndian()) {
// Below code assumes big bit endian; just works out if we swap
int x = msb; msb = lsb; lsb = x;
int x = msb;
msb = lsb;
lsb = x;
}
if (lsb > msb) {
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["
<<lsb<<":"<<msb<<"]");
int x = msb; msb = lsb; lsb = x;
nodep->v3error("["
<< msb << ":" << lsb
<< "] Range extract has backward bit ordering, perhaps you wanted ["
<< lsb << ":" << msb << "]");
int x = msb;
msb = lsb;
lsb = x;
}
AstNode* widthp = new AstConst(msbp->fileline(),
AstConst::Unsized32(), // Unsized so width from user
msb +1-lsb);
AstSel* newp = new AstSel(nodep->fileline(),
fromp,
newSubLsbOf(lsbp, fromRange),
widthp);
msb + 1 - lsb);
AstSel* newp
= new AstSel(nodep->fileline(), fromp, newSubLsbOf(lsbp, fromRange), widthp);
newp->declRange(fromRange);
UINFO(6," new "<<newp<<endl);
//if (debug()>=9) newp->dumpTree(cout, "--SELEXnew: ");
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else if (VN_IS(ddtypep, NodeUOrStructDType)) {
UINFO(6, " new " << newp << endl);
// if (debug() >= 9) newp->dumpTree(cout, "--SELEXnew: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else if (VN_IS(ddtypep, NodeUOrStructDType)) {
// Classes aren't little endian
if (lsb > msb) {
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["
<<lsb<<":"<<msb<<"]");
int x = msb; msb = lsb; lsb = x;
nodep->v3error("["
<< msb << ":" << lsb
<< "] Range extract has backward bit ordering, perhaps you wanted ["
<< lsb << ":" << msb << "]");
int x = msb;
msb = lsb;
lsb = x;
}
AstNode* widthp = new AstConst(msbp->fileline(),
AstConst::Unsized32(), // Unsized so width from user
msb +1-lsb);
AstSel* newp = new AstSel(nodep->fileline(),
fromp,
newSubLsbOf(lsbp, fromRange),
widthp);
msb + 1 - lsb);
AstSel* newp
= new AstSel(nodep->fileline(), fromp, newSubLsbOf(lsbp, fromRange), widthp);
newp->declRange(fromRange);
UINFO(6," new "<<newp<<endl);
//if (debug()>=9) newp->dumpTree(cout, "--SELEXnew: ");
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else { // NULL=bad extract, or unknown node type
UINFO(6, " new " << newp << endl);
// if (debug() >= 9) newp->dumpTree(cout, "--SELEXnew: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else { // NULL=bad extract, or unknown node type
nodep->v3error("Illegal range select; type already selected, or bad dimension: "
<< "data type is " << fromdata.m_errp->prettyDTypeNameQ());
UINFO(1, " Related ddtype: " << ddtypep << endl);
@ -447,38 +448,40 @@ private:
void replaceSelPlusMinus(AstNodePreSel* nodep) {
// Select of a range specified with +: or -:, i.e. "array[2+:3], [2-:3]"
// This select style has a lsb and width
UINFO(6,"SELPLUS/MINUS "<<nodep<<endl);
UINFO(6, "SELPLUS/MINUS " << nodep << endl);
// Below 2 lines may change nodep->widthp()
if (debug()>=9) nodep->dumpTree(cout, "--SELPM0: ");
if (debug() >= 9) nodep->dumpTree(cout, "--SELPM0: ");
V3Const::constifyParamsEdit(nodep->thsp()); // May relink pointed to node
checkConstantOrReplace(nodep->thsp(), "Width of :+ or :- bit extract isn't a constant");
if (debug()>=9) nodep->dumpTree(cout, "--SELPM3: ");
if (debug() >= 9) nodep->dumpTree(cout, "--SELPM3: ");
// Now replace it with an AstSel
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* widthp = nodep->thsp()->unlinkFrBack();
int width = VN_CAST(widthp, Const)->toSInt();
if (width > (1<<28)) nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "
<<widthp->prettyName());
if (width<0) nodep->v3error("Width of :+ or :- is < 0: "<<widthp->prettyName());
if (width > (1 << 28)) {
nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "
<< widthp->prettyName());
}
if (width < 0) nodep->v3error("Width of :+ or :- is < 0: " << widthp->prettyName());
FromData fromdata = fromDataForArray(nodep, fromp);
AstNodeDType* ddtypep = fromdata.m_dtypep;
VNumRange fromRange = fromdata.m_fromRange;
if (VN_IS(ddtypep, BasicDType)
|| VN_IS(ddtypep, PackArrayDType)
if (VN_IS(ddtypep, BasicDType) || VN_IS(ddtypep, PackArrayDType)
|| (VN_IS(ddtypep, NodeUOrStructDType)
&& VN_CAST(ddtypep, NodeUOrStructDType)->packedUnsup())) {
int elwidth = 1;
AstNode* newwidthp = widthp;
if (const AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {
elwidth = adtypep->width() / fromRange.elements();
newwidthp = new AstConst(nodep->fileline(), AstConst::Unsized32(), width * elwidth);
newwidthp
= new AstConst(nodep->fileline(), AstConst::Unsized32(), width * elwidth);
}
AstNode* newlsbp = NULL;
if (VN_IS(nodep, SelPlus)) {
if (fromRange.littleEndian()) {
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
newlsbp = newSubNeg((fromRange.hi()-width+1), rhsp);
newlsbp = newSubNeg((fromRange.hi() - width + 1), rhsp);
} else {
// SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
newlsbp = newSubNeg(rhsp, fromRange.lo());
@ -489,22 +492,23 @@ private:
newlsbp = newSubNeg(fromRange.hi(), rhsp);
} else {
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
newlsbp = newSubNeg(rhsp, fromRange.lo()+(width-1));
newlsbp = newSubNeg(rhsp, fromRange.lo() + (width - 1));
}
} else {
nodep->v3fatalSrc("Bad Case");
}
if (elwidth != 1) newlsbp = new AstMul(nodep->fileline(), newlsbp,
new AstConst(nodep->fileline(), elwidth));
AstSel* newp = new AstSel(nodep->fileline(),
fromp, newlsbp, newwidthp);
if (elwidth != 1) {
newlsbp = new AstMul(nodep->fileline(), newlsbp,
new AstConst(nodep->fileline(), elwidth));
}
AstSel* newp = new AstSel(nodep->fileline(), fromp, newlsbp, newwidthp);
newp->declRange(fromRange);
newp->declElWidth(elwidth);
UINFO(6," new "<<newp<<endl);
if (debug()>=9) newp->dumpTree(cout, "--SELNEW: ");
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
else { // NULL=bad extract, or unknown node type
UINFO(6, " new " << newp << endl);
if (debug() >= 9) newp->dumpTree(cout, "--SELNEW: ");
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else { // NULL=bad extract, or unknown node type
nodep->v3error("Illegal +: or -: select; type already selected, or bad dimension: "
<< "data type is " << fromdata.m_errp->prettyDTypeNameQ());
// How to recover? We'll strip a dimension.
@ -516,12 +520,8 @@ private:
if (!rhsp->backp()) { VL_DO_DANGLING(pushDeletep(rhsp), rhsp); }
if (!widthp->backp()) { VL_DO_DANGLING(pushDeletep(widthp), widthp); }
}
virtual void visit(AstSelPlus* nodep) VL_OVERRIDE {
replaceSelPlusMinus(nodep);
}
virtual void visit(AstSelMinus* nodep) VL_OVERRIDE {
replaceSelPlusMinus(nodep);
}
virtual void visit(AstSelPlus* nodep) VL_OVERRIDE { replaceSelPlusMinus(nodep); }
virtual void visit(AstSelMinus* nodep) VL_OVERRIDE { replaceSelPlusMinus(nodep); }
// If adding new visitors, ensure V3Width's visit(TYPE) calls into here
//--------------------
@ -534,9 +534,7 @@ private:
public:
// CONSTRUCTORS
WidthSelVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) {
return iterateSubtreeReturnEdits(nodep);
}
AstNode* mainAcceptEdit(AstNode* nodep) { return iterateSubtreeReturnEdits(nodep); }
virtual ~WidthSelVisitor() {}
};
@ -544,7 +542,7 @@ public:
// Width class functions
AstNode* V3Width::widthSelNoIterEdit(AstNode* nodep) {
UINFO(4,__FUNCTION__<<": "<<nodep<<endl);
UINFO(4, __FUNCTION__ << ": " << nodep << endl);
WidthSelVisitor visitor;
nodep = visitor.mainAcceptEdit(nodep);
return nodep;