Support rand_mode (#5273)

Signed-off-by: Krzysztof Bieganski <[email protected]>
This commit is contained in:
Krzysztof Bieganski
2024-07-31 22:30:48 +01:00
committed by GitHub
parent 403a197e23
commit 2f5c58b345
21 changed files with 762 additions and 189 deletions
+351 -20
View File
@@ -41,15 +41,64 @@
VL_DEFINE_DEBUG_FUNCTIONS;
// ######################################################################
// Establishes the target of a rand_mode() call
struct RandModeTarget final {
// MEMBERS
AstVar* const receiverp; // Variable that is the target of the rand_mode() call
AstNodeExpr* const fromp; // Expression from which the rand_mode() call originates
AstClass* const classp; // Class in which rand_mode should be set
// METHODS
static RandModeTarget get(AstNodeExpr* fromp, AstNodeModule* modp) {
if (!fromp) return {nullptr, nullptr, VN_AS(modp, Class)};
if (AstCMethodHard* const methodHardp = VN_CAST(fromp, CMethodHard)) {
return RandModeTarget::get(methodHardp->fromp(), modp);
}
AstVar* receiverp = nullptr;
if (AstVarRef* const varrefp = VN_CAST(fromp, VarRef)) {
receiverp = varrefp->varp();
} else if (AstMemberSel* const memberSelp = VN_CAST(fromp, MemberSel)) {
receiverp = memberSelp->varp();
}
UASSERT_OBJ(receiverp, fromp, "Unknown rand_mode() receiver");
if (receiverp->isRand()) {
if (AstMemberSel* const memberselp = VN_CAST(fromp, MemberSel)) {
return {receiverp, memberselp->fromp(),
VN_AS(memberselp->fromp()->dtypep()->skipRefp(), ClassRefDType)->classp()};
}
} else {
AstClassRefDType* const classRefDtp
= VN_CAST(receiverp->dtypep()->skipRefp(), ClassRefDType);
if (classRefDtp) return {receiverp, fromp, classRefDtp->classp()};
}
return {receiverp, nullptr, VN_AS(modp, Class)};
}
};
// ######################################################################
// Stores info about a variable's rand_mode state
union VarRandMode final {
// MEMBERS
struct {
bool usesRandMode : 1; // True if variable uses rand_mode
uint32_t index : 31; // Index of var in rand_mode vector
};
int asInt; // Representation as int to be stored in nodep->user*
};
//######################################################################
// Visitor that marks classes needing a randomize() method
class RandomizeMarkVisitor final : public VNVisitorConst {
class RandomizeMarkVisitor final : public VNVisitor {
// NODE STATE
// Cleared on Netlist
// AstClass::user1() -> bool. Set true to indicate needs randomize processing
// AstNodeExpr::user1() -> bool. Set true to indicate constraint expression depending on a
// randomized variable
// AstVar::user1() -> bool. Set true to indicate needs rand_mode
// AstVar::user2p() -> AstNodeModule*. Pointer to containing module
const VNUser1InUse m_inuser1;
const VNUser2InUse m_inuser2;
@@ -61,6 +110,7 @@ class RandomizeMarkVisitor final : public VNVisitorConst {
AstClass* m_classp = nullptr; // Current class
AstNode* m_constraintExprp = nullptr; // Current constraint expression
AstNodeModule* m_modp; // Current module
AstNodeStmt* m_stmtp = nullptr; // Current statement
std::set<AstNodeVarRef*> m_staticRefs; // References to static variables under `with` clauses
// METHODS
@@ -119,8 +169,78 @@ class RandomizeMarkVisitor final : public VNVisitorConst {
m_baseToDerivedMap[basep].insert(nodep);
}
}
void visit(AstNodeStmt* nodep) override {
VL_RESTORER(m_stmtp);
m_stmtp = nodep;
iterateChildren(nodep);
if (!nodep->backp()) VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void visit(AstNodeFTaskRef* nodep) override {
iterateChildrenConst(nodep);
if (nodep->name() == "rand_mode") {
AstMethodCall* const methodCallp = VN_CAST(nodep, MethodCall);
AstNodeExpr* const fromp = methodCallp ? methodCallp->fromp() : nullptr;
bool valid = true;
if (VN_IS(fromp, ArraySel)) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: 'rand_mode()' on unpacked array element");
valid = false;
} else if (VN_IS(fromp, Sel)) {
nodep->v3error("Cannot call 'rand_mode()' on packed array element");
valid = false;
} else if (AstCMethodHard* const methodHardp = VN_CAST(fromp, CMethodHard)) {
if (methodHardp->name() == "at" && VN_IS(fromp, CMethodHard)) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: 'rand_mode()' on dynamic array element");
valid = false;
} else {
methodHardp->v3fatal("Unknown rand_mode() receiver");
}
}
if (!nodep->pinsp() && VN_IS(nodep->backp(), StmtExpr)) {
nodep->v3warn(
IGNOREDRETURN,
"Ignoring return value of non-void function (IEEE 1800-2023 13.4.1)");
valid = false;
}
if (valid) {
const RandModeTarget randModeTarget = RandModeTarget::get(fromp, m_classp);
if ((!randModeTarget.receiverp || !randModeTarget.receiverp->isRand())
&& !nodep->pinsp()) {
nodep->v3error(
"Cannot call 'rand_mode()' as a function on non-random variable");
valid = false;
} else if (!randModeTarget.classp) {
nodep->v3error("Cannot call 'rand_mode()' on non-random, non-class variable");
valid = false;
} else if (nodep->pinsp() && !VN_IS(nodep->backp(), StmtExpr)) {
nodep->v3error("'rand_mode()' with arguments cannot be called as a function");
valid = false;
} else if (randModeTarget.receiverp && randModeTarget.receiverp->isRand()) {
// Called on a rand member variable
VarRandMode randMode = {};
randMode.usesRandMode = true;
randModeTarget.receiverp->user1(randMode.asInt);
} else {
// Called on 'this' or a non-rand class instance
randModeTarget.classp->foreachMember([&](AstClass*, AstVar* varp) {
if (!varp->isRand()) return;
VarRandMode randMode = {};
randMode.usesRandMode = true;
varp->user1(randMode.asInt);
});
}
}
if (!valid) {
if (!nodep->pinsp() && !VN_IS(nodep->backp(), StmtExpr)) {
nodep->replaceWith(new AstConst{nodep->fileline(), 0});
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else {
m_stmtp->unlinkFrBack();
}
}
return;
}
if (nodep->name() != "randomize") return;
AstClass* classp = m_classp;
if (const AstMethodCall* const methodCallp = VN_CAST(nodep, MethodCall)) {
@@ -192,17 +312,20 @@ class ConstraintExprVisitor final : public VNVisitor {
AstNodeFTask* const m_inlineInitTaskp; // Method to add write_var calls to
// (may be null, then new() is used)
AstVar* const m_genp; // VlRandomizer variable of the class
AstVar* m_randModeVarp; // Relevant randmode state variable
bool m_wantSingle = false; // Whether to merge constraint expressions with LOGAND
VMemberMap& m_memberMap; // Member names cached for fast lookup
AstSFormatF* getConstFormat(AstNodeExpr* nodep) {
return new AstSFormatF{nodep->fileline(), (nodep->width() & 3) ? "#b%b" : "#x%x", false,
nodep};
}
bool editFormat(AstNodeExpr* nodep) {
if (nodep->user1()) return false;
// Replace computable expression with SMT constant
VNRelinker handle;
nodep->unlinkFrBack(&handle);
AstSFormatF* const newp = new AstSFormatF{
nodep->fileline(), (nodep->width() & 3) ? "#b%b" : "#x%x", false, nodep};
handle.relink(newp);
handle.relink(getConstFormat(nodep));
return true;
}
void editSMT(AstNodeExpr* nodep, AstNodeExpr* lhsp = nullptr, AstNodeExpr* rhsp = nullptr,
@@ -282,14 +405,28 @@ class ConstraintExprVisitor final : public VNVisitor {
// VISITORS
void visit(AstNodeVarRef* nodep) override {
if (editFormat(nodep)) return;
AstVar* const varp = nodep->varp();
const VarRandMode randMode = {.asInt = varp->user1()};
if (!randMode.usesRandMode && editFormat(nodep)) return;
// In SMT just variable name, but we also ensure write_var for the variable
const std::string smtName = nodep->name(); // Can be anything unique
nodep->replaceWith(new AstSFormatF{nodep->fileline(), smtName, false, nullptr});
AstVar* const varp = nodep->varp();
VL_DO_DANGLING(pushDeletep(nodep), nodep);
VNRelinker relinker;
nodep->unlinkFrBack(&relinker);
AstNodeExpr* exprp = new AstSFormatF{nodep->fileline(), smtName, false, nullptr};
if (randMode.usesRandMode) {
AstNodeExpr* constFormatp = getConstFormat(nodep);
AstCMethodHard* const atp = new AstCMethodHard{
nodep->fileline(),
new AstVarRef{varp->fileline(), VN_AS(m_randModeVarp->user2p(), NodeModule),
m_randModeVarp, VAccess::READ},
"at", new AstConst{nodep->fileline(), randMode.index}};
atp->dtypeSetUInt32();
exprp = new AstCond{varp->fileline(), atp, exprp, constFormatp};
} else {
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
relinker.relink(exprp);
if (!varp->user3()) {
AstCMethodHard* const methodp = new AstCMethodHard{
@@ -308,6 +445,10 @@ class ConstraintExprVisitor final : public VNVisitor {
= new AstCExpr{varp->fileline(), "\"" + smtName + "\"", varp->width()};
varnamep->dtypep(varp->dtypep());
methodp->addPinsp(varnamep);
if (randMode.usesRandMode) {
methodp->addPinsp(
new AstConst{varp->fileline(), AstConst::Unsized64{}, randMode.index});
}
AstNodeFTask* initTaskp = m_inlineInitTaskp;
if (!initTaskp) {
varp->user3(true); // Mark as set up in new()
@@ -430,9 +571,11 @@ class ConstraintExprVisitor final : public VNVisitor {
public:
// CONSTRUCTORS
explicit ConstraintExprVisitor(VMemberMap& memberMap, AstNode* nodep,
AstNodeFTask* inlineInitTaskp, AstVar* genp)
AstNodeFTask* inlineInitTaskp, AstVar* genp,
AstVar* randModeVarp)
: m_inlineInitTaskp{inlineInitTaskp}
, m_genp{genp}
, m_randModeVarp{randModeVarp}
, m_memberMap{memberMap} {
iterateAndNextNull(nodep);
}
@@ -538,15 +681,19 @@ class RandomizeVisitor final : public VNVisitor {
// AstClass::user2p() -> AstTask*. Pointer to full constraint setup procedure
// AstVar::user3() -> bool. Handled in constraints
// AstClass::user3p() -> AstVar*. Constrained randomizer variable
// AstClass::user4p() -> AstVar*. Rand mode state variable
// VNUser1InUse m_inuser1; (Allocated for use in RandomizeMarkVisitor)
// VNUser2InUse m_inuser2; (Allocated for use in RandomizeMarkVisitor)
const VNUser3InUse m_inuser3;
const VNUser4InUse m_inuser4;
// STATE
V3UniqueNames m_inlineUniqueNames; // For generating unique function names
VMemberMap m_memberMap; // Member names cached for fast lookup
AstNodeModule* m_modp = nullptr; // Current module
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
AstNodeStmt* m_stmtp = nullptr; // Current statement
AstDynArrayDType* m_dynarrayDtp = nullptr; // Dynamic array type (for rand mode)
size_t m_enumValueTabCount = 0; // Number of tables with enum values created
int m_randCaseNum = 0; // Randcase number within a module for var naming
std::map<std::string, AstCDType*> m_randcDtypes; // RandC data type deduplication
@@ -579,14 +726,119 @@ class RandomizeVisitor final : public VNVisitor {
classp->user2p(setupAllTaskp);
return setupAllTaskp;
}
AstVar* getCreateRandModeVar(AstClass* const classp) {
if (classp->user4p()) return VN_AS(classp->user4p(), Var);
if (AstClassExtends* const extendsp = classp->extendsp()) {
return getCreateRandModeVar(extendsp->classp());
}
FileLine* const fl = classp->fileline();
if (!m_dynarrayDtp) {
m_dynarrayDtp = new AstDynArrayDType{
fl, v3Global.rootp()->typeTablep()->findBitDType()->dtypep()};
m_dynarrayDtp->dtypep(m_dynarrayDtp);
v3Global.rootp()->typeTablep()->addTypesp(m_dynarrayDtp);
}
AstVar* const randModeVarp
= new AstVar{fl, VVarType::MODULETEMP, "__Vrandmode", m_dynarrayDtp};
randModeVarp->user2p(classp);
classp->addStmtsp(randModeVarp);
classp->user4p(randModeVarp);
return randModeVarp;
}
AstVar* getRandModeVar(AstClass* const classp) {
if (classp->user4p()) return VN_AS(classp->user4p(), Var);
if (AstClassExtends* const extendsp = classp->extendsp()) {
return getRandModeVar(extendsp->classp());
}
return nullptr;
}
void addSetRandMode(AstNodeFTask* const ftaskp, AstVar* const genp,
AstVar* const randModeVarp) {
FileLine* const fl = ftaskp->fileline();
AstCMethodHard* const setRandModep = new AstCMethodHard{
fl, new AstVarRef{fl, VN_AS(genp->user2p(), NodeModule), genp, VAccess::WRITE},
"set_randmode",
new AstVarRef{fl, VN_AS(randModeVarp->user2p(), NodeModule), randModeVarp,
VAccess::READ}};
setRandModep->dtypeSetVoid();
ftaskp->addStmtsp(setRandModep->makeStmt());
}
void createRandomizeClassVars(AstNetlist* const netlistp) {
netlistp->foreach([&](AstClass* const classp) {
if (classp->existsMember(
[&](const AstClass*, const AstConstraint*) { return true; })) {
createRandomGenerator(classp);
}
uint32_t randModeCount = 0;
classp->foreachMember([&](AstClass*, AstVar* memberVarp) {
VarRandMode randMode = {.asInt = memberVarp->user1()};
if (!randMode.usesRandMode) return;
// SystemVerilog only allows single inheritance, so we don't need to worry about
// index overlap. If the index > 0, it's already been set.
if (randMode.index == 0) {
randMode.index = randModeCount++;
memberVarp->user1(randMode.asInt);
} else {
randModeCount = randMode.index + 1;
}
});
if (randModeCount > 0) {
AstVar* const randModeVarp = getCreateRandModeVar(classp);
AstNodeModule* const randModeModp = VN_AS(randModeVarp->user2p(), NodeModule);
FileLine* fl = randModeVarp->fileline();
AstCMethodHard* const dynarrayNewp = new AstCMethodHard{
fl, new AstVarRef{fl, randModeModp, randModeVarp, VAccess::WRITE},
"renew_copy", new AstConst{fl, randModeCount}};
dynarrayNewp->addPinsp(
new AstVarRef{fl, randModeModp, randModeVarp, VAccess::READ});
dynarrayNewp->dtypeSetVoid();
AstNodeFTask* const newp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask);
fl = classp->fileline();
UASSERT_OBJ(newp, classp, "No new() in class");
newp->addStmtsp(dynarrayNewp->makeStmt());
newp->addStmtsp(makeRandModeInitLoop(
fl, new AstVarRef{fl, randModeModp, randModeVarp, VAccess::WRITE},
new AstConst{fl, 1}, true));
}
});
}
static AstNode* makeRandModeInitLoop(FileLine* const fl, AstNodeExpr* const lhsp,
AstNodeExpr* const rhsp, bool inTask) {
AstVar* const iterVarp = new AstVar{fl, VVarType::BLOCKTEMP, "i", lhsp->findUInt32DType()};
iterVarp->funcLocal(inTask);
iterVarp->lifetime(VLifetime::AUTOMATIC);
AstCMethodHard* const sizep = new AstCMethodHard{fl, lhsp, "size", nullptr};
sizep->dtypeSetUInt32();
AstCMethodHard* const atp = new AstCMethodHard{fl, lhsp->cloneTree(false), "at",
new AstVarRef{fl, iterVarp, VAccess::READ}};
atp->dtypeSetUInt32();
AstNode* const stmtsp = iterVarp;
stmtsp->addNext(
new AstAssign{fl, new AstVarRef{fl, iterVarp, VAccess::WRITE}, new AstConst{fl, 0}});
stmtsp->addNext(
new AstWhile{fl, new AstLt{fl, new AstVarRef{fl, iterVarp, VAccess::READ}, sizep},
new AstAssign{fl, atp, rhsp},
new AstAssign{fl, new AstVarRef{fl, iterVarp, VAccess::WRITE},
new AstAdd{fl, new AstConst{fl, 1},
new AstVarRef{fl, iterVarp, VAccess::READ}}}});
return new AstBegin{fl, "", stmtsp, false, true};
}
AstNodeStmt* wrapIfRandMode(AstVar* const varp, AstNodeStmt* stmtp) {
FileLine* const fl = stmtp->fileline();
const VarRandMode randMode = {.asInt = varp->user1()};
if (randMode.usesRandMode) {
AstVar* randModeVarp = getRandModeVar(VN_AS(m_modp, Class));
AstCMethodHard* const atp
= new AstCMethodHard{fl,
new AstVarRef{fl, VN_AS(randModeVarp->user2p(), Class),
randModeVarp, VAccess::READ},
"at", new AstConst{fl, randMode.index}};
atp->dtypeSetUInt32();
return new AstIf{fl, atp, stmtp};
}
return stmtp;
}
AstVar* enumValueTabp(AstEnumDType* const nodep) {
if (nodep->user2p()) return VN_AS(nodep->user2p(), Var);
UINFO(9, "Construct Venumvaltab " << nodep << endl);
@@ -702,10 +954,17 @@ class RandomizeVisitor final : public VNVisitor {
valp
= newRandValue(fl, randcVarp, (memberp ? memberp->dtypep() : exprp->dtypep()));
}
return new AstAssign{fl,
new AstSel{fl, exprp, offset + (memberp ? memberp->lsb() : 0),
memberp ? memberp->width() : exprp->width()},
valp};
AstAssign* assignp
= new AstAssign{fl,
new AstSel{fl, exprp, offset + (memberp ? memberp->lsb() : 0),
memberp ? memberp->width() : exprp->width()},
valp};
AstVar* varp = nullptr;
exprp->exists([&](const AstVarRef* varrefp) {
if (varrefp->access().isWriteOrRW()) varp = varrefp->varp();
return varp != nullptr;
});
return wrapIfRandMode(varp, assignp);
}
}
AstNodeExpr* newRandValue(FileLine* const fl, AstVar* const randcVarp,
@@ -780,7 +1039,7 @@ class RandomizeVisitor final : public VNVisitor {
new AstConst{fl, AstConst::Null{}}},
new AstAssign{fl, basicFvarRefp->cloneTree(false),
new AstAnd{fl, basicFvarRefReadp, callp}}};
basicRandomizep->addStmtsp(assignIfNotNullp);
basicRandomizep->addStmtsp(wrapIfRandMode(memberVarp, assignIfNotNullp));
} else {
memberVarp->v3warn(E_UNSUPPORTED, "Unsupported: random member variable with type "
<< memberVarp->dtypep()->prettyDTypeNameQ());
@@ -815,6 +1074,7 @@ class RandomizeVisitor final : public VNVisitor {
addPrePostCall(nodep, randomizep, "pre_randomize");
FileLine* fl = nodep->fileline();
AstVar* const randModeVarp = getRandModeVar(nodep);
AstNodeExpr* beginValp = nullptr;
AstVar* genp = getRandomGenerator(nodep);
if (genp) {
@@ -833,7 +1093,7 @@ class RandomizeVisitor final : public VNVisitor {
setupAllTaskp->addStmtsp(setupTaskRefp->makeStmt());
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp};
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp, randModeVarp};
if (constrp->itemsp()) taskp->addStmtsp(constrp->itemsp()->unlinkFrBackWithNext());
});
randomizep->addStmtsp(implementConstraintsClear(fl, genp));
@@ -843,13 +1103,22 @@ class RandomizeVisitor final : public VNVisitor {
randomizep->addStmtsp(implementConstraintsClear(fl, genp));
randomizep->addStmtsp(setupTaskRefp->makeStmt());
AstVarRef* genRefp
= new AstVarRef{fl, VN_AS(genp->user2p(), NodeModule), genp, VAccess::READWRITE};
AstNodeModule* const genModp = VN_AS(genp->user2p(), NodeModule);
AstVarRef* const genRefp = new AstVarRef{fl, genModp, genp, VAccess::READWRITE};
AstNode* const argsp = genRefp;
argsp->addNext(new AstText{fl, ".next(__Vm_rng)"});
AstNodeExpr* const solverCallp = new AstCExpr{fl, argsp};
solverCallp->dtypeSetBit();
beginValp = solverCallp;
if (randModeVarp) {
AstNodeModule* const randModeClassp = VN_AS(randModeVarp->user2p(), Class);
AstNodeFTask* const newp
= VN_AS(m_memberMap.findMember(randModeClassp, "new"), NodeFTask);
UASSERT_OBJ(newp, randModeClassp, "No new() in class");
addSetRandMode(newp, genp, randModeVarp);
}
} else {
beginValp = new AstConst{fl, AstConst::WidthedValue{}, 32, 1};
}
@@ -933,6 +1202,58 @@ class RandomizeVisitor final : public VNVisitor {
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstNodeFTaskRef* nodep) override {
if (nodep->name() == "rand_mode") {
AstMethodCall* const methodCallp = VN_CAST(nodep, MethodCall);
AstNodeExpr* const fromp = methodCallp ? methodCallp->fromp() : nullptr;
const RandModeTarget randModeTarget = RandModeTarget::get(fromp, m_modp);
UASSERT_OBJ(randModeTarget.classp, nodep,
"Should have checked in RandomizeMarkVisitor");
AstVar* const randModeVarp = getRandModeVar(randModeTarget.classp);
AstNodeExpr* lhsp = nullptr;
if (randModeTarget.classp == m_modp) {
// Called on 'this' or a member of 'this'
lhsp = new AstVarRef{nodep->fileline(), VN_AS(randModeVarp->user2p(), NodeModule),
randModeVarp, VAccess::WRITE};
} else {
AstMemberSel* const memberselp = new AstMemberSel{
nodep->fileline(), randModeTarget.fromp->unlinkFrBack(), randModeVarp};
memberselp->foreach([](AstVarRef* varrefp) { varrefp->access(VAccess::WRITE); });
lhsp = memberselp;
}
if (nodep->pinsp()) { // Set rand mode
UASSERT_OBJ(VN_IS(nodep->backp(), StmtExpr), nodep, "Should be a statement");
AstNodeExpr* const rhsp = VN_AS(nodep->pinsp(), Arg)->exprp()->unlinkFrBack();
if (randModeTarget.receiverp && randModeTarget.receiverp->isRand()) {
// Called on a rand member variable. Set the variable's rand mode
const VarRandMode randMode = {.asInt = randModeTarget.receiverp->user1()};
UASSERT_OBJ(randMode.usesRandMode, nodep, "Failed to set usesRandMode");
AstCMethodHard* const atp
= new AstCMethodHard{nodep->fileline(), lhsp, "at",
new AstConst{nodep->fileline(), randMode.index}};
atp->dtypeSetUInt32();
m_stmtp->replaceWith(new AstAssign{nodep->fileline(), atp, rhsp});
} else {
// Called on 'this' or a non-rand class instance. Set the rand mode of all
// members
m_stmtp->replaceWith(
makeRandModeInitLoop(nodep->fileline(), lhsp, rhsp, m_ftaskp));
}
pushDeletep(m_stmtp);
} else { // Retrieve rand mode
UASSERT_OBJ(randModeTarget.receiverp, nodep, "Should have receiver");
UASSERT_OBJ(randModeTarget.receiverp->isRand(), nodep, "Should be rand");
const VarRandMode randMode = {.asInt = randModeTarget.receiverp->user1()};
UASSERT_OBJ(randMode.usesRandMode, nodep, "Failed to set usesRandMode");
AstCMethodHard* const atp
= new AstCMethodHard{nodep->fileline(), lhsp, "at",
new AstConst{nodep->fileline(), randMode.index}};
atp->dtypeSetUInt32();
nodep->replaceWith(atp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
return;
}
AstWith* const withp = VN_CAST(nodep->pinsp(), With);
if (!(nodep->name() == "randomize") || !withp) {
@@ -1018,9 +1339,14 @@ class RandomizeVisitor final : public VNVisitor {
VAccess::READ}});
}
// Set rand mode if present (not needed if classGenp exists and was copied)
AstVar* const randModeVarp = getRandModeVar(classp);
if (!classGenp && randModeVarp) addSetRandMode(randomizeFuncp, localGenp, randModeVarp);
// Generate constraint setup code and a hardcoded call to the solver
randomizeFuncp->addStmtsp(captured.getTree());
ConstraintExprVisitor{m_memberMap, captured.getTree(), randomizeFuncp, localGenp};
ConstraintExprVisitor{m_memberMap, captured.getTree(), randomizeFuncp, localGenp,
randModeVarp};
// Call the solver and set return value
AstVarRef* const randNextp
@@ -1042,6 +1368,11 @@ class RandomizeVisitor final : public VNVisitor {
UINFO(9, "Added `%s` randomization procedure");
VL_DO_DANGLING(withp->deleteTree(), withp);
}
void visit(AstNodeStmt* nodep) override {
VL_RESTORER(m_stmtp);
m_stmtp = nodep;
iterateChildren(nodep);
}
void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: