Track rand/randc qualifier on unpacked struct members

The random_qualifier on struct/union members was discarded at parse time.
Record it as a VRandAttr on AstMemberDType (mirroring AstVar), threaded
through GRAMMARP->m_memRand and applied when each member node is built,
with dump()/dumpJson() support. No behavioral change on its own; consumed
by the following commit.
This commit is contained in:
Philip Axer 2026-07-10 16:31:42 +02:00
parent 1d42c45a34
commit 8d2f859adc
7 changed files with 21 additions and 4 deletions

View File

@ -968,7 +968,7 @@ class AstMemberDType final : public AstNodeDType {
string m_tag; // Holds the string of the verilator tag -- used in JSON output. string m_tag; // Holds the string of the verilator tag -- used in JSON output.
int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member
bool m_constrainedRand = false; bool m_constrainedRand = false;
// UNSUP: int m_randType; // Randomization type (IEEE) VRandAttr m_rand; // Randomizability of this member (rand, randc, etc)
public: public:
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp, AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp,
AstNode* valuep) AstNode* valuep)
@ -1025,6 +1025,8 @@ public:
} }
bool isConstrainedRand() const { return m_constrainedRand; } bool isConstrainedRand() const { return m_constrainedRand; }
void markConstrainedRand(bool flag) { m_constrainedRand = flag; } void markConstrainedRand(bool flag) { m_constrainedRand = flag; }
VRandAttr rand() const { return m_rand; }
void rand(const VRandAttr flag) { m_rand = flag; }
}; };
class AstNBACommitQueueDType final : public AstNodeDType { class AstNBACommitQueueDType final : public AstNodeDType {
// @astgen ptr := m_subDTypep : AstNodeDType // Type of the corresponding variable // @astgen ptr := m_subDTypep : AstNodeDType // Type of the corresponding variable

View File

@ -2488,12 +2488,14 @@ const char* AstLoopTest::broken() const {
void AstMemberDType::dump(std::ostream& str) const { void AstMemberDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str); this->AstNodeDType::dump(str);
if (isConstrainedRand()) str << " [CONSTRAINEDRAND]"; if (isConstrainedRand()) str << " [CONSTRAINEDRAND]";
if (rand().isRandomizable()) str << " [" << rand() << "]";
if (name() != "") str << " name=" << name(); if (name() != "") str << " name=" << name();
if (tag() != "") str << " tag=" << tag(); if (tag() != "") str << " tag=" << tag();
} }
void AstMemberDType::dumpJson(std::ostream& str) const { void AstMemberDType::dumpJson(std::ostream& str) const {
dumpJsonBoolFuncIf(str, isConstrainedRand); dumpJsonBoolFuncIf(str, isConstrainedRand);
if (rand().isRandomizable()) dumpJsonStr(str, "rand", rand().ascii());
dumpJsonStrFunc(str, name); dumpJsonStrFunc(str, name);
dumpJsonStrFunc(str, tag); dumpJsonStrFunc(str, tag);
dumpJsonGen(str); dumpJsonGen(str);

View File

@ -31,6 +31,7 @@ public:
AstCase* m_caseAttrp = nullptr; // Current case statement for attribute adding AstCase* m_caseAttrp = nullptr; // Current case statement for attribute adding
AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration
AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration
VRandAttr m_memRand; // 'rand'/'randc' qualifier for next member declaration
AstDelay* m_netDelayp = nullptr; // Pointer to delay for next signal declaration AstDelay* m_netDelayp = nullptr; // Pointer to delay for next signal declaration
AstStrengthSpec* m_netStrengthp = nullptr; // Pointer to strength for next net declaration AstStrengthSpec* m_netStrengthp = nullptr; // Pointer to strength for next net declaration
FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations

View File

@ -69,6 +69,11 @@ struct VMemberQualifiers final {
q.m_flags = a.m_flags | b.m_flags; q.m_flags = a.m_flags | b.m_flags;
return q; return q;
} }
VRandAttr randAttr() const {
if (m_randc) return VRandAttr::RAND_CYCLIC;
if (m_rand) return VRandAttr::RAND;
return VRandAttr::NONE;
}
void applyToNodes(AstNodeFTask* nodesp) const { void applyToNodes(AstNodeFTask* nodesp) const {
for (AstNodeFTask* nodep = nodesp; nodep; nodep = VN_AS(nodep->nextp(), NodeFTask)) { for (AstNodeFTask* nodep = nodesp; nodep; nodep = VN_AS(nodep->nextp(), NodeFTask)) {
if (m_local) nodep->isHideLocal(true); if (m_local) nodep->isHideLocal(true);

View File

@ -2204,11 +2204,13 @@ struct_union_memberList<memberDTypep>: // IEEE: { struct_union_member }
; ;
struct_union_member<memberDTypep>: // ==IEEE: struct_union_member struct_union_member<memberDTypep>: // ==IEEE: struct_union_member
// // UNSUP random_qualifer not propagated until have randomize support
random_qualifierE data_type_or_void random_qualifierE data_type_or_void
/*mid*/ { GRAMMARP->m_memDTypep = $2; } // As a list follows, need to attach this dtype to each member. /*mid*/ { GRAMMARP->m_memDTypep = $2; // As a list follows, need to attach this dtype to each member.
GRAMMARP->m_memRand = $1.randAttr(); }
/*cont*/ list_of_member_decl_assignments ';' /*cont*/ list_of_member_decl_assignments ';'
{ $$ = $4; DEL(GRAMMARP->m_memDTypep); GRAMMARP->m_memDTypep = nullptr; } { $$ = $4;
DEL(GRAMMARP->m_memDTypep); GRAMMARP->m_memDTypep = nullptr;
GRAMMARP->m_memRand = VRandAttr::NONE; }
| vlTag { $$ = nullptr; } | vlTag { $$ = nullptr; }
; ;
@ -2226,6 +2228,7 @@ member_decl_assignment<memberDTypep>: // Derived from IEEE: variable_decl_assi
? GRAMMARP->m_memDTypep->cloneTree(true) : nullptr), ? GRAMMARP->m_memDTypep->cloneTree(true) : nullptr),
$2, false), $2, false),
nullptr}; nullptr};
$$->rand(GRAMMARP->m_memRand);
PARSEP->tagNodep($$); PARSEP->tagNodep($$);
} }
| idAny variable_dimensionListE '=' variable_declExpr | idAny variable_dimensionListE '=' variable_declExpr
@ -2234,6 +2237,7 @@ member_decl_assignment<memberDTypep>: // Derived from IEEE: variable_decl_assi
? GRAMMARP->m_memDTypep->cloneTree(true) : nullptr), ? GRAMMARP->m_memDTypep->cloneTree(true) : nullptr),
$2, false), $2, false),
$4}; $4};
$$->rand(GRAMMARP->m_memRand);
PARSEP->tagNodep($$); PARSEP->tagNodep($$);
} }
| idSVKwd { $$ = nullptr; } | idSVKwd { $$ = nullptr; }

View File

@ -10,6 +10,7 @@ module Vt_debug_emitv_t;
} ps_t; } ps_t;
typedef struct { typedef struct {
logic signed [2:0] a; logic signed [2:0] a;
logic [1:0] b;
} us_t; } us_t;
typedef union { typedef union {
logic a; logic a;
@ -19,6 +20,7 @@ module Vt_debug_emitv_t;
} ps[0:2]; } ps[0:2];
struct { struct {
logic signed [2:0] a; logic signed [2:0] a;
logic [1:0] b;
} us; } us;
union { union {
logic a; logic a;

View File

@ -64,6 +64,7 @@ module t (/*AUTOARG*/
} ps_t; } ps_t;
typedef struct { typedef struct {
logic signed [2:0] a; logic signed [2:0] a;
rand logic [1:0] b;
} us_t; } us_t;
typedef union { typedef union {
logic a; logic a;