mirror of
https://github.com/verilator/verilator.git
synced 2026-10-07 02:23:19 +02:00
Internals: Make the constant pool a regular package (#8512)
The constant pool is now an ordinary package, created with the netlist and instantiated under $root like any other package, and most special handling has been removed, including AstConstPool. Lookups go through V3ConstPool, which has a singleton instance owned by V3Global. Static methods on V3Common form the public interfce to add/find constant pool entries. With that, the constant pool is usable at any stage during compilation, so enum and dimension tables created by V3Width, and enum value tables created by V3Randomize now also live in the constant pool instead of $unit, so identical tables are shared. Associative array constants are handled separately from unpacked tables, which used to be broken but unused. Emitted constant pool variables use direct initialization, and `constinit` with C++20 where the type allows it. This ensures we don't change a run-time in a way that would result in unintended code size increase. -fno-merge-const-pool, which was introduced years ago but never prompted a bug report is deprecated and has no effect. This is also prep for future work.
This commit is contained in:
+131
-149
@@ -70,6 +70,7 @@
|
||||
#include "V3Ast.h"
|
||||
#include "V3Begin.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3ConstPool.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3LinkDotIfaceCapture.h"
|
||||
@@ -254,7 +255,6 @@ public:
|
||||
|
||||
class WidthVisitor final : public VNVisitor {
|
||||
// TYPES
|
||||
using TableMap = std::map<std::pair<const AstNodeDType*, VAttrType>, AstVar*>;
|
||||
using PatVecMap = std::map<int, AstPatMember*>;
|
||||
using DTypeMap = std::map<const std::string, AstPatMember*>;
|
||||
|
||||
@@ -285,10 +285,10 @@ class WidthVisitor final : public VNVisitor {
|
||||
const bool m_paramsOnly; // Computing parameter value; limit operation
|
||||
const bool m_doGenerate; // Do errors later inside generate statement
|
||||
bool m_streamConcat = false; // True if visiting arguments of stream concatenation
|
||||
int m_dtTables = 0; // Number of created data type tables
|
||||
TableMap m_tableMap; // Created tables so can remove duplicates
|
||||
std::map<const AstNodeDType*, AstQueueDType*>
|
||||
m_queueDTypeIndexed; // Queues with given index type
|
||||
// Created dimension and enum tables, mapped to a reference reading the table (always cloned)
|
||||
std::map<std::pair<const AstNodeDType*, VAttrType>, AstVarRef*> m_tableMap;
|
||||
// Queues with given index type
|
||||
std::map<const AstNodeDType*, AstQueueDType*> m_queueDTypeIndexed;
|
||||
ContainingClassFinder m_containingClassFinder;
|
||||
std::unordered_set<AstVar*> m_aliasedVars; // Variables referenced in alias
|
||||
std::unordered_set<const AstVar*> m_curModVars; // Variables declared in current module
|
||||
@@ -2542,10 +2542,9 @@ class WidthVisitor final : public VNVisitor {
|
||||
VL_DO_DANGLING(deleteTreeCaptured(nodep), nodep);
|
||||
} else { // Need a runtime lookup table. Yuk.
|
||||
UASSERT_OBJ(nodep->fromp() && dtypep, nodep, "Unsized expression");
|
||||
AstVar* const varp = dimensionVarp(dtypep, nodep->attrType(), msbdim);
|
||||
AstVarRef* const tabRefp = dimensionVarRefp(dtypep, nodep->attrType(), msbdim);
|
||||
AstNodeExpr* const dimp = nodep->dimp()->unlinkFrBack();
|
||||
AstNodeExpr* const newp
|
||||
= new AstArraySel{nodep->fileline(), newVarRefDollarUnit(varp), dimp};
|
||||
AstNodeExpr* const newp = new AstArraySel{nodep->fileline(), tabRefp, dimp};
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(deleteTreeCaptured(nodep), nodep);
|
||||
}
|
||||
@@ -10250,35 +10249,29 @@ class WidthVisitor final : public VNVisitor {
|
||||
<< ")=" << valp);
|
||||
return valp;
|
||||
}
|
||||
AstVar* dimensionVarp(AstNodeDType* nodep, VAttrType attrType, uint32_t msbdim) {
|
||||
// Return a variable table which has specified dimension properties for this variable
|
||||
const auto pair = m_tableMap.emplace(std::piecewise_construct, //
|
||||
std::forward_as_tuple(nodep, attrType),
|
||||
std::forward_as_tuple(nullptr));
|
||||
if (pair.second) {
|
||||
AstNodeArrayDType* const vardtypep
|
||||
= new AstUnpackArrayDType{nodep->fileline(), nodep->findIntDType(),
|
||||
new AstRange(nodep->fileline(), msbdim, 0)};
|
||||
AstInitArray* const initp = new AstInitArray{nodep->fileline(), vardtypep, nullptr};
|
||||
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
|
||||
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MODULETEMP,
|
||||
"__Vdimtab_" + VString::downcase(attrType.ascii())
|
||||
+ cvtToStr(m_dtTables++),
|
||||
vardtypep};
|
||||
varp->isConst(true);
|
||||
varp->isStatic(true);
|
||||
varp->valuep(initp);
|
||||
// Add to root, as don't know module we are in, and aids later structure sharing
|
||||
v3Global.rootp()->dollarUnitPkgp()->addStmtsp(varp);
|
||||
// Element 0 is a non-index and has speced values
|
||||
initp->addValuep(dimensionValue(nodep->fileline(), nodep, attrType, 0));
|
||||
for (unsigned i = 1; i < msbdim + 1; ++i) {
|
||||
initp->addValuep(dimensionValue(nodep->fileline(), nodep, attrType, i));
|
||||
}
|
||||
userIterate(varp, nullptr); // May have already done $unit so must do this var
|
||||
pair.first->second = varp;
|
||||
AstVarRef* dimensionVarRefp(AstNodeDType* nodep, VAttrType attrType, uint32_t msbdim) {
|
||||
// Return a reference to a constant table which has the specified dimension properties
|
||||
// for this data type. The reference is cached, so the table is built only once.
|
||||
AstVarRef*& cachedpr = m_tableMap[std::make_pair(nodep, attrType)];
|
||||
if (cachedpr) return cachedpr->cloneTree(false);
|
||||
|
||||
AstNodeArrayDType* const vardtypep = new AstUnpackArrayDType{
|
||||
nodep->fileline(), nodep->findIntDType(), new AstRange(nodep->fileline(), msbdim, 0)};
|
||||
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
|
||||
userIterate(vardtypep, WidthVP{SELF, BOTH}.p());
|
||||
AstInitArray* const initp = new AstInitArray{nodep->fileline(), vardtypep, nullptr};
|
||||
// Element 0 is a non-index and has speced values
|
||||
initp->addValuep(dimensionValue(nodep->fileline(), nodep, attrType, 0));
|
||||
for (unsigned i = 1; i < msbdim + 1; ++i) {
|
||||
initp->addValuep(dimensionValue(nodep->fileline(), nodep, attrType, i));
|
||||
}
|
||||
return pair.first->second;
|
||||
|
||||
// Share identical tables via the constant pool
|
||||
cachedpr = V3ConstPool::find(initp);
|
||||
VL_DO_DANGLING(initp->deleteTree(), initp); // V3ConstPool::find clones it
|
||||
cachedpr->varp()->didWidth(true);
|
||||
pushDeletep(cachedpr); // Deleted with the visitor - always cloned
|
||||
return cachedpr->cloneTree(false);
|
||||
}
|
||||
static uint64_t enumMaxValue(const AstNode* errNodep, const AstEnumDType* adtypep) {
|
||||
// Most enums unless overridden are 32 bits, so we size array
|
||||
@@ -10301,102 +10294,97 @@ class WidthVisitor final : public VNVisitor {
|
||||
}
|
||||
return maxval;
|
||||
}
|
||||
static AstVar* enumVarp(AstEnumDType* const nodep, VAttrType attrType, bool assoc,
|
||||
uint32_t msbdim) {
|
||||
// Return a variable table which has specified dimension properties for this variable
|
||||
const auto pair = nodep->tableMap().emplace(attrType, nullptr);
|
||||
if (pair.second) {
|
||||
UINFO(9, "Construct Venumtab attr=" << attrType.ascii() << " assoc=" << assoc
|
||||
<< " max=" << msbdim << " for " << nodep);
|
||||
AstNodeDType* basep;
|
||||
if (attrType == VAttrType::ENUM_NAME) {
|
||||
basep = nodep->findStringDType();
|
||||
} else if (attrType == VAttrType::ENUM_VALID) {
|
||||
// TODO in theory we could bit-pack the bits in the table, but
|
||||
// would require additional operations to extract, so only
|
||||
// would be worth it for larger tables which perhaps could be
|
||||
// better handled with equation generation?
|
||||
basep = nodep->findBitDType();
|
||||
} else {
|
||||
basep = nodep->dtypep();
|
||||
}
|
||||
AstNodeDType* vardtypep;
|
||||
if (assoc) {
|
||||
vardtypep = new AstAssocArrayDType{nodep->fileline(), basep, nodep};
|
||||
} else {
|
||||
vardtypep = new AstUnpackArrayDType{nodep->fileline(), basep,
|
||||
new AstRange(nodep->fileline(), msbdim, 0)};
|
||||
}
|
||||
AstInitArray* const initp = new AstInitArray{nodep->fileline(), vardtypep, nullptr};
|
||||
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
|
||||
// Rebuilt tables may coexist with live tables from earlier widthing.
|
||||
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MODULETEMP,
|
||||
"__Venumtab_" + VString::downcase(attrType.ascii())
|
||||
+ cvtToStr(AstNodeDType::uniqueNumInc()),
|
||||
vardtypep};
|
||||
varp->lifetime(VLifetime::STATIC_EXPLICIT);
|
||||
varp->isConst(true);
|
||||
varp->isStatic(true);
|
||||
varp->valuep(initp);
|
||||
// Add to root, as don't know module we are in, and aids later structure sharing
|
||||
v3Global.rootp()->dollarUnitPkgp()->addStmtsp(varp);
|
||||
AstVarRef* enumVarRefp(AstEnumDType* const nodep, VAttrType attrType, bool assoc,
|
||||
uint32_t msbdim) {
|
||||
// Return a reference to a constant table which has the specified attrType information
|
||||
// for this enum. The reference is cached, so the table is built only once.
|
||||
AstVarRef*& cachedpr = m_tableMap[std::make_pair(nodep, attrType)];
|
||||
if (cachedpr) return cachedpr->cloneTree(false);
|
||||
|
||||
// Default for all unspecified values
|
||||
if (attrType == VAttrType::ENUM_NAME) {
|
||||
initp->defaultp(new AstConst{nodep->fileline(), AstConst::String{}, ""});
|
||||
} else if (attrType == VAttrType::ENUM_NEXT || attrType == VAttrType::ENUM_PREV) {
|
||||
initp->defaultp(
|
||||
new AstConst{nodep->fileline(), V3Number{nodep, nodep->width(), 0}});
|
||||
} else if (attrType == VAttrType::ENUM_VALID) {
|
||||
initp->defaultp(new AstConst{nodep->fileline(), AstConst::BitFalse{}});
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad case");
|
||||
}
|
||||
|
||||
// Find valid values and populate
|
||||
UASSERT_OBJ(nodep->itemsp(), nodep, "enum without items");
|
||||
std::map<uint64_t, AstNodeExpr*> values;
|
||||
{
|
||||
uint64_t ordinal = 0;
|
||||
AstEnumItem* const firstp = nodep->itemsp();
|
||||
const AstEnumItem* prevp = firstp; // Prev must start with last item
|
||||
while (prevp->nextp()) prevp = VN_AS(prevp->nextp(), EnumItem);
|
||||
for (AstEnumItem* itemp = firstp; itemp;) {
|
||||
AstEnumItem* const nextp = VN_AS(itemp->nextp(), EnumItem);
|
||||
const AstConst* const vconstp = VN_AS(itemp->valuep(), Const);
|
||||
UASSERT_OBJ(vconstp, nodep, "Enum item without constified value");
|
||||
if (!vconstp->num().isAnyXZ()) { // Can 2-state runtime decode
|
||||
const uint64_t i = nodep->isWide() ? ++ordinal : vconstp->toUQuad();
|
||||
if (attrType == VAttrType::ENUM_NAME) {
|
||||
values[i] = new AstConst{nodep->fileline(), AstConst::String{},
|
||||
V3Number::displayedEnumName(itemp)};
|
||||
} else if (attrType == VAttrType::ENUM_NEXT) {
|
||||
values[i]
|
||||
= (nextp ? nextp : firstp)->valuep()->cloneTree(false); // A const
|
||||
} else if (attrType == VAttrType::ENUM_PREV) {
|
||||
values[i] = prevp->valuep()->cloneTree(false); // A const
|
||||
} else if (attrType == VAttrType::ENUM_VALID) {
|
||||
values[i] = new AstConst{nodep->fileline(), AstConst::BitTrue{}};
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad case");
|
||||
}
|
||||
}
|
||||
prevp = itemp;
|
||||
itemp = nextp;
|
||||
}
|
||||
}
|
||||
// Add all specified values to table
|
||||
if (assoc) {
|
||||
for (const auto& itr : values) initp->addIndexValuep(itr.first, itr.second);
|
||||
} else {
|
||||
for (uint64_t i = 0; i < (msbdim + 1); ++i) {
|
||||
if (values[i]) initp->addIndexValuep(i, values[i]);
|
||||
}
|
||||
}
|
||||
varp->didWidth(true); // May have already done $unit so must do this var
|
||||
pair.first->second = varp;
|
||||
UINFO(9, "Construct Venumtab attr=" << attrType.ascii() << " assoc=" << assoc
|
||||
<< " max=" << msbdim << " for " << nodep);
|
||||
AstNodeDType* basep;
|
||||
if (attrType == VAttrType::ENUM_NAME) {
|
||||
basep = nodep->findStringDType();
|
||||
} else if (attrType == VAttrType::ENUM_VALID) {
|
||||
// TODO in theory we could bit-pack the bits in the table, but
|
||||
// would require additional operations to extract, so only
|
||||
// would be worth it for larger tables which perhaps could be
|
||||
// better handled with equation generation?
|
||||
basep = nodep->findBitDType();
|
||||
} else {
|
||||
basep = nodep->dtypep();
|
||||
}
|
||||
return pair.first->second;
|
||||
AstNodeDType* vardtypep;
|
||||
if (assoc) {
|
||||
// Key by the base type of the enum, not the enum itself, so identical maps of
|
||||
// different enum types can be shared in the constant pool
|
||||
vardtypep = new AstAssocArrayDType{nodep->fileline(), basep, nodep->subDTypep()};
|
||||
} else {
|
||||
vardtypep = new AstUnpackArrayDType{nodep->fileline(), basep,
|
||||
new AstRange(nodep->fileline(), msbdim, 0)};
|
||||
}
|
||||
AstInitArray* const initp = new AstInitArray{nodep->fileline(), vardtypep, nullptr};
|
||||
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
|
||||
|
||||
// Default for all unspecified values
|
||||
if (attrType == VAttrType::ENUM_NAME) {
|
||||
initp->defaultp(new AstConst{nodep->fileline(), AstConst::String{}, ""});
|
||||
} else if (attrType == VAttrType::ENUM_NEXT || attrType == VAttrType::ENUM_PREV) {
|
||||
initp->defaultp(new AstConst{nodep->fileline(), V3Number{nodep, nodep->width(), 0}});
|
||||
} else if (attrType == VAttrType::ENUM_VALID) {
|
||||
initp->defaultp(new AstConst{nodep->fileline(), AstConst::BitFalse{}});
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad case");
|
||||
}
|
||||
|
||||
// Find valid values and populate
|
||||
UASSERT_OBJ(nodep->itemsp(), nodep, "enum without items");
|
||||
std::map<uint64_t, AstNodeExpr*> values;
|
||||
{
|
||||
uint64_t ordinal = 0;
|
||||
AstEnumItem* const firstp = nodep->itemsp();
|
||||
const AstEnumItem* prevp = firstp; // Prev must start with last item
|
||||
while (prevp->nextp()) prevp = VN_AS(prevp->nextp(), EnumItem);
|
||||
for (AstEnumItem* itemp = firstp; itemp;) {
|
||||
AstEnumItem* const nextp = VN_AS(itemp->nextp(), EnumItem);
|
||||
const AstConst* const vconstp = VN_AS(itemp->valuep(), Const);
|
||||
UASSERT_OBJ(vconstp, nodep, "Enum item without constified value");
|
||||
if (!vconstp->num().isAnyXZ()) { // Can 2-state runtime decode
|
||||
const uint64_t i = nodep->isWide() ? ++ordinal : vconstp->toUQuad();
|
||||
if (attrType == VAttrType::ENUM_NAME) {
|
||||
values[i] = new AstConst{nodep->fileline(), AstConst::String{},
|
||||
V3Number::displayedEnumName(itemp)};
|
||||
} else if (attrType == VAttrType::ENUM_NEXT) {
|
||||
values[i]
|
||||
= (nextp ? nextp : firstp)->valuep()->cloneTree(false); // A const
|
||||
} else if (attrType == VAttrType::ENUM_PREV) {
|
||||
values[i] = prevp->valuep()->cloneTree(false); // A const
|
||||
} else if (attrType == VAttrType::ENUM_VALID) {
|
||||
values[i] = new AstConst{nodep->fileline(), AstConst::BitTrue{}};
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad case");
|
||||
}
|
||||
}
|
||||
prevp = itemp;
|
||||
itemp = nextp;
|
||||
}
|
||||
}
|
||||
// Add all specified values to table
|
||||
if (assoc) {
|
||||
for (const auto& itr : values) initp->addIndexValuep(itr.first, itr.second);
|
||||
} else {
|
||||
for (uint64_t i = 0; i < (msbdim + 1); ++i) {
|
||||
if (values[i]) initp->addIndexValuep(i, values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Share identical tables via the constant pool
|
||||
cachedpr = V3ConstPool::find(initp);
|
||||
VL_DO_DANGLING(initp->deleteTree(), initp); // V3ConstPool::find clones it
|
||||
cachedpr->varp()->didWidth(true);
|
||||
pushDeletep(cachedpr); // Deleted with the visitor - always cloned
|
||||
return cachedpr->cloneTree(false);
|
||||
}
|
||||
|
||||
AstNodeExpr* enumSelect(AstNodeExpr* nodep, AstEnumDType* adtypep, VAttrType attrType) {
|
||||
@@ -10430,9 +10418,8 @@ class WidthVisitor final : public VNVisitor {
|
||||
itemp->valuep()->cloneTree(false)},
|
||||
new AstConst{nodep->fileline(), ++ordinal}, indexp};
|
||||
}
|
||||
AstVar* const varp = enumVarp(adtypep, attrType, false, ordinal);
|
||||
AstNodeExpr* const newp
|
||||
= new AstArraySel{nodep->fileline(), newVarRefDollarUnit(varp), indexp};
|
||||
AstVarRef* const tabRefp = enumVarRefp(adtypep, attrType, false, ordinal);
|
||||
AstNodeExpr* const newp = new AstArraySel{nodep->fileline(), tabRefp, indexp};
|
||||
newp->dtypeSetString();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return newp;
|
||||
@@ -10441,11 +10428,12 @@ class WidthVisitor final : public VNVisitor {
|
||||
const bool assoc = msbdim > ENUM_LOOKUP_BITS;
|
||||
AstNodeExpr* newp;
|
||||
if (assoc) {
|
||||
AstVar* const varp = enumVarp(adtypep, attrType, true, 0);
|
||||
newp = new AstAssocSel{nodep->fileline(), newVarRefDollarUnit(varp), nodep};
|
||||
AstVarRef* const tabRefp = enumVarRefp(adtypep, attrType, true, 0);
|
||||
newp = new AstAssocSel{nodep->fileline(), tabRefp, nodep};
|
||||
} else {
|
||||
const int selwidth = V3Number::log2b(msbdim) + 1; // Width to address a bit
|
||||
AstVar* const varp = enumVarp(adtypep, attrType, false, (1ULL << selwidth) - 1);
|
||||
AstVarRef* const tabRefp
|
||||
= enumVarRefp(adtypep, attrType, false, (1ULL << selwidth) - 1);
|
||||
AstNodeExpr* const boundp
|
||||
= attrType == VAttrType::ENUM_NAME
|
||||
&& (adtypep->width() > selwidth || msbdim != (1ULL << selwidth) - 1)
|
||||
@@ -10455,7 +10443,7 @@ class WidthVisitor final : public VNVisitor {
|
||||
static_cast<uint32_t>(msbdim)}}}
|
||||
: nullptr;
|
||||
newp = new AstArraySel{
|
||||
nodep->fileline(), newVarRefDollarUnit(varp),
|
||||
nodep->fileline(), tabRefp,
|
||||
// Select in case widths are off due to msblen!=width
|
||||
// We return "random" values if outside the range, which is fine
|
||||
// as next/previous on illegal values just need something good out
|
||||
@@ -10474,7 +10462,7 @@ class WidthVisitor final : public VNVisitor {
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
static AstNodeExpr* enumTestValid(AstNodeExpr* valp, AstEnumDType* enumDtp) {
|
||||
AstNodeExpr* enumTestValid(AstNodeExpr* valp, AstEnumDType* enumDtp) {
|
||||
const uint64_t maxval = enumMaxValue(valp, enumDtp);
|
||||
const bool assoc = maxval > ENUM_LOOKUP_BITS;
|
||||
AstNodeExpr* testp = nullptr;
|
||||
@@ -10482,13 +10470,12 @@ class WidthVisitor final : public VNVisitor {
|
||||
fl_novalue->warnOff(V3ErrorCode::ENUMVALUE, true);
|
||||
fl_novalue->warnOff(V3ErrorCode::CMPCONST, true);
|
||||
if (assoc) {
|
||||
AstVar* const varp = enumVarp(enumDtp, VAttrType::ENUM_VALID, true, 0);
|
||||
testp = new AstAssocSel{fl_novalue, newVarRefDollarUnit(varp),
|
||||
valp->cloneTreePure(false)};
|
||||
AstVarRef* const tabRefp = enumVarRefp(enumDtp, VAttrType::ENUM_VALID, true, 0);
|
||||
testp = new AstAssocSel{fl_novalue, tabRefp, valp->cloneTreePure(false)};
|
||||
} else {
|
||||
const int selwidth = V3Number::log2b(maxval) + 1; // Width to address a bit
|
||||
AstVar* const varp
|
||||
= enumVarp(enumDtp, VAttrType::ENUM_VALID, false, (1ULL << selwidth) - 1);
|
||||
AstVarRef* const tabRefp
|
||||
= enumVarRefp(enumDtp, VAttrType::ENUM_VALID, false, (1ULL << selwidth) - 1);
|
||||
FileLine* const fl_nowidth = new FileLine{fl_novalue};
|
||||
fl_nowidth->warnOff(V3ErrorCode::WIDTH, true);
|
||||
testp = new AstCond{
|
||||
@@ -10496,7 +10483,7 @@ class WidthVisitor final : public VNVisitor {
|
||||
new AstGt{fl_nowidth, valp->cloneTreePure(false),
|
||||
new AstConst{fl_nowidth, AstConst::Unsized64{}, maxval}},
|
||||
new AstConst{fl_novalue, AstConst::BitFalse{}},
|
||||
new AstArraySel{fl_novalue, newVarRefDollarUnit(varp),
|
||||
new AstArraySel{fl_novalue, tabRefp,
|
||||
new AstSel{fl_novalue, valp->cloneTreePure(false), 0, selwidth}}};
|
||||
}
|
||||
return testp;
|
||||
@@ -10682,11 +10669,6 @@ class WidthVisitor final : public VNVisitor {
|
||||
return;
|
||||
}
|
||||
}
|
||||
static AstVarRef* newVarRefDollarUnit(AstVar* nodep) {
|
||||
AstVarRef* const varrefp = new AstVarRef{nodep->fileline(), nodep, VAccess::READ};
|
||||
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgp());
|
||||
return varrefp;
|
||||
}
|
||||
AstNode* nodeForUnsizedWarning(AstNode* nodep) {
|
||||
// Return a nodep to use for unsized warnings, reporting on child if can
|
||||
if (nodep->op1p() && nodep->op1p()->dtypep() && !nodep->op1p()->dtypep()->widthSized()) {
|
||||
|
||||
Reference in New Issue
Block a user