1 // -*- mode: C++; c-file-style: "cc-mode" -*-
2 //*************************************************************************
3 // DESCRIPTION: Verilator: Expression width calculations
4 //
5 // Code available from: https://verilator.org
6 //
7 //*************************************************************************
8 //
9 // Copyright 2003-2021 by Wilson Snyder. This program is free software; you
10 // can redistribute it and/or modify it under the terms of either the GNU
11 // Lesser General Public License Version 3 or the Perl Artistic License
12 // Version 2.0.
13 // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
14 //
15 //*************************************************************************
16 // V3Width's Transformations:
17 // Top down traversal:
18 // Determine width of sub-expressions
19 // width() = # bits upper expression wants, 0 for anything-goes
20 // widthUnsized() = # bits for unsized constant, or 0 if it's sized
21 // widthMin() = Alternative acceptable width for linting, or width() if sized
22 // Determine this subop's width, can be either:
23 // Fixed width X
24 // Unsized, min width X ('d5 is unsized, min 3 bits.)
25 // Pass up:
26 // width() = # bits this expression generates
27 // widthSized() = true if all constants sized, else false
28 // Compute size of this expression
29 // Lint warn about mismatches
30 // If expr size != subop fixed, bad
31 // If expr size < subop unsized minimum, bad
32 // If expr size != subop, edit netlist
33 // For == and similar ops, if multibit underneath, add a REDOR
34 // If subop larger, add a EXTRACT
35 // If subop smaller, add a EXTEND
36 // Pass size to sub-expressions if required (+/-* etc)
37 // FINAL = true.
38 // Subexpressions lint and extend as needed
39 //
40 //*************************************************************************
41 // Signedness depends on:
42 // Decimal numbers are signed
43 // Based numbers are unsigned unless 's' prefix
44 // Comparison results are unsigned
45 // Bit&Part selects are unsigned, even if whole
46 // Concatenates are unsigned
47 // Ignore signedness of self-determined:
48 // shift rhs, ** rhs, x?: lhs, concat and replicate members
49 // Else, if any operand unsigned, output unsigned
50 //
51 // Real number rules:
52 // Real numbers are real (duh)
53 // Reals convert to integers by rounding
54 // Reals init to 0.0
55 // Logicals convert compared to zero
56 // If any operand is real, result is real
57 //*************************************************************************
58 // V3Width is the only visitor that uses vup. We could switch to using userp,
59 // though note some iterators operate on next() and so would need to pass the
60 // same value on each nextp().
61 //*************************************************************************
62 // See notes in internal.txt about misuse of iterateAndNext and use of
63 // iterateSubtreeReturnEdits.
64 //*************************************************************************
65
66 #include "config_build.h"
67 #include "verilatedos.h"
68
69 #include "V3Global.h"
70 #include "V3Width.h"
71 #include "V3Number.h"
72 #include "V3Const.h"
73 #include "V3Randomize.h"
74 #include "V3String.h"
75 #include "V3Task.h"
76
77 #include <algorithm>
78
79 // More code; this file was getting too large; see actions there
80 #define VERILATOR_V3WIDTH_CPP_
81 #include "V3WidthCommit.h"
82
83 //######################################################################
84
85 enum Stage : uint8_t {
86 PRELIM = 1,
87 FINAL = 2,
88 BOTH = 3
89 }; // Numbers are a bitmask <0>=prelim, <1>=final
operator <<(std::ostream & str,const Stage & rhs)90 std::ostream& operator<<(std::ostream& str, const Stage& rhs) {
91 return str << ("-PFB"[static_cast<int>(rhs)]);
92 }
93
94 enum Determ : uint8_t {
95 SELF, // Self-determined
96 CONTEXT, // Context-determined
97 ASSIGN // Assignment-like where sign comes from RHS only
98 };
operator <<(std::ostream & str,const Determ & rhs)99 std::ostream& operator<<(std::ostream& str, const Determ& rhs) {
100 static const char* const s_det[] = {"SELF", "CNTX", "ASSN"};
101 return str << s_det[rhs];
102 }
103
104 enum Castable : uint8_t { UNSUPPORTED, COMPATIBLE, DYNAMIC_ENUM, DYNAMIC_CLASS, INCOMPATIBLE };
operator <<(std::ostream & str,const Castable & rhs)105 std::ostream& operator<<(std::ostream& str, const Castable& rhs) {
106 static const char* const s_det[] = {"UNSUP", "COMPAT", "DYN_ENUM", "DYN_CLS", "INCOMPAT"};
107 return str << s_det[rhs];
108 }
109
110 //######################################################################
111 // Width state, as a visitor of each AstNode
112
113 class WidthVP final {
114 // Parameters to pass down hierarchy with visit functions.
115 AstNodeDType* const m_dtypep; // Parent's data type to resolve to
116 const Stage m_stage; // If true, report errors
117 public:
WidthVP(AstNodeDType * dtypep,Stage stage)118 WidthVP(AstNodeDType* dtypep, Stage stage)
119 : m_dtypep{dtypep}
120 , m_stage{stage} {
121 // Prelim doesn't look at assignments, so shouldn't need a dtype,
122 // however AstPattern uses them
123 }
WidthVP(Determ determ,Stage stage)124 WidthVP(Determ determ, Stage stage)
125 : m_dtypep{nullptr}
126 , m_stage{stage} {
127 if (determ != SELF && stage != PRELIM)
128 v3fatalSrc("Context-determined width request only allowed as prelim step");
129 }
p()130 WidthVP* p() { return this; }
selfDtm() const131 bool selfDtm() const { return m_dtypep == nullptr; }
dtypep() const132 AstNodeDType* dtypep() const {
133 // Detect where overrideDType is probably the intended call
134 if (!m_dtypep) v3fatalSrc("Width dtype request on self-determined or preliminary VUP");
135 return m_dtypep;
136 }
dtypeNullp() const137 AstNodeDType* dtypeNullp() const { return m_dtypep; }
dtypeNullSkipRefp() const138 AstNodeDType* dtypeNullSkipRefp() const {
139 AstNodeDType* dtp = dtypeNullp();
140 if (dtp) dtp = dtp->skipRefp();
141 return dtp;
142 }
dtypeOverridep(AstNodeDType * defaultp) const143 AstNodeDType* dtypeOverridep(AstNodeDType* defaultp) const {
144 if (m_stage == PRELIM) v3fatalSrc("Parent dtype should be a final-stage action");
145 return m_dtypep ? m_dtypep : defaultp;
146 }
width() const147 int width() const {
148 if (!m_dtypep) v3fatalSrc("Width request on self-determined or preliminary VUP");
149 return m_dtypep->width();
150 }
widthMin() const151 int widthMin() const {
152 if (!m_dtypep) v3fatalSrc("Width request on self-determined or preliminary VUP");
153 return m_dtypep->widthMin();
154 }
prelim() const155 bool prelim() const { return m_stage & PRELIM; }
final() const156 bool final() const { return m_stage & FINAL; }
dump(std::ostream & str) const157 void dump(std::ostream& str) const {
158 if (!m_dtypep) {
159 str << " VUP(s=" << m_stage << ",self)";
160 } else {
161 str << " VUP(s=" << m_stage << ",dt=" << cvtToHex(dtypep());
162 dtypep()->dumpSmall(str);
163 str << ")";
164 }
165 }
166 };
operator <<(std::ostream & str,const WidthVP * vup)167 std::ostream& operator<<(std::ostream& str, const WidthVP* vup) {
168 if (vup) vup->dump(str);
169 return str;
170 }
171
172 //######################################################################
173
174 class WidthClearVisitor final {
175 // Rather than a AstNVisitor, can just quickly touch every node
clearWidthRecurse(AstNode * nodep)176 void clearWidthRecurse(AstNode* nodep) {
177 for (; nodep; nodep = nodep->nextp()) {
178 nodep->didWidth(false);
179 if (nodep->op1p()) clearWidthRecurse(nodep->op1p());
180 if (nodep->op2p()) clearWidthRecurse(nodep->op2p());
181 if (nodep->op3p()) clearWidthRecurse(nodep->op3p());
182 if (nodep->op4p()) clearWidthRecurse(nodep->op4p());
183 }
184 }
185
186 public:
187 // CONSTRUCTORS
WidthClearVisitor(AstNetlist * nodep)188 explicit WidthClearVisitor(AstNetlist* nodep) { clearWidthRecurse(nodep); }
189 virtual ~WidthClearVisitor() = default;
190 };
191
192 //######################################################################
193
194 #define accept in_WidthVisitor_use_AstNode_iterate_instead_of_AstNode_accept
195
196 //######################################################################
197
198 class WidthVisitor final : public AstNVisitor {
199 private:
200 // TYPES
201 using TableMap = std::map<std::pair<const AstNodeDType*, AstAttrType>, AstVar*>;
202 using PatVecMap = std::map<int, AstPatMember*>;
203
204 // STATE
205 WidthVP* m_vup = nullptr; // Current node state
206 const AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations
207 const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
208 const AstNodeProcedure* m_procedurep = nullptr; // Current final/always
209 const AstWith* m_withp = nullptr; // Current 'with' statement
210 const AstFunc* m_funcp = nullptr; // Current function
211 const AstAttrOf* m_attrp = nullptr; // Current attribute
212 const bool m_paramsOnly; // Computing parameter value; limit operation
213 const bool m_doGenerate; // Do errors later inside generate statement
214 int m_dtTables = 0; // Number of created data type tables
215 TableMap m_tableMap; // Created tables so can remove duplicates
216 std::map<const AstNodeDType*, AstQueueDType*>
217 m_queueDTypeIndexed; // Queues with given index type
218
219 // ENUMS
220 enum ExtendRule : uint8_t {
221 EXTEND_EXP, // Extend if expect sign and node signed, e.g. node=y in ADD(x,y), "x + y"
222 EXTEND_ZERO, // Extend with zeros. e.g. node=y in EQ(x,y), "x == y"
223 EXTEND_LHS, // Extend with sign if node signed. e.g. node=y in ASSIGN(y,x), "x = y"
224 EXTEND_OFF // No extension
225 };
226
227 // METHODS
debug()228 static int debug() { return V3Width::debug(); }
229
230 // VISITORS
231 // Naming: width_O{outputtype}_L{lhstype}_R{rhstype}_W{widthing}_S{signing}
232 // Where type:
233 // _O1=boolean (width 1 unsigned)
234 // _Ou=unsigned
235 // _Os=signed
236 // _Ous=unsigned or signed
237 // _Or=real
238 // _Ox=anything
239
240 // Widths: 1 bit out, lhs 1 bit; Real: converts via compare with 0
visit(AstLogNot * nodep)241 virtual void visit(AstLogNot* nodep) override { visit_log_not(nodep); }
242 // Widths: 1 bit out, lhs 1 bit, rhs 1 bit; Real: converts via compare with 0
visit(AstLogAnd * nodep)243 virtual void visit(AstLogAnd* nodep) override { visit_log_and_or(nodep); }
visit(AstLogOr * nodep)244 virtual void visit(AstLogOr* nodep) override { visit_log_and_or(nodep); }
visit(AstLogEq * nodep)245 virtual void visit(AstLogEq* nodep) override {
246 // Conversion from real not in IEEE, but a fallout
247 visit_log_and_or(nodep);
248 }
visit(AstLogIf * nodep)249 virtual void visit(AstLogIf* nodep) override {
250 // Conversion from real not in IEEE, but a fallout
251 visit_log_and_or(nodep);
252 }
253
254 // Widths: 1 bit out, Any width lhs
visit(AstRedAnd * nodep)255 virtual void visit(AstRedAnd* nodep) override { visit_red_and_or(nodep); }
visit(AstRedOr * nodep)256 virtual void visit(AstRedOr* nodep) override { visit_red_and_or(nodep); }
visit(AstRedXor * nodep)257 virtual void visit(AstRedXor* nodep) override { visit_red_and_or(nodep); }
visit(AstOneHot * nodep)258 virtual void visit(AstOneHot* nodep) override { visit_red_and_or(nodep); }
visit(AstOneHot0 * nodep)259 virtual void visit(AstOneHot0* nodep) override { visit_red_and_or(nodep); }
visit(AstIsUnknown * nodep)260 virtual void visit(AstIsUnknown* nodep) override {
261 visit_red_unknown(nodep); // Allow real
262 }
263
264 // These have different node types, as they operate differently
265 // Must add to case statement below,
266 // Widths: 1 bit out, lhs width == rhs width. real if lhs|rhs real
visit(AstEq * nodep)267 virtual void visit(AstEq* nodep) override { visit_cmp_eq_gt(nodep, true); }
visit(AstNeq * nodep)268 virtual void visit(AstNeq* nodep) override { visit_cmp_eq_gt(nodep, true); }
visit(AstGt * nodep)269 virtual void visit(AstGt* nodep) override { visit_cmp_eq_gt(nodep, true); }
visit(AstGte * nodep)270 virtual void visit(AstGte* nodep) override { visit_cmp_eq_gt(nodep, true); }
visit(AstLt * nodep)271 virtual void visit(AstLt* nodep) override { visit_cmp_eq_gt(nodep, true); }
visit(AstLte * nodep)272 virtual void visit(AstLte* nodep) override { visit_cmp_eq_gt(nodep, true); }
visit(AstGtS * nodep)273 virtual void visit(AstGtS* nodep) override { visit_cmp_eq_gt(nodep, true); }
visit(AstGteS * nodep)274 virtual void visit(AstGteS* nodep) override { visit_cmp_eq_gt(nodep, true); }
visit(AstLtS * nodep)275 virtual void visit(AstLtS* nodep) override { visit_cmp_eq_gt(nodep, true); }
visit(AstLteS * nodep)276 virtual void visit(AstLteS* nodep) override { visit_cmp_eq_gt(nodep, true); }
visit(AstEqCase * nodep)277 virtual void visit(AstEqCase* nodep) override { visit_cmp_eq_gt(nodep, true); }
visit(AstNeqCase * nodep)278 virtual void visit(AstNeqCase* nodep) override { visit_cmp_eq_gt(nodep, true); }
279 // ... These comparisons don't allow reals
visit(AstEqWild * nodep)280 virtual void visit(AstEqWild* nodep) override { visit_cmp_eq_gt(nodep, false); }
visit(AstNeqWild * nodep)281 virtual void visit(AstNeqWild* nodep) override { visit_cmp_eq_gt(nodep, false); }
282 // ... Real compares
visit(AstEqD * nodep)283 virtual void visit(AstEqD* nodep) override { visit_cmp_real(nodep); }
visit(AstNeqD * nodep)284 virtual void visit(AstNeqD* nodep) override { visit_cmp_real(nodep); }
visit(AstLtD * nodep)285 virtual void visit(AstLtD* nodep) override { visit_cmp_real(nodep); }
visit(AstLteD * nodep)286 virtual void visit(AstLteD* nodep) override { visit_cmp_real(nodep); }
visit(AstGtD * nodep)287 virtual void visit(AstGtD* nodep) override { visit_cmp_real(nodep); }
visit(AstGteD * nodep)288 virtual void visit(AstGteD* nodep) override { visit_cmp_real(nodep); }
289 // ... String compares
visit(AstEqN * nodep)290 virtual void visit(AstEqN* nodep) override { visit_cmp_string(nodep); }
visit(AstNeqN * nodep)291 virtual void visit(AstNeqN* nodep) override { visit_cmp_string(nodep); }
visit(AstLtN * nodep)292 virtual void visit(AstLtN* nodep) override { visit_cmp_string(nodep); }
visit(AstLteN * nodep)293 virtual void visit(AstLteN* nodep) override { visit_cmp_string(nodep); }
visit(AstGtN * nodep)294 virtual void visit(AstGtN* nodep) override { visit_cmp_string(nodep); }
visit(AstGteN * nodep)295 virtual void visit(AstGteN* nodep) override { visit_cmp_string(nodep); }
296
297 // Widths: out width = lhs width = rhs width
298 // Signed: Output signed iff LHS & RHS signed.
299 // Real: Not allowed
visit(AstAnd * nodep)300 virtual void visit(AstAnd* nodep) override { visit_boolmath_and_or(nodep); }
visit(AstOr * nodep)301 virtual void visit(AstOr* nodep) override { visit_boolmath_and_or(nodep); }
visit(AstXor * nodep)302 virtual void visit(AstXor* nodep) override { visit_boolmath_and_or(nodep); }
visit(AstBufIf1 * nodep)303 virtual void visit(AstBufIf1* nodep) override {
304 visit_boolmath_and_or(nodep);
305 } // Signed behavior changing in 3.814
306 // Width: Max(Lhs,Rhs) sort of.
307 // Real: If either side real
308 // Signed: If both sides real
visit(AstAdd * nodep)309 virtual void visit(AstAdd* nodep) override { visit_add_sub_replace(nodep, true); }
visit(AstSub * nodep)310 virtual void visit(AstSub* nodep) override { visit_add_sub_replace(nodep, true); }
visit(AstDiv * nodep)311 virtual void visit(AstDiv* nodep) override { visit_add_sub_replace(nodep, true); }
visit(AstMul * nodep)312 virtual void visit(AstMul* nodep) override { visit_add_sub_replace(nodep, true); }
313 // These can't promote to real
visit(AstModDiv * nodep)314 virtual void visit(AstModDiv* nodep) override { visit_add_sub_replace(nodep, false); }
visit(AstModDivS * nodep)315 virtual void visit(AstModDivS* nodep) override { visit_add_sub_replace(nodep, false); }
visit(AstMulS * nodep)316 virtual void visit(AstMulS* nodep) override { visit_add_sub_replace(nodep, false); }
visit(AstDivS * nodep)317 virtual void visit(AstDivS* nodep) override { visit_add_sub_replace(nodep, false); }
318 // Widths: out width = lhs width, but upper matters
319 // Signed: Output signed iff LHS signed; unary operator
320 // Unary promote to real
visit(AstNegate * nodep)321 virtual void visit(AstNegate* nodep) override { visit_negate_not(nodep, true); }
322 // Unary never real
visit(AstNot * nodep)323 virtual void visit(AstNot* nodep) override { visit_negate_not(nodep, false); }
324
325 // Real: inputs and output real
visit(AstAddD * nodep)326 virtual void visit(AstAddD* nodep) override { visit_real_add_sub(nodep); }
visit(AstSubD * nodep)327 virtual void visit(AstSubD* nodep) override { visit_real_add_sub(nodep); }
visit(AstDivD * nodep)328 virtual void visit(AstDivD* nodep) override { visit_real_add_sub(nodep); }
visit(AstMulD * nodep)329 virtual void visit(AstMulD* nodep) override { visit_real_add_sub(nodep); }
visit(AstPowD * nodep)330 virtual void visit(AstPowD* nodep) override { visit_real_add_sub(nodep); }
visit(AstNodeSystemBiop * nodep)331 virtual void visit(AstNodeSystemBiop* nodep) override { visit_real_add_sub(nodep); }
332 // Real: Output real
visit(AstNegateD * nodep)333 virtual void visit(AstNegateD* nodep) override { visit_real_neg_ceil(nodep); }
visit(AstNodeSystemUniop * nodep)334 virtual void visit(AstNodeSystemUniop* nodep) override { visit_real_neg_ceil(nodep); }
335
336 // Widths: out signed/unsigned width = lhs width, input un|signed
visit(AstSigned * nodep)337 virtual void visit(AstSigned* nodep) override {
338 visit_signed_unsigned(nodep, VSigning::SIGNED);
339 }
visit(AstUnsigned * nodep)340 virtual void visit(AstUnsigned* nodep) override {
341 visit_signed_unsigned(nodep, VSigning::UNSIGNED);
342 }
343
344 // Widths: Output width from lhs, rhs<33 bits
345 // Signed: If lhs signed
visit(AstShiftL * nodep)346 virtual void visit(AstShiftL* nodep) override { visit_shift(nodep); }
visit(AstShiftR * nodep)347 virtual void visit(AstShiftR* nodep) override { visit_shift(nodep); }
348 // ShiftRS converts to ShiftR, but not vice-versa
visit(AstShiftRS * nodep)349 virtual void visit(AstShiftRS* nodep) override { visit_shift(nodep); }
350
351 //========
352 // Widths: Output real, input integer signed
visit(AstBitsToRealD * nodep)353 virtual void visit(AstBitsToRealD* nodep) override { visit_Or_Lu64(nodep); }
354
355 // Widths: Output integer signed, input real
visit(AstRToIS * nodep)356 virtual void visit(AstRToIS* nodep) override { visit_Os32_Lr(nodep); }
visit(AstRToIRoundS * nodep)357 virtual void visit(AstRToIRoundS* nodep) override {
358 // Only created here, size comes from upper expression
359 if (m_vup->prelim()) { // First stage evaluation
360 iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH);
361 }
362 if (!nodep->dtypep()->widthSized()) nodep->v3fatalSrc("RToIRoundS should be presized");
363 }
364
365 // Widths: Output integer unsigned, input real
visit(AstRealToBits * nodep)366 virtual void visit(AstRealToBits* nodep) override { visit_Ou64_Lr(nodep); }
367
368 // Output integer, input string
visit(AstLenN * nodep)369 virtual void visit(AstLenN* nodep) override { visit_Os32_string(nodep); }
visit(AstPutcN * nodep)370 virtual void visit(AstPutcN* nodep) override {
371 // CALLER: str.putc()
372 UASSERT_OBJ(nodep->rhsp() && nodep->thsp(), nodep, "For ternary ops only!");
373 if (m_vup && m_vup->prelim()) {
374 // See similar handling in visit_cmp_eq_gt where created
375 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
376 iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH);
377 iterateCheckSigned32(nodep, "THS", nodep->thsp(), BOTH);
378 nodep->dtypeSetString(); // AstPutcN returns the new string to be assigned by
379 // AstAssign
380 }
381 }
visit(AstGetcN * nodep)382 virtual void visit(AstGetcN* nodep) override {
383 // CALLER: str.getc()
384 UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!");
385 if (m_vup && m_vup->prelim()) {
386 // See similar handling in visit_cmp_eq_gt where created
387 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
388 iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH);
389 nodep->dtypeSetBitSized(8, VSigning::UNSIGNED);
390 }
391 }
visit(AstGetcRefN * nodep)392 virtual void visit(AstGetcRefN* nodep) override {
393 // CALLER: str.getc()
394 UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!");
395 if (m_vup && m_vup->prelim()) {
396 // See similar handling in visit_cmp_eq_gt where created
397 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
398 iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH);
399 nodep->dtypeSetBitSized(8, VSigning::UNSIGNED);
400 }
401 }
visit(AstSubstrN * nodep)402 virtual void visit(AstSubstrN* nodep) override {
403 // CALLER: str.substr()
404 UASSERT_OBJ(nodep->rhsp() && nodep->thsp(), nodep, "For ternary ops only!");
405 if (m_vup && m_vup->prelim()) {
406 // See similar handling in visit_cmp_eq_gt where created
407 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
408 iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH);
409 iterateCheckSigned32(nodep, "THS", nodep->thsp(), BOTH);
410 nodep->dtypeSetString();
411 }
412 }
visit(AstCompareNN * nodep)413 virtual void visit(AstCompareNN* nodep) override {
414 // CALLER: str.compare(), str.icompare()
415 // Widths: 32 bit out
416 UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!");
417 if (m_vup->prelim()) {
418 // See similar handling in visit_cmp_eq_gt where created
419 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
420 iterateCheckString(nodep, "RHS", nodep->rhsp(), BOTH);
421 nodep->dtypeSetSigned32();
422 }
423 }
visit(AstAtoN * nodep)424 virtual void visit(AstAtoN* nodep) override {
425 // CALLER: str.atobin(), atoi(), atohex(), atooct(), atoreal()
426 // Width: 64bit floating point for atoreal(), 32bit out for the others
427 if (m_vup->prelim()) {
428 // See similar handling in visit_cmp_eq_gt where created
429 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
430 if (nodep->format() == AstAtoN::ATOREAL) {
431 nodep->dtypeSetDouble();
432 } else {
433 nodep->dtypeSetSigned32();
434 }
435 }
436 }
437
438 // Widths: Constant, terminal
visit(AstTime * nodep)439 virtual void visit(AstTime* nodep) override { nodep->dtypeSetUInt64(); }
visit(AstTimeD * nodep)440 virtual void visit(AstTimeD* nodep) override { nodep->dtypeSetDouble(); }
visit(AstTestPlusArgs * nodep)441 virtual void visit(AstTestPlusArgs* nodep) override { nodep->dtypeSetSigned32(); }
visit(AstScopeName * nodep)442 virtual void visit(AstScopeName* nodep) override {
443 nodep->dtypeSetUInt64(); // A pointer, but not that it matters
444 }
445
visit(AstNodeCond * nodep)446 virtual void visit(AstNodeCond* nodep) override {
447 // op = cond ? expr1 : expr2
448 // See IEEE-2012 11.4.11 and Table 11-21.
449 // LHS is self-determined
450 // Width: max(RHS, THS)
451 // Signed: Output signed iff RHS & THS signed (presumed, not in IEEE)
452 // Real: Output real if either expression is real, non-real argument gets converted
453 if (m_vup->prelim()) { // First stage evaluation
454 // Just once, do the conditional, expect one bit out.
455 iterateCheckBool(nodep, "Conditional Test", nodep->condp(), BOTH);
456 // Determine sub expression widths only relying on what's in the subops
457 // CONTEXT determined, but need data type for pattern assignments
458 userIterateAndNext(nodep->expr1p(), WidthVP(m_vup->dtypeNullp(), PRELIM).p());
459 userIterateAndNext(nodep->expr2p(), WidthVP(m_vup->dtypeNullp(), PRELIM).p());
460 // Calculate width of this expression.
461 // First call (prelim()) m_vup->width() is probably zero, so we'll return
462 // the size of this subexpression only.
463 // Second call (final()) m_vup->width() is probably the expression size, so
464 // the expression includes the size of the output too.
465 if (nodep->expr1p()->isDouble() || nodep->expr2p()->isDouble()) {
466 nodep->dtypeSetDouble();
467 } else if (nodep->expr1p()->isString() || nodep->expr2p()->isString()) {
468 nodep->dtypeSetString();
469 } else {
470 const int width = std::max(nodep->expr1p()->width(), nodep->expr2p()->width());
471 const int mwidth
472 = std::max(nodep->expr1p()->widthMin(), nodep->expr2p()->widthMin());
473 const bool issigned = nodep->expr1p()->isSigned() && nodep->expr2p()->isSigned();
474 nodep->dtypeSetLogicUnsized(width, mwidth, VSigning::fromBool(issigned));
475 }
476 }
477 if (m_vup->final()) {
478 AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep());
479 AstNodeDType* const subDTypep = expDTypep;
480 nodep->dtypeFrom(expDTypep);
481 // Error report and change sizes for suboperands of this node.
482 iterateCheck(nodep, "Conditional True", nodep->expr1p(), CONTEXT, FINAL, subDTypep,
483 EXTEND_EXP);
484 iterateCheck(nodep, "Conditional False", nodep->expr2p(), CONTEXT, FINAL, subDTypep,
485 EXTEND_EXP);
486 }
487 }
visit(AstConcat * nodep)488 virtual void visit(AstConcat* nodep) override {
489 // Real: Not allowed (assumed)
490 // Signed: unsigned output, input either (assumed)
491 // IEEE-2012 Table 11-21, and 11.8.1:
492 // LHS, RHS is self-determined
493 // signed: Unsigned (11.8.1)
494 // width: LHS + RHS
495 AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp();
496 userIterate(vdtypep, WidthVP(SELF, BOTH).p());
497 if (VN_IS(vdtypep, QueueDType)) {
498 // Queue "element 0" is lhsp, so we need to swap arguments
499 auto* const newp = new AstConsQueue(nodep->fileline(), nodep->rhsp()->unlinkFrBack(),
500 nodep->lhsp()->unlinkFrBack());
501 nodep->replaceWith(newp);
502 VL_DO_DANGLING(pushDeletep(nodep), nodep);
503 userIterateChildren(newp, m_vup);
504 return;
505 }
506 if (VN_IS(vdtypep, DynArrayDType)) {
507 auto* const newp = new AstConsDynArray(
508 nodep->fileline(), nodep->rhsp()->unlinkFrBack(), nodep->lhsp()->unlinkFrBack());
509 nodep->replaceWith(newp);
510 VL_DO_DANGLING(pushDeletep(nodep), nodep);
511 userIterateChildren(newp, m_vup);
512 return;
513 }
514 if (m_vup->prelim()) {
515 if (VN_IS(vdtypep, AssocArrayDType) //
516 || VN_IS(vdtypep, DynArrayDType) //
517 || VN_IS(vdtypep, QueueDType)) {
518 nodep->v3warn(E_UNSUPPORTED, "Unsupported: Concatenation to form "
519 << vdtypep->prettyDTypeNameQ() << "data type");
520 }
521
522 iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
523 iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
524 nodep->dtypeSetLogicUnsized(nodep->lhsp()->width() + nodep->rhsp()->width(),
525 nodep->lhsp()->widthMin() + nodep->rhsp()->widthMin(),
526 VSigning::UNSIGNED);
527 // Cleanup zero width Verilog2001 {x,{0{foo}}} now,
528 // otherwise having width(0) will cause later assertions to fire
529 if (const AstReplicate* const repp = VN_CAST(nodep->lhsp(), Replicate)) {
530 if (repp->width() == 0) { // Keep rhs
531 nodep->replaceWith(nodep->rhsp()->unlinkFrBack());
532 VL_DO_DANGLING(pushDeletep(nodep), nodep);
533 return;
534 }
535 }
536 if (const AstReplicate* const repp = VN_CAST(nodep->rhsp(), Replicate)) {
537 if (repp->width() == 0) { // Keep lhs
538 nodep->replaceWith(nodep->lhsp()->unlinkFrBack());
539 VL_DO_DANGLING(pushDeletep(nodep), nodep);
540 return;
541 }
542 }
543 }
544 if (m_vup->final()) {
545 if (nodep->lhsp()->isString() || nodep->rhsp()->isString()) {
546 AstNode* const newp
547 = new AstConcatN(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
548 nodep->rhsp()->unlinkFrBack());
549 nodep->replaceWith(newp);
550 VL_DO_DANGLING(pushDeletep(nodep), nodep);
551 return;
552 }
553 if (!nodep->dtypep()->widthSized()) {
554 // See also error in V3Number
555 nodeForUnsizedWarning(nodep)->v3warn(
556 WIDTHCONCAT, "Unsized numbers/parameters not allowed in concatenations.");
557 }
558 }
559 }
visit(AstConcatN * nodep)560 virtual void visit(AstConcatN* nodep) override {
561 // String concatenate.
562 // Already did AstConcat simplifications
563 if (m_vup->prelim()) {
564 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
565 iterateCheckString(nodep, "RHS", nodep->rhsp(), BOTH);
566 nodep->dtypeSetString();
567 }
568 if (m_vup->final()) {
569 if (!nodep->dtypep()->widthSized()) {
570 // See also error in V3Number
571 nodeForUnsizedWarning(nodep)->v3warn(
572 WIDTHCONCAT, "Unsized numbers/parameters not allowed in concatenations.");
573 }
574 }
575 }
visit(AstDelay * nodep)576 virtual void visit(AstDelay* nodep) override {
577 if (VN_IS(m_procedurep, Final)) {
578 nodep->v3error("Delays are not legal in final blocks (IEEE 1800-2017 9.2.3)");
579 VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
580 return;
581 }
582 if (VN_IS(m_ftaskp, Func)) {
583 nodep->v3error("Delays are not legal in functions. Suggest use a task "
584 "(IEEE 1800-2017 13.4.4)");
585 VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
586 return;
587 }
588 nodep->v3warn(STMTDLY, "Unsupported: Ignoring delay on this delayed statement.");
589 VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
590 }
visit(AstFork * nodep)591 virtual void visit(AstFork* nodep) override {
592 if (VN_IS(m_ftaskp, Func) && !nodep->joinType().joinNone()) {
593 nodep->v3error("Only fork .. join_none is legal in functions. "
594 "(IEEE 1800-2017 13.4.4)");
595 VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
596 return;
597 }
598 if (v3Global.opt.bboxUnsup()
599 // With no statements, begin is identical
600 || !nodep->stmtsp()
601 // With one statement, a begin block does as good as a fork/join or join_any
602 || (!nodep->stmtsp()->nextp() && !nodep->joinType().joinNone())) {
603 AstNode* stmtsp = nullptr;
604 if (nodep->stmtsp()) stmtsp = nodep->stmtsp()->unlinkFrBack();
605 AstBegin* const newp = new AstBegin{nodep->fileline(), nodep->name(), stmtsp};
606 nodep->replaceWith(newp);
607 VL_DO_DANGLING(nodep->deleteTree(), nodep);
608 } else {
609 nodep->v3warn(E_UNSUPPORTED, "Unsupported: fork statements");
610 // TBD might support only normal join, if so complain about other join flavors
611 }
612 }
visit(AstDisableFork * nodep)613 virtual void visit(AstDisableFork* nodep) override {
614 nodep->v3warn(E_UNSUPPORTED, "Unsupported: disable fork statements");
615 VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
616 }
visit(AstWaitFork * nodep)617 virtual void visit(AstWaitFork* nodep) override {
618 nodep->v3warn(E_UNSUPPORTED, "Unsupported: wait fork statements");
619 VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
620 }
visit(AstToLowerN * nodep)621 virtual void visit(AstToLowerN* nodep) override {
622 if (m_vup->prelim()) {
623 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
624 nodep->dtypeSetString();
625 }
626 }
visit(AstToUpperN * nodep)627 virtual void visit(AstToUpperN* nodep) override {
628 if (m_vup->prelim()) {
629 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
630 nodep->dtypeSetString();
631 }
632 }
visit(AstReplicate * nodep)633 virtual void visit(AstReplicate* nodep) override {
634 // IEEE-2012 Table 11-21:
635 // LHS, RHS is self-determined
636 // width: value(LHS) * width(RHS)
637 if (m_vup->prelim()) {
638 iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
639 V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change
640 const AstConst* const constp = VN_CAST(nodep->rhsp(), Const);
641 if (!constp) {
642 nodep->v3error("Replication value isn't a constant.");
643 return;
644 }
645 uint32_t times = constp->toUInt();
646 if (times == 0
647 && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up.
648 nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE "
649 "1800-2017 11.4.12.1)");
650 times = 1;
651 }
652
653 AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp();
654 if (VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, DynArrayDType)) {
655 if (times != 1)
656 nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-1 replication to form "
657 << vdtypep->prettyDTypeNameQ()
658 << " data type");
659 // Don't iterate lhsp as SELF, the potential Concat below needs
660 // the adtypep passed down to recognize the QueueDType
661 userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, BOTH).p());
662 nodep->replaceWith(nodep->lhsp()->unlinkFrBack());
663 VL_DO_DANGLING(pushDeletep(nodep), nodep);
664 return;
665 }
666 if (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, UnpackArrayDType)) {
667 nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form "
668 << vdtypep->prettyDTypeNameQ() << " data type");
669 }
670 iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
671 if (nodep->lhsp()->isString()) {
672 AstNode* const newp
673 = new AstReplicateN(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
674 nodep->rhsp()->unlinkFrBack());
675 nodep->replaceWith(newp);
676 VL_DO_DANGLING(pushDeletep(nodep), nodep);
677 return;
678 } else {
679 nodep->dtypeSetLogicUnsized((nodep->lhsp()->width() * times),
680 (nodep->lhsp()->widthMin() * times),
681 VSigning::UNSIGNED);
682 }
683 }
684 if (m_vup->final()) {
685 if (!nodep->dtypep()->widthSized()) {
686 // See also error in V3Number
687 nodeForUnsizedWarning(nodep)->v3warn(
688 WIDTHCONCAT, "Unsized numbers/parameters not allowed in replications.");
689 }
690 }
691 }
visit(AstReplicateN * nodep)692 virtual void visit(AstReplicateN* nodep) override {
693 // Replicate with string
694 if (m_vup->prelim()) {
695 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
696 iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
697 V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change
698 const AstConst* const constp = VN_CAST(nodep->rhsp(), Const);
699 if (!constp) {
700 nodep->v3error("Replication value isn't a constant.");
701 return;
702 }
703 const uint32_t times = constp->toUInt();
704 if (times == 0
705 && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up.
706 nodep->v3error("Replication value of 0 is only legal under a concatenation (IEEE "
707 "1800-2017 11.4.12.1)");
708 }
709 nodep->dtypeSetString();
710 }
711 if (m_vup->final()) {
712 if (!nodep->dtypep()->widthSized()) {
713 // See also error in V3Number
714 nodeForUnsizedWarning(nodep)->v3warn(
715 WIDTHCONCAT, "Unsized numbers/parameters not allowed in replications.");
716 }
717 }
718 }
visit(AstNodeStream * nodep)719 virtual void visit(AstNodeStream* nodep) override {
720 if (m_vup->prelim()) {
721 iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
722 iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
723 V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change
724 const AstConst* const constp = VN_CAST(nodep->rhsp(), Const);
725 AstBasicDType* const basicp = VN_CAST(nodep->rhsp(), BasicDType);
726 if (!constp && !basicp) {
727 nodep->v3error("Slice size isn't a constant or basic data type.");
728 return;
729 }
730 if (basicp) { // Convert data type to a constant size
731 AstConst* const newp = new AstConst(basicp->fileline(), basicp->width());
732 nodep->rhsp()->replaceWith(newp);
733 pushDeletep(basicp);
734 } else {
735 const uint32_t sliceSize = constp->toUInt();
736 if (!sliceSize) {
737 nodep->v3error("Slice size cannot be zero.");
738 return;
739 }
740 }
741 nodep->dtypeSetLogicUnsized(nodep->lhsp()->width(), nodep->lhsp()->widthMin(),
742 VSigning::UNSIGNED);
743 }
744 if (m_vup->final()) {
745 if (!nodep->dtypep()->widthSized()) {
746 // See also error in V3Number
747 nodeForUnsizedWarning(nodep)->v3warn(
748 WIDTHCONCAT, "Unsized numbers/parameters not allowed in streams.");
749 }
750 }
751 }
visit(AstRange * nodep)752 virtual void visit(AstRange* nodep) override {
753 // Real: Not allowed
754 // Signed: unsigned output, input either
755 // Convert all range values to constants
756 UINFO(6, "RANGE " << nodep << endl);
757 V3Const::constifyParamsEdit(nodep->leftp()); // May relink pointed to node
758 V3Const::constifyParamsEdit(nodep->rightp()); // May relink pointed to node
759 checkConstantOrReplace(nodep->leftp(), "left side of bit range isn't a constant");
760 checkConstantOrReplace(nodep->rightp(), "right side of bit range isn't a constant");
761 if (m_vup->prelim()) {
762 // Don't need to iterate because V3Const already constified
763 const int width = nodep->elementsConst();
764 if (width > (1 << 28)) {
765 nodep->v3error("Width of bit range is huge; vector of over 1billion bits: 0x"
766 << std::hex << width);
767 }
768 // Note width() not set on range; use elementsConst()
769 if (nodep->littleEndian() && !VN_IS(nodep->backp(), UnpackArrayDType)
770 && !VN_IS(nodep->backp(), Cell)) { // For cells we warn in V3Inst
771 nodep->v3warn(LITENDIAN, "Little bit endian vector: left < right of bit range: ["
772 << nodep->leftConst() << ":" << nodep->rightConst()
773 << "]");
774 }
775 }
776 }
777
visit(AstSel * nodep)778 virtual void visit(AstSel* nodep) override {
779 // Signed: always unsigned; Real: Not allowed
780 // LSB is self-determined (IEEE 2012 11.5.1)
781 // We also use SELs to shorten a signed constant etc, in this case they are signed.
782 if (nodep->didWidth()) return;
783 UASSERT_OBJ(m_vup, nodep, "Select under an unexpected context");
784 if (m_vup->prelim()) {
785 if (debug() >= 9) nodep->dumpTree(cout, "-selWidth: ");
786 userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT, PRELIM).p());
787 userIterateAndNext(nodep->lsbp(), WidthVP(SELF, PRELIM).p());
788 checkCvtUS(nodep->fromp());
789 iterateCheckSizedSelf(nodep, "Select Width", nodep->widthp(), SELF, BOTH);
790 iterateCheckSizedSelf(nodep, "Select LHS", nodep->lhsp(), SELF, BOTH);
791 V3Const::constifyParamsEdit(nodep->widthp()); // widthp may change
792 const AstConst* const widthConstp = VN_CAST(nodep->widthp(), Const);
793 if (!widthConstp) {
794 nodep->v3error("Width of bit extract isn't a constant");
795 nodep->dtypeSetBit();
796 return;
797 }
798 int width = nodep->widthConst();
799 UASSERT_OBJ(nodep->dtypep(), nodep, "dtype wasn't set"); // by V3WidthSel
800 if (VN_IS(nodep->lsbp(), Const) && nodep->msbConst() < nodep->lsbConst()) {
801 nodep->v3warn(E_UNSUPPORTED, "Unsupported: left < right of bit extract: "
802 << nodep->msbConst() << "<" << nodep->lsbConst());
803 width = (nodep->lsbConst() - nodep->msbConst() + 1);
804 nodep->dtypeSetLogicSized(width, VSigning::UNSIGNED);
805 nodep->widthp()->replaceWith(new AstConst(nodep->widthp()->fileline(), width));
806 nodep->lsbp()->replaceWith(new AstConst(nodep->lsbp()->fileline(), 0));
807 }
808 // We're extracting, so just make sure the expression is at least wide enough.
809 if (nodep->fromp()->width() < width) {
810 nodep->v3warn(SELRANGE, "Extracting " << width << " bits from only "
811 << nodep->fromp()->width() << " bit number");
812 // Extend it.
813 AstNodeDType* const subDTypep
814 = nodep->findLogicDType(width, width, nodep->fromp()->dtypep()->numeric());
815 widthCheckSized(nodep, "errorless...", nodep->fromp(), subDTypep, EXTEND_EXP,
816 false /*noerror*/);
817 }
818 // Check bit indexes.
819 // What is the MSB? We want the true MSB, not one starting at
820 // 0, because a 4 bit index is required to look at a one-bit
821 // variable[15:15] and 5 bits for [15:-2]
822 int frommsb = nodep->fromp()->width() - 1;
823 int fromlsb = 0;
824 const int elw = nodep->declElWidth(); // Must adjust to tell user bit ranges
825 if (nodep->declRange().ranged()) {
826 frommsb = nodep->declRange().hiMaxSelect() * elw
827 + (elw - 1); // Corrected for negative lsb
828 fromlsb = nodep->declRange().lo() * elw;
829 } else {
830 // nodep->v3fatalSrc("Should have been declRanged in V3WidthSel");
831 }
832 const int selwidth = V3Number::log2b(frommsb + 1 - 1) + 1; // Width to address a bit
833 AstNodeDType* const selwidthDTypep
834 = nodep->findLogicDType(selwidth, selwidth, nodep->lsbp()->dtypep()->numeric());
835 userIterateAndNext(nodep->fromp(), WidthVP(SELF, FINAL).p());
836 userIterateAndNext(nodep->lsbp(), WidthVP(SELF, FINAL).p());
837 if (widthBad(nodep->lsbp(), selwidthDTypep) && nodep->lsbp()->width() != 32) {
838 if (!nodep->fileline()->warnIsOff(V3ErrorCode::WIDTH)) {
839 nodep->v3warn(WIDTH,
840 "Bit extraction of var["
841 << (frommsb / elw) << ":" << (fromlsb / elw) << "] requires "
842 << (selwidth / elw) << " bit index, not "
843 << (nodep->lsbp()->width() / elw)
844 << (nodep->lsbp()->width() != nodep->lsbp()->widthMin()
845 ? " or " + cvtToStr(nodep->lsbp()->widthMin() / elw)
846 : "")
847 << " bits.");
848 UINFO(1, " Related node: " << nodep << endl);
849 }
850 }
851 if (VN_IS(nodep->lsbp(), Const) && nodep->msbConst() > frommsb) {
852 // See also warning in V3Const
853 // We need to check here, because the widthCheckSized may silently
854 // add another SEL which will lose the out-of-range check
855 //
856 // We don't want to trigger an error here if we are just
857 // evaluating type sizes for a generate block condition. We
858 // should only trigger the error if the out-of-range access is
859 // actually generated.
860 if (m_doGenerate) {
861 UINFO(5, "Selection index out of range inside generate." << endl);
862 } else {
863 nodep->v3warn(SELRANGE, "Selection index out of range: "
864 << nodep->msbConst() << ":" << nodep->lsbConst()
865 << " outside " << frommsb << ":" << fromlsb);
866 UINFO(1, " Related node: " << nodep << endl);
867 }
868 }
869 // iterate FINAL is two blocks above
870 //
871 // If we have a width problem with GENERATE etc, this will reduce
872 // it down and mask it, so we have no chance of finding a real
873 // error in the future. So don't do this for them.
874 if (!m_doGenerate) {
875 // lsbp() must be self-determined, however for performance
876 // we want the select to be truncated to fit within the
877 // maximum select range, e.g. turn Xs outside of the select
878 // into something fast which pulls from within the array.
879 widthCheckSized(nodep, "Extract Range", nodep->lsbp(), selwidthDTypep, EXTEND_EXP,
880 false /*NOWARN*/);
881 }
882 }
883 }
884
visit(AstArraySel * nodep)885 virtual void visit(AstArraySel* nodep) override {
886 // Signed/Real: Output signed iff LHS signed/real; binary operator
887 // Note by contrast, bit extract selects are unsigned
888 // LSB is self-determined (IEEE 2012 11.5.1)
889 if (m_vup->prelim()) {
890 iterateCheckSizedSelf(nodep, "Bit select", nodep->bitp(), SELF, BOTH);
891 userIterateAndNext(nodep->fromp(), WidthVP(SELF, BOTH).p());
892 //
893 int frommsb;
894 int fromlsb;
895 const AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefp();
896 if (const AstUnpackArrayDType* const adtypep = VN_CAST(fromDtp, UnpackArrayDType)) {
897 frommsb = adtypep->hi();
898 fromlsb = adtypep->lo();
899 if (fromlsb > frommsb) {
900 const int t = frommsb;
901 frommsb = fromlsb;
902 fromlsb = t;
903 }
904 // However, if the lsb<0 we may go negative, so need more bits!
905 if (fromlsb < 0) frommsb += -fromlsb;
906 nodep->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
907 } else {
908 // Note PackArrayDType doesn't use an ArraySel but a normal Sel.
909 UINFO(1, " Related dtype: " << fromDtp << endl);
910 nodep->v3fatalSrc("Array reference exceeds dimension of array");
911 frommsb = fromlsb = 0;
912 }
913 const int selwidth = V3Number::log2b(frommsb + 1 - 1) + 1; // Width to address a bit
914 AstNodeDType* const selwidthDTypep
915 = nodep->findLogicDType(selwidth, selwidth, nodep->bitp()->dtypep()->numeric());
916 if (widthBad(nodep->bitp(), selwidthDTypep) && nodep->bitp()->width() != 32) {
917 nodep->v3warn(WIDTH, "Bit extraction of array["
918 << frommsb << ":" << fromlsb << "] requires " << selwidth
919 << " bit index, not " << nodep->bitp()->width()
920 << (nodep->bitp()->width() != nodep->bitp()->widthMin()
921 ? " or " + cvtToStr(nodep->bitp()->widthMin())
922 : "")
923 << " bits.");
924 if (!nodep->fileline()->warnIsOff(V3ErrorCode::WIDTH)) {
925 UINFO(1, " Related node: " << nodep << endl);
926 UINFO(1, " Related dtype: " << nodep->dtypep() << endl);
927 }
928 }
929 if (!m_doGenerate) {
930 // Must check bounds before adding a select that truncates the bound
931 // Note we've already subtracted off LSB
932 if (VN_IS(nodep->bitp(), Const)
933 && (VN_AS(nodep->bitp(), Const)->toSInt() > (frommsb - fromlsb)
934 || VN_AS(nodep->bitp(), Const)->toSInt() < 0)) {
935 nodep->v3warn(SELRANGE,
936 "Selection index out of range: "
937 << (VN_AS(nodep->bitp(), Const)->toSInt() + fromlsb)
938 << " outside " << frommsb << ":" << fromlsb);
939 UINFO(1, " Related node: " << nodep << endl);
940 }
941 widthCheckSized(nodep, "Extract Range", nodep->bitp(), selwidthDTypep, EXTEND_EXP,
942 false /*NOWARN*/);
943 }
944 }
945 }
946
visit(AstAssocSel * nodep)947 virtual void visit(AstAssocSel* nodep) override {
948 // Signed/Real: Output type based on array-declared type; binary operator
949 if (m_vup->prelim()) {
950 const AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefp();
951 const AstAssocArrayDType* const adtypep = VN_CAST(fromDtp, AssocArrayDType);
952 if (!adtypep) {
953 UINFO(1, " Related dtype: " << fromDtp << endl);
954 nodep->v3fatalSrc("Associative array reference is not to associative array");
955 }
956 iterateCheckTyped(nodep, "Associative select", nodep->bitp(), adtypep->keyDTypep(),
957 BOTH);
958 nodep->dtypeFrom(adtypep->subDTypep());
959 }
960 }
961
visit(AstSliceSel * nodep)962 virtual void visit(AstSliceSel* nodep) override {
963 // Always creates as output an unpacked array
964 if (m_vup->prelim()) {
965 userIterateAndNext(nodep->fromp(), WidthVP(SELF, BOTH).p());
966 //
967 // Array indices are always constant
968 const AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefp();
969 const AstUnpackArrayDType* const adtypep = VN_CAST(fromDtp, UnpackArrayDType);
970 if (!adtypep) {
971 UINFO(1, " Related dtype: " << fromDtp << endl);
972 nodep->v3fatalSrc("Packed array reference exceeds dimension of array");
973 }
974 // Build new array Dtype based on the original's base type, but with new bounds
975 AstNodeDType* const newDtp
976 = new AstUnpackArrayDType(nodep->fileline(), adtypep->subDTypep(),
977 new AstRange(nodep->fileline(), nodep->declRange()));
978 v3Global.rootp()->typeTablep()->addTypesp(newDtp);
979 nodep->dtypeFrom(newDtp);
980
981 if (!m_doGenerate) {
982 // Must check bounds before adding a select that truncates the bound
983 // Note we've already subtracted off LSB
984 const int subtracted = adtypep->declRange().lo();
985 // Add subtracted value to get the original range
986 const VNumRange declRange{nodep->declRange().hi() + subtracted,
987 nodep->declRange().lo() + subtracted,
988 nodep->declRange().littleEndian()};
989 if ((declRange.hi() > adtypep->declRange().hi())
990 || declRange.lo() < adtypep->declRange().lo()) {
991 // Other simulators warn too
992 nodep->v3error("Slice selection index '" << declRange << "'"
993 << " outside data type's '"
994 << adtypep->declRange() << "'");
995 } else if ((declRange.littleEndian() != adtypep->declRange().littleEndian())
996 && declRange.hi() != declRange.lo()) {
997 nodep->v3error("Slice selection '"
998 << declRange << "'"
999 << " has backward indexing versus data type's '"
1000 << adtypep->declRange() << "'");
1001 }
1002 }
1003 }
1004 }
1005
visit(AstSelBit * nodep)1006 virtual void visit(AstSelBit* nodep) override {
1007 // Just a quick check as after V3Param these nodes instead are AstSel's
1008 userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1009 userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1010 userIterateAndNext(nodep->thsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1011 userIterateAndNext(nodep->attrp(), WidthVP(SELF, BOTH).p());
1012 AstNode* const selp = V3Width::widthSelNoIterEdit(nodep);
1013 if (selp != nodep) {
1014 nodep = nullptr;
1015 userIterate(selp, m_vup);
1016 return;
1017 }
1018 nodep->v3fatalSrc("AstSelBit should disappear after widthSel");
1019 }
visit(AstSelExtract * nodep)1020 virtual void visit(AstSelExtract* nodep) override {
1021 // Just a quick check as after V3Param these nodes instead are AstSel's
1022 userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1023 userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1024 userIterateAndNext(nodep->thsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1025 userIterateAndNext(nodep->attrp(), WidthVP(SELF, BOTH).p());
1026 AstNode* const selp = V3Width::widthSelNoIterEdit(nodep);
1027 if (selp != nodep) {
1028 nodep = nullptr;
1029 userIterate(selp, m_vup);
1030 return;
1031 }
1032 nodep->v3fatalSrc("AstSelExtract should disappear after widthSel");
1033 }
visit(AstSelPlus * nodep)1034 virtual void visit(AstSelPlus* nodep) override {
1035 userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1036 userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1037 userIterateAndNext(nodep->thsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1038 userIterateAndNext(nodep->attrp(), WidthVP(SELF, BOTH).p());
1039 AstNode* const selp = V3Width::widthSelNoIterEdit(nodep);
1040 if (selp != nodep) {
1041 nodep = nullptr;
1042 userIterate(selp, m_vup);
1043 return;
1044 }
1045 nodep->v3fatalSrc("AstSelPlus should disappear after widthSel");
1046 }
visit(AstSelMinus * nodep)1047 virtual void visit(AstSelMinus* nodep) override {
1048 userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1049 userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1050 userIterateAndNext(nodep->thsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel
1051 userIterateAndNext(nodep->attrp(), WidthVP(SELF, BOTH).p());
1052 AstNode* const selp = V3Width::widthSelNoIterEdit(nodep);
1053 if (selp != nodep) {
1054 nodep = nullptr;
1055 userIterate(selp, m_vup);
1056 return;
1057 }
1058 nodep->v3fatalSrc("AstSelMinus should disappear after widthSel");
1059 }
1060
visit(AstExtend * nodep)1061 virtual void visit(AstExtend* nodep) override {
1062 // Only created by this process, so we know width from here down is correct.
1063 }
visit(AstExtendS * nodep)1064 virtual void visit(AstExtendS* nodep) override {
1065 // Only created by this process, so we know width from here down is correct.
1066 }
visit(AstConst * nodep)1067 virtual void visit(AstConst* nodep) override {
1068 // The node got setup with the signed/real state of the node.
1069 // However a later operation may have changed the node->signed w/o changing
1070 // the number's sign. So we don't: nodep->dtypeChgSigned(nodep->num().isSigned());
1071 if (m_vup && m_vup->prelim()) {
1072 if (nodep->num().isString()) {
1073 nodep->dtypeSetString();
1074 } else if (nodep->num().sized()) {
1075 nodep->dtypeChgWidth(nodep->num().width(), nodep->num().width());
1076 } else {
1077 nodep->dtypeChgWidth(nodep->num().width(), nodep->num().widthMin());
1078 }
1079 }
1080 // We don't size the constant until we commit the widths, as need parameters
1081 // to remain unsized, and numbers to remain unsized to avoid backp() warnings
1082 }
visit(AstEmptyQueue * nodep)1083 virtual void visit(AstEmptyQueue* nodep) override {
1084 nodep->dtypeSetEmptyQueue();
1085 if (!VN_IS(nodep->backp(), Assign))
1086 nodep->v3warn(E_UNSUPPORTED,
1087 "Unsupported/Illegal: empty queue ('{}') in this context");
1088 }
visit(AstFell * nodep)1089 virtual void visit(AstFell* nodep) override {
1090 if (m_vup->prelim()) {
1091 iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
1092 nodep->dtypeSetBit();
1093 }
1094 }
visit(AstPast * nodep)1095 virtual void visit(AstPast* nodep) override {
1096 if (m_vup->prelim()) {
1097 iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
1098 nodep->dtypeFrom(nodep->exprp());
1099 if (nodep->ticksp()) {
1100 iterateCheckSizedSelf(nodep, "Ticks", nodep->ticksp(), SELF, BOTH);
1101 V3Const::constifyParamsEdit(nodep->ticksp()); // ticksp may change
1102 const AstConst* const constp = VN_CAST(nodep->ticksp(), Const);
1103 if (!constp) {
1104 nodep->v3error("$past tick value must be constant (IEEE 1800-2017 16.9.3)");
1105 nodep->ticksp()->unlinkFrBack()->deleteTree();
1106 } else if (constp->toSInt() < 1) {
1107 constp->v3error("$past tick value must be >= 1 (IEEE 1800-2017 16.9.3)");
1108 nodep->ticksp()->unlinkFrBack()->deleteTree();
1109 } else {
1110 if (constp->toSInt() > 10) {
1111 constp->v3warn(TICKCOUNT, "$past tick value of "
1112 << constp->toSInt()
1113 << " may have a large performance cost");
1114 }
1115 }
1116 }
1117 }
1118 }
visit(AstRose * nodep)1119 virtual void visit(AstRose* nodep) override {
1120 if (m_vup->prelim()) {
1121 iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
1122 nodep->dtypeSetBit();
1123 }
1124 }
1125
visit(AstSampled * nodep)1126 virtual void visit(AstSampled* nodep) override {
1127 if (m_vup->prelim()) {
1128 iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
1129 nodep->dtypeFrom(nodep->exprp());
1130 }
1131 }
1132
visit(AstStable * nodep)1133 virtual void visit(AstStable* nodep) override {
1134 if (m_vup->prelim()) {
1135 iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH);
1136 nodep->dtypeSetBit();
1137 }
1138 }
1139
visit(AstImplication * nodep)1140 virtual void visit(AstImplication* nodep) override {
1141 if (m_vup->prelim()) {
1142 iterateCheckBool(nodep, "LHS", nodep->lhsp(), BOTH);
1143 iterateCheckBool(nodep, "RHS", nodep->rhsp(), BOTH);
1144 nodep->dtypeSetBit();
1145 }
1146 }
1147
visit(AstRand * nodep)1148 virtual void visit(AstRand* nodep) override {
1149 if (m_vup->prelim()) {
1150 if (nodep->urandom()) {
1151 nodep->dtypeSetUInt32(); // Says the spec
1152 } else {
1153 nodep->dtypeSetSigned32(); // Says the spec
1154 }
1155 if (nodep->seedp()) iterateCheckSigned32(nodep, "seed", nodep->seedp(), BOTH);
1156 }
1157 }
visit(AstURandomRange * nodep)1158 virtual void visit(AstURandomRange* nodep) override {
1159 if (m_vup->prelim()) {
1160 nodep->dtypeSetUInt32(); // Says the spec
1161 AstNodeDType* const expDTypep = nodep->findUInt32DType();
1162 userIterateAndNext(nodep->lhsp(), WidthVP(CONTEXT, PRELIM).p());
1163 userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p());
1164 iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, expDTypep, EXTEND_EXP);
1165 iterateCheck(nodep, "RHS", nodep->rhsp(), SELF, FINAL, expDTypep, EXTEND_EXP);
1166 }
1167 }
visit(AstUnbounded * nodep)1168 virtual void visit(AstUnbounded* nodep) override {
1169 nodep->dtypeSetSigned32(); // Used in int context
1170 if (VN_IS(nodep->backp(), IsUnbounded)) return; // Ok, leave
1171 if (VN_IS(nodep->backp(), BracketArrayDType)) return; // Ok, leave
1172 if (const auto* const varp = VN_CAST(nodep->backp(), Var)) {
1173 if (varp->isParam()) return; // Ok, leave
1174 }
1175 // queue_slice[#:$]
1176 if (const auto* const selp = VN_CAST(nodep->backp(), SelExtract)) {
1177 if (VN_IS(selp->fromp()->dtypep(), QueueDType)) {
1178 nodep->replaceWith(
1179 new AstConst(nodep->fileline(), AstConst::Signed32(), 0x7FFFFFFF));
1180 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1181 return;
1182 }
1183 }
1184 nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context.");
1185 }
visit(AstIsUnbounded * nodep)1186 virtual void visit(AstIsUnbounded* nodep) override {
1187 if (m_vup->prelim()) {
1188 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
1189 nodep->dtypeSetBit();
1190 }
1191 }
visit(AstUCFunc * nodep)1192 virtual void visit(AstUCFunc* nodep) override {
1193 // Give it the size the user wants.
1194 if (m_vup && m_vup->prelim()) {
1195 nodep->dtypeSetLogicUnsized(32, 1, VSigning::UNSIGNED); // We don't care
1196 // All arguments seek their natural sizes
1197 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
1198 }
1199 if (m_vup->final()) {
1200 AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep());
1201 nodep->dtypeFrom(expDTypep); // Assume user knows the rules; go with the flow
1202 if (nodep->width() > 64) {
1203 nodep->v3warn(E_UNSUPPORTED, "Unsupported: $c can't generate wider than 64 bits");
1204 }
1205 }
1206 }
visit(AstCLog2 * nodep)1207 virtual void visit(AstCLog2* nodep) override {
1208 if (m_vup->prelim()) {
1209 iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
1210 nodep->dtypeSetSigned32();
1211 }
1212 }
visit(AstPow * nodep)1213 virtual void visit(AstPow* nodep) override {
1214 // Pow is special, output sign only depends on LHS sign, but
1215 // function result depends on both signs
1216 // RHS is self-determined (IEEE)
1217 // Real if either side is real (as with AstAdd)
1218 if (m_vup->prelim()) {
1219 userIterateAndNext(nodep->lhsp(), WidthVP(CONTEXT, PRELIM).p());
1220 userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p());
1221 if (nodep->lhsp()->isDouble() || nodep->rhsp()->isDouble()) {
1222 spliceCvtD(nodep->lhsp());
1223 spliceCvtD(nodep->rhsp());
1224 VL_DO_DANGLING(replaceWithDVersion(nodep), nodep);
1225 return;
1226 }
1227
1228 checkCvtUS(nodep->lhsp());
1229 iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
1230 nodep->dtypeFrom(nodep->lhsp());
1231 }
1232
1233 if (m_vup->final()) {
1234 AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep());
1235 nodep->dtypeFrom(expDTypep);
1236 // rhs already finalized in iterate_shift_prelim
1237 iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, nodep->dtypep(), EXTEND_EXP);
1238 AstNode* newp = nullptr; // No change
1239 if (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()) {
1240 newp = new AstPowSS(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
1241 nodep->rhsp()->unlinkFrBack());
1242 } else if (nodep->lhsp()->isSigned() && !nodep->rhsp()->isSigned()) {
1243 newp = new AstPowSU(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
1244 nodep->rhsp()->unlinkFrBack());
1245 } else if (!nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()) {
1246 newp = new AstPowUS(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
1247 nodep->rhsp()->unlinkFrBack());
1248 }
1249 if (newp) {
1250 newp->dtypeFrom(nodep);
1251 UINFO(9, "powOld " << nodep << endl);
1252 UINFO(9, "powNew " << newp << endl);
1253 VL_DO_DANGLING(nodep->replaceWith(newp), nodep);
1254 }
1255 }
1256 }
visit(AstPowSU * nodep)1257 virtual void visit(AstPowSU* nodep) override {
1258 // POWSU/SS/US only created here, dtype already determined, so
1259 // nothing to do in this function
1260 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
1261 userIterateAndNext(nodep->rhsp(), WidthVP(SELF, BOTH).p());
1262 }
visit(AstPowSS * nodep)1263 virtual void visit(AstPowSS* nodep) override {
1264 // POWSU/SS/US only created here, dtype already determined, so
1265 // nothing to do in this function
1266 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
1267 userIterateAndNext(nodep->rhsp(), WidthVP(SELF, BOTH).p());
1268 }
visit(AstPowUS * nodep)1269 virtual void visit(AstPowUS* nodep) override {
1270 // POWSU/SS/US only created here, dtype already determined, so
1271 // nothing to do in this function
1272 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
1273 userIterateAndNext(nodep->rhsp(), WidthVP(SELF, BOTH).p());
1274 }
visit(AstCountBits * nodep)1275 virtual void visit(AstCountBits* nodep) override {
1276 if (m_vup->prelim()) {
1277 iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
1278 iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
1279 iterateCheckSizedSelf(nodep, "THS", nodep->thsp(), SELF, BOTH);
1280 iterateCheckSizedSelf(nodep, "FHS", nodep->fhsp(), SELF, BOTH);
1281 // If it's a 32 bit number, we need a 6 bit number as we need to return '32'.
1282 const int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1;
1283 nodep->dtypeSetLogicSized(selwidth,
1284 VSigning::UNSIGNED); // Spec doesn't indicate if an integer
1285 }
1286 }
visit(AstCountOnes * nodep)1287 virtual void visit(AstCountOnes* nodep) override {
1288 if (m_vup->prelim()) {
1289 iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
1290 // If it's a 32 bit number, we need a 6 bit number as we need to return '32'.
1291 const int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1;
1292 nodep->dtypeSetLogicSized(selwidth,
1293 VSigning::UNSIGNED); // Spec doesn't indicate if an integer
1294 }
1295 }
visit(AstCvtPackString * nodep)1296 virtual void visit(AstCvtPackString* nodep) override {
1297 // Opaque returns, so arbitrary
1298 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
1299 // Type set in constructor
1300 }
visit(AstTimeImport * nodep)1301 virtual void visit(AstTimeImport* nodep) override {
1302 // LHS is a real number in seconds
1303 // Need to round to time units and precision
1304 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
1305 const AstConst* const constp = VN_CAST(nodep->lhsp(), Const);
1306 if (!constp || !constp->isDouble()) nodep->v3fatalSrc("Times should be doubles");
1307 if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time import no units");
1308 double time = constp->num().toDouble();
1309 if (v3Global.rootp()->timeprecision().isNone()) nodep->v3fatalSrc("Never set precision?");
1310 time /= nodep->timeunit().multiplier();
1311 // IEEE claims you should round to time precision here, but no simulator seems to do this
1312 AstConst* const newp = new AstConst(nodep->fileline(), AstConst::RealDouble(), time);
1313 nodep->replaceWith(newp);
1314 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1315 }
visit(AstTimingControl * nodep)1316 virtual void visit(AstTimingControl* nodep) override {
1317 nodep->v3warn(E_UNSUPPORTED, "Unsupported: timing control statement in this location\n"
1318 << nodep->warnMore()
1319 << "... Suggest have one timing control statement "
1320 << "per procedure, at the top of the procedure");
1321 VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
1322 }
visit(AstAttrOf * nodep)1323 virtual void visit(AstAttrOf* nodep) override {
1324 VL_RESTORER(m_attrp);
1325 m_attrp = nodep;
1326 userIterateAndNext(nodep->fromp(), WidthVP(SELF, BOTH).p());
1327 if (nodep->dimp()) userIterateAndNext(nodep->dimp(), WidthVP(SELF, BOTH).p());
1328 // Don't iterate children, don't want to lose VarRef.
1329 switch (nodep->attrType()) {
1330 case AstAttrType::VAR_BASE:
1331 case AstAttrType::MEMBER_BASE:
1332 case AstAttrType::ENUM_BASE:
1333 // Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf
1334 break;
1335 case AstAttrType::DIM_DIMENSIONS:
1336 case AstAttrType::DIM_UNPK_DIMENSIONS: {
1337 UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, "Unsized expression");
1338 const std::pair<uint32_t, uint32_t> dim = nodep->fromp()->dtypep()->dimensions(true);
1339 const int val = (nodep->attrType() == AstAttrType::DIM_UNPK_DIMENSIONS
1340 ? dim.second
1341 : (dim.first + dim.second));
1342 nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Signed32(), val));
1343 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1344 break;
1345 }
1346 case AstAttrType::DIM_BITS:
1347 case AstAttrType::DIM_HIGH:
1348 case AstAttrType::DIM_INCREMENT:
1349 case AstAttrType::DIM_LEFT:
1350 case AstAttrType::DIM_LOW:
1351 case AstAttrType::DIM_RIGHT:
1352 case AstAttrType::DIM_SIZE: {
1353 UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, "Unsized expression");
1354 AstNodeDType* const dtypep = nodep->fromp()->dtypep();
1355 if (VN_IS(dtypep, QueueDType)) {
1356 switch (nodep->attrType()) {
1357 case AstAttrType::DIM_SIZE: {
1358 AstNode* const newp = new AstCMethodHard(
1359 nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size", nullptr);
1360 newp->dtypeSetSigned32();
1361 newp->didWidth(true);
1362 newp->protect(false);
1363 nodep->replaceWith(newp);
1364 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1365 break;
1366 }
1367 case AstAttrType::DIM_LEFT:
1368 case AstAttrType::DIM_LOW: {
1369 AstNode* const newp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0);
1370 nodep->replaceWith(newp);
1371 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1372 break;
1373 }
1374 case AstAttrType::DIM_RIGHT:
1375 case AstAttrType::DIM_HIGH: {
1376 AstNode* const sizep = new AstCMethodHard(
1377 nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size", nullptr);
1378 sizep->dtypeSetSigned32();
1379 sizep->didWidth(true);
1380 sizep->protect(false);
1381 AstNode* const newp
1382 = new AstSub(nodep->fileline(), sizep,
1383 new AstConst(nodep->fileline(), AstConst::Signed32(), 1));
1384 nodep->replaceWith(newp);
1385 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1386 break;
1387 }
1388 case AstAttrType::DIM_INCREMENT: {
1389 AstNode* const newp
1390 = new AstConst(nodep->fileline(), AstConst::Signed32(), -1);
1391 nodep->replaceWith(newp);
1392 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1393 break;
1394 }
1395 case AstAttrType::DIM_BITS: {
1396 nodep->v3warn(E_UNSUPPORTED, "Unsupported: $bits for queue");
1397 break;
1398 }
1399 default: nodep->v3error("Unhandled attribute type");
1400 }
1401 } else {
1402 const std::pair<uint32_t, uint32_t> dimpair = dtypep->skipRefp()->dimensions(true);
1403 const uint32_t msbdim = dimpair.first + dimpair.second;
1404 if (!nodep->dimp() || msbdim < 1) {
1405 if (VN_IS(dtypep, BasicDType) && dtypep->basicp()->isString()) {
1406 // IEEE undocumented but $bits(string) must give length(string) * 8
1407 AstNode* const newp = new AstShiftL{
1408 nodep->fileline(),
1409 new AstLenN{nodep->fileline(), nodep->fromp()->unlinkFrBack()},
1410 new AstConst{nodep->fileline(), 3}, // * 8
1411 32};
1412 nodep->replaceWith(newp);
1413 VL_DO_DANGLING(pushDeletep(nodep), nodep);
1414 } else {
1415 const int dim = 1;
1416 AstConst* const newp
1417 = dimensionValue(nodep->fileline(), dtypep, nodep->attrType(), dim);
1418 nodep->replaceWith(newp);
1419 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1420 }
1421 } else if (VN_IS(nodep->dimp(), Const)) {
1422 const int dim = VN_AS(nodep->dimp(), Const)->toSInt();
1423 AstConst* const newp
1424 = dimensionValue(nodep->fileline(), dtypep, nodep->attrType(), dim);
1425 nodep->replaceWith(newp);
1426 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1427 } else { // Need a runtime lookup table. Yuk.
1428 UASSERT_OBJ(nodep->fromp() && dtypep, nodep, "Unsized expression");
1429 AstVar* const varp = dimensionVarp(dtypep, nodep->attrType(), msbdim);
1430 AstNode* const dimp = nodep->dimp()->unlinkFrBack();
1431 AstVarRef* const varrefp
1432 = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
1433 varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
1434 AstNode* const newp = new AstArraySel(nodep->fileline(), varrefp, dimp);
1435 nodep->replaceWith(newp);
1436 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1437 }
1438 }
1439 break;
1440 }
1441 case AstAttrType::TYPENAME: {
1442 UASSERT_OBJ(nodep->fromp(), nodep, "Unprovided expression");
1443 const string result = nodep->fromp()->dtypep()->prettyDTypeName();
1444 AstNode* const newp = new AstConst(nodep->fileline(), AstConst::String(), result);
1445 nodep->replaceWith(newp);
1446 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1447 break;
1448 }
1449 default: {
1450 // Everything else resolved earlier
1451 nodep->dtypeSetLogicUnsized(32, 1, VSigning::UNSIGNED); // Approximation, unsized 32
1452 UINFO(1, "Missing ATTR type case node: " << nodep << endl);
1453 nodep->v3fatalSrc("Missing ATTR type case");
1454 break;
1455 }
1456 }
1457 }
visit(AstPull * nodep)1458 virtual void visit(AstPull* nodep) override {
1459 // May have select underneath, let seek natural size
1460 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
1461 }
visit(AstText * nodep)1462 virtual void visit(AstText* nodep) override {
1463 // Only used in CStmts which don't care....
1464 }
1465
1466 // DTYPES
visit(AstNodeArrayDType * nodep)1467 virtual void visit(AstNodeArrayDType* nodep) override {
1468 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
1469
1470 if (nodep->subDTypep() == nodep->basicp()) { // Innermost dimension
1471 AstBasicDType* const basicp = nodep->basicp();
1472 // If basic dtype is LOGIC_IMPLICIT, it is actually 1 bit LOGIC
1473 if (basicp->implicit()) {
1474 UASSERT_OBJ(basicp->width() <= 1, basicp,
1475 "must be 1 bit but actually " << basicp->width() << " bits");
1476 AstBasicDType* const newp = new AstBasicDType(
1477 basicp->fileline(), AstBasicDTypeKwd::LOGIC, basicp->numeric());
1478 newp->widthForce(1, 1);
1479 basicp->replaceWith(newp);
1480 VL_DO_DANGLING(pushDeletep(basicp), basicp);
1481 }
1482 }
1483 // Iterate into subDTypep() to resolve that type and update pointer.
1484 nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
1485 // Cleanup array size
1486 userIterateAndNext(nodep->rangep(), WidthVP(SELF, BOTH).p());
1487 nodep->dtypep(nodep); // The array itself, not subDtype
1488 if (auto* const adtypep = VN_CAST(nodep, UnpackArrayDType)) {
1489 // Historically array elements have width of the ref type not the full array
1490 nodep->widthFromSub(nodep->subDTypep());
1491 if (nodep->subDTypep()->skipRefp()->isCompound()) adtypep->isCompound(true);
1492 } else {
1493 const int width = nodep->subDTypep()->width() * nodep->rangep()->elementsConst();
1494 nodep->widthForce(width, width);
1495 }
1496 UINFO(4, "dtWidthed " << nodep << endl);
1497 }
visit(AstAssocArrayDType * nodep)1498 virtual void visit(AstAssocArrayDType* nodep) override {
1499 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
1500 // Iterate into subDTypep() to resolve that type and update pointer.
1501 nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
1502 nodep->keyDTypep(iterateEditMoveDTypep(nodep, nodep->keyDTypep()));
1503 nodep->dtypep(nodep); // The array itself, not subDtype
1504 UINFO(4, "dtWidthed " << nodep << endl);
1505 }
visit(AstBracketArrayDType * nodep)1506 virtual void visit(AstBracketArrayDType* nodep) override {
1507 // Type inserted only because parser didn't know elementsp() type
1508 // Resolve elementsp's type
1509 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
1510 // We must edit when dtype still under normal nodes and before type table
1511 // See notes in iterateEditMoveDTypep
1512 AstNodeDType* const childp = nodep->childDTypep();
1513 childp->unlinkFrBack();
1514 AstNode* const elementsp = nodep->elementsp()->unlinkFrBack();
1515 AstNode* newp;
1516 if (VN_IS(elementsp, Unbounded)) {
1517 newp = new AstQueueDType(nodep->fileline(), VFlagChildDType(), childp, nullptr);
1518 VL_DO_DANGLING(elementsp->deleteTree(), elementsp);
1519 } else if (AstNodeDType* const keyp = VN_CAST(elementsp, NodeDType)) {
1520 newp = new AstAssocArrayDType(nodep->fileline(), VFlagChildDType(), childp, keyp);
1521 } else {
1522 // Must be expression that is constant, but we'll determine that later
1523 newp = new AstUnpackArrayDType(
1524 nodep->fileline(), VFlagChildDType(), childp,
1525 new AstRange(nodep->fileline(), new AstConst(elementsp->fileline(), 0),
1526 new AstSub(elementsp->fileline(), elementsp,
1527 new AstConst(elementsp->fileline(), 1))));
1528 }
1529 nodep->replaceWith(newp);
1530 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1531 // Normally parent's iteration would cover this, but we might have entered by a specific
1532 // visit
1533 VL_DO_DANGLING(userIterate(newp, nullptr), newp);
1534 }
visit(AstDynArrayDType * nodep)1535 virtual void visit(AstDynArrayDType* nodep) override {
1536 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
1537 // Iterate into subDTypep() to resolve that type and update pointer.
1538 nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
1539 nodep->dtypep(nodep); // The array itself, not subDtype
1540 UINFO(4, "dtWidthed " << nodep << endl);
1541 }
visit(AstQueueDType * nodep)1542 virtual void visit(AstQueueDType* nodep) override {
1543 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
1544 // Iterate into subDTypep() to resolve that type and update pointer.
1545 nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
1546 nodep->dtypep(nodep); // The array itself, not subDtype
1547 if (VN_IS(nodep->boundp(), Unbounded)) {
1548 nodep->boundp()->unlinkFrBack()->deleteTree(); // nullptr will represent unbounded
1549 }
1550 UINFO(4, "dtWidthed " << nodep << endl);
1551 }
visit(AstVoidDType * nodep)1552 virtual void visit(AstVoidDType* nodep) override {
1553 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
1554 nodep->dtypep(nodep);
1555 UINFO(4, "dtWidthed " << nodep << endl);
1556 }
visit(AstUnsizedArrayDType * nodep)1557 virtual void visit(AstUnsizedArrayDType* nodep) override {
1558 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
1559 // Iterate into subDTypep() to resolve that type and update pointer.
1560 nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
1561 // Cleanup array size
1562 nodep->dtypep(nodep); // The array itself, not subDtype
1563 UINFO(4, "dtWidthed " << nodep << endl);
1564 }
visit(AstBasicDType * nodep)1565 virtual void visit(AstBasicDType* nodep) override {
1566 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
1567 if (nodep->generic()) return; // Already perfect
1568 if (nodep->rangep()) {
1569 userIterateAndNext(nodep->rangep(), WidthVP(SELF, BOTH).p());
1570 // Because this DType has a unique child range, we know it's not
1571 // pointed at by other nodes unless they are referencing this type.
1572 // Furthermore the width() calculation would return identical
1573 // values. Therefore we can directly replace the width
1574 nodep->widthForce(nodep->rangep()->elementsConst(), nodep->rangep()->elementsConst());
1575 } else if (nodep->isRanged()) {
1576 nodep->widthForce(nodep->nrange().elements(), nodep->nrange().elements());
1577 } else if (nodep->implicit()) {
1578 // Parameters may notice implicitness and change to different dtype
1579 nodep->widthForce(1, 1);
1580 }
1581 // else width in node is correct; it was set based on keyword().width()
1582 // at construction time. Ditto signed, so "unsigned byte" etc works right.
1583 nodep->cvtRangeConst();
1584 // TODO: If BasicDType now looks like a generic type, we can convert to a real generic
1585 // dtype Instead for now doing this in V3WidthCommit
1586 UINFO(4, "dtWidthed " << nodep << endl);
1587 }
visit(AstConstDType * nodep)1588 virtual void visit(AstConstDType* nodep) override {
1589 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
1590 // Iterate into subDTypep() to resolve that type and update pointer.
1591 nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
1592 userIterateChildren(nodep, nullptr);
1593 nodep->dtypep(nodep); // Should already be set, but be clear it's not the subDType
1594 nodep->widthFromSub(nodep->subDTypep());
1595 UINFO(4, "dtWidthed " << nodep << endl);
1596 }
visit(AstRefDType * nodep)1597 virtual void visit(AstRefDType* nodep) override {
1598 if (nodep->doingWidth()) { // Early exit if have circular parameter definition
1599 nodep->v3error("Typedef's type is circular: " << nodep->prettyName());
1600 nodep->dtypeSetBit();
1601 nodep->doingWidth(false);
1602 return;
1603 }
1604 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
1605 nodep->doingWidth(true);
1606 if (nodep->typeofp()) { // type(typeofp_expression)
1607 // Type comes from expression's type
1608 userIterateAndNext(nodep->typeofp(), WidthVP(SELF, BOTH).p());
1609 AstNode* const typeofp = nodep->typeofp();
1610 nodep->typedefp(nullptr);
1611 nodep->refDTypep(typeofp->dtypep());
1612 VL_DO_DANGLING(typeofp->unlinkFrBack()->deleteTree(), typeofp);
1613 // We had to use AstRefDType for this construct as pointers to this type
1614 // in type table are still correct (which they wouldn't be if we replaced the node)
1615 }
1616 userIterateChildren(nodep, nullptr);
1617 if (nodep->subDTypep()) {
1618 // Normally iterateEditMoveDTypep iterate would work, but the refs are under
1619 // the TypeDef which will upset iterateEditMoveDTypep as it can't find it under
1620 // this node's childDTypep
1621 userIterate(nodep->subDTypep(), nullptr);
1622 nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
1623 nodep->typedefp(nullptr); // Note until line above subDTypep() may have followed this
1624 // Widths are resolved, but special iterate to check for recurstion
1625 userIterate(nodep->subDTypep(), nullptr);
1626 }
1627 // Effectively nodep->dtypeFrom(nodep->dtypeSkipRefp());
1628 // But might be recursive, so instead manually recurse into the referenced type
1629 UASSERT_OBJ(nodep->subDTypep(), nodep, "Unlinked");
1630 nodep->dtypeFrom(nodep->subDTypep());
1631 nodep->widthFromSub(nodep->subDTypep());
1632 UINFO(4, "dtWidthed " << nodep << endl);
1633 nodep->doingWidth(false);
1634 }
visit(AstTypedef * nodep)1635 virtual void visit(AstTypedef* nodep) override {
1636 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
1637 if (auto* const refp = checkRefToTypedefRecurse(nodep, nodep)) {
1638 nodep->v3error("Typedef has self-reference: " << nodep->prettyNameQ() << '\n'
1639 << nodep->warnContextPrimary() << '\n'
1640 << refp->warnOther()
1641 << "... Location of reference\n"
1642 << refp->warnContextSecondary());
1643 // May cause internel error but avoids infinite loop on dump
1644 refp->typedefp(nullptr);
1645 VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
1646 return;
1647 }
1648 nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
1649 userIterateChildren(nodep, nullptr);
1650 }
visit(AstParamTypeDType * nodep)1651 virtual void visit(AstParamTypeDType* nodep) override {
1652 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
1653 nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
1654 userIterateChildren(nodep, nullptr);
1655 nodep->widthFromSub(nodep->subDTypep());
1656 }
visit(AstCastDynamic * nodep)1657 virtual void visit(AstCastDynamic* nodep) override {
1658 nodep->dtypeChgWidthSigned(32, 1, VSigning::SIGNED); // Spec says integer return
1659 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
1660 AstNodeDType* const toDtp = nodep->top()->dtypep()->skipRefToEnump();
1661 AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
1662 FileLine* const fl = nodep->fileline();
1663 const auto castable = computeCastable(toDtp, fromDtp, nodep->fromp());
1664 AstNode* newp;
1665 if (castable == DYNAMIC_CLASS) {
1666 // Keep in place, will compute at runtime
1667 return;
1668 } else if (castable == DYNAMIC_ENUM) {
1669 // TODO is from is a constant we could simplify, though normal constant
1670 // elimination should do much the same
1671 // Form: "( ((v > size) ? false : enum_valid[v[N:0]])
1672 // ? ExprStmt(ExprAssign(out, Cast(v, type)), 1) : 0)"
1673 auto* const enumDtp = VN_AS(toDtp, EnumDType);
1674 UASSERT_OBJ(enumDtp, nodep, "$cast determined as enum, but not enum type");
1675 const uint64_t maxval = enumMaxValue(nodep, enumDtp);
1676 const int selwidth = V3Number::log2b(maxval) + 1; // Width to address a bit
1677 AstVar* const varp
1678 = enumVarp(enumDtp, AstAttrType::ENUM_VALID, (1ULL << selwidth) - 1);
1679 AstVarRef* const varrefp = new AstVarRef(fl, varp, VAccess::READ);
1680 varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
1681 FileLine* const fl_nowarn = new FileLine(fl);
1682 fl_nowarn->warnOff(V3ErrorCode::WIDTH, true);
1683 auto* const testp = new AstCond{
1684 fl,
1685 new AstGt{fl_nowarn, nodep->fromp()->cloneTree(false),
1686 new AstConst{fl_nowarn, AstConst::Unsized64{}, maxval}},
1687 new AstConst{fl, AstConst::BitFalse{}},
1688 new AstArraySel{fl, varrefp,
1689 new AstSel{fl, nodep->fromp()->cloneTree(false), 0, selwidth}}};
1690 newp = new AstCond{fl, testp,
1691 new AstExprStmt{fl,
1692 new AstAssign{fl, nodep->top()->unlinkFrBack(),
1693 nodep->fromp()->unlinkFrBack()},
1694 new AstConst{fl, AstConst::Signed32(), 1}},
1695 new AstConst{fl, AstConst::Signed32(), 0}};
1696 } else if (castable == COMPATIBLE) {
1697 nodep->v3warn(CASTCONST, "$cast will always return one as "
1698 << toDtp->prettyDTypeNameQ()
1699 << " is always castable from "
1700 << fromDtp->prettyDTypeNameQ() << '\n'
1701 << nodep->warnMore() << "... Suggest static cast");
1702 newp = new AstExprStmt{
1703 fl,
1704 new AstAssign{fl, nodep->top()->unlinkFrBack(),
1705 new AstCast{fl, nodep->fromp()->unlinkFrBack(), toDtp}},
1706 new AstConst{fl, AstConst::Signed32(), 1}};
1707 } else if (castable == INCOMPATIBLE) {
1708 newp = new AstConst{fl, 0};
1709 nodep->v3warn(CASTCONST, "$cast will always return zero as "
1710 << toDtp->prettyDTypeNameQ() << " is not castable from "
1711 << fromDtp->prettyDTypeNameQ());
1712 } else {
1713 newp = new AstConst{fl, 0};
1714 nodep->v3warn(E_UNSUPPORTED, "Unsupported: $cast to "
1715 << toDtp->prettyDTypeNameQ() << " from "
1716 << fromDtp->prettyDTypeNameQ() << '\n'
1717 << nodep->warnMore()
1718 << "... Suggest try static cast");
1719 }
1720 newp->dtypeFrom(nodep);
1721 nodep->replaceWith(newp);
1722 VL_DO_DANGLING(pushDeletep(nodep), nodep);
1723 userIterate(newp, m_vup);
1724 }
visit(AstCastParse * nodep)1725 virtual void visit(AstCastParse* nodep) override {
1726 // nodep->dtp could be data type, or a primary_constant
1727 // Don't iterate lhsp, will deal with that once convert the type
1728 V3Const::constifyParamsEdit(nodep->dtp()); // itemp may change
1729 if (AstConst* const constp = VN_CAST(nodep->dtp(), Const)) {
1730 constp->unlinkFrBack();
1731 AstNode* const newp
1732 = new AstCastSize(nodep->fileline(), nodep->lhsp()->unlinkFrBack(), constp);
1733 nodep->replaceWith(newp);
1734 VL_DO_DANGLING(pushDeletep(nodep), nodep);
1735 userIterate(newp, m_vup);
1736 } else {
1737 nodep->v3warn(E_UNSUPPORTED,
1738 "Unsupported: Cast to " << nodep->dtp()->prettyTypeName());
1739 nodep->replaceWith(nodep->lhsp()->unlinkFrBack());
1740 }
1741 }
visit(AstCast * nodep)1742 virtual void visit(AstCast* nodep) override {
1743 nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
1744 if (m_vup->prelim()) {
1745 // if (debug()) nodep->dumpTree(cout, " CastPre: ");
1746 userIterateAndNext(nodep->fromp(), WidthVP(SELF, PRELIM).p());
1747 AstNodeDType* const toDtp = nodep->dtypep()->skipRefToEnump();
1748 AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
1749 const auto castable = computeCastable(toDtp, fromDtp, nodep->fromp());
1750 bool bad = false;
1751 if (castable == UNSUPPORTED) {
1752 nodep->v3warn(E_UNSUPPORTED, "Unsupported: static cast to "
1753 << toDtp->prettyDTypeNameQ() << " from "
1754 << fromDtp->prettyDTypeNameQ());
1755 bad = true;
1756 } else if (castable == COMPATIBLE || castable == DYNAMIC_ENUM) {
1757 ; // Continue
1758 } else if (castable == DYNAMIC_CLASS) {
1759 nodep->v3error("Dynamic, not static cast, required to cast "
1760 << toDtp->prettyDTypeNameQ() << " from "
1761 << fromDtp->prettyDTypeNameQ() << '\n'
1762 << nodep->warnMore() << "... Suggest dynamic $cast");
1763 bad = true;
1764 } else if (castable == INCOMPATIBLE) {
1765 nodep->v3error("Incompatible types to static cast to "
1766 << toDtp->prettyDTypeNameQ() << " from "
1767 << fromDtp->prettyDTypeNameQ() << '\n');
1768 bad = true;
1769 } else {
1770 nodep->v3fatalSrc("bad casting case");
1771 }
1772 // For now, replace it ASAP, so widthing can propagate easily
1773 // The cast may change signing, but we don't know the sign yet. Make it so.
1774 // Note we don't sign fromp() that would make the algorithm O(n^2) if lots of casting.
1775 AstNode* newp = nullptr;
1776 if (bad) {
1777 } else if (const AstBasicDType* const basicp = toDtp->basicp()) {
1778 if (!basicp->isDouble() && !fromDtp->isDouble()) {
1779 const int width = toDtp->width();
1780 castSized(nodep, nodep->fromp(), width);
1781 // Note castSized might modify nodep->fromp()
1782 } else {
1783 iterateCheck(nodep, "value", nodep->lhsp(), SELF, FINAL, fromDtp, EXTEND_EXP,
1784 false);
1785 }
1786 if (basicp->isDouble() && !nodep->fromp()->isDouble()) {
1787 if (nodep->fromp()->isSigned()) {
1788 newp = new AstISToRD(nodep->fileline(), nodep->fromp()->unlinkFrBack());
1789 } else {
1790 newp = new AstIToRD(nodep->fileline(), nodep->fromp()->unlinkFrBack());
1791 }
1792 } else if (!basicp->isDouble() && nodep->fromp()->isDouble()) {
1793 if (basicp->isSigned()) {
1794 newp
1795 = new AstRToIRoundS(nodep->fileline(), nodep->fromp()->unlinkFrBack());
1796 } else {
1797 newp = new AstUnsigned(
1798 nodep->fileline(),
1799 new AstRToIS(nodep->fileline(), nodep->fromp()->unlinkFrBack()));
1800 }
1801 } else if (basicp->isSigned() && !nodep->fromp()->isSigned()) {
1802 newp = new AstSigned(nodep->fileline(), nodep->fromp()->unlinkFrBack());
1803 } else if (!basicp->isSigned() && nodep->fromp()->isSigned()) {
1804 newp = new AstUnsigned(nodep->fileline(), nodep->fromp()->unlinkFrBack());
1805 } else {
1806 // Can just remove cast
1807 }
1808 } else if (VN_IS(toDtp, ClassRefDType)) {
1809 // Can just remove cast
1810 } else {
1811 nodep->v3fatalSrc("Unimplemented: Casting non-simple data type "
1812 << toDtp->prettyDTypeNameQ());
1813 }
1814 if (!newp) newp = nodep->fromp()->unlinkFrBack();
1815 nodep->lhsp(newp);
1816 // if (debug()) nodep->dumpTree(cout, " CastOut: ");
1817 // if (debug()) nodep->backp()->dumpTree(cout, " CastOutUpUp: ");
1818 }
1819 if (m_vup->final()) {
1820 iterateCheck(nodep, "value", nodep->lhsp(), SELF, FINAL, nodep->lhsp()->dtypep(),
1821 EXTEND_EXP, false);
1822 AstNode* const underp = nodep->lhsp()->unlinkFrBack();
1823 // if (debug()) underp->dumpTree(cout, " CastRep: ");
1824 nodep->replaceWith(underp);
1825 VL_DO_DANGLING(pushDeletep(nodep), nodep);
1826 }
1827 }
visit(AstCastSize * nodep)1828 virtual void visit(AstCastSize* nodep) override {
1829 // IEEE: Signedness of result is same as self-determined signedness
1830 // However, the result is same as BITSEL, so we do not sign extend the LHS
1831 UASSERT_OBJ(VN_IS(nodep->rhsp(), Const), nodep, "Unsupported: Non-const cast of size");
1832 // if (debug()) nodep->dumpTree(cout, " CastSizePre: ");
1833 if (m_vup->prelim()) {
1834 int width = VN_AS(nodep->rhsp(), Const)->toSInt();
1835 if (width < 1) {
1836 nodep->v3error("Size-changing cast to zero or negative size");
1837 width = 1;
1838 }
1839 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p());
1840 castSized(nodep, nodep->lhsp(), width); // lhsp may change
1841 }
1842 if (m_vup->final()) {
1843 // CastSize not needed once sizes determined
1844 AstNode* const underp = nodep->lhsp()->unlinkFrBack();
1845 underp->dtypeFrom(nodep);
1846 nodep->replaceWith(underp);
1847 VL_DO_DANGLING(pushDeletep(nodep), nodep);
1848 }
1849 // if (debug()) nodep->dumpTree(cout, " CastSizeOut: ");
1850 }
castSized(AstNode * nodep,AstNode * underp,int width)1851 void castSized(AstNode* nodep, AstNode* underp, int width) {
1852 const AstBasicDType* underDtp = VN_CAST(underp->dtypep(), BasicDType);
1853 if (!underDtp) underDtp = underp->dtypep()->basicp();
1854 if (!underDtp) {
1855 nodep->v3warn(E_UNSUPPORTED, "Unsupported: Size-changing cast on non-basic data type");
1856 underDtp = VN_AS(nodep->findBitDType(), BasicDType);
1857 }
1858 UASSERT_OBJ(underp == nodep->op1p(), nodep, "Assuming op1 is cast value");
1859 // A cast propagates its size to the lower expression and is included in the maximum
1860 // width, so 23'(1'b1 + 1'b1) uses 23-bit math, but 1'(2'h2 * 2'h1) uses two-bit math.
1861 // However the output width is exactly that requested.
1862 // So two steps, first do the calculation's width (max of the two widths)
1863 {
1864 const int calcWidth = std::max(width, underDtp->width());
1865 AstNodeDType* const calcDtp
1866 = (underDtp->isFourstate()
1867 ? nodep->findLogicDType(calcWidth, calcWidth, underDtp->numeric())
1868 : nodep->findBitDType(calcWidth, calcWidth, underDtp->numeric()));
1869 nodep->dtypep(calcDtp);
1870 // We ignore warnings as that is sort of the point of a cast
1871 iterateCheck(nodep, "Cast expr", underp, CONTEXT, FINAL, calcDtp, EXTEND_EXP, false);
1872 VL_DANGLING(underp);
1873 underp = nodep->op1p(); // Above asserts that op1 was underp pre-relink
1874 }
1875 // if (debug()) nodep->dumpTree(cout, " CastSizeClc: ");
1876 // Next step, make the proper output width
1877 {
1878 AstNodeDType* const outDtp
1879 = (underDtp->isFourstate()
1880 ? nodep->findLogicDType(width, width, underDtp->numeric())
1881 : nodep->findBitDType(width, width, underDtp->numeric()));
1882 nodep->dtypep(outDtp);
1883 // We ignore warnings as that is sort of the point of a cast
1884 widthCheckSized(nodep, "Cast expr", underp, outDtp, EXTEND_EXP, false);
1885 VL_DANGLING(underp);
1886 }
1887 }
visit(AstVar * nodep)1888 virtual void visit(AstVar* nodep) override {
1889 // if (debug()) nodep->dumpTree(cout, " InitPre: ");
1890 // Must have deterministic constant width
1891 // We can't skip this step when width()!=0, as creating a AstVar
1892 // with non-constant range gets size 1, not size 0. So use didWidth().
1893 if (nodep->didWidth()) return;
1894 if (nodep->doingWidth()) { // Early exit if have circular parameter definition
1895 UASSERT_OBJ(nodep->valuep(), nodep, "circular, but without value");
1896 nodep->v3error("Variable's initial value is circular: " << nodep->prettyNameQ());
1897 pushDeletep(nodep->valuep()->unlinkFrBack());
1898 nodep->valuep(new AstConst(nodep->fileline(), AstConst::BitTrue()));
1899 nodep->dtypeFrom(nodep->valuep());
1900 nodep->didWidth(true);
1901 return;
1902 }
1903 nodep->doingWidth(true);
1904 // Make sure dtype is sized
1905 nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
1906 UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype determined for var");
1907 if (const AstUnsizedArrayDType* const unsizedp
1908 = VN_CAST(nodep->dtypeSkipRefp(), UnsizedArrayDType)) {
1909 if (!(m_ftaskp && m_ftaskp->dpiImport())) {
1910 UINFO(9, "Unsized becomes dynamic array " << nodep << endl);
1911 AstDynArrayDType* const newp
1912 = new AstDynArrayDType(unsizedp->fileline(), unsizedp->subDTypep());
1913 nodep->dtypep(newp);
1914 v3Global.rootp()->typeTablep()->addTypesp(newp);
1915 }
1916 }
1917 if (VN_IS(nodep->dtypep()->skipRefToConstp(), ConstDType)) nodep->isConst(true);
1918 // Parameters if implicit untyped inherit from what they are assigned to
1919 const AstBasicDType* const bdtypep = VN_CAST(nodep->dtypep(), BasicDType);
1920 bool didchk = false;
1921 const bool implicitParam = nodep->isParam() && bdtypep && bdtypep->implicit();
1922 if (implicitParam) {
1923 if (nodep->valuep()) {
1924 userIterateAndNext(nodep->valuep(), WidthVP(nodep->dtypep(), PRELIM).p());
1925 UINFO(9, "implicitParamPRELIMIV " << nodep->valuep() << endl);
1926 // Although nodep will get a different width for parameters
1927 // just below, we want the init numbers to retain their
1928 // width/minwidth until parameters are replaced.
1929 // This prevents width warnings at the location the parameter is substituted in
1930 if (nodep->valuep()->isDouble()) {
1931 nodep->dtypeSetDouble();
1932 VL_DANGLING(bdtypep);
1933 } else {
1934 int width = 0;
1935 const AstBasicDType* const valueBdtypep = nodep->valuep()->dtypep()->basicp();
1936 bool issigned = false;
1937 if (bdtypep->isNosign()) {
1938 if (valueBdtypep && valueBdtypep->isSigned()) issigned = true;
1939 } else {
1940 issigned = bdtypep->isSigned();
1941 }
1942 if (valueBdtypep->isString()) {
1943 // parameter X = "str", per IEEE is a number, not a string
1944 if (const auto* const constp = VN_CAST(nodep->valuep(), Const)) {
1945 if (constp->num().isString()) {
1946 width = constp->num().toString().length() * 8;
1947 }
1948 }
1949 if (width < 8) width = 8;
1950 } else if (nodep->valuep()->dtypep()->widthSized()) {
1951 width = nodep->valuep()->width();
1952 } else {
1953 if (nodep->valuep()->width() > 32) {
1954 nodep->valuep()->v3warn(
1955 WIDTH,
1956 "Assigning >32 bit to unranged parameter (defaults to 32 bits)");
1957 }
1958 width = 32;
1959 }
1960 // Can't just inherit valuep()->dtypep() as mwidth might not equal width
1961 if (width == 1) {
1962 // one bit parameter is same as "parameter [0] foo",
1963 // not "parameter logic foo" as you can extract
1964 // "foo[0]" from a parameter but not a wire
1965 nodep->dtypeChgWidthSigned(width, nodep->valuep()->widthMin(),
1966 VSigning::fromBool(issigned));
1967 nodep->dtypep(nodep->findLogicRangeDType(VNumRange{0, 0},
1968 nodep->valuep()->widthMin(),
1969 VSigning::fromBool(issigned)));
1970 } else {
1971 nodep->dtypeChgWidthSigned(width, nodep->valuep()->widthMin(),
1972 VSigning::fromBool(issigned));
1973 }
1974 didchk = true;
1975 }
1976 iterateCheckAssign(nodep, "Initial value", nodep->valuep(), FINAL,
1977 nodep->dtypep());
1978 UINFO(9, "implicitParamFromIV " << nodep->valuep() << endl);
1979 // UINFO below will print variable nodep
1980 } else {
1981 // Or, if nothing assigned, they're integral
1982 nodep->dtypeSetSigned32();
1983 VL_DANGLING(bdtypep);
1984 }
1985 } else if (bdtypep && bdtypep->implicit()) { // Implicits get converted to size 1
1986 nodep->dtypeSetLogicSized(1, bdtypep->numeric());
1987 VL_DANGLING(bdtypep);
1988 }
1989 if (nodep->valuep() && !didchk) {
1990 // if (debug()) nodep->dumpTree(cout, " final: ");
1991 // AstPattern requires assignments to pass datatype on PRELIM
1992 userIterateAndNext(nodep->valuep(), WidthVP(nodep->dtypep(), PRELIM).p());
1993 iterateCheckAssign(nodep, "Initial value", nodep->valuep(), FINAL, nodep->dtypep());
1994 }
1995 UINFO(4, "varWidthed " << nodep << endl);
1996 // if (debug()) nodep->dumpTree(cout, " InitOut: ");
1997 nodep->didWidth(true);
1998 nodep->doingWidth(false);
1999 }
visit(AstNodeVarRef * nodep)2000 virtual void visit(AstNodeVarRef* nodep) override {
2001 if (nodep->didWidth()) return;
2002 if (!nodep->varp()) {
2003 if (m_paramsOnly && VN_IS(nodep, VarXRef)) {
2004 checkConstantOrReplace(
2005 nodep, "Parameter-resolved constants must not use dotted references: "
2006 + nodep->prettyNameQ());
2007 VL_DANGLING(nodep);
2008 return;
2009 } else {
2010 nodep->v3fatalSrc("Unlinked varref");
2011 }
2012 }
2013 if (!nodep->varp()->didWidth()) {
2014 // Var hasn't been widthed, so make it so.
2015 userIterate(nodep->varp(), nullptr);
2016 }
2017 // if (debug()>=9) { nodep->dumpTree(cout, " VRin ");
2018 // nodep->varp()->dumpTree(cout, " forvar "); }
2019 // Note genvar's are also entered as integers
2020 nodep->dtypeFrom(nodep->varp());
2021 if (VN_IS(nodep->backp(), NodeAssign) && nodep->access().isWriteOrRW()) { // On LHS
2022 UASSERT_OBJ(nodep->dtypep(), nodep, "LHS var should be dtype completed");
2023 }
2024 // if (debug() >= 9) nodep->dumpTree(cout, " VRout ");
2025 if (nodep->access().isWriteOrRW() && nodep->varp()->direction() == VDirection::CONSTREF) {
2026 nodep->v3error("Assigning to const ref variable: " << nodep->prettyNameQ());
2027 } else if (nodep->access().isWriteOrRW() && nodep->varp()->isConst() && !m_paramsOnly
2028 && (!m_ftaskp || !m_ftaskp->isConstructor()) && !VN_IS(m_procedurep, Initial)) {
2029 // Too loose, but need to allow our generated first assignment
2030 // Move this to a property of the AstInitial block
2031 nodep->v3error("Assigning to const variable: " << nodep->prettyNameQ());
2032 }
2033 nodep->didWidth(true);
2034 }
2035
visit(AstEnumDType * nodep)2036 virtual void visit(AstEnumDType* nodep) override {
2037 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
2038 UINFO(5, " ENUMDTYPE " << nodep << endl);
2039 nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
2040 nodep->dtypep(nodep);
2041 nodep->widthFromSub(nodep->subDTypep());
2042 // Assign widths
2043 userIterateAndNext(nodep->itemsp(), WidthVP(nodep->dtypep(), BOTH).p());
2044 // Assign missing values
2045 V3Number num(nodep, nodep->width(), 0);
2046 const V3Number one{nodep, nodep->width(), 1};
2047 std::map<const V3Number, AstEnumItem*> inits;
2048 for (AstEnumItem* itemp = nodep->itemsp(); itemp;
2049 itemp = VN_AS(itemp->nextp(), EnumItem)) {
2050 if (itemp->valuep()) {
2051 if (debug() >= 9) {
2052 UINFO(0, "EnumInit " << itemp << endl);
2053 itemp->valuep()->dumpTree(cout, "-EnumInit: ");
2054 }
2055 V3Const::constifyParamsEdit(itemp->valuep()); // itemp may change
2056 if (!VN_IS(itemp->valuep(), Const)) {
2057 itemp->valuep()->v3error("Enum value isn't a constant");
2058 itemp->valuep()->unlinkFrBack()->deleteTree();
2059 continue;
2060 }
2061 // TODO IEEE says assigning sized number that is not same size as enum is illegal
2062 }
2063 if (!itemp->valuep()) {
2064 if (num.isEqZero() && itemp != nodep->itemsp()) {
2065 itemp->v3error("Enum value illegally wrapped around (IEEE 1800-2017 6.19)");
2066 }
2067 if (num.isFourState()) {
2068 itemp->v3error("Enum value that is unassigned cannot follow value with X/Zs "
2069 "(IEEE 1800-2017 6.19)");
2070 }
2071 if (!nodep->dtypep()->basicp()
2072 && !nodep->dtypep()->basicp()->keyword().isIntNumeric()) {
2073 itemp->v3error("Enum names without values only allowed on numeric types");
2074 // as can't +1 to resolve them.
2075 }
2076 itemp->valuep(new AstConst(itemp->fileline(), num));
2077 }
2078
2079 const AstConst* const constp = VN_AS(itemp->valuep(), Const);
2080 if (constp->num().isFourState() && nodep->dtypep()->basicp()
2081 && !nodep->dtypep()->basicp()->isFourstate()) {
2082 itemp->v3error("Enum value with X/Zs cannot be assigned to non-fourstate type "
2083 "(IEEE 1800-2017 6.19)");
2084 }
2085 num.opAssign(constp->num());
2086 // Look for duplicates
2087 if (inits.find(num) != inits.end()) { // IEEE says illegal
2088 const AstNode* const otherp = inits.find(num)->second;
2089 itemp->v3error("Overlapping enumeration value: "
2090 << itemp->prettyNameQ() << '\n'
2091 << itemp->warnContextPrimary() << '\n'
2092 << otherp->warnOther() << "... Location of original declaration\n"
2093 << otherp->warnContextSecondary());
2094 } else {
2095 inits.emplace(num, itemp);
2096 }
2097 num.opAdd(one, constp->num());
2098 }
2099 }
visit(AstEnumItem * nodep)2100 virtual void visit(AstEnumItem* nodep) override {
2101 UINFO(5, " ENUMITEM " << nodep << endl);
2102 AstNodeDType* const vdtypep = m_vup->dtypep();
2103 UASSERT_OBJ(vdtypep, nodep, "ENUMITEM not under ENUM");
2104 nodep->dtypep(vdtypep);
2105 if (nodep->valuep()) { // else the value will be assigned sequentially
2106 // Default type is int, but common to assign narrower values, so minwidth from value
2107 userIterateAndNext(nodep->valuep(), WidthVP(CONTEXT, PRELIM).p());
2108 // Minwidth does not come from value, as spec says set based on parent
2109 // and if we keep minwidth we'll consider it unsized which is incorrect
2110 iterateCheck(nodep, "Enum value", nodep->valuep(), CONTEXT, FINAL, nodep->dtypep(),
2111 EXTEND_EXP);
2112 }
2113 }
visit(AstEnumItemRef * nodep)2114 virtual void visit(AstEnumItemRef* nodep) override {
2115 if (!nodep->itemp()->didWidth()) {
2116 // We need to do the whole enum en-mass
2117 AstNode* enump = nodep->itemp();
2118 UASSERT_OBJ(enump, nodep, "EnumItemRef not linked");
2119 for (; enump; enump = enump->backp()) {
2120 if (VN_IS(enump, EnumDType)) break;
2121 }
2122 UASSERT_OBJ(enump, nodep, "EnumItemRef can't deref back to an Enum");
2123 VL_DO_DANGLING(userIterate(enump, m_vup), enump); // Parent enump maybe relinked
2124 }
2125 nodep->dtypeFrom(nodep->itemp());
2126 }
visit(AstConsAssoc * nodep)2127 virtual void visit(AstConsAssoc* nodep) override {
2128 // Type computed when constructed here
2129 auto* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), AssocArrayDType);
2130 UASSERT_OBJ(vdtypep, nodep, "ConsAssoc requires assoc upper parent data type");
2131 if (m_vup->prelim()) {
2132 nodep->dtypeFrom(vdtypep);
2133 if (nodep->defaultp()) {
2134 iterateCheck(nodep, "default", nodep->defaultp(), CONTEXT, FINAL,
2135 vdtypep->subDTypep(), EXTEND_EXP);
2136 }
2137 }
2138 }
visit(AstSetAssoc * nodep)2139 virtual void visit(AstSetAssoc* nodep) override {
2140 // Type computed when constructed here
2141 auto* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), AssocArrayDType);
2142 UASSERT_OBJ(vdtypep, nodep, "SetsAssoc requires assoc upper parent data type");
2143 if (m_vup->prelim()) {
2144 nodep->dtypeFrom(vdtypep);
2145 userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, BOTH).p());
2146 iterateCheck(nodep, "key", nodep->keyp(), CONTEXT, FINAL, vdtypep->keyDTypep(),
2147 EXTEND_EXP);
2148 iterateCheck(nodep, "value", nodep->valuep(), CONTEXT, FINAL, vdtypep->subDTypep(),
2149 EXTEND_EXP);
2150 }
2151 }
visit(AstConsDynArray * nodep)2152 virtual void visit(AstConsDynArray* nodep) override {
2153 // Type computed when constructed here
2154 AstDynArrayDType* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), DynArrayDType);
2155 UASSERT_OBJ(vdtypep, nodep, "ConsDynArray requires queue upper parent data type");
2156 if (m_vup->prelim()) {
2157 userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, PRELIM).p());
2158 userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, PRELIM).p());
2159 nodep->dtypeFrom(vdtypep);
2160 }
2161 if (m_vup->final()) {
2162 // Arguments can be either elements of the queue or a queue itself
2163 // Concats (part of tree of concats) must always become ConsDynArray's
2164 if (nodep->lhsp()) {
2165 if (VN_IS(nodep->lhsp()->dtypep(), DynArrayDType)
2166 || VN_IS(nodep->lhsp(), ConsDynArray)) {
2167 userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, FINAL).p());
2168 } else {
2169 // Sub elements are not queues, but concats, must always pass concats down
2170 iterateCheckTyped(nodep, "LHS", nodep->lhsp(), vdtypep->subDTypep(), FINAL);
2171 }
2172 }
2173 if (nodep->rhsp()) {
2174 if (VN_IS(nodep->rhsp()->dtypep(), DynArrayDType)
2175 || VN_IS(nodep->rhsp(), ConsDynArray)) {
2176 userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, FINAL).p());
2177 } else {
2178 iterateCheckTyped(nodep, "RHS", nodep->rhsp(), vdtypep->subDTypep(), FINAL);
2179 }
2180 }
2181 nodep->dtypeFrom(vdtypep);
2182 }
2183 }
visit(AstConsQueue * nodep)2184 virtual void visit(AstConsQueue* nodep) override {
2185 // Type computed when constructed here
2186 AstQueueDType* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), QueueDType);
2187 UASSERT_OBJ(vdtypep, nodep, "ConsQueue requires queue upper parent data type");
2188 if (m_vup->prelim()) {
2189 userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, PRELIM).p());
2190 userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, PRELIM).p());
2191 nodep->dtypeFrom(vdtypep);
2192 }
2193 if (m_vup->final()) {
2194 // Arguments can be either elements of the queue or a queue itself
2195 // Concats (part of tree of concats) must always become ConsQueue's
2196 if (nodep->lhsp()) {
2197 if (VN_IS(nodep->lhsp()->dtypep(), QueueDType)
2198 || VN_IS(nodep->lhsp(), ConsQueue)) {
2199 userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, FINAL).p());
2200 } else {
2201 // Sub elements are not queues, but concats, must always pass concats down
2202 iterateCheckTyped(nodep, "LHS", nodep->lhsp(), vdtypep->subDTypep(), FINAL);
2203 }
2204 }
2205 if (nodep->rhsp()) {
2206 if (VN_IS(nodep->rhsp()->dtypep(), QueueDType)
2207 || VN_IS(nodep->rhsp(), ConsQueue)) {
2208 userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, FINAL).p());
2209 } else {
2210 iterateCheckTyped(nodep, "RHS", nodep->rhsp(), vdtypep->subDTypep(), FINAL);
2211 }
2212 }
2213 nodep->dtypeFrom(vdtypep);
2214 }
2215 }
visit(AstInitItem * nodep)2216 virtual void visit(AstInitItem* nodep) override { //
2217 userIterateChildren(nodep, m_vup);
2218 }
visit(AstInitArray * nodep)2219 virtual void visit(AstInitArray* nodep) override {
2220 // InitArray has type of the array; children are array values
2221 if (m_vup->prelim()) { // First stage evaluation
2222 AstNodeDType* const vdtypep = m_vup->dtypeNullp();
2223 UASSERT_OBJ(vdtypep, nodep, "InitArray type not assigned by AstPattern/Var visitor");
2224 nodep->dtypep(vdtypep);
2225 if (const AstNodeArrayDType* const arrayp
2226 = VN_CAST(vdtypep->skipRefp(), NodeArrayDType)) {
2227 userIterateChildren(nodep, WidthVP(arrayp->subDTypep(), BOTH).p());
2228 } else {
2229 UINFO(1, "dtype object " << vdtypep->skipRefp() << endl);
2230 nodep->v3fatalSrc("InitArray on non-array");
2231 }
2232 }
2233 }
visit(AstInside * nodep)2234 virtual void visit(AstInside* nodep) override {
2235 userIterateAndNext(nodep->exprp(), WidthVP(CONTEXT, PRELIM).p());
2236 for (AstNode *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
2237 nextip = itemp->nextp(); // Prelim may cause the node to get replaced
2238 VL_DO_DANGLING(userIterate(itemp, WidthVP(CONTEXT, PRELIM).p()), itemp);
2239 }
2240 // Take width as maximum across all items
2241 int width = nodep->exprp()->width();
2242 int mwidth = nodep->exprp()->widthMin();
2243 for (const AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) {
2244 width = std::max(width, itemp->width());
2245 mwidth = std::max(mwidth, itemp->widthMin());
2246 }
2247 // Apply width
2248 AstNodeDType* const subDTypep
2249 = nodep->findLogicDType(width, mwidth, nodep->exprp()->dtypep()->numeric());
2250 iterateCheck(nodep, "Inside expression", nodep->exprp(), CONTEXT, FINAL, subDTypep,
2251 EXTEND_EXP);
2252 for (AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) {
2253 iterateCheck(nodep, "Inside Item", itemp, CONTEXT, FINAL, subDTypep, EXTEND_EXP);
2254 }
2255 nodep->dtypeSetBit();
2256 if (debug() >= 9) nodep->dumpTree(cout, "-inside-in: ");
2257 // Now rip out the inside and replace with simple math
2258 AstNode* newp = nullptr;
2259 for (AstNode *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
2260 nextip = itemp->nextp(); // Will be unlinking
2261 AstNode* inewp;
2262 const AstNodeDType* const itemDtp = itemp->dtypep()->skipRefp();
2263 if (AstInsideRange* const irangep = VN_CAST(itemp, InsideRange)) {
2264 // Similar logic in V3Case
2265 inewp = irangep->newAndFromInside(nodep->exprp(), irangep->lhsp()->unlinkFrBack(),
2266 irangep->rhsp()->unlinkFrBack());
2267 } else if (VN_IS(itemDtp, UnpackArrayDType)) {
2268 nodep->v3error("Unsupported: inside (set membership operator) on unpacked array");
2269 // Need the AstInside type to persist, then
2270 // for parameters, need V3Simulate support.
2271 // For non-parameters, need runtime support.
2272 continue;
2273 } else if (VN_IS(itemDtp, AssocArrayDType) || VN_IS(itemDtp, DynArrayDType)
2274 || VN_IS(itemDtp, QueueDType)) {
2275 nodep->v3error(
2276 "Inside operator not legal on non-unpacked arrays (IEEE 1800-2017 11.4.13)");
2277 continue;
2278 } else {
2279 inewp = new AstEqWild(itemp->fileline(), nodep->exprp()->cloneTree(true),
2280 itemp->unlinkFrBack());
2281 }
2282 if (newp) {
2283 newp = new AstOr(nodep->fileline(), newp, inewp);
2284 } else {
2285 newp = inewp;
2286 }
2287 }
2288 if (!newp) newp = new AstConst(nodep->fileline(), AstConst::BitFalse());
2289 if (debug() >= 9) newp->dumpTree(cout, "-inside-out: ");
2290 nodep->replaceWith(newp);
2291 VL_DO_DANGLING(pushDeletep(nodep), nodep);
2292 }
visit(AstInsideRange * nodep)2293 virtual void visit(AstInsideRange* nodep) override {
2294 // Just do each side; AstInside will rip these nodes out later
2295 userIterateAndNext(nodep->lhsp(), m_vup);
2296 userIterateAndNext(nodep->rhsp(), m_vup);
2297 nodep->dtypeFrom(nodep->lhsp());
2298 }
2299
visit(AstIfaceRefDType * nodep)2300 virtual void visit(AstIfaceRefDType* nodep) override {
2301 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
2302 UINFO(5, " IFACEREF " << nodep << endl);
2303 userIterateChildren(nodep, m_vup);
2304 nodep->dtypep(nodep);
2305 nodep->widthForce(1, 1); // Not really relevant
2306 UINFO(4, "dtWidthed " << nodep << endl);
2307 }
visit(AstNodeUOrStructDType * nodep)2308 virtual void visit(AstNodeUOrStructDType* nodep) override {
2309 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
2310 UINFO(5, " NODECLASS " << nodep << endl);
2311 // if (debug() >= 9) nodep->dumpTree("-class-in--");
2312 if (!nodep->packed()) {
2313 nodep->v3warn(UNPACKED, "Unsupported: Unpacked struct/union");
2314 if (!v3Global.opt.structsPacked()) {
2315 nodep->v3warn(UNPACKED, "Unsupported: --no-structs-packed");
2316 }
2317 }
2318 userIterateChildren(nodep, nullptr); // First size all members
2319 nodep->repairMemberCache();
2320 // Determine bit assignments and width
2321 nodep->dtypep(nodep);
2322 int lsb = 0;
2323 int width = 0;
2324 nodep->isFourstate(false);
2325 // MSB is first, so go backwards
2326 AstMemberDType* itemp;
2327 for (itemp = nodep->membersp(); itemp && itemp->nextp();
2328 itemp = VN_AS(itemp->nextp(), MemberDType)) {}
2329 for (AstMemberDType* backip; itemp; itemp = backip) {
2330 if (itemp->isFourstate()) nodep->isFourstate(true);
2331 backip = VN_CAST(itemp->backp(), MemberDType);
2332 itemp->lsb(lsb);
2333 if (VN_IS(nodep, UnionDType)) {
2334 width = std::max(width, itemp->width());
2335 } else {
2336 lsb += itemp->width();
2337 width += itemp->width();
2338 }
2339 }
2340 nodep->widthForce(width, width); // Signing stays as-is, as parsed from declaration
2341 // if (debug() >= 9) nodep->dumpTree("-class-out-");
2342 }
visit(AstClass * nodep)2343 virtual void visit(AstClass* nodep) override {
2344 if (nodep->didWidthAndSet()) return;
2345 // Must do extends first, as we may in functions under this class
2346 // start following a tree of extends that takes us to other classes
2347 userIterateAndNext(nodep->extendsp(), nullptr);
2348 userIterateChildren(nodep, nullptr); // First size all members
2349 nodep->repairCache();
2350 }
visit(AstClassRefDType * nodep)2351 virtual void visit(AstClassRefDType* nodep) override {
2352 if (nodep->didWidthAndSet()) return;
2353 // TODO this maybe eventually required to properly resolve members,
2354 // though causes problems with t_class_forward.v, so for now avoided
2355 // userIterateChildren(nodep->classp(), nullptr);
2356 }
visit(AstClassExtends * nodep)2357 virtual void visit(AstClassExtends* nodep) override {
2358 if (nodep->didWidthAndSet()) return;
2359 if (VN_IS(nodep->childDTypep(), ClassRefDType)) {
2360 nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->childDTypep()));
2361 }
2362 }
visit(AstMemberDType * nodep)2363 virtual void visit(AstMemberDType* nodep) override {
2364 if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
2365 // Iterate into subDTypep() to resolve that type and update pointer.
2366 nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
2367 nodep->dtypep(nodep); // The member itself, not subDtype
2368 nodep->widthFromSub(nodep->subDTypep());
2369 }
visit(AstMemberSel * nodep)2370 virtual void visit(AstMemberSel* nodep) override {
2371 UINFO(5, " MEMBERSEL " << nodep << endl);
2372 if (debug() >= 9) nodep->dumpTree("-mbs-in: ");
2373 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
2374 if (debug() >= 9) nodep->dumpTree("-mbs-ic: ");
2375 // Find the fromp dtype - should be a class
2376 if (!nodep->fromp()->dtypep()) nodep->fromp()->v3fatalSrc("Unlinked data type");
2377 AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
2378 UINFO(9, " from dt " << fromDtp << endl);
2379 if (AstNodeUOrStructDType* const adtypep = VN_CAST(fromDtp, NodeUOrStructDType)) {
2380 if (memberSelStruct(nodep, adtypep)) return;
2381 } else if (AstClassRefDType* const adtypep = VN_CAST(fromDtp, ClassRefDType)) {
2382 if (AstNode* const foundp = memberSelClass(nodep, adtypep)) {
2383 if (AstVar* const varp = VN_CAST(foundp, Var)) {
2384 nodep->dtypep(foundp->dtypep());
2385 nodep->varp(varp);
2386 return;
2387 }
2388 if (AstEnumItemRef* const adfoundp = VN_CAST(foundp, EnumItemRef)) {
2389 nodep->replaceWith(adfoundp->cloneTree(false));
2390 return;
2391 }
2392 UINFO(1, "found object " << foundp << endl);
2393 nodep->v3fatalSrc("MemberSel of non-variable\n"
2394 << nodep->warnContextPrimary() << '\n'
2395 << foundp->warnOther() << "... Location of found object\n"
2396 << foundp->warnContextSecondary());
2397 }
2398 } else if (VN_IS(fromDtp, EnumDType) //
2399 || VN_IS(fromDtp, AssocArrayDType) //
2400 || VN_IS(fromDtp, UnpackArrayDType) //
2401 || VN_IS(fromDtp, DynArrayDType) //
2402 || VN_IS(fromDtp, QueueDType) //
2403 || VN_IS(fromDtp, BasicDType)) {
2404 // Method call on enum without following parenthesis, e.g. "ENUM.next"
2405 // Convert this into a method call, and let that visitor figure out what to do next
2406 AstNode* const newp = new AstMethodCall(
2407 nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), nullptr);
2408 nodep->replaceWith(newp);
2409 VL_DO_DANGLING(pushDeletep(nodep), nodep);
2410 userIterate(newp, m_vup);
2411 return;
2412 } else {
2413 nodep->v3error("Member selection of non-struct/union object '"
2414 << nodep->fromp()->prettyTypeName() << "' which is a '"
2415 << nodep->fromp()->dtypep()->prettyTypeName() << "'");
2416 }
2417 // Error handling
2418 nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::BitFalse()));
2419 VL_DO_DANGLING(pushDeletep(nodep), nodep);
2420 }
memberSelClass(AstMemberSel * nodep,AstClassRefDType * adtypep)2421 AstNode* memberSelClass(AstMemberSel* nodep, AstClassRefDType* adtypep) {
2422 // Returns node if ok
2423 // No need to width-resolve the class, as it was done when we did the child
2424 AstClass* const first_classp = adtypep->classp();
2425 UASSERT_OBJ(first_classp, nodep, "Unlinked");
2426 for (AstClass* classp = first_classp; classp;) {
2427 if (AstNode* const foundp = classp->findMember(nodep->name())) return foundp;
2428 classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr;
2429 }
2430 VSpellCheck speller;
2431 for (AstClass* classp = first_classp; classp;) {
2432 for (AstNode* itemp = classp->membersp(); itemp; itemp = itemp->nextp()) {
2433 if (VN_IS(itemp, Var) || VN_IS(itemp, EnumItemRef)) {
2434 speller.pushCandidate(itemp->prettyName());
2435 }
2436 }
2437 classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr;
2438 }
2439 const string suggest = speller.bestCandidateMsg(nodep->prettyName());
2440 nodep->v3error(
2441 "Member " << nodep->prettyNameQ() << " not found in class "
2442 << first_classp->prettyNameQ() << "\n"
2443 << (suggest.empty() ? "" : nodep->fileline()->warnMore() + suggest));
2444 return nullptr; // Caller handles error
2445 }
memberSelStruct(AstMemberSel * nodep,AstNodeUOrStructDType * adtypep)2446 bool memberSelStruct(AstMemberSel* nodep, AstNodeUOrStructDType* adtypep) {
2447 // Returns true if ok
2448 if (AstMemberDType* const memberp = adtypep->findMember(nodep->name())) {
2449 if (m_attrp) { // Looking for the base of the attribute
2450 nodep->dtypep(memberp);
2451 UINFO(9, " MEMBERSEL(attr) -> " << nodep << endl);
2452 UINFO(9, " dt-> " << nodep->dtypep() << endl);
2453 } else {
2454 AstSel* const newp = new AstSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2455 memberp->lsb(), memberp->width());
2456 // Must skip over the member to find the union; as the member may disappear later
2457 newp->dtypep(memberp->subDTypep()->skipRefToEnump());
2458 newp->didWidth(true); // Don't replace dtype with basic type
2459 UINFO(9, " MEMBERSEL -> " << newp << endl);
2460 UINFO(9, " dt-> " << newp->dtypep() << endl);
2461 nodep->replaceWith(newp);
2462 VL_DO_DANGLING(pushDeletep(nodep), nodep);
2463 // Should be able to treat it as a normal-ish nodesel - maybe.
2464 // The lhsp() will be strange until this stage; create the number here?
2465 }
2466 return true;
2467 }
2468 nodep->v3error("Member " << nodep->prettyNameQ() << " not found in structure");
2469 return false;
2470 }
2471
visit(AstCMethodHard * nodep)2472 virtual void visit(AstCMethodHard* nodep) override {
2473 // Never created before V3Width, so no need to redo it
2474 UASSERT_OBJ(nodep->dtypep(), nodep, "CMETHODCALLs should have already been sized");
2475 }
2476
visit(AstMethodCall * nodep)2477 virtual void visit(AstMethodCall* nodep) override {
2478 UINFO(5, " METHODCALL " << nodep << endl);
2479 if (nodep->didWidth()) return;
2480 if (debug() >= 9) nodep->dumpTree("-mts-in: ");
2481 // Should check types the method requires, but at present we don't do much
2482 userIterate(nodep->fromp(), WidthVP(SELF, BOTH).p());
2483 // Any AstWith is checked later when know types, in methodWithArgument
2484 for (AstArg* argp = VN_CAST(nodep->pinsp(), Arg); argp; argp = VN_AS(argp->nextp(), Arg)) {
2485 if (argp->exprp()) userIterate(argp->exprp(), WidthVP(SELF, BOTH).p());
2486 }
2487 // Find the fromp dtype - should be a class
2488 UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, "Unsized expression");
2489 AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
2490 AstBasicDType* const basicp = fromDtp ? fromDtp->basicp() : nullptr;
2491 UINFO(9, " from dt " << fromDtp << endl);
2492 userIterate(fromDtp, WidthVP(SELF, BOTH).p());
2493 if (AstEnumDType* const adtypep = VN_CAST(fromDtp, EnumDType)) {
2494 methodCallEnum(nodep, adtypep);
2495 } else if (AstAssocArrayDType* const adtypep = VN_CAST(fromDtp, AssocArrayDType)) {
2496 methodCallAssoc(nodep, adtypep);
2497 } else if (AstDynArrayDType* const adtypep = VN_CAST(fromDtp, DynArrayDType)) {
2498 methodCallDyn(nodep, adtypep);
2499 } else if (AstQueueDType* const adtypep = VN_CAST(fromDtp, QueueDType)) {
2500 methodCallQueue(nodep, adtypep);
2501 } else if (AstClassRefDType* const adtypep = VN_CAST(fromDtp, ClassRefDType)) {
2502 methodCallClass(nodep, adtypep);
2503 } else if (AstUnpackArrayDType* const adtypep = VN_CAST(fromDtp, UnpackArrayDType)) {
2504 methodCallUnpack(nodep, adtypep);
2505 } else if (basicp && basicp->isEventValue()) {
2506 methodCallEvent(nodep, basicp);
2507 } else if (basicp && basicp->isString()) {
2508 methodCallString(nodep, basicp);
2509 } else {
2510 nodep->v3warn(E_UNSUPPORTED, "Unsupported: Member call on object '"
2511 << nodep->fromp()->prettyTypeName()
2512 << "' which is a '"
2513 << nodep->fromp()->dtypep()->prettyTypeName() << "'");
2514 }
2515 }
methodWithArgument(AstMethodCall * nodep,bool required,bool arbReturn,AstNodeDType * returnDtp,AstNodeDType * indexDtp,AstNodeDType * valueDtp)2516 AstWith* methodWithArgument(AstMethodCall* nodep, bool required, bool arbReturn,
2517 AstNodeDType* returnDtp, AstNodeDType* indexDtp,
2518 AstNodeDType* valueDtp) {
2519 UASSERT_OBJ(arbReturn || returnDtp, nodep, "Null return type");
2520 if (AstWith* const withp = VN_CAST(nodep->pinsp(), With)) {
2521 withp->indexArgRefp()->dtypep(indexDtp);
2522 withp->valueArgRefp()->dtypep(valueDtp);
2523 userIterate(withp, WidthVP(returnDtp, BOTH).p());
2524 withp->unlinkFrBack();
2525 return withp;
2526 } else if (required) {
2527 nodep->v3error("'with' statement is required for ." << nodep->prettyName()
2528 << " method");
2529 }
2530 return nullptr;
2531 }
methodOkArguments(AstMethodCall * nodep,int minArg,int maxArg)2532 void methodOkArguments(AstMethodCall* nodep, int minArg, int maxArg) {
2533 int narg = 0;
2534 for (AstNode* argp = nodep->pinsp(); argp; argp = argp->nextp()) {
2535 if (VN_IS(argp, With)) {
2536 argp->v3error("'with' not legal on this method");
2537 // Delete all arguments as nextp() otherwise dangling
2538 VL_DO_DANGLING(pushDeletep(argp->unlinkFrBackWithNext()), argp);
2539 break;
2540 }
2541 ++narg;
2542 UASSERT_OBJ(VN_IS(argp, Arg), nodep, "Method arg without Arg type");
2543 }
2544 const bool ok = (narg >= minArg) && (narg <= maxArg);
2545 if (!ok) {
2546 nodep->v3error("The " << narg << " arguments passed to ." << nodep->prettyName()
2547 << " method does not match its requiring " << cvtToStr(minArg)
2548 << (minArg == maxArg ? "" : " to " + cvtToStr(maxArg))
2549 << " arguments");
2550 // Adjust to required argument counts, very bogus, but avoids core dump
2551 for (; narg < minArg; ++narg) {
2552 nodep->addPinsp(
2553 new AstArg(nodep->fileline(), "", new AstConst(nodep->fileline(), 0)));
2554 }
2555 for (; narg > maxArg; --narg) {
2556 AstNode* argp = nodep->pinsp();
2557 while (argp->nextp()) argp = argp->nextp();
2558 argp->unlinkFrBack();
2559 VL_DO_DANGLING(argp->deleteTree(), argp);
2560 }
2561 }
2562 }
2563
methodCallEnum(AstMethodCall * nodep,AstEnumDType * adtypep)2564 void methodCallEnum(AstMethodCall* nodep, AstEnumDType* adtypep) {
2565 // Method call on enum without following parenthesis, e.g. "ENUM.next"
2566 // Convert this into a method call, and let that visitor figure out what to do next
2567 if (adtypep) {}
2568 if (nodep->name() == "num" //
2569 || nodep->name() == "first" //
2570 || nodep->name() == "last") {
2571 // Constant value
2572 AstConst* newp = nullptr;
2573 methodOkArguments(nodep, 0, 0);
2574 if (nodep->name() == "num") {
2575 int items = 0;
2576 for (AstNode* itemp = adtypep->itemsp(); itemp; itemp = itemp->nextp()) ++items;
2577 newp = new AstConst(nodep->fileline(), AstConst::Signed32(), items);
2578 } else if (nodep->name() == "first") {
2579 const AstEnumItem* itemp = adtypep->itemsp();
2580 if (!itemp) {
2581 newp = new AstConst(nodep->fileline(), AstConst::Signed32(),
2582 0); // Spec doesn't say what to do
2583 } else {
2584 newp = VN_AS(itemp->valuep()->cloneTree(false), Const); // A const
2585 }
2586 } else if (nodep->name() == "last") {
2587 const AstEnumItem* itemp = adtypep->itemsp();
2588 while (itemp && itemp->nextp()) itemp = VN_AS(itemp->nextp(), EnumItem);
2589 if (!itemp) {
2590 newp = new AstConst(nodep->fileline(), AstConst::Signed32(),
2591 0); // Spec doesn't say what to do
2592 } else {
2593 newp = VN_AS(itemp->valuep()->cloneTree(false), Const); // A const
2594 }
2595 }
2596 UASSERT_OBJ(newp, nodep, "Enum method (perhaps enum item) not const");
2597 newp->fileline(nodep->fileline()); // Use method's filename/line number to be clearer;
2598 // may have warning disables
2599 nodep->replaceWith(newp);
2600 VL_DO_DANGLING(pushDeletep(nodep), nodep);
2601 } else if (nodep->name() == "name" || nodep->name() == "next" || nodep->name() == "prev") {
2602 AstAttrType attrType;
2603 if (nodep->name() == "name") {
2604 attrType = AstAttrType::ENUM_NAME;
2605 } else if (nodep->name() == "next") {
2606 attrType = AstAttrType::ENUM_NEXT;
2607 } else if (nodep->name() == "prev") {
2608 attrType = AstAttrType::ENUM_PREV;
2609 } else {
2610 nodep->v3fatalSrc("Bad case");
2611 }
2612
2613 if (nodep->name() == "name") {
2614 methodOkArguments(nodep, 0, 0);
2615 } else if (nodep->pinsp() && !(VN_IS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const))) {
2616 nodep->pinsp()->v3fatalSrc("Unsupported: enum next/prev with non-const argument");
2617 } else if (nodep->pinsp()
2618 && !(VN_IS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)
2619 && VN_AS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)->toUInt() == 1
2620 && !nodep->pinsp()->nextp())) {
2621 // Unroll of enumVar.next(k) to enumVar.next(1).next(k - 1)
2622 AstMethodCall* const clonep = nodep->cloneTree(false);
2623 VN_AS(VN_AS(clonep->pinsp(), Arg)->exprp(), Const)->num().setLong(1);
2624 const uint32_t stepWidth
2625 = VN_AS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)->toUInt();
2626 AstConst* const constp = new AstConst(nodep->fileline(), stepWidth - 1);
2627 AstArg* const argp = new AstArg(nodep->fileline(), "", constp);
2628 AstMethodCall* const newp
2629 = new AstMethodCall(nodep->fileline(), clonep, nodep->name(), argp);
2630 nodep->replaceWith(newp);
2631 VL_DO_DANGLING(nodep->deleteTree(), nodep);
2632 return;
2633 }
2634 // Need a runtime lookup table. Yuk.
2635 const uint64_t msbdim = enumMaxValue(nodep, adtypep);
2636 const int selwidth = V3Number::log2b(msbdim) + 1; // Width to address a bit
2637 AstVar* const varp = enumVarp(adtypep, attrType, (1ULL << selwidth) - 1);
2638 AstVarRef* const varrefp = new AstVarRef(nodep->fileline(), varp, VAccess::READ);
2639 varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
2640 AstNode* const newp = new AstArraySel(
2641 nodep->fileline(), varrefp,
2642 // Select in case widths are off due to msblen!=width
2643 // We return "random" values if outside the range, which is fine
2644 // as next/previous on illegal values just need something good out
2645 new AstSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(), 0, selwidth));
2646 nodep->replaceWith(newp);
2647 VL_DO_DANGLING(nodep->deleteTree(), nodep);
2648 } else {
2649 nodep->v3error("Unknown built-in enum method " << nodep->prettyNameQ());
2650 }
2651 }
methodCallAssoc(AstMethodCall * nodep,AstAssocArrayDType * adtypep)2652 void methodCallAssoc(AstMethodCall* nodep, AstAssocArrayDType* adtypep) {
2653 AstCMethodHard* newp = nullptr;
2654 if (nodep->name() == "num" // function int num()
2655 || nodep->name() == "size") {
2656 methodOkArguments(nodep, 0, 0);
2657 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size",
2658 nullptr); // So don't need num()
2659 newp->dtypeSetSigned32();
2660 } else if (nodep->name() == "first" // function int first(ref index)
2661 || nodep->name() == "last" //
2662 || nodep->name() == "next" //
2663 || nodep->name() == "prev") {
2664 methodOkArguments(nodep, 1, 1);
2665 AstNode* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep);
2666 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2667 nodep->name(), // first/last/next/prev
2668 index_exprp->unlinkFrBack());
2669 newp->dtypeSetSigned32();
2670 } else if (nodep->name() == "exists") { // function int exists(input index)
2671 // IEEE really should have made this a "bit" return
2672 methodOkArguments(nodep, 1, 1);
2673 AstNode* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep);
2674 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "exists",
2675 index_exprp->unlinkFrBack());
2676 newp->dtypeSetSigned32();
2677 newp->pure(true);
2678 } else if (nodep->name() == "delete") { // function void delete([input integer index])
2679 methodOkArguments(nodep, 0, 1);
2680 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
2681 if (!nodep->pinsp()) {
2682 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2683 "clear", nullptr);
2684 newp->makeStatement();
2685 } else {
2686 AstNode* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep);
2687 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2688 "erase", index_exprp->unlinkFrBack());
2689 newp->makeStatement();
2690 }
2691 } else if (nodep->name() == "sort" || nodep->name() == "rsort"
2692 || nodep->name() == "reverse" || nodep->name() == "shuffle") {
2693 nodep->v3error("Array method " << nodep->prettyNameQ()
2694 << " not legal on associative arrays");
2695 } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor"
2696 || nodep->name() == "sum" || nodep->name() == "product") {
2697 // All value return
2698 AstWith* const withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(),
2699 adtypep->keyDTypep(), adtypep->subDTypep());
2700 methodOkArguments(nodep, 0, 0);
2701 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2702 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2703 "r_" + nodep->name(), withp);
2704 newp->dtypeFrom(adtypep->subDTypep());
2705 if (!nodep->firstAbovep()) newp->makeStatement();
2706 } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
2707 || nodep->name() == "unique_index") {
2708 methodOkArguments(nodep, 0, 0);
2709 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2710 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2711 nodep->name(), nullptr);
2712 if (nodep->name() == "unique_index") {
2713 newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep()));
2714 } else {
2715 newp->dtypeFrom(adtypep);
2716 }
2717 if (!nodep->firstAbovep()) newp->makeStatement();
2718 } else if (nodep->name() == "find" || nodep->name() == "find_first"
2719 || nodep->name() == "find_last") {
2720 AstWith* const withp = methodWithArgument(nodep, true, false, nodep->findBitDType(),
2721 adtypep->keyDTypep(), adtypep->subDTypep());
2722 methodOkArguments(nodep, 0, 0);
2723 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2724 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2725 nodep->name(), withp);
2726 newp->dtypeFrom(adtypep);
2727 if (!nodep->firstAbovep()) newp->makeStatement();
2728 } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
2729 || nodep->name() == "find_last_index") {
2730 AstWith* const withp = methodWithArgument(nodep, true, false, nodep->findBitDType(),
2731 adtypep->keyDTypep(), adtypep->subDTypep());
2732 methodOkArguments(nodep, 0, 0);
2733 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2734 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2735 nodep->name(), withp);
2736 newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep()));
2737 if (!nodep->firstAbovep()) newp->makeStatement();
2738 } else {
2739 nodep->v3error("Unknown built-in associative array method " << nodep->prettyNameQ());
2740 nodep->dtypeFrom(adtypep->subDTypep()); // Best guess
2741 }
2742 if (newp) {
2743 newp->protect(false);
2744 newp->didWidth(true);
2745 nodep->replaceWith(newp);
2746 VL_DO_DANGLING(nodep->deleteTree(), nodep);
2747 }
2748 }
methodCallAssocIndexExpr(AstMethodCall * nodep,AstAssocArrayDType * adtypep)2749 AstNode* methodCallAssocIndexExpr(AstMethodCall* nodep, AstAssocArrayDType* adtypep) {
2750 AstNode* const index_exprp = VN_CAST(nodep->pinsp(), Arg)->exprp();
2751 iterateCheck(nodep, "index", index_exprp, CONTEXT, FINAL, adtypep->keyDTypep(),
2752 EXTEND_EXP);
2753 VL_DANGLING(index_exprp); // May have been edited
2754 return VN_AS(nodep->pinsp(), Arg)->exprp();
2755 }
methodCallLValueRecurse(AstMethodCall * nodep,AstNode * childp,const VAccess & access)2756 void methodCallLValueRecurse(AstMethodCall* nodep, AstNode* childp, const VAccess& access) {
2757 if (AstNodeVarRef* const varrefp = VN_CAST(childp, NodeVarRef)) {
2758 varrefp->access(access);
2759 } else if (const AstMemberSel* const ichildp = VN_CAST(childp, MemberSel)) {
2760 methodCallLValueRecurse(nodep, ichildp->fromp(), access);
2761 } else if (const AstNodeSel* const ichildp = VN_CAST(childp, NodeSel)) {
2762 methodCallLValueRecurse(nodep, ichildp->fromp(), access);
2763 } else {
2764 UINFO(1, " Related node: " << childp << endl);
2765 nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-variable on LHS of built-in method '"
2766 << nodep->prettyName() << "'");
2767 }
2768 }
methodCallDyn(AstMethodCall * nodep,AstDynArrayDType * adtypep)2769 void methodCallDyn(AstMethodCall* nodep, AstDynArrayDType* adtypep) {
2770 AstCMethodHard* newp = nullptr;
2771 if (nodep->name() == "at") { // Created internally for []
2772 methodOkArguments(nodep, 1, 1);
2773 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
2774 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at",
2775 nullptr);
2776 newp->dtypeFrom(adtypep->subDTypep());
2777 } else if (nodep->name() == "size") {
2778 methodOkArguments(nodep, 0, 0);
2779 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size",
2780 nullptr);
2781 newp->dtypeSetSigned32();
2782 } else if (nodep->name() == "delete") { // function void delete()
2783 methodOkArguments(nodep, 0, 0);
2784 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
2785 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear",
2786 nullptr);
2787 newp->makeStatement();
2788 } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor"
2789 || nodep->name() == "sum" || nodep->name() == "product") {
2790 // All value return
2791 AstWith* const withp
2792 = methodWithArgument(nodep, false, false, adtypep->subDTypep(),
2793 nodep->findUInt32DType(), adtypep->subDTypep());
2794 methodOkArguments(nodep, 0, 0);
2795 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2796 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2797 "r_" + nodep->name(), withp);
2798 newp->dtypeFrom(adtypep->subDTypep());
2799 if (!nodep->firstAbovep()) newp->makeStatement();
2800 } else if (nodep->name() == "reverse" || nodep->name() == "shuffle"
2801 || nodep->name() == "sort" || nodep->name() == "rsort") {
2802 AstWith* withp = nullptr;
2803 if (nodep->name() == "sort" || nodep->name() == "rsort") {
2804 withp = methodWithArgument(nodep, false, true, nullptr, nodep->findUInt32DType(),
2805 adtypep->subDTypep());
2806 }
2807 methodOkArguments(nodep, 0, 0);
2808 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
2809 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2810 nodep->name(), withp);
2811 newp->makeStatement();
2812 } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
2813 || nodep->name() == "unique_index") {
2814 methodOkArguments(nodep, 0, 0);
2815 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2816 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2817 nodep->name(), nullptr);
2818 if (nodep->name() == "unique_index") {
2819 newp->dtypep(newp->findQueueIndexDType());
2820 } else {
2821 newp->dtypeFrom(adtypep);
2822 }
2823 if (!nodep->firstAbovep()) newp->makeStatement();
2824 } else if (nodep->name() == "find" || nodep->name() == "find_first"
2825 || nodep->name() == "find_last" || nodep->name() == "find_index") {
2826 AstWith* const withp
2827 = methodWithArgument(nodep, true, false, nodep->findBitDType(),
2828 nodep->findUInt32DType(), adtypep->subDTypep());
2829 methodOkArguments(nodep, 0, 0);
2830 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2831 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2832 nodep->name(), withp);
2833 newp->dtypeFrom(adtypep);
2834 if (!nodep->firstAbovep()) newp->makeStatement();
2835 } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
2836 || nodep->name() == "find_last_index") {
2837 AstWith* const withp
2838 = methodWithArgument(nodep, true, false, nodep->findBitDType(),
2839 nodep->findUInt32DType(), adtypep->subDTypep());
2840 methodOkArguments(nodep, 0, 0);
2841 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2842 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2843 nodep->name(), withp);
2844 newp->dtypep(newp->findQueueIndexDType());
2845 if (!nodep->firstAbovep()) newp->makeStatement();
2846 } else {
2847 nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in dynamic array method "
2848 << nodep->prettyNameQ());
2849 nodep->dtypeFrom(adtypep->subDTypep()); // Best guess
2850 }
2851 if (newp) {
2852 newp->protect(false);
2853 newp->didWidth(true);
2854 nodep->replaceWith(newp);
2855 VL_DO_DANGLING(nodep->deleteTree(), nodep);
2856 }
2857 }
methodCallQueue(AstMethodCall * nodep,AstQueueDType * adtypep)2858 void methodCallQueue(AstMethodCall* nodep, AstQueueDType* adtypep) {
2859 AstCMethodHard* newp = nullptr;
2860 if (nodep->name() == "at") { // Created internally for []
2861 methodOkArguments(nodep, 1, 1);
2862 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
2863 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at",
2864 nullptr);
2865 newp->dtypeFrom(adtypep->subDTypep());
2866 } else if (nodep->name() == "num" // function int num()
2867 || nodep->name() == "size") {
2868 methodOkArguments(nodep, 0, 0);
2869 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size",
2870 nullptr);
2871 newp->dtypeSetSigned32();
2872 } else if (nodep->name() == "delete") { // function void delete([input integer index])
2873 methodOkArguments(nodep, 0, 1);
2874 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
2875 if (!nodep->pinsp()) {
2876 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2877 "clear", nullptr);
2878 newp->makeStatement();
2879 } else {
2880 AstNode* const index_exprp = methodCallQueueIndexExpr(nodep);
2881 if (index_exprp->isZero()) { // delete(0) is a pop_front
2882 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2883 "pop_front", nullptr);
2884 newp->dtypeFrom(adtypep->subDTypep());
2885 newp->makeStatement();
2886 } else {
2887 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2888 "erase", index_exprp->unlinkFrBack());
2889 newp->makeStatement();
2890 }
2891 }
2892 } else if (nodep->name() == "insert") {
2893 methodOkArguments(nodep, 2, 2);
2894 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
2895 AstNode* const index_exprp = methodCallQueueIndexExpr(nodep);
2896 AstArg* const argp = VN_AS(nodep->pinsp()->nextp(), Arg);
2897 iterateCheckTyped(nodep, "insert value", argp->exprp(), adtypep->subDTypep(), BOTH);
2898 if (index_exprp->isZero()) { // insert(0, ...) is a push_front
2899 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2900 "push_front", argp->exprp()->unlinkFrBack());
2901 newp->makeStatement();
2902 } else {
2903 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2904 nodep->name(), index_exprp->unlinkFrBack());
2905 newp->addPinsp(argp->exprp()->unlinkFrBack());
2906 newp->makeStatement();
2907 }
2908 } else if (nodep->name() == "pop_front" || nodep->name() == "pop_back") {
2909 methodOkArguments(nodep, 0, 0);
2910 // Returns element, so method both consumes (reads) and modifies the queue
2911 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READWRITE);
2912 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2913 nodep->name(), nullptr);
2914 newp->dtypeFrom(adtypep->subDTypep());
2915 if (!nodep->firstAbovep()) newp->makeStatement();
2916 } else if (nodep->name() == "push_back" || nodep->name() == "push_front") {
2917 methodOkArguments(nodep, 1, 1);
2918 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
2919 AstArg* const argp = VN_AS(nodep->pinsp(), Arg);
2920 iterateCheckTyped(nodep, "push value", argp->exprp(), adtypep->subDTypep(), BOTH);
2921 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2922 nodep->name(), argp->exprp()->unlinkFrBack());
2923 newp->makeStatement();
2924 } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor"
2925 || nodep->name() == "sum" || nodep->name() == "product") {
2926 AstWith* const withp
2927 = methodWithArgument(nodep, false, false, adtypep->subDTypep(),
2928 nodep->findUInt32DType(), adtypep->subDTypep());
2929 methodOkArguments(nodep, 0, 0);
2930 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2931 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2932 "r_" + nodep->name(), withp);
2933 newp->dtypeFrom(adtypep->subDTypep());
2934 if (!nodep->firstAbovep()) newp->makeStatement();
2935 } else if (nodep->name() == "reverse" || nodep->name() == "shuffle"
2936 || nodep->name() == "sort" || nodep->name() == "rsort") {
2937 AstWith* withp = nullptr;
2938 if (nodep->name() == "sort" || nodep->name() == "rsort") {
2939 withp = methodWithArgument(nodep, false, true, nullptr, nodep->findUInt32DType(),
2940 adtypep->subDTypep());
2941 }
2942 methodOkArguments(nodep, 0, 0);
2943 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
2944 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2945 nodep->name(), withp);
2946 newp->makeStatement();
2947 } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
2948 || nodep->name() == "unique_index") {
2949 methodOkArguments(nodep, 0, 0);
2950 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2951 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2952 nodep->name(), nullptr);
2953 if (nodep->name() == "unique_index") {
2954 newp->dtypep(newp->findQueueIndexDType());
2955 } else {
2956 newp->dtypeFrom(adtypep);
2957 }
2958 if (!nodep->firstAbovep()) newp->makeStatement();
2959 } else if (nodep->name() == "find" || nodep->name() == "find_first"
2960 || nodep->name() == "find_last") {
2961 AstWith* const withp
2962 = methodWithArgument(nodep, true, false, nodep->findBitDType(),
2963 nodep->findUInt32DType(), adtypep->subDTypep());
2964 methodOkArguments(nodep, 0, 0);
2965 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2966 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2967 nodep->name(), withp);
2968 newp->dtypeFrom(adtypep);
2969 if (!nodep->firstAbovep()) newp->makeStatement();
2970 } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
2971 || nodep->name() == "find_last_index") {
2972 AstWith* const withp
2973 = methodWithArgument(nodep, true, false, nodep->findBitDType(),
2974 nodep->findUInt32DType(), adtypep->subDTypep());
2975 methodOkArguments(nodep, 0, 0);
2976 methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
2977 newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
2978 nodep->name(), withp);
2979 newp->dtypep(newp->findQueueIndexDType());
2980 if (!nodep->firstAbovep()) newp->makeStatement();
2981 } else {
2982 nodep->v3warn(E_UNSUPPORTED,
2983 "Unsupported/unknown built-in queue method " << nodep->prettyNameQ());
2984 nodep->dtypeFrom(adtypep->subDTypep()); // Best guess
2985 }
2986 if (newp) {
2987 newp->protect(false);
2988 newp->didWidth(true);
2989 nodep->replaceWith(newp);
2990 VL_DO_DANGLING(nodep->deleteTree(), nodep);
2991 }
2992 }
methodCallQueueIndexExpr(AstMethodCall * nodep)2993 AstNode* methodCallQueueIndexExpr(AstMethodCall* nodep) {
2994 AstNode* const index_exprp = VN_AS(nodep->pinsp(), Arg)->exprp();
2995 iterateCheckSigned32(nodep, "index", index_exprp, BOTH);
2996 VL_DANGLING(index_exprp); // May have been edited
2997 return VN_AS(nodep->pinsp(), Arg)->exprp();
2998 }
methodCallClass(AstMethodCall * nodep,AstClassRefDType * adtypep)2999 void methodCallClass(AstMethodCall* nodep, AstClassRefDType* adtypep) {
3000 // No need to width-resolve the class, as it was done when we did the child
3001 AstClass* const first_classp = adtypep->classp();
3002 if (nodep->name() == "randomize") {
3003 v3Global.useRandomizeMethods(true);
3004 V3Randomize::newRandomizeFunc(first_classp);
3005 }
3006 UASSERT_OBJ(first_classp, nodep, "Unlinked");
3007 for (AstClass* classp = first_classp; classp;) {
3008 if (AstNodeFTask* const ftaskp
3009 = VN_CAST(classp->findMember(nodep->name()), NodeFTask)) {
3010 userIterate(ftaskp, nullptr);
3011 if (ftaskp->lifetime().isStatic()) {
3012 AstNode* argsp = nullptr;
3013 if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext();
3014 AstNodeFTaskRef* newp = nullptr;
3015 if (VN_IS(ftaskp, Task)) {
3016 newp = new AstTaskRef(nodep->fileline(), ftaskp->name(), argsp);
3017 } else {
3018 newp = new AstFuncRef(nodep->fileline(), ftaskp->name(), argsp);
3019 }
3020 newp->taskp(ftaskp);
3021 newp->classOrPackagep(classp);
3022 nodep->replaceWith(newp);
3023 VL_DO_DANGLING(nodep->deleteTree(), nodep);
3024 } else {
3025 nodep->taskp(ftaskp);
3026 nodep->dtypeFrom(ftaskp);
3027 nodep->classOrPackagep(classp);
3028 if (VN_IS(ftaskp, Task)) nodep->makeStatement();
3029 }
3030 return;
3031 }
3032 classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr;
3033 }
3034 {
3035 VSpellCheck speller;
3036 for (AstClass* classp = first_classp; classp;) {
3037 for (AstNode* itemp = classp->membersp(); itemp; itemp = itemp->nextp()) {
3038 if (VN_IS(itemp, NodeFTask)) speller.pushCandidate(itemp->prettyName());
3039 }
3040 classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr;
3041 }
3042 const string suggest = speller.bestCandidateMsg(nodep->prettyName());
3043 nodep->v3error("Class method "
3044 << nodep->prettyNameQ() << " not found in class "
3045 << first_classp->prettyNameQ() << "\n"
3046 << (suggest.empty() ? "" : nodep->fileline()->warnMore() + suggest));
3047 }
3048 nodep->dtypeSetSigned32(); // Guess on error
3049 }
methodCallUnpack(AstMethodCall * nodep,AstUnpackArrayDType * adtypep)3050 void methodCallUnpack(AstMethodCall* nodep, AstUnpackArrayDType* adtypep) {
3051 enum : uint8_t {
3052 UNKNOWN = 0,
3053 ARRAY_OR,
3054 ARRAY_AND,
3055 ARRAY_XOR,
3056 ARRAY_SUM,
3057 ARRAY_PRODUCT
3058 } methodId;
3059
3060 methodId = UNKNOWN;
3061 if (nodep->name() == "or") {
3062 methodId = ARRAY_OR;
3063 } else if (nodep->name() == "and") {
3064 methodId = ARRAY_AND;
3065 } else if (nodep->name() == "xor") {
3066 methodId = ARRAY_XOR;
3067 } else if (nodep->name() == "sum") {
3068 methodId = ARRAY_SUM;
3069 } else if (nodep->name() == "product") {
3070 methodId = ARRAY_PRODUCT;
3071 }
3072
3073 if (methodId) {
3074 methodOkArguments(nodep, 0, 0);
3075 FileLine* const fl = nodep->fileline();
3076 AstNode* newp = nullptr;
3077 for (int i = 0; i < adtypep->elementsConst(); ++i) {
3078 AstNode* const arrayRef = nodep->fromp()->cloneTree(false);
3079 AstNode* const selector = new AstArraySel(fl, arrayRef, i);
3080 if (!newp) {
3081 newp = selector;
3082 } else {
3083 switch (methodId) {
3084 case ARRAY_OR: newp = new AstOr(fl, newp, selector); break;
3085 case ARRAY_AND: newp = new AstAnd(fl, newp, selector); break;
3086 case ARRAY_XOR: newp = new AstXor(fl, newp, selector); break;
3087 case ARRAY_SUM: newp = new AstAdd(fl, newp, selector); break;
3088 case ARRAY_PRODUCT: newp = new AstMul(fl, newp, selector); break;
3089 default: nodep->v3fatalSrc("bad case");
3090 }
3091 }
3092 }
3093 nodep->replaceWith(newp);
3094 VL_DO_DANGLING(nodep->deleteTree(), nodep);
3095 } else {
3096 nodep->v3error("Unknown built-in array method " << nodep->prettyNameQ());
3097 nodep->dtypeFrom(adtypep->subDTypep()); // Best guess
3098 }
3099 }
methodCallEvent(AstMethodCall * nodep,AstBasicDType *)3100 void methodCallEvent(AstMethodCall* nodep, AstBasicDType*) {
3101 // Method call on event
3102 if (nodep->name() == "triggered") {
3103 // We represent events as numbers, so can just return number
3104 methodOkArguments(nodep, 0, 0);
3105 AstNode* const newp = nodep->fromp()->unlinkFrBack();
3106 nodep->replaceWith(newp);
3107 VL_DO_DANGLING(pushDeletep(nodep), nodep);
3108 } else {
3109 nodep->v3error("Unknown built-in event method " << nodep->prettyNameQ());
3110 }
3111 }
methodCallString(AstMethodCall * nodep,AstBasicDType *)3112 void methodCallString(AstMethodCall* nodep, AstBasicDType*) {
3113 // Method call on string
3114 if (nodep->name() == "len") {
3115 // Constant value
3116 methodOkArguments(nodep, 0, 0);
3117 AstNode* const newp = new AstLenN(nodep->fileline(), nodep->fromp()->unlinkFrBack());
3118 nodep->replaceWith(newp);
3119 VL_DO_DANGLING(pushDeletep(nodep), nodep);
3120 } else if (nodep->name() == "itoa") {
3121 methodOkArguments(nodep, 1, 1);
3122 VL_DO_DANGLING(replaceWithSFormat(nodep, "%0d"), nodep);
3123 } else if (nodep->name() == "hextoa") {
3124 methodOkArguments(nodep, 1, 1);
3125 VL_DO_DANGLING(replaceWithSFormat(nodep, "%0x"), nodep);
3126 } else if (nodep->name() == "octtoa") {
3127 methodOkArguments(nodep, 1, 1);
3128 VL_DO_DANGLING(replaceWithSFormat(nodep, "%0o"), nodep);
3129 } else if (nodep->name() == "bintoa") {
3130 methodOkArguments(nodep, 1, 1);
3131 VL_DO_DANGLING(replaceWithSFormat(nodep, "%0b"), nodep);
3132 } else if (nodep->name() == "realtoa") {
3133 methodOkArguments(nodep, 1, 1);
3134 VL_DO_DANGLING(replaceWithSFormat(nodep, "%g"), nodep);
3135 } else if (nodep->name() == "tolower") {
3136 methodOkArguments(nodep, 0, 0);
3137 AstNode* const newp
3138 = new AstToLowerN(nodep->fileline(), nodep->fromp()->unlinkFrBack());
3139 nodep->replaceWith(newp);
3140 VL_DO_DANGLING(nodep->deleteTree(), nodep);
3141 } else if (nodep->name() == "toupper") {
3142 methodOkArguments(nodep, 0, 0);
3143 AstNode* const newp
3144 = new AstToUpperN(nodep->fileline(), nodep->fromp()->unlinkFrBack());
3145 nodep->replaceWith(newp);
3146 VL_DO_DANGLING(nodep->deleteTree(), nodep);
3147 } else if (nodep->name() == "compare" || nodep->name() == "icompare") {
3148 const bool ignoreCase = nodep->name()[0] == 'i';
3149 methodOkArguments(nodep, 1, 1);
3150 AstArg* const argp = VN_AS(nodep->pinsp(), Arg);
3151 AstNode* const lhs = nodep->fromp()->unlinkFrBack();
3152 AstNode* const rhs = argp->exprp()->unlinkFrBack();
3153 AstNode* const newp = new AstCompareNN(nodep->fileline(), lhs, rhs, ignoreCase);
3154 nodep->replaceWith(newp);
3155 VL_DO_DANGLING(nodep->deleteTree(), nodep);
3156 } else if (nodep->name() == "putc") {
3157 methodOkArguments(nodep, 2, 2);
3158 AstArg* const arg0p = VN_AS(nodep->pinsp(), Arg);
3159 AstArg* const arg1p = VN_AS(arg0p->nextp(), Arg);
3160 AstNodeVarRef* const fromp = VN_AS(nodep->fromp()->unlinkFrBack(), VarRef);
3161 AstNode* const rhsp = arg0p->exprp()->unlinkFrBack();
3162 AstNode* const thsp = arg1p->exprp()->unlinkFrBack();
3163 AstVarRef* const varrefp
3164 = new AstVarRef(nodep->fileline(), fromp->varp(), VAccess::READ);
3165 AstNode* const newp = new AstAssign(
3166 nodep->fileline(), fromp, new AstPutcN(nodep->fileline(), varrefp, rhsp, thsp));
3167 fromp->access(VAccess::WRITE);
3168 nodep->replaceWith(newp);
3169 VL_DO_DANGLING(nodep->deleteTree(), nodep);
3170 } else if (nodep->name() == "getc") {
3171 methodOkArguments(nodep, 1, 1);
3172 AstArg* const arg0p = VN_AS(nodep->pinsp(), Arg);
3173 AstNode* const lhsp = nodep->fromp()->unlinkFrBack();
3174 AstNode* const rhsp = arg0p->exprp()->unlinkFrBack();
3175 AstNode* const newp = new AstGetcN(nodep->fileline(), lhsp, rhsp);
3176 nodep->replaceWith(newp);
3177 VL_DO_DANGLING(nodep->deleteTree(), nodep);
3178 } else if (nodep->name() == "substr") {
3179 methodOkArguments(nodep, 2, 2);
3180 AstArg* const arg0p = VN_AS(nodep->pinsp(), Arg);
3181 AstArg* const arg1p = VN_AS(arg0p->nextp(), Arg);
3182 AstNode* const lhsp = nodep->fromp()->unlinkFrBack();
3183 AstNode* const rhsp = arg0p->exprp()->unlinkFrBack();
3184 AstNode* const thsp = arg1p->exprp()->unlinkFrBack();
3185 AstNode* const newp = new AstSubstrN(nodep->fileline(), lhsp, rhsp, thsp);
3186 nodep->replaceWith(newp);
3187 VL_DO_DANGLING(nodep->deleteTree(), nodep);
3188 } else if (nodep->name() == "atobin" || nodep->name() == "atohex"
3189 || nodep->name() == "atoi" || nodep->name() == "atooct"
3190 || nodep->name() == "atoreal") {
3191 AstAtoN::FmtType fmt;
3192 if (nodep->name() == "atobin") {
3193 fmt = AstAtoN::ATOBIN;
3194 } else if (nodep->name() == "atohex") {
3195 fmt = AstAtoN::ATOHEX;
3196 } else if (nodep->name() == "atoi") {
3197 fmt = AstAtoN::ATOI;
3198 } else if (nodep->name() == "atooct") {
3199 fmt = AstAtoN::ATOOCT;
3200 } else if (nodep->name() == "atoreal") {
3201 fmt = AstAtoN::ATOREAL;
3202 } else {
3203 V3ERROR_NA;
3204 fmt = AstAtoN::ATOI;
3205 } // dummy assignment to suppress compiler warning
3206 methodOkArguments(nodep, 0, 0);
3207 AstNode* const newp
3208 = new AstAtoN(nodep->fileline(), nodep->fromp()->unlinkFrBack(), fmt);
3209 nodep->replaceWith(newp);
3210 VL_DO_DANGLING(nodep->deleteTree(), nodep);
3211 } else {
3212 nodep->v3error("Unknown built-in string method " << nodep->prettyNameQ());
3213 }
3214 }
queueDTypeIndexedBy(AstNodeDType * indexDTypep)3215 AstQueueDType* queueDTypeIndexedBy(AstNodeDType* indexDTypep) {
3216 // Return a Queue data type with the specified index, remembering so can use again if
3217 // needed
3218 if (AstQueueDType* const queuep = m_queueDTypeIndexed[indexDTypep]) {
3219 return queuep;
3220 } else {
3221 auto* const newp = new AstQueueDType(indexDTypep->fileline(), indexDTypep, nullptr);
3222 v3Global.rootp()->typeTablep()->addTypesp(newp);
3223 m_queueDTypeIndexed[indexDTypep] = newp;
3224 return newp;
3225 }
3226 }
3227
visit(AstNew * nodep)3228 virtual void visit(AstNew* nodep) override {
3229 if (nodep->didWidth()) return;
3230 AstClassRefDType* const refp
3231 = m_vup ? VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType) : nullptr;
3232 if (!refp) { // e.g. int a = new;
3233 nodep->v3error("new() not expected in this context");
3234 return;
3235 }
3236 nodep->dtypep(refp);
3237
3238 AstClass* const classp = refp->classp();
3239 UASSERT_OBJ(classp, nodep, "Unlinked");
3240 if (AstNodeFTask* const ftaskp = VN_CAST(classp->findMember("new"), Func)) {
3241 nodep->taskp(ftaskp);
3242 nodep->classOrPackagep(classp);
3243 } else {
3244 // Either made explicitly or V3LinkDot made implicitly
3245 classp->v3fatalSrc("Can't find class's new");
3246 }
3247 if (classp->isVirtual()) {
3248 nodep->v3error(
3249 "Illegal to call 'new' using an abstract virtual class (IEEE 1800-2017 8.21)");
3250 }
3251 userIterate(nodep->taskp(), nullptr);
3252 processFTaskRefArgs(nodep);
3253 }
visit(AstNewCopy * nodep)3254 virtual void visit(AstNewCopy* nodep) override {
3255 if (nodep->didWidthAndSet()) return;
3256 AstClassRefDType* const refp = VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType);
3257 if (!refp) { // e.g. int a = new;
3258 nodep->v3error("new() not expected in this context");
3259 return;
3260 }
3261 nodep->dtypep(refp);
3262 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
3263 if (!similarDTypeRecurse(nodep->dtypep(), nodep->rhsp()->dtypep())) {
3264 nodep->rhsp()->v3error("New-as-copier passed different data type '"
3265 << nodep->dtypep()->prettyTypeName() << "' then expected '"
3266 << nodep->rhsp()->dtypep()->prettyTypeName() << "'");
3267 }
3268 }
visit(AstNewDynamic * nodep)3269 virtual void visit(AstNewDynamic* nodep) override {
3270 if (nodep->didWidthAndSet()) return;
3271 AstDynArrayDType* const adtypep = VN_CAST(m_vup->dtypeNullSkipRefp(), DynArrayDType);
3272 if (!adtypep) { // e.g. int a = new;
3273 nodep->v3error(
3274 "dynamic new() not expected in this context (data type must be dynamic array)");
3275 return;
3276 }
3277 // The AstNodeAssign visitor will be soon be replacing this node, make sure it gets it
3278 if (!VN_IS(nodep->backp(), NodeAssign)) {
3279 if (adtypep) UINFO(1, "Got backp " << nodep->backp() << endl);
3280 nodep->v3error(
3281 "dynamic new() not expected in this context (expected under an assign)");
3282 return;
3283 }
3284 nodep->dtypep(adtypep);
3285 if (m_vup && m_vup->prelim()) {
3286 iterateCheckSigned32(nodep, "new() size", nodep->sizep(), BOTH);
3287 }
3288 if (nodep->rhsp()) {
3289 iterateCheckTyped(nodep, "Dynamic array new RHS", nodep->rhsp(), adtypep, BOTH);
3290 }
3291 }
3292
visit(AstPattern * nodep)3293 virtual void visit(AstPattern* nodep) override {
3294 if (nodep->didWidthAndSet()) return;
3295 UINFO(9, "PATTERN " << nodep << endl);
3296 if (nodep->childDTypep()) { // data_type '{ pattern }
3297 nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
3298 }
3299 if (!nodep->dtypep() && m_vup->dtypeNullp()) { // Get it from parent assignment/pin/etc
3300 nodep->dtypep(m_vup->dtypep());
3301 }
3302 AstNodeDType* dtypep = nodep->dtypep();
3303 if (!dtypep) {
3304 nodep->v3warn(E_UNSUPPORTED, "Unsupported/Illegal: Assignment pattern"
3305 " member not underneath a supported construct: "
3306 << nodep->backp()->prettyTypeName());
3307 return;
3308 }
3309 {
3310 dtypep = dtypep->skipRefp();
3311 nodep->dtypep(dtypep);
3312 UINFO(9, " dtypep " << dtypep << endl);
3313 nodep->dtypep(dtypep);
3314 // Determine replication count, and replicate initial value as
3315 // widths need to be individually determined
3316 for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
3317 patp = VN_AS(patp->nextp(), PatMember)) {
3318 const int times = visitPatMemberRep(patp);
3319 for (int i = 1; i < times; i++) {
3320 AstNode* const newp = patp->cloneTree(false);
3321 patp->addNextHere(newp);
3322 // This loop will see the new elements as part of nextp()
3323 }
3324 }
3325 // Convert any PatMember with multiple items to multiple PatMembers
3326 for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
3327 patp = VN_AS(patp->nextp(), PatMember)) {
3328 if (patp->lhssp()->nextp()) {
3329 // Can't just addNext, as would add to end of all members.
3330 // So detach, add next and reattach
3331 AstNRelinker relinkHandle;
3332 patp->unlinkFrBack(&relinkHandle);
3333 while (AstNode* const movep = patp->lhssp()->nextp()) {
3334 movep->unlinkFrBack(); // Not unlinkFrBackWithNext, just one
3335 AstNode* newkeyp = nullptr;
3336 if (patp->keyp()) newkeyp = patp->keyp()->cloneTree(true);
3337 AstPatMember* const newp
3338 = new AstPatMember(patp->fileline(), movep, newkeyp, nullptr);
3339 patp->addNext(newp);
3340 }
3341 relinkHandle.relink(patp);
3342 }
3343 }
3344 AstPatMember* defaultp = nullptr;
3345 for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
3346 patp = VN_AS(patp->nextp(), PatMember)) {
3347 if (patp->isDefault()) {
3348 if (defaultp) nodep->v3error("Multiple '{ default: } clauses");
3349 defaultp = patp;
3350 patp->unlinkFrBack();
3351 }
3352 }
3353 while (const AstConstDType* const vdtypep = VN_CAST(dtypep, ConstDType)) {
3354 dtypep = vdtypep->subDTypep()->skipRefp();
3355 }
3356
3357 userIterate(dtypep, WidthVP(SELF, BOTH).p());
3358
3359 if (auto* const vdtypep = VN_CAST(dtypep, NodeUOrStructDType)) {
3360 VL_DO_DANGLING(patternUOrStruct(nodep, vdtypep, defaultp), nodep);
3361 } else if (auto* const vdtypep = VN_CAST(dtypep, NodeArrayDType)) {
3362 VL_DO_DANGLING(patternArray(nodep, vdtypep, defaultp), nodep);
3363 } else if (auto* const vdtypep = VN_CAST(dtypep, AssocArrayDType)) {
3364 VL_DO_DANGLING(patternAssoc(nodep, vdtypep, defaultp), nodep);
3365 } else if (auto* const vdtypep = VN_CAST(dtypep, DynArrayDType)) {
3366 VL_DO_DANGLING(patternDynArray(nodep, vdtypep, defaultp), nodep);
3367 } else if (auto* const vdtypep = VN_CAST(dtypep, QueueDType)) {
3368 VL_DO_DANGLING(patternQueue(nodep, vdtypep, defaultp), nodep);
3369 } else if (VN_IS(dtypep, BasicDType) && VN_AS(dtypep, BasicDType)->isRanged()) {
3370 VL_DO_DANGLING(patternBasic(nodep, dtypep, defaultp), nodep);
3371 } else {
3372 nodep->v3warn(
3373 E_UNSUPPORTED,
3374 "Unsupported: Assignment pattern applies against non struct/union data type: "
3375 << dtypep->prettyDTypeNameQ());
3376 }
3377 }
3378 }
patternUOrStruct(AstPattern * nodep,AstNodeUOrStructDType * vdtypep,AstPatMember * defaultp)3379 void patternUOrStruct(AstPattern* nodep, AstNodeUOrStructDType* vdtypep,
3380 AstPatMember* defaultp) {
3381 // Due to "default" and tagged patterns, we need to determine
3382 // which member each AstPatMember corresponds to before we can
3383 // determine the dtypep for that PatMember's value, and then
3384 // width the initial value appropriately.
3385 using PatMap = std::map<const AstMemberDType*, AstPatMember*>;
3386 PatMap patmap;
3387 {
3388 const AstMemberDType* memp = vdtypep->membersp();
3389 AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember);
3390 for (; memp || patp;) {
3391 do {
3392 if (patp) {
3393 if (patp->keyp()) {
3394 if (const AstText* textp = VN_CAST(patp->keyp(), Text)) {
3395 memp = vdtypep->findMember(textp->text());
3396 if (!memp) {
3397 patp->keyp()->v3error("Assignment pattern key '"
3398 << textp->text()
3399 << "' not found as member");
3400 break;
3401 }
3402 } else {
3403 patp->keyp()->v3error(
3404 "Assignment pattern key not supported/understood: "
3405 << patp->keyp()->prettyTypeName());
3406 }
3407 }
3408 }
3409 if (memp && !patp) {
3410 // Missing init elements, warn below
3411 memp = nullptr;
3412 patp = nullptr;
3413 break;
3414 } else if (!memp && patp) {
3415 patp->v3error("Assignment pattern contains too many elements");
3416 memp = nullptr;
3417 patp = nullptr;
3418 break;
3419 } else {
3420 const std::pair<PatMap::iterator, bool> ret = patmap.emplace(memp, patp);
3421 if (!ret.second) {
3422 patp->v3error("Assignment pattern contains duplicate entry: "
3423 << VN_AS(patp->keyp(), Text)->text());
3424 }
3425 }
3426 } while (false);
3427 // Next
3428 if (memp) memp = VN_AS(memp->nextp(), MemberDType);
3429 if (patp) patp = VN_AS(patp->nextp(), PatMember);
3430 }
3431 }
3432 AstNode* newp = nullptr;
3433 for (AstMemberDType* memp = vdtypep->membersp(); memp;
3434 memp = VN_AS(memp->nextp(), MemberDType)) {
3435 const auto it = patmap.find(memp);
3436 AstPatMember* newpatp = nullptr;
3437 AstPatMember* patp = nullptr;
3438 if (it == patmap.end()) {
3439 if (defaultp) {
3440 newpatp = defaultp->cloneTree(false);
3441 patp = newpatp;
3442 } else {
3443 if (!VN_IS(vdtypep, UnionDType)) {
3444 nodep->v3error("Assignment pattern missed initializing elements: "
3445 << memp->prettyTypeName());
3446 }
3447 }
3448 } else {
3449 patp = it->second;
3450 }
3451 if (patp) {
3452 // Determine initial values
3453 patp->dtypep(memp);
3454 AstNode* const valuep = patternMemberValueIterate(patp);
3455 if (!newp) {
3456 newp = valuep;
3457 } else {
3458 AstConcat* const concatp = new AstConcat(patp->fileline(), newp, valuep);
3459 newp = concatp;
3460 newp->dtypeSetLogicSized(concatp->lhsp()->width() + concatp->rhsp()->width(),
3461 nodep->dtypep()->numeric());
3462 }
3463 }
3464 if (newpatp) VL_DO_DANGLING(pushDeletep(newpatp), newpatp);
3465 }
3466 if (newp) {
3467 nodep->replaceWith(newp);
3468 } else {
3469 nodep->v3error("Assignment pattern with no members");
3470 }
3471 VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
3472 }
patternArray(AstPattern * nodep,AstNodeArrayDType * arrayDtp,AstPatMember * defaultp)3473 void patternArray(AstPattern* nodep, AstNodeArrayDType* arrayDtp, AstPatMember* defaultp) {
3474 const VNumRange range = arrayDtp->declRange();
3475 PatVecMap patmap = patVectorMap(nodep, range);
3476 UINFO(9, "ent " << range.left() << " to " << range.right() << endl);
3477 AstNode* newp = nullptr;
3478 for (int entn = 0, ent = range.left(); entn < range.elements();
3479 ++entn, ent += range.leftToRightInc()) {
3480 AstPatMember* newpatp = nullptr;
3481 AstPatMember* patp = nullptr;
3482 const auto it = patmap.find(ent);
3483 if (it == patmap.end()) {
3484 if (defaultp) {
3485 newpatp = defaultp->cloneTree(false);
3486 patp = newpatp;
3487 } else {
3488 nodep->v3error("Assignment pattern missed initializing elements: " << ent);
3489 }
3490 } else {
3491 patp = it->second;
3492 patmap.erase(it);
3493 }
3494
3495 if (patp) {
3496 // Don't want the RHS an array
3497 patp->dtypep(arrayDtp->subDTypep());
3498 AstNode* const valuep = patternMemberValueIterate(patp);
3499 if (VN_IS(arrayDtp, UnpackArrayDType)) {
3500 if (!newp) {
3501 AstInitArray* const newap
3502 = new AstInitArray(nodep->fileline(), arrayDtp, nullptr);
3503 newp = newap;
3504 }
3505 VN_AS(newp, InitArray)->addIndexValuep(ent - range.lo(), valuep);
3506 } else { // Packed. Convert to concat for now.
3507 if (!newp) {
3508 newp = valuep;
3509 } else {
3510 AstConcat* const concatp = new AstConcat(patp->fileline(), newp, valuep);
3511 newp = concatp;
3512 newp->dtypeSetLogicSized(concatp->lhsp()->width()
3513 + concatp->rhsp()->width(),
3514 nodep->dtypep()->numeric());
3515 }
3516 }
3517 }
3518 if (newpatp) VL_DO_DANGLING(pushDeletep(newpatp), newpatp);
3519 }
3520 if (!patmap.empty()) nodep->v3error("Assignment pattern with too many elements");
3521 if (newp) {
3522 nodep->replaceWith(newp);
3523 } else {
3524 nodep->v3error("Assignment pattern with no members");
3525 }
3526 // if (debug() >= 9) newp->dumpTree("-apat-out: ");
3527 VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
3528 }
patternAssoc(AstPattern * nodep,AstAssocArrayDType * arrayDtp,AstPatMember * defaultp)3529 void patternAssoc(AstPattern* nodep, AstAssocArrayDType* arrayDtp, AstPatMember* defaultp) {
3530 AstNode* defaultValuep = nullptr;
3531 if (defaultp) defaultValuep = defaultp->lhssp()->unlinkFrBack();
3532 AstNode* newp = new AstConsAssoc(nodep->fileline(), defaultValuep);
3533 newp->dtypeFrom(arrayDtp);
3534 for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
3535 patp = VN_AS(patp->nextp(), PatMember)) {
3536 patp->dtypep(arrayDtp->subDTypep());
3537 AstNode* const valuep = patternMemberValueIterate(patp);
3538 AstNode* const keyp = patp->keyp();
3539 auto* const newap
3540 = new AstSetAssoc(nodep->fileline(), newp, keyp->unlinkFrBack(), valuep);
3541 newap->dtypeFrom(arrayDtp);
3542 newp = newap;
3543 }
3544 nodep->replaceWith(newp);
3545 // if (debug() >= 9) newp->dumpTree("-apat-out: ");
3546 VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
3547 }
patternDynArray(AstPattern * nodep,AstDynArrayDType * arrayp,AstPatMember *)3548 void patternDynArray(AstPattern* nodep, AstDynArrayDType* arrayp, AstPatMember*) {
3549 AstNode* newp = new AstConsDynArray(nodep->fileline());
3550 newp->dtypeFrom(arrayp);
3551 for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
3552 patp = VN_AS(patp->nextp(), PatMember)) {
3553 patp->dtypep(arrayp->subDTypep());
3554 AstNode* const valuep = patternMemberValueIterate(patp);
3555 auto* const newap = new AstConsDynArray(nodep->fileline(), valuep, newp);
3556 newap->dtypeFrom(arrayp);
3557 newp = newap;
3558 }
3559 nodep->replaceWith(newp);
3560 // if (debug() >= 9) newp->dumpTree("-apat-out: ");
3561 VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
3562 }
patternQueue(AstPattern * nodep,AstQueueDType * arrayp,AstPatMember *)3563 void patternQueue(AstPattern* nodep, AstQueueDType* arrayp, AstPatMember*) {
3564 AstNode* newp = new AstConsQueue(nodep->fileline());
3565 newp->dtypeFrom(arrayp);
3566 for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
3567 patp = VN_AS(patp->nextp(), PatMember)) {
3568 patp->dtypep(arrayp->subDTypep());
3569 AstNode* const valuep = patternMemberValueIterate(patp);
3570 auto* const newap = new AstConsQueue(nodep->fileline(), valuep, newp);
3571 newap->dtypeFrom(arrayp);
3572 newp = newap;
3573 }
3574 nodep->replaceWith(newp);
3575 // if (debug() >= 9) newp->dumpTree("-apat-out: ");
3576 VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
3577 }
patternBasic(AstPattern * nodep,AstNodeDType * vdtypep,AstPatMember * defaultp)3578 void patternBasic(AstPattern* nodep, AstNodeDType* vdtypep, AstPatMember* defaultp) {
3579 const AstBasicDType* bdtypep = VN_AS(vdtypep, BasicDType);
3580 const VNumRange range = bdtypep->declRange();
3581 PatVecMap patmap = patVectorMap(nodep, range);
3582 UINFO(9, "ent " << range.hi() << " to " << range.lo() << endl);
3583 AstNode* newp = nullptr;
3584 for (int ent = range.hi(); ent >= range.lo(); --ent) {
3585 AstPatMember* newpatp = nullptr;
3586 AstPatMember* patp = nullptr;
3587 const auto it = patmap.find(ent);
3588 if (it == patmap.end()) {
3589 if (defaultp) {
3590 newpatp = defaultp->cloneTree(false);
3591 patp = newpatp;
3592 } else {
3593 nodep->v3error("Assignment pattern missed initializing elements: " << ent);
3594 }
3595 } else {
3596 patp = it->second;
3597 patmap.erase(it);
3598 }
3599 if (patp) {
3600 // Determine initial values
3601 vdtypep = nodep->findBitDType();
3602 patp->dtypep(vdtypep);
3603 AstNode* const valuep = patternMemberValueIterate(patp);
3604 { // Packed. Convert to concat for now.
3605 if (!newp) {
3606 newp = valuep;
3607 } else {
3608 AstConcat* const concatp = new AstConcat(patp->fileline(), newp, valuep);
3609 newp = concatp;
3610 newp->dtypeSetLogicSized(concatp->lhsp()->width()
3611 + concatp->rhsp()->width(),
3612 nodep->dtypep()->numeric());
3613 }
3614 }
3615 }
3616 if (newpatp) VL_DO_DANGLING(pushDeletep(newpatp), newpatp);
3617 }
3618 if (!patmap.empty()) nodep->v3error("Assignment pattern with too many elements");
3619 if (newp) {
3620 nodep->replaceWith(newp);
3621 } else {
3622 nodep->v3error("Assignment pattern with no members");
3623 }
3624 // if (debug() >= 9) newp->dumpTree("-apat-out: ");
3625 VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
3626 }
patternMemberValueIterate(AstPatMember * patp)3627 AstNode* patternMemberValueIterate(AstPatMember* patp) {
3628 // Determine values - might be another InitArray
3629 userIterate(patp, WidthVP(patp->dtypep(), BOTH).p());
3630 // Convert to InitArray or constify immediately
3631 AstNode* valuep = patp->lhssp()->unlinkFrBack();
3632 if (VN_IS(valuep, Const)) {
3633 // Forming a AstConcat will cause problems with
3634 // unsized (uncommitted sized) constants
3635 if (AstNode* const newp
3636 = WidthCommitVisitor::newIfConstCommitSize(VN_AS(valuep, Const))) {
3637 VL_DO_DANGLING(pushDeletep(valuep), valuep);
3638 valuep = newp;
3639 }
3640 }
3641 return valuep;
3642 }
3643
visit(AstPatMember * nodep)3644 virtual void visit(AstPatMember* nodep) override {
3645 AstNodeDType* const vdtypep = m_vup->dtypeNullp();
3646 UASSERT_OBJ(vdtypep, nodep, "Pattern member type not assigned by AstPattern visitor");
3647 nodep->dtypep(vdtypep);
3648 UINFO(9, " PATMEMBER " << nodep << endl);
3649 UASSERT_OBJ(!nodep->lhssp()->nextp(), nodep,
3650 "PatMember value should be singular w/replicates removed");
3651 // Need to propagate assignment type downwards, even on prelim
3652 userIterateChildren(nodep, WidthVP(nodep->dtypep(), PRELIM).p());
3653 iterateCheck(nodep, "Pattern value", nodep->lhssp(), ASSIGN, FINAL, vdtypep, EXTEND_LHS);
3654 }
visitPatMemberRep(AstPatMember * nodep)3655 int visitPatMemberRep(AstPatMember* nodep) {
3656 uint32_t times = 1;
3657 if (nodep->repp()) { // else repp()==nullptr shorthand for rep count 1
3658 iterateCheckSizedSelf(nodep, "LHS", nodep->repp(), SELF, BOTH);
3659 V3Const::constifyParamsEdit(nodep->repp()); // repp may change
3660 const AstConst* const constp = VN_CAST(nodep->repp(), Const);
3661 if (!constp) {
3662 nodep->v3error("Replication value isn't a constant.");
3663 times = 0;
3664 } else {
3665 times = constp->toUInt();
3666 }
3667 if (times == 0) {
3668 nodep->v3error("Pattern replication value of 0 is not legal.");
3669 times = 1;
3670 }
3671 nodep->repp()
3672 ->unlinkFrBackWithNext()
3673 ->deleteTree(); // Done with replicate before cloning
3674 }
3675 return times;
3676 }
3677
visit(AstPropClocked * nodep)3678 virtual void visit(AstPropClocked* nodep) override {
3679 if (m_vup->prelim()) { // First stage evaluation
3680 iterateCheckBool(nodep, "Property", nodep->propp(), BOTH);
3681 userIterateAndNext(nodep->sensesp(), nullptr);
3682 if (nodep->disablep()) {
3683 iterateCheckBool(nodep, "Disable", nodep->disablep(),
3684 BOTH); // it's like an if() condition.
3685 }
3686 nodep->dtypeSetBit();
3687 }
3688 }
3689
3690 //--------------------
3691 // Top levels
3692
visit(AstNodeCase * nodep)3693 virtual void visit(AstNodeCase* nodep) override {
3694 // IEEE-2012 12.5:
3695 // Width: MAX(expr, all items)
3696 // Signed: Only if expr, and all items signed
3697 assertAtStatement(nodep);
3698 userIterateAndNext(nodep->exprp(), WidthVP(CONTEXT, PRELIM).p());
3699 for (AstCaseItem *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
3700 nextip = VN_AS(itemp->nextp(), CaseItem); // Prelim may cause the node to get replaced
3701 if (!VN_IS(nodep, GenCase)) userIterateAndNext(itemp->bodysp(), nullptr);
3702 for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) {
3703 nextcp = condp->nextp(); // Prelim may cause the node to get replaced
3704 VL_DO_DANGLING(userIterate(condp, WidthVP(CONTEXT, PRELIM).p()), condp);
3705 }
3706 }
3707
3708 // Take width as maximum across all items, if any is real whole thing is real
3709 AstNodeDType* subDTypep = nodep->exprp()->dtypep();
3710 for (AstCaseItem* itemp = nodep->itemsp(); itemp;
3711 itemp = VN_AS(itemp->nextp(), CaseItem)) {
3712 for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) {
3713 if (condp->dtypep() != subDTypep) {
3714 if (condp->dtypep()->isDouble()) {
3715 subDTypep = nodep->findDoubleDType();
3716 } else {
3717 const int width = std::max(subDTypep->width(), condp->width());
3718 const int mwidth = std::max(subDTypep->widthMin(), condp->widthMin());
3719 const bool issigned = subDTypep->isSigned() && condp->isSigned();
3720 subDTypep
3721 = nodep->findLogicDType(width, mwidth, VSigning::fromBool(issigned));
3722 }
3723 }
3724 }
3725 }
3726 // Apply width
3727 iterateCheck(nodep, "Case expression", nodep->exprp(), CONTEXT, FINAL, subDTypep,
3728 EXTEND_LHS);
3729 for (AstCaseItem* itemp = nodep->itemsp(); itemp;
3730 itemp = VN_AS(itemp->nextp(), CaseItem)) {
3731 for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) {
3732 nextcp = condp->nextp(); // Final may cause the node to get replaced
3733 iterateCheck(nodep, "Case Item", condp, CONTEXT, FINAL, subDTypep, EXTEND_LHS);
3734 }
3735 }
3736 }
visit(AstNodeFor * nodep)3737 virtual void visit(AstNodeFor* nodep) override {
3738 assertAtStatement(nodep);
3739 userIterateAndNext(nodep->initsp(), nullptr);
3740 iterateCheckBool(nodep, "For Test Condition", nodep->condp(),
3741 BOTH); // it's like an if() condition.
3742 if (!VN_IS(nodep, GenFor)) userIterateAndNext(nodep->bodysp(), nullptr);
3743 userIterateAndNext(nodep->incsp(), nullptr);
3744 }
visit(AstRepeat * nodep)3745 virtual void visit(AstRepeat* nodep) override {
3746 assertAtStatement(nodep);
3747 userIterateAndNext(nodep->countp(), WidthVP(SELF, BOTH).p());
3748 userIterateAndNext(nodep->bodysp(), nullptr);
3749 }
visit(AstWhile * nodep)3750 virtual void visit(AstWhile* nodep) override {
3751 assertAtStatement(nodep);
3752 userIterateAndNext(nodep->precondsp(), nullptr);
3753 iterateCheckBool(nodep, "For Test Condition", nodep->condp(),
3754 BOTH); // it's like an if() condition.
3755 userIterateAndNext(nodep->bodysp(), nullptr);
3756 userIterateAndNext(nodep->incsp(), nullptr);
3757 }
visit(AstNodeIf * nodep)3758 virtual void visit(AstNodeIf* nodep) override {
3759 assertAtStatement(nodep);
3760 // if (debug()) nodep->dumpTree(cout, " IfPre: ");
3761 if (!VN_IS(nodep, GenIf)) { // for m_paramsOnly
3762 userIterateAndNext(nodep->ifsp(), nullptr);
3763 userIterateAndNext(nodep->elsesp(), nullptr);
3764 }
3765 iterateCheckBool(nodep, "If", nodep->condp(), BOTH); // it's like an if() condition.
3766 // if (debug()) nodep->dumpTree(cout, " IfOut: ");
3767 }
visit(AstExprStmt * nodep)3768 virtual void visit(AstExprStmt* nodep) override {
3769 userIterateAndNext(nodep->stmtsp(), nullptr);
3770 // expected result is same as parent's expected result
3771 userIterateAndNext(nodep->resultp(), m_vup);
3772 nodep->dtypeFrom(nodep->resultp());
3773 }
3774
visit(AstNodeAssign * nodep)3775 virtual void visit(AstNodeAssign* nodep) override {
3776 // IEEE-2012 10.7, 11.8.2, 11.8.3, 11.5: (Careful of 11.8.1 which is
3777 // only one step; final dtype depends on assign LHS.)
3778 // Determine RHS type width and signing
3779 // Propagate type down to *non-self-determined* operators
3780 // Real propagates only across one operator if one side is real -
3781 // handled in each visitor.
3782 // Then LHS sign-extends only if *RHS* is signed
3783 assertAtStatement(nodep);
3784 // if (debug()) nodep->dumpTree(cout, " AssignPre: ");
3785 {
3786 // if (debug()) nodep->dumpTree(cout, "- assin: ");
3787 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
3788 UASSERT_OBJ(nodep->lhsp()->dtypep(), nodep, "How can LHS be untyped?");
3789 UASSERT_OBJ(nodep->lhsp()->dtypep()->widthSized(), nodep, "How can LHS be unsized?");
3790 nodep->dtypeFrom(nodep->lhsp());
3791 //
3792 // AstPattern needs to know the proposed data type of the lhs, so pass on the prelim
3793 userIterateAndNext(nodep->rhsp(), WidthVP(nodep->dtypep(), PRELIM).p());
3794 //
3795 // if (debug()) nodep->dumpTree(cout, "- assign: ");
3796 AstNodeDType* const lhsDTypep
3797 = nodep->lhsp()->dtypep(); // Note we use rhsp for context determined
3798 iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep);
3799 // if (debug()) nodep->dumpTree(cout, " AssignOut: ");
3800 }
3801 if (const AstBasicDType* const basicp = nodep->rhsp()->dtypep()->basicp()) {
3802 if (basicp->isEventValue()) {
3803 // see t_event_copy.v for commentary on the mess involved
3804 nodep->v3warn(E_UNSUPPORTED, "Unsupported: assignment of event data type");
3805 }
3806 }
3807 if (VN_IS(nodep->rhsp(), EmptyQueue)) {
3808 UINFO(9, "= {} -> .delete(): " << nodep);
3809 if (!VN_IS(nodep->lhsp()->dtypep()->skipRefp(), QueueDType)) {
3810 nodep->v3warn(E_UNSUPPORTED,
3811 "Unsupported/Illegal: empty queue ('{}') in this assign context");
3812 VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
3813 return;
3814 }
3815 AstMethodCall* const newp = new AstMethodCall{
3816 nodep->fileline(), nodep->lhsp()->unlinkFrBack(), "delete", nullptr};
3817 newp->makeStatement();
3818 nodep->replaceWith(newp);
3819 VL_DO_DANGLING(pushDeletep(nodep), nodep);
3820 // Need to now convert it
3821 visit(newp);
3822 return;
3823 }
3824 if (const AstNewDynamic* const dynp = VN_CAST(nodep->rhsp(), NewDynamic)) {
3825 UINFO(9, "= new[] -> .resize(): " << nodep);
3826 AstCMethodHard* newp;
3827 if (!dynp->rhsp()) {
3828 newp = new AstCMethodHard(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
3829 "renew", dynp->sizep()->unlinkFrBack());
3830 } else {
3831 newp = new AstCMethodHard(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
3832 "renew_copy", dynp->sizep()->unlinkFrBack());
3833 newp->addPinsp(dynp->rhsp()->unlinkFrBack());
3834 }
3835 newp->didWidth(true);
3836 newp->protect(false);
3837 newp->makeStatement();
3838 nodep->replaceWith(newp);
3839 VL_DO_DANGLING(pushDeletep(nodep), nodep);
3840 // return;
3841 }
3842 }
3843
visit(AstSFormatF * nodep)3844 virtual void visit(AstSFormatF* nodep) override {
3845 // Excludes NodeDisplay, see below
3846 if (m_vup && !m_vup->prelim()) return; // Can be called as statement or function
3847 // Just let all arguments seek their natural sizes
3848 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
3849 //
3850 UINFO(9, " Display in " << nodep->text() << endl);
3851 string newFormat;
3852 bool inPct = false;
3853 AstNode* argp = nodep->exprsp();
3854 const string txt = nodep->text();
3855 string fmt;
3856 for (char ch : txt) {
3857 if (!inPct && ch == '%') {
3858 inPct = true;
3859 fmt = ch;
3860 } else if (inPct && (isdigit(ch) || ch == '.' || ch == '-')) {
3861 fmt += ch;
3862 } else if (tolower(inPct)) {
3863 inPct = false;
3864 bool added = false;
3865 switch (tolower(ch)) {
3866 case '%': break; // %% - just output a %
3867 case 'm': break; // %m - auto insert "name"
3868 case 'l': break; // %m - auto insert "library"
3869 case 'd': { // Convert decimal to either 'd' or '#'
3870 if (argp) {
3871 AstNode* const nextp = argp->nextp();
3872 if (argp->isDouble()) {
3873 spliceCvtS(argp, true, 64);
3874 ch = '~';
3875 } else if (argp->isSigned()) { // Convert it
3876 ch = '~';
3877 }
3878 argp = nextp;
3879 }
3880 break;
3881 }
3882 case 'p': { // Pattern
3883 const AstNodeDType* const dtypep = argp ? argp->dtypep()->skipRefp() : nullptr;
3884 const AstBasicDType* const basicp = dtypep ? dtypep->basicp() : nullptr;
3885 if (basicp && basicp->isString()) {
3886 added = true;
3887 newFormat += "\"%@\"";
3888 } else if (basicp && basicp->isDouble()) {
3889 added = true;
3890 newFormat += "%g";
3891 } else if (VN_IS(dtypep, AssocArrayDType) //
3892 || VN_IS(dtypep, ClassRefDType) //
3893 || VN_IS(dtypep, DynArrayDType) //
3894 || VN_IS(dtypep, QueueDType)) {
3895 added = true;
3896 newFormat += "%@";
3897 AstNRelinker handle;
3898 argp->unlinkFrBack(&handle);
3899 AstCMath* const newp
3900 = new AstCMath(nodep->fileline(), "VL_TO_STRING(", 0, true);
3901 newp->addBodysp(argp);
3902 newp->addBodysp(new AstText(nodep->fileline(), ")", true));
3903 newp->dtypeSetString();
3904 newp->pure(true);
3905 newp->protect(false);
3906 handle.relink(newp);
3907 } else {
3908 added = true;
3909 if (fmt == "%0") {
3910 newFormat += "'h%0h"; // IEEE our choice
3911 } else {
3912 newFormat += "%d";
3913 }
3914 }
3915 if (argp) argp = argp->nextp();
3916 break;
3917 }
3918 case 's': { // Convert string to pack string
3919 if (argp && argp->dtypep()->basicp()->isString()) { // Convert it
3920 ch = '@';
3921 }
3922 if (argp) argp = argp->nextp();
3923 break;
3924 }
3925 case 't': { // Convert decimal time to realtime
3926 if (argp) {
3927 AstNode* const nextp = argp->nextp();
3928 if (argp->isDouble()) ch = '^'; // Convert it
3929 if (nodep->timeunit().isNone()) {
3930 nodep->v3fatalSrc("display %t has no time units");
3931 }
3932 argp = nextp;
3933 }
3934 break;
3935 }
3936 case 'f': // FALLTHRU
3937 case 'g': {
3938 if (argp) {
3939 AstNode* const nextp = argp->nextp();
3940 if (!argp->isDouble()) {
3941 iterateCheckReal(nodep, "Display argument", argp, BOTH);
3942 }
3943 argp = nextp;
3944 }
3945 break;
3946 }
3947 case '?': { // Unspecified by user, guess
3948 if (argp && argp->isDouble()) {
3949 ch = 'g';
3950 } else if (argp && argp->isString()) {
3951 ch = '@';
3952 } else if (nodep->missingArgChar() == 'd' && argp->isSigned()) {
3953 ch = '~';
3954 } else {
3955 ch = nodep->missingArgChar();
3956 }
3957 if (argp) argp = argp->nextp();
3958 break;
3959 }
3960 default: { // Most operators, just move to next argument
3961 if (argp) argp = argp->nextp();
3962 break;
3963 }
3964 } // switch
3965 if (!added) {
3966 fmt += ch;
3967 newFormat += fmt;
3968 }
3969 } else {
3970 newFormat += ch;
3971 }
3972 }
3973 nodep->text(newFormat);
3974 UINFO(9, " Display out " << nodep->text() << endl);
3975 }
visit(AstDisplay * nodep)3976 virtual void visit(AstDisplay* nodep) override {
3977 assertAtStatement(nodep);
3978 if (nodep->filep()) iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
3979 // Just let all arguments seek their natural sizes
3980 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
3981 }
visit(AstElabDisplay * nodep)3982 virtual void visit(AstElabDisplay* nodep) override {
3983 assertAtStatement(nodep);
3984 // Just let all arguments seek their natural sizes
3985 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
3986 if (!m_paramsOnly) {
3987 V3Const::constifyParamsEdit(nodep->fmtp()); // fmtp may change
3988 string text = nodep->fmtp()->text();
3989 if (text.empty()) text = "Elaboration system task message (IEEE 1800-2017 20.11)";
3990 switch (nodep->displayType()) {
3991 case AstDisplayType::DT_INFO: nodep->v3warn(USERINFO, text); break;
3992 case AstDisplayType::DT_ERROR: nodep->v3warn(USERERROR, text); break;
3993 case AstDisplayType::DT_WARNING: nodep->v3warn(USERWARN, text); break;
3994 case AstDisplayType::DT_FATAL: nodep->v3warn(USERFATAL, text); break;
3995 default: UASSERT_OBJ(false, nodep, "Unexpected elaboration display type");
3996 }
3997 VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
3998 }
3999 }
visit(AstDumpCtl * nodep)4000 virtual void visit(AstDumpCtl* nodep) override {
4001 assertAtStatement(nodep);
4002 // Just let all arguments seek their natural sizes
4003 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
4004 }
visit(AstFOpen * nodep)4005 virtual void visit(AstFOpen* nodep) override {
4006 // Although a system function in IEEE, here a statement which sets the file pointer (MCD)
4007 assertAtStatement(nodep);
4008 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4009 userIterateAndNext(nodep->filenamep(), WidthVP(SELF, BOTH).p());
4010 userIterateAndNext(nodep->modep(), WidthVP(SELF, BOTH).p());
4011 }
visit(AstFOpenMcd * nodep)4012 virtual void visit(AstFOpenMcd* nodep) override {
4013 assertAtStatement(nodep);
4014 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4015 userIterateAndNext(nodep->filenamep(), WidthVP(SELF, BOTH).p());
4016 }
visit(AstFClose * nodep)4017 virtual void visit(AstFClose* nodep) override {
4018 assertAtStatement(nodep);
4019 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4020 }
visit(AstFError * nodep)4021 virtual void visit(AstFError* nodep) override {
4022 if (m_vup->prelim()) {
4023 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4024 // We only support string types, not packed array
4025 iterateCheckString(nodep, "$ferror string result", nodep->strp(), BOTH);
4026 nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return
4027 }
4028 }
visit(AstFEof * nodep)4029 virtual void visit(AstFEof* nodep) override {
4030 if (m_vup->prelim()) {
4031 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4032 nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return
4033 }
4034 }
visit(AstFFlush * nodep)4035 virtual void visit(AstFFlush* nodep) override {
4036 assertAtStatement(nodep);
4037 if (nodep->filep()) iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4038 }
visit(AstFRewind * nodep)4039 virtual void visit(AstFRewind* nodep) override {
4040 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4041 nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return
4042 }
visit(AstFTell * nodep)4043 virtual void visit(AstFTell* nodep) override {
4044 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4045 nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return
4046 }
visit(AstFSeek * nodep)4047 virtual void visit(AstFSeek* nodep) override {
4048 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4049 iterateCheckSigned32(nodep, "$fseek offset", nodep->offset(), BOTH);
4050 iterateCheckSigned32(nodep, "$fseek operation", nodep->operation(), BOTH);
4051 nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return
4052 }
visit(AstFGetC * nodep)4053 virtual void visit(AstFGetC* nodep) override {
4054 if (m_vup->prelim()) {
4055 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4056 nodep->dtypeSetLogicUnsized(32, 8, VSigning::SIGNED); // Spec says integer return
4057 }
4058 }
visit(AstFGetS * nodep)4059 virtual void visit(AstFGetS* nodep) override {
4060 if (m_vup->prelim()) {
4061 nodep->dtypeSetSigned32(); // Spec says integer return
4062 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4063 userIterateAndNext(nodep->strgp(), WidthVP(SELF, BOTH).p());
4064 }
4065 }
visit(AstFUngetC * nodep)4066 virtual void visit(AstFUngetC* nodep) override {
4067 if (m_vup->prelim()) {
4068 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4069 iterateCheckSigned32(nodep, "$fungetc character", nodep->charp(), BOTH);
4070 nodep->dtypeSetLogicUnsized(32, 8, VSigning::SIGNED); // Spec says integer return
4071 }
4072 }
visit(AstFRead * nodep)4073 virtual void visit(AstFRead* nodep) override {
4074 if (m_vup->prelim()) {
4075 nodep->dtypeSetSigned32(); // Spec says integer return
4076 userIterateAndNext(nodep->memp(), WidthVP(SELF, BOTH).p());
4077 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4078 if (nodep->startp()) {
4079 iterateCheckSigned32(nodep, "$fread start", nodep->startp(), BOTH);
4080 }
4081 if (nodep->countp()) {
4082 iterateCheckSigned32(nodep, "$fread count", nodep->countp(), BOTH);
4083 }
4084 }
4085 }
visit(AstFScanF * nodep)4086 virtual void visit(AstFScanF* nodep) override {
4087 if (m_vup->prelim()) {
4088 nodep->dtypeSetSigned32(); // Spec says integer return
4089 iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
4090 userIterateAndNext(nodep->exprsp(), WidthVP(SELF, BOTH).p());
4091 }
4092 }
visit(AstSScanF * nodep)4093 virtual void visit(AstSScanF* nodep) override {
4094 if (m_vup->prelim()) {
4095 nodep->dtypeSetSigned32(); // Spec says integer return
4096 userIterateAndNext(nodep->fromp(), WidthVP(SELF, BOTH).p());
4097 userIterateAndNext(nodep->exprsp(), WidthVP(SELF, BOTH).p());
4098 }
4099 }
visit(AstSysIgnore * nodep)4100 virtual void visit(AstSysIgnore* nodep) override {
4101 userIterateAndNext(nodep->exprsp(), WidthVP(SELF, BOTH).p());
4102 }
visit(AstSystemF * nodep)4103 virtual void visit(AstSystemF* nodep) override {
4104 if (m_vup->prelim()) {
4105 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
4106 nodep->dtypeSetSigned32(); // Spec says integer return
4107 }
4108 }
visit(AstSysFuncAsTask * nodep)4109 virtual void visit(AstSysFuncAsTask* nodep) override {
4110 assertAtStatement(nodep);
4111 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
4112 }
visit(AstSystemT * nodep)4113 virtual void visit(AstSystemT* nodep) override {
4114 assertAtStatement(nodep);
4115 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
4116 }
visit(AstNodeReadWriteMem * nodep)4117 virtual void visit(AstNodeReadWriteMem* nodep) override {
4118 assertAtStatement(nodep);
4119 userIterateAndNext(nodep->filenamep(), WidthVP(SELF, BOTH).p());
4120 userIterateAndNext(nodep->memp(), WidthVP(SELF, BOTH).p());
4121 const AstNodeDType* subp = nullptr;
4122 if (const AstAssocArrayDType* adtypep
4123 = VN_CAST(nodep->memp()->dtypep()->skipRefp(), AssocArrayDType)) {
4124 subp = adtypep->subDTypep();
4125 if (!adtypep->keyDTypep()->skipRefp()->basicp()
4126 || !adtypep->keyDTypep()->skipRefp()->basicp()->keyword().isIntNumeric()) {
4127 nodep->memp()->v3error(nodep->verilogKwd()
4128 << " address/key must be integral (IEEE 1800-2017 21.4.1)");
4129 }
4130 } else if (const AstUnpackArrayDType* const adtypep
4131 = VN_CAST(nodep->memp()->dtypep()->skipRefp(), UnpackArrayDType)) {
4132 subp = adtypep->subDTypep();
4133 } else {
4134 nodep->memp()->v3warn(E_UNSUPPORTED,
4135 "Unsupported: "
4136 << nodep->verilogKwd()
4137 << " into other than unpacked or associative array");
4138 }
4139 if (subp
4140 && (!subp->skipRefp()->basicp()
4141 || !subp->skipRefp()->basicp()->keyword().isIntNumeric())) {
4142 nodep->memp()->v3warn(E_UNSUPPORTED,
4143 "Unsupported: " << nodep->verilogKwd()
4144 << " array values must be integral");
4145 }
4146 userIterateAndNext(nodep->lsbp(), WidthVP(SELF, BOTH).p());
4147 userIterateAndNext(nodep->msbp(), WidthVP(SELF, BOTH).p());
4148 }
visit(AstValuePlusArgs * nodep)4149 virtual void visit(AstValuePlusArgs* nodep) override {
4150 if (m_vup->prelim()) {
4151 userIterateAndNext(nodep->searchp(), WidthVP(SELF, BOTH).p());
4152 userIterateAndNext(nodep->outp(), WidthVP(SELF, BOTH).p());
4153 nodep->dtypeChgWidthSigned(32, 1, VSigning::SIGNED); // Spec says integer return
4154 }
4155 }
visit(AstTimeFormat * nodep)4156 virtual void visit(AstTimeFormat* nodep) override {
4157 assertAtStatement(nodep);
4158 iterateCheckSigned32(nodep, "units", nodep->unitsp(), BOTH);
4159 iterateCheckSigned32(nodep, "precision", nodep->precisionp(), BOTH);
4160 iterateCheckString(nodep, "suffix", nodep->suffixp(), BOTH);
4161 iterateCheckSigned32(nodep, "width", nodep->widthp(), BOTH);
4162 }
visit(AstUCStmt * nodep)4163 virtual void visit(AstUCStmt* nodep) override {
4164 // Just let all arguments seek their natural sizes
4165 assertAtStatement(nodep);
4166 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
4167 }
visit(AstAssert * nodep)4168 virtual void visit(AstAssert* nodep) override {
4169 assertAtStatement(nodep);
4170 iterateCheckBool(nodep, "Property", nodep->propp(), BOTH); // it's like an if() condition.
4171 userIterateAndNext(nodep->passsp(), nullptr);
4172 userIterateAndNext(nodep->failsp(), nullptr);
4173 }
visit(AstAssertIntrinsic * nodep)4174 virtual void visit(AstAssertIntrinsic* nodep) override {
4175 assertAtStatement(nodep);
4176 iterateCheckBool(nodep, "Property", nodep->propp(), BOTH); // it's like an if() condition.
4177 userIterateAndNext(nodep->passsp(), nullptr);
4178 userIterateAndNext(nodep->failsp(), nullptr);
4179 }
visit(AstCover * nodep)4180 virtual void visit(AstCover* nodep) override {
4181 assertAtStatement(nodep);
4182 iterateCheckBool(nodep, "Property", nodep->propp(), BOTH); // it's like an if() condition.
4183 userIterateAndNext(nodep->passsp(), nullptr);
4184 }
visit(AstRestrict * nodep)4185 virtual void visit(AstRestrict* nodep) override {
4186 assertAtStatement(nodep);
4187 iterateCheckBool(nodep, "Property", nodep->propp(), BOTH); // it's like an if() condition.
4188 }
visit(AstPin * nodep)4189 virtual void visit(AstPin* nodep) override {
4190 // if (debug()) nodep->dumpTree(cout, "- PinPre: ");
4191 // TOP LEVEL NODE
4192 if (nodep->modVarp() && nodep->modVarp()->isGParam()) {
4193 // Widthing handled as special init() case
4194 if (auto* const patternp = VN_CAST(nodep->exprp(), Pattern))
4195 if (const auto* modVarp = nodep->modVarp())
4196 patternp->childDTypep(modVarp->childDTypep()->cloneTree(false));
4197 userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
4198 } else if (!m_paramsOnly) {
4199 if (!nodep->modVarp()->didWidth()) {
4200 // Var hasn't been widthed, so make it so.
4201 userIterate(nodep->modVarp(), nullptr);
4202 }
4203 if (!nodep->exprp()) { // No-connect
4204 return;
4205 }
4206 // Very much like like an assignment, but which side is LH/RHS
4207 // depends on pin being a in/output/inout.
4208 userIterateAndNext(nodep->exprp(), WidthVP(nodep->modVarp()->dtypep(), PRELIM).p());
4209 AstNodeDType* modDTypep = nodep->modVarp()->dtypep();
4210 AstNodeDType* conDTypep = nodep->exprp()->dtypep();
4211 if (!modDTypep) nodep->v3fatalSrc("Unlinked pin data type");
4212 if (!conDTypep) nodep->v3fatalSrc("Unlinked pin data type");
4213 modDTypep = modDTypep->skipRefp();
4214 conDTypep = conDTypep->skipRefp();
4215 AstNodeDType* subDTypep = modDTypep;
4216 const int pinwidth = modDTypep->width();
4217 const int conwidth = conDTypep->width();
4218 if (conDTypep == modDTypep // If match, we're golden
4219 || similarDTypeRecurse(conDTypep, modDTypep)) {
4220 userIterateAndNext(nodep->exprp(), WidthVP(subDTypep, FINAL).p());
4221 } else if (m_cellp->rangep()) {
4222 const int numInsts = m_cellp->rangep()->elementsConst();
4223 if (conwidth == pinwidth) {
4224 // Arrayed instants: widths match so connect to each instance
4225 subDTypep = conDTypep; // = same expr dtype
4226 } else if (conwidth == numInsts * pinwidth) {
4227 // Arrayed instants: one bit for each of the instants (each
4228 // assign is 1 pinwidth wide)
4229 subDTypep = conDTypep; // = same expr dtype (but numInst*pin_dtype)
4230 } else {
4231 // Must be a error according to spec
4232 // (Because we need to know if to connect to one or all instants)
4233 nodep->v3error(ucfirst(nodep->prettyOperatorName())
4234 << " as part of a module instance array"
4235 << " requires " << pinwidth << " or " << pinwidth * numInsts
4236 << " bits, but connection's "
4237 << nodep->exprp()->prettyTypeName() << " generates " << conwidth
4238 << " bits. (IEEE 1800-2017 23.3.3)");
4239 subDTypep = conDTypep; // = same expr dtype
4240 }
4241 userIterateAndNext(nodep->exprp(), WidthVP(subDTypep, FINAL).p());
4242 } else {
4243 if (nodep->modVarp()->direction() == VDirection::REF) {
4244 nodep->v3error("Ref connection "
4245 << nodep->modVarp()->prettyNameQ()
4246 << " requires matching types;"
4247 << " ref requires " << modDTypep->prettyDTypeNameQ()
4248 << " data type but connection is "
4249 << conDTypep->prettyDTypeNameQ() << " data type.");
4250 } else if (nodep->modVarp()->isTristate()) {
4251 if (pinwidth != conwidth) {
4252 // Ideally should call pinReconnectSimple which would tolerate this
4253 // then have a conversion warning
4254 nodep->v3warn(E_UNSUPPORTED,
4255 "Unsupported: " << ucfirst(nodep->prettyOperatorName())
4256 << " to inout signal requires " << pinwidth
4257 << " bits, but connection's "
4258 << nodep->exprp()->prettyTypeName()
4259 << " generates " << conwidth << " bits.");
4260 // otherwise would need some mess to force both sides to proper size
4261 }
4262 } else if (nodep->modVarp()->direction().isWritable()
4263 && ((conDTypep->isDouble() && !modDTypep->isDouble())
4264 || (!conDTypep->isDouble() && modDTypep->isDouble()))) {
4265 nodep->v3warn(E_UNSUPPORTED,
4266 "Unsupported: " << ucfirst(nodep->prettyOperatorName())
4267 << " connects real to non-real");
4268 }
4269
4270 // Check if an interface is connected to a non-interface and vice versa
4271 if ((VN_IS(modDTypep, IfaceRefDType) && !VN_IS(conDTypep, IfaceRefDType))
4272 || (VN_IS(conDTypep, IfaceRefDType) && !VN_IS(modDTypep, IfaceRefDType))) {
4273 nodep->v3error("Illegal " << nodep->prettyOperatorName() << ","
4274 << " mismatch between port which is"
4275 << (VN_CAST(modDTypep, IfaceRefDType) ? "" : " not")
4276 << " an interface,"
4277 << " and expression which is"
4278 << (VN_CAST(conDTypep, IfaceRefDType) ? "" : " not")
4279 << " an interface.");
4280 }
4281
4282 // TODO Simple dtype checking, should be a more general check
4283 const AstNodeArrayDType* const exprArrayp = VN_CAST(conDTypep, UnpackArrayDType);
4284 const AstNodeArrayDType* const modArrayp = VN_CAST(modDTypep, UnpackArrayDType);
4285 if (exprArrayp && modArrayp && VN_IS(exprArrayp->subDTypep(), IfaceRefDType)
4286 && exprArrayp->declRange().elements() != modArrayp->declRange().elements()) {
4287 const int exprSize = exprArrayp->declRange().elements();
4288 const int modSize = modArrayp->declRange().elements();
4289 nodep->v3error("Illegal "
4290 << nodep->prettyOperatorName() << ","
4291 << " mismatch between port which is an interface array of size "
4292 << modSize << ","
4293 << " and expression which is an interface array of size "
4294 << exprSize << ".");
4295 UINFO(1, " Related lo: " << modDTypep << endl);
4296 UINFO(1, " Related hi: " << conDTypep << endl);
4297 } else if ((exprArrayp && !modArrayp) || (!exprArrayp && modArrayp)) {
4298 nodep->v3error("Illegal " << nodep->prettyOperatorName() << ","
4299 << " mismatch between port which is"
4300 << (modArrayp ? "" : " not") << " an array,"
4301 << " and expression which is"
4302 << (exprArrayp ? "" : " not")
4303 << " an array. (IEEE 1800-2017 7.6)");
4304 UINFO(1, " Related lo: " << modDTypep << endl);
4305 UINFO(1, " Related hi: " << conDTypep << endl);
4306 }
4307 iterateCheckAssign(nodep, "pin connection", nodep->exprp(), FINAL, subDTypep);
4308 }
4309 }
4310 // if (debug()) nodep->dumpTree(cout, "- PinOut: ");
4311 }
visit(AstCell * nodep)4312 virtual void visit(AstCell* nodep) override {
4313 VL_RESTORER(m_cellp);
4314 m_cellp = nodep;
4315 if (!m_paramsOnly) {
4316 if (VN_IS(nodep->modp(), NotFoundModule)) {
4317 // We've resolved parameters and hit a module that we couldn't resolve. It's
4318 // finally time to report it.
4319 // Note only here in V3Width as this is first visitor after V3Dead.
4320 nodep->modNameFileline()->v3error("Cannot find file containing module: '"
4321 << nodep->modName() << "'");
4322 v3Global.opt.filePathLookedMsg(nodep->modNameFileline(), nodep->modName());
4323 }
4324 if (nodep->rangep()) userIterateAndNext(nodep->rangep(), WidthVP(SELF, BOTH).p());
4325 userIterateAndNext(nodep->pinsp(), nullptr);
4326 }
4327 userIterateAndNext(nodep->paramsp(), nullptr);
4328 }
visit(AstGatePin * nodep)4329 virtual void visit(AstGatePin* nodep) override {
4330 if (m_vup->prelim()) {
4331 userIterateAndNext(nodep->rangep(), WidthVP(SELF, BOTH).p());
4332 userIterateAndNext(nodep->exprp(), WidthVP(CONTEXT, PRELIM).p());
4333 nodep->dtypeFrom(nodep->rangep());
4334 // Very much like like an pin
4335 const AstNodeDType* const conDTypep = nodep->exprp()->dtypep();
4336 const int numInsts = nodep->rangep()->elementsConst();
4337 const int pinwidth = numInsts;
4338 const int conwidth = conDTypep->width();
4339 if (conwidth == 1 && pinwidth > 1) { // Multiple connections
4340 AstNodeDType* const subDTypep = nodep->findLogicDType(1, 1, conDTypep->numeric());
4341 userIterateAndNext(nodep->exprp(), WidthVP(subDTypep, FINAL).p());
4342 AstNode* const newp = new AstReplicate(nodep->fileline(),
4343 nodep->exprp()->unlinkFrBack(), numInsts);
4344 nodep->replaceWith(newp);
4345 } else {
4346 // Eliminating so pass down all of vup
4347 userIterateAndNext(nodep->exprp(), m_vup);
4348 nodep->replaceWith(nodep->exprp()->unlinkFrBack());
4349 }
4350 VL_DO_DANGLING(pushDeletep(nodep), nodep);
4351 }
4352 }
visit(AstNodeFTask * nodep)4353 virtual void visit(AstNodeFTask* nodep) override {
4354 // Grab width from the output variable (if it's a function)
4355 if (nodep->didWidth()) return;
4356 if (nodep->doingWidth()) {
4357 nodep->v3warn(E_UNSUPPORTED, "Unsupported: Recursive function or task call");
4358 nodep->dtypeSetBit();
4359 nodep->didWidth(true);
4360 return;
4361 }
4362 if (nodep->classMethod() && nodep->name() == "rand_mode") {
4363 nodep->v3error("The 'rand_mode' method is built-in and cannot be overridden"
4364 " (IEEE 1800-2017 18.8)");
4365 } else if (nodep->classMethod() && nodep->name() == "constraint_mode") {
4366 nodep->v3error("The 'constraint_mode' method is built-in and cannot be overridden"
4367 " (IEEE 1800-2017 18.9)");
4368 }
4369 // Function hasn't been widthed, so make it so.
4370 // Would use user1 etc, but V3Width called from too many places to spend a user
4371 nodep->doingWidth(true);
4372 m_ftaskp = nodep;
4373 userIterateChildren(nodep, nullptr);
4374 if (nodep->isConstructor()) {
4375 // Pretend it's void so less special casing needed when look at dtypes
4376 nodep->dtypeSetVoid();
4377 } else if (nodep->fvarp()) {
4378 m_funcp = VN_AS(nodep, Func);
4379 UASSERT_OBJ(m_funcp, nodep, "FTask with function variable, but isn't a function");
4380 nodep->dtypeFrom(nodep->fvarp()); // Which will get it from fvarp()->dtypep()
4381 }
4382 nodep->didWidth(true);
4383 nodep->doingWidth(false);
4384 m_funcp = nullptr;
4385 m_ftaskp = nullptr;
4386 if (nodep->dpiImport() && !nodep->dpiOpenParent() && markHasOpenArray(nodep)) {
4387 nodep->dpiOpenParentInc(); // Mark so V3Task will wait for a child to build calling
4388 // func
4389 }
4390 }
visit(AstReturn * nodep)4391 virtual void visit(AstReturn* nodep) override {
4392 // IEEE: Assignment-like context
4393 assertAtStatement(nodep);
4394 if (!m_funcp) {
4395 if (nodep->lhsp()) { // Return w/o value ok other places
4396 nodep->v3error("Return with return value isn't underneath a function");
4397 }
4398 } else {
4399 if (nodep->lhsp()) {
4400 // Function hasn't been widthed, so make it so.
4401 nodep->dtypeFrom(m_funcp->fvarp());
4402 // AstPattern requires assignments to pass datatype on PRELIM
4403 userIterateAndNext(nodep->lhsp(), WidthVP(nodep->dtypep(), PRELIM).p());
4404 iterateCheckAssign(nodep, "Return value", nodep->lhsp(), FINAL, nodep->dtypep());
4405 }
4406 }
4407 }
4408
visit(AstFuncRef * nodep)4409 virtual void visit(AstFuncRef* nodep) override {
4410 visit(static_cast<AstNodeFTaskRef*>(nodep));
4411 nodep->dtypeFrom(nodep->taskp());
4412 // if (debug()) nodep->dumpTree(cout, " FuncOut: ");
4413 }
4414 // Returns true if dtypep0 and dtypep1 have same dimensions
areSameSize(AstUnpackArrayDType * dtypep0,AstUnpackArrayDType * dtypep1)4415 static bool areSameSize(AstUnpackArrayDType* dtypep0, AstUnpackArrayDType* dtypep1) {
4416 const std::vector<AstUnpackArrayDType*> dims0 = dtypep0->unpackDimensions();
4417 const std::vector<AstUnpackArrayDType*> dims1 = dtypep1->unpackDimensions();
4418 if (dims0.size() != dims1.size()) return false;
4419 for (size_t i = 0; i < dims0.size(); ++i) {
4420 if (dims0[i]->elementsConst() != dims1[i]->elementsConst()) return false;
4421 }
4422 return true;
4423 }
4424 // Makes sure that port and pin have same size and same datatype
checkUnpackedArrayArgs(AstVar * portp,AstNode * pinp)4425 void checkUnpackedArrayArgs(AstVar* portp, AstNode* pinp) {
4426 if (AstUnpackArrayDType* const portDtypep
4427 = VN_CAST(portp->dtypep()->skipRefp(), UnpackArrayDType)) {
4428 if (AstUnpackArrayDType* const pinDtypep
4429 = VN_CAST(pinp->dtypep()->skipRefp(), UnpackArrayDType)) {
4430 if (!areSameSize(portDtypep, pinDtypep)) {
4431 pinp->v3warn(E_UNSUPPORTED,
4432 "Shape of the argument does not match the shape of the parameter "
4433 << "(" << pinDtypep->prettyDTypeNameQ() << " v.s. "
4434 << portDtypep->prettyDTypeNameQ() << ")");
4435 }
4436 if (portDtypep->basicp()->width() != pinDtypep->basicp()->width()
4437 || (portDtypep->basicp()->keyword() != pinDtypep->basicp()->keyword()
4438 && !(portDtypep->basicp()->keyword() == AstBasicDTypeKwd::LOGIC_IMPLICIT
4439 && pinDtypep->basicp()->keyword() == AstBasicDTypeKwd::LOGIC)
4440 && !(portDtypep->basicp()->keyword() == AstBasicDTypeKwd::LOGIC
4441 && pinDtypep->basicp()->keyword()
4442 == AstBasicDTypeKwd::LOGIC_IMPLICIT))) {
4443 pinp->v3warn(E_UNSUPPORTED,
4444 "Shape of the argument does not match the shape of the parameter "
4445 << "(" << pinDtypep->basicp()->prettyDTypeNameQ() << " v.s. "
4446 << portDtypep->basicp()->prettyDTypeNameQ() << ")");
4447 }
4448 } else {
4449 pinp->v3warn(E_UNSUPPORTED, "Argument is not an unpacked array while parameter "
4450 << portp->prettyNameQ() << " is");
4451 }
4452 }
4453 }
processFTaskRefArgs(AstNodeFTaskRef * nodep)4454 void processFTaskRefArgs(AstNodeFTaskRef* nodep) {
4455 // For arguments, is assignment-like context; see IEEE rules in AstNodeAssign
4456 // Function hasn't been widthed, so make it so.
4457 UINFO(5, " FTASKREF " << nodep << endl);
4458 UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked");
4459 if (nodep->didWidth()) return;
4460 userIterate(nodep->taskp(), nullptr);
4461 //
4462 // And do the arguments to the task/function too
4463 do {
4464 reloop:
4465 const V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
4466 for (const auto& tconnect : tconnects) {
4467 const AstVar* const portp = tconnect.first;
4468 AstArg* const argp = tconnect.second;
4469 AstNode* pinp = argp->exprp();
4470 if (!pinp) continue; // Argument error we'll find later
4471 // Prelim may cause the node to get replaced; we've lost our
4472 // pointer, so need to iterate separately later
4473 if (portp->attrSFormat()
4474 && (!VN_IS(pinp, SFormatF) || pinp->nextp())) { // Not already done
4475 UINFO(4, " sformat via metacomment: " << nodep << endl);
4476 AstNRelinker handle;
4477 argp->unlinkFrBackWithNext(&handle); // Format + additional args, if any
4478 AstNode* argsp = nullptr;
4479 while (AstArg* const nextargp = VN_AS(argp->nextp(), Arg)) {
4480 argsp = AstNode::addNext(
4481 argsp, nextargp->exprp()
4482 ->unlinkFrBackWithNext()); // Expression goes to SFormatF
4483 nextargp->unlinkFrBack()->deleteTree(); // Remove the call's Arg wrapper
4484 }
4485 string format;
4486 if (VN_IS(pinp, Const)) {
4487 format = VN_AS(pinp, Const)->num().toString();
4488 } else {
4489 pinp->v3error(
4490 "Format to $display-like function must have constant format string");
4491 }
4492 VL_DO_DANGLING(pushDeletep(argp), argp);
4493 AstSFormatF* const newp
4494 = new AstSFormatF(nodep->fileline(), format, false, argsp);
4495 if (!newp->scopeNamep() && newp->formatScopeTracking()) {
4496 newp->scopeNamep(new AstScopeName{newp->fileline(), true});
4497 }
4498 handle.relink(new AstArg(newp->fileline(), "", newp));
4499 // Connection list is now incorrect (has extra args in it).
4500 goto reloop; // so exit early; next loop will correct it
4501 } //
4502 else if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::STRING
4503 && !VN_IS(pinp, CvtPackString)
4504 && !VN_IS(pinp, SFormatF) // Already generates a string
4505 && !VN_IS(portp->dtypep(), UnpackArrayDType) // Unpacked array must match
4506 && !(VN_IS(pinp, VarRef)
4507 && VN_AS(pinp, VarRef)->varp()->basicp()->keyword()
4508 == AstBasicDTypeKwd::STRING)) {
4509 UINFO(4, " Add CvtPackString: " << pinp << endl);
4510 AstNRelinker handle;
4511 pinp->unlinkFrBack(&handle); // No next, that's the next pin
4512 AstNode* const newp = new AstCvtPackString(pinp->fileline(), pinp);
4513 handle.relink(newp);
4514 pinp = newp;
4515 }
4516 // AstPattern requires assignments to pass datatype on PRELIM
4517 VL_DO_DANGLING(userIterate(pinp, WidthVP(portp->dtypep(), PRELIM).p()), pinp);
4518 }
4519 } while (false);
4520 // Stage 2
4521 {
4522 const V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
4523 for (const auto& tconnect : tconnects) {
4524 AstVar* const portp = tconnect.first;
4525 const AstArg* const argp = tconnect.second;
4526 AstNode* const pinp = argp->exprp();
4527 if (!pinp) continue; // Argument error we'll find later
4528 // Change data types based on above accept completion
4529 if (nodep->taskp()->dpiImport()) checkUnpackedArrayArgs(portp, pinp);
4530 if (portp->isDouble()) VL_DO_DANGLING(spliceCvtD(pinp), pinp);
4531 }
4532 }
4533 // Stage 3
4534 {
4535 const V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
4536 for (const auto& tconnect : tconnects) {
4537 const AstVar* const portp = tconnect.first;
4538 const AstArg* const argp = tconnect.second;
4539 AstNode* const pinp = argp->exprp();
4540 if (!pinp) continue; // Argument error we'll find later
4541 // Do PRELIM again, because above accept may have exited early
4542 // due to node replacement
4543 userIterate(pinp, WidthVP(portp->dtypep(), PRELIM).p());
4544 }
4545 }
4546 // Cleanup any open arrays
4547 if (markHasOpenArray(nodep->taskp())) makeOpenArrayShell(nodep);
4548 // Stage 4
4549 {
4550 const V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
4551 for (const auto& tconnect : tconnects) {
4552 const AstVar* const portp = tconnect.first;
4553 const AstArg* const argp = tconnect.second;
4554 AstNode* const pinp = argp->exprp();
4555 if (!pinp) continue; // Argument error we'll find later
4556 if (portp->direction() == VDirection::REF
4557 && !similarDTypeRecurse(portp->dtypep(), pinp->dtypep())) {
4558 pinp->v3error("Ref argument requires matching types;"
4559 << " port " << portp->prettyNameQ() << " requires "
4560 << portp->prettyTypeName() << " but connection is "
4561 << pinp->prettyTypeName() << ".");
4562 } else if (portp->isWritable() && pinp->width() != portp->width()) {
4563 pinp->v3warn(E_UNSUPPORTED, "Unsupported: Function output argument "
4564 << portp->prettyNameQ() << " requires "
4565 << portp->width() << " bits, but connection's "
4566 << pinp->prettyTypeName() << " generates "
4567 << pinp->width() << " bits.");
4568 // otherwise would need some mess to force both sides to proper size
4569 // (get an ASSIGN with EXTEND on the lhs instead of rhs)
4570 }
4571 if (!portp->basicp() || portp->basicp()->isOpaque()) {
4572 userIterate(pinp, WidthVP(portp->dtypep(), FINAL).p());
4573 } else {
4574 iterateCheckAssign(nodep, "Function Argument", pinp, FINAL, portp->dtypep());
4575 }
4576 }
4577 }
4578 }
visit(AstNodeFTaskRef * nodep)4579 virtual void visit(AstNodeFTaskRef* nodep) override {
4580 // For arguments, is assignment-like context; see IEEE rules in AstNodeAssign
4581 // Function hasn't been widthed, so make it so.
4582 UINFO(5, " FTASKREF " << nodep << endl);
4583 UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked");
4584 if (nodep->didWidth()) return;
4585 userIterate(nodep->taskp(), nullptr);
4586 // And do the arguments to the task/function too
4587 processFTaskRefArgs(nodep);
4588 nodep->didWidth(true);
4589 }
visit(AstNodeProcedure * nodep)4590 virtual void visit(AstNodeProcedure* nodep) override {
4591 assertAtStatement(nodep);
4592 m_procedurep = nodep;
4593 userIterateChildren(nodep, nullptr);
4594 m_procedurep = nullptr;
4595 }
visit(AstWith * nodep)4596 virtual void visit(AstWith* nodep) override {
4597 // Should otherwise be underneath a method call
4598 AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp();
4599 {
4600 VL_RESTORER(m_withp);
4601 m_withp = nodep;
4602 userIterateChildren(nodep->indexArgRefp(), nullptr);
4603 userIterateChildren(nodep->valueArgRefp(), nullptr);
4604 if (vdtypep) {
4605 userIterateAndNext(nodep->exprp(), WidthVP(nodep->dtypep(), PRELIM).p());
4606 } else { // 'sort with' allows arbitrary type
4607 userIterateAndNext(nodep->exprp(), WidthVP(SELF, PRELIM).p());
4608 }
4609 nodep->dtypeFrom(nodep->exprp());
4610 iterateCheckAssign(nodep, "'with' return value", nodep->exprp(), FINAL,
4611 nodep->dtypep());
4612 }
4613 }
visit(AstLambdaArgRef * nodep)4614 virtual void visit(AstLambdaArgRef* nodep) override {
4615 UASSERT_OBJ(m_withp, nodep, "LambdaArgRef not underneath 'with' lambda");
4616 if (nodep->index()) {
4617 nodep->dtypeFrom(m_withp->indexArgRefp());
4618 } else {
4619 nodep->dtypeFrom(m_withp->valueArgRefp());
4620 }
4621 }
visit(AstNetlist * nodep)4622 virtual void visit(AstNetlist* nodep) override {
4623 // Iterate modules backwards, in bottom-up order. That's faster
4624 userIterateChildrenBackwards(nodep, nullptr);
4625 }
4626
4627 //--------------------
4628 // Default
visit(AstNodeMath * nodep)4629 virtual void visit(AstNodeMath* nodep) override {
4630 if (!nodep->didWidth()) {
4631 nodep->v3fatalSrc(
4632 "Visit function missing? Widthed function missing for math node: " << nodep);
4633 }
4634 userIterateChildren(nodep, nullptr);
4635 }
visit(AstNode * nodep)4636 virtual void visit(AstNode* nodep) override {
4637 // Default: Just iterate
4638 UASSERT_OBJ(!m_vup, nodep,
4639 "Visit function missing? Widthed expectation for this node: " << nodep);
4640 userIterateChildren(nodep, nullptr);
4641 }
4642
4643 //----------------------------------------------------------------------
4644 // WIDTH METHODs -- all iterate
4645
visit_Or_Lu64(AstNodeUniop * nodep)4646 void visit_Or_Lu64(AstNodeUniop* nodep) {
4647 // CALLER: AstBitsToRealD
4648 // Real: Output real
4649 // LHS presumed self-determined, then coerced to real
4650 if (m_vup->prelim()) { // First stage evaluation
4651 nodep->dtypeSetDouble();
4652 AstNodeDType* const subDTypep = nodep->findLogicDType(64, 64, VSigning::UNSIGNED);
4653 // Self-determined operand
4654 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p());
4655 iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP);
4656 }
4657 }
visit(AstIToRD * nodep)4658 virtual void visit(AstIToRD* nodep) override {
4659 // Real: Output real
4660 // LHS presumed self-determined, then coerced to real
4661 if (m_vup->prelim()) { // First stage evaluation
4662 nodep->dtypeSetDouble();
4663 // Self-determined operand (TODO check if numeric type)
4664 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p());
4665 if (nodep->lhsp()->isSigned()) {
4666 nodep->replaceWith(
4667 new AstISToRD(nodep->fileline(), nodep->lhsp()->unlinkFrBack()));
4668 VL_DO_DANGLING(nodep->deleteTree(), nodep);
4669 }
4670 }
4671 }
visit(AstISToRD * nodep)4672 virtual void visit(AstISToRD* nodep) override {
4673 // Real: Output real
4674 // LHS presumed self-determined, then coerced to real
4675 if (m_vup->prelim()) { // First stage evaluation
4676 nodep->dtypeSetDouble();
4677 // Self-determined operand (TODO check if numeric type)
4678 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p());
4679 }
4680 }
visit_Os32_Lr(AstNodeUniop * nodep)4681 void visit_Os32_Lr(AstNodeUniop* nodep) {
4682 // CALLER: RToI
4683 // Real: LHS real
4684 // LHS presumed self-determined, then coerced to real
4685 if (m_vup->prelim()) { // First stage evaluation
4686 iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH);
4687 nodep->dtypeSetSigned32();
4688 }
4689 }
visit_Ou64_Lr(AstNodeUniop * nodep)4690 void visit_Ou64_Lr(AstNodeUniop* nodep) {
4691 // CALLER: RealToBits
4692 // Real: LHS real
4693 // LHS presumed self-determined, then coerced to real
4694 if (m_vup->prelim()) { // First stage evaluation
4695 iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH);
4696 nodep->dtypeSetUInt64();
4697 }
4698 }
4699
visit_log_not(AstNode * nodep)4700 void visit_log_not(AstNode* nodep) {
4701 // CALLER: LogNot
4702 // Width-check: lhs 1 bit
4703 // Real: Allowed; implicitly compares with zero
4704 // We calculate the width of the UNDER expression.
4705 // We then check its width to see if it's legal, and edit if not
4706 // We finally set the width of our output
4707 // IEEE-2012: Table 11-21 and 11.8.1 (same as RedAnd):
4708 // LHS is self-determined
4709 // Width: 1 bit out
4710 // Sign: unsigned out (11.8.1)
4711 UASSERT_OBJ(!nodep->op2p(), nodep, "For unary ops only!");
4712 if (m_vup->prelim()) {
4713 iterateCheckBool(nodep, "LHS", nodep->op1p(), BOTH);
4714 nodep->dtypeSetBit();
4715 }
4716 }
visit_log_and_or(AstNodeBiop * nodep)4717 void visit_log_and_or(AstNodeBiop* nodep) {
4718 // CALLER: LogAnd, LogOr, LogEq, LogIf
4719 // Widths: 1 bit out, lhs 1 bit, rhs 1 bit
4720 // IEEE-2012 Table 11-21:
4721 // LHS is self-determined
4722 // RHS is self-determined
4723 if (m_vup->prelim()) {
4724 iterateCheckBool(nodep, "LHS", nodep->lhsp(), BOTH);
4725 iterateCheckBool(nodep, "RHS", nodep->rhsp(), BOTH);
4726 nodep->dtypeSetBit();
4727 }
4728 }
visit_red_and_or(AstNodeUniop * nodep)4729 void visit_red_and_or(AstNodeUniop* nodep) {
4730 // CALLER: RedAnd, RedOr, ...
4731 // Signed: Output unsigned, Lhs/Rhs/etc non-real (presumed, not in IEEE)
4732 // IEEE-2012: Table 11-21 and 11.8.1:
4733 // LHS is self-determined
4734 // Width: 1 bit out
4735 // Sign: unsigned out (11.8.1)
4736 if (m_vup->prelim()) {
4737 iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
4738 nodep->dtypeSetBit();
4739 }
4740 }
visit_red_unknown(AstNodeUniop * nodep)4741 void visit_red_unknown(AstNodeUniop* nodep) {
4742 // CALLER: IsUnknown
4743 // Signed: Output unsigned, Lhs/Rhs/etc non-real (presumed, not in IEEE)
4744 // IEEE-2012: Table 11-21 and 11.8.1:
4745 // LHS is self-determined
4746 // Width: 1 bit out
4747 // Sign: unsigned out (11.8.1)
4748 if (m_vup->prelim()) {
4749 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
4750 nodep->dtypeSetBit();
4751 }
4752 }
4753
visit_cmp_eq_gt(AstNodeBiop * nodep,bool realok)4754 void visit_cmp_eq_gt(AstNodeBiop* nodep, bool realok) {
4755 // CALLER: AstEq, AstGt, ..., AstLtS
4756 // Real allowed if and only if real_lhs set
4757 // See IEEE-2012 11.4.4, and 11.8.1:
4758 // Widths: 1 bit out, width is max of LHS or RHS
4759 // Sign: signed compare (not output) if both signed, compare is signed,
4760 // width mismatches sign extend
4761 // else, compare is unsigned, **zero-extends**
4762 // Real: If either real, other side becomes real and real compare
4763 // TODO: chandle/class handle/iface handle: WildEq/WildNeq same as Eq/Neq
4764 // TODO: chandle/class handle/iface handle only allowed to self-compare or against null
4765 // TODO: chandle/class handle/iface handle no relational compares
4766 UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!");
4767 if (m_vup->prelim()) {
4768 userIterateAndNext(nodep->lhsp(), WidthVP(CONTEXT, PRELIM).p());
4769 userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p());
4770 if (nodep->lhsp()->isDouble() || nodep->rhsp()->isDouble()) {
4771 if (!realok) nodep->v3error("Real not allowed as operand to in ?== operator");
4772 if (AstNodeBiop* const newp = replaceWithDVersion(nodep)) {
4773 VL_DANGLING(nodep);
4774 nodep = newp; // Process new node instead
4775 iterateCheckReal(nodep, "LHS", nodep->lhsp(), FINAL);
4776 iterateCheckReal(nodep, "RHS", nodep->rhsp(), FINAL);
4777 }
4778 } else if (nodep->lhsp()->isString() || nodep->rhsp()->isString()) {
4779 if (AstNodeBiop* const newp = replaceWithNVersion(nodep)) {
4780 VL_DANGLING(nodep);
4781 nodep = newp; // Process new node instead
4782 iterateCheckString(nodep, "LHS", nodep->lhsp(), FINAL);
4783 iterateCheckString(nodep, "RHS", nodep->rhsp(), FINAL);
4784 }
4785 } else {
4786 const bool signedFl = nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned();
4787 if (AstNodeBiop* const newp = replaceWithUOrSVersion(nodep, signedFl)) {
4788 VL_DANGLING(nodep);
4789 nodep = newp; // Process new node instead
4790 }
4791 const int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width());
4792 const int ewidth = std::max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin());
4793 AstNodeDType* const subDTypep
4794 = nodep->findLogicDType(width, ewidth, VSigning::fromBool(signedFl));
4795 bool warnOn = true;
4796 if (!signedFl && width == 32) {
4797 // Waive on unsigned < or <= if RHS is narrower, since can't give wrong answer
4798 if ((VN_IS(nodep, Lt) || VN_IS(nodep, Lte))
4799 && (nodep->lhsp()->width() >= nodep->rhsp()->widthMin())) {
4800 warnOn = false;
4801 }
4802 // Waive on unsigned > or >= if RHS is wider, since can't give wrong answer
4803 if ((VN_IS(nodep, Gt) || VN_IS(nodep, Gte))
4804 && (nodep->lhsp()->widthMin() >= nodep->rhsp()->width())) {
4805 warnOn = false;
4806 }
4807 }
4808 iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT, FINAL, subDTypep,
4809 (signedFl ? EXTEND_LHS : EXTEND_ZERO), warnOn);
4810 iterateCheck(nodep, "RHS", nodep->rhsp(), CONTEXT, FINAL, subDTypep,
4811 (signedFl ? EXTEND_LHS : EXTEND_ZERO), warnOn);
4812 }
4813 nodep->dtypeSetBit();
4814 }
4815 }
visit_cmp_real(AstNodeBiop * nodep)4816 void visit_cmp_real(AstNodeBiop* nodep) {
4817 // CALLER: EqD, LtD
4818 // Widths: 1 bit out, lhs width == rhs width
4819 // Signed compare (not output) if both sides signed
4820 // Real if and only if real_allow set
4821 // IEEE, 11.4.4: relational compares (<,>,<=,>=,==,===,!=,!==) use
4822 // "zero padding" on unsigned
4823 UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!");
4824 if (m_vup->prelim()) {
4825 // See similar handling in visit_cmp_eq_gt where created
4826 iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH);
4827 iterateCheckReal(nodep, "RHS", nodep->rhsp(), BOTH);
4828 nodep->dtypeSetBit();
4829 }
4830 }
visit_cmp_string(AstNodeBiop * nodep)4831 void visit_cmp_string(AstNodeBiop* nodep) {
4832 // CALLER: EqN, LtN
4833 // Widths: 1 bit out, lhs width == rhs width
4834 // String compare (not output)
4835 // Real if and only if real_allow set
4836 UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!");
4837 if (m_vup->prelim()) {
4838 // See similar handling in visit_cmp_eq_gt where created
4839 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
4840 iterateCheckString(nodep, "RHS", nodep->rhsp(), BOTH);
4841 nodep->dtypeSetBit();
4842 }
4843 }
4844
visit_Os32_string(AstNodeUniop * nodep)4845 void visit_Os32_string(AstNodeUniop* nodep) {
4846 // CALLER: LenN
4847 // Widths: 32 bit out
4848 UASSERT_OBJ(nodep->lhsp(), nodep, "For unary ops only!");
4849 if (m_vup->prelim()) {
4850 // See similar handling in visit_cmp_eq_gt where created
4851 iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
4852 nodep->dtypeSetSigned32();
4853 }
4854 }
4855
visit_negate_not(AstNodeUniop * nodep,bool real_ok)4856 void visit_negate_not(AstNodeUniop* nodep, bool real_ok) {
4857 // CALLER: (real_ok=false) Not
4858 // CALLER: (real_ok=true) Negate
4859 // Signed: From lhs
4860 // IEEE-2012 Table 11-21:
4861 // Widths: out width = lhs width
4862 UASSERT_OBJ(!nodep->op2p(), nodep, "For unary ops only!");
4863 if (m_vup->prelim()) {
4864 userIterateAndNext(nodep->lhsp(), WidthVP(CONTEXT, PRELIM).p());
4865 if (!real_ok) checkCvtUS(nodep->lhsp());
4866 }
4867 if (real_ok && nodep->lhsp()->isDouble()) {
4868 spliceCvtD(nodep->lhsp());
4869 if (AstNodeUniop* const newp = replaceWithDVersion(nodep)) {
4870 VL_DANGLING(nodep);
4871 nodep = newp; // Process new node instead
4872 iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH);
4873 nodep->dtypeSetDouble();
4874 return;
4875 }
4876 } else {
4877 // Note there aren't yet uniops that need version changes
4878 // So no need to call replaceWithUOrSVersion(nodep, nodep->isSigned())
4879 }
4880 if (m_vup->prelim()) nodep->dtypeFrom(nodep->lhsp());
4881 if (m_vup->final()) {
4882 AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep());
4883 nodep->dtypep(expDTypep); // Propagate expression type to negation
4884 AstNodeDType* const subDTypep = expDTypep;
4885 iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP);
4886 }
4887 }
4888
visit_signed_unsigned(AstNodeUniop * nodep,VSigning rs_out)4889 void visit_signed_unsigned(AstNodeUniop* nodep, VSigning rs_out) {
4890 // CALLER: Signed, Unsigned
4891 // Width: lhs is self determined width
4892 // See IEEE-2012 6.24.1:
4893 // Width: Returns packed array, of size $bits(expression).
4894 // Sign: Output sign is as specified by operation
4895 // TODO: Type: Two-state if input is two-state, else four-state
4896 UASSERT_OBJ(!nodep->op2p(), nodep, "For unary ops only!");
4897 if (m_vup->prelim()) {
4898 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p());
4899 checkCvtUS(nodep->lhsp());
4900 const int width = nodep->lhsp()->width();
4901 AstNodeDType* const expDTypep = nodep->findLogicDType(width, width, rs_out);
4902 nodep->dtypep(expDTypep);
4903 AstNodeDType* const subDTypep = expDTypep;
4904 // The child's width is self determined
4905 iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP);
4906 }
4907 }
4908
visit_shift(AstNodeBiop * nodep)4909 void visit_shift(AstNodeBiop* nodep) {
4910 // CALLER: ShiftL, ShiftR, ShiftRS
4911 // Widths: Output width from lhs, rhs<33 bits
4912 // Signed: Output signed iff LHS signed; unary operator
4913 // See IEEE 2012 11.4.10:
4914 // RHS is self-determined. RHS is always treated as unsigned, has no effect on result.
4915 iterate_shift_prelim(nodep);
4916 nodep->dtypeChgSigned(nodep->lhsp()->isSigned());
4917 const AstNodeBiop* const newp = iterate_shift_final(nodep);
4918 VL_DANGLING(nodep);
4919 if (newp) {} // Ununused
4920 }
iterate_shift_prelim(AstNodeBiop * nodep)4921 void iterate_shift_prelim(AstNodeBiop* nodep) {
4922 // Shifts
4923 // See IEEE-2012 11.4.10 and Table 11-21.
4924 // RHS is self-determined. RHS is always treated as unsigned, has no effect on result.
4925 if (m_vup->prelim()) {
4926 userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p());
4927 checkCvtUS(nodep->lhsp());
4928 iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
4929 nodep->dtypeFrom(nodep->lhsp());
4930 }
4931 }
iterate_shift_final(AstNodeBiop * nodep)4932 AstNodeBiop* iterate_shift_final(AstNodeBiop* nodep) {
4933 // Nodep maybe edited
4934 if (m_vup->final()) {
4935 AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep());
4936 AstNodeDType* const subDTypep = expDTypep;
4937 nodep->dtypeFrom(expDTypep);
4938 // ShiftRS converts to ShiftR, but not vice-versa
4939 if (VN_IS(nodep, ShiftRS)) {
4940 if (AstNodeBiop* const newp = replaceWithUOrSVersion(nodep, nodep->isSigned())) {
4941 VL_DANGLING(nodep);
4942 nodep = newp; // Process new node instead
4943 }
4944 }
4945 bool warnOn = true;
4946 // No warning if "X = 1'b1<<N"; assume user is doing what they want
4947 if (nodep->lhsp()->isOne() && VN_IS(nodep->backp(), NodeAssign)) warnOn = false;
4948 iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP,
4949 warnOn);
4950 if (nodep->rhsp()->width() > 32) {
4951 AstConst* const shiftp = VN_CAST(nodep->rhsp(), Const);
4952 if (shiftp && shiftp->num().mostSetBitP1() <= 32) {
4953 // If (number)<<96'h1, then make it into (number)<<32'h1
4954 V3Number num(shiftp, 32, 0);
4955 num.opAssign(shiftp->num());
4956 AstNode* const shiftrhsp = nodep->rhsp();
4957 nodep->rhsp()->replaceWith(new AstConst(shiftrhsp->fileline(), num));
4958 VL_DO_DANGLING(shiftrhsp->deleteTree(), shiftrhsp);
4959 }
4960 }
4961 }
4962 return nodep; // May edit
4963 }
4964
visit_boolmath_and_or(AstNodeBiop * nodep)4965 void visit_boolmath_and_or(AstNodeBiop* nodep) {
4966 // CALLER: And, Or, Xor, ...
4967 // Lint widths: out width = lhs width = rhs width
4968 // Signed: if lhs & rhs signed
4969 // IEEE-2012 Table 11-21:
4970 // Width: max(LHS, RHS)
4971 UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!");
4972 // If errors are off, we need to follow the spec; thus we really need to do the max()
4973 // because the rhs could be larger, and we need to have proper editing to get the widths
4974 // to be the same for our operations.
4975 if (m_vup->prelim()) { // First stage evaluation
4976 // Determine expression widths only relying on what's in the subops
4977 userIterateAndNext(nodep->lhsp(), WidthVP(CONTEXT, PRELIM).p());
4978 userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p());
4979 checkCvtUS(nodep->lhsp());
4980 checkCvtUS(nodep->rhsp());
4981 const int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width());
4982 const int mwidth = std::max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin());
4983 const bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned());
4984 nodep->dtypeChgWidthSigned(width, mwidth, VSigning::fromBool(expSigned));
4985 }
4986 if (m_vup->final()) {
4987 AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep());
4988 AstNodeDType* const subDTypep = expDTypep;
4989 nodep->dtypeFrom(expDTypep);
4990 // Error report and change sizes for suboperands of this node.
4991 iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP);
4992 iterateCheck(nodep, "RHS", nodep->rhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP);
4993 }
4994 }
4995
visit_add_sub_replace(AstNodeBiop * nodep,bool real_ok)4996 void visit_add_sub_replace(AstNodeBiop* nodep, bool real_ok) {
4997 // CALLER: (real_ok=false) AddS, SubS, ...
4998 // CALLER: (real_ok=true) Add, Sub, ...
4999 // Widths: out width = lhs width = rhs width
5000 // Signed: Replace operator with signed operator, or signed to unsigned
5001 // Real: Replace operator with real operator
5002 // IEEE-2012 Table 11-21:
5003 // Width: max(LHS, RHS)
5004 // If errors are off, we need to follow the spec; thus we really need to do the max()
5005 // because the rhs could be larger, and we need to have proper editing to get the widths
5006 // to be the same for our operations.
5007 //
5008 // if (debug() >= 9) { UINFO(0,"-rus "<<m_vup<<endl); nodep->dumpTree(cout, "-rusin-"); }
5009 if (m_vup->prelim()) { // First stage evaluation
5010 // Determine expression widths only relying on what's in the subops
5011 userIterateAndNext(nodep->lhsp(), WidthVP(CONTEXT, PRELIM).p());
5012 userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p());
5013 if (!real_ok) {
5014 checkCvtUS(nodep->lhsp());
5015 checkCvtUS(nodep->rhsp());
5016 }
5017 if (nodep->lhsp()->isDouble() || nodep->rhsp()->isDouble()) {
5018 spliceCvtD(nodep->lhsp());
5019 spliceCvtD(nodep->rhsp());
5020 if (AstNodeBiop* const newp = replaceWithDVersion(nodep)) {
5021 VL_DANGLING(nodep);
5022 nodep = newp; // Process new node instead
5023 }
5024 nodep->dtypeSetDouble();
5025 iterateCheckReal(nodep, "LHS", nodep->lhsp(), FINAL);
5026 iterateCheckReal(nodep, "RHS", nodep->rhsp(), FINAL);
5027 return;
5028 } else {
5029 const int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width());
5030 const int mwidth = std::max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin());
5031 const bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned());
5032 nodep->dtypeChgWidthSigned(width, mwidth, VSigning::fromBool(expSigned));
5033 }
5034 }
5035 if (m_vup->final()) {
5036 // Parent's data type was computed using the max(upper, nodep->dtype)
5037 AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep());
5038 AstNodeDType* const subDTypep = expDTypep;
5039 nodep->dtypeFrom(expDTypep);
5040 // We don't use LHS && RHS -- unspecified language corner, see t_math_signed5 test
5041 // bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned());
5042 if (AstNodeBiop* const newp = replaceWithUOrSVersion(nodep, expDTypep->isSigned())) {
5043 VL_DANGLING(nodep);
5044 nodep = newp; // Process new node instead
5045 }
5046 // Some warning suppressions
5047 bool lhsWarn = true;
5048 bool rhsWarn = true;
5049 if (VN_IS(nodep, Add) || VN_IS(nodep, Sub)) {
5050 // Warn if user wants extra bit from carry
5051 if (subDTypep->widthMin() == (nodep->lhsp()->widthMin() + 1)) lhsWarn = false;
5052 if (subDTypep->widthMin() == (nodep->rhsp()->widthMin() + 1)) rhsWarn = false;
5053 } else if (VN_IS(nodep, Mul) || VN_IS(nodep, MulS)) {
5054 if (subDTypep->widthMin() >= (nodep->lhsp()->widthMin())) lhsWarn = false;
5055 if (subDTypep->widthMin() >= (nodep->rhsp()->widthMin())) rhsWarn = false;
5056 }
5057 // Final call, so make sure children check their sizes
5058 // Error report and change sizes for suboperands of this node.
5059 iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP,
5060 lhsWarn);
5061 iterateCheck(nodep, "RHS", nodep->rhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP,
5062 rhsWarn);
5063 }
5064 // if (debug() >= 9) nodep->dumpTree(cout, "-rusou-");
5065 }
visit_real_add_sub(AstNodeBiop * nodep)5066 void visit_real_add_sub(AstNodeBiop* nodep) {
5067 // CALLER: AddD, MulD, ...
5068 if (m_vup->prelim()) { // First stage evaluation
5069 // Note similar steps in visit_add_sub_replace promotion to double
5070 iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH);
5071 iterateCheckReal(nodep, "RHS", nodep->rhsp(), BOTH);
5072 nodep->dtypeSetDouble();
5073 }
5074 }
visit_real_neg_ceil(AstNodeUniop * nodep)5075 void visit_real_neg_ceil(AstNodeUniop* nodep) {
5076 // CALLER: Negate, Ceil, Log, ...
5077 if (m_vup->prelim()) { // First stage evaluation
5078 // See alsl visit_negate_not conversion
5079 iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH);
5080 nodep->dtypeSetDouble();
5081 }
5082 }
5083
5084 //----------------------------------------------------------------------
5085 // LOWER LEVEL WIDTH METHODS (none iterate)
5086
widthBad(AstNode * nodep,AstNodeDType * expDTypep)5087 bool widthBad(AstNode* nodep, AstNodeDType* expDTypep) {
5088 const int expWidth = expDTypep->width();
5089 int expWidthMin = expDTypep->widthMin();
5090 UASSERT_OBJ(nodep->dtypep(), nodep,
5091 "Under node " << nodep->prettyTypeName()
5092 << " has no dtype?? Missing Visitor func?");
5093 UASSERT_OBJ(nodep->width() != 0, nodep,
5094 "Under node " << nodep->prettyTypeName()
5095 << " has no expected width?? Missing Visitor func?");
5096 UASSERT_OBJ(expWidth != 0, nodep,
5097 "Node " << nodep->prettyTypeName()
5098 << " has no expected width?? Missing Visitor func?");
5099 if (expWidthMin == 0) expWidthMin = expWidth;
5100 if (nodep->dtypep()->width() == expWidth) return false;
5101 if (nodep->dtypep()->widthSized() && nodep->width() != expWidthMin) return true;
5102 if (!nodep->dtypep()->widthSized() && nodep->widthMin() > expWidthMin) return true;
5103 return false;
5104 }
5105
fixWidthExtend(AstNode * nodep,AstNodeDType * expDTypep,ExtendRule extendRule)5106 void fixWidthExtend(AstNode* nodep, AstNodeDType* expDTypep, ExtendRule extendRule) {
5107 // Fix the width mismatch by extending or truncating bits
5108 // *ONLY* call this from checkWidth()
5109 // Truncation is rarer, but can occur: parameter [3:0] FOO = 64'h12312;
5110 // A(CONSTwide)+B becomes A(CONSTwidened)+B
5111 // A(somewide)+B becomes A(TRUNC(somewide,width))+B
5112 // or A(EXTRACT(somewide,width,0))+B
5113 // Sign extension depends on the type of the *present*
5114 // node, while the output dtype is the *expected* sign.
5115 // It is reasonable to have sign extension with unsigned output,
5116 // for example $unsigned(a)+$signed(b), the SIGNED(B) will be unsigned dtype out
5117 UINFO(4, " widthExtend_(r=" << extendRule << ") old: " << nodep << endl);
5118 if (extendRule == EXTEND_OFF) return;
5119 AstConst* const constp = VN_CAST(nodep, Const);
5120 const int expWidth = expDTypep->width();
5121 if (constp && !constp->num().isNegative()) {
5122 // Save later constant propagation work, just right-size it.
5123 V3Number num(nodep, expWidth);
5124 num.opAssign(constp->num());
5125 num.isSigned(false);
5126 AstNode* const newp = new AstConst(nodep->fileline(), num);
5127 constp->replaceWith(newp);
5128 VL_DO_DANGLING(pushDeletep(constp), constp);
5129 VL_DANGLING(nodep);
5130 nodep = newp;
5131 } else if (expWidth < nodep->width()) {
5132 // Trunc - Extract
5133 AstNRelinker linker;
5134 nodep->unlinkFrBack(&linker);
5135 AstNode* const newp = new AstSel(nodep->fileline(), nodep, 0, expWidth);
5136 newp->didWidth(true); // Don't replace dtype with unsigned
5137 linker.relink(newp);
5138 nodep = newp;
5139 } else {
5140 // Extend
5141 AstNRelinker linker;
5142 nodep->unlinkFrBack(&linker);
5143 bool doSigned = false;
5144 switch (extendRule) {
5145 case EXTEND_ZERO: doSigned = false; break;
5146 case EXTEND_EXP: doSigned = nodep->isSigned() && expDTypep->isSigned(); break;
5147 case EXTEND_LHS: doSigned = nodep->isSigned(); break;
5148 default: nodep->v3fatalSrc("bad case");
5149 }
5150 AstNode* const newp
5151 = (doSigned ? static_cast<AstNode*>(new AstExtendS{nodep->fileline(), nodep})
5152 : static_cast<AstNode*>(new AstExtend{nodep->fileline(), nodep}));
5153 linker.relink(newp);
5154 nodep = newp;
5155 }
5156 if (expDTypep->isDouble() && !nodep->isDouble()) {
5157 // For AstVar init() among others
5158 // TODO do all to-real and to-integer conversions in this function
5159 // rather than in callers
5160 AstNode* const newp = spliceCvtD(nodep);
5161 nodep = newp;
5162 }
5163 nodep->dtypeFrom(expDTypep);
5164 UINFO(4, " _new: " << nodep << endl);
5165 }
5166
fixWidthReduce(AstNode * nodep)5167 void fixWidthReduce(AstNode* nodep) {
5168 // Fix the width mismatch by adding a reduction OR operator
5169 // IF (A(CONSTwide)) becomes IF (A(CONSTreduced))
5170 // IF (A(somewide)) becomes IF (A(REDOR(somewide)))
5171 // Attempt to fix it quietly
5172 const int expWidth = 1;
5173 const int expSigned = false;
5174 UINFO(4, " widthReduce_old: " << nodep << endl);
5175 AstConst* const constp = VN_CAST(nodep, Const);
5176 if (constp) {
5177 V3Number num(nodep, expWidth);
5178 num.opRedOr(constp->num());
5179 num.isSigned(expSigned);
5180 AstNode* const newp = new AstConst(nodep->fileline(), num);
5181 constp->replaceWith(newp);
5182 VL_DO_DANGLING(constp->deleteTree(), constp);
5183 VL_DANGLING(nodep);
5184 nodep = newp;
5185 } else {
5186 AstNRelinker linker;
5187 nodep->unlinkFrBack(&linker);
5188 AstNode* const newp = new AstRedOr(nodep->fileline(), nodep);
5189 linker.relink(newp);
5190 nodep = newp;
5191 }
5192 nodep->dtypeChgWidthSigned(expWidth, expWidth, VSigning::fromBool(expSigned));
5193 UINFO(4, " _new: " << nodep << endl);
5194 }
5195
fixAutoExtend(AstNode * & nodepr,int expWidth)5196 bool fixAutoExtend(AstNode*& nodepr, int expWidth) {
5197 // For SystemVerilog '0,'1,'x,'z, autoextend and don't warn
5198 if (AstConst* const constp = VN_CAST(nodepr, Const)) {
5199 if (constp->num().autoExtend() && !constp->num().sized() && constp->width() == 1) {
5200 // Make it the proper size. Careful of proper extension of 0's/1's
5201 V3Number num(constp, expWidth);
5202 num.opRepl(constp->num(), expWidth); // {width{'1}}
5203 AstNode* const newp = new AstConst(constp->fileline(), num);
5204 // Spec says always unsigned with proper width
5205 if (debug() > 4) constp->dumpTree(cout, " fixAutoExtend_old: ");
5206 if (debug() > 4) newp->dumpTree(cout, " _new: ");
5207 constp->replaceWith(newp);
5208 VL_DO_DANGLING(constp->deleteTree(), constp);
5209 // Tell caller the new constp, and that we changed it.
5210 nodepr = newp;
5211 return true;
5212 }
5213 // X/Z also upper bit extend. In pre-SV only to 32-bits, SV forever.
5214 else if (!constp->num().sized()
5215 // Make it the proper size. Careful of proper extension of 0's/1's
5216 && expWidth > 32 && constp->num().isMsbXZ()) {
5217 constp->v3warn(WIDTH, "Unsized constant being X/Z extended to "
5218 << expWidth << " bits: " << constp->prettyName());
5219 V3Number num(constp, expWidth);
5220 num.opExtendXZ(constp->num(), constp->width());
5221 AstNode* const newp = new AstConst(constp->fileline(), num);
5222 // Spec says always unsigned with proper width
5223 if (debug() > 4) constp->dumpTree(cout, " fixUnszExtend_old: ");
5224 if (debug() > 4) newp->dumpTree(cout, " _new: ");
5225 constp->replaceWith(newp);
5226 VL_DO_DANGLING(constp->deleteTree(), constp);
5227 // Tell caller the new constp, and that we changed it.
5228 nodepr = newp;
5229 return true;
5230 }
5231 }
5232 return false; // No change
5233 }
5234
similarDTypeRecurse(AstNodeDType * node1p,AstNodeDType * node2p)5235 static bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) {
5236 return node1p->skipRefp()->similarDType(node2p->skipRefp());
5237 }
iterateCheckFileDesc(AstNode * nodep,AstNode * underp,Stage stage)5238 void iterateCheckFileDesc(AstNode* nodep, AstNode* underp, Stage stage) {
5239 UASSERT_OBJ(stage == BOTH, nodep, "Bad call");
5240 // underp may change as a result of replacement
5241 underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p());
5242 AstNodeDType* const expDTypep = underp->findUInt32DType();
5243 underp
5244 = iterateCheck(nodep, "file_descriptor", underp, SELF, FINAL, expDTypep, EXTEND_EXP);
5245 if (underp) {} // cppcheck
5246 }
iterateCheckSigned32(AstNode * nodep,const char * side,AstNode * underp,Stage stage)5247 void iterateCheckSigned32(AstNode* nodep, const char* side, AstNode* underp, Stage stage) {
5248 // Coerce child to signed32 if not already. Child is self-determined
5249 // underp may change as a result of replacement
5250 if (stage & PRELIM) {
5251 underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p());
5252 }
5253 if (stage & FINAL) {
5254 AstNodeDType* const expDTypep = nodep->findSigned32DType();
5255 underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP);
5256 }
5257 if (underp) {} // cppcheck
5258 }
iterateCheckReal(AstNode * nodep,const char * side,AstNode * underp,Stage stage)5259 void iterateCheckReal(AstNode* nodep, const char* side, AstNode* underp, Stage stage) {
5260 // Coerce child to real if not already. Child is self-determined
5261 // e.g. nodep=ADDD, underp=ADD in ADDD(ADD(a,b), real-CONST)
5262 // Don't need separate PRELIM and FINAL(double) calls;
5263 // as if resolves to double, the BOTH correctly resolved double,
5264 // otherwise self-determined was correct
5265 // underp may change as a result of replacement
5266 if (stage & PRELIM) {
5267 underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p());
5268 }
5269 if (stage & FINAL) {
5270 AstNodeDType* const expDTypep = nodep->findDoubleDType();
5271 underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP);
5272 }
5273 if (underp) {} // cppcheck
5274 }
iterateCheckString(AstNode * nodep,const char * side,AstNode * underp,Stage stage)5275 void iterateCheckString(AstNode* nodep, const char* side, AstNode* underp, Stage stage) {
5276 if (stage & PRELIM) {
5277 underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p());
5278 }
5279 if (stage & FINAL) {
5280 AstNodeDType* const expDTypep = nodep->findStringDType();
5281 underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP);
5282 }
5283 if (underp) {} // cppcheck
5284 }
iterateCheckTyped(AstNode * nodep,const char * side,AstNode * underp,AstNodeDType * expDTypep,Stage stage)5285 void iterateCheckTyped(AstNode* nodep, const char* side, AstNode* underp,
5286 AstNodeDType* expDTypep, Stage stage) {
5287 if (stage & PRELIM) {
5288 underp = userIterateSubtreeReturnEdits(underp, WidthVP(expDTypep, PRELIM).p());
5289 }
5290 if (stage & FINAL) {
5291 underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP);
5292 }
5293 if (underp) {} // cppcheck
5294 }
iterateCheckSizedSelf(AstNode * nodep,const char * side,AstNode * underp,Determ determ,Stage stage)5295 void iterateCheckSizedSelf(AstNode* nodep, const char* side, AstNode* underp, Determ determ,
5296 Stage stage) {
5297 // Coerce child to any sized-number data type; child is self-determined
5298 // i.e. isolated from expected type.
5299 // e.g. nodep=CONCAT, underp=lhs in CONCAT(lhs,rhs)
5300 UASSERT_OBJ(determ == SELF, nodep, "Bad call");
5301 UASSERT_OBJ(stage == FINAL || stage == BOTH, nodep, "Bad call");
5302 // underp may change as a result of replacement
5303 if (stage & PRELIM) {
5304 underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p());
5305 }
5306 underp = checkCvtUS(underp);
5307 AstNodeDType* const expDTypep = underp->dtypep();
5308 underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP);
5309 if (underp) {} // cppcheck
5310 }
iterateCheckAssign(AstNode * nodep,const char * side,AstNode * rhsp,Stage stage,AstNodeDType * lhsDTypep)5311 void iterateCheckAssign(AstNode* nodep, const char* side, AstNode* rhsp, Stage stage,
5312 AstNodeDType* lhsDTypep) {
5313 // Check using assignment-like context rules
5314 // if (debug()) nodep->dumpTree(cout, "-checkass: ");
5315 UASSERT_OBJ(stage == FINAL, nodep, "Bad width call");
5316 // We iterate and size the RHS based on the result of RHS evaluation
5317 const bool lhsStream
5318 = (VN_IS(nodep, NodeAssign) && VN_IS(VN_AS(nodep, NodeAssign)->lhsp(), NodeStream));
5319 rhsp = iterateCheck(nodep, side, rhsp, ASSIGN, FINAL, lhsDTypep,
5320 lhsStream ? EXTEND_OFF : EXTEND_LHS);
5321 // if (debug()) nodep->dumpTree(cout, "-checkout: ");
5322 if (rhsp) {} // cppcheck
5323 }
5324
iterateCheckBool(AstNode * nodep,const char * side,AstNode * underp,Stage stage)5325 void iterateCheckBool(AstNode* nodep, const char* side, AstNode* underp, Stage stage) {
5326 UASSERT_OBJ(stage == BOTH, nodep,
5327 "Bad call"); // Booleans always self-determined so do BOTH at once
5328 // Underp is used in a self-determined but boolean context, reduce a
5329 // multibit number to one bit
5330 // stage is always BOTH so not passed as argument
5331 // underp may change as a result of replacement
5332 UASSERT_OBJ(underp, nodep, "Node has no type");
5333 underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, BOTH).p());
5334 UASSERT_OBJ(underp && underp->dtypep(), nodep,
5335 "Node has no type"); // Perhaps forgot to do a prelim visit on it?
5336 //
5337 // For DOUBLE under a logical op, add implied test against zero, never a warning
5338 if (underp && underp->isDouble()) {
5339 UINFO(6, " spliceCvtCmpD0: " << underp << endl);
5340 AstNRelinker linker;
5341 underp->unlinkFrBack(&linker);
5342 AstNode* const newp
5343 = new AstNeqD(nodep->fileline(), underp,
5344 new AstConst(nodep->fileline(), AstConst::RealDouble(), 0.0));
5345 linker.relink(newp);
5346 } else if (VN_IS(underp->dtypep(), ClassRefDType)
5347 || (VN_IS(underp->dtypep(), BasicDType)
5348 && VN_AS(underp->dtypep(), BasicDType)->keyword()
5349 == AstBasicDTypeKwd::CHANDLE)) {
5350 // Allow warning-free "if (handle)"
5351 VL_DO_DANGLING(fixWidthReduce(underp), underp); // Changed
5352 } else if (!underp->dtypep()->basicp()) {
5353 nodep->v3error("Logical operator " << nodep->prettyTypeName()
5354 << " expects a non-complex data type on the "
5355 << side << ".");
5356 underp->replaceWith(new AstConst(nodep->fileline(), AstConst::BitFalse()));
5357 VL_DO_DANGLING(pushDeletep(underp), underp);
5358 } else {
5359 const bool bad = widthBad(underp, nodep->findBitDType());
5360 if (bad) {
5361 { // if (warnOn), but not needed here
5362 if (debug() > 4) nodep->backp()->dumpTree(cout, " back: ");
5363 nodep->v3warn(WIDTH, "Logical operator "
5364 << nodep->prettyTypeName() << " expects 1 bit on the "
5365 << side << ", but " << side << "'s "
5366 << underp->prettyTypeName() << " generates "
5367 << underp->width()
5368 << (underp->width() != underp->widthMin()
5369 ? " or " + cvtToStr(underp->widthMin())
5370 : "")
5371 << " bits.");
5372 }
5373 VL_DO_DANGLING(fixWidthReduce(underp), underp); // Changed
5374 }
5375 }
5376 }
5377
iterateCheck(AstNode * nodep,const char * side,AstNode * underp,Determ determ,Stage stage,AstNodeDType * expDTypep,ExtendRule extendRule,bool warnOn=true)5378 AstNode* iterateCheck(AstNode* nodep, const char* side, AstNode* underp, Determ determ,
5379 Stage stage, AstNodeDType* expDTypep, ExtendRule extendRule,
5380 bool warnOn = true) {
5381 // Perform data type check on underp, which is underneath nodep used for error reporting
5382 // Returns the new underp
5383 // Conversion to/from doubles and integers are before iterating.
5384 UASSERT_OBJ(stage == FINAL, nodep, "Bad state to iterateCheck");
5385 UASSERT_OBJ(underp && underp->dtypep(), nodep,
5386 "Node has no type"); // Perhaps forgot to do a prelim visit on it?
5387 if (VN_IS(underp, NodeDType)) { // Note the node itself, not node's data type
5388 // Must be near top of these checks as underp->dtypep() will look normal
5389 underp->v3error(ucfirst(nodep->prettyOperatorName())
5390 << " expected non-datatype " << side << " but '" << underp->name()
5391 << "' is a datatype.");
5392 } else if (expDTypep == underp->dtypep()) { // Perfect
5393 underp = userIterateSubtreeReturnEdits(underp, WidthVP(expDTypep, FINAL).p());
5394 } else if (expDTypep->isDouble() && underp->isDouble()) { // Also good
5395 underp = userIterateSubtreeReturnEdits(underp, WidthVP(expDTypep, FINAL).p());
5396 } else if (expDTypep->isDouble() && !underp->isDouble()) {
5397 AstNode* const oldp
5398 = underp; // Need FINAL on children; otherwise splice would block it
5399 underp = spliceCvtD(underp);
5400 underp = userIterateSubtreeReturnEdits(oldp, WidthVP(SELF, FINAL).p());
5401 } else if (!expDTypep->isDouble() && underp->isDouble()) {
5402 AstNode* const oldp
5403 = underp; // Need FINAL on children; otherwise splice would block it
5404 underp = spliceCvtS(underp, true, expDTypep->width()); // Round RHS
5405 underp = userIterateSubtreeReturnEdits(oldp, WidthVP(SELF, FINAL).p());
5406 } else if (expDTypep->isString() && !underp->dtypep()->isString()) {
5407 AstNode* const oldp
5408 = underp; // Need FINAL on children; otherwise splice would block it
5409 underp = spliceCvtString(underp);
5410 underp = userIterateSubtreeReturnEdits(oldp, WidthVP(SELF, FINAL).p());
5411 } else {
5412 const AstBasicDType* const expBasicp = expDTypep->basicp();
5413 const AstBasicDType* const underBasicp = underp->dtypep()->basicp();
5414 if (expBasicp && underBasicp) {
5415 AstNodeDType* subDTypep = expDTypep;
5416 // We then iterate FINAL before width fixes, as if the under-operation
5417 // is e.g. an ADD, the ADD will auto-adjust to the proper data type
5418 // or if another operation e.g. ATOI will not.
5419 if (determ == SELF) {
5420 underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, FINAL).p());
5421 } else if (determ == ASSIGN) {
5422 // IEEE: Signedness is solely determined by the RHS
5423 // (underp), not by the LHS (expDTypep)
5424 if (underp->isSigned() != subDTypep->isSigned()
5425 || underp->width() != subDTypep->width()) {
5426 subDTypep = nodep->findLogicDType(
5427 std::max(subDTypep->width(), underp->width()),
5428 std::max(subDTypep->widthMin(), underp->widthMin()),
5429 VSigning::fromBool(underp->isSigned()));
5430 UINFO(9, "Assignment of opposite-signed RHS to LHS: " << nodep << endl);
5431 }
5432 underp = userIterateSubtreeReturnEdits(underp, WidthVP(subDTypep, FINAL).p());
5433 } else {
5434 underp = userIterateSubtreeReturnEdits(underp, WidthVP(subDTypep, FINAL).p());
5435 }
5436 // Note the check uses the expected size, not the child's subDTypep as we want the
5437 // child node's width to end up correct for the assignment (etc)
5438 widthCheckSized(nodep, side, underp, expDTypep, extendRule, warnOn);
5439 } else if (!VN_IS(expDTypep, IfaceRefDType)
5440 && VN_IS(underp->dtypep(), IfaceRefDType)) {
5441 underp->v3error(ucfirst(nodep->prettyOperatorName())
5442 << " expected non-interface on " << side << " but '"
5443 << underp->name() << "' is an interface.");
5444 } else {
5445 // Hope it just works out (perhaps a cast will deal with it)
5446 underp = userIterateSubtreeReturnEdits(underp, WidthVP(expDTypep, FINAL).p());
5447 }
5448 }
5449 return underp;
5450 }
5451
widthCheckSized(AstNode * nodep,const char * side,AstNode * underp,AstNodeDType * expDTypep,ExtendRule extendRule,bool warnOn=true)5452 void widthCheckSized(AstNode* nodep, const char* side,
5453 AstNode* underp, // Node to be checked or have typecast added in front of
5454 AstNodeDType* expDTypep, ExtendRule extendRule, bool warnOn = true) {
5455 // Issue warnings on sized number width mismatches, then do appropriate size extension
5456 // Generally iterateCheck is what is wanted instead of this
5457 // UINFO(9,"wchk "<<side<<endl<<" "<<nodep<<endl<<" "<<underp<<endl<<" e="<<expDTypep<<"
5458 // i"<<warnOn<<endl);
5459 const AstBasicDType* const expBasicp = expDTypep->basicp();
5460 const AstBasicDType* const underBasicp = underp->dtypep()->basicp();
5461 if (expDTypep == underp->dtypep()) {
5462 return; // Same type must match
5463 } else if (!expBasicp || expBasicp->isDouble() || !underBasicp
5464 || underBasicp->isDouble()) {
5465 // This is perhaps a v3fatalSrc as we should have checked the types
5466 // before calling widthCheck, but we may have missed a non-sized
5467 // check in earlier code, so might as well assume it is the users'
5468 // fault.
5469 nodep->v3error(ucfirst(nodep->prettyOperatorName())
5470 << " expected non-complex non-double " << side << " in width check");
5471 #if VL_DEBUG
5472 nodep->v3fatalSrc("widthCheckSized should not be called on doubles/complex types");
5473 #endif
5474 return;
5475 } else {
5476 const int expWidth = expDTypep->width();
5477 int expWidthMin = expDTypep->widthMin();
5478 if (expWidthMin == 0) expWidthMin = expWidth;
5479 const bool bad = widthBad(underp, expDTypep);
5480 if ((bad || underp->width() != expWidth) && fixAutoExtend(underp /*ref*/, expWidth)) {
5481 underp = nullptr; // Changes underp
5482 return;
5483 }
5484 if (VN_IS(underp, Const) && VN_AS(underp, Const)->num().isFromString()
5485 && expWidth > underp->width()
5486 && (((expWidth - underp->width()) % 8) == 0)) { // At least it's character sized
5487 // reg [31:0] == "foo" we'll consider probably fine.
5488 // Maybe this should be a special warning? Not for now.
5489 warnOn = false;
5490 }
5491 if ((VN_IS(nodep, Add) && underp->width() == 1 && underp->isOne())
5492 || (VN_IS(nodep, Sub) && underp->width() == 1 && underp->isOne()
5493 && 0 == strcmp(side, "RHS"))) {
5494 // "foo + 1'b1", or "foo - 1'b1" are very common, people assume
5495 // they extend correctly
5496 warnOn = false;
5497 }
5498 if (bad && warnOn) {
5499 if (debug() > 4) nodep->backp()->dumpTree(cout, " back: ");
5500 nodep->v3warn(
5501 WIDTH, ucfirst(nodep->prettyOperatorName())
5502 << " expects " << expWidth
5503 << (expWidth != expWidthMin ? " or " + cvtToStr(expWidthMin) : "")
5504 << " bits on the " << side << ", but " << side << "'s "
5505 << underp->prettyTypeName() << " generates " << underp->width()
5506 << (underp->width() != underp->widthMin()
5507 ? " or " + cvtToStr(underp->widthMin())
5508 : "")
5509 << " bits.");
5510 }
5511 if (bad || underp->width() != expWidth) {
5512 // If we're in an NodeAssign, don't truncate the RHS if the LHS is
5513 // a NodeStream. The streaming operator changes the rules regarding
5514 // which bits to truncate.
5515 const AstNodeAssign* assignp = VN_CAST(nodep, NodeAssign);
5516 const AstPin* pinp = VN_CAST(nodep, Pin);
5517 if (assignp && VN_IS(assignp->lhsp(), NodeStream)) {
5518 } else if (pinp && pinp->modVarp()->direction() != VDirection::INPUT) {
5519 // V3Inst::pinReconnectSimple must deal
5520 UINFO(5, "pinInSizeMismatch: " << pinp);
5521 } else {
5522 VL_DO_DANGLING(fixWidthExtend(underp, expDTypep, extendRule), underp);
5523 }
5524 }
5525 }
5526 }
5527
5528 //----------------------------------------------------------------------
5529 // SIGNED/DOUBLE METHODS
5530
checkCvtUS(AstNode * nodep)5531 AstNode* checkCvtUS(AstNode* nodep) {
5532 if (nodep && nodep->isDouble()) {
5533 nodep->v3error("Expected integral (non-" << nodep->dtypep()->prettyDTypeName()
5534 << ") input to "
5535 << nodep->backp()->prettyTypeName());
5536 nodep = spliceCvtS(nodep, true, 32);
5537 }
5538 return nodep;
5539 }
5540
spliceCvtD(AstNode * nodep)5541 AstNode* spliceCvtD(AstNode* nodep) {
5542 // For integer used in REAL context, convert to real
5543 // We don't warn here, "2.0 * 2" is common and reasonable
5544 if (nodep && !nodep->dtypep()->skipRefp()->isDouble()) {
5545 UINFO(6, " spliceCvtD: " << nodep << endl);
5546 AstNRelinker linker;
5547 nodep->unlinkFrBack(&linker);
5548 AstNode* newp;
5549 if (nodep->dtypep()->skipRefp()->isSigned()) {
5550 newp = new AstISToRD(nodep->fileline(), nodep);
5551 } else {
5552 newp = new AstIToRD(nodep->fileline(), nodep);
5553 }
5554 linker.relink(newp);
5555 return newp;
5556 } else {
5557 return nodep;
5558 }
5559 }
spliceCvtS(AstNode * nodep,bool warnOn,int width)5560 AstNode* spliceCvtS(AstNode* nodep, bool warnOn, int width) {
5561 // IEEE-2012 11.8.1: Signed: Type coercion creates signed
5562 // 11.8.2: Argument to convert is self-determined
5563 if (nodep && nodep->dtypep()->skipRefp()->isDouble()) {
5564 UINFO(6, " spliceCvtS: " << nodep << endl);
5565 AstNRelinker linker;
5566 nodep->unlinkFrBack(&linker);
5567 if (const AstConst* const constp = VN_CAST(nodep, Const)) {
5568 // We convert to/from vlsint32 rather than use floor() as want to make sure is
5569 // representable in integer's number of bits
5570 if (constp->isDouble()
5571 && v3EpsilonEqual(
5572 constp->num().toDouble(),
5573 static_cast<double>(static_cast<vlsint32_t>(constp->num().toDouble())))) {
5574 warnOn = false;
5575 }
5576 }
5577 if (warnOn) nodep->v3warn(REALCVT, "Implicit conversion of real to integer");
5578 AstNode* const newp = new AstRToIRoundS(nodep->fileline(), nodep);
5579 linker.relink(newp);
5580 newp->dtypeSetBitSized(width, VSigning::SIGNED);
5581 return newp;
5582 } else {
5583 return nodep;
5584 }
5585 }
spliceCvtString(AstNode * nodep)5586 AstNode* spliceCvtString(AstNode* nodep) {
5587 // IEEE-2012 11.8.1: Signed: Type coercion creates signed
5588 // 11.8.2: Argument to convert is self-determined
5589 if (nodep && !(nodep->dtypep()->basicp() && nodep->dtypep()->basicp()->isString())) {
5590 UINFO(6, " spliceCvtString: " << nodep << endl);
5591 AstNRelinker linker;
5592 nodep->unlinkFrBack(&linker);
5593 AstNode* const newp = new AstCvtPackString(nodep->fileline(), nodep);
5594 linker.relink(newp);
5595 return newp;
5596 } else {
5597 return nodep;
5598 }
5599 }
replaceWithUOrSVersion(AstNodeBiop * nodep,bool signedFlavorNeeded)5600 AstNodeBiop* replaceWithUOrSVersion(AstNodeBiop* nodep, bool signedFlavorNeeded) {
5601 // Given a signed/unsigned node type, create the opposite type
5602 // Return new node or nullptr if nothing
5603 if (signedFlavorNeeded == nodep->signedFlavor()) return nullptr;
5604 if (!nodep->dtypep()) nodep->dtypeFrom(nodep->lhsp());
5605 // To simplify callers, some node types don't need to change
5606 switch (nodep->type()) {
5607 case AstType::atEq: nodep->dtypeChgSigned(signedFlavorNeeded); return nullptr;
5608 case AstType::atNeq: nodep->dtypeChgSigned(signedFlavorNeeded); return nullptr;
5609 case AstType::atEqCase: nodep->dtypeChgSigned(signedFlavorNeeded); return nullptr;
5610 case AstType::atNeqCase: nodep->dtypeChgSigned(signedFlavorNeeded); return nullptr;
5611 case AstType::atEqWild: nodep->dtypeChgSigned(signedFlavorNeeded); return nullptr;
5612 case AstType::atNeqWild: nodep->dtypeChgSigned(signedFlavorNeeded); return nullptr;
5613 case AstType::atAdd: nodep->dtypeChgSigned(signedFlavorNeeded); return nullptr;
5614 case AstType::atSub: nodep->dtypeChgSigned(signedFlavorNeeded); return nullptr;
5615 case AstType::atShiftL: nodep->dtypeChgSigned(signedFlavorNeeded); return nullptr;
5616 default: break;
5617 }
5618 FileLine* const fl = nodep->fileline();
5619 AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
5620 AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
5621 AstNodeBiop* newp = nullptr;
5622 switch (nodep->type()) {
5623 case AstType::atGt: newp = new AstGtS(fl, lhsp, rhsp); break;
5624 case AstType::atGtS: newp = new AstGt(fl, lhsp, rhsp); break;
5625 case AstType::atGte: newp = new AstGteS(fl, lhsp, rhsp); break;
5626 case AstType::atGteS: newp = new AstGte(fl, lhsp, rhsp); break;
5627 case AstType::atLt: newp = new AstLtS(fl, lhsp, rhsp); break;
5628 case AstType::atLtS: newp = new AstLt(fl, lhsp, rhsp); break;
5629 case AstType::atLte: newp = new AstLteS(fl, lhsp, rhsp); break;
5630 case AstType::atLteS: newp = new AstLte(fl, lhsp, rhsp); break;
5631 case AstType::atDiv: newp = new AstDivS(fl, lhsp, rhsp); break;
5632 case AstType::atDivS: newp = new AstDiv(fl, lhsp, rhsp); break;
5633 case AstType::atModDiv: newp = new AstModDivS(fl, lhsp, rhsp); break;
5634 case AstType::atModDivS: newp = new AstModDiv(fl, lhsp, rhsp); break;
5635 case AstType::atMul: newp = new AstMulS(fl, lhsp, rhsp); break;
5636 case AstType::atMulS: newp = new AstMul(fl, lhsp, rhsp); break;
5637 case AstType::atShiftR: newp = new AstShiftRS(fl, lhsp, rhsp); break;
5638 case AstType::atShiftRS: newp = new AstShiftR(fl, lhsp, rhsp); break;
5639 default: // LCOV_EXCL_LINE
5640 nodep->v3fatalSrc("Node needs sign change, but bad case: " << nodep);
5641 break;
5642 }
5643 UINFO(6, " ReplaceWithUOrSVersion: " << nodep << " w/ " << newp << endl);
5644 nodep->replaceWith(newp);
5645 newp->dtypeFrom(nodep);
5646 VL_DO_DANGLING(pushDeletep(nodep), nodep);
5647 return newp;
5648 }
replaceWithDVersion(AstNodeBiop * nodep)5649 AstNodeBiop* replaceWithDVersion(AstNodeBiop* nodep) {
5650 // Given a signed/unsigned node type, create the opposite type
5651 // Return new node or nullptr if nothing
5652 if (nodep->doubleFlavor()) return nullptr;
5653 FileLine* const fl = nodep->fileline();
5654 AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
5655 AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
5656 AstNodeBiop* newp = nullptr;
5657 // No width change on output;... // All below have bool or double outputs
5658 switch (nodep->type()) {
5659 case AstType::atAdd: newp = new AstAddD(fl, lhsp, rhsp); break;
5660 case AstType::atSub: newp = new AstSubD(fl, lhsp, rhsp); break;
5661 case AstType::atPow: newp = new AstPowD(fl, lhsp, rhsp); break;
5662 case AstType::atEq:
5663 case AstType::atEqCase: newp = new AstEqD(fl, lhsp, rhsp); break;
5664 case AstType::atNeq:
5665 case AstType::atNeqCase: newp = new AstNeqD(fl, lhsp, rhsp); break;
5666 case AstType::atGt:
5667 case AstType::atGtS: newp = new AstGtD(fl, lhsp, rhsp); break;
5668 case AstType::atGte:
5669 case AstType::atGteS: newp = new AstGteD(fl, lhsp, rhsp); break;
5670 case AstType::atLt:
5671 case AstType::atLtS: newp = new AstLtD(fl, lhsp, rhsp); break;
5672 case AstType::atLte:
5673 case AstType::atLteS: newp = new AstLteD(fl, lhsp, rhsp); break;
5674 case AstType::atDiv:
5675 case AstType::atDivS: newp = new AstDivD(fl, lhsp, rhsp); break;
5676 case AstType::atMul:
5677 case AstType::atMulS: newp = new AstMulD(fl, lhsp, rhsp); break;
5678 default: // LCOV_EXCL_LINE
5679 nodep->v3fatalSrc("Node needs conversion to double, but bad case: " << nodep);
5680 break;
5681 }
5682 UINFO(6, " ReplaceWithDVersion: " << nodep << " w/ " << newp << endl);
5683 nodep->replaceWith(newp);
5684 // No width change; the default created type (bool or double) is correct
5685 VL_DO_DANGLING(pushDeletep(nodep), nodep);
5686 return newp;
5687 }
replaceWithNVersion(AstNodeBiop * nodep)5688 AstNodeBiop* replaceWithNVersion(AstNodeBiop* nodep) {
5689 // Given a signed/unsigned node type, replace with string version
5690 // Return new node or nullptr if nothing
5691 if (nodep->stringFlavor()) return nullptr;
5692 FileLine* const fl = nodep->fileline();
5693 AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
5694 AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
5695 AstNodeBiop* newp = nullptr;
5696 // No width change on output;... // All below have bool or double outputs
5697 switch (nodep->type()) {
5698 case AstType::atEq:
5699 case AstType::atEqCase: newp = new AstEqN(fl, lhsp, rhsp); break;
5700 case AstType::atNeq:
5701 case AstType::atNeqCase: newp = new AstNeqN(fl, lhsp, rhsp); break;
5702 case AstType::atGt:
5703 case AstType::atGtS: newp = new AstGtN(fl, lhsp, rhsp); break;
5704 case AstType::atGte:
5705 case AstType::atGteS: newp = new AstGteN(fl, lhsp, rhsp); break;
5706 case AstType::atLt:
5707 case AstType::atLtS: newp = new AstLtN(fl, lhsp, rhsp); break;
5708 case AstType::atLte:
5709 case AstType::atLteS: newp = new AstLteN(fl, lhsp, rhsp); break;
5710 default: // LCOV_EXCL_LINE
5711 nodep->v3fatalSrc("Node needs conversion to string, but bad case: " << nodep);
5712 break;
5713 }
5714 UINFO(6, " ReplaceWithNVersion: " << nodep << " w/ " << newp << endl);
5715 nodep->replaceWith(newp);
5716 // No width change; the default created type (bool or string) is correct
5717 VL_DO_DANGLING(pushDeletep(nodep), nodep);
5718 return newp;
5719 }
replaceWithDVersion(AstNodeUniop * nodep)5720 AstNodeUniop* replaceWithDVersion(AstNodeUniop* nodep) {
5721 // Given a signed/unsigned node type, create the opposite type
5722 // Return new node or nullptr if nothing
5723 if (nodep->doubleFlavor()) return nullptr;
5724 FileLine* const fl = nodep->fileline();
5725 AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
5726 AstNodeUniop* newp = nullptr;
5727 switch (nodep->type()) {
5728 case AstType::atNegate: newp = new AstNegateD(fl, lhsp); break;
5729 default: // LCOV_EXCL_LINE
5730 nodep->v3fatalSrc("Node needs conversion to double, but bad case: " << nodep);
5731 break;
5732 }
5733 UINFO(6, " ReplaceWithDVersion: " << nodep << " w/ " << newp << endl);
5734 nodep->replaceWith(newp);
5735 newp->dtypeFrom(nodep);
5736 VL_DO_DANGLING(pushDeletep(nodep), nodep);
5737 return newp;
5738 }
5739
5740 //----------------------------------------------------------------------
5741 // METHODS - strings
5742
replaceWithSFormat(AstMethodCall * nodep,const string & format)5743 void replaceWithSFormat(AstMethodCall* nodep, const string& format) {
5744 // For string.itoa and similar, replace with SFormatF
5745 const AstArg* argp = VN_CAST(nodep->pinsp(), Arg);
5746 if (!argp) {
5747 nodep->v3error("Argument needed for string." + nodep->prettyName() + " method");
5748 return;
5749 }
5750 AstNodeVarRef* const fromp = VN_AS(nodep->fromp()->unlinkFrBack(), VarRef);
5751 AstNode* const newp = new AstAssign(
5752 nodep->fileline(), fromp,
5753 new AstSFormatF(nodep->fileline(), format, false, argp->exprp()->unlinkFrBack()));
5754 fromp->access(VAccess::WRITE);
5755 nodep->replaceWith(newp);
5756 VL_DO_DANGLING(pushDeletep(nodep), nodep);
5757 }
5758
5759 //----------------------------------------------------------------------
5760 // METHODS - data types
5761
iterateEditMoveDTypep(AstNode * parentp,AstNodeDType * dtnodep)5762 AstNodeDType* iterateEditMoveDTypep(AstNode* parentp, AstNodeDType* dtnodep) {
5763 UASSERT_OBJ(dtnodep, parentp, "Caller should check for nullptr before computing dtype");
5764 // Iterate into a data type to resolve that type.
5765 // The data type may either:
5766 // 1. Be a child (typically getChildDTypep() returns it)
5767 // DTypes at parse time get added as these to some node types
5768 // such as AstVars.
5769 // This function will move it to global scope (that is #2
5770 // will now apply).
5771 // 2. Be under the Netlist and pointed to by an Ast member variable
5772 // (typically refDTypep() or dtypep() returns it)
5773 // so removing/changing a variable won't lose the dtype
5774
5775 // Case #1 above applies?
5776 const bool child1 = (parentp->getChildDTypep() == dtnodep);
5777 const bool child2 = (parentp->getChild2DTypep() == dtnodep);
5778 if (child1 || child2) {
5779 UINFO(9, "iterateEditMoveDTypep child iterating " << dtnodep << endl);
5780 // Iterate, this might edit the dtypes which means dtnodep now lost
5781 VL_DO_DANGLING(userIterate(dtnodep, nullptr), dtnodep);
5782 // Figure out the new dtnodep, remained a child of parent so find it there
5783 dtnodep = child1 ? parentp->getChildDTypep() : parentp->getChild2DTypep();
5784 UASSERT_OBJ(dtnodep, parentp, "iterateEditMoveDTypep lost pointer to child");
5785 UASSERT_OBJ(dtnodep->didWidth(), parentp,
5786 "iterateEditMoveDTypep didn't get width resolution of "
5787 << dtnodep->prettyTypeName());
5788 // Move to under netlist
5789 UINFO(9, "iterateEditMoveDTypep child moving " << dtnodep << endl);
5790 dtnodep->unlinkFrBack();
5791 v3Global.rootp()->typeTablep()->addTypesp(dtnodep);
5792 }
5793 if (!dtnodep->didWidth()) {
5794 UINFO(9, "iterateEditMoveDTypep pointer iterating " << dtnodep << endl);
5795 // See notes in visit(AstBracketArrayDType*)
5796 UASSERT_OBJ(!VN_IS(dtnodep, BracketArrayDType), parentp,
5797 "Brackets should have been iterated as children");
5798 userIterate(dtnodep, nullptr);
5799 UASSERT_OBJ(dtnodep->didWidth(), parentp,
5800 "iterateEditMoveDTypep didn't get width resolution");
5801 }
5802 return dtnodep;
5803 }
5804
dimensionValue(FileLine * fileline,AstNodeDType * nodep,AstAttrType attrType,int dim)5805 AstConst* dimensionValue(FileLine* fileline, AstNodeDType* nodep, AstAttrType attrType,
5806 int dim) {
5807 // Return the dimension value for the specified attribute and constant dimension
5808 AstNodeDType* dtypep = nodep->skipRefp();
5809 VNumRange declRange; // ranged() set false
5810 for (int i = 1; i <= dim; ++i) {
5811 // UINFO(9, " dim at "<<dim<<" "<<dtypep<<endl);
5812 declRange = VNumRange(); // ranged() set false
5813 if (const AstNodeArrayDType* const adtypep = VN_CAST(dtypep, NodeArrayDType)) {
5814 declRange = adtypep->declRange();
5815 if (i < dim) dtypep = adtypep->subDTypep()->skipRefp();
5816 continue;
5817 } else if (const AstNodeUOrStructDType* const adtypep
5818 = VN_CAST(dtypep, NodeUOrStructDType)) {
5819 declRange = adtypep->declRange();
5820 break; // Sub elements don't look like arrays and can't iterate into
5821 } else if (const AstBasicDType* const adtypep = VN_CAST(dtypep, BasicDType)) {
5822 if (adtypep->isRanged()) declRange = adtypep->declRange();
5823 break;
5824 }
5825 break; // LCOV_EXCL_LINE
5826 }
5827 AstConst* valp = nullptr; // If nullptr, construct from val
5828 int val = 0;
5829 switch (attrType) {
5830 case AstAttrType::DIM_BITS: {
5831 int bits = 1;
5832 while (dtypep) {
5833 // UINFO(9, " bits at "<<bits<<" "<<dtypep<<endl);
5834 if (const AstNodeArrayDType* const adtypep = VN_CAST(dtypep, NodeArrayDType)) {
5835 bits *= adtypep->declRange().elements();
5836 dtypep = adtypep->subDTypep()->skipRefp();
5837 continue;
5838 } else if (const AstNodeUOrStructDType* const adtypep
5839 = VN_CAST(dtypep, NodeUOrStructDType)) {
5840 bits *= adtypep->width();
5841 break;
5842 } else if (const AstBasicDType* const adtypep = VN_CAST(dtypep, BasicDType)) {
5843 bits *= adtypep->width();
5844 break;
5845 }
5846 break;
5847 }
5848 if (dim == 0) {
5849 val = 0;
5850 } else if (dim == 1 && !declRange.ranged()
5851 && bits == 1) { // $bits should be sane for non-arrays
5852 val = nodep->width();
5853 } else {
5854 val = bits;
5855 }
5856 break; // LCOV_EXCL_LINE
5857 }
5858 case AstAttrType::DIM_HIGH: val = !declRange.ranged() ? 0 : declRange.hi(); break;
5859 case AstAttrType::DIM_LEFT: val = !declRange.ranged() ? 0 : declRange.left(); break;
5860 case AstAttrType::DIM_LOW: val = !declRange.ranged() ? 0 : declRange.lo(); break;
5861 case AstAttrType::DIM_RIGHT: val = !declRange.ranged() ? 0 : declRange.right(); break;
5862 case AstAttrType::DIM_INCREMENT:
5863 val = (declRange.ranged() && declRange.littleEndian()) ? -1 : 1;
5864 break;
5865 case AstAttrType::DIM_SIZE: val = !declRange.ranged() ? 0 : declRange.elements(); break;
5866 default: nodep->v3fatalSrc("Missing DIM ATTR type case"); break;
5867 }
5868 if (!valp) valp = new AstConst(fileline, AstConst::Signed32(), val);
5869 UINFO(9, " $dimension " << attrType.ascii() << "(" << cvtToHex(dtypep) << "," << dim
5870 << ")=" << valp << endl);
5871 return valp;
5872 }
dimensionVarp(AstNodeDType * nodep,AstAttrType attrType,uint32_t msbdim)5873 AstVar* dimensionVarp(AstNodeDType* nodep, AstAttrType attrType, uint32_t msbdim) {
5874 // Return a variable table which has specified dimension properties for this variable
5875 const auto pos = m_tableMap.find(std::make_pair(nodep, attrType));
5876 if (pos != m_tableMap.end()) return pos->second;
5877 AstNodeArrayDType* const vardtypep
5878 = new AstUnpackArrayDType(nodep->fileline(), nodep->findSigned32DType(),
5879 new AstRange(nodep->fileline(), msbdim, 0));
5880 AstInitArray* const initp = new AstInitArray(nodep->fileline(), vardtypep, nullptr);
5881 v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
5882 AstVar* const varp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
5883 "__Vdimtab_" + VString::downcase(attrType.ascii())
5884 + cvtToStr(m_dtTables++),
5885 vardtypep);
5886 varp->isConst(true);
5887 varp->isStatic(true);
5888 varp->valuep(initp);
5889 // Add to root, as don't know module we are in, and aids later structure sharing
5890 v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp);
5891 // Element 0 is a non-index and has speced values
5892 initp->addValuep(dimensionValue(nodep->fileline(), nodep, attrType, 0));
5893 for (unsigned i = 1; i < msbdim + 1; ++i) {
5894 initp->addValuep(dimensionValue(nodep->fileline(), nodep, attrType, i));
5895 }
5896 userIterate(varp, nullptr); // May have already done $unit so must do this var
5897 m_tableMap.emplace(std::make_pair(nodep, attrType), varp);
5898 return varp;
5899 }
enumMaxValue(const AstNode * errNodep,const AstEnumDType * adtypep)5900 uint64_t enumMaxValue(const AstNode* errNodep, const AstEnumDType* adtypep) {
5901 // Most enums unless overridden are 32 bits, so we size array
5902 // based on max enum value used.
5903 // Ideally we would have a fast algorithm when a number is
5904 // of small width and complete and so can use an array, and
5905 // a map for when the value is many bits and sparse.
5906 uint64_t maxval = 0;
5907 for (const AstEnumItem* itemp = adtypep->itemsp(); itemp;
5908 itemp = VN_AS(itemp->nextp(), EnumItem)) {
5909 const AstConst* const vconstp = VN_AS(itemp->valuep(), Const);
5910 UASSERT_OBJ(vconstp, errNodep, "Enum item without constified value");
5911 if (vconstp->toUQuad() >= maxval) maxval = vconstp->toUQuad();
5912 }
5913 if (adtypep->itemsp()->width() > 64 || maxval >= (1 << 16)) {
5914 errNodep->v3warn(E_UNSUPPORTED,
5915 "Unsupported: enum next/prev method on enum with > 10 bits");
5916 return 0;
5917 }
5918 return maxval;
5919 }
enumVarp(AstEnumDType * nodep,AstAttrType attrType,uint32_t msbdim)5920 AstVar* enumVarp(AstEnumDType* nodep, AstAttrType attrType, uint32_t msbdim) {
5921 // Return a variable table which has specified dimension properties for this variable
5922 const auto pos = m_tableMap.find(std::make_pair(nodep, attrType));
5923 if (pos != m_tableMap.end()) return pos->second;
5924 UINFO(9, "Construct Venumtab attr=" << attrType.ascii() << " max=" << msbdim << " for "
5925 << nodep << endl);
5926 AstNodeDType* basep;
5927 if (attrType == AstAttrType::ENUM_NAME) {
5928 basep = nodep->findStringDType();
5929 } else if (attrType == AstAttrType::ENUM_VALID) {
5930 // TODO in theory we could bit-pack the bits in the table, but
5931 // would require additional operations to extract, so only
5932 // would be worth it for larger tables which perhaps could be
5933 // better handled with equation generation?
5934 basep = nodep->findBitDType();
5935 } else {
5936 basep = nodep->dtypep();
5937 }
5938 AstNodeArrayDType* const vardtypep = new AstUnpackArrayDType(
5939 nodep->fileline(), basep, new AstRange(nodep->fileline(), msbdim, 0));
5940 AstInitArray* const initp = new AstInitArray(nodep->fileline(), vardtypep, nullptr);
5941 v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
5942 AstVar* const varp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
5943 "__Venumtab_" + VString::downcase(attrType.ascii())
5944 + cvtToStr(m_dtTables++),
5945 vardtypep);
5946 varp->isConst(true);
5947 varp->isStatic(true);
5948 varp->valuep(initp);
5949 // Add to root, as don't know module we are in, and aids later structure sharing
5950 v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp);
5951
5952 // Default for all unspecified values
5953 if (attrType == AstAttrType::ENUM_NAME) {
5954 initp->defaultp(new AstConst(nodep->fileline(), AstConst::String(), ""));
5955 } else if (attrType == AstAttrType::ENUM_NEXT || attrType == AstAttrType::ENUM_PREV) {
5956 initp->defaultp(new AstConst(nodep->fileline(), V3Number(nodep, nodep->width(), 0)));
5957 } else if (attrType == AstAttrType::ENUM_VALID) {
5958 initp->defaultp(new AstConst{nodep->fileline(), AstConst::BitFalse{}});
5959 } else {
5960 nodep->v3fatalSrc("Bad case");
5961 }
5962
5963 // Find valid values and populate
5964 UASSERT_OBJ(nodep->itemsp(), nodep, "enum without items");
5965 std::vector<AstNode*> values;
5966 values.resize(msbdim + 1);
5967 for (unsigned i = 0; i < (msbdim + 1); ++i) values[i] = nullptr;
5968 {
5969 AstEnumItem* const firstp = nodep->itemsp();
5970 const AstEnumItem* prevp = firstp; // Prev must start with last item
5971 while (prevp->nextp()) prevp = VN_AS(prevp->nextp(), EnumItem);
5972 for (AstEnumItem* itemp = firstp; itemp;) {
5973 AstEnumItem* const nextp = VN_AS(itemp->nextp(), EnumItem);
5974 const AstConst* const vconstp = VN_AS(itemp->valuep(), Const);
5975 UASSERT_OBJ(vconstp, nodep, "Enum item without constified value");
5976 const uint32_t i = vconstp->toUInt();
5977 if (attrType == AstAttrType::ENUM_NAME) {
5978 values[i] = new AstConst(nodep->fileline(), AstConst::String(), itemp->name());
5979 } else if (attrType == AstAttrType::ENUM_NEXT) {
5980 values[i] = (nextp ? nextp : firstp)->valuep()->cloneTree(false); // A const
5981 } else if (attrType == AstAttrType::ENUM_PREV) {
5982 values[i] = prevp->valuep()->cloneTree(false); // A const
5983 } else if (attrType == AstAttrType::ENUM_VALID) {
5984 values[i] = new AstConst(nodep->fileline(), AstConst::BitTrue{});
5985 } else {
5986 nodep->v3fatalSrc("Bad case");
5987 }
5988 prevp = itemp;
5989 itemp = nextp;
5990 }
5991 }
5992 // Add all specified values to table
5993 for (unsigned i = 0; i < (msbdim + 1); ++i) {
5994 if (values[i]) initp->addIndexValuep(i, values[i]);
5995 }
5996 userIterate(varp, nullptr); // May have already done $unit so must do this var
5997 m_tableMap.emplace(std::make_pair(nodep, attrType), varp);
5998 return varp;
5999 }
6000
patVectorMap(AstPattern * nodep,const VNumRange & range)6001 PatVecMap patVectorMap(AstPattern* nodep, const VNumRange& range) {
6002 PatVecMap patmap;
6003 int element = range.left();
6004 for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
6005 patp = VN_AS(patp->nextp(), PatMember)) {
6006 if (patp->keyp()) {
6007 if (const AstConst* const constp = VN_CAST(patp->keyp(), Const)) {
6008 element = constp->toSInt();
6009 } else {
6010 patp->keyp()->v3error("Assignment pattern key not supported/understood: "
6011 << patp->keyp()->prettyTypeName());
6012 }
6013 }
6014 if (patmap.find(element) != patmap.end()) {
6015 patp->v3error("Assignment pattern key used multiple times: " << element);
6016 } else {
6017 patmap.emplace(element, patp);
6018 }
6019 element += range.leftToRightInc();
6020 }
6021 return patmap;
6022 }
6023
makeOpenArrayShell(AstNodeFTaskRef * nodep)6024 void makeOpenArrayShell(AstNodeFTaskRef* nodep) {
6025 UINFO(4, "Replicate openarray function " << nodep->taskp() << endl);
6026 AstNodeFTask* const oldTaskp = nodep->taskp();
6027 oldTaskp->dpiOpenParentInc();
6028 UASSERT_OBJ(!oldTaskp->dpiOpenChild(), oldTaskp,
6029 "DPI task should be parent or child, not both");
6030 AstNodeFTask* const newTaskp = oldTaskp->cloneTree(false);
6031 newTaskp->dpiOpenChild(true);
6032 newTaskp->dpiOpenParentClear();
6033 newTaskp->name(newTaskp->name() + "__Vdpioc" + cvtToStr(oldTaskp->dpiOpenParent()));
6034 oldTaskp->addNextHere(newTaskp);
6035 // Relink reference to new function
6036 nodep->taskp(newTaskp);
6037 nodep->name(nodep->taskp()->name());
6038 // Replace open array arguments with the callee's task
6039 const V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
6040 for (const auto& tconnect : tconnects) {
6041 AstVar* const portp = tconnect.first;
6042 const AstArg* const argp = tconnect.second;
6043 const AstNode* const pinp = argp->exprp();
6044 if (!pinp) continue; // Argument error we'll find later
6045 if (hasOpenArrayIterateDType(portp->dtypep())) portp->dtypep(pinp->dtypep());
6046 }
6047 }
6048
markHasOpenArray(AstNodeFTask * nodep)6049 bool markHasOpenArray(AstNodeFTask* nodep) {
6050 bool hasOpen = false;
6051 for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
6052 if (AstVar* const portp = VN_CAST(stmtp, Var)) {
6053 if (portp->isDpiOpenArray() || hasOpenArrayIterateDType(portp->dtypep())) {
6054 portp->isDpiOpenArray(true);
6055 hasOpen = true;
6056 }
6057 }
6058 }
6059 return hasOpen;
6060 }
hasOpenArrayIterateDType(AstNodeDType * nodep)6061 bool hasOpenArrayIterateDType(AstNodeDType* nodep) {
6062 // Return true iff this datatype or child has an openarray
6063 if (VN_IS(nodep, UnsizedArrayDType)) return true;
6064 if (nodep->subDTypep()) return hasOpenArrayIterateDType(nodep->subDTypep()->skipRefp());
6065 return false;
6066 }
6067
6068 //----------------------------------------------------------------------
6069 // METHODS - casting
computeCastable(const AstNodeDType * toDtp,const AstNodeDType * fromDtp,const AstNode * fromConstp)6070 static Castable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
6071 const AstNode* fromConstp) {
6072 const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp);
6073 UINFO(9, " castable=" << castable << " for " << toDtp << endl);
6074 UINFO(9, " =?= " << fromDtp << endl);
6075 UINFO(9, " const= " << fromConstp << endl);
6076 return castable;
6077 }
computeCastableImp(const AstNodeDType * toDtp,const AstNodeDType * fromDtp,const AstNode * fromConstp)6078 static Castable computeCastableImp(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
6079 const AstNode* fromConstp) {
6080 const Castable castable = UNSUPPORTED;
6081 toDtp = toDtp->skipRefToEnump();
6082 fromDtp = fromDtp->skipRefToEnump();
6083 if (toDtp == fromDtp) return COMPATIBLE;
6084 const AstNodeDType* fromBaseDtp = fromDtp;
6085 while (const AstPackArrayDType* const packp = VN_CAST(fromBaseDtp, PackArrayDType)) {
6086 fromBaseDtp = packp->subDTypep();
6087 while (const AstRefDType* const refp = VN_CAST(fromBaseDtp, RefDType)) {
6088 fromBaseDtp = refp->refDTypep();
6089 }
6090 }
6091 const bool fromNumericable = VN_IS(fromBaseDtp, BasicDType)
6092 || VN_IS(fromBaseDtp, EnumDType)
6093 || VN_IS(fromBaseDtp, NodeUOrStructDType);
6094 // UNSUP unpacked struct/unions (treated like BasicDType)
6095 if (VN_IS(toDtp, BasicDType) || VN_IS(toDtp, NodeUOrStructDType)) {
6096 if (fromNumericable) return COMPATIBLE;
6097 } else if (VN_IS(toDtp, EnumDType)) {
6098 if (fromNumericable) return DYNAMIC_ENUM;
6099 } else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromConstp, Const)) {
6100 if (VN_IS(fromConstp, Const) && VN_AS(fromConstp, Const)->num().isNull())
6101 return COMPATIBLE;
6102 } else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromDtp, ClassRefDType)) {
6103 const auto toClassp = VN_AS(toDtp, ClassRefDType)->classp();
6104 const auto fromClassp = VN_AS(fromDtp, ClassRefDType)->classp();
6105 const bool downcast = AstClass::isClassExtendedFrom(toClassp, fromClassp);
6106 const bool upcast = AstClass::isClassExtendedFrom(fromClassp, toClassp);
6107 if (upcast) {
6108 return COMPATIBLE;
6109 } else if (downcast) {
6110 return DYNAMIC_CLASS;
6111 } else {
6112 return INCOMPATIBLE;
6113 }
6114 }
6115 return castable;
6116 }
6117
6118 //----------------------------------------------------------------------
6119 // METHODS - special type detection
assertAtStatement(AstNode * nodep)6120 void assertAtStatement(AstNode* nodep) {
6121 if (VL_UNCOVERABLE(m_vup && !m_vup->selfDtm())) {
6122 UINFO(1, "-: " << m_vup << endl);
6123 nodep->v3fatalSrc("No dtype expected at statement " << nodep->prettyTypeName());
6124 }
6125 }
checkConstantOrReplace(AstNode * nodep,const string & message)6126 void checkConstantOrReplace(AstNode* nodep, const string& message) {
6127 // See also V3WidthSel::checkConstantOrReplace
6128 // Note can't call V3Const::constifyParam(nodep) here, as constify may change nodep on us!
6129 if (!VN_IS(nodep, Const)) {
6130 nodep->v3error(message);
6131 nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Unsized32(), 1));
6132 VL_DO_DANGLING(pushDeletep(nodep), nodep);
6133 }
6134 }
nodeForUnsizedWarning(AstNode * nodep)6135 AstNode* nodeForUnsizedWarning(AstNode* nodep) {
6136 // Return a nodep to use for unsized warnings, reporting on child if can
6137 if (nodep->op1p() && nodep->op1p()->dtypep() && !nodep->op1p()->dtypep()->widthSized()) {
6138 return nodep->op1p();
6139 } else if (nodep->op2p() && nodep->op2p()->dtypep()
6140 && !nodep->op2p()->dtypep()->widthSized()) {
6141 return nodep->op2p();
6142 }
6143 return nodep; // By default return this
6144 }
checkRefToTypedefRecurse(AstNode * nodep,AstTypedef * typedefp)6145 AstRefDType* checkRefToTypedefRecurse(AstNode* nodep, AstTypedef* typedefp) {
6146 // Recurse all children looking for self reference
6147 // This avoids iterateEditMoveDTypep going into a hard to resolve loop
6148 // Only call once for any given typedef, or will become O(n^2)
6149 if (VL_LIKELY(!nodep)) return nullptr;
6150 if (auto* const refp = VN_CAST(nodep, RefDType)) {
6151 if (refp->typedefp() == typedefp) return refp;
6152 }
6153 if (auto* const refp = checkRefToTypedefRecurse(nodep->op1p(), typedefp)) return refp;
6154 if (auto* const refp = checkRefToTypedefRecurse(nodep->op2p(), typedefp)) return refp;
6155 if (auto* const refp = checkRefToTypedefRecurse(nodep->op3p(), typedefp)) return refp;
6156 if (auto* const refp = checkRefToTypedefRecurse(nodep->op4p(), typedefp)) return refp;
6157 return nullptr;
6158 }
6159
6160 //----------------------------------------------------------------------
6161 // METHODS - special iterators
6162 // These functions save/restore the AstNUser information so it can pass to child nodes.
6163
userIterateSubtreeReturnEdits(AstNode * nodep,WidthVP * vup)6164 AstNode* userIterateSubtreeReturnEdits(AstNode* nodep, WidthVP* vup) {
6165 if (!nodep) return nullptr;
6166 AstNode* ret;
6167 {
6168 VL_RESTORER(m_vup);
6169 m_vup = vup;
6170 ret = iterateSubtreeReturnEdits(nodep);
6171 }
6172 return ret;
6173 }
userIterate(AstNode * nodep,WidthVP * vup)6174 void userIterate(AstNode* nodep, WidthVP* vup) {
6175 if (!nodep) return;
6176 {
6177 VL_RESTORER(m_vup);
6178 m_vup = vup;
6179 iterate(nodep);
6180 }
6181 }
userIterateAndNext(AstNode * nodep,WidthVP * vup)6182 void userIterateAndNext(AstNode* nodep, WidthVP* vup) {
6183 if (!nodep) return;
6184 if (nodep->didWidth()) return; // Avoid iterating list we have already iterated
6185 {
6186 VL_RESTORER(m_vup);
6187 m_vup = vup;
6188 iterateAndNextNull(nodep);
6189 }
6190 }
userIterateChildren(AstNode * nodep,WidthVP * vup)6191 void userIterateChildren(AstNode* nodep, WidthVP* vup) {
6192 if (!nodep) return;
6193 {
6194 VL_RESTORER(m_vup);
6195 m_vup = vup;
6196 iterateChildren(nodep);
6197 }
6198 }
userIterateChildrenBackwards(AstNode * nodep,WidthVP * vup)6199