Fix pattern assignment to unpacked structs (#3510).

This commit is contained in:
Wilson Snyder 2023-01-29 16:50:10 -05:00
parent 4208db7811
commit 6a7dfb7696
8 changed files with 139 additions and 21 deletions

View File

@ -17,6 +17,7 @@ Verilator 5.007 devel
* Support interface classes and class implements.
* Support global clocking and $global_clock.
* Fix real parameters of infinity and NaN.
* Fix pattern assignment to unpacked structs (#3510). [Mostafa Garnal]
Verilator 5.006 2022-01-22

View File

@ -865,6 +865,7 @@ public:
widthFromSub(subDTypep());
}
ASTGEN_MEMBERS_AstMemberDType;
void dumpSmall(std::ostream& str) const override;
string name() const override { return m_name; } // * = Var name
bool hasDType() const override { return true; }
bool maybePointedTo() const override { return true; }

View File

@ -790,6 +790,51 @@ public:
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstConsPackMember final : public AstNodeExpr {
// Construct a packed array single emement [member1: value1]
// Don't need the member we are constructing, as the dtypep can get us to it
// @astgen op2 := rhsp : AstNodeExpr
public:
explicit AstConsPackMember(FileLine* fl, AstMemberDType* dtypep, AstNodeExpr* rhsp)
: ASTGEN_SUPER_ConsPackMember(fl) {
this->dtypep(dtypep);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstConsPackMember;
const char* broken() const override {
BROKEN_RTN(dtypep() && !VN_IS(dtypep(), MemberDType));
return nullptr;
}
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstConsPackUOrStruct final : public AstNodeExpr {
// Construct a packed struct and return object, '{member1: value1, member2: value2}
// Don't need the class we are constructing, as the dtypep can get us to it
// @astgen op1 := membersp : List[AstConsPackMember]
public:
explicit AstConsPackUOrStruct(FileLine* fl, AstNodeUOrStructDType* dtypep,
AstConsPackMember* membersp = nullptr)
: ASTGEN_SUPER_ConsPackUOrStruct(fl) {
this->dtypep(dtypep);
this->addMembersp(membersp);
}
ASTGEN_MEMBERS_AstConsPackUOrStruct;
const char* broken() const override {
BROKEN_RTN(dtypep() && !VN_IS(dtypep(), NodeUOrStructDType));
return nullptr;
}
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstConsQueue final : public AstNodeExpr {
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
// @astgen op1 := lhsp : Optional[AstNode]

View File

@ -1646,6 +1646,10 @@ void AstLogOr::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
if (sideEffect()) str << " [SIDE]";
}
void AstMemberDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "member";
}
void AstMemberSel::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
str << " -> ";

View File

@ -87,7 +87,8 @@ private:
}
void computeCppWidth(AstNode* nodep) {
if (!nodep->user2() && nodep->hasDType()) {
if (VN_IS(nodep, Var)
if (VN_IS(nodep, Var) //
|| VN_IS(nodep, ConsPackMember) //
|| VN_IS(nodep, NodeDType) // Don't want to change variable widths!
|| VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays
|| VN_IS(nodep->dtypep()->skipRefp(), WildcardArrayDType)

View File

@ -1262,6 +1262,21 @@ public:
puts(")");
}
}
void visit(AstConsPackUOrStruct* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
puts("{");
for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) {
iterate(memberp);
if (memberp->nextp()) { puts(", "); }
}
puts("}");
}
void visit(AstConsPackMember* nodep) override {
auto* const vdtypep = VN_AS(nodep->dtypep(), MemberDType);
putbs(vdtypep->name());
puts(": ");
iterate(nodep->rhsp());
}
void visit(AstConsQueue* nodep) override {
putbs(nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {

View File

@ -2320,6 +2320,18 @@ private:
EXTEND_EXP);
}
}
void visit(AstConsPackUOrStruct* nodep) override {
// Type was computed when constructed in V3Width earlier
auto* const vdtypep = VN_AS(nodep->dtypep()->skipRefp(), NodeUOrStructDType);
UASSERT_OBJ(vdtypep, nodep, "ConsPackUOrStruct requires packed array parent data type");
userIterateChildren(nodep, WidthVP{vdtypep, BOTH}.p());
}
void visit(AstConsPackMember* nodep) override {
// Type was computed when constructed in V3Width earlier
auto* const vdtypep = VN_AS(nodep->dtypep(), MemberDType);
UASSERT_OBJ(vdtypep, nodep, "ConsPackMember requires member data type");
if (m_vup->prelim()) userIterateAndNext(nodep->rhsp(), WidthVP{vdtypep, BOTH}.p());
}
void visit(AstConsDynArray* nodep) override {
// Type computed when constructed here
AstDynArrayDType* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), DynArrayDType);
@ -3835,26 +3847,45 @@ private:
}
}
AstNodeExpr* newp = nullptr;
for (AstMemberDType* memp = vdtypep->membersp(); memp;
memp = VN_AS(memp->nextp(), MemberDType)) {
const auto it = patmap.find(memp);
AstPatMember* patp = nullptr;
if (it == patmap.end()) {
// default or default_type assignment
if (AstNodeUOrStructDType* const memp_nested_vdtypep
= VN_CAST(memp->virtRefDTypep(), NodeUOrStructDType)) {
newp = nestedvalueConcat_patternUOrStruct(memp_nested_vdtypep, defaultp, newp,
nodep, dtypemap);
} else {
patp = Defaultpatp_patternUOrStruct(nodep, memp, patp, vdtypep, defaultp,
dtypemap);
if (vdtypep->packed()) {
for (AstMemberDType* memp = vdtypep->membersp(); memp;
memp = VN_AS(memp->nextp(), MemberDType)) {
const auto it = patmap.find(memp);
AstPatMember* patp = nullptr;
if (it == patmap.end()) { // default or default_type assignment
if (AstNodeUOrStructDType* const memp_nested_vdtypep
= VN_CAST(memp->virtRefDTypep(), NodeUOrStructDType)) {
newp = nestedvalueConcat_patternUOrStruct(memp_nested_vdtypep, defaultp,
newp, nodep, dtypemap);
} else {
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);
}
} else {
// member assignment
patp = it->second;
newp = valueConcat_patternUOrStruct(patp, newp, memp, nodep);
}
} else { // Unpacked
AstConsPackMember* membersp = nullptr;
for (AstMemberDType* memp = vdtypep->membersp(); memp;
memp = VN_AS(memp->nextp(), MemberDType)) {
const auto it = patmap.find(memp);
AstPatMember* patp = nullptr;
if (it == patmap.end()) { // Default or default_type assignment
patp = defaultPatp_patternUOrStruct(nodep, memp, patp, vdtypep, defaultp,
dtypemap);
} else {
patp = it->second; // Member assignment
}
patp->dtypep(memp);
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
AstConsPackMember* const cpmp
= new AstConsPackMember{patp->fileline(), memp, valuep};
membersp = membersp ? membersp->addNext(cpmp) : cpmp;
}
newp = new AstConsPackUOrStruct{nodep->fileline(), vdtypep, membersp};
}
if (newp) {
nodep->replaceWith(newp);
@ -3877,7 +3908,7 @@ private:
newp = nestedvalueConcat_patternUOrStruct(memp_multinested_vdtypep, defaultp, newp,
nodep, dtypemap);
} else {
patp = Defaultpatp_patternUOrStruct(nodep, memp_nested, patp, memp_vdtypep,
patp = defaultPatp_patternUOrStruct(nodep, memp_nested, patp, memp_vdtypep,
defaultp, dtypemap);
newp = valueConcat_patternUOrStruct(patp, newp, memp_nested, nodep);
}
@ -3885,7 +3916,7 @@ private:
return newp;
}
AstPatMember* Defaultpatp_patternUOrStruct(AstPattern* nodep, AstMemberDType* memp,
AstPatMember* defaultPatp_patternUOrStruct(AstPattern* nodep, AstMemberDType* memp,
AstPatMember* patp,
AstNodeUOrStructDType* memp_vdtypep,
AstPatMember* defaultp, const DTypeMap& dtypemap) {

View File

@ -1,9 +1,12 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2009 by Wilson Snyder.
// any use, without warranty, 2009-2023 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
`define stop $stop
`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
module x;
typedef struct {
int a, b;
@ -15,14 +18,31 @@ module x;
embedded_t tab [3:0];
} notembedded_t;
typedef struct {
logic [15:0] m_i;
string m_s;
} istr_t;
notembedded_t p;
embedded_t t [1:0];
istr_t istr;
string s;
initial begin
t[1].a = 2;
p.b.a = 1;
if (t[1].a != 2) $stop;
if (p.b.a != 1) $stop;
istr.m_i = 12;
istr.m_s = "str1";
s = $sformatf("%p", istr);
`checks(s, "'{m_i:'hc, m_s:\"str1\"}");
istr = '{m_i: '1, m_s: "str2"};
s = $sformatf("%p", istr);
`checks(s, "'{m_i:'hffff, m_s:\"str2\"}");
$write("*-* All Finished *-*\n");
$finish;
end