Fix V3Table trying to generate 'x' bits in the lookup table. (#5491)

Due to out of range selects, V3Table attempted to create a table in the
constant pool with an 'x' value in it, which caused an internal error.

Ensure V3Table behaves the same for out of range selects as the original
logic would.

There is a related bug #5490, about leaving partially out of range
selects in the logic after inserting bounds checks in V3Unknown.
This commit is contained in:
Geza Lore 2024-09-26 16:31:47 +01:00 committed by GitHub
parent 91c8866ac3
commit 2a01365f9b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 16 additions and 2 deletions

View File

@ -258,6 +258,7 @@ public:
void newValue(AstNode* nodep, const AstNodeExpr* valuep) {
if (const AstConst* const constp = VN_CAST(valuep, Const)) {
newConst(nodep)->num().opAssign(constp->num());
UINFO(9, " new val " << valuep->name() << " on " << nodep << endl);
} else if (fetchValueNull(nodep) != valuep) {
// const_cast, as clonep() is set on valuep, but nothing should care
setValue(nodep, newTrackedClone(const_cast<AstNodeExpr*>(valuep)));
@ -266,6 +267,7 @@ public:
void newOutValue(AstNode* nodep, const AstNodeExpr* valuep) {
if (const AstConst* const constp = VN_CAST(valuep, Const)) {
newOutConst(nodep)->num().opAssign(constp->num());
UINFO(9, " new oval " << valuep->name() << " on " << nodep << endl);
} else if (fetchOutValueNull(nodep) != valuep) {
// const_cast, as clonep() is set on valuep, but nothing should care
setOutValue(nodep, newTrackedClone(const_cast<AstNodeExpr*>(valuep)));
@ -282,7 +284,7 @@ private:
// Set a constant value for this node
if (!VN_IS(m_varAux(nodep).valuep, Const)) {
AstConst* const constp = allocConst(nodep);
setValue(nodep, constp);
m_varAux(nodep).valuep = constp;
return constp;
} else {
return fetchConst(nodep);
@ -292,7 +294,7 @@ private:
// Set a var-output constant value for this node
if (!VN_IS(m_varAux(nodep).outValuep, Const)) {
AstConst* const constp = allocConst(nodep);
setOutValue(nodep, constp);
m_varAux(nodep).outValuep = constp;
return constp;
} else {
return fetchOutConst(nodep);
@ -594,9 +596,18 @@ private:
checkNodeInfo(nodep);
iterateChildrenConst(nodep);
if (!m_checkOnly && optimizable()) {
AstConst* const valuep = newConst(nodep);
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(),
fetchConst(nodep->rhsp())->num(),
fetchConst(nodep->thsp())->num());
// See #5490. 'numberOperate' on partially out of range select yields 'x' bits,
// but in reality it would yield '0's without V3Table, so force 'x' bits to '0',
// to ensure the result is the same with and without V3Table.
if (!m_params && VN_IS(nodep, Sel) && valuep->num().isAnyX()) {
V3Number num{valuep, valuep->width()};
num.opAssign(valuep->num());
valuep->num().opBitsOne(num);
}
}
}
void visit(AstNodeQuadop* nodep) override {

View File

@ -315,6 +315,7 @@ private:
for (TableOutputVar& tov : m_outVarps) {
if (V3Number* const outnump = simvis.fetchOutNumberNull(tov.varScopep())) {
UINFO(8, " Output " << tov.name() << " = " << *outnump << endl);
UASSERT_OBJ(!outnump->isAnyXZ(), outnump, "Table should not contain X/Z");
outputAssignedMask.setBit(tov.ord(), 1); // Mark output as assigned
tov.addValue(inValue, *outnump);
} else {

View File

@ -83,6 +83,8 @@ module Test (/*AUTOARG*/
// verilator lint_off WIDTH
out <= p[15 + in -: 5];
// verilator lint_on WIDTH
end
always @(posedge clk) begin
mask[3] <= ((15 + in - 5) < 12);
mask[2] <= ((15 + in - 5) < 13);
mask[1] <= ((15 + in - 5) < 14);