Fix recursive default assignment for subarrays (#4589) (#7202)

This commit is contained in:
Julian Carrier 2026-03-05 16:05:54 -05:00 committed by GitHub
parent 4f4d48e9d7
commit 45a5e72509
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 107 additions and 7 deletions

View File

@ -134,6 +134,7 @@ Jose Loyola
Josep Sans
Joseph Nwabueze
Josh Redford
Julian Carrier
Julian Daube
Julie Schwartz
Julien Margetts

View File

@ -2667,12 +2667,27 @@ class ConstVisitor final : public VNVisitor {
iterateChildren(nodep);
if (const AstInitArray* const initp = VN_CAST(nodep->lhsp(), InitArray)) {
if (!(m_doExpensive || m_params)) return false;
// At present only support 1D unpacked arrays
const auto initOfConst = [](const AstNode* const nodep) -> bool { //
return VN_IS(nodep, Const) || VN_IS(nodep, InitItem);
const auto isConstInit = [](const AstNode* const exprp,
const auto& isConstInitRecurse) -> bool {
if (VN_IS(exprp, Const)) return true;
if (const AstInitItem* const itemp = VN_CAST(exprp, InitItem)) {
return isConstInitRecurse(itemp->valuep(), isConstInitRecurse);
}
if (const AstInitArray* const arrayp = VN_CAST(exprp, InitArray)) {
const auto itemIsConstInit = [&isConstInitRecurse](const AstNode* const itemp)
-> bool {
return isConstInitRecurse(itemp, isConstInitRecurse);
};
if (arrayp->initsp() && !arrayp->initsp()->forall(itemIsConstInit)) return false;
if (arrayp->defaultp()
&& !isConstInitRecurse(arrayp->defaultp(), isConstInitRecurse)) {
return false;
}
return true;
}
return false;
};
if (initp->initsp() && !initp->initsp()->forall(initOfConst)) return false;
if (initp->defaultp() && !initp->defaultp()->forall(initOfConst)) return false;
if (!isConstInit(initp, isConstInit)) return false;
} else if (!VN_IS(nodep->lhsp(), Const)) {
return false;
}

View File

@ -5282,6 +5282,34 @@ class WidthVisitor final : public VNVisitor {
return newp;
}
AstPatMember* defaultPatp_patternArray(AstPatMember* defaultp, AstNodeDType* elemDTypep) {
AstNodeExpr* const valuep = defaultp->lhssp()->cloneTree(false);
AstNodeDType* const elemDTypeSkipRefp = elemDTypep->skipRefp();
if (!VN_IS(elemDTypeSkipRefp, UnpackArrayDType)) {
VL_DO_DANGLING(pushDeletep(valuep), valuep);
return defaultp->cloneTree(false);
}
if (VN_IS(valuep, Pattern)) {
VL_DO_DANGLING(pushDeletep(valuep), valuep);
return defaultp->cloneTree(false);
}
if (!valuep->dtypep()) userIterate(valuep, WidthVP{SELF, BOTH}.p());
if (valuep->dtypep()
&& AstNode::computeCastable(valuep->dtypep()->skipRefp(), elemDTypeSkipRefp, nullptr)
.isAssignable()) {
VL_DO_DANGLING(pushDeletep(valuep), valuep);
return defaultp->cloneTree(false);
}
AstPatMember* const nestedDefaultp
= new AstPatMember{defaultp->fileline(), valuep, nullptr, nullptr};
nestedDefaultp->isDefault(true);
AstPattern* const recursivePatternp
= new AstPattern{defaultp->fileline(), nestedDefaultp};
return new AstPatMember{defaultp->fileline(), recursivePatternp, nullptr, nullptr};
}
void patternArray(AstPattern* nodep, AstNodeArrayDType* arrayDtp, AstPatMember* defaultp) {
const VNumRange range = arrayDtp->declRange();
PatVecMap patmap = patVectorMap(nodep, range);
@ -5296,7 +5324,7 @@ class WidthVisitor final : public VNVisitor {
const auto it = patmap.find(ent);
if (it == patmap.end()) {
if (defaultp) {
newpatp = defaultp->cloneTree(false);
newpatp = defaultPatp_patternArray(defaultp, arrayDtp->subDTypep());
patp = newpatp;
} else if (!(VN_IS(arrayDtp, UnpackArrayDType) && !allConstant && isConcat)) {
// If arrayDtp is an unpacked array and item is not constant,

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of either the GNU Lesser General Public License Version 3
# or the Perl Artistic License Version 2.0.
# SPDX-FileCopyrightText: 2026 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,38 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0
module t;
int arr_default_scalar[4][4];
int row[4];
int arr_default_array[2][4];
int arr_mixed_default[2][3];
initial begin
arr_default_scalar = '{default: 0};
foreach (arr_default_scalar[i, j]) begin
if (arr_default_scalar[i][j] != 0) $stop;
end
row = '{1, 2, 3, 4};
arr_default_array = '{default: row};
foreach (arr_default_array[i, j]) begin
if (arr_default_array[i][j] != row[j]) $stop;
end
arr_mixed_default = '{0: '{0: 1, default: 3}, default: '{default: 2}};
if (arr_mixed_default[0][0] != 1) $stop;
if (arr_mixed_default[0][1] != 3) $stop;
if (arr_mixed_default[0][2] != 3) $stop;
if (arr_mixed_default[1][0] != 2) $stop;
if (arr_mixed_default[1][1] != 2) $stop;
if (arr_mixed_default[1][2] != 2) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -1,4 +1,4 @@
-Info: t/t_assert_elab_p.v:14:5: %m test.sv:25: 4=4 2=2 STAGE_IDS='{'h1, 'h1, 'h1, 'h1}
-Info: t/t_assert_elab_p.v:14:5: %m test.sv:25: 4=4 2=2 STAGE_IDS='{'{'h1, 'h1}, '{'h1, 'h1}, '{'h1, 'h1}, '{'h1, 'h1}}
: ... note: In instance 't.pipe'
14 | $info("%m %s:%0d: 4=%0d 2=%0d STAGE_IDS=%p", "test.sv", 25, 4, 2, STAGE_IDS);
| ^~~~~