mirror of
https://github.com/verilator/verilator.git
synced 2025-04-16 01:26:54 +00:00
Add V3VariableOrder pass
A separate V3VariableOrder pass is now used to order module variables before Emit. All variables are now ordered together, without consideration for whether they are ports, signals form the design, or additional internal variables added by Verilator (which used to be ordered and emitted as separate groups in Emit). For single threaded models, this is performance neutral. For multi-threaded models, the MTask affinity based sorting was slightly modified, so variables with no MTask affinity are emitted last, otherwise the MTask affinity sets are sorted using the TSP sorter as before, but again, ports, signals, and internal variables are not differentiated. This yields a 2%+ speedup for the multithreaded model on OpenTitan.
This commit is contained in:
parent
8ecdc85cf7
commit
17cc452f79
@ -254,6 +254,7 @@ RAW_OBJS = \
|
||||
V3Undriven.o \
|
||||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
V3VariableOrder.o \
|
||||
V3Waiver.o \
|
||||
V3Width.o \
|
||||
V3WidthSel.o \
|
||||
|
@ -33,7 +33,7 @@ template <class T_Node, class T_Data, int T_UserN> class AstUserAllocatorBase VL
|
||||
private:
|
||||
std::vector<T_Data*> m_allocated;
|
||||
|
||||
inline T_Data* getUserp(T_Node* nodep) const {
|
||||
inline T_Data* getUserp(const T_Node* nodep) const {
|
||||
// This simplifies statically as T_UserN is constant. In C++17, use 'if constexpr'.
|
||||
if (T_UserN == 1) {
|
||||
const VNUser user = nodep->user1u();
|
||||
@ -100,6 +100,13 @@ public:
|
||||
}
|
||||
return *userp;
|
||||
}
|
||||
|
||||
// Get a reference to the user data
|
||||
T_Data& operator()(const T_Node* nodep) {
|
||||
T_Data* userp = getUserp(nodep);
|
||||
UASSERT_OBJ(userp, nodep, "Missing User data on const AstNode");
|
||||
return *userp;
|
||||
}
|
||||
};
|
||||
|
||||
// User pointer allocator classes. T_Node is the type of node the allocator should be applied to
|
||||
|
134
src/V3EmitC.cpp
134
src/V3EmitC.cpp
@ -123,7 +123,7 @@ class EmitCImp final : EmitCFunc {
|
||||
}
|
||||
}
|
||||
}
|
||||
void emitParams(AstNodeModule* modp, bool init, bool* firstp, string& sectionr) {
|
||||
void emitParams(AstNodeModule* modp, bool init, string& sectionr) {
|
||||
bool anyi = false;
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* varp = VN_CAST(nodep, Var)) {
|
||||
@ -207,6 +207,99 @@ class EmitCImp final : EmitCFunc {
|
||||
emitCFuncDecl(funcp, modp);
|
||||
}
|
||||
}
|
||||
void emitVarDecls(const AstNodeModule* modp) {
|
||||
// Output a list of variable declarations
|
||||
|
||||
std::vector<const AstVar*> varList;
|
||||
bool lastAnon = false; // initial value is not important, but is used
|
||||
|
||||
const auto emitCurrentList = [this, &varList, &lastAnon]() {
|
||||
if (varList.empty()) return;
|
||||
|
||||
if (lastAnon) { // Output as anons
|
||||
const int anonMembers = varList.size();
|
||||
const int lim = v3Global.opt.compLimitMembers();
|
||||
int anonL3s = 1;
|
||||
int anonL2s = 1;
|
||||
int anonL1s = 1;
|
||||
if (anonMembers > (lim * lim * lim)) {
|
||||
anonL3s = (anonMembers + (lim * lim * lim) - 1) / (lim * lim * lim);
|
||||
anonL2s = lim;
|
||||
anonL1s = lim;
|
||||
} else if (anonMembers > (lim * lim)) {
|
||||
anonL2s = (anonMembers + (lim * lim) - 1) / (lim * lim);
|
||||
anonL1s = lim;
|
||||
} else if (anonMembers > lim) {
|
||||
anonL1s = (anonMembers + lim - 1) / lim;
|
||||
}
|
||||
if (anonL1s != 1)
|
||||
puts("// Anonymous structures to workaround compiler member-count bugs\n");
|
||||
auto it = varList.cbegin();
|
||||
for (int l3 = 0; l3 < anonL3s && it != varList.cend(); ++l3) {
|
||||
if (anonL3s != 1) puts("struct {\n");
|
||||
for (int l2 = 0; l2 < anonL2s && it != varList.cend(); ++l2) {
|
||||
if (anonL2s != 1) puts("struct {\n");
|
||||
for (int l1 = 0; l1 < anonL1s && it != varList.cend(); ++l1) {
|
||||
if (anonL1s != 1) puts("struct {\n");
|
||||
for (int l0 = 0; l0 < lim && it != varList.cend(); ++l0) {
|
||||
emitVarDecl(*it);
|
||||
++it;
|
||||
}
|
||||
if (anonL1s != 1) puts("};\n");
|
||||
}
|
||||
if (anonL2s != 1) puts("};\n");
|
||||
}
|
||||
if (anonL3s != 1) puts("};\n");
|
||||
}
|
||||
// Leftovers, just in case off by one error somewhere above
|
||||
for (; it != varList.cend(); ++it) emitVarDecl(*it);
|
||||
} else { // Output as nonanons
|
||||
for (const auto& pair : varList) emitVarDecl(pair);
|
||||
}
|
||||
|
||||
varList.clear();
|
||||
};
|
||||
|
||||
// Emit variables in consecutive anon and non-anon batches
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
|
||||
if (varp->isIO() || varp->isSignal() || varp->isClassMember() || varp->isTemp()
|
||||
|| (varp->isParam() && !VN_IS(varp->valuep(), Const))) {
|
||||
const bool anon = isAnonOk(varp);
|
||||
if (anon != lastAnon) emitCurrentList();
|
||||
lastAnon = anon;
|
||||
varList.emplace_back(varp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emit final batch
|
||||
emitCurrentList();
|
||||
}
|
||||
void emitVarCtors(const AstNodeModule* modp) {
|
||||
ofp()->indentInc();
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
|
||||
const AstBasicDType* const dtypep = VN_CAST(varp->dtypeSkipRefp(), BasicDType);
|
||||
if (!dtypep) continue;
|
||||
if (varp->isIO() && varp->isSc()) {
|
||||
puts(", ");
|
||||
puts(varp->nameProtect());
|
||||
puts("(");
|
||||
putsQuoted(varp->nameProtect());
|
||||
puts(")\n");
|
||||
}
|
||||
if (dtypep->keyword().isMTaskState()) {
|
||||
puts(", ");
|
||||
puts(varp->nameProtect());
|
||||
puts("(");
|
||||
iterate(varp->valuep());
|
||||
puts(")\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
ofp()->indentDec();
|
||||
}
|
||||
|
||||
// Medium level
|
||||
void emitCtorImp(AstNodeModule* modp);
|
||||
@ -248,9 +341,8 @@ void EmitCImp::emitCoverageDecl(AstNodeModule*) {
|
||||
|
||||
void EmitCImp::emitCtorImp(AstNodeModule* modp) {
|
||||
puts("\n");
|
||||
bool first = true;
|
||||
string section;
|
||||
emitParams(modp, true, &first, section /*ref*/);
|
||||
emitParams(modp, true, section);
|
||||
|
||||
const string modName = prefixNameProtect(modp);
|
||||
|
||||
@ -264,9 +356,8 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) {
|
||||
} else {
|
||||
puts(modName + "::" + modName + "(const char* _vcname__)\n");
|
||||
puts(" : VerilatedModule(_vcname__)\n");
|
||||
first = false; // printed the first ':'
|
||||
}
|
||||
emitVarCtors(&first);
|
||||
emitVarCtors(modp);
|
||||
|
||||
puts(" {\n");
|
||||
|
||||
@ -500,15 +591,8 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||
|
||||
emitTypedefs(modp->stmtsp());
|
||||
|
||||
string section;
|
||||
section = "\n// PORTS\n";
|
||||
emitVarList(modp->stmtsp(), EVL_CLASS_IO, "", section /*ref*/);
|
||||
|
||||
section = "\n// LOCAL SIGNALS\n";
|
||||
emitVarList(modp->stmtsp(), EVL_CLASS_SIG, "", section /*ref*/);
|
||||
|
||||
section = "\n// LOCAL VARIABLES\n";
|
||||
emitVarList(modp->stmtsp(), EVL_CLASS_TEMP, "", section /*ref*/);
|
||||
puts("\n// DESIGN SPECIFIC STATE\n");
|
||||
emitVarDecls(modp);
|
||||
|
||||
puts("\n// INTERNAL VARIABLES\n");
|
||||
if (!VN_IS(modp, Class)) { // Avoid clang unused error (& don't want in every object)
|
||||
@ -518,12 +602,10 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||
ofp()->putsPrivate(false); // public:
|
||||
emitCoverageDecl(modp); // may flip public/private
|
||||
|
||||
section = "\n// PARAMETERS\n";
|
||||
ofp()->putsPrivate(false); // public:
|
||||
emitVarList(modp->stmtsp(), EVL_CLASS_PAR, "",
|
||||
section /*ref*/); // Only those that are non-CONST
|
||||
bool first = true;
|
||||
emitParams(modp, false, &first, section /*ref*/);
|
||||
{
|
||||
string section = "\n// PARAMETERS\n";
|
||||
emitParams(modp, false, section);
|
||||
}
|
||||
|
||||
if (!VN_IS(modp, Class)) {
|
||||
puts("\n// CONSTRUCTORS\n");
|
||||
@ -588,8 +670,16 @@ void EmitCImp::emitImpTop() {
|
||||
void EmitCImp::emitImp(AstNodeModule* modp) {
|
||||
puts("\n//==========\n");
|
||||
if (m_slow) {
|
||||
string section;
|
||||
emitVarList(modp->stmtsp(), EVL_CLASS_ALL, prefixNameProtect(modp), section /*ref*/);
|
||||
// Emit static variable definitions
|
||||
const string prefix = prefixNameProtect(modp);
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
|
||||
if (varp->isStatic()) {
|
||||
puts(varp->vlArgType(true, false, false, prefix));
|
||||
puts(";\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!VN_IS(modp, Class)) emitCtorImp(modp);
|
||||
if (!VN_IS(modp, Class)) emitConfigureImp(modp);
|
||||
if (!VN_IS(modp, Class)) emitDestructorImp(modp);
|
||||
|
@ -114,7 +114,7 @@ void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule*
|
||||
if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n");
|
||||
}
|
||||
|
||||
void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfImp, bool asRef) {
|
||||
void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
|
||||
const AstBasicDType* const basicp = nodep->basicp();
|
||||
bool refNeedParens = VN_IS(nodep->dtypeSkipRefp(), UnpackArrayDType);
|
||||
|
||||
@ -199,7 +199,7 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfIm
|
||||
&& name.substr(name.size() - suffix.size()) == suffix;
|
||||
if (beStatic) puts("static VL_THREAD_LOCAL ");
|
||||
}
|
||||
puts(nodep->vlArgType(true, false, false, prefixIfImp, asRef));
|
||||
puts(nodep->vlArgType(true, false, false, "", asRef));
|
||||
puts(";\n");
|
||||
}
|
||||
}
|
||||
|
@ -75,11 +75,18 @@ public:
|
||||
return modp == v3Global.rootp()->constPoolp()->modp();
|
||||
}
|
||||
|
||||
static bool isAnonOk(const AstVar* varp) {
|
||||
return v3Global.opt.compLimitMembers() != 0 // Enabled
|
||||
&& !varp->isStatic() // Not a static variable
|
||||
&& !varp->isSc() // Aggregates can't be anon
|
||||
&& (varp->basicp() && !varp->basicp()->isOpaque()); // Aggregates can't be anon
|
||||
}
|
||||
|
||||
static AstCFile* newCFile(const string& filename, bool slow, bool source);
|
||||
string cFuncArgs(const AstCFunc* nodep);
|
||||
void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope);
|
||||
void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false);
|
||||
void emitVarDecl(const AstVar* nodep, const string& prefixIfImp, bool asRef = false);
|
||||
void emitVarDecl(const AstVar* nodep, bool asRef = false);
|
||||
void emitModCUse(AstNodeModule* modp, VUseType useType);
|
||||
|
||||
// CONSTRUCTORS
|
||||
|
@ -28,90 +28,9 @@
|
||||
// We use a static char array in VL_VALUE_STRING
|
||||
constexpr int VL_VALUE_STRING_MAX_WIDTH = 8192;
|
||||
|
||||
//######################################################################
|
||||
// Establish mtask variable sort order in mtasks mode
|
||||
|
||||
class EmitVarTspSorter final : public V3TSP::TspStateBase {
|
||||
private:
|
||||
// MEMBERS
|
||||
const MTaskIdSet& m_mtaskIds; // Mtask we're ordering
|
||||
static unsigned s_serialNext; // Unique ID to establish serial order
|
||||
unsigned m_serial; // Serial ordering
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit EmitVarTspSorter(const MTaskIdSet& mtaskIds)
|
||||
: m_mtaskIds(mtaskIds) { // Cannot be {} or GCC 4.8 false warning
|
||||
m_serial = ++s_serialNext; // Cannot be ()/{} or GCC 4.8 false warning
|
||||
}
|
||||
virtual ~EmitVarTspSorter() = default;
|
||||
// METHODS
|
||||
virtual bool operator<(const TspStateBase& other) const override {
|
||||
return operator<(dynamic_cast<const EmitVarTspSorter&>(other));
|
||||
}
|
||||
bool operator<(const EmitVarTspSorter& other) const { return m_serial < other.m_serial; }
|
||||
const MTaskIdSet& mtaskIds() const { return m_mtaskIds; }
|
||||
virtual int cost(const TspStateBase* otherp) const override {
|
||||
return cost(dynamic_cast<const EmitVarTspSorter*>(otherp));
|
||||
}
|
||||
virtual int cost(const EmitVarTspSorter* otherp) const {
|
||||
int cost = diffs(m_mtaskIds, otherp->m_mtaskIds);
|
||||
cost += diffs(otherp->m_mtaskIds, m_mtaskIds);
|
||||
return cost;
|
||||
}
|
||||
// Returns the number of elements in set_a that don't appear in set_b
|
||||
static int diffs(const MTaskIdSet& set_a, const MTaskIdSet& set_b) {
|
||||
int diffs = 0;
|
||||
for (int i : set_a) {
|
||||
if (set_b.find(i) == set_b.end()) ++diffs;
|
||||
}
|
||||
return diffs;
|
||||
}
|
||||
};
|
||||
|
||||
unsigned EmitVarTspSorter::s_serialNext = 0;
|
||||
|
||||
//######################################################################
|
||||
// EmitCFunc
|
||||
|
||||
void EmitCFunc::emitCtorSep(bool* firstp) {
|
||||
if (*firstp) {
|
||||
puts(" : ");
|
||||
*firstp = false;
|
||||
} else {
|
||||
puts(", ");
|
||||
}
|
||||
if (ofp()->exceededWidth()) puts("\n ");
|
||||
}
|
||||
|
||||
void EmitCFunc::emitVarCtors(bool* firstp) {
|
||||
if (!m_ctorVarsVec.empty()) {
|
||||
ofp()->indentInc();
|
||||
if (*firstp) puts("\n");
|
||||
for (const AstVar* varp : m_ctorVarsVec) {
|
||||
const AstBasicDType* const dtypep = VN_CAST(varp->dtypeSkipRefp(), BasicDType);
|
||||
if (!dtypep) {
|
||||
puts("// Skipping array: ");
|
||||
puts(varp->nameProtect());
|
||||
puts("\n");
|
||||
} else if (dtypep->keyword().isMTaskState()) {
|
||||
emitCtorSep(firstp);
|
||||
puts(varp->nameProtect());
|
||||
puts("(");
|
||||
iterate(varp->valuep());
|
||||
puts(")");
|
||||
} else {
|
||||
emitCtorSep(firstp);
|
||||
puts(varp->nameProtect());
|
||||
puts("(");
|
||||
putsQuoted(varp->nameProtect());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
puts("\n");
|
||||
ofp()->indentDec();
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitCFunc::emitSimpleOk(AstNodeMath* nodep) {
|
||||
// Can we put out a simple (A + B) instead of VL_ADD_III(A,B)?
|
||||
if (nodep->emitSimpleOperator() == "") return false;
|
||||
@ -514,192 +433,6 @@ void EmitCFunc::displayNode(AstNode* nodep, AstScopeName* scopenamep, const stri
|
||||
displayEmit(nodep, isScan);
|
||||
}
|
||||
|
||||
void EmitCFunc::emitVarList(AstNode* firstp, EisWhich which, const string& prefixIfImp,
|
||||
string& sectionr) {
|
||||
// Put out a list of signal declarations
|
||||
// in order of 0:clocks, 1:vluint8, 2:vluint16, 4:vluint32, 5:vluint64, 6:wide, 7:arrays
|
||||
// This aids cache packing and locality
|
||||
//
|
||||
// Largest->smallest reduces the number of pad variables. Also
|
||||
// experimented with alternating between large->small and small->large
|
||||
// on successive Mtask groups, but then when a new mtask gets added may
|
||||
// cause a huge delta.
|
||||
//
|
||||
// TODO: Move this sort to an earlier visitor stage.
|
||||
VarSortMap varAnonMap;
|
||||
VarSortMap varNonanonMap;
|
||||
|
||||
for (int isstatic = 1; isstatic >= 0; isstatic--) {
|
||||
if (prefixIfImp != "" && !isstatic) continue;
|
||||
for (AstNode* nodep = firstp; nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* varp = VN_CAST(nodep, Var)) {
|
||||
bool doit = true;
|
||||
switch (which) {
|
||||
case EVL_CLASS_IO: doit = varp->isIO(); break;
|
||||
case EVL_CLASS_SIG:
|
||||
doit = ((varp->isSignal() || varp->isClassMember()) && !varp->isIO());
|
||||
break;
|
||||
case EVL_CLASS_TEMP: doit = (varp->isTemp() && !varp->isIO()); break;
|
||||
case EVL_CLASS_PAR:
|
||||
doit = (varp->isParam() && !VN_IS(varp->valuep(), Const));
|
||||
break;
|
||||
case EVL_CLASS_ALL: doit = true; break;
|
||||
default: v3fatalSrc("Bad Case");
|
||||
}
|
||||
if (varp->isStatic() ? !isstatic : isstatic) doit = false;
|
||||
if (doit) {
|
||||
const int sigbytes = varp->dtypeSkipRefp()->widthAlignBytes();
|
||||
int sortbytes = 9;
|
||||
if (varp->isUsedClock() && varp->widthMin() == 1) {
|
||||
sortbytes = 0;
|
||||
} else if (VN_IS(varp->dtypeSkipRefp(), UnpackArrayDType)) {
|
||||
sortbytes = 8;
|
||||
} else if (varp->basicp() && varp->basicp()->isOpaque()) {
|
||||
sortbytes = 7;
|
||||
} else if (varp->isScBv() || varp->isScBigUint()) {
|
||||
sortbytes = 6;
|
||||
} else if (sigbytes == 8) {
|
||||
sortbytes = 5;
|
||||
} else if (sigbytes == 4) {
|
||||
sortbytes = 4;
|
||||
} else if (sigbytes == 2) {
|
||||
sortbytes = 2;
|
||||
} else if (sigbytes == 1) {
|
||||
sortbytes = 1;
|
||||
}
|
||||
const bool anonOk
|
||||
= (v3Global.opt.compLimitMembers() != 0 // Enabled
|
||||
&& !varp->isStatic() && !varp->isIO() // Confusing to user
|
||||
&& !varp->isSc() // Aggregates can't be anon
|
||||
&& (varp->basicp()
|
||||
&& !varp->basicp()->isOpaque()) // Aggregates can't be anon
|
||||
);
|
||||
|
||||
if (anonOk) {
|
||||
varAnonMap[sortbytes].push_back(varp);
|
||||
} else {
|
||||
varNonanonMap[sortbytes].push_back(varp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!varAnonMap.empty() || !varNonanonMap.empty()) {
|
||||
if (!sectionr.empty()) {
|
||||
puts(sectionr);
|
||||
sectionr = "";
|
||||
}
|
||||
VarVec anons;
|
||||
VarVec nonanons;
|
||||
emitVarSort(varAnonMap, &anons);
|
||||
emitVarSort(varNonanonMap, &nonanons);
|
||||
emitSortedVarList(anons, nonanons, prefixIfImp);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitCFunc::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) {
|
||||
UASSERT(sortedp->empty(), "Sorted should be initially empty");
|
||||
if (!v3Global.opt.mtasks()) {
|
||||
// Plain old serial mode. Sort by size, from small to large,
|
||||
// to optimize for both packing and small offsets in code.
|
||||
for (const auto& itr : vmap) {
|
||||
for (VarVec::const_iterator jt = itr.second.begin(); jt != itr.second.end(); ++jt) {
|
||||
sortedp->push_back(*jt);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// MacroTask mode. Sort by MTask-affinity group first, size second.
|
||||
using MTaskVarSortMap = std::map<const MTaskIdSet, VarSortMap>;
|
||||
MTaskVarSortMap m2v;
|
||||
for (VarSortMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) {
|
||||
const int size_class = it->first;
|
||||
const VarVec& vec = it->second;
|
||||
for (const AstVar* varp : vec) { m2v[varp->mtaskIds()][size_class].push_back(varp); }
|
||||
}
|
||||
|
||||
// Create a TSP sort state for each MTaskIdSet footprint
|
||||
V3TSP::StateVec states;
|
||||
for (MTaskVarSortMap::iterator it = m2v.begin(); it != m2v.end(); ++it) {
|
||||
states.push_back(new EmitVarTspSorter(it->first));
|
||||
}
|
||||
|
||||
// Do the TSP sort
|
||||
V3TSP::StateVec sorted_states;
|
||||
V3TSP::tspSort(states, &sorted_states);
|
||||
|
||||
for (V3TSP::StateVec::iterator it = sorted_states.begin(); it != sorted_states.end(); ++it) {
|
||||
const EmitVarTspSorter* statep = dynamic_cast<const EmitVarTspSorter*>(*it);
|
||||
const VarSortMap& localVmap = m2v[statep->mtaskIds()];
|
||||
// use rbegin/rend to sort size large->small
|
||||
for (VarSortMap::const_reverse_iterator jt = localVmap.rbegin(); jt != localVmap.rend();
|
||||
++jt) {
|
||||
const VarVec& vec = jt->second;
|
||||
for (VarVec::const_iterator kt = vec.begin(); kt != vec.end(); ++kt) {
|
||||
sortedp->push_back(*kt);
|
||||
}
|
||||
}
|
||||
VL_DO_DANGLING(delete statep, statep);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitCFunc::emitSortedVarList(const VarVec& anons, const VarVec& nonanons,
|
||||
const string& prefixIfImp) {
|
||||
string curVarCmt;
|
||||
// Output anons
|
||||
{
|
||||
const int anonMembers = anons.size();
|
||||
const int lim = v3Global.opt.compLimitMembers();
|
||||
int anonL3s = 1;
|
||||
int anonL2s = 1;
|
||||
int anonL1s = 1;
|
||||
if (anonMembers > (lim * lim * lim)) {
|
||||
anonL3s = (anonMembers + (lim * lim * lim) - 1) / (lim * lim * lim);
|
||||
anonL2s = lim;
|
||||
anonL1s = lim;
|
||||
} else if (anonMembers > (lim * lim)) {
|
||||
anonL2s = (anonMembers + (lim * lim) - 1) / (lim * lim);
|
||||
anonL1s = lim;
|
||||
} else if (anonMembers > lim) {
|
||||
anonL1s = (anonMembers + lim - 1) / lim;
|
||||
}
|
||||
if (anonL1s != 1)
|
||||
puts("// Anonymous structures to workaround compiler member-count bugs\n");
|
||||
auto it = anons.cbegin();
|
||||
for (int l3 = 0; l3 < anonL3s && it != anons.cend(); ++l3) {
|
||||
if (anonL3s != 1) puts("struct {\n");
|
||||
for (int l2 = 0; l2 < anonL2s && it != anons.cend(); ++l2) {
|
||||
if (anonL2s != 1) puts("struct {\n");
|
||||
for (int l1 = 0; l1 < anonL1s && it != anons.cend(); ++l1) {
|
||||
if (anonL1s != 1) puts("struct {\n");
|
||||
for (int l0 = 0; l0 < lim && it != anons.cend(); ++l0) {
|
||||
const AstVar* varp = *it;
|
||||
emitVarDecl(varp, prefixIfImp);
|
||||
++it;
|
||||
}
|
||||
if (anonL1s != 1) puts("};\n");
|
||||
}
|
||||
if (anonL2s != 1) puts("};\n");
|
||||
}
|
||||
if (anonL3s != 1) puts("};\n");
|
||||
}
|
||||
// Leftovers, just in case off by one error somewhere above
|
||||
for (; it != anons.end(); ++it) {
|
||||
const AstVar* varp = *it;
|
||||
emitVarDecl(varp, prefixIfImp);
|
||||
}
|
||||
}
|
||||
// Output nonanons
|
||||
for (const AstVar* varp : nonanons) {
|
||||
if (varp->isIO() && varp->isSc()) { m_ctorVarsVec.push_back(varp); }
|
||||
AstBasicDType* const basicp = varp->basicp();
|
||||
if (basicp && basicp->keyword().isMTaskState()) { m_ctorVarsVec.push_back(varp); }
|
||||
emitVarDecl(varp, prefixIfImp);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitCFunc::emitCCallArgs(AstNodeCCall* nodep) {
|
||||
bool comma = false;
|
||||
if (nodep->funcp()->isLoose() && !nodep->funcp()->isStatic()) {
|
||||
|
@ -114,12 +114,8 @@ public:
|
||||
|
||||
class EmitCFunc VL_NOT_FINAL : public EmitCBaseVisitor {
|
||||
private:
|
||||
using VarVec = std::vector<const AstVar*>;
|
||||
using VarSortMap = std::map<int, VarVec>; // Map size class to VarVec
|
||||
|
||||
bool m_suppressSemi;
|
||||
AstVarRef* m_wideTempRefp; // Variable that _WW macros should be setting
|
||||
VarVec m_ctorVarsVec; // All variables in constructor order
|
||||
int m_labelNum; // Next label number
|
||||
int m_splitSize; // # of cfunc nodes placed into output file
|
||||
int m_splitFilenum; // File number being created, 0 = primary
|
||||
@ -155,18 +151,6 @@ public:
|
||||
void displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const string& vfmt, bool ignore,
|
||||
char fmtLetter);
|
||||
|
||||
enum EisWhich : uint8_t {
|
||||
EVL_CLASS_IO,
|
||||
EVL_CLASS_SIG,
|
||||
EVL_CLASS_TEMP,
|
||||
EVL_CLASS_PAR,
|
||||
EVL_CLASS_ALL
|
||||
};
|
||||
void emitVarList(AstNode* firstp, EisWhich which, const string& prefixIfImp, string& sectionr);
|
||||
static void emitVarSort(const VarSortMap& vmap, VarVec* sortedp);
|
||||
void emitSortedVarList(const VarVec& anons, const VarVec& nonanons, const string& prefixIfImp);
|
||||
void emitVarCtors(bool* firstp);
|
||||
void emitCtorSep(bool* firstp);
|
||||
bool emitSimpleOk(AstNodeMath* nodep);
|
||||
void emitIQW(AstNode* nodep) {
|
||||
// Other abbrevs: "C"har, "S"hort, "F"loat, "D"ouble, stri"N"g
|
||||
@ -242,7 +226,7 @@ public:
|
||||
|
||||
for (AstNode* subnodep = nodep->argsp(); subnodep; subnodep = subnodep->nextp()) {
|
||||
if (AstVar* varp = VN_CAST(subnodep, Var)) {
|
||||
if (varp->isFuncReturn()) emitVarDecl(varp, "");
|
||||
if (varp->isFuncReturn()) emitVarDecl(varp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,7 +255,7 @@ public:
|
||||
|
||||
virtual void visit(AstVar* nodep) override {
|
||||
UASSERT_OBJ(m_cfuncp, nodep, "Cannot emit non-local variable");
|
||||
emitVarDecl(nodep, "");
|
||||
emitVarDecl(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
|
@ -90,7 +90,7 @@ class EmitCModel final : public EmitCFunc {
|
||||
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
|
||||
if (varp->isPrimaryIO()) { //
|
||||
emitVarDecl(varp, "", /* asRef: */ true);
|
||||
emitVarDecl(varp, /* asRef: */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
207
src/V3VariableOrder.cpp
Normal file
207
src/V3VariableOrder.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Variable ordering
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2021 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3VariableOrder's Transformations:
|
||||
//
|
||||
// Each module:
|
||||
// Order module variables
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3VariableOrder.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3AstUserAllocator.h"
|
||||
#include "V3EmitCBase.h"
|
||||
#include "V3TSP.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
//######################################################################
|
||||
// Establish mtask variable sort order in mtasks mode
|
||||
|
||||
class VarTspSorter final : public V3TSP::TspStateBase {
|
||||
private:
|
||||
// MEMBERS
|
||||
const MTaskIdSet& m_mtaskIds; // Mtask we're ordering
|
||||
static unsigned s_serialNext; // Unique ID to establish serial order
|
||||
unsigned m_serial; // Serial ordering
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit VarTspSorter(const MTaskIdSet& mtaskIds)
|
||||
: m_mtaskIds(mtaskIds) { // Cannot be {} or GCC 4.8 false warning
|
||||
m_serial = ++s_serialNext; // Cannot be ()/{} or GCC 4.8 false warning
|
||||
}
|
||||
virtual ~VarTspSorter() = default;
|
||||
// METHODS
|
||||
virtual bool operator<(const TspStateBase& other) const override {
|
||||
return operator<(dynamic_cast<const VarTspSorter&>(other));
|
||||
}
|
||||
bool operator<(const VarTspSorter& other) const { return m_serial < other.m_serial; }
|
||||
const MTaskIdSet& mtaskIds() const { return m_mtaskIds; }
|
||||
virtual int cost(const TspStateBase* otherp) const override {
|
||||
return cost(dynamic_cast<const VarTspSorter*>(otherp));
|
||||
}
|
||||
virtual int cost(const VarTspSorter* otherp) const {
|
||||
int cost = diffs(m_mtaskIds, otherp->m_mtaskIds);
|
||||
cost += diffs(otherp->m_mtaskIds, m_mtaskIds);
|
||||
return cost;
|
||||
}
|
||||
// Returns the number of elements in set_a that don't appear in set_b
|
||||
static int diffs(const MTaskIdSet& set_a, const MTaskIdSet& set_b) {
|
||||
int diffs = 0;
|
||||
for (int i : set_a) {
|
||||
if (set_b.find(i) == set_b.end()) ++diffs;
|
||||
}
|
||||
return diffs;
|
||||
}
|
||||
};
|
||||
|
||||
unsigned VarTspSorter::s_serialNext = 0;
|
||||
|
||||
class VariableOrder final {
|
||||
// NODE STATE
|
||||
// AstVar::user1() -> attributes, via m_attributes
|
||||
AstUser1InUse m_user1InUse; // AstVar
|
||||
|
||||
struct VarAttributes {
|
||||
uint32_t stratum; // Roughly equivalent to alignment requirement, to avoid padding
|
||||
bool anonOk; // Can be emitted as part of anonymous structure
|
||||
};
|
||||
|
||||
AstUser1Allocator<AstVar, VarAttributes> m_attributes; // Attributes used for sorting
|
||||
|
||||
//######################################################################
|
||||
|
||||
// Simple sort
|
||||
void simpleSortVars(std::vector<AstVar*>& varps) {
|
||||
stable_sort(varps.begin(), varps.end(),
|
||||
[this](const AstVar* ap, const AstVar* bp) -> bool {
|
||||
if (ap->isStatic() != bp->isStatic()) { // Non-statics before statics
|
||||
return bp->isStatic();
|
||||
}
|
||||
const auto& attrA = m_attributes(ap);
|
||||
const auto& attrB = m_attributes(bp);
|
||||
if (attrA.anonOk != attrB.anonOk) { // Anons before non-anons
|
||||
return attrA.anonOk;
|
||||
}
|
||||
return attrA.stratum < attrB.stratum; // Finally sort by stratum
|
||||
});
|
||||
}
|
||||
|
||||
// Sort by MTask-affinity first, then the same as simpleSortVars
|
||||
void tspSortVars(std::vector<AstVar*>& varps) {
|
||||
// Map from "MTask affinity" -> "variable list"
|
||||
std::map<const MTaskIdSet, std::vector<AstVar*>> m2v;
|
||||
for (AstVar* const varp : varps) { m2v[varp->mtaskIds()].push_back(varp); }
|
||||
|
||||
// Create a TSP sort state for each unique MTaskIdSet, except for the empty set
|
||||
V3TSP::StateVec states;
|
||||
for (const auto& pair : m2v) {
|
||||
if (pair.first.empty()) continue;
|
||||
states.push_back(new VarTspSorter(pair.first));
|
||||
}
|
||||
|
||||
// Do the TSP sort
|
||||
V3TSP::StateVec sortedStates;
|
||||
V3TSP::tspSort(states, &sortedStates);
|
||||
|
||||
varps.clear();
|
||||
|
||||
// Helper function to sort given vector, then append to 'varps'
|
||||
const auto sortAndAppend = [this, &varps](std::vector<AstVar*>& subVarps) {
|
||||
simpleSortVars(subVarps);
|
||||
for (AstVar* const varp : subVarps) { varps.push_back(varp); }
|
||||
};
|
||||
|
||||
// Enumerate by sorted MTaskIdSet, sort within the set separately
|
||||
for (const V3TSP::TspStateBase* const stateBasep : sortedStates) {
|
||||
const VarTspSorter* const statep = dynamic_cast<const VarTspSorter*>(stateBasep);
|
||||
sortAndAppend(m2v[statep->mtaskIds()]);
|
||||
VL_DO_DANGLING(delete statep, statep);
|
||||
}
|
||||
|
||||
// Finally add the variables with no known MTask affinity
|
||||
sortAndAppend(m2v[MTaskIdSet()]);
|
||||
}
|
||||
|
||||
void orderModuleVars(AstNodeModule* modp) {
|
||||
std::vector<AstVar*> varps;
|
||||
|
||||
// Unlink all module variables from the module, compute attributes
|
||||
for (AstNode *nodep = modp->stmtsp(), *nextp; nodep; nodep = nextp) {
|
||||
nextp = nodep->nextp();
|
||||
if (AstVar* const varp = VN_CAST(nodep, Var)) {
|
||||
// Unlink, add to vector
|
||||
varp->unlinkFrBack();
|
||||
varps.push_back(varp);
|
||||
// Compute attributes up front
|
||||
auto& attributes = m_attributes(varp);
|
||||
// Stratum
|
||||
const int sigbytes = varp->dtypeSkipRefp()->widthAlignBytes();
|
||||
attributes.stratum = (varp->isUsedClock() && varp->widthMin() == 1) ? 0
|
||||
: VN_IS(varp->dtypeSkipRefp(), UnpackArrayDType) ? 8
|
||||
: (varp->basicp() && varp->basicp()->isOpaque()) ? 7
|
||||
: (varp->isScBv() || varp->isScBigUint()) ? 6
|
||||
: (sigbytes == 8) ? 5
|
||||
: (sigbytes == 4) ? 4
|
||||
: (sigbytes == 2) ? 2
|
||||
: (sigbytes == 1) ? 1
|
||||
: 9;
|
||||
// Anonymous structure ok
|
||||
attributes.anonOk = EmitCBaseVisitor::isAnonOk(varp);
|
||||
}
|
||||
}
|
||||
|
||||
if (!varps.empty()) {
|
||||
// Sort variables
|
||||
if (!v3Global.opt.mtasks()) {
|
||||
simpleSortVars(varps);
|
||||
} else {
|
||||
tspSortVars(varps);
|
||||
}
|
||||
|
||||
// Insert them back under the module, in the new order, but at
|
||||
// the front of the list so they come out first in dumps/XML.
|
||||
auto it = varps.cbegin();
|
||||
AstVar* const firstp = *it++;
|
||||
for (; it != varps.cend(); ++it) firstp->addNext(*it);
|
||||
if (AstNode* const stmtsp = modp->stmtsp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
firstp->addNext(stmtsp);
|
||||
}
|
||||
modp->addStmtp(firstp);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static void processModule(AstNodeModule* modp) { VariableOrder().orderModuleVars(modp); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// V3VariableOrder static functions
|
||||
|
||||
void V3VariableOrder::orderAll() {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
|
||||
modp = VN_CAST(modp->nextp(), NodeModule)) {
|
||||
VariableOrder::processModule(modp);
|
||||
}
|
||||
V3Global::dumpCheckGlobalTree("variableorder", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
30
src/V3VariableOrder.h
Normal file
30
src/V3VariableOrder.h
Normal file
@ -0,0 +1,30 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Variable ordering
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2021 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3VARIABLEORDER_H_
|
||||
#define VERILATOR_V3VARIABLEORDER_H_
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3VariableOrder final {
|
||||
public:
|
||||
static void orderAll();
|
||||
};
|
||||
|
||||
#endif // Guard
|
@ -96,6 +96,7 @@
|
||||
#include "V3Undriven.h"
|
||||
#include "V3Unknown.h"
|
||||
#include "V3Unroll.h"
|
||||
#include "V3VariableOrder.h"
|
||||
#include "V3Waiver.h"
|
||||
#include "V3Width.h"
|
||||
|
||||
@ -507,6 +508,9 @@ static void process() {
|
||||
// Must be before V3EmitC
|
||||
V3CUse::cUseAll();
|
||||
|
||||
// Order variables
|
||||
V3VariableOrder::orderAll();
|
||||
|
||||
// emitcInlines is first, as it may set needHInlines which other emitters read
|
||||
V3EmitC::emitcInlines();
|
||||
V3EmitC::emitcSyms();
|
||||
|
@ -18,10 +18,10 @@ compile(
|
||||
);
|
||||
|
||||
if ($Self->{vlt_all}) {
|
||||
file_grep("$out_filename", qr/\<var fl="d56" loc=".*?" name="formatted" dtype_id="4" dir="input" vartype="string" origName="formatted" sformat="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d77" loc=".*?" name="t.sub.in" dtype_id="3" vartype="int" origName="in" public="true" public_flat_rd="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d78" loc=".*?" name="t.sub.fr_a" dtype_id="3" vartype="int" origName="fr_a" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d79" loc=".*?" name="t.sub.fr_b" dtype_id="3" vartype="int" origName="fr_b" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d56" loc=".*?" name="formatted" dtype_id="\d+" dir="input" vartype="string" origName="formatted" sformat="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d77" loc=".*?" name="t.sub.in" dtype_id="\d+" vartype="int" origName="in" public="true" public_flat_rd="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d78" loc=".*?" name="t.sub.fr_a" dtype_id="\d+" vartype="int" origName="fr_a" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d79" loc=".*?" name="t.sub.fr_b" dtype_id="\d+" vartype="int" origName="fr_b" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
|
||||
}
|
||||
|
||||
execute(
|
||||
|
@ -20,10 +20,10 @@ compile(
|
||||
);
|
||||
|
||||
if ($Self->{vlt_all}) {
|
||||
file_grep("$out_filename", qr/\<var fl="e58" loc=".*?" name="formatted" dtype_id="4" dir="input" vartype="string" origName="formatted" sformat="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e81" loc=".*?" name="t.sub.in" dtype_id="3" vartype="int" origName="in" public="true" public_flat_rd="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e82" loc=".*?" name="t.sub.fr_a" dtype_id="3" vartype="int" origName="fr_a" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e83" loc=".*?" name="t.sub.fr_b" dtype_id="3" vartype="int" origName="fr_b" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e58" loc=".*?" name="formatted" dtype_id="\d+" dir="input" vartype="string" origName="formatted" sformat="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e81" loc=".*?" name="t.sub.in" dtype_id="\d+" vartype="int" origName="in" public="true" public_flat_rd="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e82" loc=".*?" name="t.sub.fr_a" dtype_id="\d+" vartype="int" origName="fr_a" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e83" loc=".*?" name="t.sub.fr_b" dtype_id="\d+" vartype="int" origName="fr_b" public="true" public_flat_rd="true" public_flat_rw="true"\/\>/i);
|
||||
}
|
||||
|
||||
execute(
|
||||
|
@ -18,9 +18,9 @@ compile(
|
||||
);
|
||||
|
||||
if ($Self->{vlt_all}) {
|
||||
file_grep("$out_filename", qr/\<var fl="e70" loc=".*?" name="t.u.u0.u0.z1" dtype_id="3" vartype="logic" origName="z1"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e70" loc=".*?" name="t.u.u0.u1.z1" dtype_id="3" vartype="logic" origName="z1"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e70" loc=".*?" name="t.u.u1.u0.z0" dtype_id="3" vartype="logic" origName="z0"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e70" loc=".*?" name="t.u.u0.u0.z1" dtype_id="\d+" vartype="logic" origName="z1"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e70" loc=".*?" name="t.u.u0.u1.z1" dtype_id="\d+" vartype="logic" origName="z1"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e70" loc=".*?" name="t.u.u1.u0.z0" dtype_id="\d+" vartype="logic" origName="z0"\/\>/i);
|
||||
}
|
||||
|
||||
execute(
|
||||
|
@ -19,11 +19,11 @@ compile(
|
||||
|
||||
if ($Self->{vlt_all}) {
|
||||
file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+5/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d23" loc=".*?" name="t.b" dtype_id="4" vartype="logic" origName="b" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d99" loc=".*?" name="__Vfunc_t.file.get_31_16__0__Vfuncout" dtype_id="5" vartype="logic" origName="__Vfunc_t__DOT__file__DOT__get_31_16__0__Vfuncout" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d100" loc=".*?" name="__Vfunc_t.file.get_31_16__0__t_crc" dtype_id="4" vartype="logic" origName="__Vfunc_t__DOT__file__DOT__get_31_16__0__t_crc" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d112" loc=".*?" name="__Vtask_t.file.set_b_d__1__t_crc" dtype_id="4" vartype="logic" origName="__Vtask_t__DOT__file__DOT__set_b_d__1__t_crc" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d113" loc=".*?" name="__Vtask_t.file.set_b_d__1__t_c" dtype_id="4" vartype="logic" origName="__Vtask_t__DOT__file__DOT__set_b_d__1__t_c" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d23" loc=".*?" name="t.b" dtype_id="\d+" vartype="logic" origName="b" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d99" loc=".*?" name="__Vfunc_t.file.get_31_16__0__Vfuncout" dtype_id="\d+" vartype="logic" origName="__Vfunc_t__DOT__file__DOT__get_31_16__0__Vfuncout" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d100" loc=".*?" name="__Vfunc_t.file.get_31_16__0__t_crc" dtype_id="\d+" vartype="logic" origName="__Vfunc_t__DOT__file__DOT__get_31_16__0__t_crc" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d112" loc=".*?" name="__Vtask_t.file.set_b_d__1__t_crc" dtype_id="\d+" vartype="logic" origName="__Vtask_t__DOT__file__DOT__set_b_d__1__t_crc" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="d113" loc=".*?" name="__Vtask_t.file.set_b_d__1__t_c" dtype_id="\d+" vartype="logic" origName="__Vtask_t__DOT__file__DOT__set_b_d__1__t_c" isolate_assignments="true"\/\>/i);
|
||||
}
|
||||
|
||||
execute(
|
||||
|
@ -19,11 +19,11 @@ compile(
|
||||
|
||||
if ($Self->{vlt_all}) {
|
||||
file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+5/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e23" loc=".*?" name="t.b" dtype_id="4" vartype="logic" origName="b" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e104" loc=".*?" name="__Vfunc_t.file.get_31_16__0__Vfuncout" dtype_id="5" vartype="logic" origName="__Vfunc_t__DOT__file__DOT__get_31_16__0__Vfuncout" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e105" loc=".*?" name="__Vfunc_t.file.get_31_16__0__t_crc" dtype_id="4" vartype="logic" origName="__Vfunc_t__DOT__file__DOT__get_31_16__0__t_crc" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e115" loc=".*?" name="__Vtask_t.file.set_b_d__1__t_crc" dtype_id="4" vartype="logic" origName="__Vtask_t__DOT__file__DOT__set_b_d__1__t_crc" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e116" loc=".*?" name="__Vtask_t.file.set_b_d__1__t_c" dtype_id="4" vartype="logic" origName="__Vtask_t__DOT__file__DOT__set_b_d__1__t_c" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e23" loc=".*?" name="t.b" dtype_id="\d+" vartype="logic" origName="b" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e104" loc=".*?" name="__Vfunc_t.file.get_31_16__0__Vfuncout" dtype_id="\d+" vartype="logic" origName="__Vfunc_t__DOT__file__DOT__get_31_16__0__Vfuncout" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e105" loc=".*?" name="__Vfunc_t.file.get_31_16__0__t_crc" dtype_id="\d+" vartype="logic" origName="__Vfunc_t__DOT__file__DOT__get_31_16__0__t_crc" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e115" loc=".*?" name="__Vtask_t.file.set_b_d__1__t_crc" dtype_id="\d+" vartype="logic" origName="__Vtask_t__DOT__file__DOT__set_b_d__1__t_crc" isolate_assignments="true"\/\>/i);
|
||||
file_grep("$out_filename", qr/\<var fl="e116" loc=".*?" name="__Vtask_t.file.set_b_d__1__t_c" dtype_id="\d+" vartype="logic" origName="__Vtask_t__DOT__file__DOT__set_b_d__1__t_c" isolate_assignments="true"\/\>/i);
|
||||
}
|
||||
|
||||
execute(
|
||||
|
Loading…
Reference in New Issue
Block a user