Fix dist range bounds over rand variables failing randomization since #7802

This commit is contained in:
Yilou Wang 2026-07-06 20:14:24 +02:00
parent 119493ee8a
commit 5797913600
1 changed files with 41 additions and 20 deletions

View File

@ -4571,31 +4571,47 @@ class RandomizeVisitor final : public VNVisitor {
continue;
}
const auto boundRefsRandVarp = [](const AstNode* boundp) -> bool {
bool found = false;
boundp->foreach([&](const AstVarRef* vrefp) {
if (vrefp->varp()->rand().isRandomizable()) found = true;
});
return found;
};
// (distExpr >= lo) && (distExpr <= hi); signed comparisons for signed vars
const auto rangeMembershipp = [&](const AstInsideRange* irp) -> AstNodeExpr* {
const bool isSigned = distp->exprp()->isSigned();
AstNodeExpr* const distExprGtep = distp->exprp()->cloneTreePure(false);
AstNodeExpr* const distExprLtep = distp->exprp()->cloneTreePure(false);
distExprGtep->user1(true);
distExprLtep->user1(true);
AstNodeExpr* const gep
= isSigned
? static_cast<AstNodeExpr*>(
new AstGteS{fl, distExprGtep, irp->lhsp()->cloneTreePure(false)})
: static_cast<AstNodeExpr*>(
new AstGte{fl, distExprGtep, irp->lhsp()->cloneTreePure(false)});
AstNodeExpr* const lep
= isSigned
? static_cast<AstNodeExpr*>(
new AstLteS{fl, distExprLtep, irp->rhsp()->cloneTreePure(false)})
: static_cast<AstNodeExpr*>(
new AstLte{fl, distExprLtep, irp->rhsp()->cloneTreePure(false)});
gep->user1(true);
lep->user1(true);
AstNodeExpr* const andp = new AstLogAnd{fl, gep, lep};
andp->user1(true);
return andp;
};
// IEEE 1800-2023 18.5.3: values not in the distribution must never appear.
// Build the union of all non-zero-weight ranges as a single hard ConstraintExpr
AstNodeExpr* unionExprp = nullptr;
for (const auto& bucket : buckets) {
AstNodeExpr* memberp;
if (const AstInsideRange* const irp = VN_CAST(bucket.rangep, InsideRange)) {
// (distExpr >= lo) && (distExpr <= hi); signed comparisons for signed vars
const bool isSigned = distp->exprp()->isSigned();
AstNodeExpr* const distExprGtep = distp->exprp()->cloneTreePure(false);
AstNodeExpr* const distExprLtep = distp->exprp()->cloneTreePure(false);
distExprGtep->user1(true);
distExprLtep->user1(true);
AstNodeExpr* const gep
= isSigned ? static_cast<AstNodeExpr*>(new AstGteS{
fl, distExprGtep, irp->lhsp()->cloneTreePure(false)})
: static_cast<AstNodeExpr*>(new AstGte{
fl, distExprGtep, irp->lhsp()->cloneTreePure(false)});
AstNodeExpr* const lep
= isSigned ? static_cast<AstNodeExpr*>(new AstLteS{
fl, distExprLtep, irp->rhsp()->cloneTreePure(false)})
: static_cast<AstNodeExpr*>(new AstLte{
fl, distExprLtep, irp->rhsp()->cloneTreePure(false)});
gep->user1(true);
lep->user1(true);
memberp = new AstLogAnd{fl, gep, lep};
memberp = rangeMembershipp(irp);
} else {
// distExpr == val
AstNodeExpr* const distExprCopyp = distp->exprp()->cloneTreePure(false);
@ -4673,7 +4689,12 @@ class RandomizeVisitor final : public VNVisitor {
AstNode* chainp = nullptr;
for (int i = static_cast<int>(buckets.size()) - 1; i >= 0; --i) {
AstNodeExpr* constraintExprp;
if (const AstInsideRange* const irp = VN_CAST(buckets[i].rangep, InsideRange)) {
const AstInsideRange* const irp = VN_CAST(buckets[i].rangep, InsideRange);
if (irp && (boundRefsRandVarp(irp->lhsp()) || boundRefsRandVarp(irp->rhsp()))) {
// Bounds solved concurrently cannot pin a pre-solve value; softly
// prefer the symbolic range so the hard membership stays satisfiable
constraintExprp = rangeMembershipp(irp);
} else if (irp) {
// Pick distExpr = lo + rand64() % (hi - lo + 1) for a uniform value in range
AstNodeExpr* const distExprCopyp = distp->exprp()->cloneTreePure(false);
distExprCopyp->user1(true);