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