Support unique constraint inside std::randomize (#8241)

Signed-off-by: Kornel Uriasz <[email protected]>
This commit is contained in:
Kornel Uriasz
2026-09-08 11:08:34 -04:00
committed by GitHub
parent 47b9fba5e5
commit f8c296ce2e
5 changed files with 123 additions and 46 deletions
+24 -23
View File
@@ -80,6 +80,13 @@ static AstVar* getRandModeVarFromClass(AstNodeModule* classp) {
return nullptr;
}
// Walk extends chain to find random generator variable (stored in AstClass::user3p).
static AstVar* getRandomGenerator(AstClass* const classp) {
if (classp->user3p()) return VN_AS(classp->user3p(), Var);
if (classp->extendsp()) return getRandomGenerator(classp->extendsp()->classp());
return nullptr;
}
// ######################################################################
// Establishes the target of a rand_mode() call
@@ -2459,22 +2466,18 @@ class ConstraintExprVisitor final : public VNVisitor {
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
void visit(AstConstraintUnique* nodep) override {
if (!m_classp) {
nodep->v3warn(CONSTRAINTIGN,
"Unsupported: Unique constraint in std::randomize() with {}");
pushDeletep(nodep->unlinkFrBack());
return;
}
AstNodeFTask* initTaskp;
AstVar* genVarp = m_genp;
FileLine* const fl = nodep->fileline();
AstNodeModule* genModp = nullptr;
AstNodeFTask* const initTaskp = VN_AS(m_memberMap.findMember(m_classp, "new"), NodeFTask);
UASSERT_OBJ(initTaskp, nodep, "Class has no init Task");
AstVar* const genVarp = [](const AstClass* classp) {
while (classp->extendsp()) classp = classp->extendsp()->classp();
return VN_AS(classp->user3p(), Var);
}(m_classp);
if (m_classp) {
initTaskp = VN_AS(m_memberMap.findMember(m_classp, "new"), NodeFTask);
genVarp = getRandomGenerator(m_classp);
} else {
initTaskp = m_inlineInitTaskp;
}
UASSERT_OBJ(initTaskp, nodep, "No init Task for unique constraint");
// UASSERT_OBJ(genVarp, nodep, "No generator variable");
if (!genVarp) {
@@ -2483,9 +2486,10 @@ class ConstraintExprVisitor final : public VNVisitor {
pushDeletep(nodep->unlinkFrBack());
return;
}
AstNodeModule* const genModp = VN_AS(genVarp->user2p(), NodeModule);
UASSERT_OBJ(genModp, nodep, "genVarp has no NodeModule set");
if (m_classp) {
genModp = VN_AS(genVarp->user2p(), NodeModule);
UASSERT_OBJ(genModp, nodep, "genVarp inside m_classp has no NodeModule set");
}
// Registration calls emitted where the unique statement stood, so they end up
// in the constraint setup task and re-run on every randomize()
@@ -2556,7 +2560,9 @@ class ConstraintExprVisitor final : public VNVisitor {
AstCMethodHard* const writeVarCallp = new AstCMethodHard{
fl, new AstVarRef{fl, genModp, genVarp, VAccess::READ},
VCMethod::RANDOMIZER_WRITE_VAR};
writeVarCallp->addPinsp(new AstVarRef{fl, varModp, varp, VAccess::READ});
AstVarRef* const argVarRefp = new AstVarRef{fl, varp, VAccess::READ};
if (m_classp) argVarRefp->classOrPackagep(varModp);
writeVarCallp->addPinsp(argVarRefp);
writeVarCallp->addPinsp(new AstConst{fl, AstConst::Unsized64{}, elemWidth});
writeVarCallp->addPinsp(varnamep);
writeVarCallp->addPinsp(new AstConst{fl, 1}); // Dimension
@@ -3631,11 +3637,6 @@ class RandomizeVisitor final : public VNVisitor {
}
return it->second;
}
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) {
static const char* const name = "__Vsetup_constraints";
AstTask* setupAllTaskp = VN_AS(m_memberMap.findMember(classp, name), Task);