Support randomize size constraints with restrictions (#5582 partial) (#5611)

This commit is contained in:
Ryszard Rozak
2024-11-15 10:45:06 -05:00
committed by GitHub
parent 9bde98e912
commit 5470cf9fa9
8 changed files with 229 additions and 15 deletions
+95 -2
View File
@@ -606,6 +606,12 @@ class ConstraintExprVisitor final : public VNVisitor {
// VISITORS
void visit(AstNodeVarRef* nodep) override {
AstVar* const varp = nodep->varp();
if (varp->user4p()) {
varp->user4p()->v3warn(
CONSTRAINTIGN,
"Size constraint combined with element constraint may not work correctly");
}
AstNodeModule* const classOrPackagep = nodep->classOrPackagep();
const RandomizeMode randMode = {.asInt = varp->user1()};
if (!randMode.usesMode && editFormat(nodep)) return;
@@ -1132,7 +1138,9 @@ class RandomizeVisitor final : public VNVisitor {
// AstClass::user2p() -> AstVar*. Rand mode state variable
// AstVar::user3() -> bool. Handled in constraints
// AstClass::user3p() -> AstVar*. Constrained randomizer variable
// AstConstraint::user3p() -> AstTask*. Pointer to resize procedure
// AstClass::user4p() -> AstVar*. Constraint mode state variable
// AstVar::user4p() -> AstVar*. Size variable for constrained queues
// VNUser1InUse m_inuser1; (Allocated for use in RandomizeMarkVisitor)
// VNUser2InUse m_inuser2; (Allocated for use in RandomizeMarkVisitor)
const VNUser3InUse m_inuser3;
@@ -1150,6 +1158,7 @@ class RandomizeVisitor final : public VNVisitor {
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
AstConstraint* m_constraintp = nullptr; // Current constraint
// METHODS
void createRandomGenerator(AstClass* const classp) {
@@ -1180,6 +1189,17 @@ class RandomizeVisitor final : public VNVisitor {
m_memberMap.insert(classp, setupAllTaskp);
return setupAllTaskp;
}
AstTask* getCreateAggrResizeTask(AstClass* const classp) {
static const char* const name = "__Vresize_constrained_arrays";
AstTask* resizeTaskp = VN_AS(m_memberMap.findMember(classp, name), Task);
if (resizeTaskp) return resizeTaskp;
resizeTaskp = new AstTask{classp->fileline(), name, nullptr};
resizeTaskp->classMethod(true);
resizeTaskp->isVirtual(true);
classp->addMembersp(resizeTaskp);
m_memberMap.insert(classp, resizeTaskp);
return resizeTaskp;
}
AstVar* getCreateRandModeVar(AstClass* const classp) {
if (classp->user2p()) return VN_AS(classp->user2p(), Var);
if (AstClassExtends* const extendsp = classp->extendsp()) {
@@ -1281,8 +1301,7 @@ class RandomizeVisitor final : public VNVisitor {
FileLine* fl = modeVarp->fileline();
AstCMethodHard* const dynarrayNewp
= new AstCMethodHard{fl, new AstVarRef{fl, modeVarModp, modeVarp, VAccess::WRITE},
"renew_copy", new AstConst{fl, modeCount}};
dynarrayNewp->addPinsp(new AstVarRef{fl, modeVarModp, modeVarp, VAccess::READ});
"resize", new AstConst{fl, modeCount}};
dynarrayNewp->dtypeSetVoid();
AstNodeFTask* const newp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask);
UASSERT_OBJ(newp, classp, "No new() in class");
@@ -1565,6 +1584,13 @@ class RandomizeVisitor final : public VNVisitor {
nodep->addMembersp(taskp);
return taskp;
}
AstTask* newResizeConstrainedArrayTask(AstClass* const nodep, const std::string& name) {
AstTask* const taskp
= new AstTask{nodep->fileline(), name + "_resize_constrained_array", nullptr};
taskp->classMethod(true);
nodep->addMembersp(taskp);
return taskp;
}
AstNodeStmt* implementConstraintsClear(FileLine* const fileline, AstVar* const genp) {
AstCMethodHard* const clearp = new AstCMethodHard{
fileline,
@@ -1898,6 +1924,15 @@ class RandomizeVisitor final : public VNVisitor {
setupAllTaskp->addStmtsp(setupTaskRefp->makeStmt());
if (AstTask* const resizeTaskp = VN_CAST(constrp->user3p(), Task)) {
AstTask* const resizeAllTaskp = getCreateAggrResizeTask(nodep);
AstTaskRef* const resizeTaskRefp
= new AstTaskRef{constrp->fileline(), resizeTaskp->name(), nullptr};
resizeTaskRefp->taskp(resizeTaskp);
resizeTaskRefp->classOrPackagep(classp);
resizeAllTaskp->addStmtsp(resizeTaskRefp->makeStmt());
}
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp, randModeVarp};
if (constrp->itemsp()) {
taskp->addStmtsp(wrapIfConstraintMode(
@@ -1933,6 +1968,13 @@ class RandomizeVisitor final : public VNVisitor {
AstVarRef* const fvarRefp = new AstVarRef{fl, fvarp, VAccess::WRITE};
randomizep->addStmtsp(new AstAssign{fl, fvarRefp, beginValp});
if (AstTask* const resizeAllTaskp
= VN_AS(m_memberMap.findMember(nodep, "__Vresize_constrained_arrays"), Task)) {
AstTaskRef* const resizeTaskRefp = new AstTaskRef{fl, resizeAllTaskp->name(), nullptr};
resizeTaskRefp->taskp(resizeAllTaskp);
randomizep->addStmtsp(resizeTaskRefp->makeStmt());
}
AstFunc* const basicRandomizep
= V3Randomize::newRandomizeFunc(m_memberMap, nodep, "__Vbasic_randomize");
addBasicRandomizeBody(basicRandomizep, nodep, randModeVarp);
@@ -2161,6 +2203,57 @@ class RandomizeVisitor final : public VNVisitor {
UINFO(9, "Added `%s` randomization procedure");
VL_DO_DANGLING(withp->deleteTree(), withp);
}
void visit(AstConstraint* nodep) override {
VL_RESTORER(m_constraintp);
m_constraintp = nodep;
iterateChildren(nodep);
}
void visit(AstCMethodHard* nodep) override {
iterateChildren(nodep);
FileLine* const fl = nodep->fileline();
if (m_constraintp && nodep->fromp()->user1() && nodep->name() == "size") {
AstClass* const classp = VN_AS(m_modp, Class);
AstVarRef* const queueVarRefp = VN_CAST(nodep->fromp(), VarRef);
if (!queueVarRefp) {
// Warning from ConstraintExprVisitor will be thrown
return;
}
AstVar* const queueVarp = queueVarRefp->varp();
AstVar* sizeVarp = VN_CAST(queueVarp->user4p(), Var);
if (!sizeVarp) {
sizeVarp = new AstVar{fl, VVarType::BLOCKTEMP, "__V" + queueVarp->name() + "_size",
nodep->findSigned32DType()};
classp->addMembersp(sizeVarp);
m_memberMap.insert(classp, sizeVarp);
sizeVarp->user2p(classp);
queueVarp->user4p(sizeVarp);
AstTask* resizerTaskp = VN_AS(m_constraintp->user3p(), Task);
if (!resizerTaskp) {
resizerTaskp = newResizeConstrainedArrayTask(classp, m_constraintp->name());
m_constraintp->user3p(resizerTaskp);
}
AstCMethodHard* const resizep
= new AstCMethodHard{fl, nodep->fromp()->unlinkFrBack(), "resize",
new AstVarRef{fl, sizeVarp, VAccess::READ}};
resizep->dtypep(nodep->findVoidDType());
resizerTaskp->addStmtsp(new AstStmtExpr{fl, resizep});
// Since size variable is signed int, we need additional constraint
// to make sure it is always >= 0.
AstVarRef* const sizeVarRefp = new AstVarRef{fl, sizeVarp, VAccess::READ};
sizeVarRefp->user1(true);
AstGteS* const sizeGtep = new AstGteS{fl, sizeVarRefp, new AstConst{fl, 0}};
sizeGtep->user1(true);
m_constraintp->addItemsp(new AstConstraintExpr{fl, sizeGtep});
}
AstVarRef* const sizeVarRefp = new AstVarRef{fl, sizeVarp, VAccess::READ};
sizeVarRefp->user1(true);
nodep->replaceWith(sizeVarRefp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
void visit(AstNodeStmt* nodep) override {
VL_RESTORER(m_stmtp);
m_stmtp = nodep;