fix ci failing tests
This commit is contained in:
parent
cf556aa4ab
commit
2acc674a7a
|
|
@ -3479,10 +3479,7 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
// Lower dist constraints into weighted bucket selection + AstConstraintIf chains.
|
||||
// Called for each constraint before ConstraintExprVisitor.
|
||||
// taskp: constraint setup task (bucket var declarations + assignments go here)
|
||||
// constrItemsp: first item in the constraint item list
|
||||
// Replace AstDist with weighted bucket selection via AstConstraintIf chain
|
||||
void lowerDistConstraints(AstTask* taskp, AstNode* constrItemsp) {
|
||||
for (AstNode *nextip, *itemp = constrItemsp; itemp; itemp = nextip) {
|
||||
nextip = itemp->nextp();
|
||||
|
|
@ -3493,9 +3490,8 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
|
||||
FileLine* const fl = distp->fileline();
|
||||
|
||||
// Collect buckets and compute effective weights
|
||||
struct BucketInfo final {
|
||||
AstNodeExpr* rangep; // Points into distItem (will be cloned, not unlinked)
|
||||
AstNodeExpr* rangep;
|
||||
uint64_t effectiveWeight;
|
||||
};
|
||||
std::vector<BucketInfo> buckets;
|
||||
|
|
@ -3504,21 +3500,20 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
for (AstDistItem* ditemp = distp->itemsp(); ditemp;
|
||||
ditemp = VN_AS(ditemp->nextp(), DistItem)) {
|
||||
const AstConst* const weightp = VN_CAST(ditemp->weightp(), Const);
|
||||
if (!weightp) continue; // Non-const weight: skip
|
||||
if (!weightp) continue;
|
||||
const uint64_t w = weightp->toUQuad();
|
||||
if (w == 0) continue; // weight=0 means never
|
||||
if (w == 0) continue;
|
||||
|
||||
uint64_t effectiveW = w;
|
||||
if (!ditemp->isWhole()) { // := weight is per-value; multiply by range size
|
||||
// := is per-value weight, so multiply by range size
|
||||
if (!ditemp->isWhole()) {
|
||||
if (const AstInsideRange* const irp = VN_CAST(ditemp->rangep(), InsideRange)) {
|
||||
const AstConst* const lop = VN_CAST(irp->lhsp(), Const);
|
||||
const AstConst* const hip = VN_CAST(irp->rhsp(), Const);
|
||||
if (lop && hip && hip->toUQuad() >= lop->toUQuad())
|
||||
effectiveW = w * (hip->toUQuad() - lop->toUQuad() + 1);
|
||||
}
|
||||
// scalar: effectiveW stays w
|
||||
}
|
||||
// :/ weight: effectiveW stays w (weight for whole range, not per-value)
|
||||
|
||||
buckets.push_back({ditemp->rangep(), effectiveW});
|
||||
totalWeight += effectiveW;
|
||||
|
|
@ -3526,7 +3521,6 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
|
||||
if (buckets.empty() || totalWeight == 0) continue;
|
||||
|
||||
// Create bucket selection variable: uint64_t __Vdist_bucketN
|
||||
const std::string bucketName = "__Vdist_bucket" + cvtToStr(m_distNum++);
|
||||
AstVar* const bucketVarp
|
||||
= new AstVar{fl, VVarType::BLOCKTEMP, bucketName, taskp->findUInt64DType()};
|
||||
|
|
@ -3535,8 +3529,7 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
bucketVarp->funcLocal(true);
|
||||
taskp->addStmtsp(bucketVarp);
|
||||
|
||||
// Assign: bucketVar = (rand64() % totalWeight) + 1
|
||||
// +1 ensures that weight=0 items are never selected
|
||||
// bucketVar = (rand64() % totalWeight) + 1
|
||||
AstNodeExpr* randp = new AstRand{fl, nullptr, false};
|
||||
randp->dtypeSetUInt64();
|
||||
taskp->addStmtsp(new AstAssign{
|
||||
|
|
@ -3545,10 +3538,7 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
new AstModDiv{fl, randp,
|
||||
new AstConst{fl, AstConst::Unsized64{}, totalWeight}}}});
|
||||
|
||||
// Build AstConstraintIf chain (last-to-first so nesting is natural):
|
||||
// if (bucket <= w0) { exprp == range0 }
|
||||
// else if (bucket <= w0+w1) { exprp in range1 }
|
||||
// ...
|
||||
// Build if/else chain keyed on cumulative weights
|
||||
AstNode* chainp = nullptr;
|
||||
uint64_t cumWeight = totalWeight;
|
||||
|
||||
|
|
@ -3556,10 +3546,8 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
cumWeight -= buckets[i].effectiveWeight;
|
||||
const uint64_t thisCumWeight = cumWeight + buckets[i].effectiveWeight;
|
||||
|
||||
// Build range constraint expression (user1=true for rand-dependent nodes)
|
||||
AstNodeExpr* constraintExprp;
|
||||
if (const AstInsideRange* const irp = VN_CAST(buckets[i].rangep, InsideRange)) {
|
||||
// Range bucket: exprp >= lo && exprp <= hi
|
||||
AstNodeExpr* const exprCopy1p = distp->exprp()->cloneTreePure(false);
|
||||
exprCopy1p->user1(true);
|
||||
AstNodeExpr* const exprCopy2p = distp->exprp()->cloneTreePure(false);
|
||||
|
|
@ -3573,7 +3561,6 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
constraintExprp = new AstLogAnd{fl, gtep, ltep};
|
||||
constraintExprp->user1(true);
|
||||
} else {
|
||||
// Scalar bucket: exprp == value
|
||||
AstNodeExpr* const exprCopyp = distp->exprp()->cloneTreePure(false);
|
||||
exprCopyp->user1(true);
|
||||
constraintExprp
|
||||
|
|
@ -3584,10 +3571,8 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
AstConstraintExpr* const thenp = new AstConstraintExpr{fl, constraintExprp};
|
||||
|
||||
if (!chainp) {
|
||||
// Last bucket: no condition needed (always selected when reached)
|
||||
chainp = thenp;
|
||||
} else {
|
||||
// Bucket condition: bucketVar <= thisCumWeight (NOT rand-dependent)
|
||||
AstNodeExpr* const condp
|
||||
= new AstLte{fl, new AstVarRef{fl, bucketVarp, VAccess::READ},
|
||||
new AstConst{fl, AstConst::Unsized64{}, thisCumWeight}};
|
||||
|
|
@ -3596,7 +3581,6 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
if (chainp) {
|
||||
// Replace AstConstraintExpr(AstDist) with the weighted-bucket chain
|
||||
constrExprp->replaceWith(chainp);
|
||||
VL_DO_DANGLING(constrExprp->deleteTree(), constrExprp);
|
||||
}
|
||||
|
|
@ -3669,7 +3653,6 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
if (constrp->itemsp()) expandUniqueElementList(constrp->itemsp());
|
||||
// Lower dist constraints into weighted bucket selection before SMT encoding
|
||||
if (constrp->itemsp()) lowerDistConstraints(taskp, constrp->itemsp());
|
||||
ConstraintExprVisitor{classp, m_memberMap, constrp->itemsp(), nullptr,
|
||||
genp, randModeVarp, m_writtenVars};
|
||||
|
|
|
|||
|
|
@ -3088,9 +3088,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
iterateCheck(nodep, "Dist Item", itemp, CONTEXT_DET, FINAL, subDTypep, EXTEND_EXP);
|
||||
}
|
||||
|
||||
// Inside a constraint: keep AstDist alive for V3Randomize to do weighted bucket
|
||||
// selection, but only if all items have const weights and simple ranges (scalar or
|
||||
// InsideRange). Array/queue-based dist items are not supported by lowerDistConstraints.
|
||||
// Keep AstDist for V3Randomize if all items have const weights and simple ranges
|
||||
if (m_constraintp) {
|
||||
bool canLower = true;
|
||||
for (const AstDistItem* itemp = nodep->itemsp(); itemp;
|
||||
|
|
@ -3104,7 +3102,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (canLower) return;
|
||||
}
|
||||
|
||||
// Outside constraint: lower to inside expressions (ignores weights - imperfect)
|
||||
// Outside constraint or complex items: lower to inside (ignores weights)
|
||||
nodep->v3warn(CONSTRAINTIGN, "Constraint expression ignored (imperfect distribution)");
|
||||
AstNodeExpr* newp = nullptr;
|
||||
for (AstDistItem* itemp = nodep->itemsp(); itemp;
|
||||
|
|
|
|||
|
|
@ -10,24 +10,18 @@
|
|||
`define check_range(gotv,minv,maxv) do if ((gotv) < (minv) || (gotv) > (maxv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d-%0d\n", `__FILE__,`__LINE__, (gotv), (minv), (maxv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
// Test that dist constraint weights (:= and :/) produce correct distributions.
|
||||
// IEEE 1800-2017 18.5.4
|
||||
|
||||
class DistScalar;
|
||||
rand bit [7:0] x;
|
||||
// := weight is per-value: 0 has weight 1, 255 has weight 3 => ~75% should be 255
|
||||
constraint c { x dist { 8'd0 := 1, 8'd255 := 3 }; }
|
||||
endclass
|
||||
|
||||
class DistRange;
|
||||
rand bit [7:0] x;
|
||||
// :/ weight is per-range: [0:9] has total weight 1, [10:19] has total weight 3
|
||||
constraint c { x dist { [8'd0:8'd9] :/ 1, [8'd10:8'd19] :/ 3 }; }
|
||||
endclass
|
||||
|
||||
class DistZeroWeight;
|
||||
rand bit [7:0] x;
|
||||
// Weight 0 means never selected
|
||||
constraint c { x dist { 8'd0 := 0, 8'd1 := 1, 8'd2 := 1 }; }
|
||||
endclass
|
||||
|
||||
|
|
@ -42,18 +36,17 @@ module t;
|
|||
|
||||
total = 2000;
|
||||
|
||||
// Test 1: := scalar weights (expect ~75% for value 255)
|
||||
// := scalar weights: expect ~75% for value 255
|
||||
sc = new;
|
||||
count_high = 0;
|
||||
repeat (total) begin
|
||||
`checkd(sc.randomize(), 1);
|
||||
if (sc.x == 8'd255) count_high++;
|
||||
else `checkd(sc.x, 0); // Only 0 or 255 should appear
|
||||
else `checkd(sc.x, 0);
|
||||
end
|
||||
// 75% of 2000 = 1500, allow wide range for statistical test
|
||||
`check_range(count_high, 1200, 1800);
|
||||
|
||||
// Test 2: :/ range weights (expect ~75% in [10:19])
|
||||
// :/ range weights: expect ~75% in [10:19]
|
||||
rg = new;
|
||||
count_range_high = 0;
|
||||
repeat (total) begin
|
||||
|
|
@ -66,7 +59,7 @@ module t;
|
|||
end
|
||||
`check_range(count_range_high, 1200, 1800);
|
||||
|
||||
// Test 3: Zero weight exclusion (value 0 should never appear)
|
||||
// Zero weight: value 0 must never appear
|
||||
zw = new;
|
||||
repeat (total) begin
|
||||
`checkd(zw.randomize(), 1);
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
%Warning-CONSTRAINTIGN: t/t_randomize.v:43:23: Constraint expression ignored (imperfect distribution)
|
||||
: ... note: In instance 't'
|
||||
43 | constraint order { solve length before header; }
|
||||
| ^~~~~
|
||||
... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest
|
||||
... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message.
|
||||
%Error: Exiting due to
|
||||
|
|
@ -11,6 +11,6 @@ import vltest_bootstrap
|
|||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
test.lint()
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
Loading…
Reference in New Issue