From df5f95a5bd23332d57d8470cdb2a16e4dd50d760 Mon Sep 17 00:00:00 2001 From: Mostafa Gamal Date: Fri, 12 Aug 2022 12:55:07 +0200 Subject: [PATCH] Fix nested default assignment for struct pattern (#3511) (#3524) --- src/V3Width.cpp | 110 ++++++++++++------ src/verilog.y | 2 - test_regress/t/t_array_list_bad.out | 2 +- .../t/t_structu_dataType_assignment.v | 50 ++++++++ 4 files changed, 125 insertions(+), 39 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 523d208da..f1067a896 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -209,6 +209,7 @@ private: // TYPES using TableMap = std::map, AstVar*>; using PatVecMap = std::map; + using DTypeMap = std::map; // STATE WidthVP* m_vup = nullptr; // Current node state @@ -3564,11 +3565,9 @@ private: // which member each AstPatMember corresponds to before we can // determine the dtypep for that PatMember's value, and then // width the initial value appropriately. - using PatMap = std::map; // Store member: value - using DTypeMap - = std::map; // Store data_type: default_value - PatMap patmap; - DTypeMap dtypemap; + using PatMap = std::map; + PatMap patmap; // Store member: value + DTypeMap dtypemap; // Store data_type: default_value { const AstMemberDType* memp = vdtypep->membersp(); AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); @@ -3631,44 +3630,23 @@ private: for (AstMemberDType* memp = vdtypep->membersp(); memp; memp = VN_AS(memp->nextp(), MemberDType)) { const auto it = patmap.find(memp); - AstPatMember* newpatp = nullptr; AstPatMember* patp = nullptr; if (it == patmap.end()) { - const string memp_DType = memp->virtRefDTypep()->prettyDTypeName(); - const auto it2 = dtypemap.find(memp_DType); - if (it2 != dtypemap.end()) { - // default_value for data_type - patp = it2->second; - newpatp = patp->cloneTree(false); - patp = newpatp; - } else if (defaultp) { - // default_value for any unassigned member yet - newpatp = defaultp->cloneTree(false); - patp = newpatp; + // default or deafult_type assignment + if (AstNodeUOrStructDType* const memp_nested_vdtypep + = VN_CAST(memp->virtRefDTypep(), NodeUOrStructDType)) { + newp = nestedvalueConcat_patternUOrStruct(memp_nested_vdtypep, defaultp, newp, + nodep, dtypemap); } else { - if (!VN_IS(vdtypep, UnionDType)) { - nodep->v3error("Assignment pattern missed initializing elements: " - << memp->virtRefDTypep()->prettyDTypeName() << " " - << memp->prettyName()); - } + patp = Defaultpatp_patternUOrStruct(nodep, memp, patp, vdtypep, defaultp, + dtypemap); + newp = valueConcat_patternUOrStruct(patp, newp, memp, nodep); } } else { + // member assignment patp = it->second; + newp = valueConcat_patternUOrStruct(patp, newp, memp, nodep); } - if (patp) { - // Determine initial values - patp->dtypep(memp); - AstNode* const valuep = patternMemberValueIterate(patp); - if (!newp) { - newp = valuep; - } else { - AstConcat* const concatp = new AstConcat(patp->fileline(), newp, valuep); - newp = concatp; - newp->dtypeSetLogicSized(concatp->lhsp()->width() + concatp->rhsp()->width(), - nodep->dtypep()->numeric()); - } - } - if (newpatp) VL_DO_DANGLING(pushDeletep(newpatp), newpatp); } if (newp) { nodep->replaceWith(newp); @@ -3677,6 +3655,66 @@ private: } VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } + + AstNode* nestedvalueConcat_patternUOrStruct(AstNodeUOrStructDType* memp_vdtypep, + AstPatMember* defaultp, AstNode* newp, + AstPattern* nodep, DTypeMap dtypemap) { + AstPatMember* patp = nullptr; + for (AstMemberDType* memp_nested = memp_vdtypep->membersp(); memp_nested; + memp_nested = VN_AS(memp_nested->nextp(), MemberDType)) { + if (AstNodeUOrStructDType* const memp_multinested_vdtypep + = VN_CAST(memp_nested->virtRefDTypep(), NodeUOrStructDType)) { + // When unpacked struct/union is supported this if will need some additional conditions + newp = nestedvalueConcat_patternUOrStruct(memp_multinested_vdtypep, defaultp, newp, + nodep, dtypemap); + } else { + patp = Defaultpatp_patternUOrStruct(nodep, memp_nested, patp, memp_vdtypep, + defaultp, dtypemap); + newp = valueConcat_patternUOrStruct(patp, newp, memp_nested, nodep); + } + } + return newp; + } + + AstPatMember* Defaultpatp_patternUOrStruct(AstPattern* nodep, AstMemberDType* memp, + AstPatMember* patp, + AstNodeUOrStructDType* memp_vdtypep, + AstPatMember* defaultp, DTypeMap dtypemap) { + const string memp_DType = memp->virtRefDTypep()->prettyDTypeName(); + const auto it = dtypemap.find(memp_DType); + if (it != dtypemap.end()) { + // default_value for data_type + patp = it->second->cloneTree(false); + } else if (defaultp) { + // default_value for any unmatched member yet + patp = defaultp->cloneTree(false); + } else { + if (!VN_IS(memp_vdtypep, UnionDType)) { + nodep->v3error("Assignment pattern missed initializing elements: " + << memp->virtRefDTypep()->prettyDTypeNameQ() << " " + << memp->prettyNameQ()); + } + } + return patp; + } + + AstNode* valueConcat_patternUOrStruct(AstPatMember* patp, AstNode* newp, AstMemberDType* memp, + AstPattern* nodep) { + if (patp) { + patp->dtypep(memp); + AstNode* const valuep = patternMemberValueIterate(patp); + if (!newp) { + newp = valuep; + } else { + AstConcat* const concatp = new AstConcat{patp->fileline(), newp, valuep}; + newp = concatp; + newp->dtypeSetLogicSized(concatp->lhsp()->width() + concatp->rhsp()->width(), + nodep->dtypep()->numeric()); + } + } + return newp; + } + void patternArray(AstPattern* nodep, AstNodeArrayDType* arrayDtp, AstPatMember* defaultp) { const VNumRange range = arrayDtp->declRange(); PatVecMap patmap = patVectorMap(nodep, range); diff --git a/src/verilog.y b/src/verilog.y index 75f377213..b53fe528e 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3532,8 +3532,6 @@ patternKey: // IEEE: merge structure_pattern_key, array_patt // // id/*member*/ is part of constExpr below //UNSUP constExpr { $$ = $1; } // // IEEE: assignment_pattern_key - //UNSUP simple_type { $1->v3error("Unsupported: '{} with data type as key"); $$ = $1; } - // // simple_type reference looks like constExpr // // Verilator: // // The above expressions cause problems because "foo" may be // // a constant identifier (if array) or a reference to the diff --git a/test_regress/t/t_array_list_bad.out b/test_regress/t/t_array_list_bad.out index 0eeb8a06f..3ce83ac48 100644 --- a/test_regress/t/t_array_list_bad.out +++ b/test_regress/t/t_array_list_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_array_list_bad.v:38:25: Assignment pattern missed initializing elements: logic t3 +%Error: t/t_array_list_bad.v:38:25: Assignment pattern missed initializing elements: 'logic' 't3' : ... In instance t 38 | test_out <= '{'0, '0}; | ^~ diff --git a/test_regress/t/t_structu_dataType_assignment.v b/test_regress/t/t_structu_dataType_assignment.v index 2962a6e78..209dc34b6 100644 --- a/test_regress/t/t_structu_dataType_assignment.v +++ b/test_regress/t/t_structu_dataType_assignment.v @@ -34,6 +34,20 @@ module top(); } DEF_struct; + typedef struct { // IEEE 1800-2017 SV CH:10.9.2 + int A; + struct { + int B, C; + struct{ + int D, E; + struct{ + int F; + shortint G; + } FG1; + } DE1; + } BC1; + } HIJ_struct; + // struct ab ab_struct ab; ab_struct abkey[1:0]; @@ -48,6 +62,9 @@ module top(); // struct DEF DEF_struct DEF; + // struct HIJ + HIJ_struct HIJ; + initial begin; // struct ab ab = '{0, 0}; //constant member by position @@ -130,6 +147,39 @@ module top(); if (DEF.BC2.B != 5) $stop; if (DEF.BC2.C != 5) $stop; + DEF = '{default:10}; + if (DEF.A != 10) $stop; + if (DEF.BC1.B != 10) $stop; + if (DEF.BC1.C != 10) $stop; + if (DEF.BC2.B != 10) $stop; + if (DEF.BC2.C != 10) $stop; + + DEF = '{int:10}; + if (DEF.A != 10) $stop; + if (DEF.BC1.B != 10) $stop; + if (DEF.BC1.C != 10) $stop; + if (DEF.BC2.B != 10) $stop; + if (DEF.BC2.C != 10) $stop; + + // struct HIJ + HIJ = '{int:10, default: 5}; + if (HIJ.A != 10) $stop; + if (HIJ.BC1.B != 10) $stop; + if (HIJ.BC1.C != 10) $stop; + if (HIJ.BC1.DE1.D != 10) $stop; + if (HIJ.BC1.DE1.E != 10) $stop; + if (HIJ.BC1.DE1.FG1.F != 10) $stop; + if (HIJ.BC1.DE1.FG1.G != 5) $stop; + + HIJ = '{shortint:10, default: 5}; + if (HIJ.A != 5) $stop; + if (HIJ.BC1.B != 5) $stop; + if (HIJ.BC1.C != 5) $stop; + if (HIJ.BC1.DE1.D != 5) $stop; + if (HIJ.BC1.DE1.E != 5) $stop; + if (HIJ.BC1.DE1.FG1.F != 5) $stop; + if (HIJ.BC1.DE1.FG1.G != 10) $stop; + $write("*-* All Finished *-*\n"); $finish; end