Fix array reference in reduction constraints (#8158)

Signed-off-by: Kornel Uriasz <kuriasz@antmicro.com>
This commit is contained in:
Kornel Uriasz 2026-08-19 15:52:04 +02:00 committed by GitHub
parent cacadd6c7d
commit f6f6f84047
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 83 additions and 27 deletions

View File

@ -1218,6 +1218,14 @@ class ConstraintExprVisitor final : public VNVisitor {
return preamblep;
}
// Create SFormatF for array dereference inside solver
AstSFormatF* createSolverArrDerefp(FileLine* const fl, AstNodeExpr* const arrExprp,
AstNodeExpr* const idxExprp) {
AstNodeExpr* const argsp = AstNode::addNext(arrExprp, idxExprp);
AstSFormatF* const formatp = new AstSFormatF{fl, "(select %s %s)", false, argsp};
return formatp;
}
// VISITORS
void visit(AstNodeVarRef* nodep) override {
AstVar* varp = nodep->varp();
@ -2650,9 +2658,9 @@ class ConstraintExprVisitor final : public VNVisitor {
iterateChildren(nodep);
AstNodeExpr* const pinp = nodep->pinsp()->unlinkFrBack();
if (VN_IS(pinp, SFormatF) && m_structSel) VN_AS(pinp, SFormatF)->name("%x");
AstNodeExpr* const argsp = AstNode::addNext(nodep->fromp()->unlinkFrBack(), pinp);
AstSFormatF* newp;
if (m_structSel) {
AstNodeExpr* const argsp = AstNode::addNext(nodep->fromp()->unlinkFrBack(), pinp);
sizep->dtypeSetInt();
AstLogAnd* const condp = new AstLogAnd{
fl,
@ -2663,7 +2671,7 @@ class ConstraintExprVisitor final : public VNVisitor {
m_conditionp = m_conditionp ? new AstLogAnd{fl, m_conditionp, condp} : condp;
newp = new AstSFormatF{fl, "%s.%s", false, argsp};
} else {
newp = new AstSFormatF{fl, "(select %s %s)", false, argsp};
newp = createSolverArrDerefp(fl, nodep->fromp()->unlinkFrBack(), pinp);
}
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
@ -2874,34 +2882,40 @@ class ConstraintExprVisitor final : public VNVisitor {
AstNodeModule* const genModulep = VN_AS(m_genp->user2p(), NodeModule);
arrVarp->user3(true);
// Create variable name using AstSFormatF
AstSFormatF* const varNamep = new AstSFormatF{
fl, smtArrayName + "_%x", false, new AstVarRef{fl, loopVarp, VAccess::READ}};
// Add write_var call to init task
AstNodeExpr* const arrVarNamep
= new AstCExpr{fl, AstCExpr::Pure{}, "\"" + smtArrayName + "\"", elemWidth};
AstCMethodHard* const writeVarCallp
= new AstCMethodHard{fl, new AstVarRef{fl, genModulep, m_genp, VAccess::READ},
VCMethod::RANDOMIZER_WRITE_VAR};
writeVarCallp->addPinsp(new AstVarRef{fl, arrModulep, arrVarp, VAccess::READ});
writeVarCallp->addPinsp(
new AstConst{fl, AstConst::Unsized64{}, static_cast<uint64_t>(elemWidth)});
writeVarCallp->addPinsp(arrVarNamep);
const uint32_t unpackedDims = arrVarp->dtypep()->dimensions(false).second;
UASSERT_OBJ(unpackedDims == 1, arrVarp, "Array isn't 1-D");
writeVarCallp->addPinsp(new AstConst{fl, 1}); // Dimension
// Create array element reference: array.atWrite(index)
AstCMethodHard* const atWritep = new AstCMethodHard{
fl, new AstVarRef{fl, arrModulep, arrVarp, VAccess::READWRITE},
VCMethod::ARRAY_AT_WRITE, new AstVarRef{fl, loopVarp, VAccess::READ}};
atWritep->dtypeFrom(elemDtp);
const RandomizeMode randMode = {.asInt = arrVarp->user1()};
if (randMode.usesMode) {
writeVarCallp->addPinsp(
new AstConst{fl, AstConst::Unsized64{}, randMode.index});
}
writeVarCallp->dtypeSetVoid();
AstNodeFTask* initTaskp = m_inlineInitTaskp;
if (!initTaskp) {
initTaskp = VN_AS(m_memberMap.findMember(arrModulep, "new"), NodeFTask);
UASSERT_OBJ(initTaskp, arrModulep, "No new() in class");
}
initTaskp->addStmtsp(writeVarCallp->makeStmt());
// Convert std::string to const char* for write_var
AstCExpr* const varNameCStrp = new AstCExpr{fl, AstCExpr::Pure{}};
varNameCStrp->dtypeSetString();
varNameCStrp->add("(");
varNameCStrp->add(varNamep->cloneTree(false));
varNameCStrp->add(").c_str()");
// Create solver constraints
AstSFormatF* const idxFormatp = new AstSFormatF{
fl, "#x%08x", false, new AstVarRef{fl, loopVarp, VAccess::READ}};
iterateChildren(nodep);
AstSFormatF* const varNamep
= createSolverArrDerefp(fl, nodep->fromp()->unlinkFrBack(), idxFormatp);
// Create write_var method call: gen.write_var(arrElement, width, name, 0)
AstCMethodHard* const writeVarp = new AstCMethodHard{
fl, new AstVarRef{fl, genModulep, m_genp, VAccess::READWRITE},
VCMethod::RANDOMIZER_WRITE_VAR, atWritep};
writeVarp->addPinsp(new AstConst{fl, AstConst::WidthedValue{}, 64,
static_cast<uint32_t>(elemWidth)});
writeVarp->addPinsp(varNameCStrp);
writeVarp->addPinsp(new AstConst{fl, AstConst::WidthedValue{}, 64, 0});
writeVarp->dtypeSetVoid();
cstmtp->add(writeVarp->makeStmt());
cstmtp->add("ret += \" \";\n");
cstmtp->add("ret += ");
cstmtp->add(varNamep);

View File

@ -153,6 +153,38 @@ class H;
}
endclass
class I;
rand int a;
rand int arr[];
constraint c1 {
arr.size() == 5;
foreach(arr[i]) {
arr[i] inside {[10 : 200]};
}
}
constraint c2 {
a + arr.sum() == 200;
}
endclass
class J;
rand int a;
rand int arr[];
function new();
arr = new [5];
endfunction
constraint c1 {
foreach(arr[i]) {
arr[i] inside {[10 : 200]};
}
}
constraint c2 {
a + arr.sum() == 200;
}
endclass
module t;
initial begin
automatic C c = new;
@ -161,6 +193,8 @@ module t;
automatic F f = new;
automatic G g = new;
automatic H h = new;
automatic I i = new;
automatic J j = new;
`check_rand(c, c.x, 4 < c.x && c.x < 7);
`check_rand(d, d.posit, (d.posit ? 4 : -3) < d.x && d.x < (d.posit ? 7 : 0));
@ -176,6 +210,14 @@ module t;
foreach (h.a[i]) begin
`check_rand(h, h.a[i], (h.a[i] != h.b));
end
`check_rand(i, i.a, (i.arr.sum() + i.a == 200));
foreach (i.arr[it]) begin
`check_rand(i, i.arr[it], (i.arr[it] inside {[10 : 200]}));
end
`check_rand(j, j.a, (j.arr.sum() + j.a == 200));
foreach (j.arr[i]) begin
`check_rand(j, j.arr[i], (j.arr[i] inside {[10 : 200]}));
end
$write("*-* All Finished *-*\n");
$finish;
end