Gate dist by whether the expression value can still be drawn, fixing frozen-index weights
This commit is contained in:
parent
50c1059374
commit
71334a9234
|
|
@ -4561,19 +4561,25 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
return new AstConstraintExpr{fl, unionExprp};
|
return new AstConstraintExpr{fl, unionExprp};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gate the weighted chain on the rand_mode bits of the dist's variables, so a
|
// Weighted chain while any value-source variable is active, membership once
|
||||||
// frozen variable requires only membership, not a freshly drawn bucket.
|
// all are frozen.
|
||||||
AstNode* gateFrozenDist(AstNode* chainp, AstDist* distp,
|
AstNode* gateFrozenDist(AstNode* chainp, AstDist* distp,
|
||||||
const std::vector<DistBucket>& buckets, AstVar* randModeVarp) {
|
const std::vector<DistBucket>& buckets, AstVar* randModeVarp) {
|
||||||
FileLine* const fl = distp->fileline();
|
FileLine* const fl = distp->fileline();
|
||||||
AstNodeExpr* gatep = nullptr;
|
AstNodeExpr* gatep = nullptr;
|
||||||
std::unordered_set<const AstVar*> gatedVars;
|
std::unordered_set<const AstVar*> gatedVars;
|
||||||
|
// Handles are never re-pointed by randomize(), only read through.
|
||||||
|
std::unordered_set<const AstVar*> handleVars;
|
||||||
|
distp->exprp()->foreach([&](const AstMemberSel* mselp) {
|
||||||
|
mselp->fromp()->foreach(
|
||||||
|
[&](const AstNodeVarRef* hrefp) { handleVars.insert(hrefp->varp()); });
|
||||||
|
});
|
||||||
const auto addModeGate = [&](AstNodeExpr* modeArrayp, uint32_t index) {
|
const auto addModeGate = [&](AstNodeExpr* modeArrayp, uint32_t index) {
|
||||||
AstCMethodHard* const atp
|
AstCMethodHard* const atp
|
||||||
= new AstCMethodHard{fl, modeArrayp, VCMethod::ARRAY_AT, new AstConst{fl, index}};
|
= new AstCMethodHard{fl, modeArrayp, VCMethod::ARRAY_AT, new AstConst{fl, index}};
|
||||||
atp->dtypeSetUInt32();
|
atp->dtypeSetUInt32();
|
||||||
if (gatep) {
|
if (gatep) {
|
||||||
gatep = new AstLogAnd{fl, gatep, atp};
|
gatep = new AstLogOr{fl, gatep, atp};
|
||||||
gatep->dtypeSetBit();
|
gatep->dtypeSetBit();
|
||||||
} else {
|
} else {
|
||||||
gatep = atp;
|
gatep = atp;
|
||||||
|
|
@ -4586,13 +4592,21 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
return new AstVarRef{fl, VN_AS(smodep->user2p(), NodeModule), smodep, VAccess::READ};
|
return new AstVarRef{fl, VN_AS(smodep->user2p(), NodeModule), smodep, VAccess::READ};
|
||||||
};
|
};
|
||||||
// Each direct, static, or sub-object member reference carries a mode bit.
|
// Each direct, static, or sub-object member reference carries a mode bit.
|
||||||
|
// A rand variable without a mode bit can never freeze, so no gate is needed.
|
||||||
|
bool alwaysActive = false;
|
||||||
distp->exprp()->foreach([&](const AstNode* nodep) {
|
distp->exprp()->foreach([&](const AstNode* nodep) {
|
||||||
const AstNodeVarRef* const refp = VN_CAST(nodep, NodeVarRef);
|
const AstNodeVarRef* const refp = VN_CAST(nodep, NodeVarRef);
|
||||||
const AstMemberSel* const mselp = VN_CAST(nodep, MemberSel);
|
const AstMemberSel* const mselp = VN_CAST(nodep, MemberSel);
|
||||||
if (!refp && !mselp) return;
|
if (!refp && !mselp) return;
|
||||||
AstVar* const varp = refp ? refp->varp() : mselp->varp();
|
AstVar* const varp = refp ? refp->varp() : mselp->varp();
|
||||||
|
if (refp && handleVars.count(varp)) return;
|
||||||
|
if (!varp->rand().isRandomizable()) return;
|
||||||
const RandomizeMode rmode = {.asInt = varp->user1()};
|
const RandomizeMode rmode = {.asInt = varp->user1()};
|
||||||
if (!rmode.usesMode || !gatedVars.insert(varp).second) return;
|
if (!rmode.usesMode) {
|
||||||
|
alwaysActive = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!gatedVars.insert(varp).second) return;
|
||||||
if (varp->lifetime().isStatic()) {
|
if (varp->lifetime().isStatic()) {
|
||||||
if (AstNodeExpr* const readp = staticModeRead(varp)) {
|
if (AstNodeExpr* const readp = staticModeRead(varp)) {
|
||||||
addModeGate(readp, rmode.index);
|
addModeGate(readp, rmode.index);
|
||||||
|
|
@ -4603,7 +4617,6 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
if (!memberModep) return;
|
if (!memberModep) return;
|
||||||
AstMemberSel* const modeSelp
|
AstMemberSel* const modeSelp
|
||||||
= new AstMemberSel{fl, mselp->fromp()->cloneTreePure(false), memberModep};
|
= new AstMemberSel{fl, mselp->fromp()->cloneTreePure(false), memberModep};
|
||||||
modeSelp->dtypep(memberModep->dtypep());
|
|
||||||
addModeGate(modeSelp, rmode.index);
|
addModeGate(modeSelp, rmode.index);
|
||||||
} else if (randModeVarp) {
|
} else if (randModeVarp) {
|
||||||
addModeGate(new AstVarRef{fl, VN_AS(randModeVarp->user2p(), NodeModule),
|
addModeGate(new AstVarRef{fl, VN_AS(randModeVarp->user2p(), NodeModule),
|
||||||
|
|
@ -4611,7 +4624,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
rmode.index);
|
rmode.index);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!gatep) return chainp;
|
if (alwaysActive || !gatep) return chainp;
|
||||||
|
|
||||||
AstNodeExpr* unionExprp = nullptr;
|
AstNodeExpr* unionExprp = nullptr;
|
||||||
for (auto& bucket : buckets) {
|
for (auto& bucket : buckets) {
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,18 @@ class RtWeight;
|
||||||
}
|
}
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
|
class IdxSel;
|
||||||
|
rand uint a[4];
|
||||||
|
rand uint idx;
|
||||||
|
constraint ci {idx inside {[0 : 3]};}
|
||||||
|
constraint c {
|
||||||
|
a[idx] dist {
|
||||||
|
10 := 9,
|
||||||
|
20 := 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
endclass
|
||||||
|
|
||||||
module t;
|
module t;
|
||||||
int ok;
|
int ok;
|
||||||
initial begin
|
initial begin
|
||||||
|
|
@ -170,6 +182,7 @@ module t;
|
||||||
RtWeight r;
|
RtWeight r;
|
||||||
DistInIf di;
|
DistInIf di;
|
||||||
DistInForeach df;
|
DistInForeach df;
|
||||||
|
IdxSel ix;
|
||||||
|
|
||||||
// Frozen in the low-weight bucket -> succeeds, value untouched.
|
// Frozen in the low-weight bucket -> succeeds, value untouched.
|
||||||
sv = new;
|
sv = new;
|
||||||
|
|
@ -441,6 +454,19 @@ module t;
|
||||||
foreach (df.arr[j]) if (df.arr[j] != 10 && df.arr[j] != 20) `checkd(0, 1);
|
foreach (df.arr[j]) if (df.arr[j] != 10 && df.arr[j] != 20) `checkd(0, 1);
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// Frozen index into an active array: a[idx] is still freshly drawn.
|
||||||
|
ix = new;
|
||||||
|
ok = ix.randomize();
|
||||||
|
`checkd(ok, 1);
|
||||||
|
ix.idx.rand_mode(0);
|
||||||
|
ix.idx = 2;
|
||||||
|
for (int i = 0; i < 16; ++i) begin
|
||||||
|
ok = ix.randomize();
|
||||||
|
`checkd(ok, 1);
|
||||||
|
`checkd(ix.idx, 2);
|
||||||
|
if (ix.a[2] != 10 && ix.a[2] != 20) `checkd(ix.a[2], 10);
|
||||||
|
end
|
||||||
|
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue