diff --git a/docs/internals.rst b/docs/internals.rst index a3f70ea36..3c4a2404b 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -114,6 +114,13 @@ you are at the top of the tree. By convention, each function/method uses the variable ``nodep`` as a pointer to the ``AstNode`` currently being processed. +There are notable sub-hierarchies of the ``AstNode`` sub-types, namely: + +1. All AST nodes representing data types derive from ``AstNodeDType``. + +2. All AST nodes representing expressions (i.e.: anything that stands for, + or evaluates to a value) derive from ``AstNodeExpr``. + ``VNVisitor`` ^^^^^^^^^^^^^^^ @@ -205,7 +212,7 @@ writing DFG passes easier. The ``DfgGraph`` represents combinational logic equations as a graph of ``DfgVertex`` vertices. Each sub-class of ``DfgVertex`` corresponds to an -expression (a sub-class of ``AstNodeMath``), a constanat, or a variable +expression (a sub-class of ``AstNodeExpr``), a constanat, or a variable reference. LValues and RValues referencing the same storage location are represented by the same ``DfgVertex``. Consumers of such vertices read as the LValue, writers of such vertices write the RValue. The bulk of the final @@ -1117,7 +1124,7 @@ will be used as the base name of the generated operand accessors, and An example of the full syntax of the directive is -``@astgen op1 := lhsp : AstNodeMath``. +``@astgen op1 := lhsp : AstNodeExpr``. ``astnode`` generates accessors for the child nodes based on these directives. For non-list children, the names of the getter and setter both are that of the diff --git a/include/verilated.cpp b/include/verilated.cpp index 6428c4ee5..0d0d1a5c8 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -395,7 +395,7 @@ void _vl_debug_print_w(int lbits, const WDataInP iwp) VL_MT_SAFE { } //=========================================================================== -// Slow math +// Slow expressions WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WDataInP rwp, bool is_modulus) VL_MT_SAFE { diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 8f5027f96..1733d33d4 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -929,7 +929,7 @@ static inline int _vl_cmps_w(int lbits, WDataInP const lwp, WDataInP const rwp) } //========================================================================= -// Math +// Expressions // Output NOT clean static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP const lwp) VL_MT_SAFE { @@ -1917,7 +1917,7 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, WDataOutP owp, WDataIn } //====================================================================== -// Math needing insert/select +// Expressions needing insert/select // Return QData from double (numeric) // EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index bcde753fc..616b9c43e 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -288,14 +288,14 @@ VLCOV_OBJS = \ NON_STANDALONE_HEADERS = \ V3AstInlines.h \ V3AstNodeDType.h \ - V3AstNodeMath.h \ + V3AstNodeExpr.h \ V3AstNodeOther.h \ V3DfgVertices.h \ V3WidthCommit.h \ AST_DEFS := \ V3AstNodeDType.h \ - V3AstNodeMath.h \ + V3AstNodeExpr.h \ V3AstNodeOther.h \ DFG_DEFS := \ diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp index 2be352c17..47f183122 100644 --- a/src/V3ActiveTop.cpp +++ b/src/V3ActiveTop.cpp @@ -129,7 +129,7 @@ class ActiveTopVisitor final : public VNVisitor { nodep->v3fatalSrc("Node should have been under ACTIVE"); } //-------------------- - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstVarScope*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 40d9f609f..62976a59a 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -105,7 +105,7 @@ private: // This allows syntax errors and such to be detected normally. (v3Global.opt.assertOn() ? static_cast( - new AstCMath{fl, "vlSymsp->_vm_contextp__->assertOn()", 1}) + new AstCExpr{fl, "vlSymsp->_vm_contextp__->assertOn()", 1}) : static_cast(new AstConst{fl, AstConst::BitFalse{}}))), nodep}; newp->isBoundsCheck(true); // To avoid LATCH warning diff --git a/src/V3Ast.h b/src/V3Ast.h index c38b73ce2..0e8f277a7 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2218,11 +2218,11 @@ void AstNode::addPrev(AstNode* newp) { // Specializations of AstNode::mayBeUnder template <> inline bool AstNode::mayBeUnder(const AstNode* nodep) { - return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeMath); + return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeExpr); } template <> inline bool AstNode::mayBeUnder(const AstNode* nodep) { - return !VN_IS(nodep, NodeMath); + return !VN_IS(nodep, NodeExpr); } template <> inline bool AstNode::mayBeUnder(const AstNode* nodep) { @@ -2230,7 +2230,7 @@ inline bool AstNode::mayBeUnder(const AstNode* nodep) { if (VN_IS(nodep, Var)) return false; if (VN_IS(nodep, Active)) return false; if (VN_IS(nodep, NodeStmt)) return false; - if (VN_IS(nodep, NodeMath)) return false; + if (VN_IS(nodep, NodeExpr)) return false; return true; } template <> @@ -2512,7 +2512,7 @@ AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) { // AstNode subclasses #include "V3AstNodeDType.h" -#include "V3AstNodeMath.h" +#include "V3AstNodeExpr.h" #include "V3AstNodeOther.h" // Inline function definitions need to go last diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h index 144419d05..3793225c0 100644 --- a/src/V3AstInlines.h +++ b/src/V3AstInlines.h @@ -141,8 +141,8 @@ AstCStmt::AstCStmt(FileLine* fl, const string& textStmt) addExprsp(new AstText{fl, textStmt, true}); } -AstCMath::AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut) - : ASTGEN_SUPER_CMath(fl) +AstCExpr::AstCExpr(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut) + : ASTGEN_SUPER_CExpr(fl) , m_cleanOut{cleanOut} , m_pure{true} { addExprsp(new AstText{fl, textStmt, true}); @@ -180,4 +180,6 @@ AstVarXRef::AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const V dtypeFrom(varp); } +AstStmtExpr* AstNodeExpr::makeStmt() { return new AstStmtExpr{fileline(), this}; } + #endif // Guard diff --git a/src/V3AstNodeMath.h b/src/V3AstNodeExpr.h similarity index 87% rename from src/V3AstNodeMath.h rename to src/V3AstNodeExpr.h index ef635a14a..305ac78b8 100644 --- a/src/V3AstNodeMath.h +++ b/src/V3AstNodeExpr.h @@ -14,20 +14,14 @@ // //************************************************************************* // -// This files contains all 'AstNode' sub-types that representing expressions, -// i.e.: those constructs that evaluate to [a possible void/unit] value. The -// root of the hierarchy is 'AstNodeMath', which could also be called -// 'AstNodeExpr'. -// -// Warning: Although the above is what we are aiming for, currently there are -// some 'AstNode' sub-types defined elsewhere, that represent expressions but -// are not part of the `AstNodeMath` hierarchy (e.g.: 'AstNodeCall' and its -// sub-types). These should eventually be fixed and moved under 'AstNodeMath'. +// This files contains all 'AstNode' sub-types that represent expressions, +// i.e.: those constructs that represent, or evaluate to [a possible void] +// value. The root of the hierarchy is 'AstNodeExpr'. // //************************************************************************* -#ifndef VERILATOR_V3ASTNODEMATH_H_ -#define VERILATOR_V3ASTNODEMATH_H_ +#ifndef VERILATOR_V3ASTNODEEXPR_H_ +#define VERILATOR_V3ASTNODEEXPR_H_ #ifndef VERILATOR_V3AST_H_ #error "Use V3Ast.h as the include" @@ -37,34 +31,37 @@ // === Abstract base node types (AstNode*) ===================================== -class AstNodeMath VL_NOT_FINAL : public AstNode { - // Math -- anything that's part of an expression tree +class AstNodeExpr VL_NOT_FINAL : public AstNode { + // An expression tree node protected: - AstNodeMath(VNType t, FileLine* fl) + AstNodeExpr(VNType t, FileLine* fl) : AstNode{t, fl} {} public: - ASTGEN_MEMBERS_AstNodeMath; + ASTGEN_MEMBERS_AstNodeExpr; // METHODS void dump(std::ostream& str) const override; - bool hasDType() const override { return true; } + bool hasDType() const final override { return true; } virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV // For documentation on emitC format see EmitCFunc::emitOpName virtual string emitC() = 0; virtual string emitSimpleOperator() { return ""; } // "" means not ok to use virtual bool emitCheckMaxWords() { return false; } // Check VL_MULS_MAX_WORDS virtual bool cleanOut() const = 0; // True if output has extra upper bits zero - // Someday we will generically support data types on every math node + // Someday we will generically support data types on every expr node // Until then isOpaque indicates we shouldn't constant optimize this node type bool isOpaque() const { return VN_IS(this, CvtPackString); } + + // Wrap This expression into an AstStmtExpr to denote it occurs in statement position + inline AstStmtExpr* makeStmt(); }; -class AstNodeBiop VL_NOT_FINAL : public AstNodeMath { +class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr { // Binary expression // @astgen op1 := lhsp : AstNode // @astgen op2 := rhsp : AstNode protected: AstNodeBiop(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : AstNodeMath{t, fl} { + : AstNodeExpr{t, fl} { this->lhsp(lhsp); this->rhsp(rhsp); } @@ -88,7 +85,7 @@ public: bool same(const AstNode*) const override { return true; } }; class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop { - // Binary math with commutative properties + // Binary expr with commutative properties protected: AstNodeBiCom(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) : AstNodeBiop{t, fl, lhs, rhs} {} @@ -97,7 +94,7 @@ public: ASTGEN_MEMBERS_AstNodeBiCom; }; class AstNodeBiComAsv VL_NOT_FINAL : public AstNodeBiCom { - // Binary math with commutative & associative properties + // Binary expr with commutative & associative properties protected: AstNodeBiComAsv(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) : AstNodeBiCom{t, fl, lhs, rhs} {} @@ -116,7 +113,6 @@ protected: public: ASTGEN_MEMBERS_AstNodeSel; int bitConst() const; - bool hasDType() const override { return true; } }; class AstNodeStream VL_NOT_FINAL : public AstNodeBiop { // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() @@ -144,7 +140,113 @@ public: int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } bool doubleFlavor() const override { return true; } }; -class AstNodeQuadop VL_NOT_FINAL : public AstNodeMath { +class AstNodeCCall VL_NOT_FINAL : public AstNodeExpr { + // A call of a C++ function, perhaps a AstCFunc or perhaps globally named + // @astgen op2 := argsp : List[AstNode] // Note: op1 used by some sub-types only + AstCFunc* m_funcp; + string m_argTypes; + +protected: + AstNodeCCall(VNType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) + : AstNodeExpr{t, fl} + , m_funcp{funcp} { + addArgsp(argsp); + } + +public: + ASTGEN_MEMBERS_AstNodeCCall; + void dump(std::ostream& str = std::cout) const override; + void cloneRelink() override; + const char* broken() const override; + int instrCount() const override { return INSTR_COUNT_CALL; } + bool same(const AstNode* samep) const override { + const AstNodeCCall* const asamep = static_cast(samep); + return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes()); + } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override; + bool isOutputter() const override { return !isPure(); } + AstCFunc* funcp() const { return m_funcp; } + void funcp(AstCFunc* funcp) { m_funcp = funcp; } + void argTypes(const string& str) { m_argTypes = str; } + string argTypes() const { return m_argTypes; } + + string emitVerilog() final override { V3ERROR_NA_RETURN(""); } + string emitC() final override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const final override { return true; } +}; +class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr { + // A reference to a task (or function) + // @astgen op1 := namep : Optional[AstNode] + // op2 used by some sub-types only + // @astgen op3 := pinsp : List[AstNode] + // @astgen op4 := scopeNamep : Optional[AstScopeName] + AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy + string m_name; // Name of variable + string m_dotted; // Dotted part of scope the name()ed task/func is under or "" + string m_inlinedDots; // Dotted hierarchy flattened out + bool m_pli = false; // Pli system call ($name) +protected: + AstNodeFTaskRef(VNType t, FileLine* fl, AstNode* namep, AstNode* pinsp) + : AstNodeExpr{t, fl} { + this->namep(namep); + this->addPinsp(pinsp); + } + AstNodeFTaskRef(VNType t, FileLine* fl, const string& name, AstNode* pinsp) + : AstNodeExpr{t, fl} + , m_name{name} { + this->addPinsp(pinsp); + } + +public: + ASTGEN_MEMBERS_AstNodeFTaskRef; + const char* broken() const override; + void cloneRelink() override; + void dump(std::ostream& str = std::cout) const override; + string name() const override { return m_name; } // * = Var name + bool isGateOptimizable() const override; + string dotted() const { return m_dotted; } // * = Scope name or "" + string inlinedDots() const { return m_inlinedDots; } + void inlinedDots(const string& flag) { m_inlinedDots = flag; } + AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable + void taskp(AstNodeFTask* taskp) { m_taskp = taskp; } + void name(const string& name) override { m_name = name; } + void dotted(const string& name) { m_dotted = name; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } + bool pli() const { return m_pli; } + void pli(bool flag) { m_pli = flag; } + + string emitVerilog() final override { V3ERROR_NA_RETURN(""); } + string emitC() final override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const final override { V3ERROR_NA_RETURN(true); } +}; +class AstNodePreSel VL_NOT_FINAL : public AstNodeExpr { + // Something that becomes an AstSel + // @astgen op1 := fromp : AstNode + // @astgen op2 := rhsp : AstNode + // @astgen op3 := thsp : Optional[AstNode] + // @astgen op4 := attrp : Optional[AstAttrOf] +protected: + AstNodePreSel(VNType t, FileLine* fl, AstNode* fromp, AstNode* rhsp, AstNode* thsp) + : AstNodeExpr{t, fl} { + this->fromp(fromp); + this->rhsp(rhsp); + this->thsp(thsp); + } + +public: + ASTGEN_MEMBERS_AstNodePreSel; + // METHODS + bool same(const AstNode*) const override { return true; } + + string emitVerilog() final override { V3ERROR_NA_RETURN(""); } + string emitC() final override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const final override { V3ERROR_NA_RETURN(true); } +}; +class AstNodeQuadop VL_NOT_FINAL : public AstNodeExpr { // 4-ary expression // @astgen op1 := lhsp : AstNode // @astgen op2 := rhsp : AstNode @@ -153,7 +255,7 @@ class AstNodeQuadop VL_NOT_FINAL : public AstNodeMath { protected: AstNodeQuadop(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp, AstNode* fhsp) - : AstNodeMath{t, fl} { + : AstNodeExpr{t, fl} { this->lhsp(lhsp); this->rhsp(rhsp); this->thsp(thsp); @@ -178,11 +280,11 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode*) const override { return true; } }; -class AstNodeTermop VL_NOT_FINAL : public AstNodeMath { +class AstNodeTermop VL_NOT_FINAL : public AstNodeExpr { // Terminal operator -- a operator with no "inputs" protected: AstNodeTermop(VNType t, FileLine* fl) - : AstNodeMath{t, fl} {} + : AstNodeExpr{t, fl} {} public: ASTGEN_MEMBERS_AstNodeTermop; @@ -191,14 +293,14 @@ public: void iterateChildren(VNVisitor& v) {} void dump(std::ostream& str) const override; }; -class AstNodeTriop VL_NOT_FINAL : public AstNodeMath { +class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr { // Ternary expression // @astgen op1 := lhsp : AstNode // @astgen op2 := rhsp : AstNode // @astgen op3 := thsp : AstNode protected: AstNodeTriop(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : AstNodeMath{t, fl} { + : AstNodeExpr{t, fl} { this->lhsp(lhsp); this->rhsp(rhsp); this->thsp(thsp); @@ -251,12 +353,12 @@ public: int instrCount() const override { return INSTR_COUNT_BRANCH; } virtual AstNode* cloneType(AstNode* condp, AstNode* thenp, AstNode* elsep) = 0; }; -class AstNodeUniop VL_NOT_FINAL : public AstNodeMath { +class AstNodeUniop VL_NOT_FINAL : public AstNodeExpr { // Unary expression // @astgen op1 := lhsp : AstNode protected: AstNodeUniop(VNType t, FileLine* fl, AstNode* lhsp) - : AstNodeMath{t, fl} { + : AstNodeExpr{t, fl} { dtypeFrom(lhsp); this->lhsp(lhsp); } @@ -289,9 +391,8 @@ public: int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } bool doubleFlavor() const override { return true; } }; -class AstNodeVarRef VL_NOT_FINAL : public AstNodeMath { +class AstNodeVarRef VL_NOT_FINAL : public AstNodeExpr { // An AstVarRef or AstVarXRef -private: VAccess m_access; // Left hand side assignment AstVar* m_varp; // [AfterLink] Pointer to variable itself AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy @@ -301,13 +402,13 @@ private: protected: AstNodeVarRef(VNType t, FileLine* fl, const string& name, const VAccess& access) - : AstNodeMath{t, fl} + : AstNodeExpr{t, fl} , m_access{access} , m_name{name} { varp(nullptr); } AstNodeVarRef(VNType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access) - : AstNodeMath{t, fl} + : AstNodeExpr{t, fl} , m_access{access} , m_name{name} { // May have varp==nullptr @@ -317,7 +418,6 @@ protected: public: ASTGEN_MEMBERS_AstNodeVarRef; void dump(std::ostream& str) const override; - bool hasDType() const override { return true; } const char* broken() const override; int instrCount() const override { return widthInstrs(); } void cloneRelink() override; @@ -344,10 +444,9 @@ public: // === Concrete node types ===================================================== -// === AstNodeMath === -class AstAddrOfCFunc final : public AstNodeMath { +// === AstNodeExpr === +class AstAddrOfCFunc final : public AstNodeExpr { // Get address of CFunc -private: AstCFunc* m_funcp; // Pointer to function itself public: @@ -366,22 +465,41 @@ public: bool cleanOut() const override { return true; } AstCFunc* funcp() const { return m_funcp; } }; -class AstCMath final : public AstNodeMath { +class AstAttrOf final : public AstNodeExpr { + // Return a value of a attribute, for example a LSB or array LSB of a signal + // @astgen op1 := fromp : Optional[AstNode] + // @astgen op2 := dimp : Optional[AstNode] + VAttrType m_attrType; // What sort of extraction +public: + AstAttrOf(FileLine* fl, VAttrType attrtype, AstNode* fromp = nullptr, AstNode* dimp = nullptr) + : ASTGEN_SUPER_AttrOf(fl) { + this->fromp(fromp); + this->dimp(dimp); + m_attrType = attrtype; + } + ASTGEN_MEMBERS_AstAttrOf; + VAttrType attrType() const { return m_attrType; } + void dump(std::ostream& str = std::cout) const override; + + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(true); } +}; +class AstCExpr final : public AstNodeExpr { // @astgen op1 := exprsp : List[AstNode] // Expressions to print -private: const bool m_cleanOut; bool m_pure; // Pure optimizable public: - // Emit C textual math function (like AstUCFunc) - AstCMath(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_CMath(fl) + // Emit C textual expr function (like AstUCFunc) + AstCExpr(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_CExpr(fl) , m_cleanOut{true} , m_pure{false} { addExprsp(exprsp); dtypeFrom(exprsp); } - inline AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut = true); - ASTGEN_MEMBERS_AstCMath; + inline AstCExpr(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut = true); + ASTGEN_MEMBERS_AstCExpr; bool isGateOptimizable() const override { return m_pure; } bool isPredictOptimizable() const override { return m_pure; } bool cleanOut() const override { return m_cleanOut; } @@ -391,7 +509,82 @@ public: bool pure() const { return m_pure; } void pure(bool flag) { m_pure = flag; } }; -class AstConsAssoc final : public AstNodeMath { +class AstCMethodHard final : public AstNodeExpr { + // A reference to a "C" hardcoded member task (or function) + // PARENTS: stmt/expr + // @astgen op1 := fromp : AstNode // Subject of method call + // @astgen op2 := pinsp : List[AstNode] // Arguments + string m_name; // Name of method + bool m_pure = false; // Pure optimizable +public: + AstCMethodHard(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, + AstNode* pinsp = nullptr) + : ASTGEN_SUPER_CMethodHard(fl) + , m_name{name} { + // TODO: this constructor is exactly the same as the other, bar the ignored tag argument + this->fromp(fromp); + this->addPinsp(pinsp); + dtypep(nullptr); // V3Width will resolve + } + AstCMethodHard(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp = nullptr) + : ASTGEN_SUPER_CMethodHard(fl) + , m_name{name} { + this->fromp(fromp); + this->addPinsp(pinsp); + } + ASTGEN_MEMBERS_AstCMethodHard; + string name() const override { return m_name; } // * = Var name + void name(const string& name) override { m_name = name; } + bool same(const AstNode* samep) const override { + const AstCMethodHard* asamep = static_cast(samep); + return (m_name == asamep->m_name); + } + bool isPure() const override { return m_pure; } + void pure(bool flag) { m_pure = flag; } + int instrCount() const override; + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } +}; +class AstCast final : public AstNodeExpr { + // Cast to appropriate data type + // @astgen op1 := fromp : AstNode + // @astgen op2 := childDTypep : Optional[AstNodeDType] +public: + AstCast(FileLine* fl, AstNode* fromp, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_Cast(fl) { + this->fromp(fromp); + this->childDTypep(dtp); + dtypeFrom(dtp); + } + AstCast(FileLine* fl, AstNode* fromp, AstNodeDType* dtp) + : ASTGEN_SUPER_Cast(fl) { + this->fromp(fromp); + dtypeFrom(dtp); + } + ASTGEN_MEMBERS_AstCast; + string emitVerilog() override { return "((%d)'(%l))"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(true); } + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } +}; +class AstCastParse final : public AstNodeExpr { + // Cast to appropriate type, where we haven't determined yet what the data type is + // @astgen op1 := lhsp : AstNode + // @astgen op2 := dtp : AstNode +public: + AstCastParse(FileLine* fl, AstNode* lhsp, AstNode* dtp) + : ASTGEN_SUPER_CastParse(fl) { + this->lhsp(lhsp); + this->dtp(dtp); + } + ASTGEN_MEMBERS_AstCastParse; + string emitVerilog() override { return "((%d)'(%l))"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(true); } +}; +class AstConsAssoc final : public AstNodeExpr { // Construct an assoc array and return object, '{} // @astgen op1 := defaultp : Optional[AstNode] public: @@ -407,7 +600,7 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstConsDynArray final : public AstNodeMath { +class AstConsDynArray final : public AstNodeExpr { // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} // @astgen op1 := lhsp : Optional[AstNode] // @astgen op2 := rhsp : Optional[AstNode] @@ -425,7 +618,7 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstConsQueue final : public AstNodeMath { +class AstConsQueue final : public AstNodeExpr { // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} // @astgen op1 := lhsp : Optional[AstNode] // @astgen op2 := rhsp : Optional[AstNode] @@ -443,7 +636,7 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstConsWildcard final : public AstNodeMath { +class AstConsWildcard final : public AstNodeExpr { // Construct a wildcard assoc array and return object, '{} // @astgen op1 := defaultp : Optional[AstNode] public: @@ -459,9 +652,8 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstConst final : public AstNodeMath { +class AstConst final : public AstNodeExpr { // A constant -private: V3Number m_num; // Constant value void initWithNumber() { if (m_num.isDouble()) { @@ -593,7 +785,33 @@ public: // May return nullptr on parse failure. static AstConst* parseParamLiteral(FileLine* fl, const string& literal); }; -class AstEmptyQueue final : public AstNodeMath { +class AstDot final : public AstNodeExpr { + // A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef + // These are eliminated in the link stage + // @astgen op1 := lhsp : AstNode + // @astgen op2 := rhsp : AstNode + const bool m_colon; // Is a "::" instead of a "." (lhs must be package/class) +public: + AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Dot(fl) + , m_colon{colon} { + this->lhsp(lhsp); + this->rhsp(rhsp); + } + ASTGEN_MEMBERS_AstDot; + // For parser, make only if non-null package + static AstNodeExpr* newIfPkg(FileLine* fl, AstNode* packageOrClassp, AstNodeExpr* rhsp) { + if (!packageOrClassp) return rhsp; + return new AstDot(fl, true, packageOrClassp, rhsp); + } + void dump(std::ostream& str) const override; + bool colon() const { return m_colon; } + + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(true); } +}; +class AstEmptyQueue final : public AstNodeExpr { public: explicit AstEmptyQueue(FileLine* fl) : ASTGEN_SUPER_EmptyQueue(fl) {} @@ -603,8 +821,7 @@ public: bool same(const AstNode* /*samep*/) const override { return true; } bool cleanOut() const override { return true; } }; -class AstEnumItemRef final : public AstNodeMath { -private: +class AstEnumItemRef final : public AstNodeExpr { AstEnumItem* m_itemp; // [AfterLink] Pointer to item AstNodeModule* m_classOrPackagep; // Package hierarchy public: @@ -633,8 +850,8 @@ public: AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } }; -class AstExprStmt final : public AstNodeMath { - // Perform a statement, often assignment inside an expression/math node, +class AstExprStmt final : public AstNodeExpr { + // Perform a statement, often assignment inside an expression node, // the parent gets passed the 'resultp()'. // resultp is evaluated AFTER the statement(s). // @astgen op1 := stmtsp : List[AstNode] @@ -653,7 +870,7 @@ public: bool cleanOut() const override { return false; } bool same(const AstNode*) const override { return true; } }; -class AstFError final : public AstNodeMath { +class AstFError final : public AstNodeExpr { // @astgen op1 := filep : AstNode // @astgen op2 := strp : AstNode public: @@ -666,13 +883,11 @@ public: string emitVerilog() override { return "%f$ferror(%l, %r)"; } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } - virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } int instrCount() const override { return widthInstrs() * 64; } bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstFRead final : public AstNodeMath { +class AstFRead final : public AstNodeExpr { // @astgen op1 := memp : AstNode // VarRef for result // @astgen op2 := filep : AstNode // file (must be a VarRef) // @astgen op3 := startp : Optional[AstNode] // Offset @@ -696,8 +911,7 @@ public: bool cleanOut() const override { return false; } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstFRewind final : public AstNodeMath { - // Parents: stmtlist +class AstFRewind final : public AstNodeExpr { // @astgen op1 := filep : Optional[AstNode] public: AstFRewind(FileLine* fl, AstNode* filep) @@ -716,10 +930,9 @@ public: bool cleanOut() const override { return false; } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstFScanF final : public AstNodeMath { +class AstFScanF final : public AstNodeExpr { // @astgen op1 := exprsp : List[AstNode] // VarRefs for results // @astgen op2 := filep : Optional[AstNode] // file (must be a VarRef) -private: string m_text; public: @@ -745,7 +958,7 @@ public: string text() const { return m_text; } // * = Text to display void text(const string& text) { m_text = text; } }; -class AstFSeek final : public AstNodeMath { +class AstFSeek final : public AstNodeExpr { // @astgen op1 := filep : AstNode // file (must be a VarRef) // @astgen op2 := offset : Optional[AstNode] // @astgen op3 := operation : Optional[AstNode] @@ -767,8 +980,7 @@ public: bool cleanOut() const override { return false; } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstFTell final : public AstNodeMath { - // Parents: stmtlist +class AstFTell final : public AstNodeExpr { // @astgen op1 := filep : AstNode // file (must be a VarRef) public: AstFTell(FileLine* fl, AstNode* filep) @@ -787,7 +999,7 @@ public: bool cleanOut() const override { return false; } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstFell final : public AstNodeMath { +class AstFell final : public AstNodeExpr { // Verilog $fell // @astgen op1 := exprp : AstNode // @astgen op2 := sentreep : Optional[AstSenTree] @@ -804,7 +1016,7 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstGatePin final : public AstNodeMath { +class AstGatePin final : public AstNodeExpr { // Possibly expand a gate primitive input pin value to match the range of the gate primitive // @astgen op1 := exprp : AstNode // Pin expression // @astgen op2 := rangep : AstRange // Range of pin @@ -819,7 +1031,7 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } }; -class AstImplication final : public AstNodeMath { +class AstImplication final : public AstNodeExpr { // Verilog |-> |=> // @astgen op1 := lhsp : AstNode // @astgen op2 := rhsp : AstNode @@ -838,7 +1050,7 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstInside final : public AstNodeMath { +class AstInside final : public AstNodeExpr { // @astgen op1 := exprp : AstNode // @astgen op2 := itemsp : List[AstNode] public: @@ -853,7 +1065,7 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return false; } // NA }; -class AstInsideRange final : public AstNodeMath { +class AstInsideRange final : public AstNodeExpr { // @astgen op1 := lhsp : AstNode // @astgen op2 := rhsp : AstNode public: @@ -869,11 +1081,10 @@ public: // Create AstAnd(AstGte(...), AstLte(...)) AstNode* newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp); }; -class AstLambdaArgRef final : public AstNodeMath { +class AstLambdaArgRef final : public AstNodeExpr { // Lambda argument usage // These are not AstVarRefs because we need to be able to delete/clone lambdas during // optimizations and AstVar's are painful to remove. -private: string m_name; // Name of variable bool m_index; // Index, not value @@ -887,16 +1098,13 @@ public: string emitVerilog() override { return name(); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } - bool hasDType() const override { return true; } int instrCount() const override { return widthInstrs(); } string name() const override { return m_name; } // * = Var name void name(const string& name) override { m_name = name; } bool index() const { return m_index; } }; -class AstMemberSel final : public AstNodeMath { - // Parents: math|stmt +class AstMemberSel final : public AstNodeExpr { // @astgen op1 := fromp : AstNode -private: // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it string m_name; AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection @@ -926,9 +1134,8 @@ public: AstVar* varp() const { return m_varp; } void varp(AstVar* nodep) { m_varp = nodep; } }; -class AstNewCopy final : public AstNodeMath { +class AstNewCopy final : public AstNodeExpr { // New as shallow copy - // Parents: math|stmt // @astgen op1 := rhsp : AstNode public: AstNewCopy(FileLine* fl, AstNode* rhsp) @@ -943,9 +1150,8 @@ public: bool same(const AstNode* /*samep*/) const override { return true; } int instrCount() const override { return widthInstrs(); } }; -class AstNewDynamic final : public AstNodeMath { +class AstNewDynamic final : public AstNodeExpr { // New for dynamic array - // Parents: math|stmt // @astgen op1 := sizep : AstNode // @astgen op2 := rhsp : Optional[AstNode] public: @@ -962,7 +1168,41 @@ public: bool same(const AstNode* /*samep*/) const override { return true; } int instrCount() const override { return widthInstrs(); } }; -class AstPast final : public AstNodeMath { +class AstParseRef final : public AstNodeExpr { + // A reference to a variable, function or task + // We don't know which at parse time due to bison constraints + // The link stages will replace this with AstVarRef, or AstTaskRef, etc. + // @astgen op1 := lhsp : Optional[AstNode] + // @astgen op2 := ftaskrefp : Optional[AstNodeFTaskRef] + + VParseRefExp m_expect; // Type we think it should resolve to + string m_name; + +public: + AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp = nullptr, + AstNodeFTaskRef* ftaskrefp = nullptr) + : ASTGEN_SUPER_ParseRef(fl) + , m_expect{expect} + , m_name{name} { + this->lhsp(lhsp); + this->ftaskrefp(ftaskrefp); + } + ASTGEN_MEMBERS_AstParseRef; + void dump(std::ostream& str) const override; + string name() const override { return m_name; } // * = Var name + bool same(const AstNode* samep) const override { + const AstParseRef* const asamep = static_cast(samep); + return (expect() == asamep->expect() && m_name == asamep->m_name); + } + void name(const string& name) override { m_name = name; } + VParseRefExp expect() const { return m_expect; } + void expect(VParseRefExp exp) { m_expect = exp; } + + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(true); } +}; +class AstPast final : public AstNodeExpr { // Verilog $past // @astgen op1 := exprp : AstNode // @astgen op2 := ticksp : Optional[AstNode] @@ -981,7 +1221,7 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstPatMember final : public AstNodeMath { +class AstPatMember final : public AstNodeExpr { // Verilog '{a} or '{a{b}} // Parents: AstPattern // Children: expression, AstPattern, replication count @@ -989,7 +1229,6 @@ class AstPatMember final : public AstNodeMath { // @astgen op1 := lhssp : List[AstNode] // @astgen op2 := keyp : Optional[AstNode] // @astgen op3 := repp : Optional[AstNode] // replication count, or nullptr for count 1 -private: bool m_default = false; public: @@ -1009,7 +1248,7 @@ public: bool isDefault() const { return m_default; } void isDefault(bool flag) { m_default = flag; } }; -class AstPattern final : public AstNodeMath { +class AstPattern final : public AstNodeExpr { // Verilog '{a,b,c,d...} // Parents: AstNodeAssign, AstPattern, ... // Children: expression, AstPattern, AstPatReplicate @@ -1027,13 +1266,12 @@ public: bool cleanOut() const override { V3ERROR_NA_RETURN(""); } int instrCount() const override { return widthInstrs(); } AstNodeDType* getChildDTypep() const override { return childDTypep(); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } }; -class AstRand final : public AstNodeMath { +class AstRand final : public AstNodeExpr { // $random/$random(seed) or $urandom/$urandom(seed) // Return a random number, based upon width() // @astgen op1 := seedp : Optional[AstNode] -private: const bool m_urandom = false; // $urandom vs $random const bool m_reset = false; // Random reset, versus always random public: @@ -1072,7 +1310,7 @@ public: bool reset() const { return m_reset; } bool urandom() const { return m_urandom; } }; -class AstRose final : public AstNodeMath { +class AstRose final : public AstNodeExpr { // Verilog $rose // @astgen op1 := exprp : AstNode // @astgen op2 := sentreep : Optional[AstSenTree] @@ -1089,10 +1327,64 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstSScanF final : public AstNodeMath { +class AstSFormatF final : public AstNodeExpr { + // Convert format to string, generally under an AstDisplay or AstSFormat + // Also used as "real" function for /*verilator sformat*/ functions + // @astgen op1 := exprsp : List[AstNode] + // @astgen op2 := scopeNamep : Optional[AstScopeName] + string m_text; + const bool m_hidden; // Under display, etc + bool m_hasFormat; // Has format code + const char m_missingArgChar; // Format code when argument without format, 'h'/'o'/'b' + VTimescale m_timeunit; // Parent module time unit +public: + class NoFormat {}; + AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp, + char missingArgChar = 'd') + : ASTGEN_SUPER_SFormatF(fl) + , m_text{text} + , m_hidden{hidden} + , m_hasFormat{true} + , m_missingArgChar{missingArgChar} { + dtypeSetString(); + addExprsp(exprsp); + } + AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd', + bool hidden = true) + : ASTGEN_SUPER_SFormatF(fl) + , m_text{""} + , m_hidden{hidden} + , m_hasFormat{false} + , m_missingArgChar{missingArgChar} { + dtypeSetString(); + addExprsp(exprsp); + } + ASTGEN_MEMBERS_AstSFormatF; + string name() const override { return m_text; } + int instrCount() const override { return INSTR_COUNT_PLI; } + bool same(const AstNode* samep) const override { + return text() == static_cast(samep)->text(); + } + string verilogKwd() const override { return "$sformatf"; } + string text() const { return m_text; } // * = Text to display + void text(const string& text) { m_text = text; } + bool formatScopeTracking() const { // Track scopeNamep(); Ok if false positive + return (name().find("%m") != string::npos || name().find("%M") != string::npos); + } + bool hidden() const { return m_hidden; } + void hasFormat(bool flag) { m_hasFormat = flag; } + bool hasFormat() const { return m_hasFormat; } + char missingArgChar() const { return m_missingArgChar; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } + + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(true); } +}; +class AstSScanF final : public AstNodeExpr { // @astgen op1 := exprsp : List[AstNode] // VarRefs for results // @astgen op2 := fromp : AstNode -private: string m_text; public: @@ -1118,7 +1410,7 @@ public: string text() const { return m_text; } // * = Text to display void text(const string& text) { m_text = text; } }; -class AstSampled final : public AstNodeMath { +class AstSampled final : public AstNodeExpr { // Verilog $sampled // @astgen op1 := exprp : AstNode public: @@ -1134,12 +1426,11 @@ public: int instrCount() const override { return 0; } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstScopeName final : public AstNodeMath { +class AstScopeName final : public AstNodeExpr { // For display %m and DPI context imports // Parents: DISPLAY // @astgen op1 := scopeAttrp : List[AstText] // @astgen op2 := scopeEntrp : List[AstText] -private: bool m_dpiExport = false; // Is for dpiExport const bool m_forFormat = false; // Is for a format %m string scopeNameFormatter(AstText* scopeTextp) const; @@ -1177,9 +1468,8 @@ public: void dpiExport(bool flag) { m_dpiExport = flag; } bool forFormat() const { return m_forFormat; } }; -class AstSetAssoc final : public AstNodeMath { +class AstSetAssoc final : public AstNodeExpr { // Set an assoc array element and return object, '{} - // Parents: math // @astgen op1 := lhsp : AstNode // @astgen op2 := keyp : Optional[AstNode] // @astgen op3 := valuep : AstNode @@ -1198,9 +1488,8 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstSetWildcard final : public AstNodeMath { +class AstSetWildcard final : public AstNodeExpr { // Set a wildcard assoc array element and return object, '{} - // Parents: math // @astgen op1 := lhsp : AstNode // @astgen op2 := keyp : Optional[AstNode] // @astgen op3 := valuep : AstNode @@ -1219,7 +1508,7 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstStable final : public AstNodeMath { +class AstStable final : public AstNodeExpr { // Verilog $stable // @astgen op1 := exprp : AstNode // @astgen op2 := sentreep : Optional[AstSenTree] @@ -1236,7 +1525,26 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstSystemF final : public AstNodeMath { +class AstSysIgnore final : public AstNodeExpr { + // @astgen op1 := exprsp : List[AstNode] // Expressions to output (???) +public: + AstSysIgnore(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_SysIgnore(fl) { + this->addExprsp(exprsp); + } + ASTGEN_MEMBERS_AstSysIgnore; + string verilogKwd() const override { return "$ignored"; } + bool isGateOptimizable() const override { return false; } // Though deleted before opt + bool isPredictOptimizable() const override { return false; } // Though deleted before opt + bool isPure() const override { return false; } // Though deleted before opt + bool isOutputter() const override { return true; } // Though deleted before opt + int instrCount() const override { return INSTR_COUNT_PLI; } + + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(true); } +}; +class AstSystemF final : public AstNodeExpr { // $system used as function // @astgen op1 := lhsp : AstNode public: @@ -1256,7 +1564,7 @@ public: bool cleanOut() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstTestPlusArgs final : public AstNodeMath { +class AstTestPlusArgs final : public AstNodeExpr { // Search expression. If nullptr then this is a $test$plusargs instead of $value$plusargs. // @astgen op1 := searchp : Optional[AstNode] public: @@ -1273,7 +1581,7 @@ public: bool cleanOut() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstThisRef final : public AstNodeMath { +class AstThisRef final : public AstNodeExpr { // Reference to 'this'. // @astgen op1 := childDTypep : Optional[AstClassRefDType] // dtype of the node public: @@ -1287,9 +1595,9 @@ public: bool same(const AstNode* /*samep*/) const override { return true; } bool cleanOut() const override { return true; } AstNodeDType* getChildDTypep() const override { return childDTypep(); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } }; -class AstUCFunc final : public AstNodeMath { +class AstUCFunc final : public AstNodeExpr { // User's $c function // Perhaps this should be an AstNodeListop; but there's only one list math right now // @astgen op1 := exprsp : List[AstNode] // Expressions to print @@ -1310,7 +1618,7 @@ public: int instrCount() const override { return INSTR_COUNT_PLI; } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstUnbounded final : public AstNodeMath { +class AstUnbounded final : public AstNodeExpr { // A $ in the parser, used for unbounded and queues // Due to where is used, treated as Signed32 public: @@ -1323,7 +1631,26 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } }; -class AstValuePlusArgs final : public AstNodeMath { +class AstUnlinkedRef final : public AstNodeExpr { + // As-of-yet unlinkable Ref + // @astgen op1 := refp : AstNode + // @astgen op2 := cellrefp : AstNode + + string m_name; // Var name // TODO: There is no way to access this, fix or remove +public: + AstUnlinkedRef(FileLine* fl, AstNode* refp, const string& name, AstNode* cellrefp) + : ASTGEN_SUPER_UnlinkedRef(fl) + , m_name{name} { + this->refp(refp); + this->cellrefp(cellrefp); + } + ASTGEN_MEMBERS_AstUnlinkedRef; + + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(true); } +}; +class AstValuePlusArgs final : public AstNodeExpr { // Search expression. If nullptr then this is a $test$plusargs instead of $value$plusargs. // @astgen op1 := searchp : Optional[AstNode] // @astgen op2 := outp : AstNode // VarRef for result @@ -1343,6 +1670,26 @@ public: bool cleanOut() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; +class AstWithParse final : public AstNodeExpr { + // In early parse, FUNC(index) WITH equation-using-index + // Replaced with AstWith + // Parents: expr|stmt + // Children: funcref, expr + // @astgen op1 := funcrefp : AstNode + // @astgen op2 := exprp : Optional[AstNode] +public: + AstWithParse(FileLine* fl, AstNode* funcrefp, AstNode* exprp) + : ASTGEN_SUPER_WithParse(fl) { + this->funcrefp(funcrefp); + this->exprp(exprp); + } + ASTGEN_MEMBERS_AstWithParse; + bool same(const AstNode* /*samep*/) const override { return true; } + + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(true); } +}; // === AstNodeBiop === class AstBufIf1 final : public AstNodeBiop { @@ -1373,8 +1720,6 @@ public: class AstCastDynamic final : public AstNodeBiop { // Verilog $cast used as a function // Task usage of $cast is converted during parse to assert($cast(...)) - // Parents: MATH - // Children: MATH // lhsp() is value (we are converting FROM) to match AstCCast etc, this // is opposite of $cast's order, because the first access is to the // value reading from. Suggest use fromp()/top() instead of lhsp/rhsp(). @@ -1402,7 +1747,6 @@ public: }; class AstCompareNN final : public AstNodeBiop { // Verilog str.compare() and str.icompare() -private: const bool m_ignoreCase; // True for str.icompare() public: AstCompareNN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, bool ignoreCase) @@ -2917,9 +3261,6 @@ public: // === AstNodeSel === class AstArraySel final : public AstNodeSel { - // Parents: math|stmt - // Children: varref|arraysel, math -private: void init(AstNode* fromp) { if (fromp && VN_IS(fromp->dtypep()->skipRefp(), NodeArrayDType)) { // Strip off array to find what array references @@ -2959,9 +3300,6 @@ public: static AstNode* baseFromp(AstNode* nodep, bool overMembers); }; class AstAssocSel final : public AstNodeSel { - // Parents: math|stmt - // Children: varref|arraysel, math -private: void init(AstNode* fromp) { if (fromp && VN_IS(fromp->dtypep()->skipRefp(), AssocArrayDType)) { // Strip off array to find what array references @@ -2994,9 +3332,6 @@ public: int instrCount() const override { return widthInstrs(); } }; class AstWildcardSel final : public AstNodeSel { - // Parents: math|stmt - // Children: varref|arraysel, math -private: void init(AstNode* fromp) { if (fromp && VN_IS(fromp->dtypep()->skipRefp(), WildcardArrayDType)) { // Strip off array to find what array references @@ -3128,6 +3463,144 @@ public: string emitC() override { return "hypot(%li,%ri)"; } }; +// === AstNodeCCall === +class AstCCall final : public AstNodeCCall { + // C++ function call + string m_selfPointer; // Output code object pointer (e.g.: 'this') + +public: + AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) + : ASTGEN_SUPER_CCall(fl, funcp, argsp) {} + ASTGEN_MEMBERS_AstCCall; + + string selfPointer() const { return m_selfPointer; } + void selfPointer(const string& value) { m_selfPointer = value; } + string selfPointerProtect(bool useSelfForThis) const; +}; +class AstCMethodCall final : public AstNodeCCall { + // C++ method call + // @astgen op1 := fromp : AstNode +public: + AstCMethodCall(FileLine* fl, AstNode* fromp, AstCFunc* funcp, AstNode* argsp = nullptr) + : ASTGEN_SUPER_CMethodCall(fl, funcp, argsp) { + this->fromp(fromp); + } + ASTGEN_MEMBERS_AstCMethodCall; + const char* broken() const override { + BROKEN_BASE_RTN(AstNodeCCall::broken()); + BROKEN_RTN(!fromp()); + return nullptr; + } +}; +class AstCNew final : public AstNodeCCall { + // C++ new() call +public: + AstCNew(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) + : ASTGEN_SUPER_CNew(fl, funcp, argsp) {} + ASTGEN_MEMBERS_AstCNew; +}; + +// === AstNodeFTaskRef === +class AstFuncRef final : public AstNodeFTaskRef { + // A reference to a function +public: + AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) + : ASTGEN_SUPER_FuncRef(fl, (AstNode*)namep, pinsp) {} + AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp) + : ASTGEN_SUPER_FuncRef(fl, name, pinsp) {} + ASTGEN_MEMBERS_AstFuncRef; +}; +class AstMethodCall final : public AstNodeFTaskRef { + // A reference to a member task (or function) + // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it + // @astgen op2 := fromp : AstNode + // +public: + AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, + AstNode* pinsp) + : ASTGEN_SUPER_MethodCall(fl, name, pinsp) { + this->fromp(fromp); + dtypep(nullptr); // V3Width will resolve + } + AstMethodCall(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp) + : ASTGEN_SUPER_MethodCall(fl, name, pinsp) { + this->fromp(fromp); + } + ASTGEN_MEMBERS_AstMethodCall; + const char* broken() const override { + BROKEN_BASE_RTN(AstNodeFTaskRef::broken()); + BROKEN_RTN(!fromp()); + return nullptr; + } + void dump(std::ostream& str) const override; +}; +class AstNew final : public AstNodeFTaskRef { + // New as constructor + // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it +public: + AstNew(FileLine* fl, AstNode* pinsp) + : ASTGEN_SUPER_New(fl, "new", pinsp) {} + ASTGEN_MEMBERS_AstNew; + bool same(const AstNode* /*samep*/) const override { return true; } + int instrCount() const override { return widthInstrs(); } +}; +class AstTaskRef final : public AstNodeFTaskRef { + // A reference to a task +public: + AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) + : ASTGEN_SUPER_TaskRef(fl, (AstNode*)namep, pinsp) { + dtypeSetVoid(); + } + AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp) + : ASTGEN_SUPER_TaskRef(fl, name, pinsp) { + dtypeSetVoid(); + } + ASTGEN_MEMBERS_AstTaskRef; +}; + +// === AstNodePreSel === +class AstSelBit final : public AstNodePreSel { + // Single bit range extraction, perhaps with non-constant selection or array selection + // Gets replaced during link with AstArraySel or AstSel +public: + AstSelBit(FileLine* fl, AstNode* fromp, AstNode* bitp) + : ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) { + UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, + "not coded to create after dtypes resolved"); + } + ASTGEN_MEMBERS_AstSelBit; + AstNode* bitp() const { return rhsp(); } +}; +class AstSelExtract final : public AstNodePreSel { + // Range extraction, gets replaced with AstSel +public: + AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp) + : ASTGEN_SUPER_SelExtract(fl, fromp, msbp, lsbp) {} + ASTGEN_MEMBERS_AstSelExtract; + AstNode* leftp() const { return rhsp(); } + AstNode* rightp() const { return thsp(); } +}; +class AstSelMinus final : public AstNodePreSel { + // -: range extraction, perhaps with non-constant selection + // Gets replaced during link with AstSel +public: + AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) + : ASTGEN_SUPER_SelMinus(fl, fromp, bitp, widthp) {} + ASTGEN_MEMBERS_AstSelMinus; + AstNode* bitp() const { return rhsp(); } + AstNode* widthp() const { return thsp(); } +}; +class AstSelPlus final : public AstNodePreSel { + // +: range extraction, perhaps with non-constant selection + // Gets replaced during link with AstSel +public: + AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) + : ASTGEN_SUPER_SelPlus(fl, fromp, bitp, widthp) {} + ASTGEN_MEMBERS_AstSelPlus; + AstNode* bitp() const { return rhsp(); } + AstNode* widthp() const { return thsp(); } +}; + // === AstNodeQuadop === class AstCountBits final : public AstNodeQuadop { // Number of bits set in vector @@ -3203,7 +3676,6 @@ public: // === AstNodeTriop === class AstPostAdd final : public AstNodeTriop { // Post-increment/add - // Parents: MATH // Children: lhsp: AstConst (1) as currently support only ++ not += // Children: rhsp: tree with AstVarRef that is value to read before operation // Children: thsp: tree with AstVarRef LValue that is stored after operation @@ -3228,7 +3700,6 @@ public: }; class AstPostSub final : public AstNodeTriop { // Post-decrement/subtract - // Parents: MATH // Children: lhsp: AstConst (1) as currently support only -- not -= // Children: rhsp: tree with AstVarRef that is value to read before operation // Children: thsp: tree with AstVarRef LValue that is stored after operation @@ -3253,7 +3724,6 @@ public: }; class AstPreAdd final : public AstNodeTriop { // Pre-increment/add - // Parents: MATH // Children: lhsp: AstConst (1) as currently support only ++ not += // Children: rhsp: tree with AstVarRef that is value to read before operation // Children: thsp: tree with AstVarRef LValue that is stored after operation @@ -3278,7 +3748,6 @@ public: }; class AstPreSub final : public AstNodeTriop { // Pre-decrement/subtract - // Parents: MATH // Children: lhsp: AstConst (1) as currently support only -- not -= // Children: rhsp: tree with AstVarRef that is value to read before operation // Children: thsp: tree with AstVarRef LValue that is stored after operation @@ -3327,12 +3796,9 @@ public: }; class AstSel final : public AstNodeTriop { // Multiple bit range extraction - // Parents: math|stmt - // Children: varref|arraysel, math, constant math // @astgen alias op1 := fromp // @astgen alias op2 := lsbp // @astgen alias op3 := widthp -private: VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid int m_declElWidth; // If a packed array, the number of bits per element public: @@ -3380,9 +3846,7 @@ public: }; class AstSliceSel final : public AstNodeTriop { // Multiple array element extraction - // Parents: math|stmt // @astgen alias op1 := fromp -private: VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid public: AstSliceSel(FileLine* fl, AstNode* fromp, const VNumRange& declRange) @@ -3438,9 +3902,7 @@ public: // === AstNodeCond === class AstCond final : public AstNodeCond { - // Conditional ?: statement - // Parents: MATH - // Children: MATH + // Conditional ?: expressoin public: AstCond(FileLine* fl, AstNode* condp, AstNode* thenp, AstNode* elsep) : ASTGEN_SUPER_Cond(fl, condp, thenp, elsep) {} @@ -3450,9 +3912,7 @@ public: } }; class AstCondBound final : public AstNodeCond { - // Conditional ?: statement, specially made for safety checking of array bounds - // Parents: MATH - // Children: MATH + // Conditional ?: expression, specially made for safety checking of array bounds public: AstCondBound(FileLine* fl, AstNode* condp, AstNode* thenp, AstNode* elsep) : ASTGEN_SUPER_CondBound(fl, condp, thenp, elsep) {} @@ -3519,9 +3979,30 @@ public: bool sizeMattersLhs() const override { return false; } // Eliminated before matters int instrCount() const override { return INSTR_COUNT_DBL; } }; +class AstCAwait final : public AstNodeUniop { + // Emit C++'s co_await expression + // @astgen alias op1 := exprp + AstSenTree* m_sensesp; // Sentree related to this await +public: + AstCAwait(FileLine* fl, AstNode* exprp, AstSenTree* sensesp = nullptr) + : ASTGEN_SUPER_CAwait(fl, exprp) + , m_sensesp{sensesp} {} + ASTGEN_MEMBERS_AstCAwait; + bool isTimingControl() const override { return true; } + const char* broken() const override; + void cloneRelink() override; + void dump(std::ostream& str) const override; + AstSenTree* sensesp() const { return m_sensesp; } + void clearSensesp() { m_sensesp = nullptr; } + void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } +}; class AstCCast final : public AstNodeUniop { // Cast to C-based data type -private: int m_size; public: @@ -3817,7 +4298,6 @@ public: }; class AstNullCheck final : public AstNodeUniop { // Return LHS after checking that LHS is non-null - // Children: VarRef or something returning pointer public: AstNullCheck(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER_NullCheck(fl, lhsp) { @@ -4273,7 +4753,6 @@ public: class AstVarXRef final : public AstNodeVarRef { // A VarRef to something in another module before AstScope. // Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope -private: string m_dotted; // Dotted part of scope the name()'ed reference is under or "" string m_inlinedDots; // Dotted hierarchy flattened out public: diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 7343024d4..cbafbfc8b 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -264,25 +264,6 @@ public: void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } }; -class AstNodePreSel VL_NOT_FINAL : public AstNode { - // Something that becomes an AstSel - // @astgen op1 := fromp : AstNode - // @astgen op2 := rhsp : AstNode - // @astgen op3 := thsp : Optional[AstNode] - // @astgen op4 := attrp : Optional[AstAttrOf] -protected: - AstNodePreSel(VNType t, FileLine* fl, AstNode* fromp, AstNode* rhsp, AstNode* thsp) - : AstNode{t, fl} { - this->fromp(fromp); - this->rhsp(rhsp); - this->thsp(thsp); - } - -public: - ASTGEN_MEMBERS_AstNodePreSel; - // METHODS - bool same(const AstNode*) const override { return true; } -}; class AstNodeProcedure VL_NOT_FINAL : public AstNode { // IEEE procedure: initial, final, always // @astgen op2 := stmtsp : List[AstNode] // Note: op1 is used in some sub-types only @@ -312,18 +293,14 @@ public: void dump(std::ostream& str) const override; }; class AstNodeStmt VL_NOT_FINAL : public AstNode { - // Statement -- anything that's directly under a function - bool m_statement; // Really a statement (e.g. not a function with return) + // Procedural statement protected: - AstNodeStmt(VNType t, FileLine* fl, bool statement = true) - : AstNode{t, fl} - , m_statement{statement} {} + AstNodeStmt(VNType t, FileLine* fl) + : AstNode{t, fl} {} public: ASTGEN_MEMBERS_AstNodeStmt; // METHODS - bool isStatement() const { return m_statement; } // Really a statement - void statement(bool flag) { m_statement = flag; } void addNextStmt(AstNode* newp, AstNode* belowp) override; // Stop statement searchback here void addBeforeStmt(AstNode* newp, @@ -357,40 +334,6 @@ public: bool isTimingControl() const override { return timingControlp(); } virtual bool brokeLhsMustBeLvalue() const = 0; }; -class AstNodeCCall VL_NOT_FINAL : public AstNodeStmt { - // A call of a C++ function, perhaps a AstCFunc or perhaps globally named - // @astgen op2 := argsp : List[AstNode] // Note: op1 used by some sub-types only - // - // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. - AstCFunc* m_funcp; - string m_argTypes; - -protected: - AstNodeCCall(VNType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : AstNodeStmt{t, fl, true} - , m_funcp{funcp} { - addArgsp(argsp); - } - -public: - ASTGEN_MEMBERS_AstNodeCCall; - void dump(std::ostream& str = std::cout) const override; - void cloneRelink() override; - const char* broken() const override; - int instrCount() const override { return INSTR_COUNT_CALL; } - bool same(const AstNode* samep) const override { - const AstNodeCCall* const asamep = static_cast(samep); - return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes()); - } - bool isGateOptimizable() const override { return false; } - bool isPredictOptimizable() const override { return false; } - bool isPure() const override; - bool isOutputter() const override { return !isPure(); } - AstCFunc* funcp() const { return m_funcp; } - void funcp(AstCFunc* funcp) { m_funcp = funcp; } - void argTypes(const string& str) { m_argTypes = str; } - string argTypes() const { return m_argTypes; } -}; class AstNodeCase VL_NOT_FINAL : public AstNodeStmt { // @astgen op1 := exprp : AstNode // Condition (scurtinee) expression // @astgen op2 := itemsp : List[AstCaseItem] @@ -431,52 +374,6 @@ public: void dump(std::ostream& str = std::cout) const override; bool immediate() const { return m_immediate; } }; -class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeStmt { - // A reference to a task (or function) - // @astgen op1 := namep : Optional[AstNode] - // op2 used by some sub-types only - // @astgen op3 := pinsp : List[AstNode] - // @astgen op4 := scopeNamep : Optional[AstScopeName] - // - // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. -private: - AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy - string m_name; // Name of variable - string m_dotted; // Dotted part of scope the name()ed task/func is under or "" - string m_inlinedDots; // Dotted hierarchy flattened out - bool m_pli = false; // Pli system call ($name) -protected: - AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) - : AstNodeStmt{t, fl, statement} { - this->namep(namep); - this->addPinsp(pinsp); - } - AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp) - : AstNodeStmt{t, fl, statement} - , m_name{name} { - this->addPinsp(pinsp); - } - -public: - ASTGEN_MEMBERS_AstNodeFTaskRef; - const char* broken() const override; - void cloneRelink() override; - void dump(std::ostream& str = std::cout) const override; - string name() const override { return m_name; } // * = Var name - bool isGateOptimizable() const override { return m_taskp && m_taskp->isGateOptimizable(); } - string dotted() const { return m_dotted; } // * = Scope name or "" - string inlinedDots() const { return m_inlinedDots; } - void inlinedDots(const string& flag) { m_inlinedDots = flag; } - AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable - void taskp(AstNodeFTask* taskp) { m_taskp = taskp; } - void name(const string& name) override { m_name = name; } - void dotted(const string& name) { m_dotted = name; } - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } - bool pli() const { return m_pli; } - void pli(bool flag) { m_pli = flag; } -}; class AstNodeFor VL_NOT_FINAL : public AstNodeStmt { // @astgen op1 := initsp : List[AstNode] // @astgen op2 := condp : AstNode @@ -635,22 +532,6 @@ public: void name(const string& name) override { m_name = name; } bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); } }; -class AstAttrOf final : public AstNode { - // Return a value of a attribute, for example a LSB or array LSB of a signal - // @astgen op1 := fromp : Optional[AstNode] - // @astgen op2 := dimp : Optional[AstNode] - VAttrType m_attrType; // What sort of extraction -public: - AstAttrOf(FileLine* fl, VAttrType attrtype, AstNode* fromp = nullptr, AstNode* dimp = nullptr) - : ASTGEN_SUPER_AttrOf(fl) { - this->fromp(fromp); - this->dimp(dimp); - m_attrType = attrtype; - } - ASTGEN_MEMBERS_AstAttrOf; - VAttrType attrType() const { return m_attrType; } - void dump(std::ostream& str = std::cout) const override; -}; class AstBind final : public AstNode { // Parents: MODULE // Children: CELL @@ -849,48 +730,6 @@ public: bool isDefault() const { return condsp() == nullptr; } bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } }; -class AstCast final : public AstNode { - // Cast to appropriate data type - // @astgen op1 := fromp : AstNode - // @astgen op2 := childDTypep : Optional[AstNodeDType] -public: - AstCast(FileLine* fl, AstNode* fromp, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_Cast(fl) { - this->fromp(fromp); - this->childDTypep(dtp); - dtypeFrom(dtp); - } - AstCast(FileLine* fl, AstNode* fromp, AstNodeDType* dtp) - : ASTGEN_SUPER_Cast(fl) { - this->fromp(fromp); - dtypeFrom(dtp); - } - ASTGEN_MEMBERS_AstCast; - bool hasDType() const override { return true; } - virtual string emitVerilog() { return "((%d)'(%l))"; } - virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } - virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } - AstNodeDType* getChildDTypep() const override { return childDTypep(); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } -}; -class AstCastParse final : public AstNode { - // Cast to appropriate type, where we haven't determined yet what the data type is - // @astgen op1 := lhsp : AstNode - // @astgen op2 := dtp : AstNode -public: - AstCastParse(FileLine* fl, AstNode* lhsp, AstNode* dtp) - : ASTGEN_SUPER_CastParse(fl) { - this->lhsp(lhsp); - this->dtp(dtp); - } - ASTGEN_MEMBERS_AstCastParse; - virtual string emitVerilog() { return "((%d)'(%l))"; } - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } - virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } -}; class AstCastSize final : public AstNode { // Cast to specific size; signed/twostate inherited from lower element per IEEE // @astgen op1 := lhsp : AstNode @@ -1135,28 +974,6 @@ public: bool same(const AstNode*) const override { return true; } string path() const { return m_path; } }; -class AstDot final : public AstNode { - // A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef - // These are eliminated in the link stage - // @astgen op1 := lhsp : AstNode - // @astgen op2 := rhsp : AstNode - const bool m_colon; // Is a "::" instead of a "." (lhs must be package/class) -public: - AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Dot(fl) - , m_colon{colon} { - this->lhsp(lhsp); - this->rhsp(rhsp); - } - ASTGEN_MEMBERS_AstDot; - // For parser, make only if non-null package - static AstNode* newIfPkg(FileLine* fl, AstNode* packageOrClassp, AstNode* rhsp) { - if (!packageOrClassp) return rhsp; - return new AstDot(fl, true, packageOrClassp, rhsp); - } - void dump(std::ostream& str) const override; - bool colon() const { return m_colon; } -}; class AstDpiExport final : public AstNode { // We could put an AstNodeFTaskRef instead of the verilog function name, // however we're not *calling* it, so that seems somehow wrong. @@ -1497,37 +1314,6 @@ public: AstPackage* packagep() const { return m_packagep; } void packagep(AstPackage* nodep) { m_packagep = nodep; } }; -class AstParseRef final : public AstNode { - // A reference to a variable, function or task - // We don't know which at parse time due to bison constraints - // The link stages will replace this with AstVarRef, or AstTaskRef, etc. - // Parents: math|stmt - // @astgen op1 := lhsp : Optional[AstNode] - // @astgen op2 := ftaskrefp : Optional[AstNodeFTaskRef] - - VParseRefExp m_expect; // Type we think it should resolve to - string m_name; - -public: - AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp = nullptr, - AstNodeFTaskRef* ftaskrefp = nullptr) - : ASTGEN_SUPER_ParseRef(fl) - , m_expect{expect} - , m_name{name} { - this->lhsp(lhsp); - this->ftaskrefp(ftaskrefp); - } - ASTGEN_MEMBERS_AstParseRef; - void dump(std::ostream& str) const override; - string name() const override { return m_name; } // * = Var name - bool same(const AstNode* samep) const override { - const AstParseRef* const asamep = static_cast(samep); - return (expect() == asamep->expect() && m_name == asamep->m_name); - } - void name(const string& name) override { m_name = name; } - VParseRefExp expect() const { return m_expect; } - void expect(VParseRefExp exp) { m_expect = exp; } -}; class AstPin final : public AstNode { // A port or parameter assignment on an instantiaton // @astgen op1 := exprp : Optional[AstNode] // Expression connected (nullptr if unconnected) @@ -1629,58 +1415,6 @@ public: } uint32_t direction() const { return (uint32_t)m_direction; } }; -class AstSFormatF final : public AstNode { - // Convert format to string, generally under an AstDisplay or AstSFormat - // Also used as "real" function for /*verilator sformat*/ functions - // @astgen op1 := exprsp : List[AstNode] - // @astgen op2 := scopeNamep : Optional[AstScopeName] - string m_text; - const bool m_hidden; // Under display, etc - bool m_hasFormat; // Has format code - const char m_missingArgChar; // Format code when argument without format, 'h'/'o'/'b' - VTimescale m_timeunit; // Parent module time unit -public: - class NoFormat {}; - AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp, - char missingArgChar = 'd') - : ASTGEN_SUPER_SFormatF(fl) - , m_text{text} - , m_hidden{hidden} - , m_hasFormat{true} - , m_missingArgChar{missingArgChar} { - dtypeSetString(); - addExprsp(exprsp); - } - AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd', - bool hidden = true) - : ASTGEN_SUPER_SFormatF(fl) - , m_text{""} - , m_hidden{hidden} - , m_hasFormat{false} - , m_missingArgChar{missingArgChar} { - dtypeSetString(); - addExprsp(exprsp); - } - ASTGEN_MEMBERS_AstSFormatF; - string name() const override { return m_text; } - int instrCount() const override { return INSTR_COUNT_PLI; } - bool hasDType() const override { return true; } - bool same(const AstNode* samep) const override { - return text() == static_cast(samep)->text(); - } - string verilogKwd() const override { return "$sformatf"; } - string text() const { return m_text; } // * = Text to display - void text(const string& text) { m_text = text; } - bool formatScopeTracking() const { // Track scopeNamep(); Ok if false positive - return (name().find("%m") != string::npos || name().find("%M") != string::npos); - } - bool hidden() const { return m_hidden; } - void hasFormat(bool flag) { m_hasFormat = flag; } - bool hasFormat() const { return m_hasFormat; } - char missingArgChar() const { return m_missingArgChar; } - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; class AstScope final : public AstNode { // A particular usage of a cell // Parents: MODULE @@ -1952,21 +1686,6 @@ public: string name() const override { return m_text; } string text() const { return m_text; } }; -class AstUnlinkedRef final : public AstNode { - // As-of-yet unlinkable Ref - // @astgen op1 := refp : AstNode - // @astgen op2 := cellrefp : AstNode - - string m_name; // Var name // TODO: There is no way to access this, fix or remove -public: - AstUnlinkedRef(FileLine* fl, AstNode* refp, const string& name, AstNode* cellrefp) - : ASTGEN_SUPER_UnlinkedRef(fl) - , m_name{name} { - this->refp(refp); - this->cellrefp(cellrefp); - } - ASTGEN_MEMBERS_AstUnlinkedRef; -}; class AstVar final : public AstNode { // A variable (in/out/wire/reg/param) inside a module // @@ -2593,49 +2312,6 @@ public: bool timescaleMatters() const override { return false; } }; -// === AstNodePreSel === -class AstSelBit final : public AstNodePreSel { - // Single bit range extraction, perhaps with non-constant selection or array selection - // Gets replaced during link with AstArraySel or AstSel -public: - AstSelBit(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) { - UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, - "not coded to create after dtypes resolved"); - } - ASTGEN_MEMBERS_AstSelBit; - AstNode* bitp() const { return rhsp(); } -}; -class AstSelExtract final : public AstNodePreSel { - // Range extraction, gets replaced with AstSel -public: - AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp) - : ASTGEN_SUPER_SelExtract(fl, fromp, msbp, lsbp) {} - ASTGEN_MEMBERS_AstSelExtract; - AstNode* leftp() const { return rhsp(); } - AstNode* rightp() const { return thsp(); } -}; -class AstSelMinus final : public AstNodePreSel { - // -: range extraction, perhaps with non-constant selection - // Gets replaced during link with AstSel -public: - AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) - : ASTGEN_SUPER_SelMinus(fl, fromp, bitp, widthp) {} - ASTGEN_MEMBERS_AstSelMinus; - AstNode* bitp() const { return rhsp(); } - AstNode* widthp() const { return thsp(); } -}; -class AstSelPlus final : public AstNodePreSel { - // +: range extraction, perhaps with non-constant selection - // Gets replaced during link with AstSel -public: - AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) - : ASTGEN_SUPER_SelPlus(fl, fromp, bitp, widthp) {} - ASTGEN_MEMBERS_AstSelPlus; - AstNode* bitp() const { return rhsp(); } - AstNode* widthp() const { return thsp(); } -}; - // === AstNodeProcedure === class AstAlways final : public AstNodeProcedure { // @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list iff clocked @@ -2797,70 +2473,6 @@ public: return true; // SPECIAL: We don't process code after breaks } }; -class AstCAwait final : public AstNodeStmt { - // Emit C++'s co_await statement - // @astgen op1 := exprp : AstNode - AstSenTree* m_sensesp; // Sentree related to this await -public: - AstCAwait(FileLine* fl, AstNode* exprp, AstSenTree* sensesp = nullptr) - : ASTGEN_SUPER_CAwait(fl) - , m_sensesp{sensesp} { - this->exprp(exprp); - } - ASTGEN_MEMBERS_AstCAwait; - bool isTimingControl() const override { return true; } - const char* broken() const override { - BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); - return nullptr; - } - void cloneRelink() override { - if (m_sensesp && m_sensesp->clonep()) m_sensesp = m_sensesp->clonep(); - } - void dump(std::ostream& str) const override; - AstSenTree* sensesp() const { return m_sensesp; } - void clearSensesp() { m_sensesp = nullptr; } -}; -class AstCMethodHard final : public AstNodeStmt { - // A reference to a "C" hardcoded member task (or function) - // PARENTS: stmt/math - // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. - // @astgen op1 := fromp : AstNode // Subject of method call - // @astgen op2 := pinsp : List[AstNode] // Arguments -private: - string m_name; // Name of method - bool m_pure = false; // Pure optimizable -public: - AstCMethodHard(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, - AstNode* pinsp = nullptr) - : ASTGEN_SUPER_CMethodHard(fl, false) - , m_name{name} { - // TODO: this constructor is exactly the same as the other, bar the ignored tag argument - this->fromp(fromp); - this->addPinsp(pinsp); - dtypep(nullptr); // V3Width will resolve - } - AstCMethodHard(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp = nullptr) - : ASTGEN_SUPER_CMethodHard(fl, false) - , m_name{name} { - this->fromp(fromp); - this->addPinsp(pinsp); - } - ASTGEN_MEMBERS_AstCMethodHard; - string name() const override { return m_name; } // * = Var name - bool hasDType() const override { return true; } - void name(const string& name) override { m_name = name; } - bool same(const AstNode* samep) const override { - const AstCMethodHard* asamep = static_cast(samep); - return (m_name == asamep->m_name); - } - bool isPure() const override { return m_pure; } - void pure(bool flag) { m_pure = flag; } - void makeStatement() { - statement(true); - dtypeSetVoid(); - } - int instrCount() const override; -}; class AstCReset final : public AstNodeStmt { // Reset variable at startup // @astgen op1 := varrefp : AstVarRef @@ -3448,6 +3060,16 @@ public: int instrCount() const override { return INSTR_COUNT_PLI; } bool same(const AstNode* /*samep*/) const override { return true; } }; +class AstStmtExpr final : public AstNodeStmt { + // Expression in statement position + // @astgen op1 := exprp : AstNodeExpr +public: + AstStmtExpr(FileLine* fl, AstNodeExpr* exprp) + : ASTGEN_SUPER_StmtExpr(fl) { + this->exprp(exprp); + } + ASTGEN_MEMBERS_AstStmtExpr; +}; class AstStop final : public AstNodeStmt { public: AstStop(FileLine* fl, bool maybe) @@ -3478,21 +3100,6 @@ public: int instrCount() const override { return 0; } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstSysIgnore final : public AstNodeStmt { - // @astgen op1 := exprsp : List[AstNode] // Expressions to output (???) -public: - AstSysIgnore(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_SysIgnore(fl) { - this->addExprsp(exprsp); - } - ASTGEN_MEMBERS_AstSysIgnore; - string verilogKwd() const override { return "$ignored"; } - bool isGateOptimizable() const override { return false; } // Though deleted before opt - bool isPredictOptimizable() const override { return false; } // Though deleted before opt - bool isPure() const override { return false; } // Though deleted before opt - bool isOutputter() const override { return true; } // Though deleted before opt - int instrCount() const override { return INSTR_COUNT_PLI; } -}; class AstSystemT final : public AstNodeStmt { // $system used as task // @astgen op1 := lhsp : AstNode @@ -3708,7 +3315,7 @@ class AstWith final : public AstNodeStmt { // Parents: funcref (similar to AstArg) // Children: LambdaArgRef that declares the item variable // Children: LambdaArgRef that declares the item.index variable - // Children: math (equation establishing the with) + // Children: expression (equation establishing the with) // @astgen op1 := indexArgRefp : AstLambdaArgRef // @astgen op2 := valueArgRefp : AstLambdaArgRef // @astgen op3 := exprp : AstNode @@ -3729,23 +3336,6 @@ public: return nullptr; } }; -class AstWithParse final : public AstNodeStmt { - // In early parse, FUNC(index) WITH equation-using-index - // Replaced with AstWith - // Parents: math|stmt - // Children: funcref, math - // @astgen op1 := funcrefp : AstNode - // @astgen op2 := exprp : Optional[AstNode] -public: - AstWithParse(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* exprp) - : ASTGEN_SUPER_WithParse(fl) { - statement(stmt); - this->funcrefp(funcrefp); - this->exprp(exprp); - } - ASTGEN_MEMBERS_AstWithParse; - bool same(const AstNode* /*samep*/) const override { return true; } -}; // === AstNodeAssign === class AstAssign final : public AstNodeAssign { @@ -3850,52 +3440,6 @@ public: AstAlways* convertToAlways(); }; -// === AstNodeCCall === -class AstCCall final : public AstNodeCCall { - // C++ function call - // Parents: Anything above a statement - // Children: Args to the function - - string m_selfPointer; // Output code object pointer (e.g.: 'this') - -public: - AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER_CCall(fl, funcp, argsp) {} - ASTGEN_MEMBERS_AstCCall; - - string selfPointer() const { return m_selfPointer; } - void selfPointer(const string& value) { m_selfPointer = value; } - string selfPointerProtect(bool useSelfForThis) const; -}; -class AstCMethodCall final : public AstNodeCCall { - // C++ method call - // Parents: Anything above a statement - // @astgen op1 := fromp : AstNode -public: - AstCMethodCall(FileLine* fl, AstNode* fromp, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER_CMethodCall(fl, funcp, argsp) { - this->fromp(fromp); - } - ASTGEN_MEMBERS_AstCMethodCall; - const char* broken() const override { - BROKEN_BASE_RTN(AstNodeCCall::broken()); - BROKEN_RTN(!fromp()); - return nullptr; - } -}; -class AstCNew final : public AstNodeCCall { - // C++ new() call - // Parents: Anything above an expression - // Children: Args to the function -public: - AstCNew(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER_CNew(fl, funcp, argsp) { - statement(false); - } - bool hasDType() const override { return true; } - ASTGEN_MEMBERS_AstCNew; -}; - // === AstNodeCase === class AstCase final : public AstNodeCase { // Case statement @@ -3979,74 +3523,6 @@ public: : ASTGEN_SUPER_Restrict(fl, propp, nullptr, false, "") {} }; -// === AstNodeFTaskRef === -class AstFuncRef final : public AstNodeFTaskRef { - // A reference to a function -public: - AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) - : ASTGEN_SUPER_FuncRef(fl, false, namep, pinsp) {} - AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp) - : ASTGEN_SUPER_FuncRef(fl, false, name, pinsp) {} - ASTGEN_MEMBERS_AstFuncRef; - bool hasDType() const override { return true; } -}; -class AstMethodCall final : public AstNodeFTaskRef { - // A reference to a member task (or function) - // PARENTS: stmt/math - // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. - // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it - // @astgen op2 := fromp : AstNode - // -public: - AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, - AstNode* pinsp) - : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { - this->fromp(fromp); - dtypep(nullptr); // V3Width will resolve - } - AstMethodCall(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp) - : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { - this->fromp(fromp); - } - ASTGEN_MEMBERS_AstMethodCall; - const char* broken() const override { - BROKEN_BASE_RTN(AstNodeFTaskRef::broken()); - BROKEN_RTN(!fromp()); - return nullptr; - } - void dump(std::ostream& str) const override; - bool hasDType() const override { return true; } - void makeStatement() { - statement(true); - dtypeSetVoid(); - } -}; -class AstNew final : public AstNodeFTaskRef { - // New as constructor - // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it - // Parents: math|stmt - // Children: varref|arraysel, math -public: - AstNew(FileLine* fl, AstNode* pinsp) - : ASTGEN_SUPER_New(fl, false, "new", pinsp) {} - ASTGEN_MEMBERS_AstNew; - virtual bool cleanOut() const { return true; } - bool same(const AstNode* /*samep*/) const override { return true; } - bool hasDType() const override { return true; } - int instrCount() const override { return widthInstrs(); } -}; -class AstTaskRef final : public AstNodeFTaskRef { - // A reference to a task -public: - AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) - : ASTGEN_SUPER_TaskRef(fl, true, namep, pinsp) { - statement(true); - } - AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp) - : ASTGEN_SUPER_TaskRef(fl, true, name, pinsp) {} - ASTGEN_MEMBERS_AstTaskRef; -}; - // === AstNodeFor === class AstGenFor final : public AstNodeFor { public: diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 3487e1814..9f6dde5b0 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -60,6 +60,8 @@ void AstNodeFTaskRef::cloneRelink() { } } +bool AstNodeFTaskRef::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); } + const char* AstNodeVarRef::broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists()); @@ -123,7 +125,7 @@ const char* AstNodeUOrStructDType::broken() const { void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); } void AstNodeCCall::dump(std::ostream& str) const { - this->AstNodeStmt::dump(str); + this->AstNodeExpr::dump(str); if (funcp()) { str << " " << funcp()->name() << " => "; funcp()->dump(str); @@ -1376,8 +1378,8 @@ string AstBasicDType::prettyDTypeName() const { return os.str(); } -void AstNodeMath::dump(std::ostream& str) const { this->AstNode::dump(str); } -void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); } +void AstNodeExpr::dump(std::ostream& str) const { this->AstNode::dump(str); } +void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); } void AstCCast::dump(std::ostream& str) const { this->AstNodeUniop::dump(str); @@ -1504,7 +1506,7 @@ void AstDisplay::dump(std::ostream& str) const { // str << " " << displayType().ascii(); } void AstEnumItemRef::dump(std::ostream& str) const { - this->AstNodeMath::dump(str); + this->AstNodeExpr::dump(str); str << " -> "; if (itemp()) { itemp()->dump(str); @@ -1615,11 +1617,11 @@ void AstJumpLabel::dump(std::ostream& str) const { } } void AstLogOr::dump(std::ostream& str) const { - this->AstNodeMath::dump(str); + this->AstNodeExpr::dump(str); if (sideEffect()) str << " [SIDE]"; } void AstMemberSel::dump(std::ostream& str) const { - this->AstNodeMath::dump(str); + this->AstNodeExpr::dump(str); str << " -> "; if (varp()) { varp()->dump(str); @@ -1636,7 +1638,6 @@ const char* AstMemberSel::broken() const { } void AstMethodCall::dump(std::ostream& str) const { this->AstNodeFTaskRef::dump(str); - if (isStatement()) str << " [STMT]"; str << " -> "; if (taskp()) { taskp()->dump(str); @@ -1705,7 +1706,7 @@ void AstPrintTimeScale::dump(std::ostream& str) const { str << " " << timeunit(); } -void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); } +void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); } void AstTime::dump(std::ostream& str) const { this->AstNodeTermop::dump(str); str << " " << timeunit(); @@ -1908,10 +1909,10 @@ void AstPackageImport::cloneRelink() { if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); } void AstPatMember::dump(std::ostream& str) const { - this->AstNodeMath::dump(str); + this->AstNodeExpr::dump(str); if (isDefault()) str << " [DEFAULT]"; } -void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); } +void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); } void AstSel::dump(std::ostream& str) const { this->AstNodeTriop::dump(str); if (declRange().ranged()) { @@ -2018,7 +2019,7 @@ void AstVarScope::dump(std::ostream& str) const { } } void AstNodeVarRef::dump(std::ostream& str) const { - this->AstNodeMath::dump(str); + this->AstNodeExpr::dump(str); if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); str << " " << access().arrow() << " "; } @@ -2086,7 +2087,7 @@ void AstScope::dump(std::ostream& str) const { str << " [modp=" << reinterpret_cast(modp()) << "]"; } void AstScopeName::dump(std::ostream& str) const { - this->AstNodeMath::dump(str); + this->AstNodeExpr::dump(str); if (dpiExport()) str << " [DPIEX]"; if (forFormat()) str << " [FMT]"; } @@ -2145,7 +2146,7 @@ void AstActive::cloneRelink() { if (m_sensesp->clonep()) m_sensesp = m_sensesp->clonep(); } void AstNodeFTaskRef::dump(std::ostream& str) const { - this->AstNodeStmt::dump(str); + this->AstNodeExpr::dump(str); if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); str << " -> "; if (dotted() != "") str << ".=" << dotted() << " "; @@ -2248,8 +2249,15 @@ void AstCFunc::dump(std::ostream& str) const { if (isVirtual()) str << " [VIRT]"; if (isCoroutine()) str << " [CORO]"; } +const char* AstCAwait::broken() const { + BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); + return nullptr; +} +void AstCAwait::cloneRelink() { + if (m_sensesp && m_sensesp->clonep()) m_sensesp = m_sensesp->clonep(); +} void AstCAwait::dump(std::ostream& str) const { - this->AstNodeStmt::dump(str); + this->AstNodeUniop::dump(str); if (sensesp()) { str << " => "; sensesp()->dump(str); @@ -2265,7 +2273,7 @@ int AstCMethodHard::instrCount() const { return INSTR_COUNT_LD; } } - return AstNodeStmt::instrCount(); + return 0; } const char* AstCFunc::broken() const { BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 2dbc74121..f1e5b1bca 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -112,13 +112,14 @@ public: rootFuncp->name(m_basename); for (AstCFunc* const funcp : m_newFunctions) { AstCCall* const callp = new AstCCall{m_modp->fileline(), funcp}; + callp->dtypeSetVoid(); if (m_type.isClass()) { callp->argTypes("vlSymsp"); } else { if (m_type.isCoverage()) callp->argTypes("first"); callp->selfPointer("this"); } - rootFuncp->addStmtsp(callp); + rootFuncp->addStmtsp(callp->makeStmt()); } } } diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index 8f7c303e3..0db4e7578 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -16,9 +16,9 @@ // V3Cast's Transformations: // // Each module: -// For each math operator, if above operator requires 32 bits, +// For each expression, if above expression requires 32 bits, // and this isn't, cast to 32 bits. -// Likewise for 64 bit operators. +// Likewise for 64 bit expressions. // // C++ rules: // Integral promotions allow conversion to larger int. Unsigned is only @@ -158,7 +158,8 @@ private: } void visit(AstVarRef* nodep) override { const AstNode* const backp = nodep->backp(); - if (nodep->access().isReadOnly() && !VN_IS(backp, CCast) && VN_IS(backp, NodeMath) + if (nodep->access().isReadOnly() && VN_IS(backp, NodeExpr) && !VN_IS(backp, CCast) + && !VN_IS(backp, NodeCCall) && !VN_IS(backp, CMethodHard) && !VN_IS(backp, SFormatF) && !VN_IS(backp, ArraySel) && !VN_IS(backp, RedXor) && (nodep->varp()->basicp() && !nodep->varp()->basicp()->isTriggerVec() && !nodep->varp()->basicp()->isForkSync()) diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index 163a34002..0bd371111 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -697,7 +697,7 @@ private: void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); } void visit(AstAssignW* nodep) override { iterateNewStmt(nodep); } - // Math that shouldn't cause us to clear hazard + // Expressions that shouldn't cause us to clear hazard void visit(AstConst*) override {} void visit(AstReplicate* nodep) override { iterateChildren(nodep); } void visit(AstConcat* nodep) override { iterateChildren(nodep); } @@ -721,7 +721,7 @@ private: //-------------------- // Default - void visit(AstNodeMath* nodep) override { + void visit(AstNodeExpr* nodep) override { setNodeHazard(nodep); iterateChildren(nodep); } diff --git a/src/V3Class.cpp b/src/V3Class.cpp index 810fe95d7..88cae1fc9 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -166,7 +166,7 @@ private: } } - void visit(AstNodeMath* nodep) override {} // Short circuit + void visit(AstNodeExpr* nodep) override {} // Short circuit void visit(AstNodeStmt* nodep) override {} // Short circuit void visit(AstNode* nodep) override { iterateChildren(nodep); } diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index cd9c96d7d..db31e87fb 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -16,7 +16,7 @@ // V3Clean's Transformations: // // Each module: -// For each math operator, if it requires a clean operand, +// For each expression, if it requires a clean operand, // and the operand is dirty, insert a CLEAN node. // Resize operands to C++ 32/64/wide types. // Copy all width() values to widthMin() so RANGE, etc can still see orig widths @@ -207,7 +207,7 @@ private: operandQuadop(nodep); setClean(nodep, nodep->cleanOut()); } - void visit(AstNodeMath* nodep) override { + void visit(AstNodeExpr* nodep) override { iterateChildren(nodep); computeCppWidth(nodep); setClean(nodep, nodep->cleanOut()); diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index 7d61aae35..ee19f0eef 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -69,7 +69,9 @@ class CombineVisitor final : VNVisitor { if (funcp->emptyBody()) { // Delete call sites for (AstCCall* const callp : m_callSites(funcp)) { - VL_DO_DANGLING(callp->unlinkFrBack()->deleteTree(), callp); + UASSERT_OBJ(VN_IS(callp->backp(), StmtExpr), callp, + "Deleting non-statement call"); + VL_DO_DANGLING(callp->backp()->unlinkFrBack()->deleteTree(), callp); } m_callSites(funcp).clear(); // Remove from list diff --git a/src/V3Common.cpp b/src/V3Common.cpp index 907c5a33d..9df1abc8a 100644 --- a/src/V3Common.cpp +++ b/src/V3Common.cpp @@ -42,7 +42,7 @@ static void makeVlToString(AstClass* nodep) { funcp->isConst(false); funcp->isStatic(false); funcp->protect(false); - AstNode* const exprp = new AstCMath{nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0}; + AstNode* const exprp = new AstCExpr{nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0}; exprp->dtypeSetString(); funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); nodep->addStmtsp(funcp); @@ -55,7 +55,7 @@ static void makeVlToString(AstIface* nodep) { funcp->isConst(false); funcp->isStatic(false); funcp->protect(false); - AstNode* const exprp = new AstCMath{nodep->fileline(), "obj ? obj->name() : \"null\"", 0}; + AstNode* const exprp = new AstCExpr{nodep->fileline(), "obj ? obj->name() : \"null\"", 0}; exprp->dtypeSetString(); funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); nodep->addStmtsp(funcp); @@ -66,7 +66,7 @@ static void makeToString(AstClass* nodep) { funcp->isStatic(false); funcp->protect(false); AstNode* const exprp - = new AstCMath{nodep->fileline(), R"(std::string{"'{"} + to_string_middle() + "}")", 0}; + = new AstCExpr{nodep->fileline(), R"(std::string{"'{"} + to_string_middle() + "}")", 0}; exprp->dtypeSetString(); funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); nodep->addStmtsp(funcp); diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 9d1b7f7f8..3f75f93ae 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2602,6 +2602,10 @@ private: } m_selp = nullptr; } + void visit(AstCAwait* nodep) override { + m_hasJumpDelay = true; + iterateChildren(nodep); + } void visit(AstNodeVarRef* nodep) override { iterateChildren(nodep); UASSERT_OBJ(nodep->varp(), nodep, "Not linked"); @@ -2682,7 +2686,7 @@ private: } // void visit(AstCvtPackString* nodep) override { - // Not constant propagated (for today) because AstNodeMath::isOpaque is set + // Not constant propagated (for today) because AstNodeExpr::isOpaque is set // Someday if lower is constant, convert to quoted "string". bool onlySenItemInSenTree(AstSenItem* nodep) { @@ -3166,6 +3170,11 @@ private: if (m_doNConst) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } + void visit(AstStmtExpr* nodep) override { + iterateChildren(nodep); + if (!nodep->exprp()) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + } + // Simplify void visit(AstBasicDType* nodep) override { iterateChildren(nodep); @@ -3232,6 +3241,7 @@ private: //----- // clang-format off TREE_SKIP_VISIT("ArraySel"); + TREE_SKIP_VISIT("CAwait"); //----- // "AstNODETYPE { # bracket not paren diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp index d5571a7a7..8e1b6cc6d 100644 --- a/src/V3CoverageJoin.cpp +++ b/src/V3CoverageJoin.cpp @@ -100,7 +100,7 @@ private: iterateChildren(nodep); } //-------------------- - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index c7012c72b..56f67b57d 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -485,9 +485,8 @@ private: AstIf* const ifp = new AstIf{flp, dlyRef(VAccess::READ)}; postp->addStmtsp(ifp); AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "fire"}; - callp->statement(true); callp->dtypeSetVoid(); - ifp->addThensp(callp); + ifp->addThensp(callp->makeStmt()); } AstActive* const activep = createActive(nodep); @@ -501,8 +500,7 @@ private: AstCMethodHard* const callp = new AstCMethodHard{flp, nodep->operandp()->unlinkFrBack(), "fire"}; callp->dtypeSetVoid(); - callp->statement(true); - nodep->replaceWith(callp); + nodep->replaceWith(callp->makeStmt()); } nodep->deleteTree(); } diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index 489d36b7d..fa1c31ea5 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -107,16 +107,10 @@ private: iterateChildren(nodep); } } - void visit(AstNodeStmt* nodep) override { - if (!nodep->isStatement()) { - iterateChildren(nodep); - } else { - visitStmt(nodep); - } - } + void visit(AstNodeStmt* nodep) override { visitStmt(nodep); } // Operators void visit(AstNodeTermop* nodep) override {} - void visit(AstNodeMath* nodep) override { + void visit(AstNodeExpr* nodep) override { // We have some operator defines that use 2 parens, so += 2. { VL_RESTORER(m_depth); diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp index 9399e78e0..69497def3 100644 --- a/src/V3DepthBlock.cpp +++ b/src/V3DepthBlock.cpp @@ -47,7 +47,7 @@ private: // METHODS - AstCFunc* createDeepFunc(AstNode* nodep) { + AstCFunc* createDeepFunc(AstNodeStmt* nodep) { VNRelinker relinkHandle; nodep->unlinkFrBack(&relinkHandle); // Create sub function @@ -61,12 +61,13 @@ private: scopep->addBlocksp(funcp); // Call sub function at the point where the body was removed from AstCCall* const callp = new AstCCall(nodep->fileline(), funcp); + callp->dtypeSetVoid(); if (VN_IS(m_modp, Class)) { funcp->argTypes(EmitCBaseVisitor::symClassVar()); callp->argTypes("vlSymsp"); } UINFO(6, " New " << callp << endl); - relinkHandle.relink(callp); + relinkHandle.relink(callp->makeStmt()); // Done return funcp; } @@ -91,10 +92,10 @@ private: iterateChildren(nodep); } } - void visitStmt(AstNodeStmt* nodep) { + void visit(AstStmtExpr* nodep) override {} // Stop recursion after introducing new function + void visit(AstNodeStmt* nodep) override { m_depth++; - if (m_depth > v3Global.opt.compLimitBlocks() - && !VN_IS(nodep, NodeCCall)) { // Already done + if (m_depth > v3Global.opt.compLimitBlocks()) { // Already done UINFO(4, "DeepBlocks " << m_depth << " " << nodep << endl); const AstNode* const backp = nodep->backp(); // Only for debug if (debug() >= 9) backp->dumpTree(cout, "- pre : "); @@ -107,15 +108,8 @@ private: } m_depth--; } - void visit(AstNodeStmt* nodep) override { - if (!nodep->isStatement()) { - iterateChildren(nodep); - } else { - visitStmt(nodep); - } - } - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate //-------------------- void visit(AstVar*) override {} // Don't hit varrefs under vars void visit(AstNode* nodep) override { iterateChildren(nodep); } diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 10ab9b2ff..07f985362 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -152,15 +152,20 @@ private: } } - AstNode* const returnp = new AstCReturn( - funcp->fileline(), new AstCCall(funcp->fileline(), funcp, argsp)); + AstCCall* const callp = new AstCCall{funcp->fileline(), funcp, argsp}; + if (AstNodeDType* const dtypep = funcp->dtypep()) { + callp->dtypep(dtypep); + } else { + callp->dtypeSetVoid(); + } + AstNode* const returnp = new AstCReturn{funcp->fileline(), callp}; if (moreOfSame) { AstIf* const ifp = new AstIf( funcp->fileline(), new AstEq( - funcp->fileline(), new AstCMath(funcp->fileline(), "this", 64), - new AstCMath(funcp->fileline(), + funcp->fileline(), new AstCExpr(funcp->fileline(), "this", 64), + new AstCExpr(funcp->fileline(), string("&(") + funcp->scopep()->nameVlSym() + ")", 64)), returnp); diff --git a/src/V3Dfg.h b/src/V3Dfg.h index a81f0cea5..f49110296 100644 --- a/src/V3Dfg.h +++ b/src/V3Dfg.h @@ -870,7 +870,7 @@ public: // DfgVertex subclasses #include "V3DfgVertices.h" -// The rest of the DfgVertex subclasses are generated by 'astgen' from AstNodeMath nodes +// The rest of the DfgVertex subclasses are generated by 'astgen' from AstNodeExpr nodes #include "V3Dfg__gen_auto_classes.h" DfgVertexVar* DfgGraph::varVerticesBeginp() const { diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp index b494c81dc..d81ecbfb3 100644 --- a/src/V3DfgAstToDfg.cpp +++ b/src/V3DfgAstToDfg.cpp @@ -39,7 +39,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; namespace { -// Create a DfgVertex out of a AstNodeMath. For most AstNodeMath subtypes, this can be done +// Create a DfgVertex out of a AstNodeExpr. For most AstNodeExpr subtypes, this can be done // automatically. For the few special cases, we provide specializations below template Vertex* makeVertex(const Node* nodep, DfgGraph& dfg) { @@ -132,7 +132,7 @@ class AstToDfgVisitor final : public VNVisitor { } // Returns true if the expression cannot (or should not) be represented by DFG - bool unhandled(AstNodeMath* nodep) { + bool unhandled(AstNodeExpr* nodep) { // Short-circuiting if something was already unhandled if (!m_foundUnhandled) { // Impure nodes cannot be represented diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp index 1ac43d319..f87c443c8 100644 --- a/src/V3DfgDfgToAst.cpp +++ b/src/V3DfgDfgToAst.cpp @@ -14,7 +14,7 @@ // //************************************************************************* // -// Convert DfgGraph back to AstModule. We recursively construct AstNodeMath expressions for each +// Convert DfgGraph back to AstModule. We recursively construct AstNodeExpr expressions for each // DfgVertex which represents a storage location (e.g.: DfgVarPacked), or has multiple sinks // without driving a storage location (and hence needs a temporary variable to duplication). The // recursion stops when we reach a DfgVertex representing a storage location (e.g.: DfgVarPacked), @@ -40,7 +40,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; namespace { -// Create an AstNodeMath out of a DfgVertex. For most AstNodeMath subtypes, this can be done +// Create an AstNodeExpr out of a DfgVertex. For most AstNodeExpr subtypes, this can be done // automatically. For the few special cases, we provide specializations below template Node* makeNode(const Vertex* vtxp, Ops... ops) { @@ -55,8 +55,8 @@ Node* makeNode(const Vertex* vtxp, Ops... ops) { // Vertices needing special conversion template <> -AstCountOnes* makeNode( // - const DfgCountOnes* vtxp, AstNodeMath* op1) { +AstCountOnes* makeNode( // + const DfgCountOnes* vtxp, AstNodeExpr* op1) { AstCountOnes* const nodep = new AstCountOnes{vtxp->fileline(), op1}; // Set dtype same as V3Width const int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1; @@ -65,32 +65,32 @@ AstCountOnes* makeNode( // } template <> -AstExtend* makeNode( // - const DfgExtend* vtxp, AstNodeMath* op1) { +AstExtend* makeNode( // + const DfgExtend* vtxp, AstNodeExpr* op1) { return new AstExtend{vtxp->fileline(), op1, static_cast(vtxp->width())}; } template <> -AstExtendS* makeNode( // - const DfgExtendS* vtxp, AstNodeMath* op1) { +AstExtendS* makeNode( // + const DfgExtendS* vtxp, AstNodeExpr* op1) { return new AstExtendS{vtxp->fileline(), op1, static_cast(vtxp->width())}; } template <> -AstShiftL* makeNode( // - const DfgShiftL* vtxp, AstNodeMath* op1, AstNodeMath* op2) { +AstShiftL* makeNode( // + const DfgShiftL* vtxp, AstNodeExpr* op1, AstNodeExpr* op2) { return new AstShiftL{vtxp->fileline(), op1, op2, static_cast(vtxp->width())}; } template <> -AstShiftR* makeNode( // - const DfgShiftR* vtxp, AstNodeMath* op1, AstNodeMath* op2) { +AstShiftR* makeNode( // + const DfgShiftR* vtxp, AstNodeExpr* op1, AstNodeExpr* op2) { return new AstShiftR{vtxp->fileline(), op1, op2, static_cast(vtxp->width())}; } template <> -AstShiftRS* makeNode( // - const DfgShiftRS* vtxp, AstNodeMath* op1, AstNodeMath* op2) { +AstShiftRS* makeNode( // + const DfgShiftRS* vtxp, AstNodeExpr* op1, AstNodeExpr* op2) { return new AstShiftRS{vtxp->fileline(), op1, op2, static_cast(vtxp->width())}; } @@ -98,22 +98,22 @@ AstShiftRS* makeNode( // // Currently unhandled nodes - see corresponding AstToDfg functions // LCOV_EXCL_START template <> -AstCCast* makeNode(const DfgCCast* vtxp, AstNodeMath*) { +AstCCast* makeNode(const DfgCCast* vtxp, AstNodeExpr*) { vtxp->v3fatalSrc("not implemented"); } template <> -AstAtoN* makeNode(const DfgAtoN* vtxp, AstNodeMath*) { +AstAtoN* makeNode(const DfgAtoN* vtxp, AstNodeExpr*) { vtxp->v3fatalSrc("not implemented"); } template <> AstCompareNN* -makeNode(const DfgCompareNN* vtxp, - AstNodeMath*, AstNodeMath*) { +makeNode(const DfgCompareNN* vtxp, + AstNodeExpr*, AstNodeExpr*) { vtxp->v3fatalSrc("not implemented"); } template <> -AstSliceSel* makeNode( - const DfgSliceSel* vtxp, AstNodeMath*, AstNodeMath*, AstNodeMath*) { +AstSliceSel* makeNode( + const DfgSliceSel* vtxp, AstNodeExpr*, AstNodeExpr*, AstNodeExpr*) { vtxp->v3fatalSrc("not implemented"); } // LCOV_EXCL_STOP @@ -130,7 +130,7 @@ class DfgToAstVisitor final : DfgVisitor { AstModule* const m_modp; // The parent/result module V3DfgOptimizationContext& m_ctx; // The optimization context for stats - AstNodeMath* m_resultp = nullptr; // The result node of the current traversal + AstNodeExpr* m_resultp = nullptr; // The result node of the current traversal // Map from DfgVertex to the AstVar holding the value of that DfgVertex after conversion std::unordered_map m_resultVars; // Map from an AstVar, to the canonical AstVar that can be substituted for that AstVar @@ -212,11 +212,11 @@ class DfgToAstVisitor final : DfgVisitor { return varp; } - AstNodeMath* convertDfgVertexToAstNodeMath(DfgVertex* vtxp) { + AstNodeExpr* convertDfgVertexToAstNodeExpr(DfgVertex* vtxp) { UASSERT_OBJ(!m_resultp, vtxp, "Result already computed"); iterate(vtxp); UASSERT_OBJ(m_resultp, vtxp, "Missing result"); - AstNodeMath* const resultp = m_resultp; + AstNodeExpr* const resultp = m_resultp; m_resultp = nullptr; return resultp; } @@ -232,11 +232,11 @@ class DfgToAstVisitor final : DfgVisitor { return false; } - AstNodeMath* convertSource(DfgVertex* vtxp) { + AstNodeExpr* convertSource(DfgVertex* vtxp) { if (inlineVertex(*vtxp)) { // Inlined vertices are simply recursively converted UASSERT_OBJ(vtxp->hasSinks(), vtxp, "Must have one sink: " << vtxp->typeName()); - return convertDfgVertexToAstNodeMath(vtxp); + return convertDfgVertexToAstNodeExpr(vtxp); } else { // Vertices that are not inlined need a variable, just return a reference return new AstVarRef{vtxp->fileline(), getResultVar(vtxp), VAccess::READ}; @@ -249,14 +249,14 @@ class DfgToAstVisitor final : DfgVisitor { }; if (dfgVarp->isDrivenFullyByDfg()) { // Whole variable is driven. Render driver and assign directly to whole variable. - AstNodeMath* const rhsp = convertDfgVertexToAstNodeMath(dfgVarp->source(0)); + AstNodeExpr* const rhsp = convertDfgVertexToAstNodeExpr(dfgVarp->source(0)); addResultEquation(dfgVarp->driverFileLine(0), wRef(), rhsp); } else { // Variable is driven partially. Render each driver as a separate assignment. dfgVarp->forEachSourceEdge([&](const DfgEdge& edge, size_t idx) { UASSERT_OBJ(edge.sourcep(), dfgVarp, "Should have removed undriven sources"); // Render the rhs expression - AstNodeMath* const rhsp = convertDfgVertexToAstNodeMath(edge.sourcep()); + AstNodeExpr* const rhsp = convertDfgVertexToAstNodeExpr(edge.sourcep()); // Create select LValue FileLine* const flp = dfgVarp->driverFileLine(idx); AstConst* const lsbp = new AstConst{flp, dfgVarp->driverLsb(idx)}; @@ -299,7 +299,7 @@ class DfgToAstVisitor final : DfgVisitor { dfgVarp->forEachSourceEdge([&](const DfgEdge& edge, size_t idx) { UASSERT_OBJ(edge.sourcep(), dfgVarp, "Should have removed undriven sources"); // Render the rhs expression - AstNodeMath* const rhsp = convertDfgVertexToAstNodeMath(edge.sourcep()); + AstNodeExpr* const rhsp = convertDfgVertexToAstNodeExpr(edge.sourcep()); // Create select LValue FileLine* const flp = dfgVarp->driverFileLine(idx); AstVarRef* const refp = new AstVarRef{flp, dfgVarp->varp(), VAccess::WRITE}; @@ -334,7 +334,7 @@ class DfgToAstVisitor final : DfgVisitor { void visit(DfgSel* vtxp) override { FileLine* const flp = vtxp->fileline(); - AstNodeMath* const fromp = convertSource(vtxp->fromp()); + AstNodeExpr* const fromp = convertSource(vtxp->fromp()); AstConst* const lsbp = new AstConst{flp, vtxp->lsb()}; AstConst* const widthp = new AstConst{flp, vtxp->width()}; m_resultp = new AstSel{flp, fromp, lsbp, widthp}; @@ -342,8 +342,8 @@ class DfgToAstVisitor final : DfgVisitor { void visit(DfgMux* vtxp) override { FileLine* const flp = vtxp->fileline(); - AstNodeMath* const fromp = convertSource(vtxp->fromp()); - AstNodeMath* const lsbp = convertSource(vtxp->lsbp()); + AstNodeExpr* const fromp = convertSource(vtxp->fromp()); + AstNodeExpr* const lsbp = convertSource(vtxp->lsbp()); AstConst* const widthp = new AstConst{flp, vtxp->width()}; m_resultp = new AstSel{flp, fromp, lsbp, widthp}; } @@ -415,9 +415,9 @@ class DfgToAstVisitor final : DfgVisitor { ++m_ctx.m_intermediateVars; FileLine* const flp = vtxp->fileline(); // Just render the logic - AstNodeMath* const rhsp = convertDfgVertexToAstNodeMath(vtxp); + AstNodeExpr* const rhsp = convertDfgVertexToAstNodeExpr(vtxp); // The lhs is the temporary - AstNodeMath* const lhsp = new AstVarRef{flp, resultVarp, VAccess::WRITE}; + AstNodeExpr* const lhsp = new AstVarRef{flp, resultVarp, VAccess::WRITE}; // Add assignment of the value to the variable addResultEquation(flp, lhsp, rhsp); } diff --git a/src/V3DfgOptimizer.cpp b/src/V3DfgOptimizer.cpp index b162f6819..f093b453d 100644 --- a/src/V3DfgOptimizer.cpp +++ b/src/V3DfgOptimizer.cpp @@ -47,7 +47,7 @@ class DataflowExtractVisitor final : public VNVisitor { // Expressions considered for extraction as separate assignment to gain more opportunities for // optimization, together with the list of variables they read. - using Candidates = std::vector>>; + using Candidates = std::vector>>; // Expressions considered for extraction. All the candidates are pure expressions. AstUser4Allocator m_extractionCandidates; @@ -65,7 +65,7 @@ class DataflowExtractVisitor final : public VNVisitor { // Node considered for extraction as a combinational equation. Trace variable usage/purity. void iterateExtractionCandidate(AstNode* nodep) { - UASSERT_OBJ(!VN_IS(nodep->backp(), NodeMath), nodep, + UASSERT_OBJ(!VN_IS(nodep->backp(), NodeExpr), nodep, "Should not try to extract nested expressions (only root expressions)"); // Simple VarRefs should not be extracted, as they only yield trivial assignments. @@ -93,7 +93,7 @@ class DataflowExtractVisitor final : public VNVisitor { if (m_readVars.empty()) return; // Add to candidate list - m_candidatesp->emplace_back(VN_AS(nodep, NodeMath), std::move(m_readVars)); + m_candidatesp->emplace_back(VN_AS(nodep, NodeExpr), std::move(m_readVars)); } // VISIT methods @@ -110,7 +110,7 @@ class DataflowExtractVisitor final : public VNVisitor { if (!VN_IS(modp, Module)) continue; for (const auto& pair : m_extractionCandidates(modp)) { - AstNodeMath* const nodep = pair.first; + AstNodeExpr* const nodep = pair.first; // Do not extract expressions without any variable references if (pair.second.empty()) continue; @@ -204,7 +204,7 @@ class DataflowExtractVisitor final : public VNVisitor { m_inForceReleaseLhs = false; } - void visit(AstNodeMath* nodep) override { iterateChildrenConst(nodep); } + void visit(AstNodeExpr* nodep) override { iterateChildrenConst(nodep); } void visit(AstNodeVarRef* nodep) override { if (nodep->access().isWriteOrRW()) { @@ -220,7 +220,7 @@ class DataflowExtractVisitor final : public VNVisitor { void visit(AstNode* nodep) override { // Conservatively assume unhandled nodes are impure. This covers all AstNodeFTaskRef - // as AstNodeFTaskRef are sadly not AstNodeMath. + // as AstNodeFTaskRef are sadly not AstNodeExpr. m_impure = true; // Still need to gather all references/force/release, etc. iterateChildrenConst(nodep); diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index f81998976..059e64c65 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -32,7 +32,7 @@ constexpr int VL_VALUE_STRING_MAX_WIDTH = 8192; //###################################################################### // EmitCFunc -bool EmitCFunc::emitSimpleOk(AstNodeMath* nodep) { +bool EmitCFunc::emitSimpleOk(AstNodeExpr* nodep) { // Can we put out a simple (A + B) instead of VL_ADD_III(A,B)? if (nodep->emitSimpleOperator() == "") return false; if (nodep->isWide()) return false; @@ -433,12 +433,7 @@ void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPoint iterate(subnodep); comma = true; } - if (VN_IS(nodep->backp(), NodeMath) || VN_IS(nodep->backp(), CReturn)) { - // We should have a separate CCall for math and statement usage, but... - puts(")"); - } else { - puts(");\n"); - } + puts(")"); } void EmitCFunc::emitDereference(const string& pointer) { diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index c91ef4174..45f863d21 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -110,15 +110,15 @@ public: void reset() { m_emitted.clear(); } }; -//###################################################################### -// Emit statements and math operators +// ###################################################################### +// Emit statements and expressions class EmitCFunc VL_NOT_FINAL : public EmitCConstInit { private: AstVarRef* m_wideTempRefp = nullptr; // Variable that _WW macros should be setting int m_labelNum = 0; // Next label number int m_splitSize = 0; // # of cfunc nodes placed into output file - bool m_inUC = false; // Inside an AstUCStmt or AstUCMath + bool m_inUC = false; // Inside an AstUCStmt or AstUCExpr bool m_emitConstInit = false; // Emitting constant initializer // State associated with processing $display style string formatting @@ -167,7 +167,7 @@ public: void displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const string& vfmt, bool ignore, char fmtLetter); - bool emitSimpleOk(AstNodeMath* nodep); + bool emitSimpleOk(AstNodeExpr* nodep); void emitIQW(AstNode* nodep) { // Other abbrevs: "C"har, "S"hort, "F"loat, "D"ouble, stri"N"g puts(nodep->dtypep()->charIQWN()); @@ -330,7 +330,7 @@ public: iterateAndNextNull(nodep->lhsp()); puts(", "); } else if (nodep->isWide() && VN_IS(nodep->lhsp(), VarRef) // - && !VN_IS(nodep->rhsp(), CMath) // + && !VN_IS(nodep->rhsp(), CExpr) // && !VN_IS(nodep->rhsp(), CMethodHard) // && !VN_IS(nodep->rhsp(), VarRef) // && !VN_IS(nodep->rhsp(), AssocSel) // @@ -415,7 +415,6 @@ public: void visit(AstCAwait* nodep) override { puts("co_await "); iterate(nodep->exprp()); - if (nodep->isStatement()) puts(";\n"); } void visit(AstCNew* nodep) override { bool comma = false; @@ -446,10 +445,6 @@ public: comma = true; } puts(")"); - // Some are statements some are math. - if (nodep->isStatement()) puts(";\n"); - UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep, - "Statement of non-void data type"); } void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); } void visit(AstWith* nodep) override { @@ -804,6 +799,10 @@ public: iterateAndNextNull(nodep->lhsp()); puts(")"); } + void visit(AstStmtExpr* node) override { + iterate(node->exprp()); + puts(";\n"); + } void visit(AstJumpBlock* nodep) override { nodep->labelNum(++m_labelNum); puts("{\n"); // Make it visually obvious label jumps outside these @@ -931,7 +930,7 @@ public: putbs(""); iterateAndNextNull(nodep->exprsp()); } - void visit(AstCMath* nodep) override { + void visit(AstCExpr* nodep) override { putbs(""); iterateAndNextNull(nodep->exprsp()); } diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 2d00e01a9..163e408ba 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -26,8 +26,8 @@ VL_DEFINE_DEBUG_FUNCTIONS; -//###################################################################### -// Emit statements and math operators +// ###################################################################### +// Emit statements and expressions class EmitMk final { public: diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 3b2d6a3fd..02f658334 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -28,8 +28,8 @@ VL_DEFINE_DEBUG_FUNCTIONS; -//###################################################################### -// Emit statements and math operators +// ###################################################################### +// Emit statements and expressions class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { // MEMBERS @@ -381,6 +381,10 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } void visit(AstStop* nodep) override { putfs(nodep, "$stop;\n"); } void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\n"); } + void visit(AstStmtExpr* nodep) override { + iterate(nodep->exprp()); + puts(";\n"); + } void visit(AstNodeSimpleText* nodep) override { if (nodep->tracking() || m_trackText) { puts(nodep->text()); @@ -405,8 +409,8 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { iterateAndNextConstNull(nodep->exprsp()); puts(");\n"); } - void visit(AstCMath* nodep) override { - putfs(nodep, "$_CMATH("); + void visit(AstCExpr* nodep) override { + putfs(nodep, "$_CEXPR("); iterateAndNextConstNull(nodep->exprsp()); puts(");\n"); } diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index 7d1df2878..17a35a426 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -28,8 +28,8 @@ VL_DEFINE_DEBUG_FUNCTIONS; -//###################################################################### -// Emit statements and math operators +// ###################################################################### +// Emit statements and expressions class EmitXmlFileVisitor final : public VNVisitor { // NODE STATE diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index 7bba5f825..d7d957654 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -828,10 +828,6 @@ private: void visit(AstNodeStmt* nodep) override { if (nodep->user1SetOnce()) return; // Process once - if (!nodep->isStatement()) { - iterateChildren(nodep); - return; - } m_stmtp = nodep; iterateChildren(nodep); m_stmtp = nullptr; diff --git a/src/V3Force.cpp b/src/V3Force.cpp index a1c136f6b..3c3b1c5de 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -104,7 +104,7 @@ class ForceConvertVisitor final : public VNVisitor { AstVarRef* const lhsp = new AstVarRef{flp, m_enVscp, VAccess::WRITE}; V3Number zero{m_enVscp, m_enVscp->width()}; zero.setAllBits0(); - AstNodeMath* const rhsp = new AstConst{flp, zero}; + AstNodeExpr* const rhsp = new AstConst{flp, zero}; AstAssign* const assignp = new AstAssign{flp, lhsp, rhsp}; AstActive* const activep = new AstActive{ flp, "force-init", diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index cb5a1f498..628465602 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -185,8 +185,8 @@ public: } }; -//###################################################################### -// Is this a simple math expression with a single input and single output? +// ###################################################################### +// Is this a simple expression with a single input and single output? class GateOkVisitor final : public VNVisitor { private: @@ -801,7 +801,7 @@ private: // comparing AstActive nodes, which are very likely not to compare equals (and for the // purposes of V3Gate, we probably only care about them either being identical instances, // or having the same sensitivities anyway, so if this becomes a problem, it can be - // improved which should also speed things up), and AstNodeMath for if conditions, which + // improved which should also speed things up), and AstNodeExpr for if conditions, which // are hopefully small, and to be safe they should probably be only considered same when // identical instances (otherwise if writing the condition between 2 ifs don't really // merge). diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index 681c68c92..2916d70cf 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -183,8 +183,8 @@ private: } //------------------------------------------------------------ - // AstNodeMath - void visit(AstNodeMath* nodep) override { + // AstNodeExpr + void visit(AstNodeExpr* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } void visit(AstConst* nodep) override { diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp index a5f2fa38a..5f4754925 100644 --- a/src/V3HierBlock.cpp +++ b/src/V3HierBlock.cpp @@ -296,7 +296,7 @@ class HierBlockUsageCollectVisitor final : public VNVisitor { if (nodep->isGParam() && nodep->overriddenParam()) m_gparams.push_back(nodep); } - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 3b0214adb..8d0eb3b6d 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -691,7 +691,7 @@ private: cellp->addIntfRefsp(new AstIntfRef(varlp->fileline(), alias)); } //-------------------- - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstNodeStmt*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 328318dc5..2de50c0b6 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -124,7 +124,7 @@ private: } // Save some time - void visit(AstNodeMath*) override {} + void visit(AstNodeExpr*) override {} void visit(AstNodeAssign*) override {} void visit(AstAlways*) override {} @@ -153,7 +153,7 @@ private: } iterateChildren(nodep); } - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } public: @@ -473,7 +473,7 @@ private: } //-------------------- - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 1c4bea7df..d1a3ff617 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -441,7 +441,7 @@ private: m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment iterateChildren(nodep); } - void visit(AstCMath* nodep) override { + void visit(AstCExpr* nodep) override { m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment iterateChildren(nodep); } @@ -494,7 +494,7 @@ private: } void visit(AstVar*) override {} // Accelerate void visit(AstNodeStmt*) override {} // Accelerate - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 3ed4bd599..6659a4662 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2915,6 +2915,7 @@ private: outp = AstNode::addNext(outp, addp); } newp = new AstSysIgnore(nodep->fileline(), outp); + newp->dtypep(nodep->dtypep()); } nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 56a7512a8..6f1fe68f0 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -175,10 +175,6 @@ private: m_insStmtp = nullptr; } void visit(AstNodeStmt* nodep) override { - if (!nodep->isStatement()) { - iterateChildren(nodep); - return; - } m_insMode = IM_BEFORE; m_insStmtp = nodep; iterateChildren(nodep); diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 03cb0abf0..fdcfb1f80 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -499,7 +499,7 @@ private: if (nodep->modp()->modPublic()) m_modp->modPublic(true); //** No iteration for speed } - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 88283587b..450ecd583 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -1242,9 +1242,10 @@ AstActive* OrderProcess::processMoveOneLogic(const OrderLogicVertex* lvertexp, scopep->addBlocksp(newFuncpr); // Create top call to it AstCCall* const callp = new AstCCall{nodep->fileline(), newFuncpr}; + callp->dtypeSetVoid(); // Where will we be adding the call? AstActive* const newActivep = new AstActive{nodep->fileline(), name, domainp}; - newActivep->addStmtsp(callp); + newActivep->addStmtsp(callp->makeStmt()); if (!activep) { activep = newActivep; } else { diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index a9106d549..18744fffc 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -3186,8 +3186,9 @@ static void addThreadStartToExecGraph(AstExecGraph* const execGraphp, } else { // The last will run on the main thread. AstCCall* const callp = new AstCCall(fl, funcp); + callp->dtypeSetVoid(); callp->argTypes("vlSelf, vlSymsp->__Vm_even_cycle__" + tag); - execGraphp->addStmtsp(callp); + execGraphp->addStmtsp(callp->makeStmt()); addStrStmt("Verilated::mtaskId(0);\n"); } } diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 5411dbf07..d38eff5e3 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -46,7 +46,7 @@ constexpr int STATIC_CONST_MIN_WIDTH = 256; // Minimum size to extract to stati class PremitVisitor final : public VNVisitor { private: // NODE STATE - // AstNodeMath::user() -> bool. True if iterated already + // AstNodeExpr::user() -> bool. True if iterated already // AstShiftL::user2() -> bool. True if converted to conditional // AstShiftR::user2() -> bool. True if converted to conditional // *::user3() -> Used when visiting AstNodeAssign @@ -56,6 +56,7 @@ private: // STATE AstCFunc* m_cfuncp = nullptr; // Current block AstNode* m_stmtp = nullptr; // Current statement + AstCCall* m_callp = nullptr; // Current AstCCall AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions AstTraceInc* m_inTracep = nullptr; // Inside while loop, special statement additions bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts @@ -89,8 +90,7 @@ private: && VN_AS(nodep->backp(), Sel)->widthp() == nodep) { // AstSel::width must remain a constant } else if ((nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), ArraySel)) - || ((VN_IS(m_stmtp, CCall) || VN_IS(m_stmtp, CStmt)) - && VN_IS(nodep, ArraySel))) { + || ((m_callp || VN_IS(m_stmtp, CStmt)) && VN_IS(nodep, ArraySel))) { // ArraySel's are pointer refs, ignore } else { UINFO(4, "Cre Temp: " << nodep << endl); @@ -208,10 +208,6 @@ private: m_stmtp = nullptr; } void visit(AstNodeStmt* nodep) override { - if (!nodep->isStatement()) { - iterateChildren(nodep); - return; - } UINFO(4, " STMT " << nodep << endl); startStatement(nodep); iterateChildren(nodep); @@ -337,6 +333,11 @@ private: } checkNode(nodep); } + void visit(AstCCall* nodep) override { + VL_RESTORER(m_callp); + m_callp = nodep; + iterateChildren(nodep); + } // Autoflush void visit(AstDisplay* nodep) override { diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 3677a1071..385d50b3e 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -172,7 +172,7 @@ private: } return stmtsp; } else { - AstNodeMath* valp; + AstNodeExpr* valp; if (auto* const enumDtp = VN_CAST(memberp ? memberp->subDTypep()->subDTypep() : varrefp->dtypep()->subDTypep(), EnumDType)) { diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index db48e6b2e..00d3bfc68 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -252,7 +252,7 @@ private: } //-------------------- void visit(AstVar*) override {} // Accelerate - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 50f8f12ea..52b7adce5 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -146,7 +146,8 @@ void splitCheck(AstCFunc* ofuncp) { ofuncp->scopep()->addBlocksp(funcp); // AstCCall* const callp = new AstCCall{funcp->fileline(), funcp}; - ofuncp->addStmtsp(callp); + callp->dtypeSetVoid(); + ofuncp->addStmtsp(callp->makeStmt()); func_stmts = 0; } funcp->addStmtsp(itemp); @@ -215,7 +216,9 @@ void orderSequentially(AstCFunc* funcp, const LogicByScope& lbs) { subFuncp->slow(funcp->slow()); scopep->addBlocksp(subFuncp); // Call it from the top function - funcp->addStmtsp(new AstCCall{scopep->fileline(), subFuncp}); + AstCCall* const callp = new AstCCall{scopep->fileline(), subFuncp}; + callp->dtypeSetVoid(); + funcp->addStmtsp(callp->makeStmt()); return subFuncp; }; const VNUser1InUse user1InUse; // AstScope -> AstCFunc: the sub-function for the scope @@ -506,7 +509,9 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp, const auto add = [&](const string& text) { blockp->addText(flp, text, true); }; add("#ifdef VL_DEBUG\n"); add("if (VL_UNLIKELY(vlSymsp->_vm_contextp__->debug())) {\n"); - blockp->addNodesp(new AstCCall{flp, dumpp}); + AstCCall* const callp = new AstCCall{flp, dumpp}; + callp->dtypeSetVoid(); + blockp->addNodesp(callp->makeStmt()); add("}\n"); add("#endif\n"); } @@ -520,8 +525,8 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp, //============================================================================ // Helpers to construct an evaluation loop. -AstNode* buildLoop(AstNetlist* netlistp, const string& name, - const std::function& build) // +AstNodeStmt* buildLoop(AstNetlist* netlistp, const string& name, + const std::function& build) // { AstTopScope* const topScopep = netlistp->topScopep(); AstScope* const scopeTopp = topScopep->scopep(); @@ -529,7 +534,7 @@ AstNode* buildLoop(AstNetlist* netlistp, const string& name, // Create the loop condition variable AstVarScope* const condp = scopeTopp->createTemp("__V" + name + "Continue", 1); // Initialize the loop condition variable to true - AstNode* const resp = setVar(condp, 1); + AstNodeStmt* const resp = setVar(condp, 1); // Add the loop AstWhile* const loopp = new AstWhile{flp, new AstVarRef{flp, condp, VAccess::READ}}; resp->addNext(loopp); @@ -541,11 +546,11 @@ AstNode* buildLoop(AstNetlist* netlistp, const string& name, return resp; }; -std::pair makeEvalLoop(AstNetlist* netlistp, const string& tag, - const string& name, AstVarScope* trigVscp, - AstCFunc* trigDumpp, - std::function computeTriggers, - std::function makeBody) { +std::pair makeEvalLoop(AstNetlist* netlistp, const string& tag, + const string& name, AstVarScope* trigVscp, + AstCFunc* trigDumpp, + std::function computeTriggers, + std::function makeBody) { UASSERT_OBJ(trigVscp->dtypep()->basicp()->isTriggerVec(), trigVscp, "Not TRIGGERVEC"); AstTopScope* const topScopep = netlistp->topScopep(); AstScope* const scopeTopp = topScopep->scopep(); @@ -553,7 +558,7 @@ std::pair makeEvalLoop(AstNetlist* netlistp, const strin AstVarScope* const counterp = scopeTopp->createTemp("__V" + tag + "IterCount", 32); - AstNode* nodep = setVar(counterp, 0); + AstNodeStmt* nodep = setVar(counterp, 0); nodep->addNext(buildLoop(netlistp, tag, [&](AstVarScope* continuep, AstWhile* loopp) { // Compute triggers loopp->addStmtsp(computeTriggers()); @@ -572,7 +577,7 @@ std::pair makeEvalLoop(AstNetlist* netlistp, const strin AstVarRef* const refp = new AstVarRef{flp, counterp, VAccess::READ}; AstConst* const constp = new AstConst{flp, AstConst::DTyped{}, counterp->dtypep()}; constp->num().setLong(limit); - AstNodeMath* const condp = new AstGt{flp, refp, constp}; + AstNodeExpr* const condp = new AstGt{flp, refp, constp}; AstIf* const failp = new AstIf{flp, condp}; failp->branchPred(VBranchPred::BP_UNLIKELY); ifp->addThensp(failp); @@ -583,7 +588,9 @@ std::pair makeEvalLoop(AstNetlist* netlistp, const strin const string& line = cvtToStr(locp->lineno()); const auto add = [&](const string& text) { blockp->addText(flp, text, true); }; add("#ifdef VL_DEBUG\n"); - blockp->addNodesp(new AstCCall{flp, trigDumpp}); + AstCCall* const callp = new AstCCall{flp, trigDumpp}; + callp->dtypeSetVoid(); + blockp->addNodesp(callp->makeStmt()); add("#endif\n"); add("VL_FATAL_MT(\"" + file + "\", " + line + ", \"\", "); add("\"" + name + " region did not converge.\");\n"); @@ -651,10 +658,14 @@ void createSettle(AstNetlist* netlistp, AstCFunc* const initFuncp, SenExprBuilde const auto& pair = makeEvalLoop( netlistp, "stl", "Settle", trig.m_vscp, trig.m_dumpp, [&]() { // Trigger - return new AstCCall{stlFuncp->fileline(), trig.m_funcp}; + AstCCall* const callp = new AstCCall{stlFuncp->fileline(), trig.m_funcp}; + callp->dtypeSetVoid(); + return callp->makeStmt(); }, [&]() { // Body - return new AstCCall{stlFuncp->fileline(), stlFuncp}; + AstCCall* const callp = new AstCCall{stlFuncp->fileline(), stlFuncp}; + callp->dtypeSetVoid(); + return callp->makeStmt(); }); // Add the first iteration trigger to the trigger computation function @@ -735,10 +746,14 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp, const auto& pair = makeEvalLoop( netlistp, "ico", "Input combinational", trig.m_vscp, trig.m_dumpp, [&]() { // Trigger - return new AstCCall{icoFuncp->fileline(), trig.m_funcp}; + AstCCall* const callp = new AstCCall{icoFuncp->fileline(), trig.m_funcp}; + callp->dtypeSetVoid(); + return callp->makeStmt(); }, [&]() { // Body - return new AstCCall{icoFuncp->fileline(), icoFuncp}; + AstCCall* const callp = new AstCCall{icoFuncp->fileline(), icoFuncp}; + callp->dtypeSetVoid(); + return callp->makeStmt(); }); // Add the first iteration trigger to the trigger computation function @@ -785,19 +800,28 @@ void createEval(AstNetlist* netlistp, // }); // Create the active eval loop - AstNode* const activeEvalLoopp + AstNodeStmt* const activeEvalLoopp = makeEvalLoop( netlistp, "act", "Active", actTrig.m_vscp, actTrig.m_dumpp, [&]() { // Trigger - AstNode* const resultp = new AstCCall{flp, actTrig.m_funcp}; - // Commit trigger awaits from the previous iteration - if (AstNode* const commitp = timingKit.createCommit(netlistp)) { - resultp->addNext(commitp); + AstNodeStmt* resultp = nullptr; + + // Compute the current triggers + { + AstCCall* const trigsp = new AstCCall{flp, actTrig.m_funcp}; + trigsp->dtypeSetVoid(); + resultp = AstNode::addNext(resultp, trigsp->makeStmt()); } + + // Commit trigger awaits from the previous iteration + if (AstCCall* const commitp = timingKit.createCommit(netlistp)) { + resultp = AstNode::addNext(resultp, commitp->makeStmt()); + } + return resultp; }, [&]() { // Body - AstNode* resultp = nullptr; + AstNodeStmt* resultp = nullptr; // Compute the pre triggers { @@ -806,9 +830,8 @@ void createEval(AstNetlist* netlistp, // AstVarRef* const opbp = new AstVarRef{flp, nbaTrigsp, VAccess::READ}; opap->addNext(opbp); AstCMethodHard* const callp = new AstCMethodHard{flp, lhsp, "andNot", opap}; - callp->statement(true); callp->dtypeSetVoid(); - resultp = AstNode::addNext(resultp, callp); + resultp = AstNode::addNext(resultp, callp->makeStmt()); } // Latch the active trigger flags under the NBA trigger flags @@ -816,42 +839,48 @@ void createEval(AstNetlist* netlistp, // AstVarRef* const lhsp = new AstVarRef{flp, nbaTrigsp, VAccess::WRITE}; AstVarRef* const argp = new AstVarRef{flp, actTrig.m_vscp, VAccess::READ}; AstCMethodHard* const callp = new AstCMethodHard{flp, lhsp, "set", argp}; - callp->statement(true); callp->dtypeSetVoid(); - resultp = AstNode::addNext(resultp, callp); + resultp = AstNode::addNext(resultp, callp->makeStmt()); } // Resume triggered timing schedulers - if (AstNode* const resumep = timingKit.createResume(netlistp)) { - resultp = AstNode::addNext(resultp, resumep); + if (AstCCall* const resumep = timingKit.createResume(netlistp)) { + resultp = AstNode::addNext(resultp, resumep->makeStmt()); } // Invoke body function - return AstNode::addNext(resultp, new AstCCall{flp, actFuncp}); + { + AstCCall* const callp = new AstCCall{flp, actFuncp}; + callp->dtypeSetVoid(); + return AstNode::addNext(resultp, callp->makeStmt()); + } + + return resultp; }) .second; // Create the NBA eval loop. This uses the Active eval loop in the trigger section. - AstNode* const nbaEvalLoopp + AstNodeStmt* const nbaEvalLoopp = makeEvalLoop( netlistp, "nba", "NBA", nbaTrigsp, nbaDumpp, [&]() { // Trigger - AstNode* resultp = nullptr; + AstNodeStmt* resultp = nullptr; // Reset NBA triggers { AstVarRef* const refp = new AstVarRef{flp, nbaTrigsp, VAccess::WRITE}; AstCMethodHard* const callp = new AstCMethodHard{flp, refp, "clear"}; - callp->statement(true); callp->dtypeSetVoid(); - resultp = AstNode::addNext(resultp, callp); + resultp = AstNode::addNext(resultp, callp->makeStmt()); } // Run the Active eval loop return AstNode::addNext(resultp, activeEvalLoopp); }, [&]() { // Body - return new AstCCall{flp, nbaFuncp}; + AstCCall* const callp = new AstCCall{flp, nbaFuncp}; + callp->dtypeSetVoid(); + return callp->makeStmt(); }) .second; @@ -859,7 +888,11 @@ void createEval(AstNetlist* netlistp, // funcp->addStmtsp(nbaEvalLoopp); // Add the Postponed eval call - if (postponedFuncp) funcp->addStmtsp(new AstCCall{flp, postponedFuncp}); + if (postponedFuncp) { + AstCCall* const callp = new AstCCall{flp, postponedFuncp}; + callp->dtypeSetVoid(); + funcp->addStmtsp(callp->makeStmt()); + } } } // namespace diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index de8845b43..4bf3de0c7 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -75,7 +75,9 @@ AstCCall* TimingKit::createResume(AstNetlist* const netlistp) { m_resumeFuncp->addStmtsp(activep); } } - return new AstCCall{m_resumeFuncp->fileline(), m_resumeFuncp}; + AstCCall* const callp = new AstCCall{m_resumeFuncp->fileline(), m_resumeFuncp}; + callp->dtypeSetVoid(); + return callp; } //============================================================================ @@ -85,7 +87,7 @@ AstCCall* TimingKit::createCommit(AstNetlist* const netlistp) { if (!m_commitFuncp) { for (auto& p : m_lbs) { AstActive* const activep = p.second; - auto* const resumep = VN_AS(activep->stmtsp(), CMethodHard); + auto* const resumep = VN_AS(VN_AS(activep->stmtsp(), StmtExpr)->exprp(), CMethodHard); UASSERT_OBJ(!resumep->nextp(), resumep, "Should be the only statement here"); AstVarScope* const schedulerp = VN_AS(resumep->fromp(), VarRef)->varScopep(); UASSERT_OBJ(schedulerp->dtypep()->basicp()->isDelayScheduler() @@ -117,15 +119,16 @@ AstCCall* TimingKit::createCommit(AstNetlist* const netlistp) { auto* const commitp = new AstCMethodHard{ flp, new AstVarRef{flp, schedulerp, VAccess::READWRITE}, "commit"}; if (resumep->pinsp()) commitp->addPinsp(resumep->pinsp()->cloneTree(false)); - commitp->statement(true); commitp->dtypeSetVoid(); - newactp->addStmtsp(commitp); + newactp->addStmtsp(commitp->makeStmt()); m_commitFuncp->addStmtsp(newactp); } // We still haven't created a commit function (no trigger schedulers), return null if (!m_commitFuncp) return nullptr; } - return new AstCCall{m_commitFuncp->fileline(), m_commitFuncp}; + AstCCall* const callp = new AstCCall{m_commitFuncp->fileline(), m_commitFuncp}; + callp->dtypeSetVoid(); + return callp; } //============================================================================ @@ -161,18 +164,17 @@ TimingKit prepareTiming(AstNetlist* const netlistp) { // Create a resume() call on the timing scheduler auto* const resumep = new AstCMethodHard{ flp, new AstVarRef{flp, schedulerp, VAccess::READWRITE}, "resume"}; - resumep->statement(true); resumep->dtypeSetVoid(); if (schedulerp->dtypep()->basicp()->isTriggerScheduler()) { if (methodp->pinsp()) resumep->addPinsp(methodp->pinsp()->cloneTree(false)); } else if (schedulerp->dtypep()->basicp()->isDynamicTriggerScheduler()) { auto* const postp = resumep->cloneTree(false); postp->name("doPostUpdates"); - m_postUpdatesr = AstNode::addNext(m_postUpdatesr, postp); + m_postUpdatesr = AstNode::addNext(m_postUpdatesr, postp->makeStmt()); } // Put it in an active and put that in the global resume function auto* const activep = new AstActive{flp, "_timing", sensesp}; - activep->addStmtsp(resumep); + activep->addStmtsp(resumep->makeStmt()); m_lbs.emplace_back(m_scopeTopp, activep); } @@ -216,7 +218,7 @@ TimingKit prepareTiming(AstNetlist* const netlistp) { } //-------------------- - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } public: @@ -278,10 +280,12 @@ void transformForks(AstNetlist* const netlistp) { // If it's fork..join, we can refer to variables from the parent process if (!m_funcp->user1SetOnce()) { // Only do this once per function // Move all locals to the heap before the fork - auto* const awaitp = new AstCAwait{ - m_forkp->fileline(), new AstCStmt{m_forkp->fileline(), "VlNow{}"}}; - awaitp->statement(true); - m_forkp->addHereThisAsNext(awaitp); + AstCExpr* const nowp + = new AstCExpr{m_forkp->fileline(), "VlNow{}", 0, true}; + nowp->dtypeSetVoid(); // TODO: this is sloppy but harmless + AstCAwait* const awaitp = new AstCAwait{m_forkp->fileline(), nowp}; + awaitp->dtypeSetVoid(); + m_forkp->addHereThisAsNext(awaitp->makeStmt()); } } else { refp->v3warn(E_UNSUPPORTED, "Unsupported: variable local to a forking process " @@ -353,8 +357,9 @@ void transformForks(AstNetlist* const netlistp) { newfuncp->isConst(m_funcp->isConst()); newfuncp->declPrivate(true); // Replace the begin with a call to the newly created function - auto* const callp = new AstCCall{flp, newfuncp}; - nodep->replaceWith(callp); + AstCCall* const callp = new AstCCall{flp, newfuncp}; + callp->dtypeSetVoid(); + nodep->replaceWith(callp->makeStmt()); // If we're in a class, add a vlSymsp arg if (m_inClass) { newfuncp->addInitsp(new AstCStmt{nodep->fileline(), "VL_KEEP_THIS;\n"}); @@ -376,7 +381,7 @@ void transformForks(AstNetlist* const netlistp) { } //-------------------- - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/src/V3SenExprBuilder.h b/src/V3SenExprBuilder.h index 97b31e5b2..81e189d83 100644 --- a/src/V3SenExprBuilder.h +++ b/src/V3SenExprBuilder.h @@ -141,8 +141,7 @@ class SenExprBuilder final { if (AstUnpackArrayDType* const dtypep = VN_CAST(exprp->dtypep(), UnpackArrayDType)) { AstCMethodHard* const cmhp = new AstCMethodHard{flp, wrPrev(), "assign", rdCurr()}; cmhp->dtypeSetVoid(); - cmhp->statement(true); - m_postUpdates.push_back(cmhp); + m_postUpdates.push_back(cmhp->makeStmt()); } else { m_postUpdates.push_back(new AstAssign{flp, wrPrev(), rdCurr()}); } @@ -157,7 +156,7 @@ class SenExprBuilder final { const auto currp = [=]() { return getCurr(senp); }; const auto prevp = [=]() { return new AstVarRef{flp, getPrev(senp), VAccess::READ}; }; - const auto lsb = [=](AstNodeMath* opp) { return new AstSel{flp, opp, 0, 1}; }; + const auto lsb = [=](AstNodeExpr* opp) { return new AstSel{flp, opp, 0, 1}; }; // All event signals should be 1-bit at this point switch (senItemp->edgeType()) { @@ -188,9 +187,8 @@ class SenExprBuilder final { // Clear 'fired' state when done AstCMethodHard* const clearp = new AstCMethodHard{flp, currp(), "clearFired"}; - ifp->addThensp(clearp); clearp->dtypeSetVoid(); - clearp->statement(true); + ifp->addThensp(clearp->makeStmt()); // Enqueue for clearing 'triggered' state on next eval AstTextBlock* const blockp = new AstTextBlock{flp}; diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index 1d7b4d86d..52810f33c 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -86,10 +86,6 @@ private: } } void visit(AstNodeStmt* nodep) override { - if (!nodep->isStatement()) { - iterateChildren(nodep); - return; - } UINFO(6, " CL STMT " << nodep << endl); const bool oldKeep = m_keepStmt; { @@ -179,8 +175,7 @@ private: } } - // Speedup; no always under math - void visit(AstNodeMath*) override {} + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 7b82c3f46..1b90d3384 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -405,7 +405,7 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { VarSet m_foundTargetVar; UnpackRefMap m_refs; AstNodeModule* m_modp = nullptr; - // AstNodeStmt, AstCell, AstNodeFTaskRef, or AstAlways(Public) for sensitivity + // AstNodeStmt, AstCell, or AstAlways(Public) for sensitivity AstNode* m_contextp = nullptr; const AstNodeFTask* m_inFTask = nullptr; size_t m_numSplit = 0; @@ -492,38 +492,34 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { } } void visit(AstNodeFTaskRef* nodep) override { - VL_RESTORER(m_contextp); - { - m_contextp = nodep; - const AstNodeFTask* const ftaskp = nodep->taskp(); - UASSERT_OBJ(ftaskp, nodep, "Unlinked"); - // Iterate arguments of a function/task. - for (AstNode *argp = nodep->pinsp(), *paramp = ftaskp->stmtsp(); argp; - argp = argp->nextp(), paramp = paramp ? paramp->nextp() : nullptr) { - const char* reason = nullptr; - const AstVar* vparamp = nullptr; - while (paramp) { - vparamp = VN_CAST(paramp, Var); - if (vparamp && vparamp->isIO()) { - reason = cannotSplitVarDirectionReason(vparamp->direction()); - break; - } - paramp = paramp->nextp(); - vparamp = nullptr; + const AstNodeFTask* const ftaskp = nodep->taskp(); + UASSERT_OBJ(ftaskp, nodep, "Unlinked"); + // Iterate arguments of a function/task. + for (AstNode *argp = nodep->pinsp(), *paramp = ftaskp->stmtsp(); argp; + argp = argp->nextp(), paramp = paramp ? paramp->nextp() : nullptr) { + const char* reason = nullptr; + const AstVar* vparamp = nullptr; + while (paramp) { + vparamp = VN_CAST(paramp, Var); + if (vparamp && vparamp->isIO()) { + reason = cannotSplitVarDirectionReason(vparamp->direction()); + break; } - if (!reason && !vparamp) { - reason = "the number of argument to the task/function mismatches"; - } - m_foundTargetVar.clear(); - iterate(argp); - if (reason) { - for (AstVar* const varp : m_foundTargetVar) { - warnNoSplit(varp, argp, reason); - m_refs.remove(varp); - } - } - m_foundTargetVar.clear(); + paramp = paramp->nextp(); + vparamp = nullptr; } + if (!reason && !vparamp) { + reason = "the number of argument to the task/function mismatches"; + } + m_foundTargetVar.clear(); + iterate(argp); + if (reason) { + for (AstVar* const varp : m_foundTargetVar) { + warnNoSplit(varp, argp, reason); + m_refs.remove(varp); + } + } + m_foundTargetVar.clear(); } } void visit(AstPin* nodep) override { @@ -605,12 +601,6 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { iterateChildren(nodep); } } - AstNode* toInsertPoint(AstNode* insertp) { - if (const AstNodeStmt* const stmtp = VN_CAST(insertp, NodeStmt)) { - if (!stmtp->isStatement()) insertp = stmtp->backp(); - } - return insertp; - } AstVarRef* createTempVar(AstNode* context, AstNode* nodep, AstUnpackArrayDType* dtypep, const std::string& name_prefix, std::vector& vars, int start_idx, bool lvalue, bool /*ftask*/) { @@ -640,7 +630,7 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { if (!lvalue) std::swap(lhsp, rhsp); AstNode* newassignp; if (use_simple_assign) { - AstNode* const insertp = toInsertPoint(context); + AstNode* const insertp = context; newassignp = new AstAssign{fl, lhsp, rhsp}; if (lvalue) { // If varp is LHS, this assignment must appear after the original @@ -662,7 +652,6 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { } void connectPort(AstVar* varp, std::vector& vars, AstNode* insertp) { UASSERT_OBJ(varp->isIO(), varp, "must be port"); - insertp = insertp ? toInsertPoint(insertp) : nullptr; const bool lvalue = varp->direction().isWritable(); FileLine* const fl = varp->fileline(); for (size_t i = 0; i < vars.size(); ++i) { @@ -1055,9 +1044,7 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl { static void connectPortAndVar(const std::vector& vars, AstVar* portp, AstNode* insertp) { for (; insertp; insertp = insertp->backp()) { - if (const AstNodeStmt* const stmtp = VN_CAST(insertp, NodeStmt)) { - if (stmtp->isStatement()) break; - } + if (VN_IS(insertp, NodeStmt)) break; } const bool in = portp->isReadOnly(); FileLine* const fl = portp->fileline(); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 0d1eb2c22..fea8d97c1 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -552,10 +552,12 @@ private: cnewpr = cnewp; } else if (const AstMethodCall* const mrefp = VN_CAST(refp, MethodCall)) { ccallp = new AstCMethodCall(refp->fileline(), mrefp->fromp()->unlinkFrBack(), cfuncp); - beginp->addNext(ccallp); + ccallp->dtypeSetVoid(); + beginp->addNext(ccallp->makeStmt()); } else { ccallp = new AstCCall(refp->fileline(), cfuncp); - beginp->addNext(ccallp); + ccallp->dtypeSetVoid(); + beginp->addNext(ccallp->makeStmt()); } // Convert complicated outputs to temp signals @@ -617,7 +619,7 @@ private: UASSERT_OBJ(snp, refp, "Missing scoping context"); ccallp->addArgsp(snp); // __Vfilenamep - ccallp->addArgsp(new AstCMath(refp->fileline(), + ccallp->addArgsp(new AstCExpr(refp->fileline(), "\"" + refp->fileline()->filename() + "\"", 64, true)); // __Vlineno ccallp->addArgsp(new AstConst(refp->fileline(), refp->fileline()->lineno())); @@ -701,7 +703,7 @@ private: string frstmt; string ket; const bool useSetWSvlv = TaskDpiUtils::dpiToInternalFrStmt(portp, frName, frstmt, ket); - // Use a AstCMath, as we want V3Clean to mask off bits that don't make sense. + // Use a AstCExpr, as we want V3Clean to mask off bits that don't make sense. int cwidth = VL_IDATASIZE; if (!useSetWSvlv && portp->basicp()) { if (portp->basicp()->keyword().isBitLogic()) { @@ -743,7 +745,7 @@ private: } from += ket; AstNode* const rhsp = new AstSel( - portp->fileline(), new AstCMath(portp->fileline(), from, cwidth, false), 0, + portp->fileline(), new AstCExpr(portp->fileline(), from, cwidth, false), 0, portp->width()); stmtp = new AstAssign(portp->fileline(), srcp, rhsp); } @@ -1039,8 +1041,9 @@ private: cfuncp->addStmtsp(new AstText(nodep->fileline(), stmt, /* tracking: */ true)); } AstCCall* const callp = new AstCCall(nodep->fileline(), dpiFuncp); + callp->dtypeSetVoid(); callp->argTypes(args); - cfuncp->addStmtsp(callp); + cfuncp->addStmtsp(callp->makeStmt()); } // Convert output/inout arguments back to internal type @@ -1401,30 +1404,26 @@ private: beginp = createInlinedFTask(nodep, namePrefix, outvscp); } // Replace the ref - AstNode* visitp = nullptr; + AstNode* const visitp = insertBeforeStmt(nodep, beginp); + if (VN_IS(nodep, New)) { - UASSERT_OBJ(!nodep->isStatement(), nodep, "new is non-stmt"); UASSERT_OBJ(cnewp, nodep, "didn't create cnew for new"); nodep->replaceWith(cnewp); - visitp = insertBeforeStmt(nodep, beginp); - } else if (!nodep->isStatement()) { + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else if (!VN_IS(nodep->backp(), StmtExpr)) { UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function"); AstVarRef* const outrefp = new AstVarRef(nodep->fileline(), outvscp, VAccess::READ); nodep->replaceWith(outrefp); - // Insert new statements - visitp = insertBeforeStmt(nodep, beginp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { if (nodep->taskp()->isFunction()) { nodep->v3warn( IGNOREDRETURN, "Ignoring return value of non-void function (IEEE 1800-2017 13.4.1)"); } - // outvscp maybe non-nullptr if calling a function in a taskref, - // but if so we want to ignore the function result - nodep->replaceWith(beginp); + nodep->unlinkFrBack(); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } - // Cleanup - VL_DO_DANGLING(nodep->deleteTree(), nodep); UINFO(4, " FTask REF Done.\n"); // Visit nodes that normal iteration won't find if (visitp) iterateAndNextNull(visitp); @@ -1519,15 +1518,18 @@ private: "For statements should have been converted to while statements in V3Begin.cpp"); } void visit(AstNodeStmt* nodep) override { - if (!nodep->isStatement()) { - iterateChildren(nodep); - return; - } m_insMode = IM_BEFORE; m_insStmtp = nodep; iterateChildren(nodep); m_insStmtp = nullptr; // Next thing should be new statement } + void visit(AstStmtExpr* nodep) override { + m_insMode = IM_BEFORE; + m_insStmtp = nodep; + iterateChildren(nodep); + if (!nodep->exprp()) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + m_insStmtp = nullptr; // Next thing should be new statement + } void visit(AstSenItem* nodep) override { UASSERT_OBJ(!m_inSensesp, nodep, "Senitem under senitem?"); VL_RESTORER(m_inSensesp); diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 8f657e0b0..85549de04 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -341,9 +341,8 @@ private: auto* const donep = new AstCMethodHard{ beginp->fileline(), new AstVarRef{flp, forkVscp, VAccess::WRITE}, "done"}; donep->dtypeSetVoid(); - donep->statement(true); addDebugInfo(donep); - beginp->addStmtsp(donep); + beginp->addStmtsp(donep->makeStmt()); } // Handle the 'join' part of a fork..join void makeForkJoin(AstFork* const forkp) { @@ -364,16 +363,15 @@ private: auto* const initp = new AstCMethodHard{flp, new AstVarRef{flp, forkVscp, VAccess::WRITE}, "init", new AstConst{flp, joinCount}}; initp->dtypeSetVoid(); - initp->statement(true); - forkp->addHereThisAsNext(initp); + forkp->addHereThisAsNext(initp->makeStmt()); // Await the join at the end auto* const joinp = new AstCMethodHard{flp, new AstVarRef{flp, forkVscp, VAccess::WRITE}, "join"}; joinp->dtypeSetVoid(); addDebugInfo(joinp); - auto* const awaitp = new AstCAwait{flp, joinp}; - awaitp->statement(true); - forkp->addNextHere(awaitp); + AstCAwait* const awaitp = new AstCAwait{flp, joinp}; + awaitp->dtypeSetVoid(); + forkp->addNextHere(awaitp->makeStmt()); } // VISITORS @@ -476,7 +474,9 @@ private: if (nodep->funcp()->user2()) { // If suspendable VNRelinker relinker; nodep->unlinkFrBack(&relinker); - relinker.relink(new AstCAwait{nodep->fileline(), nodep}); + AstCAwait* const awaitp = new AstCAwait{nodep->fileline(), nodep}; + awaitp->dtypeSetVoid(); + relinker.relink(awaitp); } else { // Add our process/func as the CFunc's dependency as we might have to put an await here DependencyVertex* const procVxp = getDependencyVertex(m_procp); @@ -515,13 +515,15 @@ private: delayMethodp->dtypeSetVoid(); addDebugInfo(delayMethodp); // Create the co_await - auto* const awaitp = new AstCAwait{flp, delayMethodp, getCreateDelaySenTree()}; - awaitp->statement(true); + AstCAwait* const awaitp = new AstCAwait{flp, delayMethodp, getCreateDelaySenTree()}; + awaitp->dtypeSetVoid(); + AstStmtExpr* const awaitStmtp = awaitp->makeStmt(); // Relink child statements after the co_await if (nodep->stmtsp()) { - AstNode::addNext(awaitp, nodep->stmtsp()->unlinkFrBackWithNext()); + AstNode::addNext(awaitStmtp, + nodep->stmtsp()->unlinkFrBackWithNext()); } - nodep->replaceWith(awaitp); + nodep->replaceWith(awaitStmtp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } void visit(AstEventControl* nodep) override { @@ -552,9 +554,9 @@ private: auto* const sensesp = nodep->sensesp(); addEventDebugInfo(evalMethodp, sensesp); // Create the co_await - auto* const awaitEvalp + AstCAwait* const awaitEvalp = new AstCAwait{flp, evalMethodp, getCreateDynamicTriggerSenTree()}; - awaitEvalp->statement(true); + awaitEvalp->dtypeSetVoid(); // Construct the sen expression for this sentree SenExprBuilder senExprBuilder{m_scopep}; auto* const assignp = new AstAssign{flp, new AstVarRef{flp, trigvscp, VAccess::WRITE}, @@ -568,8 +570,9 @@ private: } // Create the trigger eval loop, which will await the evaluation step and check the // trigger - auto* const loopp = new AstWhile{ - flp, new AstLogNot{flp, new AstVarRef{flp, trigvscp, VAccess::READ}}, awaitEvalp}; + AstWhile* const loopp = new AstWhile{ + flp, new AstLogNot{flp, new AstVarRef{flp, trigvscp, VAccess::READ}}, + awaitEvalp->makeStmt()}; // Put pre updates before the trigger check and assignment for (AstNodeStmt* const stmtp : senExprBuilder.getAndClearPreUpdates()) { loopp->addStmtsp(stmtp); @@ -579,18 +582,18 @@ private: // If the post update is destructive (e.g. event vars are cleared), create an await for // the post update step if (destructivePostUpdate(sensesp)) { - auto* const awaitPostUpdatep = awaitEvalp->cloneTree(false); + AstCAwait* const awaitPostUpdatep = awaitEvalp->cloneTree(false); VN_AS(awaitPostUpdatep->exprp(), CMethodHard)->name("postUpdate"); - loopp->addStmtsp(awaitPostUpdatep); + loopp->addStmtsp(awaitPostUpdatep->makeStmt()); } // Put the post updates at the end of the loop for (AstNodeStmt* const stmtp : senExprBuilder.getAndClearPostUpdates()) { loopp->addStmtsp(stmtp); } // Finally, await the resumption step in 'act' - auto* const awaitResumep = awaitEvalp->cloneTree(false); + AstCAwait* const awaitResumep = awaitEvalp->cloneTree(false); VN_AS(awaitResumep->exprp(), CMethodHard)->name("resumption"); - AstNode::addNext(loopp, awaitResumep); + AstNode::addNext(loopp, awaitResumep->makeStmt()); // Replace the event control with the loop nodep->replaceWith(loopp); } else { @@ -605,9 +608,9 @@ private: triggerMethodp->dtypeSetVoid(); addEventDebugInfo(triggerMethodp, sensesp); // Create the co_await - auto* const awaitp = new AstCAwait{flp, triggerMethodp, sensesp}; - awaitp->statement(true); - nodep->replaceWith(awaitp); + AstCAwait* const awaitp = new AstCAwait{flp, triggerMethodp, sensesp}; + awaitp->dtypeSetVoid(); + nodep->replaceWith(awaitp->makeStmt()); } VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -700,9 +703,11 @@ private: if (constp->isZero()) { // We have to await forever instead of simply returning in case we're deep in a // callstack - auto* const awaitp = new AstCAwait{flp, new AstCStmt{flp, "VlForever{}"}}; - awaitp->statement(true); - nodep->replaceWith(awaitp); + AstCExpr* const foreverp = new AstCExpr{flp, "VlForever{}", 0, true}; + foreverp->dtypeSetVoid(); // TODO: this is sloppy but harmless + AstCAwait* const awaitp = new AstCAwait{flp, foreverp}; + awaitp->dtypeSetVoid(); + nodep->replaceWith(awaitp->makeStmt()); if (stmtsp) VL_DO_DANGLING(stmtsp->deleteTree(), stmtsp); } else if (stmtsp) { // Just put the statements there @@ -760,7 +765,7 @@ private: } //-------------------- - void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeExpr*) override {} // Accelerate void visit(AstVar*) override {} void visit(AstNode* nodep) override { iterateChildren(nodep); } diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 89703a67f..aaf13244a 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -163,7 +163,7 @@ private: // AstCFunc::user1() // V3GraphVertex* for this node // AstTraceDecl::user1() // V3GraphVertex* for this node // AstVarScope::user1() // V3GraphVertex* for this node - // AstCCall::user2() // bool; walked next list for other ccalls + // AstStmtExpr::user2() // bool; walked next list for other ccalls // Ast*::user3() // TraceActivityVertex* for this node const VNUser1InUse m_inuser1; const VNUser2InUse m_inuser2; @@ -429,13 +429,15 @@ private: FileLine* const fl = insertp->fileline(); AstAssign* const setterp = new AstAssign(fl, selectActivity(fl, code, VAccess::WRITE), new AstConst(fl, AstConst::BitTrue())); - if (AstCCall* const callp = VN_CAST(insertp, CCall)) { - callp->addNextHere(setterp); + if (AstStmtExpr* const stmtp = VN_CAST(insertp, StmtExpr)) { + stmtp->addNextHere(setterp); } else if (AstCFunc* const funcp = VN_CAST(insertp, CFunc)) { // If there are awaits, insert the setter after each await if (funcp->isCoroutine() && funcp->stmtsp()) { funcp->stmtsp()->foreachAndNext([&](AstCAwait* awaitp) { - if (awaitp->nextp()) awaitp->addNextHere(setterp->cloneTree(false)); + AstNode* stmtp = awaitp->backp(); + while (VN_IS(stmtp, NodeExpr)) stmtp = stmtp->backp(); + if (stmtp->nextp()) stmtp->addNextHere(setterp->cloneTree(false)); }); } funcp->addStmtsp(setterp); @@ -550,8 +552,9 @@ private: } // Add call to top function AstCCall* const callp = new AstCCall(funcp->fileline(), funcp); + callp->dtypeSetVoid(); callp->argTypes("bufp"); - topFuncp->addStmtsp(callp); + topFuncp->addStmtsp(callp->makeStmt()); } // Done UINFO(5, " newCFunc " << funcp << endl); @@ -822,20 +825,24 @@ private: if (nodep->isTop()) m_topModp = nodep; iterateChildren(nodep); } - void visit(AstCCall* nodep) override { - UINFO(8, " CCALL " << nodep << endl); + void visit(AstStmtExpr* nodep) override { if (!m_finding && !nodep->user2()) { - // See if there are other calls in same statement list; - // If so, all funcs might share the same activity code - TraceActivityVertex* const activityVtxp - = getActivityVertexp(nodep, nodep->funcp()->slow()); - for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) { - if (AstCCall* const ccallp = VN_CAST(nextp, CCall)) { - ccallp->user2(true); // Processed - UINFO(8, " SubCCALL " << ccallp << endl); - V3GraphVertex* const ccallFuncVtxp = getCFuncVertexp(ccallp->funcp()); - activityVtxp->slow(ccallp->funcp()->slow()); - new V3GraphEdge(&m_graph, activityVtxp, ccallFuncVtxp, 1); + if (AstCCall* const callp = VN_CAST(nodep->exprp(), CCall)) { + UINFO(8, " CCALL " << callp << endl); + // See if there are other calls in same statement list; + // If so, all funcs might share the same activity code + TraceActivityVertex* const activityVtxp + = getActivityVertexp(nodep, callp->funcp()->slow()); + for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) { + if (AstStmtExpr* const stmtp = VN_CAST(nextp, StmtExpr)) { + if (AstCCall* const ccallp = VN_CAST(stmtp->exprp(), CCall)) { + stmtp->user2(true); // Processed + UINFO(8, " SubCCALL " << ccallp << endl); + V3GraphVertex* const ccallFuncVtxp = getCFuncVertexp(ccallp->funcp()); + activityVtxp->slow(ccallp->funcp()->slow()); + new V3GraphEdge(&m_graph, activityVtxp, ccallFuncVtxp, 1); + } + } } } } diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 41db6e5ab..aab284fc3 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -489,8 +489,9 @@ public: // Call all sub functions for this path for (AstCFunc* const subFuncp : item.second) { AstCCall* const callp = new AstCCall{flp, subFuncp}; + callp->dtypeSetVoid(); callp->argTypes("tracep"); - addToTopFunc(callp); + addToTopFunc(callp->makeStmt()); } } pathAdjustor.unwind(); @@ -503,8 +504,9 @@ public: AstCFunc* const topFuncp = newCFunc(flp, ""); for (AstCFunc* funcp : m_topFuncps) { AstCCall* const callp = new AstCCall{flp, funcp}; + callp->dtypeSetVoid(); callp->argTypes("tracep"); - topFuncp->addStmtsp(callp); + topFuncp->addStmtsp(callp->makeStmt()); } m_topFuncps.clear(); m_topFuncps.push_back(topFuncp); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index caebfdcd0..a2a966a90 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -308,11 +308,11 @@ private: // Widths: out width = lhs width = rhs width // Signed: Output signed iff LHS & RHS signed. // Real: Not allowed - void visit(AstAnd* nodep) override { visit_boolmath_and_or(nodep); } - void visit(AstOr* nodep) override { visit_boolmath_and_or(nodep); } - void visit(AstXor* nodep) override { visit_boolmath_and_or(nodep); } + void visit(AstAnd* nodep) override { visit_boolexpr_and_or(nodep); } + void visit(AstOr* nodep) override { visit_boolexpr_and_or(nodep); } + void visit(AstXor* nodep) override { visit_boolexpr_and_or(nodep); } void visit(AstBufIf1* nodep) override { - visit_boolmath_and_or(nodep); + visit_boolexpr_and_or(nodep); } // Signed behavior changing in 3.814 // Width: Max(Lhs,Rhs) sort of. // Real: If either side real @@ -2856,12 +2856,12 @@ private: if (!nodep->pinsp()) { newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear"}; - newp->makeStatement(); + newp->dtypeSetVoid(); } else { AstNode* const index_exprp = methodCallWildcardIndexExpr(nodep, adtypep); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "erase", index_exprp->unlinkFrBack()}; - newp->makeStatement(); + newp->dtypeSetVoid(); } } else if (nodep->name() == "sort" || nodep->name() == "rsort" || nodep->name() == "reverse" || nodep->name() == "shuffle") { @@ -2878,14 +2878,14 @@ private: newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "r_" + nodep->name(), withp}; newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique") { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name()}; newp->dtypeFrom(adtypep); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "find" || nodep->name() == "find_first" || nodep->name() == "find_last") { AstWith* const withp @@ -2896,7 +2896,7 @@ private: newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), withp}; newp->dtypeFrom(adtypep); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else { nodep->v3error("Unknown wildcard associative array method " << nodep->prettyNameQ()); nodep->dtypeFrom(adtypep->subDTypep()); // Best guess @@ -2926,7 +2926,7 @@ private: nodep->name(), // first/last/next/prev index_exprp->unlinkFrBack()); newp->dtypeSetSigned32(); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "exists") { // function int exists(input index) // IEEE really should have made this a "bit" return methodOkArguments(nodep, 1, 1); @@ -2941,12 +2941,12 @@ private: if (!nodep->pinsp()) { newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear"); - newp->makeStatement(); + newp->dtypeSetVoid(); } else { AstNode* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "erase", index_exprp->unlinkFrBack()); - newp->makeStatement(); + newp->dtypeSetVoid(); } } else if (nodep->name() == "sort" || nodep->name() == "rsort" || nodep->name() == "reverse" || nodep->name() == "shuffle") { @@ -2962,7 +2962,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "r_" + nodep->name(), withp); newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" || nodep->name() == "unique_index") { methodOkArguments(nodep, 0, 0); @@ -2974,7 +2974,7 @@ private: } else { newp->dtypeFrom(adtypep); } - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "find" || nodep->name() == "find_first" || nodep->name() == "find_last") { AstWith* const withp = methodWithArgument(nodep, true, false, nodep->findBitDType(), @@ -2984,7 +2984,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), withp); newp->dtypeFrom(adtypep); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" || nodep->name() == "find_last_index") { AstWith* const withp = methodWithArgument(nodep, true, false, nodep->findBitDType(), @@ -2994,7 +2994,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), withp); newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep())); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else { nodep->v3error("Unknown built-in associative array method " << nodep->prettyNameQ()); nodep->dtypeFrom(adtypep->subDTypep()); // Best guess @@ -3048,7 +3048,7 @@ private: methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear"); - newp->makeStatement(); + newp->dtypeSetVoid(); } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" || nodep->name() == "sum" || nodep->name() == "product") { // All value return @@ -3060,7 +3060,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "r_" + nodep->name(), withp); newp->dtypeFrom(adtypep->subDTypep()); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "reverse" || nodep->name() == "shuffle" || nodep->name() == "sort" || nodep->name() == "rsort") { AstWith* withp = nullptr; @@ -3072,7 +3072,7 @@ private: methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), withp); - newp->makeStatement(); + newp->dtypeSetVoid(); } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" || nodep->name() == "unique_index") { methodOkArguments(nodep, 0, 0); @@ -3084,7 +3084,7 @@ private: } else { newp->dtypeFrom(adtypep); } - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "find" || nodep->name() == "find_first" || nodep->name() == "find_last" || nodep->name() == "find_index") { AstWith* const withp @@ -3095,7 +3095,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), withp); newp->dtypeFrom(adtypep); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" || nodep->name() == "find_last_index") { AstWith* const withp @@ -3106,7 +3106,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), withp); newp->dtypep(newp->findQueueIndexDType()); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else { nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in dynamic array method " << nodep->prettyNameQ()); @@ -3137,18 +3137,18 @@ private: if (!nodep->pinsp()) { newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear"); - newp->makeStatement(); + newp->dtypeSetVoid(); } else { AstNode* const index_exprp = methodCallQueueIndexExpr(nodep); if (index_exprp->isZero()) { // delete(0) is a pop_front newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "pop_front"); newp->dtypeFrom(adtypep->subDTypep()); - newp->makeStatement(); + newp->dtypeSetVoid(); } else { newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "erase", index_exprp->unlinkFrBack()); - newp->makeStatement(); + newp->dtypeSetVoid(); } } } else if (nodep->name() == "insert") { @@ -3160,12 +3160,12 @@ private: if (index_exprp->isZero()) { // insert(0, ...) is a push_front newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "push_front", argp->exprp()->unlinkFrBack()); - newp->makeStatement(); + newp->dtypeSetVoid(); } else { newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), index_exprp->unlinkFrBack()); newp->addPinsp(argp->exprp()->unlinkFrBack()); - newp->makeStatement(); + newp->dtypeSetVoid(); } } else if (nodep->name() == "pop_front" || nodep->name() == "pop_back") { methodOkArguments(nodep, 0, 0); @@ -3174,9 +3174,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name()); newp->dtypeFrom(adtypep->subDTypep()); - // Because queue methods pop_front() or pop_back() can be void cast, - // they use makeStatement to check if they need the c++ ";" added. - if (nodep->isStandaloneBodyStmt()) newp->makeStatement(); + if (nodep->isStandaloneBodyStmt()) newp->dtypeSetVoid(); } else if (nodep->name() == "push_back" || nodep->name() == "push_front") { methodOkArguments(nodep, 1, 1); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); @@ -3184,7 +3182,7 @@ private: iterateCheckTyped(nodep, "push value", argp->exprp(), adtypep->subDTypep(), BOTH); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), argp->exprp()->unlinkFrBack()); - newp->makeStatement(); + newp->dtypeSetVoid(); } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" || nodep->name() == "sum" || nodep->name() == "product") { AstWith* const withp @@ -3195,7 +3193,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "r_" + nodep->name(), withp); newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "reverse" || nodep->name() == "shuffle" || nodep->name() == "sort" || nodep->name() == "rsort") { AstWith* withp = nullptr; @@ -3207,7 +3205,7 @@ private: methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), withp); - newp->makeStatement(); + newp->dtypeSetVoid(); } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" || nodep->name() == "unique_index") { methodOkArguments(nodep, 0, 0); @@ -3219,7 +3217,7 @@ private: } else { newp->dtypeFrom(adtypep); } - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "find" || nodep->name() == "find_first" || nodep->name() == "find_last") { AstWith* const withp @@ -3230,7 +3228,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), withp); newp->dtypeFrom(adtypep); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" || nodep->name() == "find_last_index") { AstWith* const withp @@ -3241,7 +3239,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), withp); newp->dtypep(newp->findQueueIndexDType()); - if (!nodep->firstAbovep()) newp->makeStatement(); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else { nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in queue method " << nodep->prettyNameQ()); @@ -3289,7 +3287,7 @@ private: nodep->taskp(ftaskp); nodep->dtypeFrom(ftaskp); nodep->classOrPackagep(classp); - if (VN_IS(ftaskp, Task)) nodep->makeStatement(); + if (VN_IS(ftaskp, Task)) nodep->dtypeSetVoid(); processFTaskRefArgs(nodep); } return; @@ -3432,8 +3430,8 @@ private: AstNode* const newp = new AstAssign( nodep->fileline(), fromp, new AstPutcN(nodep->fileline(), varrefp, rhsp, thsp)); fromp->access(VAccess::WRITE); - nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); + pushDeletep(nodep->backp()); + VL_DO_DANGLING(nodep->backp()->replaceWith(newp), nodep); } else if (nodep->name() == "getc") { methodOkArguments(nodep, 1, 1); AstArg* const arg0p = VN_AS(nodep->pinsp(), Arg); @@ -4351,8 +4349,8 @@ private: } AstMethodCall* const newp = new AstMethodCall{ nodep->fileline(), nodep->lhsp()->unlinkFrBack(), "delete", nullptr}; - newp->makeStatement(); - nodep->replaceWith(newp); + newp->dtypeSetVoid(); + nodep->replaceWith(newp->makeStmt()); VL_DO_DANGLING(pushDeletep(nodep), nodep); // Need to now convert it visit(newp); @@ -4371,8 +4369,8 @@ private: } newp->didWidth(true); newp->protect(false); - newp->makeStatement(); - nodep->replaceWith(newp); + newp->dtypeSetVoid(); + nodep->replaceWith(newp->makeStmt()); VL_DO_DANGLING(pushDeletep(nodep), nodep); // return; } @@ -4440,8 +4438,8 @@ private: newFormat += "%@"; VNRelinker handle; argp->unlinkFrBack(&handle); - AstCMath* const newp - = new AstCMath(nodep->fileline(), "VL_TO_STRING(", 0, true); + AstCExpr* const newp + = new AstCExpr(nodep->fileline(), "VL_TO_STRING(", 0, true); newp->addExprsp(argp); newp->addExprsp(new AstText(nodep->fileline(), ")", true)); newp->dtypeSetString(); @@ -5274,7 +5272,7 @@ private: //-------------------- // Default - void visit(AstNodeMath* nodep) override { + void visit(AstNodeExpr* nodep) override { if (!nodep->didWidth()) { nodep->v3fatalSrc( "Visit function missing? Widthed function missing for math node: " << nodep); @@ -5623,7 +5621,7 @@ private: return nodep; // May edit } - void visit_boolmath_and_or(AstNodeBiop* nodep) { + void visit_boolexpr_and_or(AstNodeBiop* nodep) { // CALLER: And, Or, Xor, ... // Lint widths: out width = lhs width = rhs width // Signed: if lhs & rhs signed @@ -6452,8 +6450,8 @@ private: nodep->fileline(), fromp, new AstSFormatF(nodep->fileline(), format, false, argp->exprp()->unlinkFrBack())); fromp->access(VAccess::WRITE); - nodep->replaceWith(newp); - VL_DO_DANGLING(pushDeletep(nodep), nodep); + pushDeletep(nodep->backp()); + VL_DO_DANGLING(nodep->backp()->replaceWith(newp), newp); } //---------------------------------------------------------------------- diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 9604eb151..536c523da 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -463,7 +463,7 @@ static void process() { // Bits between widthMin() and width() are irrelevant, but may be non zero. v3Global.widthMinUsage(VWidthMinUsage::VERILOG_WIDTH); - // Make all math operations either 8, 16, 32 or 64 bits + // Make all expressions either 8, 16, 32 or 64 bits V3Clean::cleanAll(v3Global.rootp()); // Move wide constants to BLOCK temps / ConstPool. diff --git a/src/astgen b/src/astgen index 2c7f847aa..acbb4575e 100755 --- a/src/astgen +++ b/src/astgen @@ -1196,7 +1196,7 @@ def write_dfg_dfg_to_ast(filename): "void visit(Dfg{t}* vtxp) override {{\n".format(t=node.name)) for i in range(node.arity): fh.write( - " AstNodeMath* const op{j}p = convertSource(vtxp->source<{i}>());\n" + " AstNodeExpr* const op{j}p = convertSource(vtxp->source<{i}>());\n" .format(i=i, j=i + 1)) fh.write( " m_resultp = makeNode(vtxp".format(t=node.name)) diff --git a/src/verilog.y b/src/verilog.y index d7668fffe..28f453728 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1085,6 +1085,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion +// Blank lines for type insertion %start source_text @@ -2689,7 +2690,7 @@ genvar_iteration: // ==IEEE: genvar_iteration | varRefBase yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); } | varRefBase yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); } // // inc_or_dec_operator - // When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstNodeMathStmt? + // When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstNodeExprStmt? | yP_PLUSPLUS varRefBase { $$ = new AstAssign{$1, $2, new AstAdd{$1, $2->cloneTree(true), new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; } @@ -3284,23 +3285,27 @@ statement_item: // IEEE: statement_item { $$ = $4; FileLine* const newfl = new FileLine{$$->fileline()}; newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true); - $$->fileline(newfl); } + $$->fileline(newfl); + if (AstNodeExpr* const exprp = VN_CAST($$, NodeExpr)) $$ = exprp->makeStmt(); } | yVOID yP_TICK '(' expr '.' task_subroutine_callNoMethod ')' ';' { $$ = new AstDot{$5, false, $4, $6}; FileLine* const newfl = new FileLine{$6->fileline()}; newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true); - $6->fileline(newfl); } + $6->fileline(newfl); + if (AstNodeExpr* const exprp = VN_CAST($$, NodeExpr)) $$ = exprp->makeStmt(); } // // Expr included here to resolve our not knowing what is a method call // // Expr here must result in a subroutine_call - | task_subroutine_callNoMethod ';' { $$ = $1; } + | task_subroutine_callNoMethod ';' + { $$ = $1; + if (AstNodeExpr* const exprp = VN_CAST($$, NodeExpr)) $$ = exprp->makeStmt(); } //UNSUP fexpr '.' array_methodNoRoot ';' { UNSUP } - | fexpr '.' task_subroutine_callNoMethod ';' { $$ = new AstDot($2, false, $1, $3); } + | fexpr '.' task_subroutine_callNoMethod ';' { $$ = (new AstDot{$2, false, $1, $3})->makeStmt(); } //UNSUP fexprScope ';' { UNSUP } // // Not here in IEEE; from class_constructor_declaration // // Because we've joined class_constructor_declaration into generic functions // // Way over-permissive; // // IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ] - | fexpr '.' class_new ';' { $$ = new AstDot($2, false, $1, $3); } + | fexpr '.' class_new ';' { $$ = (new AstDot{$2, false, $1, $3})->makeStmt(); } // | statementVerilatorPragmas { $$ = $1; } // @@ -3426,7 +3431,7 @@ foperator_assignment: // IEEE: operator_assignment (for first part of //UNSUP BISONPRE_COPY(operator_assignment,{s/~f~/f/g}) // {copied} ; -inc_or_dec_expression: // ==IEEE: inc_or_dec_expression +inc_or_dec_expression: // ==IEEE: inc_or_dec_expression // // Need fexprScope instead of variable_lvalue to prevent conflict ~l~exprScope yP_PLUSPLUS { $$ = $1; $$ = new AstPostAdd{$2, new AstConst{$2, AstConst::StringToParse(), "'b1"}, $1, $1->cloneTree(true)}; } @@ -3439,7 +3444,7 @@ inc_or_dec_expression: // ==IEEE: inc_or_dec_expression { $$ = $1; $$ = new AstPreSub{$1, new AstConst{$1, AstConst::StringToParse(), "'b1"}, $2, $2->cloneTree(true)}; } ; -finc_or_dec_expression: // ==IEEE: inc_or_dec_expression +finc_or_dec_expression: // ==IEEE: inc_or_dec_expression BISONPRE_COPY(inc_or_dec_expression,{s/~l~/f/g}) // {copied} ; @@ -3684,14 +3689,14 @@ loop_variables: // IEEE: loop_variables //************************************************ // Functions/tasks -taskRef: // IEEE: part of tf_call +taskRef: // IEEE: part of tf_call id { $$ = new AstTaskRef($1,*$1,nullptr); } | id '(' list_of_argumentsE ')' { $$ = new AstTaskRef($1,*$1,$3); } | packageClassScope id '(' list_of_argumentsE ')' { $$ = AstDot::newIfPkg($2, $1, new AstTaskRef($2, *$2, $4)); } ; -funcRef: // IEEE: part of tf_call +funcRef: // IEEE: part of tf_call // // package_scope/hierarchical_... is part of expr, so just need ID // // making-a id-is-a // // ----------------- ------------------ @@ -3713,9 +3718,9 @@ task_subroutine_callNoMethod: // function_subroutine_callNoMethod (as // // IEEE: tf_call taskRef { $$ = $1; } // // funcref below not task ref to avoid conflict, must later handle either - | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, true, $1, $4); } + | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse{$2, $1, $4}; } // // can call as method and yWITH without parenthesis - | id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, true, new AstFuncRef($1, *$1, nullptr), $4); } + | id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse{$2, new AstFuncRef{$1, *$1, nullptr}, $4}; } | system_t_call { $$ = $1; } // // IEEE: method_call requires a "." so is in expr // // IEEE: ['std::'] not needed, as normal std package resolution will find it @@ -3725,12 +3730,12 @@ task_subroutine_callNoMethod: // function_subroutine_callNoMethod (as //UNSUP funcRef yWITH__CUR constraint_block { } ; -function_subroutine_callNoMethod: // IEEE: function_subroutine_call (as function) +function_subroutine_callNoMethod: // IEEE: function_subroutine_call (as function) // // IEEE: tf_call funcRef { $$ = $1; } - | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, false, $1, $4); } + | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse{$2, $1, $4}; } // // can call as method and yWITH without parenthesis - | id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, false, new AstFuncRef($1, *$1, nullptr), $4); } + | id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse{$2, new AstFuncRef{$1, *$1, nullptr}, $4}; } | system_f_call { $$ = $1; } // // IEEE: method_call requires a "." so is in expr // // IEEE: ['std::'] not needed, as normal std package resolution will find it @@ -3739,7 +3744,7 @@ function_subroutine_callNoMethod: // IEEE: function_subroutine_cal // // Note yNULL is already part of expressions, so they come for free | funcRef yWITH__CUR constraint_block { $$ = $1; BBUNSUP($2, "Unsupported: randomize() 'with' constraint"); } - | funcRef yWITH__CUR '{' '}' { $$ = new AstWithParse($2, false, $1, nullptr); } + | funcRef yWITH__CUR '{' '}' { $$ = new AstWithParse{$2, $1, nullptr}; } ; system_t_call: // IEEE: system_tf_call (as task) @@ -3872,7 +3877,7 @@ system_t_call: // IEEE: system_tf_call (as task) | system_f_call_or_t { $$ = new AstSysFuncAsTask($1, $1); } ; -system_f_call: // IEEE: system_tf_call (as func) +system_f_call: // IEEE: system_tf_call (as func) yaD_PLI systemDpiArgsE { $$ = new AstFuncRef($1, *$1, $2); VN_CAST($$, FuncRef)->pli(true); } // | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? nullptr : new AstUCFunc($1,$3)); } @@ -3887,7 +3892,7 @@ systemDpiArgsE: // IEEE: part of system_if_call for aruments of | '(' exprList ')' { $$ = GRAMMARP->argWrapList($2); } ; -system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) +system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) yD_ACOS '(' expr ')' { $$ = new AstAcosD($1,$3); } | yD_ACOSH '(' expr ')' { $$ = new AstAcoshD($1,$3); } | yD_ASIN '(' expr ')' { $$ = new AstAsinD($1,$3); } @@ -4276,9 +4281,9 @@ array_methodNoRoot: array_methodWith: array_methodNoRoot parenE { $$ = $1; } | array_methodNoRoot parenE yWITH__PAREN '(' expr ')' - { $$ = new AstWithParse($3, false, $1, $5); } + { $$ = new AstWithParse{$3, $1, $5}; } | array_methodNoRoot '(' expr ')' yWITH__PAREN '(' expr ')' - { $$ = new AstWithParse($5, false, $1, $7); $1->addPinsp(new AstArg($3, "", $3)); } + { $$ = new AstWithParse{$5, $1, $7}; $1->addPinsp(new AstArg($3, "", $3)); } ; dpi_import_export: // ==IEEE: dpi_import_export @@ -4350,11 +4355,11 @@ exprOrDataTypeEqE: // IEEE: optional '=' expression (part of param_ | '=' exprOrDataType { $$ = $2; } ; -constExpr: +constExpr: expr { $$ = $1; } ; -expr: // IEEE: part of expression/constant_expression/primary +expr: // IEEE: part of expression/constant_expression/primary // *SEE BELOW* // IEEE: primary/constant_primary // // // IEEE: unary_operator primary @@ -4522,7 +4527,7 @@ expr: // IEEE: part of expression/constant_expression/ | ~l~expr yDIST '{' dist_list '}' { $$ = $1; BBUNSUP($2, "Unsupported: dist"); } ; -fexpr: // For use as first part of statement (disambiguates <=) +fexpr: // For use as first part of statement (disambiguates <=) BISONPRE_COPY(expr,{s/~l~/f/g; s/~r~/f/g; s/~f__IGNORE~/__IGNORE/g;}) // {copied} ; @@ -4555,11 +4560,11 @@ fexpr: // For use as first part of statement (disambigu //UNSUP | '(' event_expression ':' expr ':' expr ')' { $$ = $1; $$ = "(...)"; } //UNSUP ; -exprNoStr: // expression with string removed +exprNoStr: // expression with string removed BISONPRE_COPY(expr,{s/~noStr__IGNORE~/Ignore/g;}) // {copied} ; -exprOkLvalue: // expression that's also OK to use as a variable_lvalue +exprOkLvalue: // expression that's also OK to use as a variable_lvalue ~l~exprScope { $$ = $1; } // // IEEE: concatenation/constant_concatenation // // Replicate(1) required as otherwise "{a}" would not be self-determined @@ -4581,7 +4586,7 @@ exprOkLvalue: // expression that's also OK to use as a variabl | streaming_concatenation { $$ = $1; } ; -fexprOkLvalue: // exprOkLValue, For use as first part of statement (disambiguates <=) +fexprOkLvalue: // exprOkLValue, For use as first part of statement (disambiguates <=) BISONPRE_COPY(exprOkLvalue,{s/~l~/f/g}) // {copied} ; @@ -4601,11 +4606,11 @@ fexprOkLvalue: // exprOkLValue, For use as first part of statem //UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/pev_/g}) // {copied} //UNSUP ; -fexprLvalue: // For use as first part of statement (disambiguates <=) +fexprLvalue: // For use as first part of statement (disambiguates <=) fexprOkLvalue { $$ = $1; $$ = $1; } ; -exprScope: // scope and variable for use to inside an expression +exprScope: // scope and variable for use to inside an expression // // Here we've split method_call_root | implicit_class_handle | class_scope | package_scope // // from the object being called and let expr's "." deal with resolving it. // // (note method_call_root was simplified to require a primary in 1800-2009) @@ -4624,7 +4629,7 @@ exprScope: // scope and variable for use to inside an expre | ySUPER { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "super"); } ; -fexprScope: // exprScope, For use as first part of statement (disambiguates <=) +fexprScope: // exprScope, For use as first part of statement (disambiguates <=) BISONPRE_COPY(exprScope,{s/~l~/f/g}) // {copied} ; @@ -4656,23 +4661,23 @@ cStrList: | exprStrText ',' cStrList { $$ = $1->addNext($3); } ; -cateList: +cateList: // // Not just 'expr' to prevent conflict via stream_concOrExprOrType stream_expression { $$ = $1; } | cateList ',' stream_expression { $$ = new AstConcat($2,$1,$3); } ; -exprListE: +exprListE: /* empty */ { $$ = nullptr; } | exprList { $$ = $1; } ; -exprList: +exprList: expr { $$ = $1; } | exprList ',' expr { $$ = $1->addNext($3); } ; -exprDispList: // exprList for within $display +exprDispList: // exprList for within $display expr { $$ = $1; } | exprDispList ',' expr { $$ = $1->addNext($3); } // // ,, creates a space in $display @@ -4735,7 +4740,7 @@ argsDotted: // IEEE: part of list_of_arguments //UNSUP | '.' idAny '(' pev_expr ')' { $$ = new AstArg($2, *$2, $4); } //UNSUP ; -streaming_concatenation: // ==IEEE: streaming_concatenation +streaming_concatenation: // ==IEEE: streaming_concatenation // // Need to disambiguate {<< expr-{ ... expr-} stream_concat } // // From {<< stream-{ ... stream-} } // // Likewise simple_type's idScoped from constExpr's idScope @@ -4758,7 +4763,7 @@ stream_concatenation: // ==IEEE: stream_concatenation '{' cateList '}' { $$ = $2; } ; -stream_expression: // ==IEEE: stream_expression +stream_expression: // ==IEEE: stream_expression // // IEEE: array_range_expression expanded below expr { $$ = $1; } //UNSUP expr yWITH__BRA '[' expr ']' { UNSUP } @@ -5077,7 +5082,7 @@ idSVKwd: // Warn about non-forward compatible Verilog 200 { static string s = "final"; $$ = &s; ERRSVKWD($1,*$$); $$ = $1; } ; -variable_lvalue: // IEEE: variable_lvalue or net_lvalue +variable_lvalue: // IEEE: variable_lvalue or net_lvalue // // Note many variable_lvalue's must use exprOkLvalue when arbitrary expressions may also exist idClassSel { $$ = $1; } | '{' variable_lvalueConcList '}' { $$ = $2; } @@ -5089,7 +5094,7 @@ variable_lvalue: // IEEE: variable_lvalue or net_lvalue | streaming_concatenation { $$ = $1; } ; -variable_lvalueConcList: // IEEE: part of variable_lvalue: '{' variable_lvalue { ',' variable_lvalue } '}' +variable_lvalueConcList: // IEEE: part of variable_lvalue: '{' variable_lvalue { ',' variable_lvalue } '}' variable_lvalue { $$ = $1; } | variable_lvalueConcList ',' variable_lvalue { $$ = new AstConcat($2,$1,$3); } ; @@ -5100,7 +5105,7 @@ variable_lvalueConcList: // IEEE: part of variable_lvalue: '{' variable_l //UNSUP ; // VarRef to dotted, and/or arrayed, and/or bit-ranged variable -idClassSel: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable +idClassSel: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable idDotted { $$ = $1; } // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select | yTHIS '.' idDotted @@ -5124,7 +5129,7 @@ idClassSelForeach: | packageClassScope idDottedForeach { $$ = new AstDot($2, true, $1, $2); } ; -idDotted: +idDotted: yD_ROOT '.' idDottedMore { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"), $3); } | idDottedMore { $$ = $1; } @@ -5136,7 +5141,7 @@ idDottedForeach: | idDottedMoreForeach { $$ = $1; } ; -idDottedMore: +idDottedMore: idArrayed { $$ = $1; } | idDottedMore '.' idArrayed { $$ = new AstDot($2, false, $1, $3); } ; @@ -5151,7 +5156,7 @@ idDottedMoreForeach: // we'll assume so and cleanup later. // id below includes: // enum_identifier -idArrayed: // IEEE: id + select +idArrayed: // IEEE: id + select id { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, nullptr, nullptr); } // // IEEE: id + part_select_range/constant_part_select_range @@ -5174,9 +5179,9 @@ idArrayedForeach: // IEEE: id + select (under foreach expression) // // IEEE: loop_variables (under foreach expression) // // To avoid conflicts we allow expr as first element, must post-check | idArrayed '[' expr ',' loop_variables ']' - { $3 = addNextNull($3, $5); $$ = new AstSelLoopVars($2, $1, $3); } + { $$ = new AstSelLoopVars{$2, $1, addNextNull(static_cast($3), $5)}; } | idArrayed '[' ',' loop_variables ']' - { $4 = addNextNull(static_cast(new AstEmpty{$3}), $4); $$ = new AstSelLoopVars($2, $1, $4); } + { $$ = new AstSelLoopVars{$2, $1, addNextNull(static_cast(new AstEmpty{$3}), $4)}; } ; // VarRef without any dots or vectorizaion @@ -5195,7 +5200,7 @@ str: // yaSTRING but with \{escapes} need decoded yaSTRING { $$ = PARSEP->newString(GRAMMARP->deQuote($1,*$1)); } ; -strAsInt: +strAsInt: yaSTRING { if ($1->empty()) { // else "" is not representable as number as is width 0 @@ -5208,7 +5213,7 @@ strAsInt: } ; -strAsIntIgnore: // strAsInt, but never matches for when expr shouldn't parse strings +strAsIntIgnore: // strAsInt, but never matches for when expr shouldn't parse strings yaSTRING__IGNORE { $$ = nullptr; yyerror("Impossible token"); } ; @@ -6563,7 +6568,7 @@ constraintStaticE: // IEEE: part of extern_constraint_declaration //********************************************************************** // Constants -timeNumAdjusted: // Time constant, adjusted to module's time units/precision +timeNumAdjusted: // Time constant, adjusted to module's time units/precision yaTIMENUM { $$ = new AstTimeImport($1, new AstConst($1, AstConst::RealDouble(), $1)); } ; diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index 749f294de..ac753a612 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -148,7 +148,8 @@ module Vt_debug_emitv_t; other = f(i); $display("stmt %~ %~", iother, other); - t()end + t(); + end i = (i + 'h1); end end @@ -189,7 +190,8 @@ module Vt_debug_emitv_t; cyc <= (cyc + 'sh1); r <= (r + 0.01); fo = cyc; - sub.inc(fosum)sum = sub.f(sum); + sub.inc(fosum); + sum = sub.f(sum); $display("[%0t] sum = %~", $timesum, sum); $display("a?= %d", ($c('sh1) ? $c('sh14) : $c('sh1e))); diff --git a/test_regress/t/t_func_tasknsvar_bad.out b/test_regress/t/t_func_tasknsvar_bad.out index 241d8b71a..230364bae 100644 --- a/test_regress/t/t_func_tasknsvar_bad.out +++ b/test_regress/t/t_func_tasknsvar_bad.out @@ -2,7 +2,7 @@ 16 | foo(bus_we_select_from[2]); | ^ ... For error description see https://verilator.org/warn/TASKNSVAR?v=latest -%Error: Internal Error: t/t_func_tasknsvar_bad.v:10:7: ../V3Broken.cpp:#: Broken link in node (or something without maybePointedTo): 'm_varp && !m_varp->brokeExists()' @ ../V3AstNodes.cpp:64 +%Error: Internal Error: t/t_func_tasknsvar_bad.v:10:7: ../V3Broken.cpp:#: Broken link in node (or something without maybePointedTo): 'm_varp && !m_varp->brokeExists()' @ ../V3AstNodes.cpp:66 10 | sig = '1; | ^~~ ... See the manual at https://verilator.org/verilator_doc.html for more assistance. diff --git a/test_regress/t/t_xml_debugcheck.out b/test_regress/t/t_xml_debugcheck.out index 35a4d21a9..dbadeec0d 100644 --- a/test_regress/t/t_xml_debugcheck.out +++ b/test_regress/t/t_xml_debugcheck.out @@ -33,51 +33,55 @@ - + + + - + - - - - + + + + + + - + - - - - + + + + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -87,18 +91,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -107,17 +111,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -129,18 +133,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -149,17 +153,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -171,22 +175,22 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -197,21 +201,21 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -225,22 +229,22 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -251,21 +255,21 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -279,22 +283,22 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -305,21 +309,21 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -333,27 +337,27 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -363,27 +367,27 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -393,18 +397,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -413,17 +417,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -435,18 +439,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -455,17 +459,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -477,110 +481,110 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - + - - + + - - - + + + - - - + + + - - - - + + + + - - - - - - - - - + + + + + + + + + - + - - - - - - - + + + + + + + - + - - - + + + - - - - + + + + - + - - - + + + - - + + @@ -590,42 +594,44 @@ - - - - + + + + - - - + + + - - - + + + - - - + + + - + + + - - - - - - + + + + + + @@ -635,9 +641,9 @@ - - - + + + @@ -646,12 +652,12 @@ - - - - - - + + + + + + @@ -661,9 +667,9 @@ - - - + + + @@ -674,12 +680,12 @@ - - - - - - + + + + + + @@ -687,87 +693,87 @@ - - + + - - + + - - - + + + - - + + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - + - - + + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -777,27 +783,27 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -807,18 +813,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -827,17 +833,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -849,27 +855,27 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -879,27 +885,27 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -909,18 +915,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -929,17 +935,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -950,74 +956,74 @@ - - - + + + - - + + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - + - - + + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -1027,27 +1033,27 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -1057,18 +1063,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -1077,17 +1083,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -1099,27 +1105,27 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -1129,27 +1135,27 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -1159,18 +1165,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -1179,17 +1185,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -1200,74 +1206,74 @@ - - - + + + - - + + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - + - - + + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -1277,27 +1283,27 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -1307,18 +1313,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -1327,17 +1333,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -1349,27 +1355,27 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -1379,27 +1385,27 @@ - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + @@ -1409,18 +1415,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -1429,17 +1435,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -1450,20 +1456,20 @@ - - - + + + - - + + - + @@ -1480,19 +1486,21 @@ - - - + + + - - - + + + - + + + @@ -1501,65 +1509,71 @@ - + - - - + + + - + - - - + + + - - - + + + + + - + - - - + + + - + - - - + + + - + + + - - + + - - - + + + - - + + - + + + @@ -1568,45 +1582,53 @@ - - + + - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + - - - + + + - - + + - + + + @@ -1615,14 +1637,16 @@ - - + + - + + + @@ -1664,55 +1688,55 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1731,49 +1755,49 @@ - + - - + + - - + + - - + + - - + + - - + + - + - - + + - + - - + + - + + - - - - + + + diff --git a/test_regress/t/t_xml_tag.out b/test_regress/t/t_xml_tag.out index e2d426fd9..fecebf1ba 100644 --- a/test_regress/t/t_xml_tag.out +++ b/test_regress/t/t_xml_tag.out @@ -40,11 +40,13 @@ - - - - - + + + + + + + @@ -55,21 +57,22 @@ + - - - - + + + + - - - - + + + + - +