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.
int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member
bool m_constrainedRand = false;
// UNSUP: int m_randType; // Randomization type (IEEE)
VRandAttr m_rand; // Randomizability of this member (rand, randc, etc)
public:
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp,
AstNode* valuep)
@ -1025,6 +1025,8 @@ public:
}
bool isConstrainedRand() const { return m_constrainedRand; }
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 {
// @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 {
this->AstNodeDType::dump(str);
if (isConstrainedRand()) str << " [CONSTRAINEDRAND]";
if (rand().isRandomizable()) str << " [" << rand() << "]";
if (name() != "") str << " name=" << name();
if (tag() != "") str << " tag=" << tag();
}
void AstMemberDType::dumpJson(std::ostream& str) const {
dumpJsonBoolFuncIf(str, isConstrainedRand);
if (rand().isRandomizable()) dumpJsonStr(str, "rand", rand().ascii());
dumpJsonStrFunc(str, name);
dumpJsonStrFunc(str, tag);
dumpJsonGen(str);

View File

@ -31,6 +31,7 @@ public:
AstCase* m_caseAttrp = nullptr; // Current case statement for attribute adding
AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal 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
AstStrengthSpec* m_netStrengthp = nullptr; // Pointer to strength for next net declaration
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;
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 {
for (AstNodeFTask* nodep = nodesp; nodep; nodep = VN_AS(nodep->nextp(), NodeFTask)) {
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
// // UNSUP random_qualifer not propagated until have randomize support
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 ';'
{ $$ = $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; }
;
@ -2226,6 +2228,7 @@ member_decl_assignment<memberDTypep>: // Derived from IEEE: variable_decl_assi
? GRAMMARP->m_memDTypep->cloneTree(true) : nullptr),
$2, false),
nullptr};
$$->rand(GRAMMARP->m_memRand);
PARSEP->tagNodep($$);
}
| 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),
$2, false),
$4};
$$->rand(GRAMMARP->m_memRand);
PARSEP->tagNodep($$);
}
| idSVKwd { $$ = nullptr; }

View File

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

View File

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