From 2bd2b9324fea1873a4a638c7838aa101fc2b5cc5 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Fri, 19 Jul 2024 19:03:48 +0200 Subject: [PATCH] Fix inline constraints creating class random generator (#5280) --- src/V3AstNodeOther.h | 29 +++++++++- src/V3Randomize.cpp | 67 ++++++++++++++--------- test_regress/t/t_constraint_json_only.out | 18 +++--- test_regress/t/t_constraint_xml.out | 8 ++- test_regress/t/t_randomize_method_with.pl | 5 ++ 5 files changed, 87 insertions(+), 40 deletions(-) diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index b2c7eb005..f64aca8ec 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -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 - void foreachMember(const Callable& visit) { + void foreachMember(const Callable& f) { using T_Node = typename FunctionArgNoPointerNoCV::type; + static_assert( + vlstd::is_invocable::value + && std::is_base_of::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(stmtp)) { - visit(this, memberp); + f(this, memberp); } } } + // Same as above, but stops after first match + template + bool existsMember(const Callable& p) const { + using T_Node = typename FunctionArgNoPointerNoCV::type; + static_assert(vlstd::is_invocable_r::value + && std::is_base_of::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(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) diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 996f58e2f..fe1d00169 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -552,15 +552,22 @@ class RandomizeVisitor final : public VNVisitor { std::map 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); diff --git a/test_regress/t/t_constraint_json_only.out b/test_regress/t/t_constraint_json_only.out index 271c0c636..ae7c64ed3 100644 --- a/test_regress/t/t_constraint_json_only.out +++ b/test_regress/t/t_constraint_json_only.out @@ -48,7 +48,8 @@ {"type":"VARREF","name":"strings_equal","addr":"(JB)","loc":"d,62:7,62:13","dtypep":"(U)","access":"WR","varp":"(BB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} ],"timingControlp": []} ],"scopeNamep": []}, - {"type":"FUNC","name":"new","addr":"(KB)","loc":"d,7:1,7:6","dtypep":"(LB)","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"new","fvarp": [],"classOrPackagep": [],"stmtsp": [],"scopeNamep": []} + {"type":"FUNC","name":"new","addr":"(KB)","loc":"d,7:1,7:6","dtypep":"(LB)","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"new","fvarp": [],"classOrPackagep": [],"stmtsp": [],"scopeNamep": []}, + {"type":"VAR","name":"constraint","addr":"(MB)","loc":"d,7:1,7:6","dtypep":"(NB)","origName":"constraint","isSc":false,"isPrimaryIO":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isUsedClock":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"attrClocker":"UNKNOWN","lifetime":"NONE","varType":"MEMBER","dtypeName":"VlRandomizer","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []} ],"activesp": [],"extendsp": []} ],"activesp": []} ],"filesp": [], @@ -56,28 +57,29 @@ {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(LB)", "typesp": [ {"type":"BASICDTYPE","name":"logic","addr":"(GB)","loc":"d,22:14,22:15","dtypep":"(GB)","keyword":"logic","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"logic","addr":"(MB)","loc":"d,25:21,25:22","dtypep":"(MB)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, + {"type":"BASICDTYPE","name":"logic","addr":"(OB)","loc":"d,25:21,25:22","dtypep":"(OB)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"string","addr":"(M)","loc":"d,73:7,73:13","dtypep":"(M)","keyword":"string","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"int","addr":"(Q)","loc":"d,8:9,8:12","dtypep":"(Q)","keyword":"int","range":"31:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"bit","addr":"(U)","loc":"d,11:9,11:12","dtypep":"(U)","keyword":"bit","generic":true,"rangep": []}, {"type":"UNPACKARRAYDTYPE","name":"","addr":"(Y)","loc":"d,15:18,15:19","dtypep":"(Y)","isCompound":false,"declRange":"[0:1]","generic":false,"refDTypep":"(Q)","childDTypep": [], "rangep": [ - {"type":"RANGE","name":"","addr":"(NB)","loc":"d,15:18,15:19","ascending":true, + {"type":"RANGE","name":"","addr":"(PB)","loc":"d,15:18,15:19","ascending":true, "leftp": [ - {"type":"CONST","name":"32'h0","addr":"(OB)","loc":"d,15:19,15:20","dtypep":"(MB)"} + {"type":"CONST","name":"32'h0","addr":"(QB)","loc":"d,15:19,15:20","dtypep":"(OB)"} ], "rightp": [ - {"type":"CONST","name":"32'h1","addr":"(PB)","loc":"d,15:19,15:20","dtypep":"(MB)"} + {"type":"CONST","name":"32'h1","addr":"(RB)","loc":"d,15:19,15:20","dtypep":"(OB)"} ]} ]}, {"type":"VOIDDTYPE","name":"","addr":"(LB)","loc":"d,7:1,7:6","dtypep":"(LB)","generic":false}, - {"type":"CLASSREFDTYPE","name":"Packet","addr":"(H)","loc":"d,69:4,69:10","dtypep":"(H)","generic":false,"classp":"(O)","classOrPackagep":"(O)","paramsp": []} + {"type":"CLASSREFDTYPE","name":"Packet","addr":"(H)","loc":"d,69:4,69:10","dtypep":"(H)","generic":false,"classp":"(O)","classOrPackagep":"(O)","paramsp": []}, + {"type":"BASICDTYPE","name":"VlRandomizer","addr":"(NB)","loc":"d,7:1,7:6","dtypep":"(NB)","keyword":"VlRandomizer","generic":true,"rangep": []} ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ - {"type":"MODULE","name":"@CONST-POOL@","addr":"(QB)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], + {"type":"MODULE","name":"@CONST-POOL@","addr":"(SB)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], "stmtsp": [ - {"type":"SCOPE","name":"@CONST-POOL@","addr":"(RB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(QB)","varsp": [],"blocksp": [],"inlinesp": []} + {"type":"SCOPE","name":"@CONST-POOL@","addr":"(TB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(SB)","varsp": [],"blocksp": [],"inlinesp": []} ],"activesp": []} ]} ]} diff --git a/test_regress/t/t_constraint_xml.out b/test_regress/t/t_constraint_xml.out index 6b763d041..853dc773d 100644 --- a/test_regress/t/t_constraint_xml.out +++ b/test_regress/t/t_constraint_xml.out @@ -48,22 +48,24 @@ + - + - - + + + diff --git a/test_regress/t/t_randomize_method_with.pl b/test_regress/t/t_randomize_method_with.pl index 4230d5f06..3037a8f30 100755 --- a/test_regress/t/t_randomize_method_with.pl +++ b/test_regress/t/t_randomize_method_with.pl @@ -23,5 +23,10 @@ if (!$Self->have_solver) { ); } +for my $file (glob_all("$Self->{obj_dir}/$Self->{vm_prefix}*Baz*.cpp")) { + # Check that "Baz" has no constrained random generator + file_grep_not($file, "this->__PVT__constraint"); +} + ok(1); 1;