Support rand dynamic arrays used inside with clause of randomize (#8246)

Signed-off-by: Kamil Danecki <[email protected]>
Signed-off-by: Igor Zaworski <[email protected]>
This commit is contained in:
Kamil Danecki
2026-09-10 10:40:30 -04:00
committed by GitHub
parent 557c21a337
commit ee792e235a
11 changed files with 432 additions and 40 deletions
+59 -40
View File
@@ -1465,7 +1465,7 @@ class ConstraintExprVisitor final : public VNVisitor {
AstMemberSel* const memberselp, const std::string& smtName,
AstNodeModule* const classOrPackagep) const {
uint32_t unpackedDims = 0;
if (varp->dtypep()->isNonPackedArray()) {
if (varp->dtypeSkipRefp()->isNonPackedArray()) {
unpackedDims = varp->dtypep()->dimensions(false).second;
}
if (VN_IS(varp->dtypeSkipRefp(), StructDType)
@@ -2688,47 +2688,66 @@ class ConstraintExprVisitor final : public VNVisitor {
if (editFormat(nodep)) return;
FileLine* const fl = nodep->fileline();
if (nodep->method() == VCMethod::ARRAY_AT && nodep->fromp()->user1()) {
// Queue/dynamic element: pre-edit clone for the rand_mode hoist, non-rand index only.
// A std::randomize() with-clause argument carries no rand qualifier
// of its own but is still part of the solve.
bool indexIsRand = false;
if (nodep->pinsp()) {
nodep->pinsp()->foreach([&](const AstNodeVarRef* vrefp) {
if (vrefp->varp()->rand().isRandomizable()
|| vrefp->varp()->isStdRandomizeArg()) {
indexIsRand = true;
if (nodep->method() == VCMethod::ARRAY_AT) {
const bool indexIsRand = nodep->pinsp()->exists([](const AstNodeVarRef* const vrefp) {
return vrefp->varp()->rand().isRandomizable();
});
if (nodep->fromp()->user1()) {
// Queue/dynamic element: pre-edit clone for the rand_mode hoist, non-rand index
// only. A std::randomize() with-clause argument carries no rand qualifier of its
// own but is still part of the solve.
{
const AstNode* const basep = nodep->baseFromp(true);
if (basep->name() == "__Vthis"
&& VN_AS(basep->backp(), MemberSel)->varp()->isRand()) {
nodep->fromp()->v3warn(E_UNSUPPORTED,
"Unsupported: Complex expression captured from "
"current scope with randomized variable");
return;
}
});
}
AstNodeExpr* const origp = indexIsRand ? nullptr : nodep->cloneTree(false);
AstCMethodHard* const sizep
= m_structSel ? new AstCMethodHard{fl, nodep->fromp()->cloneTreePure(false),
VCMethod::DYN_SIZE}
: nullptr;
AstNodeExpr* const originalPinp = nodep->pinsp();
iterateChildren(nodep);
AstNodeExpr* const pinp = nodep->pinsp()->unlinkFrBack();
if (VN_IS(pinp, SFormatF) && m_structSel) VN_AS(pinp, SFormatF)->name("%x");
AstSFormatF* newp;
if (m_structSel) {
AstNodeExpr* const argsp = AstNode::addNext(nodep->fromp()->unlinkFrBack(), pinp);
sizep->dtypeSetInt();
AstLogAnd* const condp = new AstLogAnd{
fl,
new AstLteS{
fl, new AstConst{fl, AstConst::WidthedValue{}, originalPinp->width(), 0},
originalPinp->cloneTreePure(false)},
new AstLtS{fl, originalPinp->cloneTreePure(false), sizep}};
m_conditionp = m_conditionp ? new AstLogAnd{fl, m_conditionp, condp} : condp;
newp = new AstSFormatF{fl, "%s.%s", false, argsp};
}
AstNodeExpr* const origp = indexIsRand ? nullptr : nodep->cloneTree(false);
AstCMethodHard* const sizep
= m_structSel ? new AstCMethodHard{fl, nodep->fromp()->cloneTreePure(false),
VCMethod::DYN_SIZE}
: nullptr;
AstNodeExpr* const originalPinp = nodep->pinsp();
iterateChildren(nodep);
AstNodeExpr* const pinp = nodep->pinsp()->unlinkFrBack();
AstSFormatF* newp;
if (m_structSel) {
if (AstSFormatF* const sformatfp = VN_CAST(pinp, SFormatF)) {
sformatfp->name("%x");
}
AstNodeExpr* const argsp
= AstNode::addNext(nodep->fromp()->unlinkFrBack(), pinp);
sizep->dtypeSetInt();
AstLogAnd* const condp
= new AstLogAnd{fl,
new AstLteS{fl,
new AstConst{fl, AstConst::WidthedValue{},
originalPinp->width(), 0},
originalPinp->cloneTreePure(false)},
new AstLtS{fl, originalPinp->cloneTreePure(false), sizep}};
m_conditionp = m_conditionp ? new AstLogAnd{fl, m_conditionp, condp} : condp;
newp = new AstSFormatF{fl, "%s.%s", false, argsp};
} else {
newp = createSolverArrDerefp(fl, nodep->fromp()->unlinkFrBack(), pinp);
}
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
if (origp && !hoistRandModeOverSelect(newp, origp)) {
VL_DO_DANGLING(origp->deleteTree(), origp);
}
} else if (indexIsRand) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Randomization of an index to a non-random variable");
} else {
newp = createSolverArrDerefp(fl, nodep->fromp()->unlinkFrBack(), pinp);
}
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
if (origp && !hoistRandModeOverSelect(newp, origp)) {
VL_DO_DANGLING(origp->deleteTree(), origp);
nodep->user1(false);
UASSERT_OBJ(editFormat(nodep), nodep,
"editFormat should return true when user1 is false");
}
return;
}