diff --git a/src/V3Ast.h b/src/V3Ast.h index e00b6f34f..47b580c50 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2849,7 +2849,6 @@ private: bool m_recursive : 1; // Recursive module bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr int m_level = 0; // 1=top module, 2=cell off top module, ... - int m_varNum = 0; // Incrementing variable number int m_typeNum = 0; // Incrementing implicit type number VLifetime m_lifetime; // Lifetime VTimescale m_timeunit; // Global time unit @@ -2890,7 +2889,6 @@ public: void level(int level) { m_level = level; } int level() const { return m_level; } bool isTop() const { return level() == 1; } - int varNumGetInc() { return ++m_varNum; } int typeNumGetInc() { return ++m_typeNum; } void modPublic(bool flag) { m_modPublic = flag; } bool modPublic() const { return m_modPublic; } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 1a2148fc9..ab2bfc58c 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -30,6 +30,7 @@ #include "V3Width.h" #include "V3Simulate.h" #include "V3Stats.h" +#include "V3UniqueNames.h" #include @@ -601,6 +602,9 @@ private: AstNode* m_scopep = nullptr; // Current scope AstAttrOf* m_attrp = nullptr; // Current attribute VDouble0 m_statBitOpReduction; // Ops reduced in ConstBitOpTreeVisitor + const bool m_globalPass; // ConstVisitor invoked as a global pass + static uint32_t s_globalPassNum; // Counts number of times ConstVisitor invoked as global pass + V3UniqueNames m_concswapNames; // For generating unique temporary variable names // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -1762,14 +1766,16 @@ private: newp = AstNode::addNext(newp, asn2ap); } else { UASSERT_OBJ(m_modp, nodep, "Not under module"); + UASSERT_OBJ(m_globalPass, nodep, + "Should not reach here when not invoked on whole AstNetlist"); // We could create just one temp variable, but we'll get better optimization // if we make one per term. - string name1 = (string("__Vconcswap") + cvtToStr(m_modp->varNumGetInc())); - string name2 = (string("__Vconcswap") + cvtToStr(m_modp->varNumGetInc())); - AstVar* temp1p = new AstVar(sel1p->fileline(), AstVarType::BLOCKTEMP, name1, - VFlagLogicPacked(), msb1 - lsb1 + 1); - AstVar* temp2p = new AstVar(sel2p->fileline(), AstVarType::BLOCKTEMP, name2, - VFlagLogicPacked(), msb2 - lsb2 + 1); + AstVar* const temp1p + = new AstVar(sel1p->fileline(), AstVarType::BLOCKTEMP, + m_concswapNames.get(sel1p), VFlagLogicPacked(), msb1 - lsb1 + 1); + AstVar* const temp2p + = new AstVar(sel2p->fileline(), AstVarType::BLOCKTEMP, + m_concswapNames.get(sel2p), VFlagLogicPacked(), msb2 - lsb2 + 1); m_modp->addStmtp(temp1p); m_modp->addStmtp(temp2p); AstNodeAssign* asn1ap @@ -1931,6 +1937,7 @@ private: VL_RESTORER(m_modp); { m_modp = nodep; + m_concswapNames.reset(); iterateChildren(nodep); } } @@ -3197,7 +3204,9 @@ public: }; // CONSTRUCTORS - explicit ConstVisitor(ProcMode pmode) { + ConstVisitor(ProcMode pmode, bool globalPass) + : m_globalPass{globalPass} + , m_concswapNames{globalPass ? ("__Vconcswap_" + cvtToStr(s_globalPassNum++)) : ""} { // clang-format off switch (pmode) { case PROC_PARAMS: m_doV = true; m_doNConst = true; m_params = true; @@ -3225,6 +3234,8 @@ public: } }; +uint32_t ConstVisitor::s_globalPassNum = 0; + //###################################################################### // Const class functions @@ -3237,7 +3248,7 @@ AstNode* V3Const::constifyParamsEdit(AstNode* nodep) { // Make sure we've sized everything first nodep = V3Width::widthParamsEdit(nodep); - ConstVisitor visitor{ConstVisitor::PROC_PARAMS}; + ConstVisitor visitor{ConstVisitor::PROC_PARAMS, /* globalPass: */ false}; if (AstVar* varp = VN_CAST(nodep, Var)) { // If a var wants to be constified, it's really a param, and // we want the value to be constant. We aren't passed just the @@ -3267,7 +3278,7 @@ AstNode* V3Const::constifyGenerateParamsEdit(AstNode* nodep) { // Make sure we've sized everything first nodep = V3Width::widthGenerateParamsEdit(nodep); - ConstVisitor visitor{ConstVisitor::PROC_GENERATE}; + ConstVisitor visitor{ConstVisitor::PROC_GENERATE, /* globalPass: */ false}; if (AstVar* varp = VN_CAST(nodep, Var)) { // If a var wants to be constified, it's really a param, and // we want the value to be constant. We aren't passed just the @@ -3285,7 +3296,7 @@ void V3Const::constifyAllLint(AstNetlist* nodep) { // Only call from Verilator.cpp, as it uses user#'s UINFO(2, __FUNCTION__ << ": " << endl); { - ConstVisitor visitor{ConstVisitor::PROC_V_WARN}; + ConstVisitor visitor{ConstVisitor::PROC_V_WARN, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); @@ -3294,14 +3305,14 @@ void V3Const::constifyAllLint(AstNetlist* nodep) { void V3Const::constifyCpp(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { - ConstVisitor visitor{ConstVisitor::PROC_CPP}; + ConstVisitor visitor{ConstVisitor::PROC_CPP, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking V3Global::dumpCheckGlobalTree("const_cpp", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); } AstNode* V3Const::constifyEdit(AstNode* nodep) { - ConstVisitor visitor{ConstVisitor::PROC_V_NOWARN}; + ConstVisitor visitor{ConstVisitor::PROC_V_NOWARN, /* globalPass: */ false}; nodep = visitor.mainAcceptEdit(nodep); return nodep; } @@ -3312,7 +3323,7 @@ void V3Const::constifyAllLive(AstNetlist* nodep) { // IE doesn't prune dead statements, as we need to do some usability checks after this UINFO(2, __FUNCTION__ << ": " << endl); { - ConstVisitor visitor{ConstVisitor::PROC_LIVE}; + ConstVisitor visitor{ConstVisitor::PROC_LIVE, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); @@ -3322,14 +3333,14 @@ void V3Const::constifyAll(AstNetlist* nodep) { // Only call from Verilator.cpp, as it uses user#'s UINFO(2, __FUNCTION__ << ": " << endl); { - ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE}; + ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); } AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) { - ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE}; + ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE, /* globalPass: */ false}; nodep = visitor.mainAcceptEdit(nodep); return nodep; } diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index 05110d509..72fc81d6d 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -29,6 +29,7 @@ #include "V3Global.h" #include "V3Depth.h" #include "V3Ast.h" +#include "V3UniqueNames.h" #include @@ -39,11 +40,11 @@ private: // NODE STATE // STATE - AstNodeModule* m_modp = nullptr; // Current module AstCFunc* m_cfuncp = nullptr; // Current block AstNode* m_stmtp = nullptr; // Current statement int m_depth = 0; // How deep in an expression int m_maxdepth = 0; // Maximum depth in an expression + V3UniqueNames m_tempNames; // For generating unique temporary variable names // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -51,10 +52,8 @@ private: void createDeepTemp(AstNode* nodep) { UINFO(6, " Deep " << nodep << endl); // if (debug() >= 9) nodep->dumpTree(cout, "deep:"); - - const string newvarname = (string("__Vdeeptemp") + cvtToStr(m_modp->varNumGetInc())); - AstVar* const varp - = new AstVar{nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep()}; + AstVar* const varp = new AstVar{nodep->fileline(), AstVarType::STMTTEMP, + m_tempNames.get(nodep), nodep->dtypep()}; UASSERT_OBJ(m_cfuncp, nodep, "Deep expression not under a function"); m_cfuncp->addInitsp(varp); // Replace node tree with reference to var @@ -70,21 +69,13 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { - UINFO(4, " MOD " << nodep << endl); - VL_RESTORER(m_modp); - { - m_modp = nodep; - m_cfuncp = nullptr; - iterateChildren(nodep); - } - } virtual void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); { m_cfuncp = nodep; m_depth = 0; m_maxdepth = 0; + m_tempNames.reset(); iterateChildren(nodep); } } @@ -149,7 +140,10 @@ private: public: // CONSTRUCTORS - explicit DepthVisitor(AstNetlist* nodep) { iterate(nodep); } + explicit DepthVisitor(AstNetlist* nodep) + : m_tempNames{"__Vdeeptemp"} { + iterate(nodep); + } virtual ~DepthVisitor() override = default; }; diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 948155f20..e665628b2 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -30,8 +30,8 @@ #include "V3Global.h" #include "V3Premit.h" #include "V3Ast.h" -#include "V3DupFinder.h" #include "V3Stats.h" +#include "V3UniqueNames.h" #include @@ -92,17 +92,17 @@ private: // AstNodeMath::user() -> bool. True if iterated already // AstShiftL::user2() -> bool. True if converted to conditional // AstShiftR::user2() -> bool. True if converted to conditional - // *::user4() -> See PremitAssignVisitor + // *::user3() -> See PremitAssignVisitor AstUser1InUse m_inuser1; AstUser2InUse m_inuser2; // STATE - AstNodeModule* m_modp = nullptr; // Current module AstCFunc* m_cfuncp = nullptr; // Current block AstNode* m_stmtp = nullptr; // Current statement AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions AstTraceInc* m_inTracep = nullptr; // Inside while loop, special statement additions bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts + V3UniqueNames m_tempNames; // For generating unique temporary variable names VDouble0 m_extractedToConstPool; // Statistic tracking @@ -184,9 +184,8 @@ private: nodep->deleteTree(); ++m_extractedToConstPool; } else { - // Keep as local temporary - const string name = string("__Vtemp") + cvtToStr(m_modp->varNumGetInc()); - varp = new AstVar(fl, AstVarType::STMTTEMP, name, nodep->dtypep()); + // Keep as local temporary. Name based on hash of node for output stability. + varp = new AstVar(fl, AstVarType::STMTTEMP, m_tempNames.get(nodep), nodep->dtypep()); m_cfuncp->addInitsp(varp); // Put assignment before the referencing statement insertBeforeStmt(new AstAssign(fl, new AstVarRef(fl, varp, VAccess::WRITE), nodep)); @@ -202,16 +201,13 @@ private: // VISITORS virtual void visit(AstNodeModule* nodep) override { UINFO(4, " MOD " << nodep << endl); - UASSERT_OBJ(m_modp == nullptr, nodep, "Nested modules ?"); - m_modp = nodep; - m_cfuncp = nullptr; iterateChildren(nodep); - m_modp = nullptr; } virtual void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); { m_cfuncp = nodep; + m_tempNames.reset(); iterateChildren(nodep); } } @@ -412,7 +408,10 @@ private: public: // CONSTRUCTORS - explicit PremitVisitor(AstNetlist* nodep) { iterate(nodep); } + explicit PremitVisitor(AstNetlist* nodep) + : m_tempNames{"__Vtemp"} { + iterate(nodep); + } virtual ~PremitVisitor() { V3Stats::addStat("Optimizations, Prelim extracted value to ConstPool", m_extractedToConstPool); diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 2f96ecbdd..71818e975 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -117,6 +117,7 @@ #include "V3Global.h" #include "V3SplitVar.h" #include "V3Stats.h" +#include "V3UniqueNames.h" #include // sort #include @@ -124,6 +125,10 @@ #include struct SplitVarImpl { + // NODE STATE + // AstNodeModule::user1() -> Block number counter for generating unique names + AstUser1InUse m_user1InUse; // Only used in SplitUnpackedVarVisitor + static AstNodeAssign* newAssign(FileLine* fileline, AstNode* lhsp, AstNode* rhsp, const AstVar* varp) { if (varp->isFuncLocal() || varp->isFuncReturn()) { @@ -184,27 +189,27 @@ struct SplitVarImpl { static const char* cannotSplitPackedVarReason(const AstVar* varp); template - static void insertBeginCore(T_ALWAYSLIKE* ap, AstNodeStmt* stmtp, AstNodeModule* modp) { + void insertBeginCore(T_ALWAYSLIKE* ap, AstNodeStmt* stmtp, AstNodeModule* modp) { if (ap->isJustOneBodyStmt() && ap->bodysp() == stmtp) { stmtp->unlinkFrBack(); // Insert begin-end because temp value may be inserted to this block later. - const std::string name = "__VsplitVarBlk" + cvtToStr(modp->varNumGetInc()); + const std::string name = "__VsplitVarBlk" + cvtToStr(modp->user1Inc(1)); ap->addStmtp(new AstBegin{ap->fileline(), name, stmtp}); } } - static void insertBeginCore(AstInitial* initp, AstNodeStmt* stmtp, AstNodeModule* modp) { + void insertBeginCore(AstInitial* initp, AstNodeStmt* stmtp, AstNodeModule* modp) { if (initp->isJustOneBodyStmt() && initp->bodysp() == stmtp) { stmtp->unlinkFrBack(); // Insert begin-end because temp value may be inserted to this block later. FileLine* const fl = initp->fileline(); - const std::string name = "__VsplitVarBlk" + cvtToStr(modp->varNumGetInc()); + const std::string name = "__VsplitVarBlk" + cvtToStr(modp->user1Inc(1)); initp->replaceWith(new AstInitial{fl, new AstBegin{fl, name, stmtp}}); VL_DO_DANGLING(initp->deleteTree(), initp); } } - static void insertBeginIfNecessary(AstNodeStmt* stmtp, AstNodeModule* modp) { + void insertBeginIfNecessary(AstNodeStmt* stmtp, AstNodeModule* modp) { AstNode* const backp = stmtp->backp(); if (AstAlways* const ap = VN_CAST(backp, Always)) { insertBeginCore(ap, stmtp, modp); @@ -401,6 +406,7 @@ class SplitUnpackedVarVisitor final : public AstNVisitor, public SplitVarImpl { size_t m_numSplit = 0; // List for SplitPackedVarVisitor SplitVarRefsMap m_refsForPackedSplit; + V3UniqueNames m_tempNames; // For generating unique temporary variable names static AstVarRef* isTargetVref(AstNode* nodep) { if (AstVarRef* const refp = VN_CAST(nodep, VarRef)) { @@ -457,6 +463,7 @@ class SplitUnpackedVarVisitor final : public AstNVisitor, public SplitVarImpl { UASSERT_OBJ(!m_modp, m_modp, "Nested module declaration"); UASSERT_OBJ(m_refs.empty(), nodep, "The last module didn't finish split()"); m_modp = nodep; + m_tempNames.reset(); iterateChildren(nodep); split(); m_modp = nullptr; @@ -593,7 +600,7 @@ class SplitUnpackedVarVisitor final : public AstNVisitor, public SplitVarImpl { iterateChildren(nodep); } } - static AstNode* toInsertPoint(AstNode* insertp) { + AstNode* toInsertPoint(AstNode* insertp) { if (AstNodeStmt* const stmtp = VN_CAST(insertp, NodeStmt)) { if (!stmtp->isStatement()) insertp = stmtp->backp(); } @@ -603,8 +610,7 @@ class SplitUnpackedVarVisitor final : public AstNVisitor, public SplitVarImpl { const std::string& name_prefix, std::vector& vars, int start_idx, bool lvalue, bool ftask) { FileLine* const fl = nodep->fileline(); - const std::string name - = "__VsplitVar" + cvtToStr(m_modp->varNumGetInc()) + "__" + name_prefix; + const std::string name = m_tempNames.get(nodep) + "__" + name_prefix; AstNodeAssign* const assignp = VN_CAST(context, NodeAssign); if (assignp) { // "always_comb a = b;" to "always_comb begin a = b; end" so that local @@ -765,7 +771,8 @@ class SplitUnpackedVarVisitor final : public AstNVisitor, public SplitVarImpl { public: explicit SplitUnpackedVarVisitor(AstNetlist* nodep) - : m_refs{} { + : m_refs{} + , m_tempNames{"__VsplitVar"} { iterate(nodep); } ~SplitUnpackedVarVisitor() override { diff --git a/src/V3UniqueNames.h b/src/V3UniqueNames.h index 2d3f94560..f33c86a12 100644 --- a/src/V3UniqueNames.h +++ b/src/V3UniqueNames.h @@ -18,22 +18,47 @@ #ifndef VERILATOR_V3UNIQUENAMES_H_ #define VERILATOR_V3UNIQUENAMES_H_ + #include "config_build.h" #include "verilatedos.h" +#include "V3Hasher.h" + #include #include class V3UniqueNames final { + const std::string m_prefix; // Prefix to attach to all names + std::unordered_map m_multiplicity; // Suffix number for given key public: - // Return argument, appended with a unique suffix each time we are called with the same - // argument. + V3UniqueNames() + : m_prefix{""} {} + explicit V3UniqueNames(const std::string& prefix) + : m_prefix{prefix} {} + + // Return argument, prepended with the prefix if any, then appended with a unique suffix each + // time we are called with the same argument. std::string get(const std::string& name) { const unsigned num = m_multiplicity.emplace(name, 0).first->second++; - return name + "__" + cvtToStr(num); + std::string result; + if (!m_prefix.empty()) { + result += m_prefix; + result += "_"; + } + result += name; + result += "__"; + result += cvtToStr(num); + return result; } + + // Return hash of node as string, prepended with the prefix if any, appended with a unique + // suffix each time we are called with a node that hashes to the same value. + std::string get(const AstNode* nodep) { return get(V3Hasher::uncachedHash(nodep).toString()); } + + // Reset to initial state (as if just constructed) + void reset() { m_multiplicity.clear(); } }; #endif // Guard diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 5c86e25ed..5ac9b5763 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -36,6 +36,7 @@ #include "V3Ast.h" #include "V3Const.h" #include "V3Stats.h" +#include "V3UniqueNames.h" #include @@ -57,6 +58,8 @@ private: AstAssignDly* m_assigndlyp = nullptr; // Current assignment bool m_constXCvt = false; // Convert X's VDouble0 m_statUnkVars; // Statistic tracking + V3UniqueNames m_lvboundNames; // For generating unique temporary variable names + V3UniqueNames m_xrandNames; // For generating unique temporary variable names // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -113,11 +116,10 @@ private: UINFO(4, "Edit BOUNDLVALUE " << newp << endl); replaceHandle.relink(newp); } else { - const string name = (string("__Vlvbound") + cvtToStr(m_modp->varNumGetInc())); - AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name, prep->dtypep()); + AstVar* const varp + = new AstVar(fl, AstVarType::MODULETEMP, m_lvboundNames.get(prep), prep->dtypep()); m_modp->addStmtp(varp); - - AstNode* abovep = prep->backp(); // Grab above point before lose it w/ next replace + AstNode* const abovep = prep->backp(); // Grab above point before we replace 'prep' prep->replaceWith(new AstVarRef(fl, varp, VAccess::WRITE)); AstIf* newp = new AstIf( fl, condp, @@ -142,6 +144,8 @@ private: { m_modp = nodep; m_constXCvt = true; + m_lvboundNames.reset(); + m_xrandNames.reset(); iterateChildren(nodep); } } @@ -322,15 +326,16 @@ private: // 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"); - const string newvarname = (string("__Vxrand") + cvtToStr(m_modp->varNumGetInc())); - AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::XTEMP, newvarname, - VFlagLogicPacked(), nodep->width()); + AstVar* const newvarp + = new AstVar(nodep->fileline(), AstVarType::XTEMP, m_xrandNames.get(nodep), + VFlagLogicPacked(), nodep->width()); ++m_statUnkVars; AstNRelinker replaceHandle; nodep->unlinkFrBack(&replaceHandle); - AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, VAccess::READ); + AstNodeVarRef* const newref1p + = new AstVarRef(nodep->fileline(), newvarp, VAccess::READ); replaceHandle.relink(newref1p); // Replace const with varref - AstInitial* newinitp = new AstInitial( + AstInitial* const newinitp = new AstInitial( nodep->fileline(), new AstAssign( nodep->fileline(), @@ -342,7 +347,7 @@ private: 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(); + AstNode* const afterp = m_modp->stmtsp()->unlinkFrBackWithNext(); m_modp->addStmtp(newvarp); m_modp->addStmtp(newinitp); m_modp->addStmtp(afterp); @@ -476,7 +481,11 @@ private: public: // CONSTRUCTORS - explicit UnknownVisitor(AstNetlist* nodep) { iterate(nodep); } + explicit UnknownVisitor(AstNetlist* nodep) + : m_lvboundNames{"__Vlvbound"} + , m_xrandNames{"__Vxrand"} { + iterate(nodep); + } virtual ~UnknownVisitor() override { // V3Stats::addStat("Unknowns, variables created", m_statUnkVars); } diff --git a/test_regress/t/t_xml_debugcheck.out b/test_regress/t/t_xml_debugcheck.out index 585eb915a..3b62af357 100644 --- a/test_regress/t/t_xml_debugcheck.out +++ b/test_regress/t/t_xml_debugcheck.out @@ -31,9 +31,9 @@ - - - + + + @@ -93,11 +93,11 @@ - + - + @@ -343,11 +343,11 @@ - + - + @@ -593,11 +593,11 @@ - + - + @@ -845,7 +845,7 @@ - + @@ -1298,11 +1298,11 @@ - + - +