Fix V3Width SVA bound limit guard, leave headroom for alignment, respect --max-num-width (#8192)

Signed-off-by: Artur Bieniek <[email protected]>
This commit is contained in:
Artur Bieniek
2026-08-24 08:57:18 -04:00
committed by GitHub
parent d0321b8502
commit 33ad9d530e
14 changed files with 170 additions and 15 deletions
+23 -7
View File
@@ -744,6 +744,22 @@ class WidthVisitor final : public VNVisitor {
// it's like an if() condition.
iterateCheckBool(nodep, "default disable iff condition", nodep->condp(), BOTH);
}
static bool widthCheckSvaValueLimit(AstNode* nodep, const AstConst* constp, const char* what) {
// Temporal values can materialize as O(N) AST or state in later passes.
// Leave headroom for a range ring's extra slot and V3Number's signed
// `(bits + 31) / 32` word count.
static constexpr unsigned SVA_VALUE_HARD_LIMIT
= static_cast<unsigned>(std::numeric_limits<int>::max()) - 32U;
const unsigned configuredLimit = static_cast<unsigned>(v3Global.opt.maxNumWidth());
const unsigned limit = std::min(configuredLimit, SVA_VALUE_HARD_LIMIT);
if (constp->num().fitsInUInt() && constp->toUInt() <= limit) return true;
nodep->v3warn(E_UNSUPPORTED, "Unsupported: " << what << " exceeds implementation limit of "
<< limit
<< (configuredLimit <= SVA_VALUE_HARD_LIMIT
? " (--max-num-width)"
: " (host arithmetic limit)"));
return false;
}
static const AstConst* widthCheckSvaDelayBound(AstDelay* nodep, AstNodeExpr* boundp,
const char* what) {
const AstConst* const constp = VN_CAST(boundp, Const);
@@ -752,12 +768,7 @@ class WidthVisitor final : public VNVisitor {
" (IEEE 1800-2023 16.7)");
return nullptr;
}
if (constp->num().mostSetBitP1() > 31) {
nodep->v3warn(
E_UNSUPPORTED,
"Unsupported: SVA cycle delay exceeds implementation limit of 2147483647");
return nullptr;
}
if (!widthCheckSvaValueLimit(nodep, constp, "SVA cycle delay")) return nullptr;
return constp;
}
void visit(AstDelay* nodep) override {
@@ -1577,7 +1588,7 @@ class WidthVisitor final : public VNVisitor {
} else if (constp->toSInt() < 1) {
constp->v3error("$past tick value must be >= 1 (IEEE 1800-2023 16.9.3)");
nodep->ticksp()->unlinkFrBack()->deleteTree();
} else {
} else if (widthCheckSvaValueLimit(nodep, constp, "$past tick value")) {
if (constp->toSInt() > 10) {
constp->v3warn(TICKCOUNT, "$past tick value of "
<< constp->toSInt()
@@ -1668,6 +1679,11 @@ class WidthVisitor final : public VNVisitor {
if (loConstp && loConstp->toSInt() < 0) {
nodep->loBoundp()->v3error("always range low bound must be non-negative"
" (IEEE 1800-2023 16.12.11)");
} else if (loConstp) {
widthCheckSvaValueLimit(nodep->loBoundp(), loConstp, "always range bound");
}
if (!hiUnbounded && hiConstp) {
widthCheckSvaValueLimit(nodep->hiBoundp(), hiConstp, "always range bound");
}
if (!hiUnbounded && loConstp && hiConstp && hiConstp->toSInt() < loConstp->toSInt()) {
nodep->hiBoundp()->v3error("always range high bound must be >= low bound"