Add aggregate type error checks (#5570) (#5950)

This commit is contained in:
Shou-Li Hsu
2025-05-20 09:10:22 -04:00
committed by GitHub
parent bed0456eca
commit 25cb31c38b
12 changed files with 440 additions and 60 deletions
+42 -53
View File
@@ -319,69 +319,58 @@ class SliceVisitor final : public VNVisitor {
void expandBiOp(AstNodeBiop* nodep) {
if (nodep->user1SetOnce()) return; // Process once
// If it's an unpacked array, blow it up into comparing each element
AstNodeDType* const fromDtp = nodep->lhsp()->dtypep()->skipRefp();
UINFO(9, " Bi-Eq/Neq expansion " << nodep << endl);
// Only expand if lhs is an unpacked array (we assume type checks already passed)
const AstNodeDType* const fromDtp = nodep->lhsp()->dtypep()->skipRefp();
if (const AstUnpackArrayDType* const adtypep = VN_CAST(fromDtp, UnpackArrayDType)) {
AstNodeBiop* logp = nullptr;
if (!VN_IS(nodep->lhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
nodep->lhsp()->v3error(
"Slice operator "
<< nodep->lhsp()->prettyTypeName()
<< " on non-slicable (e.g. non-vector) left-hand-side operand");
} else if (!VN_IS(nodep->rhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
nodep->rhsp()->v3error(
"Slice operator "
<< nodep->rhsp()->prettyTypeName()
<< " on non-slicable (e.g. non-vector) right-hand-side operand");
} else {
const int elements = adtypep->rangep()->elementsConst();
for (int elemIdx = 0; elemIdx < elements; ++elemIdx) {
// EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1])
// Original node is replaced, so it is safe to copy it one time even if it is
// impure.
AstNodeBiop* const clonep
= VN_AS(nodep->cloneType(
cloneAndSel(nodep->lhsp(), elements, elemIdx, elemIdx != 0),
cloneAndSel(nodep->rhsp(), elements, elemIdx, elemIdx != 0)),
NodeBiop);
if (elemIdx == 0) {
nodep->foreach([this](AstExprStmt* const exprp) {
// Result expression is always evaluated to the same value, so the
// statements can be removed once they were included in the expression
// created for the 1st element.
AstNodeExpr* const resultp = exprp->resultp()->unlinkFrBack();
exprp->replaceWith(resultp);
VL_DO_DANGLING(pushDeletep(exprp), exprp);
});
}
if (!logp) {
logp = clonep;
} else {
switch (nodep->type()) {
case VNType::atEq: // FALLTHRU
case VNType::atEqCase:
logp = new AstLogAnd{nodep->fileline(), logp, clonep};
break;
case VNType::atNeq: // FALLTHRU
case VNType::atNeqCase:
logp = new AstLogOr{nodep->fileline(), logp, clonep};
break;
default:
nodep->v3fatalSrc("Unknown node type processing array slice");
break;
}
const int elements = adtypep->rangep()->elementsConst();
for (int elemIdx = 0; elemIdx < elements; ++elemIdx) {
// EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1])
// Original node is replaced, so it is safe to copy it one time even if it is
// impure.
AstNodeBiop* const clonep = VN_AS(
nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, elemIdx, elemIdx != 0),
cloneAndSel(nodep->rhsp(), elements, elemIdx, elemIdx != 0)),
NodeBiop);
if (elemIdx == 0) {
nodep->foreach([this](AstExprStmt* const exprp) {
// Result expression is always evaluated to the same value, so the
// statements can be removed once they were included in the expression
// created for the 1st element.
AstNodeExpr* const resultp = exprp->resultp()->unlinkFrBack();
exprp->replaceWith(resultp);
VL_DO_DANGLING(pushDeletep(exprp), exprp);
});
}
if (!logp) {
logp = clonep;
} else {
switch (nodep->type()) {
case VNType::atEq: // FALLTHRU
case VNType::atEqCase:
logp = new AstLogAnd{nodep->fileline(), logp, clonep};
break;
case VNType::atNeq: // FALLTHRU
case VNType::atNeqCase:
logp = new AstLogOr{nodep->fileline(), logp, clonep};
break;
default: nodep->v3fatalSrc("Unknown node type processing array slice"); break;
}
}
UASSERT_OBJ(logp, nodep, "Unpacked array with empty indices range");
nodep->replaceWith(logp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
nodep = logp;
}
UASSERT_OBJ(logp, nodep, "Unpacked array with empty indices range");
nodep->replaceWith(logp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
nodep = logp;
}
iterateChildren(nodep);
}
void visit(AstEq* nodep) override { expandBiOp(nodep); }
void visit(AstNeq* nodep) override { expandBiOp(nodep); }
void visit(AstEqCase* nodep) override { expandBiOp(nodep); }