Fix inline constraints creating class random generator (#5280)

This commit is contained in:
Krzysztof Bieganski
2024-07-19 13:03:48 -04:00
committed by GitHub
parent 298faa84ee
commit 2bd2b9324f
5 changed files with 87 additions and 40 deletions
+26 -3
View File
@@ -2338,17 +2338,40 @@ public:
// root superclass). Note: after V3Scope, several children are moved under an AstScope and will
// not be found by this.
template <typename Callable>
void foreachMember(const Callable& visit) {
void foreachMember(const Callable& f) {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 1>::type;
static_assert(
vlstd::is_invocable<Callable, AstClass*, T_Node*>::value
&& std::is_base_of<AstNode, T_Node>::value,
"Callable 'f' must have a signature compatible with 'void(AstClass*, T_Node*)', "
"with 'T_Node' being a subtype of 'AstNode'");
if (AstClassExtends* const extendsp = this->extendsp()) {
extendsp->classp()->foreachMember(visit);
extendsp->classp()->foreachMember(f);
}
for (AstNode* stmtp = stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (T_Node* memberp = AstNode::privateCast<T_Node, decltype(stmtp)>(stmtp)) {
visit(this, memberp);
f(this, memberp);
}
}
}
// Same as above, but stops after first match
template <typename Callable>
bool existsMember(const Callable& p) const {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 1>::type;
static_assert(vlstd::is_invocable_r<bool, Callable, const AstClass*, const T_Node*>::value
&& std::is_base_of<AstNode, T_Node>::value,
"Predicate 'p' must have a signature compatible with 'bool(const AstClass*, "
"const T_Node*)', with 'T_Node' being a subtype of 'AstNode'");
if (AstClassExtends* const extendsp = this->extendsp()) {
if (extendsp->classp()->existsMember(p)) return true;
}
for (AstNode* stmtp = stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (T_Node* memberp = AstNode::privateCast<T_Node, decltype(stmtp)>(stmtp)) {
if (p(this, memberp)) return true;
}
}
return false;
}
};
class AstClassPackage final : public AstNodeModule {
// The static information portion of a class (treated similarly to a package)
+41 -26
View File
@@ -552,15 +552,22 @@ class RandomizeVisitor final : public VNVisitor {
std::map<std::string, AstCDType*> m_randcDtypes; // RandC data type deduplication
// METHODS
AstVar* getCreateRandomGenerator(AstClass* classp) {
if (classp->user3p()) return VN_AS(classp->user3p(), Var);
if (classp->extendsp()) return getCreateRandomGenerator(classp->extendsp()->classp());
void createRandomGenerator(AstClass* const classp) {
if (classp->user3p()) return;
if (classp->extendsp()) {
createRandomGenerator(classp->extendsp()->classp());
return;
}
AstVar* const genp = new AstVar{classp->fileline(), VVarType::MEMBER, "constraint",
classp->findBasicDType(VBasicDTypeKwd::RANDOM_GENERATOR)};
genp->user2p(classp);
classp->addMembersp(genp);
classp->user3p(genp);
return genp;
}
AstVar* getRandomGenerator(AstClass* const classp) {
if (classp->user3p()) return VN_AS(classp->user3p(), Var);
if (classp->extendsp()) return getRandomGenerator(classp->extendsp()->classp());
return nullptr;
}
AstTask* getCreateConstraintSetupFunc(AstClass* classp) {
if (classp->user2p()) return VN_AS(classp->user2p(), Task);
@@ -572,6 +579,14 @@ class RandomizeVisitor final : public VNVisitor {
classp->user2p(setupAllTaskp);
return setupAllTaskp;
}
void createRandomizeClassVars(AstNetlist* const netlistp) {
netlistp->foreach([&](AstClass* const classp) {
if (classp->existsMember(
[&](const AstClass*, const AstConstraint*) { return true; })) {
createRandomGenerator(classp);
}
});
}
AstVar* enumValueTabp(AstEnumDType* const nodep) {
if (nodep->user2p()) return VN_AS(nodep->user2p(), Var);
UINFO(9, "Construct Venumvaltab " << nodep << endl);
@@ -756,27 +771,26 @@ class RandomizeVisitor final : public VNVisitor {
FileLine* fl = nodep->fileline();
AstNodeExpr* beginValp = nullptr;
AstVar* genp = nullptr;
nodep->foreachMember([&](AstClass* classp, AstConstraint* constrp) {
AstTask* taskp = VN_AS(constrp->user2p(), Task);
if (!taskp) {
taskp = newSetupConstraintTask(classp, constrp->name());
constrp->user2p(taskp);
}
AstTaskRef* const setupTaskRefp
= new AstTaskRef{constrp->fileline(), taskp->name(), nullptr};
setupTaskRefp->taskp(taskp);
setupTaskRefp->classOrPackagep(classp);
genp = getCreateRandomGenerator(nodep);
AstTask* setupAllTaskp = getCreateConstraintSetupFunc(nodep);
setupAllTaskp->addStmtsp(setupTaskRefp->makeStmt());
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp};
if (constrp->itemsp()) taskp->addStmtsp(constrp->itemsp()->unlinkFrBackWithNext());
});
AstVar* genp = getRandomGenerator(nodep);
if (genp) {
nodep->foreachMember([&](AstClass* const classp, AstConstraint* const constrp) {
AstTask* taskp = VN_AS(constrp->user2p(), Task);
if (!taskp) {
taskp = newSetupConstraintTask(classp, constrp->name());
constrp->user2p(taskp);
}
AstTaskRef* const setupTaskRefp
= new AstTaskRef{constrp->fileline(), taskp->name(), nullptr};
setupTaskRefp->taskp(taskp);
setupTaskRefp->classOrPackagep(classp);
AstTask* const setupAllTaskp = getCreateConstraintSetupFunc(nodep);
setupAllTaskp->addStmtsp(setupTaskRefp->makeStmt());
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp};
if (constrp->itemsp()) taskp->addStmtsp(constrp->itemsp()->unlinkFrBackWithNext());
});
randomizep->addStmtsp(implementConstraintsClear(fl, genp));
AstTask* setupAllTaskp = getCreateConstraintSetupFunc(nodep);
AstTaskRef* const setupTaskRefp = new AstTaskRef{fl, setupAllTaskp->name(), nullptr};
@@ -926,13 +940,13 @@ class RandomizeVisitor final : public VNVisitor {
UASSERT_OBJ(classp, m_modp, "Module not class, should have failed in V3Width");
}
if (classp->user1()) {
// We need to first ensure that the class randomizer is instantiated if needed
// We need to first ensure that the class constraints are transformed
// NOTE: This is safe only because AstClass visit function overwrites all
// nesting-dependent state variables
iterate(classp);
}
AstVar* const classGenp = getCreateRandomGenerator(classp);
AstVar* const classGenp = getRandomGenerator(classp);
AstVar* const localGenp
= new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, "randomizer",
classp->findBasicDType(VBasicDTypeKwd::RANDOM_GENERATOR)};
@@ -1007,6 +1021,7 @@ public:
// CONSTRUCTORS
explicit RandomizeVisitor(AstNetlist* nodep)
: m_inlineUniqueNames("__Vrandwith") {
createRandomizeClassVars(nodep);
iterate(nodep);
nodep->foreach([&](AstConstraint* constrp) {
VL_DO_DANGLING(pushDeletep(constrp->unlinkFrBack()), constrp);