Name temporary variables based on hash of related node.

This improves output stability by removing sequence numbers and hence
can improve ccache hit rate. No functional change intended.
This commit is contained in:
Geza Lore 2021-08-11 14:30:00 +01:00
parent 5adc856950
commit 00fe36f44c
8 changed files with 121 additions and 78 deletions

View File

@ -2849,7 +2849,6 @@ private:
bool m_recursive : 1; // Recursive module bool m_recursive : 1; // Recursive module
bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr 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_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 int m_typeNum = 0; // Incrementing implicit type number
VLifetime m_lifetime; // Lifetime VLifetime m_lifetime; // Lifetime
VTimescale m_timeunit; // Global time unit VTimescale m_timeunit; // Global time unit
@ -2890,7 +2889,6 @@ public:
void level(int level) { m_level = level; } void level(int level) { m_level = level; }
int level() const { return m_level; } int level() const { return m_level; }
bool isTop() const { return level() == 1; } bool isTop() const { return level() == 1; }
int varNumGetInc() { return ++m_varNum; }
int typeNumGetInc() { return ++m_typeNum; } int typeNumGetInc() { return ++m_typeNum; }
void modPublic(bool flag) { m_modPublic = flag; } void modPublic(bool flag) { m_modPublic = flag; }
bool modPublic() const { return m_modPublic; } bool modPublic() const { return m_modPublic; }

View File

@ -30,6 +30,7 @@
#include "V3Width.h" #include "V3Width.h"
#include "V3Simulate.h" #include "V3Simulate.h"
#include "V3Stats.h" #include "V3Stats.h"
#include "V3UniqueNames.h"
#include <algorithm> #include <algorithm>
@ -601,6 +602,9 @@ private:
AstNode* m_scopep = nullptr; // Current scope AstNode* m_scopep = nullptr; // Current scope
AstAttrOf* m_attrp = nullptr; // Current attribute AstAttrOf* m_attrp = nullptr; // Current attribute
VDouble0 m_statBitOpReduction; // Ops reduced in ConstBitOpTreeVisitor 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 // METHODS
VL_DEBUG_FUNC; // Declare debug() VL_DEBUG_FUNC; // Declare debug()
@ -1762,14 +1766,16 @@ private:
newp = AstNode::addNext(newp, asn2ap); newp = AstNode::addNext(newp, asn2ap);
} else { } else {
UASSERT_OBJ(m_modp, nodep, "Not under module"); 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 // We could create just one temp variable, but we'll get better optimization
// if we make one per term. // if we make one per term.
string name1 = (string("__Vconcswap") + cvtToStr(m_modp->varNumGetInc())); AstVar* const temp1p
string name2 = (string("__Vconcswap") + cvtToStr(m_modp->varNumGetInc())); = new AstVar(sel1p->fileline(), AstVarType::BLOCKTEMP,
AstVar* temp1p = new AstVar(sel1p->fileline(), AstVarType::BLOCKTEMP, name1, m_concswapNames.get(sel1p), VFlagLogicPacked(), msb1 - lsb1 + 1);
VFlagLogicPacked(), msb1 - lsb1 + 1); AstVar* const temp2p
AstVar* temp2p = new AstVar(sel2p->fileline(), AstVarType::BLOCKTEMP, name2, = new AstVar(sel2p->fileline(), AstVarType::BLOCKTEMP,
VFlagLogicPacked(), msb2 - lsb2 + 1); m_concswapNames.get(sel2p), VFlagLogicPacked(), msb2 - lsb2 + 1);
m_modp->addStmtp(temp1p); m_modp->addStmtp(temp1p);
m_modp->addStmtp(temp2p); m_modp->addStmtp(temp2p);
AstNodeAssign* asn1ap AstNodeAssign* asn1ap
@ -1931,6 +1937,7 @@ private:
VL_RESTORER(m_modp); VL_RESTORER(m_modp);
{ {
m_modp = nodep; m_modp = nodep;
m_concswapNames.reset();
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
@ -3197,7 +3204,9 @@ public:
}; };
// CONSTRUCTORS // CONSTRUCTORS
explicit ConstVisitor(ProcMode pmode) { ConstVisitor(ProcMode pmode, bool globalPass)
: m_globalPass{globalPass}
, m_concswapNames{globalPass ? ("__Vconcswap_" + cvtToStr(s_globalPassNum++)) : ""} {
// clang-format off // clang-format off
switch (pmode) { switch (pmode) {
case PROC_PARAMS: m_doV = true; m_doNConst = true; m_params = true; 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 // Const class functions
@ -3237,7 +3248,7 @@ AstNode* V3Const::constifyParamsEdit(AstNode* nodep) {
// Make sure we've sized everything first // Make sure we've sized everything first
nodep = V3Width::widthParamsEdit(nodep); nodep = V3Width::widthParamsEdit(nodep);
ConstVisitor visitor{ConstVisitor::PROC_PARAMS}; ConstVisitor visitor{ConstVisitor::PROC_PARAMS, /* globalPass: */ false};
if (AstVar* varp = VN_CAST(nodep, Var)) { if (AstVar* varp = VN_CAST(nodep, Var)) {
// If a var wants to be constified, it's really a param, and // 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 // 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 // Make sure we've sized everything first
nodep = V3Width::widthGenerateParamsEdit(nodep); nodep = V3Width::widthGenerateParamsEdit(nodep);
ConstVisitor visitor{ConstVisitor::PROC_GENERATE}; ConstVisitor visitor{ConstVisitor::PROC_GENERATE, /* globalPass: */ false};
if (AstVar* varp = VN_CAST(nodep, Var)) { if (AstVar* varp = VN_CAST(nodep, Var)) {
// If a var wants to be constified, it's really a param, and // 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 // 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 // Only call from Verilator.cpp, as it uses user#'s
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ {
ConstVisitor visitor{ConstVisitor::PROC_V_WARN}; ConstVisitor visitor{ConstVisitor::PROC_V_WARN, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep); (void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking } // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
@ -3294,14 +3305,14 @@ void V3Const::constifyAllLint(AstNetlist* nodep) {
void V3Const::constifyCpp(AstNetlist* nodep) { void V3Const::constifyCpp(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ {
ConstVisitor visitor{ConstVisitor::PROC_CPP}; ConstVisitor visitor{ConstVisitor::PROC_CPP, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep); (void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking } // Destruct before checking
V3Global::dumpCheckGlobalTree("const_cpp", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("const_cpp", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
} }
AstNode* V3Const::constifyEdit(AstNode* nodep) { AstNode* V3Const::constifyEdit(AstNode* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_V_NOWARN}; ConstVisitor visitor{ConstVisitor::PROC_V_NOWARN, /* globalPass: */ false};
nodep = visitor.mainAcceptEdit(nodep); nodep = visitor.mainAcceptEdit(nodep);
return 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 // IE doesn't prune dead statements, as we need to do some usability checks after this
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ {
ConstVisitor visitor{ConstVisitor::PROC_LIVE}; ConstVisitor visitor{ConstVisitor::PROC_LIVE, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep); (void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking } // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); 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 // Only call from Verilator.cpp, as it uses user#'s
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
{ {
ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE}; ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE, /* globalPass: */ true};
(void)visitor.mainAcceptEdit(nodep); (void)visitor.mainAcceptEdit(nodep);
} // Destruct before checking } // Destruct before checking
V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
} }
AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) { AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) {
ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE}; ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE, /* globalPass: */ false};
nodep = visitor.mainAcceptEdit(nodep); nodep = visitor.mainAcceptEdit(nodep);
return nodep; return nodep;
} }

View File

@ -29,6 +29,7 @@
#include "V3Global.h" #include "V3Global.h"
#include "V3Depth.h" #include "V3Depth.h"
#include "V3Ast.h" #include "V3Ast.h"
#include "V3UniqueNames.h"
#include <algorithm> #include <algorithm>
@ -39,11 +40,11 @@ private:
// NODE STATE // NODE STATE
// STATE // STATE
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_cfuncp = nullptr; // Current block AstCFunc* m_cfuncp = nullptr; // Current block
AstNode* m_stmtp = nullptr; // Current statement AstNode* m_stmtp = nullptr; // Current statement
int m_depth = 0; // How deep in an expression int m_depth = 0; // How deep in an expression
int m_maxdepth = 0; // Maximum depth in an expression int m_maxdepth = 0; // Maximum depth in an expression
V3UniqueNames m_tempNames; // For generating unique temporary variable names
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug() VL_DEBUG_FUNC; // Declare debug()
@ -51,10 +52,8 @@ private:
void createDeepTemp(AstNode* nodep) { void createDeepTemp(AstNode* nodep) {
UINFO(6, " Deep " << nodep << endl); UINFO(6, " Deep " << nodep << endl);
// if (debug() >= 9) nodep->dumpTree(cout, "deep:"); // if (debug() >= 9) nodep->dumpTree(cout, "deep:");
AstVar* const varp = new AstVar{nodep->fileline(), AstVarType::STMTTEMP,
const string newvarname = (string("__Vdeeptemp") + cvtToStr(m_modp->varNumGetInc())); m_tempNames.get(nodep), nodep->dtypep()};
AstVar* const varp
= new AstVar{nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep()};
UASSERT_OBJ(m_cfuncp, nodep, "Deep expression not under a function"); UASSERT_OBJ(m_cfuncp, nodep, "Deep expression not under a function");
m_cfuncp->addInitsp(varp); m_cfuncp->addInitsp(varp);
// Replace node tree with reference to var // Replace node tree with reference to var
@ -70,21 +69,13 @@ private:
} }
// VISITORS // 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 { virtual void visit(AstCFunc* nodep) override {
VL_RESTORER(m_cfuncp); VL_RESTORER(m_cfuncp);
{ {
m_cfuncp = nodep; m_cfuncp = nodep;
m_depth = 0; m_depth = 0;
m_maxdepth = 0; m_maxdepth = 0;
m_tempNames.reset();
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
@ -149,7 +140,10 @@ private:
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit DepthVisitor(AstNetlist* nodep) { iterate(nodep); } explicit DepthVisitor(AstNetlist* nodep)
: m_tempNames{"__Vdeeptemp"} {
iterate(nodep);
}
virtual ~DepthVisitor() override = default; virtual ~DepthVisitor() override = default;
}; };

View File

@ -30,8 +30,8 @@
#include "V3Global.h" #include "V3Global.h"
#include "V3Premit.h" #include "V3Premit.h"
#include "V3Ast.h" #include "V3Ast.h"
#include "V3DupFinder.h"
#include "V3Stats.h" #include "V3Stats.h"
#include "V3UniqueNames.h"
#include <algorithm> #include <algorithm>
@ -92,17 +92,17 @@ private:
// AstNodeMath::user() -> bool. True if iterated already // AstNodeMath::user() -> bool. True if iterated already
// AstShiftL::user2() -> bool. True if converted to conditional // AstShiftL::user2() -> bool. True if converted to conditional
// AstShiftR::user2() -> bool. True if converted to conditional // AstShiftR::user2() -> bool. True if converted to conditional
// *::user4() -> See PremitAssignVisitor // *::user3() -> See PremitAssignVisitor
AstUser1InUse m_inuser1; AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2; AstUser2InUse m_inuser2;
// STATE // STATE
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_cfuncp = nullptr; // Current block AstCFunc* m_cfuncp = nullptr; // Current block
AstNode* m_stmtp = nullptr; // Current statement AstNode* m_stmtp = nullptr; // Current statement
AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions
AstTraceInc* m_inTracep = 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 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 VDouble0 m_extractedToConstPool; // Statistic tracking
@ -184,9 +184,8 @@ private:
nodep->deleteTree(); nodep->deleteTree();
++m_extractedToConstPool; ++m_extractedToConstPool;
} else { } else {
// Keep as local temporary // Keep as local temporary. Name based on hash of node for output stability.
const string name = string("__Vtemp") + cvtToStr(m_modp->varNumGetInc()); varp = new AstVar(fl, AstVarType::STMTTEMP, m_tempNames.get(nodep), nodep->dtypep());
varp = new AstVar(fl, AstVarType::STMTTEMP, name, nodep->dtypep());
m_cfuncp->addInitsp(varp); m_cfuncp->addInitsp(varp);
// Put assignment before the referencing statement // Put assignment before the referencing statement
insertBeforeStmt(new AstAssign(fl, new AstVarRef(fl, varp, VAccess::WRITE), nodep)); insertBeforeStmt(new AstAssign(fl, new AstVarRef(fl, varp, VAccess::WRITE), nodep));
@ -202,16 +201,13 @@ private:
// VISITORS // VISITORS
virtual void visit(AstNodeModule* nodep) override { virtual void visit(AstNodeModule* nodep) override {
UINFO(4, " MOD " << nodep << endl); UINFO(4, " MOD " << nodep << endl);
UASSERT_OBJ(m_modp == nullptr, nodep, "Nested modules ?");
m_modp = nodep;
m_cfuncp = nullptr;
iterateChildren(nodep); iterateChildren(nodep);
m_modp = nullptr;
} }
virtual void visit(AstCFunc* nodep) override { virtual void visit(AstCFunc* nodep) override {
VL_RESTORER(m_cfuncp); VL_RESTORER(m_cfuncp);
{ {
m_cfuncp = nodep; m_cfuncp = nodep;
m_tempNames.reset();
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
@ -412,7 +408,10 @@ private:
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit PremitVisitor(AstNetlist* nodep) { iterate(nodep); } explicit PremitVisitor(AstNetlist* nodep)
: m_tempNames{"__Vtemp"} {
iterate(nodep);
}
virtual ~PremitVisitor() { virtual ~PremitVisitor() {
V3Stats::addStat("Optimizations, Prelim extracted value to ConstPool", V3Stats::addStat("Optimizations, Prelim extracted value to ConstPool",
m_extractedToConstPool); m_extractedToConstPool);

View File

@ -117,6 +117,7 @@
#include "V3Global.h" #include "V3Global.h"
#include "V3SplitVar.h" #include "V3SplitVar.h"
#include "V3Stats.h" #include "V3Stats.h"
#include "V3UniqueNames.h"
#include <algorithm> // sort #include <algorithm> // sort
#include <map> #include <map>
@ -124,6 +125,10 @@
#include <vector> #include <vector>
struct SplitVarImpl { 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, static AstNodeAssign* newAssign(FileLine* fileline, AstNode* lhsp, AstNode* rhsp,
const AstVar* varp) { const AstVar* varp) {
if (varp->isFuncLocal() || varp->isFuncReturn()) { if (varp->isFuncLocal() || varp->isFuncReturn()) {
@ -184,27 +189,27 @@ struct SplitVarImpl {
static const char* cannotSplitPackedVarReason(const AstVar* varp); static const char* cannotSplitPackedVarReason(const AstVar* varp);
template <class T_ALWAYSLIKE> template <class T_ALWAYSLIKE>
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) { if (ap->isJustOneBodyStmt() && ap->bodysp() == stmtp) {
stmtp->unlinkFrBack(); stmtp->unlinkFrBack();
// Insert begin-end because temp value may be inserted to this block later. // 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}); 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) { if (initp->isJustOneBodyStmt() && initp->bodysp() == stmtp) {
stmtp->unlinkFrBack(); stmtp->unlinkFrBack();
// Insert begin-end because temp value may be inserted to this block later. // Insert begin-end because temp value may be inserted to this block later.
FileLine* const fl = initp->fileline(); 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}}); initp->replaceWith(new AstInitial{fl, new AstBegin{fl, name, stmtp}});
VL_DO_DANGLING(initp->deleteTree(), initp); VL_DO_DANGLING(initp->deleteTree(), initp);
} }
} }
static void insertBeginIfNecessary(AstNodeStmt* stmtp, AstNodeModule* modp) { void insertBeginIfNecessary(AstNodeStmt* stmtp, AstNodeModule* modp) {
AstNode* const backp = stmtp->backp(); AstNode* const backp = stmtp->backp();
if (AstAlways* const ap = VN_CAST(backp, Always)) { if (AstAlways* const ap = VN_CAST(backp, Always)) {
insertBeginCore(ap, stmtp, modp); insertBeginCore(ap, stmtp, modp);
@ -401,6 +406,7 @@ class SplitUnpackedVarVisitor final : public AstNVisitor, public SplitVarImpl {
size_t m_numSplit = 0; size_t m_numSplit = 0;
// List for SplitPackedVarVisitor // List for SplitPackedVarVisitor
SplitVarRefsMap m_refsForPackedSplit; SplitVarRefsMap m_refsForPackedSplit;
V3UniqueNames m_tempNames; // For generating unique temporary variable names
static AstVarRef* isTargetVref(AstNode* nodep) { static AstVarRef* isTargetVref(AstNode* nodep) {
if (AstVarRef* const refp = VN_CAST(nodep, VarRef)) { 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_modp, m_modp, "Nested module declaration");
UASSERT_OBJ(m_refs.empty(), nodep, "The last module didn't finish split()"); UASSERT_OBJ(m_refs.empty(), nodep, "The last module didn't finish split()");
m_modp = nodep; m_modp = nodep;
m_tempNames.reset();
iterateChildren(nodep); iterateChildren(nodep);
split(); split();
m_modp = nullptr; m_modp = nullptr;
@ -593,7 +600,7 @@ class SplitUnpackedVarVisitor final : public AstNVisitor, public SplitVarImpl {
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
static AstNode* toInsertPoint(AstNode* insertp) { AstNode* toInsertPoint(AstNode* insertp) {
if (AstNodeStmt* const stmtp = VN_CAST(insertp, NodeStmt)) { if (AstNodeStmt* const stmtp = VN_CAST(insertp, NodeStmt)) {
if (!stmtp->isStatement()) insertp = stmtp->backp(); if (!stmtp->isStatement()) insertp = stmtp->backp();
} }
@ -603,8 +610,7 @@ class SplitUnpackedVarVisitor final : public AstNVisitor, public SplitVarImpl {
const std::string& name_prefix, std::vector<AstVar*>& vars, const std::string& name_prefix, std::vector<AstVar*>& vars,
int start_idx, bool lvalue, bool ftask) { int start_idx, bool lvalue, bool ftask) {
FileLine* const fl = nodep->fileline(); FileLine* const fl = nodep->fileline();
const std::string name const std::string name = m_tempNames.get(nodep) + "__" + name_prefix;
= "__VsplitVar" + cvtToStr(m_modp->varNumGetInc()) + "__" + name_prefix;
AstNodeAssign* const assignp = VN_CAST(context, NodeAssign); AstNodeAssign* const assignp = VN_CAST(context, NodeAssign);
if (assignp) { if (assignp) {
// "always_comb a = b;" to "always_comb begin a = b; end" so that local // "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: public:
explicit SplitUnpackedVarVisitor(AstNetlist* nodep) explicit SplitUnpackedVarVisitor(AstNetlist* nodep)
: m_refs{} { : m_refs{}
, m_tempNames{"__VsplitVar"} {
iterate(nodep); iterate(nodep);
} }
~SplitUnpackedVarVisitor() override { ~SplitUnpackedVarVisitor() override {

View File

@ -18,22 +18,47 @@
#ifndef VERILATOR_V3UNIQUENAMES_H_ #ifndef VERILATOR_V3UNIQUENAMES_H_
#define VERILATOR_V3UNIQUENAMES_H_ #define VERILATOR_V3UNIQUENAMES_H_
#include "config_build.h" #include "config_build.h"
#include "verilatedos.h" #include "verilatedos.h"
#include "V3Hasher.h"
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
class V3UniqueNames final { class V3UniqueNames final {
const std::string m_prefix; // Prefix to attach to all names
std::unordered_map<std::string, unsigned> m_multiplicity; // Suffix number for given key std::unordered_map<std::string, unsigned> m_multiplicity; // Suffix number for given key
public: public:
// Return argument, appended with a unique suffix each time we are called with the same V3UniqueNames()
// argument. : 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) { std::string get(const std::string& name) {
const unsigned num = m_multiplicity.emplace(name, 0).first->second++; 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 #endif // Guard

View File

@ -36,6 +36,7 @@
#include "V3Ast.h" #include "V3Ast.h"
#include "V3Const.h" #include "V3Const.h"
#include "V3Stats.h" #include "V3Stats.h"
#include "V3UniqueNames.h"
#include <algorithm> #include <algorithm>
@ -57,6 +58,8 @@ private:
AstAssignDly* m_assigndlyp = nullptr; // Current assignment AstAssignDly* m_assigndlyp = nullptr; // Current assignment
bool m_constXCvt = false; // Convert X's bool m_constXCvt = false; // Convert X's
VDouble0 m_statUnkVars; // Statistic tracking VDouble0 m_statUnkVars; // Statistic tracking
V3UniqueNames m_lvboundNames; // For generating unique temporary variable names
V3UniqueNames m_xrandNames; // For generating unique temporary variable names
// METHODS // METHODS
VL_DEBUG_FUNC; // Declare debug() VL_DEBUG_FUNC; // Declare debug()
@ -113,11 +116,10 @@ private:
UINFO(4, "Edit BOUNDLVALUE " << newp << endl); UINFO(4, "Edit BOUNDLVALUE " << newp << endl);
replaceHandle.relink(newp); replaceHandle.relink(newp);
} else { } else {
const string name = (string("__Vlvbound") + cvtToStr(m_modp->varNumGetInc())); AstVar* const varp
AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name, prep->dtypep()); = new AstVar(fl, AstVarType::MODULETEMP, m_lvboundNames.get(prep), prep->dtypep());
m_modp->addStmtp(varp); m_modp->addStmtp(varp);
AstNode* const abovep = prep->backp(); // Grab above point before we replace 'prep'
AstNode* abovep = prep->backp(); // Grab above point before lose it w/ next replace
prep->replaceWith(new AstVarRef(fl, varp, VAccess::WRITE)); prep->replaceWith(new AstVarRef(fl, varp, VAccess::WRITE));
AstIf* newp = new AstIf( AstIf* newp = new AstIf(
fl, condp, fl, condp,
@ -142,6 +144,8 @@ private:
{ {
m_modp = nodep; m_modp = nodep;
m_constXCvt = true; m_constXCvt = true;
m_lvboundNames.reset();
m_xrandNames.reset();
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
@ -322,15 +326,16 @@ private:
// Make a Vxrand variable // Make a Vxrand variable
// We use the special XTEMP type so it doesn't break pure functions // We use the special XTEMP type so it doesn't break pure functions
UASSERT_OBJ(m_modp, nodep, "X number not under module"); UASSERT_OBJ(m_modp, nodep, "X number not under module");
const string newvarname = (string("__Vxrand") + cvtToStr(m_modp->varNumGetInc())); AstVar* const newvarp
AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::XTEMP, newvarname, = new AstVar(nodep->fileline(), AstVarType::XTEMP, m_xrandNames.get(nodep),
VFlagLogicPacked(), nodep->width()); VFlagLogicPacked(), nodep->width());
++m_statUnkVars; ++m_statUnkVars;
AstNRelinker replaceHandle; AstNRelinker replaceHandle;
nodep->unlinkFrBack(&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 replaceHandle.relink(newref1p); // Replace const with varref
AstInitial* newinitp = new AstInitial( AstInitial* const newinitp = new AstInitial(
nodep->fileline(), nodep->fileline(),
new AstAssign( new AstAssign(
nodep->fileline(), nodep->fileline(),
@ -342,7 +347,7 @@ private:
nodep->dtypep(), true))))); nodep->dtypep(), true)))));
// Add inits in front of other statement. // Add inits in front of other statement.
// In the future, we should stuff the initp into the module's constructor. // 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(newvarp);
m_modp->addStmtp(newinitp); m_modp->addStmtp(newinitp);
m_modp->addStmtp(afterp); m_modp->addStmtp(afterp);
@ -476,7 +481,11 @@ private:
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit UnknownVisitor(AstNetlist* nodep) { iterate(nodep); } explicit UnknownVisitor(AstNetlist* nodep)
: m_lvboundNames{"__Vlvbound"}
, m_xrandNames{"__Vxrand"} {
iterate(nodep);
}
virtual ~UnknownVisitor() override { // virtual ~UnknownVisitor() override { //
V3Stats::addStat("Unknowns, variables created", m_statUnkVars); V3Stats::addStat("Unknowns, variables created", m_statUnkVars);
} }

View File

@ -31,9 +31,9 @@
<cfunc fl="d60" loc="d,60,4,60,10" name="_sequent__TOP__1"> <cfunc fl="d60" loc="d,60,4,60,10" name="_sequent__TOP__1">
<var fl="d22" loc="d,22,13,22,16" name="__Vdly__t.cyc" dtype_id="3" vartype="integer" origName="__Vdly__t__DOT__cyc"/> <var fl="d22" loc="d,22,13,22,16" name="__Vdly__t.cyc" dtype_id="3" vartype="integer" origName="__Vdly__t__DOT__cyc"/>
<var fl="d23" loc="d,23,9,23,10" name="__Vdly__t.e" dtype_id="2" vartype="my_t" origName="__Vdly__t__DOT__e"/> <var fl="d23" loc="d,23,9,23,10" name="__Vdly__t.e" dtype_id="2" vartype="my_t" origName="__Vdly__t__DOT__e"/>
<var fl="d67" loc="d,67,119,67,123" name="__Vtemp1" dtype_id="4" vartype="string" origName="__Vtemp1"/> <var fl="d67" loc="d,67,119,67,123" name="__Vtemp_h########__0" dtype_id="4" vartype="string" origName="__Vtemp_h########__0"/>
<var fl="d77" loc="d,77,119,77,123" name="__Vtemp2" dtype_id="4" vartype="string" origName="__Vtemp2"/> <var fl="d77" loc="d,77,119,77,123" name="__Vtemp_h########__1" dtype_id="4" vartype="string" origName="__Vtemp_h########__1"/>
<var fl="d87" loc="d,87,119,87,123" name="__Vtemp3" dtype_id="4" vartype="string" origName="__Vtemp3"/> <var fl="d87" loc="d,87,119,87,123" name="__Vtemp_h########__2" dtype_id="4" vartype="string" origName="__Vtemp_h########__2"/>
<assignpre fl="d64" loc="d,64,3,64,4" dtype_id="5"> <assignpre fl="d64" loc="d,64,3,64,4" dtype_id="5">
<varref fl="d64" loc="d,64,3,64,4" name="t.e" dtype_id="5"/> <varref fl="d64" loc="d,64,3,64,4" name="t.e" dtype_id="5"/>
<varref fl="d64" loc="d,64,3,64,4" name="__Vdly__t.e" dtype_id="5"/> <varref fl="d64" loc="d,64,3,64,4" name="__Vdly__t.e" dtype_id="5"/>
@ -93,11 +93,11 @@
</ccast> </ccast>
</and> </and>
</arraysel> </arraysel>
<varref fl="d67" loc="d,67,119,67,123" name="__Vtemp1" dtype_id="4"/> <varref fl="d67" loc="d,67,119,67,123" name="__Vtemp_h########__0" dtype_id="4"/>
</assign> </assign>
<display fl="d67" loc="d,67,38,67,44" displaytype="$write"> <display fl="d67" loc="d,67,38,67,44" displaytype="$write">
<sformatf fl="d67" loc="d,67,38,67,44" name="%%Error: t/t_enum_type_methods.v:67: got=&apos;%@&apos; exp=&apos;E01&apos;&#10;" dtype_id="4"> <sformatf fl="d67" loc="d,67,38,67,44" name="%%Error: t/t_enum_type_methods.v:67: got=&apos;%@&apos; exp=&apos;E01&apos;&#10;" dtype_id="4">
<varref fl="d67" loc="d,67,119,67,123" name="__Vtemp1" dtype_id="4"/> <varref fl="d67" loc="d,67,119,67,123" name="__Vtemp_h########__0" dtype_id="4"/>
</sformatf> </sformatf>
</display> </display>
<stop fl="d67" loc="d,67,136,67,141"/> <stop fl="d67" loc="d,67,136,67,141"/>
@ -343,11 +343,11 @@
</ccast> </ccast>
</and> </and>
</arraysel> </arraysel>
<varref fl="d77" loc="d,77,119,77,123" name="__Vtemp2" dtype_id="4"/> <varref fl="d77" loc="d,77,119,77,123" name="__Vtemp_h########__1" dtype_id="4"/>
</assign> </assign>
<display fl="d77" loc="d,77,38,77,44" displaytype="$write"> <display fl="d77" loc="d,77,38,77,44" displaytype="$write">
<sformatf fl="d77" loc="d,77,38,77,44" name="%%Error: t/t_enum_type_methods.v:77: got=&apos;%@&apos; exp=&apos;E03&apos;&#10;" dtype_id="4"> <sformatf fl="d77" loc="d,77,38,77,44" name="%%Error: t/t_enum_type_methods.v:77: got=&apos;%@&apos; exp=&apos;E03&apos;&#10;" dtype_id="4">
<varref fl="d77" loc="d,77,119,77,123" name="__Vtemp2" dtype_id="4"/> <varref fl="d77" loc="d,77,119,77,123" name="__Vtemp_h########__1" dtype_id="4"/>
</sformatf> </sformatf>
</display> </display>
<stop fl="d77" loc="d,77,136,77,141"/> <stop fl="d77" loc="d,77,136,77,141"/>
@ -593,11 +593,11 @@
</ccast> </ccast>
</and> </and>
</arraysel> </arraysel>
<varref fl="d87" loc="d,87,119,87,123" name="__Vtemp3" dtype_id="4"/> <varref fl="d87" loc="d,87,119,87,123" name="__Vtemp_h########__2" dtype_id="4"/>
</assign> </assign>
<display fl="d87" loc="d,87,38,87,44" displaytype="$write"> <display fl="d87" loc="d,87,38,87,44" displaytype="$write">
<sformatf fl="d87" loc="d,87,38,87,44" name="%%Error: t/t_enum_type_methods.v:87: got=&apos;%@&apos; exp=&apos;E04&apos;&#10;" dtype_id="4"> <sformatf fl="d87" loc="d,87,38,87,44" name="%%Error: t/t_enum_type_methods.v:87: got=&apos;%@&apos; exp=&apos;E04&apos;&#10;" dtype_id="4">
<varref fl="d87" loc="d,87,119,87,123" name="__Vtemp3" dtype_id="4"/> <varref fl="d87" loc="d,87,119,87,123" name="__Vtemp_h########__2" dtype_id="4"/>
</sformatf> </sformatf>
</display> </display>
<stop fl="d87" loc="d,87,136,87,141"/> <stop fl="d87" loc="d,87,136,87,141"/>
@ -845,7 +845,7 @@
<cfunc fl="d22" loc="d,22,17,22,18" name="_initial__TOP__2"> <cfunc fl="d22" loc="d,22,17,22,18" name="_initial__TOP__2">
<var fl="d27" loc="d,27,11,27,14" name="t.all" dtype_id="4" vartype="string" origName="t__DOT__all"/> <var fl="d27" loc="d,27,11,27,14" name="t.all" dtype_id="4" vartype="string" origName="t__DOT__all"/>
<var fl="d51" loc="d,51,17,51,18" name="t.unnamedblk1.e" dtype_id="2" vartype="my_t" origName="t__DOT__unnamedblk1__DOT__e"/> <var fl="d51" loc="d,51,17,51,18" name="t.unnamedblk1.e" dtype_id="2" vartype="my_t" origName="t__DOT__unnamedblk1__DOT__e"/>
<var fl="d48" loc="d,48,123,48,127" name="__Vtemp4" dtype_id="4" vartype="string" origName="__Vtemp4"/> <var fl="d48" loc="d,48,123,48,127" name="__Vtemp_h########__0" dtype_id="4" vartype="string" origName="__Vtemp_h########__0"/>
<assign fl="d22" loc="d,22,17,22,18" dtype_id="3"> <assign fl="d22" loc="d,22,17,22,18" dtype_id="3">
<const fl="d22" loc="d,22,17,22,18" name="32&apos;sh0" dtype_id="7"/> <const fl="d22" loc="d,22,17,22,18" name="32&apos;sh0" dtype_id="7"/>
<varref fl="d22" loc="d,22,17,22,18" name="t.cyc" dtype_id="3"/> <varref fl="d22" loc="d,22,17,22,18" name="t.cyc" dtype_id="3"/>
@ -1298,11 +1298,11 @@
</ccast> </ccast>
</and> </and>
</arraysel> </arraysel>
<varref fl="d48" loc="d,48,123,48,127" name="__Vtemp4" dtype_id="4"/> <varref fl="d48" loc="d,48,123,48,127" name="__Vtemp_h########__0" dtype_id="4"/>
</assign> </assign>
<display fl="d48" loc="d,48,42,48,48" displaytype="$write"> <display fl="d48" loc="d,48,42,48,48" displaytype="$write">
<sformatf fl="d48" loc="d,48,42,48,48" name="%%Error: t/t_enum_type_methods.v:48: got=&apos;%@&apos; exp=&apos;E03&apos;&#10;" dtype_id="4"> <sformatf fl="d48" loc="d,48,42,48,48" name="%%Error: t/t_enum_type_methods.v:48: got=&apos;%@&apos; exp=&apos;E03&apos;&#10;" dtype_id="4">
<varref fl="d48" loc="d,48,123,48,127" name="__Vtemp4" dtype_id="4"/> <varref fl="d48" loc="d,48,123,48,127" name="__Vtemp_h########__0" dtype_id="4"/>
</sformatf> </sformatf>
</display> </display>
<stop fl="d48" loc="d,48,140,48,145"/> <stop fl="d48" loc="d,48,140,48,145"/>