diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index da5d32b90..c0c9e1707 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -4453,6 +4453,39 @@ class RandomizeVisitor final : public VNVisitor { return new AstConstraintIf{fl, condp, thenBodyp, nullptr}; } + static bool distBoundRefsRandVar(const AstNode* boundp) { + 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 + static AstNodeExpr* newDistRangeMembership(AstDist* distp, const AstInsideRange* irp) { + FileLine* const fl = distp->fileline(); + 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( + new AstGteS{fl, distExprGtep, irp->lhsp()->cloneTreePure(false)}) + : static_cast( + new AstGte{fl, distExprGtep, irp->lhsp()->cloneTreePure(false)}); + AstNodeExpr* const lep + = isSigned ? static_cast( + new AstLteS{fl, distExprLtep, irp->rhsp()->cloneTreePure(false)}) + : static_cast( + 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; + } + // Replace AstDist with weighted bucket selection via AstConstraintIf chain. // Supports both constant and variable weight expressions. void lowerDistConstraints(AstTask* taskp, AstNode* constrItemsp, @@ -4571,47 +4604,13 @@ 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( - new AstGteS{fl, distExprGtep, irp->lhsp()->cloneTreePure(false)}) - : static_cast( - new AstGte{fl, distExprGtep, irp->lhsp()->cloneTreePure(false)}); - AstNodeExpr* const lep - = isSigned - ? static_cast( - new AstLteS{fl, distExprLtep, irp->rhsp()->cloneTreePure(false)}) - : static_cast( - 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)) { - memberp = rangeMembershipp(irp); + memberp = newDistRangeMembership(distp, irp); } else { // distExpr == val AstNodeExpr* const distExprCopyp = distp->exprp()->cloneTreePure(false); @@ -4690,10 +4689,11 @@ class RandomizeVisitor final : public VNVisitor { for (int i = static_cast(buckets.size()) - 1; i >= 0; --i) { AstNodeExpr* constraintExprp; const AstInsideRange* const irp = VN_CAST(buckets[i].rangep, InsideRange); - if (irp && (boundRefsRandVarp(irp->lhsp()) || boundRefsRandVarp(irp->rhsp()))) { + if (irp + && (distBoundRefsRandVar(irp->lhsp()) || distBoundRefsRandVar(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); + constraintExprp = newDistRangeMembership(distp, irp); } else if (irp) { // Pick distExpr = lo + rand64() % (hi - lo + 1) for a uniform value in range AstNodeExpr* const distExprCopyp = distp->exprp()->cloneTreePure(false);