1 // -*- mode: C++; c-file-style: "cc-mode" -*-
2 //*************************************************************************
3 // DESCRIPTION: Verilator: Ast node structure
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 
17 #ifndef VERILATOR_V3AST_H_
18 #define VERILATOR_V3AST_H_
19 
20 #include "config_build.h"
21 #include "verilatedos.h"
22 
23 #include "V3Error.h"
24 #include "V3FileLine.h"
25 #include "V3Number.h"
26 #include "V3Global.h"
27 #include "V3Broken.h"
28 
29 #include <cmath>
30 #include <type_traits>
31 #include <unordered_set>
32 
33 #include "V3Ast__gen_classes.h"  // From ./astgen
34 // Things like:
35 //   class V3AstNode;
36 
37 // Forward declarations
38 class V3Graph;
39 class ExecMTask;
40 
41 // Hint class so we can choose constructors
42 class VFlagLogicPacked {};
43 class VFlagBitPacked {};
44 class VFlagChildDType {};  // Used by parser.y to select constructor that sets childDType
45 
46 // Used as key for another map, needs operator<, hence not an unordered_set
47 using MTaskIdSet = std::set<int>;  // Set of mtaskIds for Var sorting
48 
49 //######################################################################
50 
51 // For broken() function, return error string if have a match
52 #define BROKEN_RTN(test) \
53     do { \
54         if (VL_UNCOVERABLE(test)) return "'" #test "' @ " __FILE__ ":" VL_STRINGIFY(__LINE__); \
55     } while (false)
56 // For broken() function, return error string if a base of this class has a match
57 #define BROKEN_BASE_RTN(test) \
58     do { \
59         const char* const reasonp = (test); \
60         if (VL_UNCOVERABLE(reasonp)) return reasonp; \
61     } while (false)
62 
63 // (V)erilator (N)ode is: Returns true if and only if AstNode is of the given AstNode subtype,
64 // and not nullptr.
65 #define VN_IS(nodep, nodetypename) (AstNode::privateIs<Ast##nodetypename, decltype(nodep)>(nodep))
66 
67 // (V)erilator (N)ode cast: Similar to dynamic_cast, but more efficient, use this instead.
68 // Cast to given type if node is of such type, otherwise returns nullptr. If 'nodep' is nullptr,
69 // return nullptr. Pointer constness is preserved, i.e.: given a 'const AstNode*',
70 // a 'const Ast<nodetypename>*' is returned.
71 #define VN_CAST(nodep, nodetypename) \
72     (AstNode::privateCast<Ast##nodetypename, decltype(nodep)>(nodep))
73 
74 // (V)erilator (N)ode as: Assert node is of given type then cast to that type. Use this to
75 // downcast instead of VN_CAST when you know the true type of the node. If 'nodep' is nullptr,
76 // return nullptr. Pointer constness is preserved, i.e.: given a 'const AstNode*', a 'const
77 // Ast<nodetypename>*' is returned.
78 #define VN_AS(nodep, nodetypename) (AstNode::privateAs<Ast##nodetypename, decltype(nodep)>(nodep))
79 
80 // (V)erilator (N)ode deleted: Pointer to deleted AstNode (for assertions only)
81 #define VN_DELETED(nodep) VL_UNLIKELY((vluint64_t)(nodep) == 0x1)
82 
83 //######################################################################
84 
85 class AstType final {
86 public:
87 #include "V3Ast__gen_types.h"  // From ./astgen
88     // Above include has:
89     //   enum en {...};
90     //   const char* ascii() const {...};
91     enum en m_e;
92     // cppcheck-suppress uninitVar  // responsibility of each subclass
AstType()93     inline AstType() {}
94     // cppcheck-suppress noExplicitConstructor
AstType(en _e)95     inline AstType(en _e)
96         : m_e{_e} {}
AstType(int _e)97     explicit inline AstType(int _e)
98         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()99     operator en() const { return m_e; }
100 };
101 inline bool operator==(const AstType& lhs, const AstType& rhs) { return lhs.m_e == rhs.m_e; }
102 inline bool operator==(const AstType& lhs, AstType::en rhs) { return lhs.m_e == rhs; }
103 inline bool operator==(AstType::en lhs, const AstType& rhs) { return lhs == rhs.m_e; }
104 inline std::ostream& operator<<(std::ostream& os, const AstType& rhs) { return os << rhs.ascii(); }
105 
106 //######################################################################
107 
108 class VLifetime final {
109 public:
110     enum en : uint8_t { NONE, AUTOMATIC, STATIC };
111     enum en m_e;
ascii()112     const char* ascii() const {
113         static const char* const names[] = {"NONE", "VAUTOM", "VSTATIC"};
114         return names[m_e];
115     }
VLifetime()116     inline VLifetime()
117         : m_e{NONE} {}
118     // cppcheck-suppress noExplicitConstructor
VLifetime(en _e)119     inline VLifetime(en _e)
120         : m_e{_e} {}
VLifetime(int _e)121     explicit inline VLifetime(int _e)
122         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()123     operator en() const { return m_e; }
isNone()124     bool isNone() const { return m_e == NONE; }
isAutomatic()125     bool isAutomatic() const { return m_e == AUTOMATIC; }
isStatic()126     bool isStatic() const { return m_e == STATIC; }
127 };
128 inline bool operator==(const VLifetime& lhs, const VLifetime& rhs) { return lhs.m_e == rhs.m_e; }
129 inline bool operator==(const VLifetime& lhs, VLifetime::en rhs) { return lhs.m_e == rhs; }
130 inline bool operator==(VLifetime::en lhs, const VLifetime& rhs) { return lhs == rhs.m_e; }
131 inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
132     return os << rhs.ascii();
133 }
134 
135 //######################################################################
136 
137 class VAccess final {
138 public:
139     enum en : uint8_t {
140         READ,  // Read/Consumed, variable not changed
141         WRITE,  // Written/Updated, variable might be updated, but not consumed
142         //      // so variable might be removable if not consumed elsewhere
143         READWRITE,  // Read/Consumed and written/updated, variable both set and
144         //          // also consumed, cannot remove usage of variable.
145         //          // For non-simple data types only e.g. no tristates/delayed vars.
146         NOCHANGE  // No change to previous state, used only in V3LinkLValue
147     };
148     enum en m_e;
ascii()149     const char* ascii() const {
150         static const char* const names[] = {"RD", "WR", "RW", "--"};
151         return names[m_e];
152     }
arrow()153     const char* arrow() const {
154         static const char* const names[] = {"[RV] <-", "[LV] =>", "[LV] <=>", "--"};
155         return names[m_e];
156     }
VAccess()157     inline VAccess()
158         : m_e{READ} {}
159     // cppcheck-suppress noExplicitConstructor
VAccess(en _e)160     inline VAccess(en _e)
161         : m_e{_e} {}
VAccess(int _e)162     explicit inline VAccess(int _e)
163         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()164     operator en() const { return m_e; }
invert()165     VAccess invert() const {
166         return (m_e == READWRITE) ? VAccess(m_e) : (m_e == WRITE ? VAccess(READ) : VAccess(WRITE));
167     }
isReadOnly()168     bool isReadOnly() const { return m_e == READ; }  // False with READWRITE
isWriteOnly()169     bool isWriteOnly() const { return m_e == WRITE; }  // False with READWRITE
isReadOrRW()170     bool isReadOrRW() const { return m_e == READ || m_e == READWRITE; }
isWriteOrRW()171     bool isWriteOrRW() const { return m_e == WRITE || m_e == READWRITE; }
isRW()172     bool isRW() const { return m_e == READWRITE; }
173 };
174 inline bool operator==(const VAccess& lhs, const VAccess& rhs) { return lhs.m_e == rhs.m_e; }
175 inline bool operator==(const VAccess& lhs, VAccess::en rhs) { return lhs.m_e == rhs; }
176 inline bool operator==(VAccess::en lhs, const VAccess& rhs) { return lhs == rhs.m_e; }
177 inline std::ostream& operator<<(std::ostream& os, const VAccess& rhs) { return os << rhs.ascii(); }
178 
179 //######################################################################
180 
181 class VSigning final {
182 public:
183     enum en : uint8_t {
184         UNSIGNED,
185         SIGNED,
186         NOSIGN,
187         _ENUM_MAX  // Leave last
188     };
189     enum en m_e;
ascii()190     const char* ascii() const {
191         static const char* const names[] = {"UNSIGNED", "SIGNED", "NOSIGN"};
192         return names[m_e];
193     }
VSigning()194     inline VSigning()
195         : m_e{UNSIGNED} {}
196     // cppcheck-suppress noExplicitConstructor
VSigning(en _e)197     inline VSigning(en _e)
198         : m_e{_e} {}
fromBool(bool isSigned)199     static inline VSigning fromBool(bool isSigned) {  // Factory method
200         return isSigned ? VSigning(SIGNED) : VSigning(UNSIGNED);
201     }
VSigning(int _e)202     explicit inline VSigning(int _e)
203         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()204     operator en() const { return m_e; }
isSigned()205     inline bool isSigned() const { return m_e == SIGNED; }
isNosign()206     inline bool isNosign() const { return m_e == NOSIGN; }
207     // No isUnsigned() as it's ambiguous if NOSIGN should be included or not.
208 };
209 inline bool operator==(const VSigning& lhs, const VSigning& rhs) { return lhs.m_e == rhs.m_e; }
210 inline bool operator==(const VSigning& lhs, VSigning::en rhs) { return lhs.m_e == rhs; }
211 inline bool operator==(VSigning::en lhs, const VSigning& rhs) { return lhs == rhs.m_e; }
212 inline std::ostream& operator<<(std::ostream& os, const VSigning& rhs) {
213     return os << rhs.ascii();
214 }
215 
216 //######################################################################
217 
218 class AstPragmaType final {
219 public:
220     enum en : uint8_t {
221         ILLEGAL,
222         COVERAGE_BLOCK_OFF,
223         HIER_BLOCK,
224         INLINE_MODULE,
225         NO_INLINE_MODULE,
226         NO_INLINE_TASK,
227         PUBLIC_MODULE,
228         PUBLIC_TASK,
229         FULL_CASE,
230         PARALLEL_CASE,
231         ENUM_SIZE
232     };
233     enum en m_e;
AstPragmaType()234     inline AstPragmaType()
235         : m_e{ILLEGAL} {}
236     // cppcheck-suppress noExplicitConstructor
AstPragmaType(en _e)237     inline AstPragmaType(en _e)
238         : m_e{_e} {}
AstPragmaType(int _e)239     explicit inline AstPragmaType(int _e)
240         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()241     operator en() const { return m_e; }
242 };
243 inline bool operator==(const AstPragmaType& lhs, const AstPragmaType& rhs) {
244     return lhs.m_e == rhs.m_e;
245 }
246 inline bool operator==(const AstPragmaType& lhs, AstPragmaType::en rhs) { return lhs.m_e == rhs; }
247 inline bool operator==(AstPragmaType::en lhs, const AstPragmaType& rhs) { return lhs == rhs.m_e; }
248 
249 //######################################################################
250 
251 class VEdgeType final {
252 public:
253     // REMEMBER to edit the strings below too
254     enum en : uint8_t {
255         // These must be in general -> most specific order, as we sort by it
256         // in V3Const::visit AstSenTree
257         ET_ILLEGAL,
258         // Involving a variable
259         ET_ANYEDGE,  // Default for sensitivities; rip them out
260         ET_BOTHEDGE,  // POSEDGE | NEGEDGE
261         ET_POSEDGE,
262         ET_NEGEDGE,
263         ET_HIGHEDGE,  // Is high now (latches)
264         ET_LOWEDGE,  // Is low now (latches)
265         // Not involving anything
266         ET_COMBO,  // Sensitive to all combo inputs to this block
267         ET_INITIAL,  // User initial statements
268         ET_SETTLE,  // Like combo but for initial wire resolutions after initial statement
269         ET_NEVER  // Never occurs (optimized away)
270     };
271     enum en m_e;
clockedStmt()272     bool clockedStmt() const {
273         static const bool clocked[]
274             = {false, false, true, true, true, true, true, false, false, false};
275         return clocked[m_e];
276     }
invert()277     VEdgeType invert() const {
278         switch (m_e) {
279         case ET_ANYEDGE: return ET_ANYEDGE;
280         case ET_BOTHEDGE: return ET_BOTHEDGE;
281         case ET_POSEDGE: return ET_NEGEDGE;
282         case ET_NEGEDGE: return ET_POSEDGE;
283         case ET_HIGHEDGE: return ET_LOWEDGE;
284         case ET_LOWEDGE: return ET_HIGHEDGE;
285         default: UASSERT_STATIC(0, "Inverting bad edgeType()");
286         }
287         return VEdgeType::ET_ILLEGAL;
288     }
ascii()289     const char* ascii() const {
290         static const char* const names[]
291             = {"%E-edge", "ANY",   "BOTH",    "POS",    "NEG",  "HIGH",
292                "LOW",     "COMBO", "INITIAL", "SETTLE", "NEVER"};
293         return names[m_e];
294     }
verilogKwd()295     const char* verilogKwd() const {
296         static const char* const names[]
297             = {"%E-edge", "[any]", "edge",      "posedge",  "negedge", "[high]",
298                "[low]",   "*",     "[initial]", "[settle]", "[never]"};
299         return names[m_e];
300     }
301     // Return true iff this and the other have mutually exclusive transitions
exclusiveEdge(const VEdgeType & other)302     bool exclusiveEdge(const VEdgeType& other) const {
303         switch (m_e) {
304         case VEdgeType::ET_POSEDGE:
305             switch (other.m_e) {
306             case VEdgeType::ET_NEGEDGE:  // FALLTHRU
307             case VEdgeType::ET_LOWEDGE: return true;
308             default:;
309             }
310             break;
311         case VEdgeType::ET_NEGEDGE:
312             switch (other.m_e) {
313             case VEdgeType::ET_POSEDGE:  // FALLTHRU
314             case VEdgeType::ET_HIGHEDGE: return true;
315             default:;
316             }
317             break;
318         default:;
319         }
320         return false;
321     }
VEdgeType()322     inline VEdgeType()
323         : m_e{ET_ILLEGAL} {}
324     // cppcheck-suppress noExplicitConstructor
VEdgeType(en _e)325     inline VEdgeType(en _e)
326         : m_e{_e} {}
VEdgeType(int _e)327     explicit inline VEdgeType(int _e)
328         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()329     operator en() const { return m_e; }
330 };
331 inline bool operator==(const VEdgeType& lhs, const VEdgeType& rhs) { return lhs.m_e == rhs.m_e; }
332 inline bool operator==(const VEdgeType& lhs, VEdgeType::en rhs) { return lhs.m_e == rhs; }
333 inline bool operator==(VEdgeType::en lhs, const VEdgeType& rhs) { return lhs == rhs.m_e; }
334 
335 //######################################################################
336 
337 class AstAttrType final {
338 public:
339     // clang-format off
340     enum en: uint8_t  {
341         ILLEGAL,
342         //
343         DIM_BITS,                       // V3Const converts to constant
344         DIM_DIMENSIONS,                 // V3Width converts to constant
345         DIM_HIGH,                       // V3Width processes
346         DIM_INCREMENT,                  // V3Width processes
347         DIM_LEFT,                       // V3Width processes
348         DIM_LOW,                        // V3Width processes
349         DIM_RIGHT,                      // V3Width processes
350         DIM_SIZE,                       // V3Width processes
351         DIM_UNPK_DIMENSIONS,            // V3Width converts to constant
352         //
353         DT_PUBLIC,                      // V3LinkParse moves to AstTypedef::attrPublic
354         //
355         ENUM_BASE,                      // V3LinkResolve creates for AstPreSel, V3LinkParam removes
356         ENUM_FIRST,                     // V3Width processes
357         ENUM_LAST,                      // V3Width processes
358         ENUM_NUM,                       // V3Width processes
359         ENUM_NEXT,                      // V3Width processes
360         ENUM_PREV,                      // V3Width processes
361         ENUM_NAME,                      // V3Width processes
362         ENUM_VALID,                     // V3Width processes
363         //
364         MEMBER_BASE,                    // V3LinkResolve creates for AstPreSel, V3LinkParam removes
365         //
366         TYPENAME,                       // V3Width processes
367         //
368         VAR_BASE,                       // V3LinkResolve creates for AstPreSel, V3LinkParam removes
369         VAR_CLOCK_ENABLE,               // V3LinkParse moves to AstVar::attrClockEn
370         VAR_PUBLIC,                     // V3LinkParse moves to AstVar::sigPublic
371         VAR_PUBLIC_FLAT,                // V3LinkParse moves to AstVar::sigPublic
372         VAR_PUBLIC_FLAT_RD,             // V3LinkParse moves to AstVar::sigPublic
373         VAR_PUBLIC_FLAT_RW,             // V3LinkParse moves to AstVar::sigPublic
374         VAR_ISOLATE_ASSIGNMENTS,        // V3LinkParse moves to AstVar::attrIsolateAssign
375         VAR_SC_BV,                      // V3LinkParse moves to AstVar::attrScBv
376         VAR_SFORMAT,                    // V3LinkParse moves to AstVar::attrSFormat
377         VAR_CLOCKER,                    // V3LinkParse moves to AstVar::attrClocker
378         VAR_NO_CLOCKER,                 // V3LinkParse moves to AstVar::attrClocker
379         VAR_SPLIT_VAR                   // V3LinkParse moves to AstVar::attrSplitVar
380     };
381     // clang-format on
382     enum en m_e;
ascii()383     const char* ascii() const {
384         // clang-format off
385         static const char* const names[] = {
386             "%E-AT",
387             "DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
388             "DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
389             "DT_PUBLIC",
390             "ENUM_BASE", "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM",
391             "ENUM_NEXT", "ENUM_PREV", "ENUM_NAME", "ENUM_VALID",
392             "MEMBER_BASE",
393             "TYPENAME",
394             "VAR_BASE", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
395             "VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
396             "VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER",
397             "VAR_NO_CLOCKER", "VAR_SPLIT_VAR"
398         };
399         // clang-format on
400         return names[m_e];
401     }
AstAttrType()402     inline AstAttrType()
403         : m_e{ILLEGAL} {}
404     // cppcheck-suppress noExplicitConstructor
AstAttrType(en _e)405     inline AstAttrType(en _e)
406         : m_e{_e} {}
AstAttrType(int _e)407     explicit inline AstAttrType(int _e)
408         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()409     operator en() const { return m_e; }
410 };
411 inline bool operator==(const AstAttrType& lhs, const AstAttrType& rhs) {
412     return lhs.m_e == rhs.m_e;
413 }
414 inline bool operator==(const AstAttrType& lhs, AstAttrType::en rhs) { return lhs.m_e == rhs; }
415 inline bool operator==(AstAttrType::en lhs, const AstAttrType& rhs) { return lhs == rhs.m_e; }
416 
417 //######################################################################
418 
419 class AstBasicDTypeKwd final {
420 public:
421     enum en : uint8_t {
422         UNKNOWN,
423         BIT,
424         BYTE,
425         CHANDLE,
426         EVENTVALUE,  // See comments in t_event_copy as to why this is EVENTVALUE
427         INT,
428         INTEGER,
429         LOGIC,
430         LONGINT,
431         DOUBLE,
432         SHORTINT,
433         TIME,
434         // Closer to a class type, but limited usage
435         STRING,
436         // Internal types for mid-steps
437         SCOPEPTR,
438         CHARPTR,
439         MTASKSTATE,
440         // Unsigned and two state; fundamental types
441         UINT32,
442         UINT64,
443         // Internal types, eliminated after parsing
444         LOGIC_IMPLICIT,
445         // Leave last
446         _ENUM_MAX
447     };
448     enum en m_e;
ascii()449     const char* ascii() const {
450         static const char* const names[]
451             = {"%E-unk",       "bit",     "byte",   "chandle",         "event",
452                "int",          "integer", "logic",  "longint",         "real",
453                "shortint",     "time",    "string", "VerilatedScope*", "char*",
454                "VlMTaskState", "IData",   "QData",  "LOGIC_IMPLICIT",  " MAX"};
455         return names[m_e];
456     }
dpiType()457     const char* dpiType() const {
458         static const char* const names[]
459             = {"%E-unk",        "svBit",      "char",        "void*",           "char",
460                "int",           "%E-integer", "svLogic",     "long long",       "double",
461                "short",         "%E-time",    "const char*", "dpiScope",        "const char*",
462                "%E-mtaskstate", "IData",      "QData",       "%E-logic-implct", " MAX"};
463         return names[m_e];
464     }
selfTest()465     static void selfTest() {
466         UASSERT(0 == strcmp(AstBasicDTypeKwd(_ENUM_MAX).ascii(), " MAX"),
467                 "SelfTest: Enum mismatch");
468         UASSERT(0 == strcmp(AstBasicDTypeKwd(_ENUM_MAX).dpiType(), " MAX"),
469                 "SelfTest: Enum mismatch");
470     }
AstBasicDTypeKwd()471     inline AstBasicDTypeKwd()
472         : m_e{UNKNOWN} {}
473     // cppcheck-suppress noExplicitConstructor
AstBasicDTypeKwd(en _e)474     inline AstBasicDTypeKwd(en _e)
475         : m_e{_e} {}
AstBasicDTypeKwd(int _e)476     explicit inline AstBasicDTypeKwd(int _e)
477         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()478     operator en() const { return m_e; }
width()479     int width() const {
480         switch (m_e) {
481         case BIT: return 1;  // scalar, can't bit extract unless ranged
482         case BYTE: return 8;
483         case CHANDLE: return 64;
484         case EVENTVALUE: return 1;
485         case INT: return 32;
486         case INTEGER: return 32;
487         case LOGIC: return 1;  // scalar, can't bit extract unless ranged
488         case LONGINT: return 64;
489         case DOUBLE: return 64;  // opaque
490         case SHORTINT: return 16;
491         case TIME: return 64;
492         case STRING: return 64;  // opaque  // Just the pointer, for today
493         case SCOPEPTR: return 0;  // opaque
494         case CHARPTR: return 0;  // opaque
495         case MTASKSTATE: return 0;  // opaque
496         case UINT32: return 32;
497         case UINT64: return 64;
498         default: return 0;
499         }
500     }
isSigned()501     bool isSigned() const {
502         return m_e == BYTE || m_e == SHORTINT || m_e == INT || m_e == LONGINT || m_e == INTEGER
503                || m_e == DOUBLE;
504     }
isUnsigned()505     bool isUnsigned() const {
506         return m_e == CHANDLE || m_e == EVENTVALUE || m_e == STRING || m_e == SCOPEPTR
507                || m_e == CHARPTR || m_e == UINT32 || m_e == UINT64 || m_e == BIT || m_e == LOGIC
508                || m_e == TIME;
509     }
isFourstate()510     bool isFourstate() const {
511         return m_e == INTEGER || m_e == LOGIC || m_e == LOGIC_IMPLICIT || m_e == TIME;
512     }
isZeroInit()513     bool isZeroInit() const {  // Otherwise initializes to X
514         return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == EVENTVALUE || m_e == INT
515                 || m_e == LONGINT || m_e == SHORTINT || m_e == STRING || m_e == DOUBLE);
516     }
isIntNumeric()517     bool isIntNumeric() const {  // Enum increment supported
518         return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC
519                 || m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64);
520     }
isBitLogic()521     bool isBitLogic() const {  // Bit/logic vector types; can form a packed array
522         return (m_e == LOGIC || m_e == BIT);
523     }
isDpiUnsignable()524     bool isDpiUnsignable() const {  // Can add "unsigned" to DPI
525         return (m_e == BYTE || m_e == SHORTINT || m_e == INT || m_e == LONGINT || m_e == INTEGER);
526     }
isDpiCLayout()527     bool isDpiCLayout() const {  // Uses standard C layout, for DPI runtime access
528         return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == INT || m_e == LONGINT
529                 || m_e == DOUBLE || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64);
530     }
isOpaque()531     bool isOpaque() const {  // IE not a simple number we can bit optimize
532         return (m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR || m_e == MTASKSTATE
533                 || m_e == DOUBLE);
534     }
isDouble()535     bool isDouble() const { return m_e == DOUBLE; }
isEventValue()536     bool isEventValue() const { return m_e == EVENTVALUE; }
isString()537     bool isString() const { return m_e == STRING; }
isMTaskState()538     bool isMTaskState() const { return m_e == MTASKSTATE; }
539     // Does this represent a C++ LiteralType? (can be constexpr)
isLiteralType()540     bool isLiteralType() const {
541         switch (m_e) {
542         case BIT:
543         case BYTE:
544         case CHANDLE:
545         case INT:
546         case INTEGER:
547         case LOGIC:
548         case LONGINT:
549         case DOUBLE:
550         case SHORTINT:
551         case SCOPEPTR:
552         case CHARPTR:
553         case UINT32:
554         case UINT64: return true;
555         default: return false;
556         }
557     }
558 };
559 inline bool operator==(const AstBasicDTypeKwd& lhs, const AstBasicDTypeKwd& rhs) {
560     return lhs.m_e == rhs.m_e;
561 }
562 inline bool operator==(const AstBasicDTypeKwd& lhs, AstBasicDTypeKwd::en rhs) {
563     return lhs.m_e == rhs;
564 }
565 inline bool operator==(AstBasicDTypeKwd::en lhs, const AstBasicDTypeKwd& rhs) {
566     return lhs == rhs.m_e;
567 }
568 
569 //######################################################################
570 
571 class VDirection final {
572 public:
573     enum en : uint8_t { NONE, INPUT, OUTPUT, INOUT, REF, CONSTREF };
574     enum en m_e;
VDirection()575     inline VDirection()
576         : m_e{NONE} {}
577     // cppcheck-suppress noExplicitConstructor
VDirection(en _e)578     inline VDirection(en _e)
579         : m_e{_e} {}
VDirection(int _e)580     explicit inline VDirection(int _e)
581         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()582     operator en() const { return m_e; }
ascii()583     const char* ascii() const {
584         static const char* const names[] = {"NONE", "INPUT", "OUTPUT", "INOUT", "REF", "CONSTREF"};
585         return names[m_e];
586     }
verilogKwd()587     string verilogKwd() const {
588         static const char* const names[] = {"", "input", "output", "inout", "ref", "const ref"};
589         return names[m_e];
590     }
xmlKwd()591     string xmlKwd() const {  // For historical reasons no "put" suffix
592         static const char* const names[] = {"", "in", "out", "inout", "ref", "const ref"};
593         return names[m_e];
594     }
prettyName()595     string prettyName() const { return verilogKwd(); }
isAny()596     bool isAny() const { return m_e != NONE; }
597     // Looks like inout - "ish" because not identical to being an INOUT
isInoutish()598     bool isInoutish() const { return m_e == INOUT; }
isNonOutput()599     bool isNonOutput() const {
600         return m_e == INPUT || m_e == INOUT || m_e == REF || m_e == CONSTREF;
601     }
isReadOnly()602     bool isReadOnly() const { return m_e == INPUT || m_e == CONSTREF; }
isWritable()603     bool isWritable() const { return m_e == OUTPUT || m_e == INOUT || m_e == REF; }
isRefOrConstRef()604     bool isRefOrConstRef() const { return m_e == REF || m_e == CONSTREF; }
605 };
606 inline bool operator==(const VDirection& lhs, const VDirection& rhs) { return lhs.m_e == rhs.m_e; }
607 inline bool operator==(const VDirection& lhs, VDirection::en rhs) { return lhs.m_e == rhs; }
608 inline bool operator==(VDirection::en lhs, const VDirection& rhs) { return lhs == rhs.m_e; }
609 inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) {
610     return os << rhs.ascii();
611 }
612 
613 //######################################################################
614 
615 /// Boolean or unknown
616 class VBoolOrUnknown final {
617 public:
618     enum en : uint8_t { BU_FALSE = 0, BU_TRUE = 1, BU_UNKNOWN = 2, _ENUM_END };
619     enum en m_e;
620     // CONSTRUCTOR - note defaults to *UNKNOWN*
VBoolOrUnknown()621     inline VBoolOrUnknown()
622         : m_e{BU_UNKNOWN} {}
623     // cppcheck-suppress noExplicitConstructor
VBoolOrUnknown(en _e)624     inline VBoolOrUnknown(en _e)
625         : m_e{_e} {}
VBoolOrUnknown(int _e)626     explicit inline VBoolOrUnknown(int _e)
627         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
ascii()628     const char* ascii() const {
629         static const char* const names[] = {"FALSE", "TRUE", "UNK"};
630         return names[m_e];
631     }
trueKnown()632     bool trueKnown() const { return m_e == BU_TRUE; }
trueUnknown()633     bool trueUnknown() const { return m_e == BU_TRUE || m_e == BU_UNKNOWN; }
falseKnown()634     bool falseKnown() const { return m_e == BU_FALSE; }
falseUnknown()635     bool falseUnknown() const { return m_e == BU_FALSE || m_e == BU_UNKNOWN; }
unknown()636     bool unknown() const { return m_e == BU_UNKNOWN; }
setTrueOrFalse(bool flag)637     void setTrueOrFalse(bool flag) { m_e = flag ? BU_TRUE : BU_FALSE; }
638 };
639 inline bool operator==(const VBoolOrUnknown& lhs, const VBoolOrUnknown& rhs) {
640     return lhs.m_e == rhs.m_e;
641 }
642 inline bool operator==(const VBoolOrUnknown& lhs, VBoolOrUnknown::en rhs) {
643     return lhs.m_e == rhs;
644 }
645 inline bool operator==(VBoolOrUnknown::en lhs, const VBoolOrUnknown& rhs) {
646     return lhs == rhs.m_e;
647 }
648 inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) {
649     return os << rhs.ascii();
650 }
651 
652 //######################################################################
653 
654 /// Join type
655 class VJoinType final {
656 public:
657     enum en : uint8_t { JOIN = 0, JOIN_ANY = 1, JOIN_NONE = 2 };
658     enum en m_e;
659     // CONSTRUCTOR - note defaults to *UNKNOWN*
VJoinType()660     inline VJoinType()
661         : m_e{JOIN} {}
662     // cppcheck-suppress noExplicitConstructor
VJoinType(en _e)663     inline VJoinType(en _e)
664         : m_e{_e} {}
VJoinType(int _e)665     explicit inline VJoinType(int _e)
666         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
ascii()667     const char* ascii() const {
668         static const char* const names[] = {"JOIN", "JOIN_ANY", "JOIN_NONE"};
669         return names[m_e];
670     }
verilogKwd()671     const char* verilogKwd() const {
672         static const char* const names[] = {"join", "join_any", "join_none"};
673         return names[m_e];
674     }
join()675     bool join() const { return m_e == JOIN; }
joinAny()676     bool joinAny() const { return m_e == JOIN_ANY; }
joinNone()677     bool joinNone() const { return m_e == JOIN_NONE; }
678 };
679 inline bool operator==(const VJoinType& lhs, const VJoinType& rhs) { return lhs.m_e == rhs.m_e; }
680 inline bool operator==(const VJoinType& lhs, VJoinType::en rhs) { return lhs.m_e == rhs; }
681 inline bool operator==(VJoinType::en lhs, const VJoinType& rhs) { return lhs == rhs.m_e; }
682 inline std::ostream& operator<<(std::ostream& os, const VJoinType& rhs) {
683     return os << rhs.ascii();
684 }
685 
686 //######################################################################
687 
688 class AstVarType final {
689 public:
690     enum en : uint8_t {
691         UNKNOWN,
692         GPARAM,
693         LPARAM,
694         GENVAR,
695         VAR,  // Reg, integer, logic, etc
696         SUPPLY0,
697         SUPPLY1,
698         WIRE,
699         WREAL,
700         IMPLICITWIRE,
701         TRIWIRE,
702         TRI0,
703         TRI1,
704         PORT,  // Temp type used in parser only
705         BLOCKTEMP,
706         MODULETEMP,
707         STMTTEMP,
708         XTEMP,
709         IFACEREF,  // Used to link Interfaces between modules
710         MEMBER
711     };
712     enum en m_e;
AstVarType()713     inline AstVarType()
714         : m_e{UNKNOWN} {}
715     // cppcheck-suppress noExplicitConstructor
AstVarType(en _e)716     inline AstVarType(en _e)
717         : m_e{_e} {}
AstVarType(int _e)718     explicit inline AstVarType(int _e)
719         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()720     operator en() const { return m_e; }
ascii()721     const char* ascii() const {
722         static const char* const names[] = {
723             "?",         "GPARAM",     "LPARAM",       "GENVAR",  "VAR",      "SUPPLY0", "SUPPLY1",
724             "WIRE",      "WREAL",      "IMPLICITWIRE", "TRIWIRE", "TRI0",     "TRI1",    "PORT",
725             "BLOCKTEMP", "MODULETEMP", "STMTTEMP",     "XTEMP",   "IFACEREF", "MEMBER"};
726         return names[m_e];
727     }
isSignal()728     bool isSignal() const {
729         return (m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0
730                 || m_e == TRI1 || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR);
731     }
isContAssignable()732     bool isContAssignable() const {  // In Verilog, always ok in SystemVerilog
733         return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL
734                 || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
735                 || m_e == PORT || m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP
736                 || m_e == XTEMP || m_e == IFACEREF);
737     }
isProcAssignable()738     bool isProcAssignable() const {
739         return (m_e == GPARAM || m_e == LPARAM || m_e == GENVAR || m_e == VAR || m_e == BLOCKTEMP
740                 || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP || m_e == IFACEREF
741                 || m_e == MEMBER);
742     }
isTemp()743     bool isTemp() const {
744         return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP);
745     }
746 };
747 inline bool operator==(const AstVarType& lhs, const AstVarType& rhs) { return lhs.m_e == rhs.m_e; }
748 inline bool operator==(const AstVarType& lhs, AstVarType::en rhs) { return lhs.m_e == rhs; }
749 inline bool operator==(AstVarType::en lhs, const AstVarType& rhs) { return lhs == rhs.m_e; }
750 inline std::ostream& operator<<(std::ostream& os, const AstVarType& rhs) {
751     return os << rhs.ascii();
752 }
753 
754 //######################################################################
755 
756 class VBranchPred final {
757 public:
758     enum en : uint8_t { BP_UNKNOWN = 0, BP_LIKELY, BP_UNLIKELY, _ENUM_END };
759     enum en m_e;
760     // CONSTRUCTOR - note defaults to *UNKNOWN*
VBranchPred()761     inline VBranchPred()
762         : m_e{BP_UNKNOWN} {}
763     // cppcheck-suppress noExplicitConstructor
VBranchPred(en _e)764     inline VBranchPred(en _e)
765         : m_e{_e} {}
VBranchPred(int _e)766     explicit inline VBranchPred(int _e)
767         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()768     operator en() const { return m_e; }
unknown()769     bool unknown() const { return m_e == BP_UNKNOWN; }
likely()770     bool likely() const { return m_e == BP_LIKELY; }
unlikely()771     bool unlikely() const { return m_e == BP_UNLIKELY; }
invert()772     VBranchPred invert() const {
773         if (m_e == BP_UNLIKELY) {
774             return BP_LIKELY;
775         } else if (m_e == BP_LIKELY) {
776             return BP_UNLIKELY;
777         } else {
778             return m_e;
779         }
780     }
ascii()781     const char* ascii() const {
782         static const char* const names[] = {"", "VL_LIKELY", "VL_UNLIKELY"};
783         return names[m_e];
784     }
785 };
786 inline bool operator==(const VBranchPred& lhs, const VBranchPred& rhs) {
787     return lhs.m_e == rhs.m_e;
788 }
789 inline bool operator==(const VBranchPred& lhs, VBranchPred::en rhs) { return lhs.m_e == rhs; }
790 inline bool operator==(VBranchPred::en lhs, const VBranchPred& rhs) { return lhs == rhs.m_e; }
791 inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) {
792     return os << rhs.ascii();
793 }
794 
795 //######################################################################
796 
797 class VVarAttrClocker final {
798 public:
799     enum en : uint8_t { CLOCKER_UNKNOWN = 0, CLOCKER_YES, CLOCKER_NO, _ENUM_END };
800     enum en m_e;
801     // CONSTRUCTOR - note defaults to *UNKNOWN*
VVarAttrClocker()802     inline VVarAttrClocker()
803         : m_e{CLOCKER_UNKNOWN} {}
804     // cppcheck-suppress noExplicitConstructor
VVarAttrClocker(en _e)805     inline VVarAttrClocker(en _e)
806         : m_e{_e} {}
VVarAttrClocker(int _e)807     explicit inline VVarAttrClocker(int _e)
808         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()809     operator en() const { return m_e; }
unknown()810     bool unknown() const { return m_e == CLOCKER_UNKNOWN; }
invert()811     VVarAttrClocker invert() const {
812         if (m_e == CLOCKER_YES) {
813             return CLOCKER_NO;
814         } else if (m_e == CLOCKER_NO) {
815             return CLOCKER_YES;
816         } else {
817             return m_e;
818         }
819     }
ascii()820     const char* ascii() const {
821         static const char* const names[] = {"", "clker", "non_clker"};
822         return names[m_e];
823     }
824 };
825 inline bool operator==(const VVarAttrClocker& lhs, const VVarAttrClocker& rhs) {
826     return lhs.m_e == rhs.m_e;
827 }
828 inline bool operator==(const VVarAttrClocker& lhs, VVarAttrClocker::en rhs) {
829     return lhs.m_e == rhs;
830 }
831 inline bool operator==(VVarAttrClocker::en lhs, const VVarAttrClocker& rhs) {
832     return lhs == rhs.m_e;
833 }
834 inline std::ostream& operator<<(std::ostream& os, const VVarAttrClocker& rhs) {
835     return os << rhs.ascii();
836 }
837 
838 //######################################################################
839 
840 class VAlwaysKwd final {
841 public:
842     enum en : uint8_t { ALWAYS, ALWAYS_FF, ALWAYS_LATCH, ALWAYS_COMB };
843     enum en m_e;
VAlwaysKwd()844     inline VAlwaysKwd()
845         : m_e{ALWAYS} {}
846     // cppcheck-suppress noExplicitConstructor
VAlwaysKwd(en _e)847     inline VAlwaysKwd(en _e)
848         : m_e{_e} {}
VAlwaysKwd(int _e)849     explicit inline VAlwaysKwd(int _e)
850         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()851     operator en() const { return m_e; }
ascii()852     const char* ascii() const {
853         static const char* const names[] = {"always", "always_ff", "always_latch", "always_comb"};
854         return names[m_e];
855     }
856 };
857 inline bool operator==(const VAlwaysKwd& lhs, const VAlwaysKwd& rhs) { return lhs.m_e == rhs.m_e; }
858 inline bool operator==(const VAlwaysKwd& lhs, VAlwaysKwd::en rhs) { return lhs.m_e == rhs; }
859 inline bool operator==(VAlwaysKwd::en lhs, const VAlwaysKwd& rhs) { return lhs == rhs.m_e; }
860 
861 //######################################################################
862 
863 class VCaseType final {
864 public:
865     enum en : uint8_t { CT_CASE, CT_CASEX, CT_CASEZ, CT_CASEINSIDE };
866     enum en m_e;
VCaseType()867     inline VCaseType()
868         : m_e{CT_CASE} {}
869     // cppcheck-suppress noExplicitConstructor
VCaseType(en _e)870     inline VCaseType(en _e)
871         : m_e{_e} {}
VCaseType(int _e)872     explicit inline VCaseType(int _e)
873         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()874     operator en() const { return m_e; }
875 };
876 inline bool operator==(const VCaseType& lhs, const VCaseType& rhs) { return lhs.m_e == rhs.m_e; }
877 inline bool operator==(const VCaseType& lhs, VCaseType::en rhs) { return lhs.m_e == rhs; }
878 inline bool operator==(VCaseType::en lhs, const VCaseType& rhs) { return lhs == rhs.m_e; }
879 
880 //######################################################################
881 
882 class AstDisplayType final {
883 public:
884     enum en : uint8_t {
885         DT_DISPLAY,
886         DT_WRITE,
887         DT_MONITOR,
888         DT_STROBE,
889         DT_INFO,
890         DT_ERROR,
891         DT_WARNING,
892         DT_FATAL
893     };
894     enum en m_e;
AstDisplayType()895     AstDisplayType()
896         : m_e{DT_DISPLAY} {}
897     // cppcheck-suppress noExplicitConstructor
AstDisplayType(en _e)898     AstDisplayType(en _e)
899         : m_e{_e} {}
AstDisplayType(int _e)900     explicit inline AstDisplayType(int _e)
901         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()902     operator en() const { return m_e; }
addNewline()903     bool addNewline() const { return m_e != DT_WRITE; }
needScopeTracking()904     bool needScopeTracking() const { return m_e != DT_DISPLAY && m_e != DT_WRITE; }
ascii()905     const char* ascii() const {
906         static const char* const names[]
907             = {"display", "write", "monitor", "strobe", "info", "error", "warning", "fatal"};
908         return names[m_e];
909     }
910 };
911 inline bool operator==(const AstDisplayType& lhs, const AstDisplayType& rhs) {
912     return lhs.m_e == rhs.m_e;
913 }
914 inline bool operator==(const AstDisplayType& lhs, AstDisplayType::en rhs) {
915     return lhs.m_e == rhs;
916 }
917 inline bool operator==(AstDisplayType::en lhs, const AstDisplayType& rhs) {
918     return lhs == rhs.m_e;
919 }
920 
921 //######################################################################
922 
923 class VDumpCtlType final {
924 public:
925     enum en : uint8_t { FILE, VARS, ALL, FLUSH, LIMIT, OFF, ON };
926     enum en m_e;
VDumpCtlType()927     inline VDumpCtlType()
928         : m_e{ON} {}
929     // cppcheck-suppress noExplicitConstructor
VDumpCtlType(en _e)930     inline VDumpCtlType(en _e)
931         : m_e{_e} {}
VDumpCtlType(int _e)932     explicit inline VDumpCtlType(int _e)
933         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()934     operator en() const { return m_e; }
ascii()935     const char* ascii() const {
936         static const char* const names[] = {"$dumpfile",  "$dumpvars", "$dumpall", "$dumpflush",
937                                             "$dumplimit", "$dumpoff",  "$dumpon"};
938         return names[m_e];
939     }
940 };
941 inline bool operator==(const VDumpCtlType& lhs, const VDumpCtlType& rhs) {
942     return lhs.m_e == rhs.m_e;
943 }
944 inline bool operator==(const VDumpCtlType& lhs, VDumpCtlType::en rhs) { return lhs.m_e == rhs; }
945 inline bool operator==(VDumpCtlType::en lhs, const VDumpCtlType& rhs) { return lhs == rhs.m_e; }
946 
947 //######################################################################
948 
949 class VParseRefExp final {
950 public:
951     enum en : uint8_t {
952         PX_NONE,  // Used in V3LinkParse only
953         PX_ROOT,
954         PX_TEXT  // Unknown ID component
955     };
956     enum en m_e;
VParseRefExp()957     inline VParseRefExp()
958         : m_e{PX_NONE} {}
959     // cppcheck-suppress noExplicitConstructor
VParseRefExp(en _e)960     inline VParseRefExp(en _e)
961         : m_e{_e} {}
VParseRefExp(int _e)962     explicit inline VParseRefExp(int _e)
963         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
en()964     operator en() const { return m_e; }
ascii()965     const char* ascii() const {
966         static const char* const names[] = {"", "$root", "TEXT", "PREDOT"};
967         return names[m_e];
968     }
969 };
970 inline bool operator==(const VParseRefExp& lhs, const VParseRefExp& rhs) {
971     return lhs.m_e == rhs.m_e;
972 }
973 inline bool operator==(const VParseRefExp& lhs, VParseRefExp::en rhs) { return lhs.m_e == rhs; }
974 inline bool operator==(VParseRefExp::en lhs, const VParseRefExp& rhs) { return lhs == rhs.m_e; }
975 inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) {
976     return os << rhs.ascii();
977 }
978 
979 //######################################################################
980 // VNumRange - Structure containing numeric range information
981 // See also AstRange, which is a symbolic version of this
982 
983 class VNumRange final {
984 public:
985     int m_left = 0;
986     int m_right = 0;
987     bool m_ranged = false;  // Has a range
988     bool operator==(const VNumRange& rhs) const {
989         return m_left == rhs.m_left && m_right == rhs.m_right && m_ranged == rhs.m_ranged;
990     }
991     bool operator<(const VNumRange& rhs) const {
992         if ((m_left < rhs.m_left)) return true;
993         if (!(m_left == rhs.m_left)) return false;  // lhs > rhs
994         if ((m_right < rhs.m_right)) return true;
995         if (!(m_right == rhs.m_right)) return false;  // lhs > rhs
996         if ((m_ranged < rhs.m_ranged)) return true;
997         if (!(m_ranged == rhs.m_ranged)) return false;  // lhs > rhs
998         return false;
999     }
1000     //
VNumRange()1001     VNumRange() {}
VNumRange(int hi,int lo,bool littleEndian)1002     VNumRange(int hi, int lo, bool littleEndian) { init(hi, lo, littleEndian); }
VNumRange(int left,int right)1003     VNumRange(int left, int right)
1004         : m_left{left}
1005         , m_right{right}
1006         , m_ranged{true} {}
1007     ~VNumRange() = default;
1008     // MEMBERS
init(int hi,int lo,bool littleEndian)1009     void init(int hi, int lo, bool littleEndian) {
1010         if (lo > hi) {
1011             const int t = hi;
1012             hi = lo;
1013             lo = t;
1014         }
1015         m_left = littleEndian ? lo : hi;
1016         m_right = littleEndian ? hi : lo;
1017         m_ranged = true;
1018     }
left()1019     int left() const { return m_left; }
right()1020     int right() const { return m_right; }
hi()1021     int hi() const { return m_left > m_right ? m_left : m_right; }  // How to show a declaration
lo()1022     int lo() const { return m_left > m_right ? m_right : m_left; }  // How to show a declaration
leftToRightInc()1023     int leftToRightInc() const { return littleEndian() ? 1 : -1; }
elements()1024     int elements() const { return hi() - lo() + 1; }
ranged()1025     bool ranged() const { return m_ranged; }
littleEndian()1026     bool littleEndian() const { return m_left < m_right; }
hiMaxSelect()1027     int hiMaxSelect() const {
1028         return (lo() < 0 ? hi() - lo() : hi());
1029     }  // Maximum value a [] select may index
dump(std::ostream & str)1030     void dump(std::ostream& str) const {
1031         if (ranged()) {
1032             str << "[" << left() << ":" << right() << "]";
1033         } else {
1034             str << "[norg]";
1035         }
1036     }
1037 };
1038 inline std::ostream& operator<<(std::ostream& os, const VNumRange& rhs) {
1039     rhs.dump(os);
1040     return os;
1041 }
1042 
1043 //######################################################################
1044 
1045 class VUseType final {
1046 public:
1047     enum en : uint8_t {
1048         IMP_INCLUDE,  // Implementation (.cpp) needs an include
1049         INT_INCLUDE,  // Interface (.h) needs an include
1050         IMP_FWD_CLASS,  // Implementation (.cpp) needs a forward class declaration
1051         INT_FWD_CLASS,  // Interface (.h) needs a forward class declaration
1052     };
1053     enum en m_e;
VUseType()1054     inline VUseType()
1055         : m_e{IMP_FWD_CLASS} {}
1056     // cppcheck-suppress noExplicitConstructor
VUseType(en _e)1057     inline VUseType(en _e)
1058         : m_e{_e} {}
VUseType(int _e)1059     explicit inline VUseType(int _e)
1060         : m_e(static_cast<en>(_e)) {}  // Need () or GCC 4.8 false warning
isInclude()1061     bool isInclude() const { return m_e == IMP_INCLUDE || m_e == INT_INCLUDE; }
isFwdClass()1062     bool isFwdClass() const { return m_e == IMP_FWD_CLASS || m_e == INT_FWD_CLASS; }
en()1063     operator en() const { return m_e; }
ascii()1064     const char* ascii() const {
1065         static const char* const names[] = {"IMP_INC", "INT_INC", "IMP_FWD", "INT_FWD"};
1066         return names[m_e];
1067     }
1068 };
1069 inline bool operator==(const VUseType& lhs, const VUseType& rhs) { return lhs.m_e == rhs.m_e; }
1070 inline bool operator==(const VUseType& lhs, VUseType::en rhs) { return lhs.m_e == rhs; }
1071 inline bool operator==(VUseType::en lhs, const VUseType& rhs) { return lhs == rhs.m_e; }
1072 inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
1073     return os << rhs.ascii();
1074 }
1075 
1076 //######################################################################
1077 
1078 class VBasicTypeKey final {
1079 public:
1080     const int m_width;  // From AstNodeDType: Bit width of operation
1081     const int m_widthMin;  // From AstNodeDType: If unsized, bitwidth of minimum implementation
1082     const VSigning m_numeric;  // From AstNodeDType: Node is signed
1083     const AstBasicDTypeKwd m_keyword;  // From AstBasicDType: What keyword created basic type
1084     const VNumRange m_nrange;  // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
1085     bool operator==(const VBasicTypeKey& rhs) const {
1086         return m_width == rhs.m_width && m_widthMin == rhs.m_widthMin && m_numeric == rhs.m_numeric
1087                && m_keyword == rhs.m_keyword && m_nrange == rhs.m_nrange;
1088     }
1089     bool operator<(const VBasicTypeKey& rhs) const {
1090         if ((m_width < rhs.m_width)) return true;
1091         if (!(m_width == rhs.m_width)) return false;  // lhs > rhs
1092         if ((m_widthMin < rhs.m_widthMin)) return true;
1093         if (!(m_widthMin == rhs.m_widthMin)) return false;  // lhs > rhs
1094         if ((m_numeric < rhs.m_numeric)) return true;
1095         if (!(m_numeric == rhs.m_numeric)) return false;  // lhs > rhs
1096         if ((m_keyword < rhs.m_keyword)) return true;
1097         if (!(m_keyword == rhs.m_keyword)) return false;  // lhs > rhs
1098         if ((m_nrange < rhs.m_nrange)) return true;
1099         if (!(m_nrange == rhs.m_nrange)) return false;  // lhs > rhs
1100         return false;
1101     }
VBasicTypeKey(int width,int widthMin,VSigning numeric,AstBasicDTypeKwd kwd,const VNumRange & nrange)1102     VBasicTypeKey(int width, int widthMin, VSigning numeric, AstBasicDTypeKwd kwd,
1103                   const VNumRange& nrange)
1104         : m_width{width}
1105         , m_widthMin{widthMin}
1106         , m_numeric{numeric}
1107         , m_keyword{kwd}
1108         , m_nrange{nrange} {}
1109     ~VBasicTypeKey() = default;
1110 };
1111 
1112 //######################################################################
1113 // AstNUser - Generic base class for AST User nodes.
1114 //          - Also used to allow parameter passing up/down iterate calls
1115 
1116 class WidthVP;
1117 class V3GraphVertex;
1118 class VSymEnt;
1119 
1120 class VNUser final {
1121     union {
1122         void* up;
1123         int ui;
1124     } m_u;
1125 
1126 public:
VNUser()1127     VNUser() {}
1128     // non-explicit:
1129     // cppcheck-suppress noExplicitConstructor
VNUser(int i)1130     VNUser(int i) {
1131         m_u.up = 0;
1132         m_u.ui = i;
1133     }
VNUser(void * p)1134     explicit VNUser(void* p) { m_u.up = p; }
1135     ~VNUser() = default;
1136     // Casters
1137     template <class T>  //
to()1138     typename std::enable_if<std::is_pointer<T>::value, T>::type to() const {
1139         return reinterpret_cast<T>(m_u.up);
1140     }
c()1141     WidthVP* c() const { return to<WidthVP*>(); }
toSymEnt()1142     VSymEnt* toSymEnt() const { return to<VSymEnt*>(); }
toNodep()1143     AstNode* toNodep() const { return to<AstNode*>(); }
toGraphVertex()1144     V3GraphVertex* toGraphVertex() const { return to<V3GraphVertex*>(); }
toInt()1145     int toInt() const { return m_u.ui; }
fromInt(int i)1146     static VNUser fromInt(int i) { return VNUser(i); }
1147 };
1148 
1149 //######################################################################
1150 // AstUserResource - Generic pointer base class for tracking usage of user()
1151 //
1152 //  Where AstNode->user2() is going to be used, for example, you write:
1153 //
1154 //      AstUser2InUse  m_userres;
1155 //
1156 //  This will clear the tree, and prevent another visitor from clobbering
1157 //  user2.  When the member goes out of scope it will be automagically
1158 //  freed up.
1159 
1160 class AstUserInUseBase VL_NOT_FINAL {
1161 protected:
allocate(int id,uint32_t & cntGblRef,bool & userBusyRef)1162     static void allocate(int id, uint32_t& cntGblRef, bool& userBusyRef) {
1163         // Perhaps there's still a AstUserInUse in scope for this?
1164         UASSERT_STATIC(!userBusyRef, "Conflicting user use; AstUser" + cvtToStr(id)
1165                                          + "InUse request when under another AstUserInUse");
1166         userBusyRef = true;
1167         clearcnt(id, cntGblRef, userBusyRef);
1168     }
free(int id,uint32_t & cntGblRef,bool & userBusyRef)1169     static void free(int id, uint32_t& cntGblRef, bool& userBusyRef) {
1170         UASSERT_STATIC(userBusyRef, "Free of User" + cvtToStr(id) + "() not under AstUserInUse");
1171         clearcnt(id, cntGblRef, userBusyRef);  // Includes a checkUse for us
1172         userBusyRef = false;
1173     }
clearcnt(int id,uint32_t & cntGblRef,const bool & userBusyRef)1174     static void clearcnt(int id, uint32_t& cntGblRef, const bool& userBusyRef) {
1175         UASSERT_STATIC(userBusyRef, "Clear of User" + cvtToStr(id) + "() not under AstUserInUse");
1176         // If this really fires and is real (after 2^32 edits???)
1177         // we could just walk the tree and clear manually
1178         ++cntGblRef;
1179         UASSERT_STATIC(cntGblRef, "User*() overflowed!");
1180     }
checkcnt(int id,uint32_t &,const bool & userBusyRef)1181     static void checkcnt(int id, uint32_t&, const bool& userBusyRef) {
1182         UASSERT_STATIC(userBusyRef,
1183                        "Check of User" + cvtToStr(id) + "() failed, not under AstUserInUse");
1184     }
1185 };
1186 
1187 // For each user() declare the in use structure
1188 // We let AstNode peek into here, because when under low optimization even
1189 // an accessor would be way too slow.
1190 // clang-format off
1191 class AstUser1InUse final : AstUserInUseBase {
1192 protected:
1193     friend class AstNode;
1194     static uint32_t     s_userCntGbl;   // Count of which usage of userp() this is
1195     static bool         s_userBusy;     // Count is in use
1196 public:
AstUser1InUse()1197     AstUser1InUse()     { allocate(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser1InUse()1198     ~AstUser1InUse()    { free    (1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
clear()1199     static void clear() { clearcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
check()1200     static void check() { checkcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
1201 };
1202 class AstUser2InUse final : AstUserInUseBase {
1203 protected:
1204     friend class AstNode;
1205     static uint32_t     s_userCntGbl;   // Count of which usage of userp() this is
1206     static bool         s_userBusy;     // Count is in use
1207 public:
AstUser2InUse()1208     AstUser2InUse()     { allocate(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser2InUse()1209     ~AstUser2InUse()    { free    (2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
clear()1210     static void clear() { clearcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
check()1211     static void check() { checkcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
1212 };
1213 class AstUser3InUse final : AstUserInUseBase {
1214 protected:
1215     friend class AstNode;
1216     static uint32_t     s_userCntGbl;   // Count of which usage of userp() this is
1217     static bool         s_userBusy;     // Count is in use
1218 public:
AstUser3InUse()1219     AstUser3InUse()     { allocate(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser3InUse()1220     ~AstUser3InUse()    { free    (3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
clear()1221     static void clear() { clearcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
check()1222     static void check() { checkcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
1223 };
1224 class AstUser4InUse final : AstUserInUseBase {
1225 protected:
1226     friend class AstNode;
1227     static uint32_t     s_userCntGbl;   // Count of which usage of userp() this is
1228     static bool         s_userBusy;     // Count is in use
1229 public:
AstUser4InUse()1230     AstUser4InUse()     { allocate(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser4InUse()1231     ~AstUser4InUse()    { free    (4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
clear()1232     static void clear() { clearcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
check()1233     static void check() { checkcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
1234 };
1235 class AstUser5InUse final : AstUserInUseBase {
1236 protected:
1237     friend class AstNode;
1238     static uint32_t     s_userCntGbl;   // Count of which usage of userp() this is
1239     static bool         s_userBusy;     // Count is in use
1240 public:
AstUser5InUse()1241     AstUser5InUse()     { allocate(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser5InUse()1242     ~AstUser5InUse()    { free    (5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
clear()1243     static void clear() { clearcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
check()1244     static void check() { checkcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
1245 };
1246 // clang-format on
1247 
1248 //######################################################################
1249 // Node deleter, deletes all enqueued AstNode* on destruction, or when
1250 // explicitly told to do so. This is useful when the deletion of removed
1251 // nodes needs to be deferred to a later time, because pointers to the
1252 // removed nodes might still exist.
1253 
1254 class AstNDeleter VL_NOT_FINAL {
1255     // MEMBERS
1256     std::vector<AstNode*> m_deleteps;  // Nodes to delete
1257 
1258 public:
1259     // METHODS
1260 
1261     // Enqueue node for deletion on next 'doDelete' (or destruction)
pushDeletep(AstNode * nodep)1262     void pushDeletep(AstNode* nodep) {
1263         UASSERT_STATIC(nodep, "Cannot delete nullptr node");
1264         m_deleteps.push_back(nodep);
1265     }
1266 
1267     // Delete all previously pushed nodes (by callint deleteTree)
1268     void doDeletes();
1269 
1270     // Do the deletions on destruction
~AstNDeleter()1271     virtual ~AstNDeleter() { doDeletes(); }
1272 };
1273 
1274 //######################################################################
1275 // AstNVisitor -- Allows new functions to be called on each node
1276 // type without changing the base classes.  See "Modern C++ Design".
1277 
1278 class AstNVisitor VL_NOT_FINAL : public AstNDeleter {
1279     friend class AstNode;
1280 
1281 public:
1282     /// Call visit()s on nodep
1283     void iterate(AstNode* nodep);
1284     /// Call visit()s on nodep
1285     void iterateNull(AstNode* nodep);
1286     /// Call visit()s on nodep's children
1287     void iterateChildren(AstNode* nodep);
1288     /// Call visit()s on nodep's children in backp() order
1289     void iterateChildrenBackwards(AstNode* nodep);
1290     /// Call visit()s on const nodep's children
1291     void iterateChildrenConst(AstNode* nodep);
1292     /// Call visit()s on nodep (maybe nullptr) and nodep's nextp() list
1293     void iterateAndNextNull(AstNode* nodep);
1294     /// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list
1295     void iterateAndNextConstNull(AstNode* nodep);
1296     /// Return edited nodep; see comments in V3Ast.cpp
1297     AstNode* iterateSubtreeReturnEdits(AstNode* nodep);
1298 
1299 #include "V3Ast__gen_visitor.h"  // From ./astgen
1300     // Things like:
1301     //  virtual void visit(AstBreak* nodep) { visit((AstNodeStmt*)(nodep)); }
1302     //  virtual void visit(AstNodeStmt* nodep) { visit((AstNode*)(nodep)); }
1303 };
1304 
1305 //######################################################################
1306 // AstNRelinker -- Holds the state of a unlink so a new node can be
1307 // added at the same point.
1308 
1309 class AstNRelinker final {
1310 protected:
1311     friend class AstNode;
1312     enum RelinkWhatEn : uint8_t {
1313         RELINK_BAD,
1314         RELINK_NEXT,
1315         RELINK_OP1,
1316         RELINK_OP2,
1317         RELINK_OP3,
1318         RELINK_OP4
1319     };
1320     AstNode* m_oldp = nullptr;  // The old node that was linked to this point in the tree
1321     AstNode* m_backp = nullptr;
1322     RelinkWhatEn m_chg = RELINK_BAD;
1323     AstNode** m_iterpp = nullptr;
1324 
1325 public:
1326     AstNRelinker() = default;
1327     void relink(AstNode* newp);
oldp()1328     AstNode* oldp() const { return m_oldp; }
1329     void dump(std::ostream& str = std::cout) const;
1330 };
1331 inline std::ostream& operator<<(std::ostream& os, const AstNRelinker& rhs) {
1332     rhs.dump(os);
1333     return os;
1334 }
1335 
1336 //######################################################################
1337 // Callback base class to determine if node matches some formula
1338 
1339 class VNodeMatcher VL_NOT_FINAL {
1340 public:
nodeMatch(const AstNode * nodep)1341     virtual bool nodeMatch(const AstNode* nodep) const { return true; }
1342 };
1343 
1344 //######################################################################
1345 // AstNode -- Base type of all Ast types
1346 
1347 // Prefetch a node.
1348 // The if() makes it faster, even though prefetch won't fault on null pointers
1349 #define ASTNODE_PREFETCH(nodep) \
1350     do { \
1351         if (nodep) { \
1352             VL_PREFETCH_RD(&((nodep)->m_nextp)); \
1353             VL_PREFETCH_RD(&((nodep)->m_type)); \
1354         } \
1355     } while (false)
1356 
1357 class AstNode VL_NOT_FINAL {
1358     // v ASTNODE_PREFETCH depends on below ordering of members
1359     AstNode* m_nextp;  // Next peer in the parent's list
1360     AstNode* m_backp;  // Node that points to this one (via next/op1/op2/...)
1361     AstNode* m_op1p;  // Generic pointer 1
1362     AstNode* m_op2p;  // Generic pointer 2
1363     AstNode* m_op3p;  // Generic pointer 3
1364     AstNode* m_op4p;  // Generic pointer 4
1365     AstNode** m_iterpp;  // Pointer to node iterating on, change it if we replace this node.
1366     const AstType m_type;  // Node sub-type identifier
1367     // ^ ASTNODE_PREFETCH depends on above ordering of members
1368 
1369     // AstType is 2 bytes, so we can stick another 6 bytes after it to utilize what would
1370     // otherwise be padding (on a 64-bit system). We stick the attribute flags, broken state,
1371     // and the clone count here.
1372 
1373     struct {
1374         bool didWidth : 1;  // Did V3Width computation
1375         bool doingWidth : 1;  // Inside V3Width
1376         bool protect : 1;  // Protect name if protection is on
1377         // Space for more flags here (there must be 8 bits in total)
1378         uint8_t unused : 5;
1379     } m_flags;  // Attribute flags
1380 
1381     // State variable used by V3Broken for consistency checking. The top bit of this is byte is a
1382     // flag, representing V3Broken is currently proceeding under this node. The bottom 7 bits are
1383     // a generation number. This is hot when --debug-checks so we access as a whole to avoid bit
1384     // field masking resulting in unnecessary read-modify-write ops.
1385     uint8_t m_brokenState = 0;
1386 
1387     int m_cloneCnt;  // Sequence number for when last clone was made
1388 
1389 #if defined(__x86_64__) && defined(__gnu_linux__)
1390     // Only assert this on known platforms, as it only affects performance, not correctness
1391     static_assert(sizeof(m_type) + sizeof(m_flags) + sizeof(m_brokenState) + sizeof(m_cloneCnt)
1392                       <= sizeof(void*),
1393                   "packing requires padding");
1394 #endif
1395 
1396     AstNodeDType* m_dtypep;  // Data type of output or assignment (etc)
1397     AstNode* m_headtailp;  // When at begin/end of list, the opposite end of the list
1398     FileLine* m_fileline;  // Where it was declared
1399     vluint64_t m_editCount;  // When it was last edited
1400     static vluint64_t s_editCntGbl;  // Global edit counter
1401     // Global edit counter, last value for printing * near node #s
1402     static vluint64_t s_editCntLast;
1403 
1404     AstNode* m_clonep;  // Pointer to clone of/ source of this module (for *LAST* cloneTree() ONLY)
1405     static int s_cloneCntGbl;  // Count of which userp is set
1406 
1407     // This member ordering both allows 64 bit alignment and puts associated data together
1408     VNUser m_user1u;  // Contains any information the user iteration routine wants
1409     uint32_t m_user1Cnt;  // Mark of when userp was set
1410     uint32_t m_user2Cnt;  // Mark of when userp was set
1411     VNUser m_user2u;  // Contains any information the user iteration routine wants
1412     VNUser m_user3u;  // Contains any information the user iteration routine wants
1413     uint32_t m_user3Cnt;  // Mark of when userp was set
1414     uint32_t m_user4Cnt;  // Mark of when userp was set
1415     VNUser m_user4u;  // Contains any information the user iteration routine wants
1416     VNUser m_user5u;  // Contains any information the user iteration routine wants
1417     uint32_t m_user5Cnt;  // Mark of when userp was set
1418 
1419     // METHODS
op1p(AstNode * nodep)1420     void op1p(AstNode* nodep) {
1421         m_op1p = nodep;
1422         if (nodep) nodep->m_backp = this;
1423     }
op2p(AstNode * nodep)1424     void op2p(AstNode* nodep) {
1425         m_op2p = nodep;
1426         if (nodep) nodep->m_backp = this;
1427     }
op3p(AstNode * nodep)1428     void op3p(AstNode* nodep) {
1429         m_op3p = nodep;
1430         if (nodep) nodep->m_backp = this;
1431     }
op4p(AstNode * nodep)1432     void op4p(AstNode* nodep) {
1433         m_op4p = nodep;
1434         if (nodep) nodep->m_backp = this;
1435     }
1436 
1437 private:
1438     AstNode* cloneTreeIter();
1439     AstNode* cloneTreeIterList();
1440     void checkTreeIter(AstNode* backp);
1441     void checkTreeIterList(AstNode* backp);
1442     bool gateTreeIter() const;
1443     static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext,
1444                              bool gateOnly);
1445     void deleteTreeIter();
1446     void deleteNode();
1447     string locationStr() const;
1448 
1449 public:
1450     static void relinkOneLink(AstNode*& pointpr, AstNode* newp);
1451     // cppcheck-suppress functionConst
1452     static void debugTreeChange(const AstNode* nodep, const char* prefix, int lineno, bool next);
1453 
1454 protected:
1455     // CONSTRUCTORS
1456     AstNode(AstType t, FileLine* fl);
1457     virtual AstNode* clone() = 0;  // Generally, cloneTree is what you want instead
cloneRelink()1458     virtual void cloneRelink() {}
1459     void cloneRelinkTree();
1460 
1461     // METHODS
1462     void setOp1p(AstNode* newp);  // Set non-list-type op1 to non-list element
1463     void setOp2p(AstNode* newp);  // Set non-list-type op2 to non-list element
1464     void setOp3p(AstNode* newp);  // Set non-list-type op3 to non-list element
1465     void setOp4p(AstNode* newp);  // Set non-list-type op4 to non-list element
1466 
1467     void addOp1p(AstNode* newp);  // Append newp to end of op1
1468     void addOp2p(AstNode* newp);  // Append newp to end of op2
1469     void addOp3p(AstNode* newp);  // Append newp to end of op3
1470     void addOp4p(AstNode* newp);  // Append newp to end of op4
1471 
1472     // clang-format off
setNOp1p(AstNode * newp)1473     void setNOp1p(AstNode* newp) { if (newp) setOp1p(newp); }
setNOp2p(AstNode * newp)1474     void setNOp2p(AstNode* newp) { if (newp) setOp2p(newp); }
setNOp3p(AstNode * newp)1475     void setNOp3p(AstNode* newp) { if (newp) setOp3p(newp); }
setNOp4p(AstNode * newp)1476     void setNOp4p(AstNode* newp) { if (newp) setOp4p(newp); }
1477 
addNOp1p(AstNode * newp)1478     void addNOp1p(AstNode* newp) { if (newp) addOp1p(newp); }
addNOp2p(AstNode * newp)1479     void addNOp2p(AstNode* newp) { if (newp) addOp2p(newp); }
addNOp3p(AstNode * newp)1480     void addNOp3p(AstNode* newp) { if (newp) addOp3p(newp); }
addNOp4p(AstNode * newp)1481     void addNOp4p(AstNode* newp) { if (newp) addOp4p(newp); }
1482     // clang-format on
1483 
clonep(AstNode * nodep)1484     void clonep(AstNode* nodep) {
1485         m_clonep = nodep;
1486         m_cloneCnt = s_cloneCntGbl;
1487     }
cloneClearTree()1488     static void cloneClearTree() {
1489         s_cloneCntGbl++;
1490         UASSERT_STATIC(s_cloneCntGbl, "Rollover");
1491     }
1492 
1493 public:
1494     // ACCESSORS
type()1495     inline AstType type() const { return m_type; }
typeName()1496     const char* typeName() const { return type().ascii(); }  // See also prettyTypeName
nextp()1497     AstNode* nextp() const { return m_nextp; }
backp()1498     AstNode* backp() const { return m_backp; }
1499     AstNode* abovep() const;  // Parent node above, only when no nextp() as otherwise slow
op1p()1500     AstNode* op1p() const { return m_op1p; }
op2p()1501     AstNode* op2p() const { return m_op2p; }
op3p()1502     AstNode* op3p() const { return m_op3p; }
op4p()1503     AstNode* op4p() const { return m_op4p; }
dtypep()1504     AstNodeDType* dtypep() const { return m_dtypep; }
clonep()1505     AstNode* clonep() const { return ((m_cloneCnt == s_cloneCntGbl) ? m_clonep : nullptr); }
firstAbovep()1506     AstNode* firstAbovep() const {  // Returns nullptr when second or later in list
1507         return ((backp() && backp()->nextp() != this) ? backp() : nullptr);
1508     }
brokenState()1509     uint8_t brokenState() const { return m_brokenState; }
brokenState(uint8_t value)1510     void brokenState(uint8_t value) { m_brokenState = value; }
1511 
1512     // Used by AstNode::broken()
brokeExists()1513     bool brokeExists() const { return V3Broken::isLinkable(this); }
brokeExistsAbove()1514     bool brokeExistsAbove() const { return brokeExists() && (m_brokenState >> 7); }
brokeExistsBelow()1515     bool brokeExistsBelow() const { return brokeExists() && !(m_brokenState >> 7); }
1516     // Note: brokeExistsBelow is not quite precise, as it is true for sibling nodes as well
1517 
1518     // CONSTRUCTORS
1519     virtual ~AstNode() = default;
1520 #ifdef VL_LEAK_CHECKS
1521     static void* operator new(size_t size);
1522     static void operator delete(void* obj, size_t size);
1523 #endif
1524 
1525     // CONSTANTS
1526     // The following are relative dynamic costs (~ execution cycle count) of various operations.
1527     // They are used by V3InstCount to estimate the relative execution time of code fragments.
1528     static constexpr int INSTR_COUNT_BRANCH = 4;  // Branch
1529     static constexpr int INSTR_COUNT_CALL = INSTR_COUNT_BRANCH + 10;  // Subroutine call
1530     static constexpr int INSTR_COUNT_LD = 2;  // Load memory
1531     static constexpr int INSTR_COUNT_INT_MUL = 3;  // Integer multiply
1532     static constexpr int INSTR_COUNT_INT_DIV = 10;  // Integer divide
1533     static constexpr int INSTR_COUNT_DBL = 8;  // Convert or do float ops
1534     static constexpr int INSTR_COUNT_DBL_DIV = 40;  // Double divide
1535     static constexpr int INSTR_COUNT_DBL_TRIG = 200;  // Double trigonometric ops
1536     static constexpr int INSTR_COUNT_STR = 100;  // String ops
1537     static constexpr int INSTR_COUNT_TIME = INSTR_COUNT_CALL + 5;  // Determine simulation time
1538     static constexpr int INSTR_COUNT_PLI = 20;  // PLI routines
1539 
1540     // ACCESSORS
name()1541     virtual string name() const { return ""; }
origName()1542     virtual string origName() const { return ""; }
name(const string & name)1543     virtual void name(const string& name) {
1544         this->v3fatalSrc("name() called on object without name() method");
1545     }
tag(const string & text)1546     virtual void tag(const string& text) {}
tag()1547     virtual string tag() const { return ""; }
verilogKwd()1548     virtual string verilogKwd() const { return ""; }
1549     string nameProtect() const;  // Name with --protect-id applied
1550     string origNameProtect() const;  // origName with --protect-id applied
1551     string shortName() const;  // Name with __PVT__ removed for concatenating scopes
1552     static string dedotName(const string& namein);  // Name with dots removed
1553     static string prettyName(const string& namein);  // Name for printing out to the user
prettyNameQ(const string & namein)1554     static string prettyNameQ(const string& namein) {  // Quoted pretty name (for errors)
1555         return string("'") + prettyName(namein) + "'";
1556     }
1557     static string
1558     encodeName(const string& namein);  // Encode user name into internal C representation
1559     static string encodeNumber(vlsint64_t num);  // Encode number into internal C representation
1560     static string vcdName(const string& namein);  // Name for printing out to vcd files
prettyName()1561     string prettyName() const { return prettyName(name()); }
prettyNameQ()1562     string prettyNameQ() const { return prettyNameQ(name()); }
1563     string prettyTypeName() const;  // "VARREF" for error messages (NOT dtype's pretty name)
prettyOperatorName()1564     virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); }
fileline()1565     FileLine* fileline() const { return m_fileline; }
fileline(FileLine * fl)1566     void fileline(FileLine* fl) { m_fileline = fl; }
1567     bool width1() const;
1568     int widthInstrs() const;
didWidth(bool flag)1569     void didWidth(bool flag) { m_flags.didWidth = flag; }
didWidth()1570     bool didWidth() const { return m_flags.didWidth; }
didWidthAndSet()1571     bool didWidthAndSet() {
1572         if (didWidth()) return true;
1573         didWidth(true);
1574         return false;
1575     }
doingWidth()1576     bool doingWidth() const { return m_flags.doingWidth; }
doingWidth(bool flag)1577     void doingWidth(bool flag) { m_flags.doingWidth = flag; }
protect()1578     bool protect() const { return m_flags.protect; }
protect(bool flag)1579     void protect(bool flag) { m_flags.protect = flag; }
1580 
1581     // TODO stomp these width functions out, and call via dtypep() instead
1582     int width() const;
1583     int widthMin() const;
widthMinV()1584     int widthMinV() const {
1585         return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width();
1586     }
widthWords()1587     int widthWords() const { return VL_WORDS_I(width()); }
isQuad()1588     bool isQuad() const { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); }
isWide()1589     bool isWide() const { return (width() > VL_QUADSIZE); }
1590     bool isDouble() const;
1591     bool isSigned() const;
1592     bool isString() const;
1593 
1594     // clang-format off
user1u()1595     VNUser      user1u() const {
1596         // Slows things down measurably, so disabled by default
1597         //UASSERT_STATIC(AstUser1InUse::s_userBusy, "userp set w/o busy");
1598         return ((m_user1Cnt==AstUser1InUse::s_userCntGbl) ? m_user1u : VNUser(0));
1599     }
user1p()1600     AstNode*    user1p() const { return user1u().toNodep(); }
user1u(const VNUser & user)1601     void        user1u(const VNUser& user) { m_user1u=user; m_user1Cnt=AstUser1InUse::s_userCntGbl; }
user1p(void * userp)1602     void        user1p(void* userp) { user1u(VNUser(userp)); }
user1()1603     int         user1() const { return user1u().toInt(); }
user1(int val)1604     void        user1(int val) { user1u(VNUser(val)); }
1605     int         user1Inc(int val=1) { int v=user1(); user1(v+val); return v; }
user1SetOnce()1606     int         user1SetOnce() { int v=user1(); if (!v) user1(1); return v; }  // Better for cache than user1Inc()
user1ClearTree()1607     static void user1ClearTree() { AstUser1InUse::clear(); }  // Clear userp()'s across the entire tree
1608 
user2u()1609     VNUser      user2u() const {
1610         // Slows things down measurably, so disabled by default
1611         //UASSERT_STATIC(AstUser2InUse::s_userBusy, "userp set w/o busy");
1612         return ((m_user2Cnt==AstUser2InUse::s_userCntGbl) ? m_user2u : VNUser(0));
1613     }
user2p()1614     AstNode*    user2p() const { return user2u().toNodep(); }
user2u(const VNUser & user)1615     void        user2u(const VNUser& user) { m_user2u=user; m_user2Cnt=AstUser2InUse::s_userCntGbl; }
user2p(void * userp)1616     void        user2p(void* userp) { user2u(VNUser(userp)); }
user2()1617     int         user2() const { return user2u().toInt(); }
user2(int val)1618     void        user2(int val) { user2u(VNUser(val)); }
1619     int         user2Inc(int val=1) { int v=user2(); user2(v+val); return v; }
user2SetOnce()1620     int         user2SetOnce() { int v=user2(); if (!v) user2(1); return v; }  // Better for cache than user2Inc()
user2ClearTree()1621     static void user2ClearTree() { AstUser2InUse::clear(); }  // Clear userp()'s across the entire tree
1622 
user3u()1623     VNUser      user3u() const {
1624         // Slows things down measurably, so disabled by default
1625         //UASSERT_STATIC(AstUser3InUse::s_userBusy, "userp set w/o busy");
1626         return ((m_user3Cnt==AstUser3InUse::s_userCntGbl) ? m_user3u : VNUser(0));
1627     }
user3p()1628     AstNode*    user3p() const { return user3u().toNodep(); }
user3u(const VNUser & user)1629     void        user3u(const VNUser& user) { m_user3u=user; m_user3Cnt=AstUser3InUse::s_userCntGbl; }
user3p(void * userp)1630     void        user3p(void* userp) { user3u(VNUser(userp)); }
user3()1631     int         user3() const { return user3u().toInt(); }
user3(int val)1632     void        user3(int val) { user3u(VNUser(val)); }
1633     int         user3Inc(int val=1) { int v=user3(); user3(v+val); return v; }
user3SetOnce()1634     int         user3SetOnce() { int v=user3(); if (!v) user3(1); return v; }  // Better for cache than user3Inc()
user3ClearTree()1635     static void user3ClearTree() { AstUser3InUse::clear(); }  // Clear userp()'s across the entire tree
1636 
user4u()1637     VNUser      user4u() const {
1638         // Slows things down measurably, so disabled by default
1639         //UASSERT_STATIC(AstUser4InUse::s_userBusy, "userp set w/o busy");
1640         return ((m_user4Cnt==AstUser4InUse::s_userCntGbl) ? m_user4u : VNUser(0));
1641     }
user4p()1642     AstNode*    user4p() const { return user4u().toNodep(); }
user4u(const VNUser & user)1643     void        user4u(const VNUser& user) { m_user4u=user; m_user4Cnt=AstUser4InUse::s_userCntGbl; }
user4p(void * userp)1644     void        user4p(void* userp) { user4u(VNUser(userp)); }
user4()1645     int         user4() const { return user4u().toInt(); }
user4(int val)1646     void        user4(int val) { user4u(VNUser(val)); }
1647     int         user4Inc(int val=1) { int v=user4(); user4(v+val); return v; }
user4SetOnce()1648     int         user4SetOnce() { int v=user4(); if (!v) user4(1); return v; }  // Better for cache than user4Inc()
user4ClearTree()1649     static void user4ClearTree() { AstUser4InUse::clear(); }  // Clear userp()'s across the entire tree
1650 
user5u()1651     VNUser      user5u() const {
1652         // Slows things down measurably, so disabled by default
1653         //UASSERT_STATIC(AstUser5InUse::s_userBusy, "userp set w/o busy");
1654         return ((m_user5Cnt==AstUser5InUse::s_userCntGbl) ? m_user5u : VNUser(0));
1655     }
user5p()1656     AstNode*    user5p() const { return user5u().toNodep(); }
user5u(const VNUser & user)1657     void        user5u(const VNUser& user) { m_user5u=user; m_user5Cnt=AstUser5InUse::s_userCntGbl; }
user5p(void * userp)1658     void        user5p(void* userp) { user5u(VNUser(userp)); }
user5()1659     int         user5() const { return user5u().toInt(); }
user5(int val)1660     void        user5(int val) { user5u(VNUser(val)); }
1661     int         user5Inc(int val=1) { int v=user5(); user5(v+val); return v; }
user5SetOnce()1662     int         user5SetOnce() { int v=user5(); if (!v) user5(1); return v; }  // Better for cache than user5Inc()
user5ClearTree()1663     static void user5ClearTree() { AstUser5InUse::clear(); }  // Clear userp()'s across the entire tree
1664     // clang-format on
1665 
editCount()1666     vluint64_t editCount() const { return m_editCount; }
editCountInc()1667     void editCountInc() {
1668         m_editCount = ++s_editCntGbl;  // Preincrement, so can "watch AstNode::s_editCntGbl=##"
1669     }
editCountLast()1670     static vluint64_t editCountLast() { return s_editCntLast; }
editCountGbl()1671     static vluint64_t editCountGbl() { return s_editCntGbl; }
editCountSetLast()1672     static void editCountSetLast() { s_editCntLast = editCountGbl(); }
1673 
1674     // ACCESSORS for specific types
1675     // Alas these can't be virtual or they break when passed a nullptr
1676     bool isZero() const;
1677     bool isOne() const;
1678     bool isNeqZero() const;
1679     bool isAllOnes() const;
1680     bool isAllOnesV() const;  // Verilog width rules apply
1681 
1682     // METHODS - data type changes especially for initial creation
dtypep(AstNodeDType * nodep)1683     void dtypep(AstNodeDType* nodep) {
1684         if (m_dtypep != nodep) {
1685             m_dtypep = nodep;
1686             editCountInc();
1687         }
1688     }
dtypeFrom(AstNode * fromp)1689     void dtypeFrom(AstNode* fromp) {
1690         if (fromp) dtypep(fromp->dtypep());
1691     }
1692     void dtypeChgSigned(bool flag = true);
1693     void dtypeChgWidth(int width, int widthMin);
1694     void dtypeChgWidthSigned(int width, int widthMin, VSigning numeric);
dtypeSetBitUnsized(int width,int widthMin,VSigning numeric)1695     void dtypeSetBitUnsized(int width, int widthMin, VSigning numeric) {
1696         dtypep(findBitDType(width, widthMin, numeric));
1697     }
dtypeSetBitSized(int width,VSigning numeric)1698     void dtypeSetBitSized(int width, VSigning numeric) {
1699         dtypep(findBitDType(width, width, numeric));  // Since sized, widthMin is width
1700     }
dtypeSetLogicUnsized(int width,int widthMin,VSigning numeric)1701     void dtypeSetLogicUnsized(int width, int widthMin, VSigning numeric) {
1702         dtypep(findLogicDType(width, widthMin, numeric));
1703     }
dtypeSetLogicSized(int width,VSigning numeric)1704     void dtypeSetLogicSized(int width, VSigning numeric) {
1705         dtypep(findLogicDType(width, width, numeric));  // Since sized, widthMin is width
1706     }
dtypeSetBit()1707     void dtypeSetBit() { dtypep(findBitDType()); }
dtypeSetDouble()1708     void dtypeSetDouble() { dtypep(findDoubleDType()); }
dtypeSetString()1709     void dtypeSetString() { dtypep(findStringDType()); }
dtypeSetSigned32()1710     void dtypeSetSigned32() { dtypep(findSigned32DType()); }
dtypeSetUInt32()1711     void dtypeSetUInt32() { dtypep(findUInt32DType()); }  // Twostate
dtypeSetUInt64()1712     void dtypeSetUInt64() { dtypep(findUInt64DType()); }  // Twostate
dtypeSetEmptyQueue()1713     void dtypeSetEmptyQueue() { dtypep(findEmptyQueueDType()); }
dtypeSetVoid()1714     void dtypeSetVoid() { dtypep(findVoidDType()); }
1715 
1716     // Data type locators
findBitDType()1717     AstNodeDType* findBitDType() { return findBasicDType(AstBasicDTypeKwd::LOGIC); }
findDoubleDType()1718     AstNodeDType* findDoubleDType() { return findBasicDType(AstBasicDTypeKwd::DOUBLE); }
findStringDType()1719     AstNodeDType* findStringDType() { return findBasicDType(AstBasicDTypeKwd::STRING); }
findSigned32DType()1720     AstNodeDType* findSigned32DType() { return findBasicDType(AstBasicDTypeKwd::INTEGER); }
findUInt32DType()1721     AstNodeDType* findUInt32DType() { return findBasicDType(AstBasicDTypeKwd::UINT32); }
findUInt64DType()1722     AstNodeDType* findUInt64DType() { return findBasicDType(AstBasicDTypeKwd::UINT64); }
findCHandleDType()1723     AstNodeDType* findCHandleDType() { return findBasicDType(AstBasicDTypeKwd::CHANDLE); }
1724     AstNodeDType* findEmptyQueueDType() const;
1725     AstNodeDType* findVoidDType() const;
1726     AstNodeDType* findQueueIndexDType() const;
1727     AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const;
1728     AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const;
1729     AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin,
1730                                       VSigning numeric) const;
1731     AstNodeDType* findBitRangeDType(const VNumRange& range, int widthMin, VSigning numeric) const;
1732     AstNodeDType* findBasicDType(AstBasicDTypeKwd kwd) const;
1733     static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
1734 
1735     // METHODS - dump and error
1736     void v3errorEnd(std::ostringstream& str) const;
1737     void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN;
warnContextPrimary()1738     string warnContextPrimary() const { return fileline()->warnContextPrimary(); }
warnContextSecondary()1739     string warnContextSecondary() const { return fileline()->warnContextSecondary(); }
warnMore()1740     string warnMore() const { return fileline()->warnMore(); }
warnOther()1741     string warnOther() const { return fileline()->warnOther(); }
1742 
1743     virtual void dump(std::ostream& str = std::cout) const;
1744     static void dumpGdb(const AstNode* nodep);  // For GDB only
1745     void dumpGdbHeader() const;
1746 
1747     // METHODS - Tree modifications
1748     // Returns nodep, adds newp to end of nodep's list
1749     static AstNode* addNext(AstNode* nodep, AstNode* newp);
1750     // Returns nodep, adds newp (maybe nullptr) to end of nodep's list
1751     static AstNode* addNextNull(AstNode* nodep, AstNode* newp);
addNext(AstNode * newp)1752     inline AstNode* addNext(AstNode* newp) { return addNext(this, newp); }
addNextNull(AstNode * newp)1753     inline AstNode* addNextNull(AstNode* newp) { return addNextNull(this, newp); }
1754     void addNextHere(AstNode* newp);  // Insert newp at this->nextp
addPrev(AstNode * newp)1755     void addPrev(AstNode* newp) {
1756         replaceWith(newp);
1757         newp->addNext(this);
1758     }
1759     void addHereThisAsNext(AstNode* newp);  // Adds at old place of this, this becomes next
1760     void replaceWith(AstNode* newp);  // Replace current node in tree with new node
1761     AstNode* unlinkFrBack(AstNRelinker* linkerp
1762                           = nullptr);  // Unlink this from whoever points to it.
1763     // Unlink this from whoever points to it, keep entire next list with unlinked node
1764     AstNode* unlinkFrBackWithNext(AstNRelinker* linkerp = nullptr);
1765     void swapWith(AstNode* bp);
1766     void relink(AstNRelinker* linkerp);  // Generally use linker->relink() instead
cloneRelinkNode()1767     void cloneRelinkNode() { cloneRelink(); }
1768     // Iterate and insert - assumes tree format
1769     virtual void addNextStmt(AstNode* newp,
1770                              AstNode* belowp);  // When calling, "this" is second argument
1771     virtual void addBeforeStmt(AstNode* newp,
1772                                AstNode* belowp);  // When calling, "this" is second argument
1773 
1774     // METHODS - Iterate on a tree
1775     // Clone or return nullptr if nullptr
cloneTreeNull(AstNode * nodep,bool cloneNextLink)1776     static AstNode* cloneTreeNull(AstNode* nodep, bool cloneNextLink) {
1777         return nodep ? nodep->cloneTree(cloneNextLink) : nullptr;
1778     }
1779     AstNode* cloneTree(bool cloneNextLink);  // Not const, as sets clonep() on original nodep
gateTree()1780     bool gateTree() { return gateTreeIter(); }  // Is tree isGateOptimizable?
1781     bool sameTree(const AstNode* node2p) const;  // Does tree of this == node2p?
1782     // Does tree of this == node2p?, not allowing non-isGateOptimizable
1783     bool sameGateTree(const AstNode* node2p) const;
1784     void deleteTree();  // Always deletes the next link
1785     void checkTree();  // User Interface version
1786     void checkIter() const;
clearIter()1787     void clearIter() { m_iterpp = nullptr; }
1788     void dumpPtrs(std::ostream& os = std::cout) const;
1789     void dumpTree(std::ostream& os = std::cout, const string& indent = "    ",
1790                   int maxDepth = 0) const;
1791     void dumpTree(const string& indent, int maxDepth = 0) const {
1792         dumpTree(cout, indent, maxDepth);
1793     }
1794     static void dumpTreeGdb(const AstNode* nodep);  // For GDB only
1795     void dumpTreeAndNext(std::ostream& os = std::cout, const string& indent = "    ",
1796                          int maxDepth = 0) const;
1797     void dumpTreeFile(const string& filename, bool append = false, bool doDump = true,
1798                       bool doCheck = true);
1799     static void dumpTreeFileGdb(const AstNode* nodep, const char* filenamep = nullptr);
1800 
1801     // METHODS - queries
1802     // Changes control flow, disable some optimizations
isBrancher()1803     virtual bool isBrancher() const { return false; }
1804     // Else a AstTime etc that can't be pushed out
isGateOptimizable()1805     virtual bool isGateOptimizable() const { return true; }
1806     // GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
isGateDedupable()1807     virtual bool isGateDedupable() const { return isGateOptimizable(); }
1808     // Else creates output or exits, etc, not unconsumed
isOutputter()1809     virtual bool isOutputter() const { return false; }
1810     // Else a AstTime etc which output can't be predicted from input
isPredictOptimizable()1811     virtual bool isPredictOptimizable() const { return true; }
1812     // Else a $display, etc, that must be ordered with other displays
isPure()1813     virtual bool isPure() const { return true; }
1814     // Else a AstTime etc that can't be substituted out
isSubstOptimizable()1815     virtual bool isSubstOptimizable() const { return true; }
1816     // isUnlikely handles $stop or similar statement which means an above IF
1817     // statement is unlikely to be taken
isUnlikely()1818     virtual bool isUnlikely() const { return false; }
instrCount()1819     virtual int instrCount() const { return 0; }
same(const AstNode *)1820     virtual bool same(const AstNode*) const { return true; }
1821     // Iff has a data type; dtype() must be non null
hasDType()1822     virtual bool hasDType() const { return false; }
1823     // Iff has a non-null childDTypep(), as generic node function
getChildDTypep()1824     virtual AstNodeDType* getChildDTypep() const { return nullptr; }
1825     // Iff has a non-null child2DTypep(), as generic node function
getChild2DTypep()1826     virtual AstNodeDType* getChild2DTypep() const { return nullptr; }
1827     // Another AstNode* may have a pointer into this node, other then normal front/back/etc.
maybePointedTo()1828     virtual bool maybePointedTo() const { return false; }
broken()1829     virtual const char* broken() const { return nullptr; }
1830 
1831     // INVOKERS
1832     virtual void accept(AstNVisitor& v) = 0;
1833 
1834 protected:
1835     // All AstNVisitor related functions are called as methods off the visitor
1836     friend class AstNVisitor;
1837     // Use instead AstNVisitor::iterateChildren
1838     void iterateChildren(AstNVisitor& v);
1839     // Use instead AstNVisitor::iterateChildrenBackwards
1840     void iterateChildrenBackwards(AstNVisitor& v);
1841     // Use instead AstNVisitor::iterateChildrenConst
1842     void iterateChildrenConst(AstNVisitor& v);
1843     // Use instead AstNVisitor::iterateAndNextNull
1844     void iterateAndNext(AstNVisitor& v);
1845     // Use instead AstNVisitor::iterateAndNextConstNull
1846     void iterateAndNextConst(AstNVisitor& v);
1847     // Use instead AstNVisitor::iterateSubtreeReturnEdits
1848     AstNode* iterateSubtreeReturnEdits(AstNVisitor& v);
1849 
1850 private:
1851     void iterateListBackwards(AstNVisitor& v);
1852 
1853     // For internal use only.
1854     template <typename T> inline static bool privateTypeTest(const AstNode* nodep);
1855 
uselessCast()1856     template <typename TargetType, typename DeclType> constexpr static bool uselessCast() {
1857         using NonRef = typename std::remove_reference<DeclType>::type;
1858         using NonPtr = typename std::remove_pointer<NonRef>::type;
1859         using NonCV = typename std::remove_cv<NonPtr>::type;
1860         return std::is_base_of<TargetType, NonCV>::value;
1861     }
1862 
impossibleCast()1863     template <typename TargetType, typename DeclType> constexpr static bool impossibleCast() {
1864         using NonRef = typename std::remove_reference<DeclType>::type;
1865         using NonPtr = typename std::remove_pointer<NonRef>::type;
1866         using NonCV = typename std::remove_cv<NonPtr>::type;
1867         return !std::is_base_of<NonCV, TargetType>::value;
1868     }
1869 
1870 public:
1871     // For use via the VN_IS macro only
privateIs(const AstNode * nodep)1872     template <typename T, typename E> inline static bool privateIs(const AstNode* nodep) {
1873         static_assert(!uselessCast<T, E>(), "Unnecessary VN_IS, node known to have target type.");
1874         static_assert(!impossibleCast<T, E>(), "Unnecessary VN_IS, node cannot be this type.");
1875         return nodep && privateTypeTest<T>(nodep);
1876     }
1877 
1878     // For use via the VN_CAST macro only
privateCast(AstNode * nodep)1879     template <typename T, typename E> inline static T* privateCast(AstNode* nodep) {
1880         static_assert(!uselessCast<T, E>(),
1881                       "Unnecessary VN_CAST, node known to have target type.");
1882         static_assert(!impossibleCast<T, E>(), "Unnecessary VN_CAST, node cannot be this type.");
1883         return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<T*>(nodep) : nullptr;
1884     }
privateCast(const AstNode * nodep)1885     template <typename T, typename E> inline static const T* privateCast(const AstNode* nodep) {
1886         static_assert(!uselessCast<T, E>(),
1887                       "Unnecessary VN_CAST, node known to have target type.");
1888         static_assert(!impossibleCast<T, E>(), "Unnecessary VN_CAST, node cannot be this type.");
1889         return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<const T*>(nodep) : nullptr;
1890     }
1891 
1892     // For use via the VN_AS macro only
privateAs(AstNode * nodep)1893     template <typename T, typename E> inline static T* privateAs(AstNode* nodep) {
1894         static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
1895         static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
1896         UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
1897                     "AstNode is not of expected type, but instead has type '" << nodep->typeName()
1898                                                                               << "'");
1899         return reinterpret_cast<T*>(nodep);
1900     }
privateAs(const AstNode * nodep)1901     template <typename T, typename E> inline static const T* privateAs(const AstNode* nodep) {
1902         static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
1903         static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
1904         UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
1905                     "AstNode is not of expected type, but instead has type '" << nodep->typeName()
1906                                                                               << "'");
1907         return reinterpret_cast<const T*>(nodep);
1908     }
1909 };
1910 
1911 // Specialisations of privateIs/privateCast
1912 #include "V3Ast__gen_impl.h"  // From ./astgen
1913 
1914 inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) {
1915     if (!rhs) {
1916         os << "nullptr";
1917     } else {
1918         rhs->dump(os);
1919     }
1920     return os;
1921 }
relink(AstNode * newp)1922 inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); }
1923 
1924 //######################################################################
1925 //######################################################################
1926 //=== AstNode* : Derived generic node types
1927 
1928 #define ASTNODE_BASE_FUNCS(name) \
1929     virtual ~Ast##name() override = default; \
1930     static Ast##name* cloneTreeNull(Ast##name* nodep, bool cloneNextLink) { \
1931         return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; \
1932     } \
1933     Ast##name* cloneTree(bool cloneNext) { \
1934         return static_cast<Ast##name*>(AstNode::cloneTree(cloneNext)); \
1935     } \
1936     Ast##name* clonep() const { return static_cast<Ast##name*>(AstNode::clonep()); }
1937 
1938 class AstNodeMath VL_NOT_FINAL : public AstNode {
1939     // Math -- anything that's part of an expression tree
1940 protected:
AstNodeMath(AstType t,FileLine * fl)1941     AstNodeMath(AstType t, FileLine* fl)
1942         : AstNode{t, fl} {}
1943 
1944 public:
1945     ASTNODE_BASE_FUNCS(NodeMath)
1946     // METHODS
1947     virtual void dump(std::ostream& str) const override;
hasDType()1948     virtual bool hasDType() const override { return true; }
1949     virtual string emitVerilog() = 0;  /// Format string for verilog writing; see V3EmitV
1950     // For documentation on emitC format see EmitCFunc::emitOpName
1951     virtual string emitC() = 0;
emitSimpleOperator()1952     virtual string emitSimpleOperator() { return ""; }  // "" means not ok to use
emitCheckMaxWords()1953     virtual bool emitCheckMaxWords() { return false; }  // Check VL_MULS_MAX_WORDS
1954     virtual bool cleanOut() const = 0;  // True if output has extra upper bits zero
1955     // Someday we will generically support data types on every math node
1956     // Until then isOpaque indicates we shouldn't constant optimize this node type
isOpaque()1957     bool isOpaque() const { return VN_IS(this, CvtPackString); }
1958 };
1959 
1960 class AstNodeTermop VL_NOT_FINAL : public AstNodeMath {
1961     // Terminal operator -- a operator with no "inputs"
1962 protected:
AstNodeTermop(AstType t,FileLine * fl)1963     AstNodeTermop(AstType t, FileLine* fl)
1964         : AstNodeMath{t, fl} {}
1965 
1966 public:
ASTNODE_BASE_FUNCS(NodeTermop)1967     ASTNODE_BASE_FUNCS(NodeTermop)
1968     // Know no children, and hot function, so skip iterator for speed
1969     // See checkTreeIter also that asserts no children
1970     // cppcheck-suppress functionConst
1971     void iterateChildren(AstNVisitor& v) {}
1972     virtual void dump(std::ostream& str) const override;
1973 };
1974 
1975 class AstNodeUniop VL_NOT_FINAL : public AstNodeMath {
1976     // Unary math
1977 protected:
AstNodeUniop(AstType t,FileLine * fl,AstNode * lhsp)1978     AstNodeUniop(AstType t, FileLine* fl, AstNode* lhsp)
1979         : AstNodeMath{t, fl} {
1980         dtypeFrom(lhsp);
1981         setOp1p(lhsp);
1982     }
1983 
1984 public:
ASTNODE_BASE_FUNCS(NodeUniop)1985     ASTNODE_BASE_FUNCS(NodeUniop)
1986     AstNode* lhsp() const { return op1p(); }
lhsp(AstNode * nodep)1987     void lhsp(AstNode* nodep) { return setOp1p(nodep); }
1988     // METHODS
1989     virtual void dump(std::ostream& str) const override;
1990     // Set out to evaluation of a AstConst'ed lhs
1991     virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0;
1992     virtual bool cleanLhs() const = 0;
1993     virtual bool sizeMattersLhs() const = 0;  // True if output result depends on lhs size
doubleFlavor()1994     virtual bool doubleFlavor() const { return false; }  // D flavor of nodes with both flavors?
1995     // Signed flavor of nodes with both flavors?
signedFlavor()1996     virtual bool signedFlavor() const { return false; }
stringFlavor()1997     virtual bool stringFlavor() const { return false; }  // N flavor of nodes with both flavors?
instrCount()1998     virtual int instrCount() const override { return widthInstrs(); }
same(const AstNode *)1999     virtual bool same(const AstNode*) const override { return true; }
2000 };
2001 
2002 class AstNodeBiop VL_NOT_FINAL : public AstNodeMath {
2003     // Binary math
2004 protected:
AstNodeBiop(AstType t,FileLine * fl,AstNode * lhs,AstNode * rhs)2005     AstNodeBiop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
2006         : AstNodeMath{t, fl} {
2007         setOp1p(lhs);
2008         setOp2p(rhs);
2009     }
2010 
2011 public:
2012     ASTNODE_BASE_FUNCS(NodeBiop)
2013     // Clone single node, just get same type back.
2014     virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0;
2015     // ACCESSORS
lhsp()2016     AstNode* lhsp() const { return op1p(); }
rhsp()2017     AstNode* rhsp() const { return op2p(); }
lhsp(AstNode * nodep)2018     void lhsp(AstNode* nodep) { return setOp1p(nodep); }
rhsp(AstNode * nodep)2019     void rhsp(AstNode* nodep) { return setOp2p(nodep); }
2020     // METHODS
2021     // Set out to evaluation of a AstConst'ed
2022     virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) = 0;
2023     virtual bool cleanLhs() const = 0;  // True if LHS must have extra upper bits zero
2024     virtual bool cleanRhs() const = 0;  // True if RHS must have extra upper bits zero
2025     virtual bool sizeMattersLhs() const = 0;  // True if output result depends on lhs size
2026     virtual bool sizeMattersRhs() const = 0;  // True if output result depends on rhs size
doubleFlavor()2027     virtual bool doubleFlavor() const { return false; }  // D flavor of nodes with both flavors?
2028     // Signed flavor of nodes with both flavors?
signedFlavor()2029     virtual bool signedFlavor() const { return false; }
stringFlavor()2030     virtual bool stringFlavor() const { return false; }  // N flavor of nodes with both flavors?
instrCount()2031     virtual int instrCount() const override { return widthInstrs(); }
same(const AstNode *)2032     virtual bool same(const AstNode*) const override { return true; }
2033 };
2034 
2035 class AstNodeTriop VL_NOT_FINAL : public AstNodeMath {
2036     // Trinary math
2037 protected:
AstNodeTriop(AstType t,FileLine * fl,AstNode * lhs,AstNode * rhs,AstNode * ths)2038     AstNodeTriop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
2039         : AstNodeMath{t, fl} {
2040         setOp1p(lhs);
2041         setOp2p(rhs);
2042         setOp3p(ths);
2043     }
2044 
2045 public:
ASTNODE_BASE_FUNCS(NodeTriop)2046     ASTNODE_BASE_FUNCS(NodeTriop)
2047     AstNode* lhsp() const { return op1p(); }
rhsp()2048     AstNode* rhsp() const { return op2p(); }
thsp()2049     AstNode* thsp() const { return op3p(); }
lhsp(AstNode * nodep)2050     void lhsp(AstNode* nodep) { return setOp1p(nodep); }
rhsp(AstNode * nodep)2051     void rhsp(AstNode* nodep) { return setOp2p(nodep); }
thsp(AstNode * nodep)2052     void thsp(AstNode* nodep) { return setOp3p(nodep); }
2053     // METHODS
2054     virtual void dump(std::ostream& str) const override;
2055     // Set out to evaluation of a AstConst'ed
2056     virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
2057                                const V3Number& ths)
2058         = 0;
2059     virtual bool cleanLhs() const = 0;  // True if LHS must have extra upper bits zero
2060     virtual bool cleanRhs() const = 0;  // True if RHS must have extra upper bits zero
2061     virtual bool cleanThs() const = 0;  // True if THS must have extra upper bits zero
2062     virtual bool sizeMattersLhs() const = 0;  // True if output result depends on lhs size
2063     virtual bool sizeMattersRhs() const = 0;  // True if output result depends on rhs size
2064     virtual bool sizeMattersThs() const = 0;  // True if output result depends on ths size
instrCount()2065     virtual int instrCount() const override { return widthInstrs(); }
same(const AstNode *)2066     virtual bool same(const AstNode*) const override { return true; }
2067 };
2068 
2069 class AstNodeQuadop VL_NOT_FINAL : public AstNodeMath {
2070     // Quaternary math
2071 protected:
AstNodeQuadop(AstType t,FileLine * fl,AstNode * lhs,AstNode * rhs,AstNode * ths,AstNode * fhs)2072     AstNodeQuadop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths, AstNode* fhs)
2073         : AstNodeMath{t, fl} {
2074         setOp1p(lhs);
2075         setOp2p(rhs);
2076         setOp3p(ths);
2077         setOp4p(fhs);
2078     }
2079 
2080 public:
ASTNODE_BASE_FUNCS(NodeQuadop)2081     ASTNODE_BASE_FUNCS(NodeQuadop)
2082     AstNode* lhsp() const { return op1p(); }
rhsp()2083     AstNode* rhsp() const { return op2p(); }
thsp()2084     AstNode* thsp() const { return op3p(); }
fhsp()2085     AstNode* fhsp() const { return op4p(); }
lhsp(AstNode * nodep)2086     void lhsp(AstNode* nodep) { return setOp1p(nodep); }
rhsp(AstNode * nodep)2087     void rhsp(AstNode* nodep) { return setOp2p(nodep); }
thsp(AstNode * nodep)2088     void thsp(AstNode* nodep) { return setOp3p(nodep); }
fhsp(AstNode * nodep)2089     void fhsp(AstNode* nodep) { return setOp4p(nodep); }
2090     // METHODS
2091     // Set out to evaluation of a AstConst'ed
2092     virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
2093                                const V3Number& ths, const V3Number& fhs)
2094         = 0;
2095     virtual bool cleanLhs() const = 0;  // True if LHS must have extra upper bits zero
2096     virtual bool cleanRhs() const = 0;  // True if RHS must have extra upper bits zero
2097     virtual bool cleanThs() const = 0;  // True if THS must have extra upper bits zero
2098     virtual bool cleanFhs() const = 0;  // True if THS must have extra upper bits zero
2099     virtual bool sizeMattersLhs() const = 0;  // True if output result depends on lhs size
2100     virtual bool sizeMattersRhs() const = 0;  // True if output result depends on rhs size
2101     virtual bool sizeMattersThs() const = 0;  // True if output result depends on ths size
2102     virtual bool sizeMattersFhs() const = 0;  // True if output result depends on ths size
instrCount()2103     virtual int instrCount() const override { return widthInstrs(); }
same(const AstNode *)2104     virtual bool same(const AstNode*) const override { return true; }
2105 };
2106 
2107 class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop {
2108     // Binary math with commutative properties
2109 protected:
AstNodeBiCom(AstType t,FileLine * fl,AstNode * lhs,AstNode * rhs)2110     AstNodeBiCom(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
2111         : AstNodeBiop{t, fl, lhs, rhs} {}
2112 
2113 public:
2114     ASTNODE_BASE_FUNCS(NodeBiCom)
2115 };
2116 
2117 class AstNodeBiComAsv VL_NOT_FINAL : public AstNodeBiCom {
2118     // Binary math with commutative & associative properties
2119 protected:
AstNodeBiComAsv(AstType t,FileLine * fl,AstNode * lhs,AstNode * rhs)2120     AstNodeBiComAsv(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs)
2121         : AstNodeBiCom{t, fl, lhs, rhs} {}
2122 
2123 public:
2124     ASTNODE_BASE_FUNCS(NodeBiComAsv)
2125 };
2126 
2127 class AstNodeCond VL_NOT_FINAL : public AstNodeTriop {
2128 protected:
AstNodeCond(AstType t,FileLine * fl,AstNode * condp,AstNode * expr1p,AstNode * expr2p)2129     AstNodeCond(AstType t, FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p)
2130         : AstNodeTriop{t, fl, condp, expr1p, expr2p} {
2131         if (expr1p) {
2132             dtypeFrom(expr1p);
2133         } else if (expr2p) {
2134             dtypeFrom(expr2p);
2135         }
2136     }
2137 
2138 public:
2139     ASTNODE_BASE_FUNCS(NodeCond)
2140     virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
2141                                const V3Number& ths) override;
condp()2142     AstNode* condp() const { return op1p(); }  // op1 = Condition
expr1p()2143     AstNode* expr1p() const { return op2p(); }  // op2 = If true...
expr2p()2144     AstNode* expr2p() const { return op3p(); }  // op3 = If false...
emitVerilog()2145     virtual string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; }
emitC()2146     virtual string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; }
cleanOut()2147     virtual bool cleanOut() const override { return false; }  // clean if e1 & e2 clean
cleanLhs()2148     virtual bool cleanLhs() const override { return true; }
cleanRhs()2149     virtual bool cleanRhs() const override { return false; }
cleanThs()2150     virtual bool cleanThs() const override { return false; }  // Propagates up
sizeMattersLhs()2151     virtual bool sizeMattersLhs() const override { return false; }
sizeMattersRhs()2152     virtual bool sizeMattersRhs() const override { return false; }
sizeMattersThs()2153     virtual bool sizeMattersThs() const override { return false; }
instrCount()2154     virtual int instrCount() const override { return INSTR_COUNT_BRANCH; }
2155     virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) = 0;
2156 };
2157 
2158 class AstNodeBlock VL_NOT_FINAL : public AstNode {
2159     // A Begin/fork block
2160     // Parents: statement
2161     // Children: statements
2162 private:
2163     string m_name;  // Name of block
2164     bool m_unnamed;  // Originally unnamed (name change does not affect this)
2165 protected:
AstNodeBlock(AstType t,FileLine * fl,const string & name,AstNode * stmtsp)2166     AstNodeBlock(AstType t, FileLine* fl, const string& name, AstNode* stmtsp)
2167         : AstNode{t, fl}
2168         , m_name{name} {
2169         addNOp1p(stmtsp);
2170         m_unnamed = (name == "");
2171     }
2172 
2173 public:
2174     ASTNODE_BASE_FUNCS(NodeBlock)
2175     virtual void dump(std::ostream& str) const override;
name()2176     virtual string name() const override { return m_name; }  // * = Block name
name(const string & name)2177     virtual void name(const string& name) override { m_name = name; }
2178     // op1 = Statements
stmtsp()2179     AstNode* stmtsp() const { return op1p(); }  // op1 = List of statements
addStmtsp(AstNode * nodep)2180     void addStmtsp(AstNode* nodep) { addNOp1p(nodep); }
unnamed()2181     bool unnamed() const { return m_unnamed; }
2182 };
2183 
2184 class AstNodePreSel VL_NOT_FINAL : public AstNode {
2185     // Something that becomes an AstSel
2186 protected:
AstNodePreSel(AstType t,FileLine * fl,AstNode * fromp,AstNode * rhs,AstNode * ths)2187     AstNodePreSel(AstType t, FileLine* fl, AstNode* fromp, AstNode* rhs, AstNode* ths)
2188         : AstNode{t, fl} {
2189         setOp1p(fromp);
2190         setOp2p(rhs);
2191         setNOp3p(ths);
2192     }
2193 
2194 public:
ASTNODE_BASE_FUNCS(NodePreSel)2195     ASTNODE_BASE_FUNCS(NodePreSel)
2196     AstNode* fromp() const { return op1p(); }
rhsp()2197     AstNode* rhsp() const { return op2p(); }
thsp()2198     AstNode* thsp() const { return op3p(); }
attrp()2199     AstAttrOf* attrp() const { return VN_AS(op4p(), AttrOf); }
fromp(AstNode * nodep)2200     void fromp(AstNode* nodep) { return setOp1p(nodep); }
rhsp(AstNode * nodep)2201     void rhsp(AstNode* nodep) { return setOp2p(nodep); }
thsp(AstNode * nodep)2202     void thsp(AstNode* nodep) { return setOp3p(nodep); }
attrp(AstAttrOf * nodep)2203     void attrp(AstAttrOf* nodep) { return setOp4p((AstNode*)nodep); }
2204     // METHODS
same(const AstNode *)2205     virtual bool same(const AstNode*) const override { return true; }
2206 };
2207 
2208 class AstNodeProcedure VL_NOT_FINAL : public AstNode {
2209     // IEEE procedure: initial, final, always
2210 protected:
AstNodeProcedure(AstType t,FileLine * fl,AstNode * bodysp)2211     AstNodeProcedure(AstType t, FileLine* fl, AstNode* bodysp)
2212         : AstNode{t, fl} {
2213         addNOp2p(bodysp);
2214     }
2215 
2216 public:
2217     ASTNODE_BASE_FUNCS(NodeProcedure)
2218     // METHODS
2219     virtual void dump(std::ostream& str) const override;
bodysp()2220     AstNode* bodysp() const { return op2p(); }  // op2 = Statements to evaluate
addStmtp(AstNode * nodep)2221     void addStmtp(AstNode* nodep) { addOp2p(nodep); }
isJustOneBodyStmt()2222     bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
2223 };
2224 
2225 class AstNodeStmt VL_NOT_FINAL : public AstNode {
2226     // Statement -- anything that's directly under a function
2227     bool m_statement;  // Really a statement (e.g. not a function with return)
2228 protected:
2229     AstNodeStmt(AstType t, FileLine* fl, bool statement = true)
2230         : AstNode{t, fl}
2231         , m_statement{statement} {}
2232 
2233 public:
ASTNODE_BASE_FUNCS(NodeStmt)2234     ASTNODE_BASE_FUNCS(NodeStmt)
2235     // METHODS
2236     bool isStatement() const { return m_statement; }  // Really a statement
statement(bool flag)2237     void statement(bool flag) { m_statement = flag; }
2238     virtual void addNextStmt(AstNode* newp,
2239                              AstNode* belowp) override;  // Stop statement searchback here
2240     virtual void addBeforeStmt(AstNode* newp,
2241                                AstNode* belowp) override;  // Stop statement searchback here
2242     virtual void dump(std::ostream& str = std::cout) const override;
2243 };
2244 
2245 class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt {
2246 protected:
AstNodeAssign(AstType t,FileLine * fl,AstNode * lhsp,AstNode * rhsp)2247     AstNodeAssign(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp)
2248         : AstNodeStmt{t, fl} {
2249         setOp1p(rhsp);
2250         setOp2p(lhsp);
2251         dtypeFrom(lhsp);
2252     }
2253 
2254 public:
2255     ASTNODE_BASE_FUNCS(NodeAssign)
2256     // Clone single node, just get same type back.
2257     virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0;
2258     // So iteration hits the RHS which is "earlier" in execution order, it's op1, not op2
rhsp()2259     AstNode* rhsp() const { return op1p(); }  // op1 = Assign from
lhsp()2260     AstNode* lhsp() const { return op2p(); }  // op2 = Assign to
rhsp(AstNode * np)2261     void rhsp(AstNode* np) { setOp1p(np); }
lhsp(AstNode * np)2262     void lhsp(AstNode* np) { setOp2p(np); }
hasDType()2263     virtual bool hasDType() const override { return true; }
cleanRhs()2264     virtual bool cleanRhs() const { return true; }
instrCount()2265     virtual int instrCount() const override { return widthInstrs(); }
same(const AstNode *)2266     virtual bool same(const AstNode*) const override { return true; }
verilogKwd()2267     virtual string verilogKwd() const override { return "="; }
2268     virtual bool brokeLhsMustBeLvalue() const = 0;
2269 };
2270 
2271 class AstNodeFor VL_NOT_FINAL : public AstNodeStmt {
2272 protected:
AstNodeFor(AstType t,FileLine * fl,AstNode * initsp,AstNode * condp,AstNode * incsp,AstNode * bodysp)2273     AstNodeFor(AstType t, FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp,
2274                AstNode* bodysp)
2275         : AstNodeStmt{t, fl} {
2276         addNOp1p(initsp);
2277         setOp2p(condp);
2278         addNOp3p(incsp);
2279         addNOp4p(bodysp);
2280     }
2281 
2282 public:
ASTNODE_BASE_FUNCS(NodeFor)2283     ASTNODE_BASE_FUNCS(NodeFor)
2284     AstNode* initsp() const { return op1p(); }  // op1 = initial statements
condp()2285     AstNode* condp() const { return op2p(); }  // op2 = condition to continue
incsp()2286     AstNode* incsp() const { return op3p(); }  // op3 = increment statements
bodysp()2287     AstNode* bodysp() const { return op4p(); }  // op4 = body of loop
isGateOptimizable()2288     virtual bool isGateOptimizable() const override { return false; }
instrCount()2289     virtual int instrCount() const override { return INSTR_COUNT_BRANCH; }
same(const AstNode * samep)2290     virtual bool same(const AstNode* samep) const override { return true; }
2291 };
2292 
2293 class AstNodeIf VL_NOT_FINAL : public AstNodeStmt {
2294 private:
2295     VBranchPred m_branchPred;  // Branch prediction as taken/untaken?
2296     bool m_isBoundsCheck;  // True if this if node was inserted for array bounds checking
2297 protected:
AstNodeIf(AstType t,FileLine * fl,AstNode * condp,AstNode * ifsp,AstNode * elsesp)2298     AstNodeIf(AstType t, FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
2299         : AstNodeStmt{t, fl} {
2300         setOp1p(condp);
2301         addNOp2p(ifsp);
2302         addNOp3p(elsesp);
2303         isBoundsCheck(false);
2304     }
2305 
2306 public:
ASTNODE_BASE_FUNCS(NodeIf)2307     ASTNODE_BASE_FUNCS(NodeIf)
2308     AstNode* condp() const { return op1p(); }  // op1 = condition
ifsp()2309     AstNode* ifsp() const { return op2p(); }  // op2 = list of true statements
elsesp()2310     AstNode* elsesp() const { return op3p(); }  // op3 = list of false statements
condp(AstNode * newp)2311     void condp(AstNode* newp) { setOp1p(newp); }
addIfsp(AstNode * newp)2312     void addIfsp(AstNode* newp) { addOp2p(newp); }
addElsesp(AstNode * newp)2313     void addElsesp(AstNode* newp) { addOp3p(newp); }
isGateOptimizable()2314     virtual bool isGateOptimizable() const override { return false; }
isGateDedupable()2315     virtual bool isGateDedupable() const override { return true; }
instrCount()2316     virtual int instrCount() const override { return INSTR_COUNT_BRANCH; }
same(const AstNode * samep)2317     virtual bool same(const AstNode* samep) const override { return true; }
branchPred(VBranchPred flag)2318     void branchPred(VBranchPred flag) { m_branchPred = flag; }
branchPred()2319     VBranchPred branchPred() const { return m_branchPred; }
isBoundsCheck(bool flag)2320     void isBoundsCheck(bool flag) { m_isBoundsCheck = flag; }
isBoundsCheck()2321     bool isBoundsCheck() const { return m_isBoundsCheck; }
2322 };
2323 
2324 class AstNodeCase VL_NOT_FINAL : public AstNodeStmt {
2325 protected:
AstNodeCase(AstType t,FileLine * fl,AstNode * exprp,AstNode * casesp)2326     AstNodeCase(AstType t, FileLine* fl, AstNode* exprp, AstNode* casesp)
2327         : AstNodeStmt{t, fl} {
2328         setOp1p(exprp);
2329         addNOp2p(casesp);
2330     }
2331 
2332 public:
ASTNODE_BASE_FUNCS(NodeCase)2333     ASTNODE_BASE_FUNCS(NodeCase)
2334     virtual int instrCount() const override { return INSTR_COUNT_BRANCH; }
exprp()2335     AstNode* exprp() const { return op1p(); }  // op1 = case condition <expression>
itemsp()2336     AstCaseItem* itemsp() const {
2337         return VN_AS(op2p(), CaseItem);
2338     }  // op2 = list of case expressions
notParallelp()2339     AstNode* notParallelp() const { return op3p(); }  // op3 = assertion code for non-full case's
addItemsp(AstNode * nodep)2340     void addItemsp(AstNode* nodep) { addOp2p(nodep); }
addNotParallelp(AstNode * nodep)2341     void addNotParallelp(AstNode* nodep) { setOp3p(nodep); }
2342 };
2343 
2344 class AstNodeVarRef VL_NOT_FINAL : public AstNodeMath {
2345     // An AstVarRef or AstVarXRef
2346 private:
2347     VAccess m_access;  // Left hand side assignment
2348     AstVar* m_varp;  // [AfterLink] Pointer to variable itself
2349     AstVarScope* m_varScopep = nullptr;  // Varscope for hierarchy
2350     AstNodeModule* m_classOrPackagep = nullptr;  // Package hierarchy
2351     string m_name;  // Name of variable
2352     string m_selfPointer;  // Output code object pointer (e.g.: 'this')
2353 
2354 protected:
AstNodeVarRef(AstType t,FileLine * fl,const string & name,const VAccess & access)2355     AstNodeVarRef(AstType t, FileLine* fl, const string& name, const VAccess& access)
2356         : AstNodeMath{t, fl}
2357         , m_access{access}
2358         , m_name{name} {
2359         this->varp(nullptr);
2360     }
AstNodeVarRef(AstType t,FileLine * fl,const string & name,AstVar * varp,const VAccess & access)2361     AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access)
2362         : AstNodeMath{t, fl}
2363         , m_access{access}
2364         , m_name{name} {
2365         // May have varp==nullptr
2366         this->varp(varp);
2367     }
2368 
2369 public:
2370     ASTNODE_BASE_FUNCS(NodeVarRef)
2371     virtual void dump(std::ostream& str) const override;
hasDType()2372     virtual bool hasDType() const override { return true; }
2373     virtual const char* broken() const override;
instrCount()2374     virtual int instrCount() const override { return widthInstrs(); }
2375     virtual void cloneRelink() override;
name()2376     virtual string name() const override { return m_name; }  // * = Var name
name(const string & name)2377     virtual void name(const string& name) override { m_name = name; }
access()2378     VAccess access() const { return m_access; }
access(const VAccess & flag)2379     void access(const VAccess& flag) { m_access = flag; }  // Avoid using this; Set in constructor
varp()2380     AstVar* varp() const { return m_varp; }  // [After Link] Pointer to variable
2381     void varp(AstVar* varp);
varScopep()2382     AstVarScope* varScopep() const { return m_varScopep; }
varScopep(AstVarScope * varscp)2383     void varScopep(AstVarScope* varscp) { m_varScopep = varscp; }
selfPointer()2384     string selfPointer() const { return m_selfPointer; }
selfPointer(const string & value)2385     void selfPointer(const string& value) { m_selfPointer = value; }
2386     string selfPointerProtect(bool useSelfForThis) const;
classOrPackagep()2387     AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
classOrPackagep(AstNodeModule * nodep)2388     void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
2389     // Know no children, and hot function, so skip iterator for speed
2390     // See checkTreeIter also that asserts no children
2391     // cppcheck-suppress functionConst
iterateChildren(AstNVisitor & v)2392     void iterateChildren(AstNVisitor& v) {}
2393 };
2394 
2395 class AstNodeText VL_NOT_FINAL : public AstNode {
2396 private:
2397     string m_text;
2398 
2399 protected:
2400     // Node that simply puts text into the output stream
AstNodeText(AstType t,FileLine * fl,const string & textp)2401     AstNodeText(AstType t, FileLine* fl, const string& textp)
2402         : AstNode{t, fl} {
2403         m_text = textp;  // Copy it
2404     }
2405 
2406 public:
2407     ASTNODE_BASE_FUNCS(NodeText)
2408     virtual void dump(std::ostream& str = std::cout) const override;
same(const AstNode * samep)2409     virtual bool same(const AstNode* samep) const override {
2410         const AstNodeText* asamep = static_cast<const AstNodeText*>(samep);
2411         return text() == asamep->text();
2412     }
text()2413     const string& text() const { return m_text; }
2414 };
2415 
2416 class AstNodeDType VL_NOT_FINAL : public AstNode {
2417     // Ideally width() would migrate to BasicDType as that's where it makes sense,
2418     // but it's currently so prevalent in the code we leave it here.
2419     // Note the below members are included in AstTypeTable::Key lookups
2420 private:
2421     int m_width;  // (also in AstTypeTable::Key) Bit width of operation
2422     int m_widthMin;  // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation
2423     VSigning m_numeric;  // (also in AstTypeTable::Key) Node is signed
2424     // Other members
2425     bool m_generic;  // Simple globally referenced type, don't garbage collect
2426     // Unique number assigned to each dtype during creation for IEEE matching
2427     static int s_uniqueNum;
2428 
2429 protected:
2430     // CONSTRUCTORS
AstNodeDType(AstType t,FileLine * fl)2431     AstNodeDType(AstType t, FileLine* fl)
2432         : AstNode{t, fl} {
2433         m_width = 0;
2434         m_widthMin = 0;
2435         m_generic = false;
2436     }
2437 
2438 public:
2439     ASTNODE_BASE_FUNCS(NodeDType)
2440     // ACCESSORS
2441     virtual void dump(std::ostream& str) const override;
2442     virtual void dumpSmall(std::ostream& str) const;
hasDType()2443     virtual bool hasDType() const override { return true; }
2444     /// Require VlUnpacked, instead of [] for POD elements.
2445     /// A non-POD object is always compound, but some POD elements
2446     /// are compound when methods calls operate on object, or when
2447     /// under another compound-requiring object e.g. class
2448     virtual bool isCompound() const = 0;
2449     // (Slow) recurse down to find basic data type
2450     virtual AstBasicDType* basicp() const = 0;
2451     // recurses over typedefs/const/enum to next non-typeref type
2452     virtual AstNodeDType* skipRefp() const = 0;
2453     // recurses over typedefs to next non-typeref-or-const type
2454     virtual AstNodeDType* skipRefToConstp() const = 0;
2455     // recurses over typedefs/const to next non-typeref-or-enum/struct type
2456     virtual AstNodeDType* skipRefToEnump() const = 0;
2457     // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
2458     virtual int widthAlignBytes() const = 0;
2459     // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
2460     virtual int widthTotalBytes() const = 0;
maybePointedTo()2461     virtual bool maybePointedTo() const override { return true; }
2462     // Iff has a non-null refDTypep(), as generic node function
virtRefDTypep()2463     virtual AstNodeDType* virtRefDTypep() const { return nullptr; }
2464     // Iff has refDTypep(), set as generic node function
virtRefDTypep(AstNodeDType * nodep)2465     virtual void virtRefDTypep(AstNodeDType* nodep) {}
2466     // Iff has a non-null second dtypep, as generic node function
virtRefDType2p()2467     virtual AstNodeDType* virtRefDType2p() const { return nullptr; }
2468     // Iff has second dtype, set as generic node function
virtRefDType2p(AstNodeDType * nodep)2469     virtual void virtRefDType2p(AstNodeDType* nodep) {}
2470     // Assignable equivalence.  Call skipRefp() on this and samep before calling
2471     virtual bool similarDType(AstNodeDType* samep) const = 0;
2472     // Iff has a non-null subDTypep(), as generic node function
subDTypep()2473     virtual AstNodeDType* subDTypep() const { return nullptr; }
2474     virtual bool isFourstate() const;
2475     // Ideally an IEEE $typename
prettyDTypeName()2476     virtual string prettyDTypeName() const { return prettyTypeName(); }
prettyDTypeNameQ()2477     string prettyDTypeNameQ() const { return "'" + prettyDTypeName() + "'"; }
2478     //
2479     // Changing the width may confuse the data type resolution, so must clear
2480     // TypeTable cache after use.
widthForce(int width,int widthMin)2481     void widthForce(int width, int widthMin) {
2482         m_width = width;
2483         m_widthMin = widthMin;
2484     }
2485     // For backward compatibility inherit width and signing from the subDType/base type
widthFromSub(AstNodeDType * nodep)2486     void widthFromSub(AstNodeDType* nodep) {
2487         m_width = nodep->m_width;
2488         m_widthMin = nodep->m_widthMin;
2489         m_numeric = nodep->m_numeric;
2490     }
2491     //
width()2492     int width() const { return m_width; }
numeric(VSigning flag)2493     void numeric(VSigning flag) { m_numeric = flag; }
isSigned()2494     bool isSigned() const { return m_numeric.isSigned(); }
isNosign()2495     bool isNosign() const { return m_numeric.isNosign(); }
numeric()2496     VSigning numeric() const { return m_numeric; }
widthWords()2497     int widthWords() const { return VL_WORDS_I(width()); }
widthMin()2498     int widthMin() const {  // If sized, the size, if unsized the min digits to represent it
2499         return m_widthMin ? m_widthMin : m_width;
2500     }
2501     int widthPow2() const;
widthMinFromWidth()2502     void widthMinFromWidth() { m_widthMin = m_width; }
widthSized()2503     bool widthSized() const { return !m_widthMin || m_widthMin == m_width; }
generic()2504     bool generic() const { return m_generic; }
generic(bool flag)2505     void generic(bool flag) { m_generic = flag; }
2506     std::pair<uint32_t, uint32_t> dimensions(bool includeBasic);
2507     uint32_t arrayUnpackedElements();  // 1, or total multiplication of all dimensions
uniqueNumInc()2508     static int uniqueNumInc() { return ++s_uniqueNum; }
charIQWN()2509     const char* charIQWN() const {
2510         return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I");
2511     }
2512     string cType(const string& name, bool forFunc, bool isRef) const;
2513     bool isLiteralType() const;  // Does this represent a C++ LiteralType? (can be constexpr)
2514 
2515 private:
2516     class CTypeRecursed;
2517     CTypeRecursed cTypeRecurse(bool compound) const;
2518 };
2519 
2520 class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType {
2521     // A struct or union; common handling
2522 private:
2523     // TYPES
2524     using MemberNameMap = std::map<const std::string, AstMemberDType*>;
2525     // MEMBERS
2526     string m_name;  // Name from upper typedef, if any
2527     bool m_packed;
2528     bool m_isFourstate;
2529     MemberNameMap m_members;
2530     const int m_uniqueNum;
2531 
2532 protected:
AstNodeUOrStructDType(AstType t,FileLine * fl,VSigning numericUnpack)2533     AstNodeUOrStructDType(AstType t, FileLine* fl, VSigning numericUnpack)
2534         : AstNodeDType{t, fl}
2535         , m_uniqueNum{uniqueNumInc()} {
2536         // VSigning::NOSIGN overloaded to indicate not packed
2537         m_packed = (numericUnpack != VSigning::NOSIGN);
2538         m_isFourstate = false;  // V3Width computes
2539         numeric(VSigning::fromBool(numericUnpack.isSigned()));
2540     }
2541 
2542 public:
ASTNODE_BASE_FUNCS(NodeUOrStructDType)2543     ASTNODE_BASE_FUNCS(NodeUOrStructDType)
2544     int uniqueNum() const { return m_uniqueNum; }
2545     virtual const char* broken() const override;
2546     virtual void dump(std::ostream& str) const override;
isCompound()2547     virtual bool isCompound() const override { return false; }  // Because don't support unpacked
2548     // For basicp() we reuse the size to indicate a "fake" basic type of same size
basicp()2549     virtual AstBasicDType* basicp() const override {
2550         return (isFourstate()
2551                     ? VN_AS(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
2552                             BasicDType)
2553                     : VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
2554                             BasicDType));
2555     }
skipRefp()2556     virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; }
skipRefToConstp()2557     virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
skipRefToEnump()2558     virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
2559     // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
2560     virtual int widthAlignBytes() const override;
2561     // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
2562     virtual int widthTotalBytes() const override;
2563     // op1 = members
similarDType(AstNodeDType * samep)2564     virtual bool similarDType(AstNodeDType* samep) const override {
2565         return this == samep;  // We don't compare members, require exact equivalence
2566     }
name()2567     virtual string name() const override { return m_name; }
name(const string & flag)2568     virtual void name(const string& flag) override { m_name = flag; }
membersp()2569     AstMemberDType* membersp() const {
2570         return VN_AS(op1p(), MemberDType);
2571     }  // op1 = AstMember list
addMembersp(AstNode * nodep)2572     void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
packed()2573     bool packed() const { return m_packed; }
2574     // packed() but as don't support unpacked, presently all structs
packedUnsup()2575     static bool packedUnsup() { return true; }
isFourstate(bool flag)2576     void isFourstate(bool flag) { m_isFourstate = flag; }
isFourstate()2577     virtual bool isFourstate() const override { return m_isFourstate; }
clearCache()2578     void clearCache() { m_members.clear(); }
2579     void repairMemberCache();
findMember(const string & name)2580     AstMemberDType* findMember(const string& name) const {
2581         const auto it = m_members.find(name);
2582         return (it == m_members.end()) ? nullptr : it->second;
2583     }
lo()2584     static int lo() { return 0; }
hi()2585     int hi() const { return dtypep()->width() - 1; }  // Packed classes look like arrays
declRange()2586     VNumRange declRange() const { return VNumRange{hi(), lo()}; }
2587 };
2588 
2589 class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType {
2590     // Array data type, ie "some_dtype var_name [2:0]"
2591     // Children: DTYPE (moved to refDTypep() in V3Width)
2592     // Children: RANGE (array bounds)
2593 private:
2594     AstNodeDType* m_refDTypep = nullptr;  // Elements of this type (after widthing)
rangenp()2595     AstNode* rangenp() const { return op2p(); }  // op2 = Array(s) of variable
2596 protected:
AstNodeArrayDType(AstType t,FileLine * fl)2597     AstNodeArrayDType(AstType t, FileLine* fl)
2598         : AstNodeDType{t, fl} {}
2599 
2600 public:
2601     ASTNODE_BASE_FUNCS(NodeArrayDType)
2602     virtual void dump(std::ostream& str) const override;
2603     virtual void dumpSmall(std::ostream& str) const override;
broken()2604     virtual const char* broken() const override {
2605         BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
2606                      || (!m_refDTypep && childDTypep())));
2607         return nullptr;
2608     }
cloneRelink()2609     virtual void cloneRelink() override {
2610         if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
2611     }
same(const AstNode * samep)2612     virtual bool same(const AstNode* samep) const override {
2613         const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
2614         return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep()
2615                 && rangenp()->sameTree(asamep->rangenp()));
2616     }  // HashedDT doesn't recurse, so need to check children
similarDType(AstNodeDType * samep)2617     virtual bool similarDType(AstNodeDType* samep) const override {
2618         const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
2619         return (asamep && type() == samep->type() && hi() == asamep->hi()
2620                 && rangenp()->sameTree(asamep->rangenp())
2621                 && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
2622     }
getChildDTypep()2623     virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); }
childDTypep()2624     AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); }
childDTypep(AstNodeDType * nodep)2625     void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
subDTypep()2626     virtual AstNodeDType* subDTypep() const override {
2627         return m_refDTypep ? m_refDTypep : childDTypep();
2628     }
refDTypep(AstNodeDType * nodep)2629     void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
virtRefDTypep()2630     virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
virtRefDTypep(AstNodeDType * nodep)2631     virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
rangep()2632     AstRange* rangep() const { return VN_AS(op2p(), Range); }  // op2 = Array(s) of variable
2633     void rangep(AstRange* nodep);
2634     // METHODS
basicp()2635     virtual AstBasicDType* basicp() const override {
2636         return subDTypep()->basicp();
2637     }  // (Slow) recurse down to find basic data type
skipRefp()2638     virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; }
skipRefToConstp()2639     virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
skipRefToEnump()2640     virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
widthAlignBytes()2641     virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
widthTotalBytes()2642     virtual int widthTotalBytes() const override {
2643         return elementsConst() * subDTypep()->widthTotalBytes();
2644     }
2645     int left() const;
2646     int right() const;
2647     int hi() const;
2648     int lo() const;
2649     int elementsConst() const;
2650     VNumRange declRange() const;
2651 };
2652 
2653 class AstNodeSel VL_NOT_FINAL : public AstNodeBiop {
2654     // Single bit range extraction, perhaps with non-constant selection or array selection
2655 protected:
AstNodeSel(AstType t,FileLine * fl,AstNode * fromp,AstNode * bitp)2656     AstNodeSel(AstType t, FileLine* fl, AstNode* fromp, AstNode* bitp)
2657         : AstNodeBiop{t, fl, fromp, bitp} {}
2658 
2659 public:
ASTNODE_BASE_FUNCS(NodeSel)2660     ASTNODE_BASE_FUNCS(NodeSel)
2661     AstNode* fromp() const {
2662         return op1p();
2663     }  // op1 = Extracting what (nullptr=TBD during parsing)
fromp(AstNode * nodep)2664     void fromp(AstNode* nodep) { setOp1p(nodep); }
bitp()2665     AstNode* bitp() const { return op2p(); }  // op2 = Msb selection expression
bitp(AstNode * nodep)2666     void bitp(AstNode* nodep) { setOp2p(nodep); }
2667     int bitConst() const;
hasDType()2668     virtual bool hasDType() const override { return true; }
2669 };
2670 
2671 class AstNodeStream VL_NOT_FINAL : public AstNodeBiop {
2672     // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
2673 protected:
AstNodeStream(AstType t,FileLine * fl,AstNode * lhsp,AstNode * rhsp)2674     AstNodeStream(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp)
2675         : AstNodeBiop{t, fl, lhsp, rhsp} {
2676         if (lhsp->dtypep()) dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED);
2677     }
2678 
2679 public:
2680     ASTNODE_BASE_FUNCS(NodeStream)
2681 };
2682 
2683 //######################################################################
2684 // Tasks/functions common handling
2685 
2686 class AstNodeCCall VL_NOT_FINAL : public AstNodeStmt {
2687     // A call of a C++ function, perhaps a AstCFunc or perhaps globally named
2688     // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal.
2689     AstCFunc* m_funcp;
2690     string m_argTypes;
2691 
2692 protected:
2693     AstNodeCCall(AstType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr)
2694         : AstNodeStmt{t, fl, true}
2695         , m_funcp{funcp} {
2696         addNOp2p(argsp);
2697     }
2698 
2699 public:
2700     ASTNODE_BASE_FUNCS(NodeCCall)
2701     virtual void dump(std::ostream& str = std::cout) const override;
2702     virtual void cloneRelink() override;
2703     virtual const char* broken() const override;
instrCount()2704     virtual int instrCount() const override { return INSTR_COUNT_CALL; }
same(const AstNode * samep)2705     virtual bool same(const AstNode* samep) const override {
2706         const AstNodeCCall* const asamep = static_cast<const AstNodeCCall*>(samep);
2707         return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes());
2708     }
exprsp()2709     AstNode* exprsp() const { return op2p(); }  // op2 = expressions to print
isGateOptimizable()2710     virtual bool isGateOptimizable() const override { return false; }
isPredictOptimizable()2711     virtual bool isPredictOptimizable() const override { return false; }
2712     virtual bool isPure() const override;
isOutputter()2713     virtual bool isOutputter() const override { return !isPure(); }
funcp()2714     AstCFunc* funcp() const { return m_funcp; }
argTypes(const string & str)2715     void argTypes(const string& str) { m_argTypes = str; }
argTypes()2716     string argTypes() const { return m_argTypes; }
2717     // op1p reserved for AstCMethodCall
argsp()2718     AstNode* argsp() const { return op2p(); }
addArgsp(AstNode * nodep)2719     void addArgsp(AstNode* nodep) { addOp2p(nodep); }
2720 };
2721 
2722 class AstNodeFTask VL_NOT_FINAL : public AstNode {
2723 private:
2724     string m_name;  // Name of task
2725     string m_cname;  // Name of task if DPI import
2726     uint64_t m_dpiOpenParent = 0;  // DPI import open array, if !=0, how many callees
2727     bool m_taskPublic : 1;  // Public task
2728     bool m_attrIsolateAssign : 1;  // User isolate_assignments attribute
2729     bool m_classMethod : 1;  // Class method
2730     bool m_externProto : 1;  // Extern prototype
2731     bool m_externDef : 1;  // Extern definition
2732     bool m_prototype : 1;  // Just a prototype
2733     bool m_dpiExport : 1;  // DPI exported
2734     bool m_dpiImport : 1;  // DPI imported
2735     bool m_dpiContext : 1;  // DPI import context
2736     bool m_dpiOpenChild : 1;  // DPI import open array child wrapper
2737     bool m_dpiTask : 1;  // DPI import task (vs. void function)
2738     bool m_dpiTraceInit : 1;  // DPI trace_init
2739     bool m_isConstructor : 1;  // Class constructor
2740     bool m_isHideLocal : 1;  // Verilog local
2741     bool m_isHideProtected : 1;  // Verilog protected
2742     bool m_pure : 1;  // DPI import pure (vs. virtual pure)
2743     bool m_pureVirtual : 1;  // Pure virtual
2744     bool m_underGenerate : 1;  // Under generate (for warning)
2745     bool m_virtual : 1;  // Virtual method in class
2746     VLifetime m_lifetime;  // Lifetime
2747 protected:
AstNodeFTask(AstType t,FileLine * fl,const string & name,AstNode * stmtsp)2748     AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp)
2749         : AstNode{t, fl}
2750         , m_name{name}
2751         , m_taskPublic{false}
2752         , m_attrIsolateAssign{false}
2753         , m_classMethod{false}
2754         , m_externProto{false}
2755         , m_externDef{false}
2756         , m_prototype{false}
2757         , m_dpiExport{false}
2758         , m_dpiImport{false}
2759         , m_dpiContext{false}
2760         , m_dpiOpenChild{false}
2761         , m_dpiTask{false}
2762         , m_dpiTraceInit{false}
2763         , m_isConstructor{false}
2764         , m_isHideLocal{false}
2765         , m_isHideProtected{false}
2766         , m_pure{false}
2767         , m_pureVirtual{false}
2768         , m_underGenerate{false}
2769         , m_virtual{false} {
2770         addNOp3p(stmtsp);
2771         cname(name);  // Might be overridden by dpi import/export
2772     }
2773 
2774 public:
2775     ASTNODE_BASE_FUNCS(NodeFTask)
2776     virtual void dump(std::ostream& str = std::cout) const override;
name()2777     virtual string name() const override { return m_name; }  // * = Var name
maybePointedTo()2778     virtual bool maybePointedTo() const override { return true; }
isGateOptimizable()2779     virtual bool isGateOptimizable() const override {
2780         return !((m_dpiExport || m_dpiImport) && !m_pure);
2781     }
2782     // {AstFunc only} op1 = Range output variable
name(const string & name)2783     virtual void name(const string& name) override { m_name = name; }
cname()2784     string cname() const { return m_cname; }
cname(const string & cname)2785     void cname(const string& cname) { m_cname = cname; }
2786     // op1 = Output variable (functions only, nullptr for tasks)
fvarp()2787     AstNode* fvarp() const { return op1p(); }
addFvarp(AstNode * nodep)2788     void addFvarp(AstNode* nodep) { addNOp1p(nodep); }
isFunction()2789     bool isFunction() const { return fvarp() != nullptr; }
2790     // op2 = Class/package scope
classOrPackagep()2791     AstNode* classOrPackagep() const { return op2p(); }
classOrPackagep(AstNode * nodep)2792     void classOrPackagep(AstNode* nodep) { setNOp2p(nodep); }
2793     // op3 = Statements/Ports/Vars
stmtsp()2794     AstNode* stmtsp() const { return op3p(); }  // op3 = List of statements
addStmtsp(AstNode * nodep)2795     void addStmtsp(AstNode* nodep) { addNOp3p(nodep); }
2796     // op4 = scope name
scopeNamep()2797     AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); }
2798     // MORE ACCESSORS
dpiOpenParentInc()2799     void dpiOpenParentInc() { ++m_dpiOpenParent; }
dpiOpenParentClear()2800     void dpiOpenParentClear() { m_dpiOpenParent = 0; }
dpiOpenParent()2801     uint64_t dpiOpenParent() const { return m_dpiOpenParent; }
scopeNamep(AstNode * nodep)2802     void scopeNamep(AstNode* nodep) { setNOp4p(nodep); }
taskPublic(bool flag)2803     void taskPublic(bool flag) { m_taskPublic = flag; }
taskPublic()2804     bool taskPublic() const { return m_taskPublic; }
attrIsolateAssign(bool flag)2805     void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
attrIsolateAssign()2806     bool attrIsolateAssign() const { return m_attrIsolateAssign; }
classMethod(bool flag)2807     void classMethod(bool flag) { m_classMethod = flag; }
classMethod()2808     bool classMethod() const { return m_classMethod; }
isExternProto(bool flag)2809     void isExternProto(bool flag) { m_externProto = flag; }
isExternProto()2810     bool isExternProto() const { return m_externProto; }
isExternDef(bool flag)2811     void isExternDef(bool flag) { m_externDef = flag; }
isExternDef()2812     bool isExternDef() const { return m_externDef; }
prototype(bool flag)2813     void prototype(bool flag) { m_prototype = flag; }
prototype()2814     bool prototype() const { return m_prototype; }
dpiExport(bool flag)2815     void dpiExport(bool flag) { m_dpiExport = flag; }
dpiExport()2816     bool dpiExport() const { return m_dpiExport; }
dpiImport(bool flag)2817     void dpiImport(bool flag) { m_dpiImport = flag; }
dpiImport()2818     bool dpiImport() const { return m_dpiImport; }
dpiContext(bool flag)2819     void dpiContext(bool flag) { m_dpiContext = flag; }
dpiContext()2820     bool dpiContext() const { return m_dpiContext; }
dpiOpenChild(bool flag)2821     void dpiOpenChild(bool flag) { m_dpiOpenChild = flag; }
dpiOpenChild()2822     bool dpiOpenChild() const { return m_dpiOpenChild; }
dpiTask(bool flag)2823     void dpiTask(bool flag) { m_dpiTask = flag; }
dpiTask()2824     bool dpiTask() const { return m_dpiTask; }
dpiTraceInit(bool flag)2825     void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; }
dpiTraceInit()2826     bool dpiTraceInit() const { return m_dpiTraceInit; }
isConstructor(bool flag)2827     void isConstructor(bool flag) { m_isConstructor = flag; }
isConstructor()2828     bool isConstructor() const { return m_isConstructor; }
isHideLocal()2829     bool isHideLocal() const { return m_isHideLocal; }
isHideLocal(bool flag)2830     void isHideLocal(bool flag) { m_isHideLocal = flag; }
isHideProtected()2831     bool isHideProtected() const { return m_isHideProtected; }
isHideProtected(bool flag)2832     void isHideProtected(bool flag) { m_isHideProtected = flag; }
pure(bool flag)2833     void pure(bool flag) { m_pure = flag; }
pure()2834     bool pure() const { return m_pure; }
pureVirtual(bool flag)2835     void pureVirtual(bool flag) { m_pureVirtual = flag; }
pureVirtual()2836     bool pureVirtual() const { return m_pureVirtual; }
underGenerate(bool flag)2837     void underGenerate(bool flag) { m_underGenerate = flag; }
underGenerate()2838     bool underGenerate() const { return m_underGenerate; }
isVirtual(bool flag)2839     void isVirtual(bool flag) { m_virtual = flag; }
isVirtual()2840     bool isVirtual() const { return m_virtual; }
lifetime(const VLifetime & flag)2841     void lifetime(const VLifetime& flag) { m_lifetime = flag; }
lifetime()2842     VLifetime lifetime() const { return m_lifetime; }
2843 };
2844 
2845 class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeStmt {
2846     // A reference to a task (or function)
2847     // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal.
2848 private:
2849     AstNodeFTask* m_taskp = nullptr;  // [AfterLink] Pointer to task referenced
2850     AstNodeModule* m_classOrPackagep = nullptr;  // Package hierarchy
2851     string m_name;  // Name of variable
2852     string m_dotted;  // Dotted part of scope the name()ed task/func is under or ""
2853     string m_inlinedDots;  // Dotted hierarchy flattened out
2854     bool m_pli = false;  // Pli system call ($name)
2855 protected:
AstNodeFTaskRef(AstType t,FileLine * fl,bool statement,AstNode * namep,AstNode * pinsp)2856     AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp)
2857         : AstNodeStmt{t, fl, statement} {
2858         setOp1p(namep);
2859         addNOp3p(pinsp);
2860     }
AstNodeFTaskRef(AstType t,FileLine * fl,bool statement,const string & name,AstNode * pinsp)2861     AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp)
2862         : AstNodeStmt{t, fl, statement}
2863         , m_name{name} {
2864         addNOp3p(pinsp);
2865     }
2866 
2867 public:
2868     ASTNODE_BASE_FUNCS(NodeFTaskRef)
2869     virtual const char* broken() const override;
cloneRelink()2870     virtual void cloneRelink() override {
2871         if (m_taskp && m_taskp->clonep()) m_taskp = m_taskp->clonep();
2872     }
2873     virtual void dump(std::ostream& str = std::cout) const override;
name()2874     virtual string name() const override { return m_name; }  // * = Var name
isGateOptimizable()2875     virtual bool isGateOptimizable() const override {
2876         return m_taskp && m_taskp->isGateOptimizable();
2877     }
dotted()2878     string dotted() const { return m_dotted; }  // * = Scope name or ""
inlinedDots()2879     string inlinedDots() const { return m_inlinedDots; }
inlinedDots(const string & flag)2880     void inlinedDots(const string& flag) { m_inlinedDots = flag; }
taskp()2881     AstNodeFTask* taskp() const { return m_taskp; }  // [After Link] Pointer to variable
taskp(AstNodeFTask * taskp)2882     void taskp(AstNodeFTask* taskp) { m_taskp = taskp; }
name(const string & name)2883     virtual void name(const string& name) override { m_name = name; }
dotted(const string & name)2884     void dotted(const string& name) { m_dotted = name; }
classOrPackagep()2885     AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
classOrPackagep(AstNodeModule * nodep)2886     void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
pli()2887     bool pli() const { return m_pli; }
pli(bool flag)2888     void pli(bool flag) { m_pli = flag; }
2889     // op1 = namep
namep()2890     AstNode* namep() const { return op1p(); }
2891     // op2 = reserved for AstMethodCall
2892     // op3 = Pin interconnection list
pinsp()2893     AstNode* pinsp() const { return op3p(); }
addPinsp(AstNode * nodep)2894     void addPinsp(AstNode* nodep) { addOp3p(nodep); }
2895     // op4 = scope tracking
scopeNamep()2896     AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); }
scopeNamep(AstNode * nodep)2897     void scopeNamep(AstNode* nodep) { setNOp4p(nodep); }
2898 };
2899 
2900 class AstNodeModule VL_NOT_FINAL : public AstNode {
2901     // A module, package, program or interface declaration;
2902     // something that can live directly under the TOP,
2903     // excluding $unit package stuff
2904 private:
2905     string m_name;  // Name of the module
2906     const string m_origName;  // Name of the module, ignoring name() changes, for dot lookup
2907     string m_hierName;  // Hierarchical name for errors, etc.
2908     bool m_modPublic : 1;  // Module has public references
2909     bool m_modTrace : 1;  // Tracing this module
2910     bool m_inLibrary : 1;  // From a library, no error if not used, never top level
2911     bool m_dead : 1;  // LinkDot believes is dead; will remove in Dead visitors
2912     bool m_hierBlock : 1;  // Hiearchical Block marked by HIER_BLOCK pragma
2913     bool m_internal : 1;  // Internally created
2914     bool m_recursive : 1;  // Recursive module
2915     bool m_recursiveClone : 1;  // If recursive, what module it clones, otherwise nullptr
2916     int m_level = 0;  // 1=top module, 2=cell off top module, ...
2917     VLifetime m_lifetime;  // Lifetime
2918     VTimescale m_timeunit;  // Global time unit
2919     VOptionBool m_unconnectedDrive;  // State of `unconnected_drive
2920 protected:
AstNodeModule(AstType t,FileLine * fl,const string & name)2921     AstNodeModule(AstType t, FileLine* fl, const string& name)
2922         : AstNode{t, fl}
2923         , m_name{name}
2924         , m_origName{name}
2925         , m_modPublic{false}
2926         , m_modTrace{false}
2927         , m_inLibrary{false}
2928         , m_dead{false}
2929         , m_hierBlock{false}
2930         , m_internal{false}
2931         , m_recursive{false}
2932         , m_recursiveClone{false} {}
2933 
2934 public:
2935     ASTNODE_BASE_FUNCS(NodeModule)
2936     virtual void dump(std::ostream& str) const override;
maybePointedTo()2937     virtual bool maybePointedTo() const override { return true; }
name()2938     virtual string name() const override { return m_name; }
2939     virtual bool timescaleMatters() const = 0;
stmtsp()2940     AstNode* stmtsp() const { return op2p(); }  // op2 = List of statements
activesp()2941     AstActive* activesp() const { return VN_AS(op3p(), Active); }  // op3 = List of i/sblocks
2942     // METHODS
addInlinesp(AstNode * nodep)2943     void addInlinesp(AstNode* nodep) { addOp1p(nodep); }
addStmtp(AstNode * nodep)2944     void addStmtp(AstNode* nodep) { addNOp2p(nodep); }
addActivep(AstNode * nodep)2945     void addActivep(AstNode* nodep) { addOp3p(nodep); }
2946     // ACCESSORS
name(const string & name)2947     virtual void name(const string& name) override { m_name = name; }
origName()2948     virtual string origName() const override { return m_origName; }
hierName()2949     string hierName() const { return m_hierName; }
hierName(const string & hierName)2950     void hierName(const string& hierName) { m_hierName = hierName; }
inLibrary()2951     bool inLibrary() const { return m_inLibrary; }
inLibrary(bool flag)2952     void inLibrary(bool flag) { m_inLibrary = flag; }
level(int level)2953     void level(int level) { m_level = level; }
level()2954     int level() const { return m_level; }
isTop()2955     bool isTop() const { return level() == 1; }
modPublic(bool flag)2956     void modPublic(bool flag) { m_modPublic = flag; }
modPublic()2957     bool modPublic() const { return m_modPublic; }
modTrace(bool flag)2958     void modTrace(bool flag) { m_modTrace = flag; }
modTrace()2959     bool modTrace() const { return m_modTrace; }
dead(bool flag)2960     void dead(bool flag) { m_dead = flag; }
dead()2961     bool dead() const { return m_dead; }
hierBlock(bool flag)2962     void hierBlock(bool flag) { m_hierBlock = flag; }
hierBlock()2963     bool hierBlock() const { return m_hierBlock; }
internal(bool flag)2964     void internal(bool flag) { m_internal = flag; }
internal()2965     bool internal() const { return m_internal; }
recursive(bool flag)2966     void recursive(bool flag) { m_recursive = flag; }
recursive()2967     bool recursive() const { return m_recursive; }
recursiveClone(bool flag)2968     void recursiveClone(bool flag) { m_recursiveClone = flag; }
recursiveClone()2969     bool recursiveClone() const { return m_recursiveClone; }
lifetime(const VLifetime & flag)2970     void lifetime(const VLifetime& flag) { m_lifetime = flag; }
lifetime()2971     VLifetime lifetime() const { return m_lifetime; }
timeunit(const VTimescale & flag)2972     void timeunit(const VTimescale& flag) { m_timeunit = flag; }
timeunit()2973     VTimescale timeunit() const { return m_timeunit; }
unconnectedDrive(const VOptionBool flag)2974     void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; }
unconnectedDrive()2975     VOptionBool unconnectedDrive() const { return m_unconnectedDrive; }
2976 };
2977 
2978 class AstNodeRange VL_NOT_FINAL : public AstNode {
2979     // A range, sized or unsized
2980 protected:
AstNodeRange(AstType t,FileLine * fl)2981     AstNodeRange(AstType t, FileLine* fl)
2982         : AstNode{t, fl} {}
2983 
2984 public:
2985     ASTNODE_BASE_FUNCS(NodeRange)
2986     virtual void dump(std::ostream& str) const override;
2987 };
2988 
2989 //######################################################################
2990 // Inline AstNVisitor METHODS
2991 
iterate(AstNode * nodep)2992 inline void AstNVisitor::iterate(AstNode* nodep) { nodep->accept(*this); }
iterateNull(AstNode * nodep)2993 inline void AstNVisitor::iterateNull(AstNode* nodep) {
2994     if (VL_LIKELY(nodep)) nodep->accept(*this);
2995 }
iterateChildren(AstNode * nodep)2996 inline void AstNVisitor::iterateChildren(AstNode* nodep) { nodep->iterateChildren(*this); }
iterateChildrenBackwards(AstNode * nodep)2997 inline void AstNVisitor::iterateChildrenBackwards(AstNode* nodep) {
2998     nodep->iterateChildrenBackwards(*this);
2999 }
iterateChildrenConst(AstNode * nodep)3000 inline void AstNVisitor::iterateChildrenConst(AstNode* nodep) {
3001     nodep->iterateChildrenConst(*this);
3002 }
iterateAndNextNull(AstNode * nodep)3003 inline void AstNVisitor::iterateAndNextNull(AstNode* nodep) {
3004     if (VL_LIKELY(nodep)) nodep->iterateAndNext(*this);
3005 }
iterateAndNextConstNull(AstNode * nodep)3006 inline void AstNVisitor::iterateAndNextConstNull(AstNode* nodep) {
3007     if (VL_LIKELY(nodep)) nodep->iterateAndNextConst(*this);
3008 }
iterateSubtreeReturnEdits(AstNode * nodep)3009 inline AstNode* AstNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) {
3010     return nodep->iterateSubtreeReturnEdits(*this);
3011 }
3012 
3013 //######################################################################
3014 
3015 #include "V3AstNodes.h"
3016 
3017 #endif  // Guard
3018