Fix class specializations named before all their pins are folded (#8604)

This commit is contained in:
Michael Bedford Taylor
2026-10-03 12:37:32 -04:00
committed by GitHub
parent 256468e8ae
commit c8171ae37b
3 changed files with 138 additions and 6 deletions
+34 -6
View File
@@ -1417,8 +1417,11 @@ class ParamProcessor final {
any_overridesr = true;
}
// Name the specialization by a value pin, or prepare a type pin, noting in
// overridingTypePinsr whether it differs from the default
void cellPinCleanup(AstNode* nodep, AstPin* pinp, AstPin* paramsp, AstNodeModule* srcModp,
string& longnamer, bool& any_overridesr) {
string& longnamer, bool& any_overridesr,
std::unordered_set<const AstPin*>& overridingTypePinsr) {
if (!pinp->exprp()) return; // No-connect
if (AstVar* const modvarp = pinp->modVarp()) {
resolveDeferredDotsReachableFrom(modvarp->subDTypep(), m_modp);
@@ -1669,12 +1672,9 @@ class ParamProcessor final {
if (classRefDTypep->paramsp() && classRefDTypep->classp()
&& classRefDTypep->classp()->hasGParam()) {
classRefDeparam(classRefDTypep, classRefDTypep->classp());
rawTypep = VN_CAST(pinp->exprp(), NodeDType);
exprp = rawTypep ? rawTypep->skipRefToNonRefp() : nullptr;
}
}
longnamer += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp);
any_overridesr = true;
overridingTypePinsr.emplace(pinp); // Named once every pin is prepared
}
}
} else {
@@ -1945,9 +1945,37 @@ class ParamProcessor final {
longname = parameterizedHierBlockName(srcModp, paramsp);
any_overrides = longname != srcModp->name();
} else {
// Prepare every pin before naming any, as naming a value can depend on the others:
// fold each value pin, as a class reference's may not be yet, and resolve each type
std::unordered_set<const AstPin*> overridingTypePins;
for (AstPin* pinp = paramsp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
if (!pinp->exprp()) continue; // An empty override keeps the default
if (pinp->modPTypep()) {
cellPinCleanup(nodep, pinp, paramsp, srcModp, longname /*ref*/,
any_overrides /*ref*/, overridingTypePins /*ref*/);
continue;
}
AstVar* const modvarp = pinp->modVarp();
if (!modvarp || !modvarp->isGParam()) continue;
resolveDeferredDotsReachableFrom(modvarp->subDTypep(), m_modp);
// An untyped pattern can't be folded without its parameter's type
const AstPattern* const patternp = VN_CAST(pinp->exprp(), Pattern);
if (patternp && !patternp->childDTypep()) continue;
if (!VN_IS(pinp->exprp(), Const) && !isAggregateParamValue(pinp->exprp())) {
V3Const::constifyParamsEdit(pinp->exprp());
}
}
for (AstPin* pinp = paramsp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
if (AstParamTypeDType* const modptp = pinp->modPTypep()) {
if (!overridingTypePins.count(pinp)) continue;
AstNodeDType* const typep = VN_AS(pinp->exprp(), NodeDType);
longname += "_" + paramSmallName(srcModp, modptp)
+ paramValueNumber(typep->skipRefToNonRefp());
any_overrides = true;
continue;
}
cellPinCleanup(nodep, pinp, paramsp, srcModp, longname /*ref*/,
any_overrides /*ref*/);
any_overrides /*ref*/, overridingTypePins /*ref*/);
}
}
IfaceRefRefs ifaceRefRefs;
+18
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()
+86
View File
@@ -0,0 +1,86 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// A class specialization whose parameter's type depends on a parameter given
// after it, or on a type parameter, is named from every pin's folded value,
// so specializations with equal values are one class, and others are not.
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Michael Bedford Taylor
// SPDX-License-Identifier: CC0-1.0
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
// verilog_format: on
// P's width comes from N
class clw #(
parameter int N = 1,
// verilator lint_off WIDTHTRUNC
parameter logic [N-1:0] P = '0 // Given wider values
// verilator lint_on WIDTHTRUNC
);
static int count;
static function int value();
return int'(P);
endfunction
endclass
// P and Q have type T
class clt #(
parameter type T = byte,
// verilator lint_off WIDTHTRUNC
parameter T P = 0, // Given wider values
parameter T Q = 0
// verilator lint_on WIDTHTRUNC
);
static int count;
static function int value();
return int'(Q);
endfunction
endclass
module t;
localparam int TWO = 2;
logic [3:0] tv;
typedef clw#(.P(8'h81), .N(TWO * 4)) clw81_t; // Width given after the value
typedef clw#(.P(8'h01), .N(TWO * 4)) clw01_t; // Differs from clw81_t only above bit 0
typedef clw#(.P(8'h81), .N(TWO * 2)) clw4a_t; // Equal to clw4b_t once P is 4 bits
typedef clw#(.P(8'h01), .N(TWO * 2)) clw4b_t;
clw4a_t clw4a;
clw4b_t clw4b;
typedef clt#(.P(8'h01), .T(type(tv)), .Q(8'h81)) clta_t; // Equal to cltb_t once T is known
typedef clt#(.P(8'h01), .T(type(tv)), .Q(8'h01)) cltb_t;
typedef clt#(.P(8'h02), .T(type(tv)), .Q(8'h01)) cltc_t; // The same, in the other order
typedef clt#(.P(8'h02), .T(type(tv)), .Q(8'h81)) cltd_t;
typedef clt#(.T(type(tv)), .P(8'h03), .Q(8'h81)) clte_t; // The same, with T given first
typedef clt#(.T(type(tv)), .P(8'h03), .Q(8'h01)) cltf_t;
clta_t clta;
cltb_t cltb;
initial begin
`checkh(clw81_t::value(), 'h81);
`checkh(clw01_t::value(), 'h01);
clw4a = new;
clw4b = clw4a; // One specialization, so one type
clw4a_t::count = 7;
`checkd(clw4b_t::count, 7);
`checkh(clw4b_t::value(), 'h1);
clta = new;
cltb = clta; // One specialization, so one type
clta_t::count = 1;
cltc_t::count = 2;
clte_t::count = 3;
`checkd(cltb_t::count, 1);
`checkd(cltd_t::count, 2);
`checkd(cltf_t::count, 3);
`checkh(cltb_t::value(), 'h1);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule