Make all expressions derive from AstNodeExpr (#3721).

Apart from the representational changes below, this patch renames
AstNodeMath to AstNodeExpr, and AstCMath to AstCExpr.

Now every expression (i.e.: those AstNodes that represent a [possibly
void] value, with value being interpreted in a very general sense) has
AstNodeExpr as a super class. This necessitates the introduction of an
AstStmtExpr, which represents an expression in statement position, e.g :
'foo();' would be represented as AstStmtExpr(AstCCall(foo)). In exchange
we can get rid of isStatement() in AstNodeStmt, which now really always
represent a statement

Peak memory consumption and verilation speed are not measurably changed.

Partial step towards #3420
This commit is contained in:
Geza Lore 2022-10-12 10:19:21 +01:00
parent cf4c00e3b4
commit 65e08f4dbf
66 changed files with 2005 additions and 1968 deletions

View File

@ -114,6 +114,13 @@ you are at the top of the tree.
By convention, each function/method uses the variable ``nodep`` as a By convention, each function/method uses the variable ``nodep`` as a
pointer to the ``AstNode`` currently being processed. 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`` ``VNVisitor``
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
@ -205,7 +212,7 @@ writing DFG passes easier.
The ``DfgGraph`` represents combinational logic equations as a graph of The ``DfgGraph`` represents combinational logic equations as a graph of
``DfgVertex`` vertices. Each sub-class of ``DfgVertex`` corresponds to an ``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 reference. LValues and RValues referencing the same storage location are
represented by the same ``DfgVertex``. Consumers of such vertices read as the 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 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 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. ``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 For non-list children, the names of the getter and setter both are that of the

View File

@ -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, WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WDataInP rwp,
bool is_modulus) VL_MT_SAFE { bool is_modulus) VL_MT_SAFE {

View File

@ -929,7 +929,7 @@ static inline int _vl_cmps_w(int lbits, WDataInP const lwp, WDataInP const rwp)
} }
//========================================================================= //=========================================================================
// Math // Expressions
// Output NOT clean // Output NOT clean
static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP const lwp) VL_MT_SAFE { 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) // Return QData from double (numeric)
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real // EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real

View File

@ -288,14 +288,14 @@ VLCOV_OBJS = \
NON_STANDALONE_HEADERS = \ NON_STANDALONE_HEADERS = \
V3AstInlines.h \ V3AstInlines.h \
V3AstNodeDType.h \ V3AstNodeDType.h \
V3AstNodeMath.h \ V3AstNodeExpr.h \
V3AstNodeOther.h \ V3AstNodeOther.h \
V3DfgVertices.h \ V3DfgVertices.h \
V3WidthCommit.h \ V3WidthCommit.h \
AST_DEFS := \ AST_DEFS := \
V3AstNodeDType.h \ V3AstNodeDType.h \
V3AstNodeMath.h \ V3AstNodeExpr.h \
V3AstNodeOther.h \ V3AstNodeOther.h \
DFG_DEFS := \ DFG_DEFS := \

View File

@ -129,7 +129,7 @@ class ActiveTopVisitor final : public VNVisitor {
nodep->v3fatalSrc("Node should have been under ACTIVE"); 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(AstVarScope*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }

View File

@ -105,7 +105,7 @@ private:
// This allows syntax errors and such to be detected normally. // This allows syntax errors and such to be detected normally.
(v3Global.opt.assertOn() (v3Global.opt.assertOn()
? static_cast<AstNode*>( ? static_cast<AstNode*>(
new AstCMath{fl, "vlSymsp->_vm_contextp__->assertOn()", 1}) new AstCExpr{fl, "vlSymsp->_vm_contextp__->assertOn()", 1})
: static_cast<AstNode*>(new AstConst{fl, AstConst::BitFalse{}}))), : static_cast<AstNode*>(new AstConst{fl, AstConst::BitFalse{}}))),
nodep}; nodep};
newp->isBoundsCheck(true); // To avoid LATCH warning newp->isBoundsCheck(true); // To avoid LATCH warning

View File

@ -2218,11 +2218,11 @@ void AstNode::addPrev(AstNode* newp) {
// Specializations of AstNode::mayBeUnder // Specializations of AstNode::mayBeUnder
template <> template <>
inline bool AstNode::mayBeUnder<AstCell>(const AstNode* nodep) { inline bool AstNode::mayBeUnder<AstCell>(const AstNode* nodep) {
return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeMath); return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeExpr);
} }
template <> template <>
inline bool AstNode::mayBeUnder<AstNodeAssign>(const AstNode* nodep) { inline bool AstNode::mayBeUnder<AstNodeAssign>(const AstNode* nodep) {
return !VN_IS(nodep, NodeMath); return !VN_IS(nodep, NodeExpr);
} }
template <> template <>
inline bool AstNode::mayBeUnder<AstVarScope>(const AstNode* nodep) { inline bool AstNode::mayBeUnder<AstVarScope>(const AstNode* nodep) {
@ -2230,7 +2230,7 @@ inline bool AstNode::mayBeUnder<AstVarScope>(const AstNode* nodep) {
if (VN_IS(nodep, Var)) return false; if (VN_IS(nodep, Var)) return false;
if (VN_IS(nodep, Active)) return false; if (VN_IS(nodep, Active)) return false;
if (VN_IS(nodep, NodeStmt)) 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; return true;
} }
template <> template <>
@ -2512,7 +2512,7 @@ AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) {
// AstNode subclasses // AstNode subclasses
#include "V3AstNodeDType.h" #include "V3AstNodeDType.h"
#include "V3AstNodeMath.h" #include "V3AstNodeExpr.h"
#include "V3AstNodeOther.h" #include "V3AstNodeOther.h"
// Inline function definitions need to go last // Inline function definitions need to go last

View File

@ -141,8 +141,8 @@ AstCStmt::AstCStmt(FileLine* fl, const string& textStmt)
addExprsp(new AstText{fl, textStmt, true}); addExprsp(new AstText{fl, textStmt, true});
} }
AstCMath::AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut) AstCExpr::AstCExpr(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut)
: ASTGEN_SUPER_CMath(fl) : ASTGEN_SUPER_CExpr(fl)
, m_cleanOut{cleanOut} , m_cleanOut{cleanOut}
, m_pure{true} { , m_pure{true} {
addExprsp(new AstText{fl, textStmt, true}); addExprsp(new AstText{fl, textStmt, true});
@ -180,4 +180,6 @@ AstVarXRef::AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const V
dtypeFrom(varp); dtypeFrom(varp);
} }
AstStmtExpr* AstNodeExpr::makeStmt() { return new AstStmtExpr{fileline(), this}; }
#endif // Guard #endif // Guard

File diff suppressed because it is too large Load Diff

View File

@ -264,25 +264,6 @@ public:
void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; }
VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } 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 { class AstNodeProcedure VL_NOT_FINAL : public AstNode {
// IEEE procedure: initial, final, always // IEEE procedure: initial, final, always
// @astgen op2 := stmtsp : List[AstNode] // Note: op1 is used in some sub-types only // @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; void dump(std::ostream& str) const override;
}; };
class AstNodeStmt VL_NOT_FINAL : public AstNode { class AstNodeStmt VL_NOT_FINAL : public AstNode {
// Statement -- anything that's directly under a function // Procedural statement
bool m_statement; // Really a statement (e.g. not a function with return)
protected: protected:
AstNodeStmt(VNType t, FileLine* fl, bool statement = true) AstNodeStmt(VNType t, FileLine* fl)
: AstNode{t, fl} : AstNode{t, fl} {}
, m_statement{statement} {}
public: public:
ASTGEN_MEMBERS_AstNodeStmt; ASTGEN_MEMBERS_AstNodeStmt;
// METHODS // METHODS
bool isStatement() const { return m_statement; } // Really a statement
void statement(bool flag) { m_statement = flag; }
void addNextStmt(AstNode* newp, void addNextStmt(AstNode* newp,
AstNode* belowp) override; // Stop statement searchback here AstNode* belowp) override; // Stop statement searchback here
void addBeforeStmt(AstNode* newp, void addBeforeStmt(AstNode* newp,
@ -357,40 +334,6 @@ public:
bool isTimingControl() const override { return timingControlp(); } bool isTimingControl() const override { return timingControlp(); }
virtual bool brokeLhsMustBeLvalue() const = 0; 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<const AstNodeCCall*>(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 { class AstNodeCase VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := exprp : AstNode // Condition (scurtinee) expression // @astgen op1 := exprp : AstNode // Condition (scurtinee) expression
// @astgen op2 := itemsp : List[AstCaseItem] // @astgen op2 := itemsp : List[AstCaseItem]
@ -431,52 +374,6 @@ public:
void dump(std::ostream& str = std::cout) const override; void dump(std::ostream& str = std::cout) const override;
bool immediate() const { return m_immediate; } 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 { class AstNodeFor VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := initsp : List[AstNode] // @astgen op1 := initsp : List[AstNode]
// @astgen op2 := condp : AstNode // @astgen op2 := condp : AstNode
@ -635,22 +532,6 @@ public:
void name(const string& name) override { m_name = name; } void name(const string& name) override { m_name = name; }
bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); } 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 { class AstBind final : public AstNode {
// Parents: MODULE // Parents: MODULE
// Children: CELL // Children: CELL
@ -849,48 +730,6 @@ public:
bool isDefault() const { return condsp() == nullptr; } bool isDefault() const { return condsp() == nullptr; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } 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 { class AstCastSize final : public AstNode {
// Cast to specific size; signed/twostate inherited from lower element per IEEE // Cast to specific size; signed/twostate inherited from lower element per IEEE
// @astgen op1 := lhsp : AstNode // @astgen op1 := lhsp : AstNode
@ -1135,28 +974,6 @@ public:
bool same(const AstNode*) const override { return true; } bool same(const AstNode*) const override { return true; }
string path() const { return m_path; } 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 { class AstDpiExport final : public AstNode {
// We could put an AstNodeFTaskRef instead of the verilog function name, // We could put an AstNodeFTaskRef instead of the verilog function name,
// however we're not *calling* it, so that seems somehow wrong. // however we're not *calling* it, so that seems somehow wrong.
@ -1497,37 +1314,6 @@ public:
AstPackage* packagep() const { return m_packagep; } AstPackage* packagep() const { return m_packagep; }
void packagep(AstPackage* nodep) { m_packagep = nodep; } 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<const AstParseRef*>(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 { class AstPin final : public AstNode {
// A port or parameter assignment on an instantiaton // A port or parameter assignment on an instantiaton
// @astgen op1 := exprp : Optional[AstNode] // Expression connected (nullptr if unconnected) // @astgen op1 := exprp : Optional[AstNode] // Expression connected (nullptr if unconnected)
@ -1629,58 +1415,6 @@ public:
} }
uint32_t direction() const { return (uint32_t)m_direction; } 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<const AstSFormatF*>(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 { class AstScope final : public AstNode {
// A particular usage of a cell // A particular usage of a cell
// Parents: MODULE // Parents: MODULE
@ -1952,21 +1686,6 @@ public:
string name() const override { return m_text; } string name() const override { return m_text; }
string text() const { 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 { class AstVar final : public AstNode {
// A variable (in/out/wire/reg/param) inside a module // A variable (in/out/wire/reg/param) inside a module
// //
@ -2593,49 +2312,6 @@ public:
bool timescaleMatters() const override { return false; } 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 === // === AstNodeProcedure ===
class AstAlways final : public AstNodeProcedure { class AstAlways final : public AstNodeProcedure {
// @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list iff clocked // @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list iff clocked
@ -2797,70 +2473,6 @@ public:
return true; // SPECIAL: We don't process code after breaks 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<const AstCMethodHard*>(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 { class AstCReset final : public AstNodeStmt {
// Reset variable at startup // Reset variable at startup
// @astgen op1 := varrefp : AstVarRef // @astgen op1 := varrefp : AstVarRef
@ -3448,6 +3060,16 @@ public:
int instrCount() const override { return INSTR_COUNT_PLI; } int instrCount() const override { return INSTR_COUNT_PLI; }
bool same(const AstNode* /*samep*/) const override { return true; } 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 { class AstStop final : public AstNodeStmt {
public: public:
AstStop(FileLine* fl, bool maybe) AstStop(FileLine* fl, bool maybe)
@ -3478,21 +3100,6 @@ public:
int instrCount() const override { return 0; } int instrCount() const override { return 0; }
bool same(const AstNode* /*samep*/) const override { return true; } 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 { class AstSystemT final : public AstNodeStmt {
// $system used as task // $system used as task
// @astgen op1 := lhsp : AstNode // @astgen op1 := lhsp : AstNode
@ -3708,7 +3315,7 @@ class AstWith final : public AstNodeStmt {
// Parents: funcref (similar to AstArg) // Parents: funcref (similar to AstArg)
// Children: LambdaArgRef that declares the item variable // Children: LambdaArgRef that declares the item variable
// Children: LambdaArgRef that declares the item.index 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 op1 := indexArgRefp : AstLambdaArgRef
// @astgen op2 := valueArgRefp : AstLambdaArgRef // @astgen op2 := valueArgRefp : AstLambdaArgRef
// @astgen op3 := exprp : AstNode // @astgen op3 := exprp : AstNode
@ -3729,23 +3336,6 @@ public:
return nullptr; 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 === // === AstNodeAssign ===
class AstAssign final : public AstNodeAssign { class AstAssign final : public AstNodeAssign {
@ -3850,52 +3440,6 @@ public:
AstAlways* convertToAlways(); 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 === // === AstNodeCase ===
class AstCase final : public AstNodeCase { class AstCase final : public AstNodeCase {
// Case statement // Case statement
@ -3979,74 +3523,6 @@ public:
: ASTGEN_SUPER_Restrict(fl, propp, nullptr, false, "") {} : 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 === // === AstNodeFor ===
class AstGenFor final : public AstNodeFor { class AstGenFor final : public AstNodeFor {
public: public:

View File

@ -60,6 +60,8 @@ void AstNodeFTaskRef::cloneRelink() {
} }
} }
bool AstNodeFTaskRef::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); }
const char* AstNodeVarRef::broken() const { const char* AstNodeVarRef::broken() const {
BROKEN_RTN(m_varp && !m_varp->brokeExists()); BROKEN_RTN(m_varp && !m_varp->brokeExists());
BROKEN_RTN(m_varScopep && !m_varScopep->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 AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeCCall::dump(std::ostream& str) const { void AstNodeCCall::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str); this->AstNodeExpr::dump(str);
if (funcp()) { if (funcp()) {
str << " " << funcp()->name() << " => "; str << " " << funcp()->name() << " => ";
funcp()->dump(str); funcp()->dump(str);
@ -1376,8 +1378,8 @@ string AstBasicDType::prettyDTypeName() const {
return os.str(); return os.str();
} }
void AstNodeMath::dump(std::ostream& str) const { this->AstNode::dump(str); } void AstNodeExpr::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); } void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); }
void AstCCast::dump(std::ostream& str) const { void AstCCast::dump(std::ostream& str) const {
this->AstNodeUniop::dump(str); this->AstNodeUniop::dump(str);
@ -1504,7 +1506,7 @@ void AstDisplay::dump(std::ostream& str) const {
// str << " " << displayType().ascii(); // str << " " << displayType().ascii();
} }
void AstEnumItemRef::dump(std::ostream& str) const { void AstEnumItemRef::dump(std::ostream& str) const {
this->AstNodeMath::dump(str); this->AstNodeExpr::dump(str);
str << " -> "; str << " -> ";
if (itemp()) { if (itemp()) {
itemp()->dump(str); itemp()->dump(str);
@ -1615,11 +1617,11 @@ void AstJumpLabel::dump(std::ostream& str) const {
} }
} }
void AstLogOr::dump(std::ostream& str) const { void AstLogOr::dump(std::ostream& str) const {
this->AstNodeMath::dump(str); this->AstNodeExpr::dump(str);
if (sideEffect()) str << " [SIDE]"; if (sideEffect()) str << " [SIDE]";
} }
void AstMemberSel::dump(std::ostream& str) const { void AstMemberSel::dump(std::ostream& str) const {
this->AstNodeMath::dump(str); this->AstNodeExpr::dump(str);
str << " -> "; str << " -> ";
if (varp()) { if (varp()) {
varp()->dump(str); varp()->dump(str);
@ -1636,7 +1638,6 @@ const char* AstMemberSel::broken() const {
} }
void AstMethodCall::dump(std::ostream& str) const { void AstMethodCall::dump(std::ostream& str) const {
this->AstNodeFTaskRef::dump(str); this->AstNodeFTaskRef::dump(str);
if (isStatement()) str << " [STMT]";
str << " -> "; str << " -> ";
if (taskp()) { if (taskp()) {
taskp()->dump(str); taskp()->dump(str);
@ -1705,7 +1706,7 @@ void AstPrintTimeScale::dump(std::ostream& str) const {
str << " " << timeunit(); 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 { void AstTime::dump(std::ostream& str) const {
this->AstNodeTermop::dump(str); this->AstNodeTermop::dump(str);
str << " " << timeunit(); str << " " << timeunit();
@ -1908,10 +1909,10 @@ void AstPackageImport::cloneRelink() {
if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep();
} }
void AstPatMember::dump(std::ostream& str) const { void AstPatMember::dump(std::ostream& str) const {
this->AstNodeMath::dump(str); this->AstNodeExpr::dump(str);
if (isDefault()) str << " [DEFAULT]"; 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 { void AstSel::dump(std::ostream& str) const {
this->AstNodeTriop::dump(str); this->AstNodeTriop::dump(str);
if (declRange().ranged()) { if (declRange().ranged()) {
@ -2018,7 +2019,7 @@ void AstVarScope::dump(std::ostream& str) const {
} }
} }
void AstNodeVarRef::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()); if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
str << " " << access().arrow() << " "; str << " " << access().arrow() << " ";
} }
@ -2086,7 +2087,7 @@ void AstScope::dump(std::ostream& str) const {
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]"; str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
} }
void AstScopeName::dump(std::ostream& str) const { void AstScopeName::dump(std::ostream& str) const {
this->AstNodeMath::dump(str); this->AstNodeExpr::dump(str);
if (dpiExport()) str << " [DPIEX]"; if (dpiExport()) str << " [DPIEX]";
if (forFormat()) str << " [FMT]"; if (forFormat()) str << " [FMT]";
} }
@ -2145,7 +2146,7 @@ void AstActive::cloneRelink() {
if (m_sensesp->clonep()) m_sensesp = m_sensesp->clonep(); if (m_sensesp->clonep()) m_sensesp = m_sensesp->clonep();
} }
void AstNodeFTaskRef::dump(std::ostream& str) const { void AstNodeFTaskRef::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str); this->AstNodeExpr::dump(str);
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
str << " -> "; str << " -> ";
if (dotted() != "") str << ".=" << dotted() << " "; if (dotted() != "") str << ".=" << dotted() << " ";
@ -2248,8 +2249,15 @@ void AstCFunc::dump(std::ostream& str) const {
if (isVirtual()) str << " [VIRT]"; if (isVirtual()) str << " [VIRT]";
if (isCoroutine()) str << " [CORO]"; 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 { void AstCAwait::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str); this->AstNodeUniop::dump(str);
if (sensesp()) { if (sensesp()) {
str << " => "; str << " => ";
sensesp()->dump(str); sensesp()->dump(str);
@ -2265,7 +2273,7 @@ int AstCMethodHard::instrCount() const {
return INSTR_COUNT_LD; return INSTR_COUNT_LD;
} }
} }
return AstNodeStmt::instrCount(); return 0;
} }
const char* AstCFunc::broken() const { const char* AstCFunc::broken() const {
BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); BROKEN_RTN((m_scopep && !m_scopep->brokeExists()));

View File

@ -112,13 +112,14 @@ public:
rootFuncp->name(m_basename); rootFuncp->name(m_basename);
for (AstCFunc* const funcp : m_newFunctions) { for (AstCFunc* const funcp : m_newFunctions) {
AstCCall* const callp = new AstCCall{m_modp->fileline(), funcp}; AstCCall* const callp = new AstCCall{m_modp->fileline(), funcp};
callp->dtypeSetVoid();
if (m_type.isClass()) { if (m_type.isClass()) {
callp->argTypes("vlSymsp"); callp->argTypes("vlSymsp");
} else { } else {
if (m_type.isCoverage()) callp->argTypes("first"); if (m_type.isCoverage()) callp->argTypes("first");
callp->selfPointer("this"); callp->selfPointer("this");
} }
rootFuncp->addStmtsp(callp); rootFuncp->addStmtsp(callp->makeStmt());
} }
} }
} }

View File

@ -16,9 +16,9 @@
// V3Cast's Transformations: // V3Cast's Transformations:
// //
// Each module: // 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. // and this isn't, cast to 32 bits.
// Likewise for 64 bit operators. // Likewise for 64 bit expressions.
// //
// C++ rules: // C++ rules:
// Integral promotions allow conversion to larger int. Unsigned is only // Integral promotions allow conversion to larger int. Unsigned is only
@ -158,7 +158,8 @@ private:
} }
void visit(AstVarRef* nodep) override { void visit(AstVarRef* nodep) override {
const AstNode* const backp = nodep->backp(); 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) && !VN_IS(backp, ArraySel) && !VN_IS(backp, RedXor)
&& (nodep->varp()->basicp() && !nodep->varp()->basicp()->isTriggerVec() && (nodep->varp()->basicp() && !nodep->varp()->basicp()->isTriggerVec()
&& !nodep->varp()->basicp()->isForkSync()) && !nodep->varp()->basicp()->isForkSync())

View File

@ -697,7 +697,7 @@ private:
void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); } void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); }
void visit(AstAssignW* 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(AstConst*) override {}
void visit(AstReplicate* nodep) override { iterateChildren(nodep); } void visit(AstReplicate* nodep) override { iterateChildren(nodep); }
void visit(AstConcat* nodep) override { iterateChildren(nodep); } void visit(AstConcat* nodep) override { iterateChildren(nodep); }
@ -721,7 +721,7 @@ private:
//-------------------- //--------------------
// Default // Default
void visit(AstNodeMath* nodep) override { void visit(AstNodeExpr* nodep) override {
setNodeHazard(nodep); setNodeHazard(nodep);
iterateChildren(nodep); iterateChildren(nodep);
} }

View File

@ -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(AstNodeStmt* nodep) override {} // Short circuit
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }

View File

@ -16,7 +16,7 @@
// V3Clean's Transformations: // V3Clean's Transformations:
// //
// Each module: // 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. // and the operand is dirty, insert a CLEAN node.
// Resize operands to C++ 32/64/wide types. // Resize operands to C++ 32/64/wide types.
// Copy all width() values to widthMin() so RANGE, etc can still see orig widths // Copy all width() values to widthMin() so RANGE, etc can still see orig widths
@ -207,7 +207,7 @@ private:
operandQuadop(nodep); operandQuadop(nodep);
setClean(nodep, nodep->cleanOut()); setClean(nodep, nodep->cleanOut());
} }
void visit(AstNodeMath* nodep) override { void visit(AstNodeExpr* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
computeCppWidth(nodep); computeCppWidth(nodep);
setClean(nodep, nodep->cleanOut()); setClean(nodep, nodep->cleanOut());

View File

@ -69,7 +69,9 @@ class CombineVisitor final : VNVisitor {
if (funcp->emptyBody()) { if (funcp->emptyBody()) {
// Delete call sites // Delete call sites
for (AstCCall* const callp : m_callSites(funcp)) { 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(); m_callSites(funcp).clear();
// Remove from list // Remove from list

View File

@ -42,7 +42,7 @@ static void makeVlToString(AstClass* nodep) {
funcp->isConst(false); funcp->isConst(false);
funcp->isStatic(false); funcp->isStatic(false);
funcp->protect(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(); exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
nodep->addStmtsp(funcp); nodep->addStmtsp(funcp);
@ -55,7 +55,7 @@ static void makeVlToString(AstIface* nodep) {
funcp->isConst(false); funcp->isConst(false);
funcp->isStatic(false); funcp->isStatic(false);
funcp->protect(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(); exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
nodep->addStmtsp(funcp); nodep->addStmtsp(funcp);
@ -66,7 +66,7 @@ static void makeToString(AstClass* nodep) {
funcp->isStatic(false); funcp->isStatic(false);
funcp->protect(false); funcp->protect(false);
AstNode* const exprp 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(); exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
nodep->addStmtsp(funcp); nodep->addStmtsp(funcp);

View File

@ -2602,6 +2602,10 @@ private:
} }
m_selp = nullptr; m_selp = nullptr;
} }
void visit(AstCAwait* nodep) override {
m_hasJumpDelay = true;
iterateChildren(nodep);
}
void visit(AstNodeVarRef* nodep) override { void visit(AstNodeVarRef* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
UASSERT_OBJ(nodep->varp(), nodep, "Not linked"); UASSERT_OBJ(nodep->varp(), nodep, "Not linked");
@ -2682,7 +2686,7 @@ private:
} }
// void visit(AstCvtPackString* nodep) override { // 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". // Someday if lower is constant, convert to quoted "string".
bool onlySenItemInSenTree(AstSenItem* nodep) { bool onlySenItemInSenTree(AstSenItem* nodep) {
@ -3166,6 +3170,11 @@ private:
if (m_doNConst) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); 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 // Simplify
void visit(AstBasicDType* nodep) override { void visit(AstBasicDType* nodep) override {
iterateChildren(nodep); iterateChildren(nodep);
@ -3232,6 +3241,7 @@ private:
//----- //-----
// clang-format off // clang-format off
TREE_SKIP_VISIT("ArraySel"); TREE_SKIP_VISIT("ArraySel");
TREE_SKIP_VISIT("CAwait");
//----- //-----
// "AstNODETYPE { # bracket not paren // "AstNODETYPE { # bracket not paren

View File

@ -100,7 +100,7 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
//-------------------- //--------------------
void visit(AstNodeMath*) override {} // Accelerate void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:

View File

@ -485,9 +485,8 @@ private:
AstIf* const ifp = new AstIf{flp, dlyRef(VAccess::READ)}; AstIf* const ifp = new AstIf{flp, dlyRef(VAccess::READ)};
postp->addStmtsp(ifp); postp->addStmtsp(ifp);
AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "fire"}; AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "fire"};
callp->statement(true);
callp->dtypeSetVoid(); callp->dtypeSetVoid();
ifp->addThensp(callp); ifp->addThensp(callp->makeStmt());
} }
AstActive* const activep = createActive(nodep); AstActive* const activep = createActive(nodep);
@ -501,8 +500,7 @@ private:
AstCMethodHard* const callp AstCMethodHard* const callp
= new AstCMethodHard{flp, nodep->operandp()->unlinkFrBack(), "fire"}; = new AstCMethodHard{flp, nodep->operandp()->unlinkFrBack(), "fire"};
callp->dtypeSetVoid(); callp->dtypeSetVoid();
callp->statement(true); nodep->replaceWith(callp->makeStmt());
nodep->replaceWith(callp);
} }
nodep->deleteTree(); nodep->deleteTree();
} }

View File

@ -107,16 +107,10 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
void visit(AstNodeStmt* nodep) override { void visit(AstNodeStmt* nodep) override { visitStmt(nodep); }
if (!nodep->isStatement()) {
iterateChildren(nodep);
} else {
visitStmt(nodep);
}
}
// Operators // Operators
void visit(AstNodeTermop* nodep) override {} 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. // We have some operator defines that use 2 parens, so += 2.
{ {
VL_RESTORER(m_depth); VL_RESTORER(m_depth);

View File

@ -47,7 +47,7 @@ private:
// METHODS // METHODS
AstCFunc* createDeepFunc(AstNode* nodep) { AstCFunc* createDeepFunc(AstNodeStmt* nodep) {
VNRelinker relinkHandle; VNRelinker relinkHandle;
nodep->unlinkFrBack(&relinkHandle); nodep->unlinkFrBack(&relinkHandle);
// Create sub function // Create sub function
@ -61,12 +61,13 @@ private:
scopep->addBlocksp(funcp); scopep->addBlocksp(funcp);
// Call sub function at the point where the body was removed from // Call sub function at the point where the body was removed from
AstCCall* const callp = new AstCCall(nodep->fileline(), funcp); AstCCall* const callp = new AstCCall(nodep->fileline(), funcp);
callp->dtypeSetVoid();
if (VN_IS(m_modp, Class)) { if (VN_IS(m_modp, Class)) {
funcp->argTypes(EmitCBaseVisitor::symClassVar()); funcp->argTypes(EmitCBaseVisitor::symClassVar());
callp->argTypes("vlSymsp"); callp->argTypes("vlSymsp");
} }
UINFO(6, " New " << callp << endl); UINFO(6, " New " << callp << endl);
relinkHandle.relink(callp); relinkHandle.relink(callp->makeStmt());
// Done // Done
return funcp; return funcp;
} }
@ -91,10 +92,10 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
void visitStmt(AstNodeStmt* nodep) { void visit(AstStmtExpr* nodep) override {} // Stop recursion after introducing new function
void visit(AstNodeStmt* nodep) override {
m_depth++; m_depth++;
if (m_depth > v3Global.opt.compLimitBlocks() if (m_depth > v3Global.opt.compLimitBlocks()) { // Already done
&& !VN_IS(nodep, NodeCCall)) { // Already done
UINFO(4, "DeepBlocks " << m_depth << " " << nodep << endl); UINFO(4, "DeepBlocks " << m_depth << " " << nodep << endl);
const AstNode* const backp = nodep->backp(); // Only for debug const AstNode* const backp = nodep->backp(); // Only for debug
if (debug() >= 9) backp->dumpTree(cout, "- pre : "); if (debug() >= 9) backp->dumpTree(cout, "- pre : ");
@ -107,15 +108,8 @@ private:
} }
m_depth--; 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(AstVar*) override {} // Don't hit varrefs under vars
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }

View File

@ -152,15 +152,20 @@ private:
} }
} }
AstNode* const returnp = new AstCReturn( AstCCall* const callp = new AstCCall{funcp->fileline(), funcp, argsp};
funcp->fileline(), 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) { if (moreOfSame) {
AstIf* const ifp = new AstIf( AstIf* const ifp = new AstIf(
funcp->fileline(), funcp->fileline(),
new AstEq( new AstEq(
funcp->fileline(), new AstCMath(funcp->fileline(), "this", 64), funcp->fileline(), new AstCExpr(funcp->fileline(), "this", 64),
new AstCMath(funcp->fileline(), new AstCExpr(funcp->fileline(),
string("&(") + funcp->scopep()->nameVlSym() + ")", string("&(") + funcp->scopep()->nameVlSym() + ")",
64)), 64)),
returnp); returnp);

View File

@ -870,7 +870,7 @@ public:
// DfgVertex subclasses // DfgVertex subclasses
#include "V3DfgVertices.h" #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" #include "V3Dfg__gen_auto_classes.h"
DfgVertexVar* DfgGraph::varVerticesBeginp() const { DfgVertexVar* DfgGraph::varVerticesBeginp() const {

View File

@ -39,7 +39,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
namespace { 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 // automatically. For the few special cases, we provide specializations below
template <typename Vertex, typename Node> template <typename Vertex, typename Node>
Vertex* makeVertex(const Node* nodep, DfgGraph& dfg) { 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 // 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 // Short-circuiting if something was already unhandled
if (!m_foundUnhandled) { if (!m_foundUnhandled) {
// Impure nodes cannot be represented // Impure nodes cannot be represented

View File

@ -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 // 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 // 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), // recursion stops when we reach a DfgVertex representing a storage location (e.g.: DfgVarPacked),
@ -40,7 +40,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
namespace { 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 // automatically. For the few special cases, we provide specializations below
template <typename Node, typename Vertex, typename... Ops> template <typename Node, typename Vertex, typename... Ops>
Node* makeNode(const Vertex* vtxp, Ops... ops) { Node* makeNode(const Vertex* vtxp, Ops... ops) {
@ -55,8 +55,8 @@ Node* makeNode(const Vertex* vtxp, Ops... ops) {
// Vertices needing special conversion // Vertices needing special conversion
template <> template <>
AstCountOnes* makeNode<AstCountOnes, DfgCountOnes, AstNodeMath*>( // AstCountOnes* makeNode<AstCountOnes, DfgCountOnes, AstNodeExpr*>( //
const DfgCountOnes* vtxp, AstNodeMath* op1) { const DfgCountOnes* vtxp, AstNodeExpr* op1) {
AstCountOnes* const nodep = new AstCountOnes{vtxp->fileline(), op1}; AstCountOnes* const nodep = new AstCountOnes{vtxp->fileline(), op1};
// Set dtype same as V3Width // Set dtype same as V3Width
const int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1; const int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1;
@ -65,32 +65,32 @@ AstCountOnes* makeNode<AstCountOnes, DfgCountOnes, AstNodeMath*>( //
} }
template <> template <>
AstExtend* makeNode<AstExtend, DfgExtend, AstNodeMath*>( // AstExtend* makeNode<AstExtend, DfgExtend, AstNodeExpr*>( //
const DfgExtend* vtxp, AstNodeMath* op1) { const DfgExtend* vtxp, AstNodeExpr* op1) {
return new AstExtend{vtxp->fileline(), op1, static_cast<int>(vtxp->width())}; return new AstExtend{vtxp->fileline(), op1, static_cast<int>(vtxp->width())};
} }
template <> template <>
AstExtendS* makeNode<AstExtendS, DfgExtendS, AstNodeMath*>( // AstExtendS* makeNode<AstExtendS, DfgExtendS, AstNodeExpr*>( //
const DfgExtendS* vtxp, AstNodeMath* op1) { const DfgExtendS* vtxp, AstNodeExpr* op1) {
return new AstExtendS{vtxp->fileline(), op1, static_cast<int>(vtxp->width())}; return new AstExtendS{vtxp->fileline(), op1, static_cast<int>(vtxp->width())};
} }
template <> template <>
AstShiftL* makeNode<AstShiftL, DfgShiftL, AstNodeMath*, AstNodeMath*>( // AstShiftL* makeNode<AstShiftL, DfgShiftL, AstNodeExpr*, AstNodeExpr*>( //
const DfgShiftL* vtxp, AstNodeMath* op1, AstNodeMath* op2) { const DfgShiftL* vtxp, AstNodeExpr* op1, AstNodeExpr* op2) {
return new AstShiftL{vtxp->fileline(), op1, op2, static_cast<int>(vtxp->width())}; return new AstShiftL{vtxp->fileline(), op1, op2, static_cast<int>(vtxp->width())};
} }
template <> template <>
AstShiftR* makeNode<AstShiftR, DfgShiftR, AstNodeMath*, AstNodeMath*>( // AstShiftR* makeNode<AstShiftR, DfgShiftR, AstNodeExpr*, AstNodeExpr*>( //
const DfgShiftR* vtxp, AstNodeMath* op1, AstNodeMath* op2) { const DfgShiftR* vtxp, AstNodeExpr* op1, AstNodeExpr* op2) {
return new AstShiftR{vtxp->fileline(), op1, op2, static_cast<int>(vtxp->width())}; return new AstShiftR{vtxp->fileline(), op1, op2, static_cast<int>(vtxp->width())};
} }
template <> template <>
AstShiftRS* makeNode<AstShiftRS, DfgShiftRS, AstNodeMath*, AstNodeMath*>( // AstShiftRS* makeNode<AstShiftRS, DfgShiftRS, AstNodeExpr*, AstNodeExpr*>( //
const DfgShiftRS* vtxp, AstNodeMath* op1, AstNodeMath* op2) { const DfgShiftRS* vtxp, AstNodeExpr* op1, AstNodeExpr* op2) {
return new AstShiftRS{vtxp->fileline(), op1, op2, static_cast<int>(vtxp->width())}; return new AstShiftRS{vtxp->fileline(), op1, op2, static_cast<int>(vtxp->width())};
} }
@ -98,22 +98,22 @@ AstShiftRS* makeNode<AstShiftRS, DfgShiftRS, AstNodeMath*, AstNodeMath*>( //
// Currently unhandled nodes - see corresponding AstToDfg functions // Currently unhandled nodes - see corresponding AstToDfg functions
// LCOV_EXCL_START // LCOV_EXCL_START
template <> template <>
AstCCast* makeNode<AstCCast, DfgCCast, AstNodeMath*>(const DfgCCast* vtxp, AstNodeMath*) { AstCCast* makeNode<AstCCast, DfgCCast, AstNodeExpr*>(const DfgCCast* vtxp, AstNodeExpr*) {
vtxp->v3fatalSrc("not implemented"); vtxp->v3fatalSrc("not implemented");
} }
template <> template <>
AstAtoN* makeNode<AstAtoN, DfgAtoN, AstNodeMath*>(const DfgAtoN* vtxp, AstNodeMath*) { AstAtoN* makeNode<AstAtoN, DfgAtoN, AstNodeExpr*>(const DfgAtoN* vtxp, AstNodeExpr*) {
vtxp->v3fatalSrc("not implemented"); vtxp->v3fatalSrc("not implemented");
} }
template <> template <>
AstCompareNN* AstCompareNN*
makeNode<AstCompareNN, DfgCompareNN, AstNodeMath*, AstNodeMath*>(const DfgCompareNN* vtxp, makeNode<AstCompareNN, DfgCompareNN, AstNodeExpr*, AstNodeExpr*>(const DfgCompareNN* vtxp,
AstNodeMath*, AstNodeMath*) { AstNodeExpr*, AstNodeExpr*) {
vtxp->v3fatalSrc("not implemented"); vtxp->v3fatalSrc("not implemented");
} }
template <> template <>
AstSliceSel* makeNode<AstSliceSel, DfgSliceSel, AstNodeMath*, AstNodeMath*, AstNodeMath*>( AstSliceSel* makeNode<AstSliceSel, DfgSliceSel, AstNodeExpr*, AstNodeExpr*, AstNodeExpr*>(
const DfgSliceSel* vtxp, AstNodeMath*, AstNodeMath*, AstNodeMath*) { const DfgSliceSel* vtxp, AstNodeExpr*, AstNodeExpr*, AstNodeExpr*) {
vtxp->v3fatalSrc("not implemented"); vtxp->v3fatalSrc("not implemented");
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -130,7 +130,7 @@ class DfgToAstVisitor final : DfgVisitor {
AstModule* const m_modp; // The parent/result module AstModule* const m_modp; // The parent/result module
V3DfgOptimizationContext& m_ctx; // The optimization context for stats 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 // Map from DfgVertex to the AstVar holding the value of that DfgVertex after conversion
std::unordered_map<const DfgVertex*, AstVar*> m_resultVars; std::unordered_map<const DfgVertex*, AstVar*> m_resultVars;
// Map from an AstVar, to the canonical AstVar that can be substituted for that AstVar // 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; return varp;
} }
AstNodeMath* convertDfgVertexToAstNodeMath(DfgVertex* vtxp) { AstNodeExpr* convertDfgVertexToAstNodeExpr(DfgVertex* vtxp) {
UASSERT_OBJ(!m_resultp, vtxp, "Result already computed"); UASSERT_OBJ(!m_resultp, vtxp, "Result already computed");
iterate(vtxp); iterate(vtxp);
UASSERT_OBJ(m_resultp, vtxp, "Missing result"); UASSERT_OBJ(m_resultp, vtxp, "Missing result");
AstNodeMath* const resultp = m_resultp; AstNodeExpr* const resultp = m_resultp;
m_resultp = nullptr; m_resultp = nullptr;
return resultp; return resultp;
} }
@ -232,11 +232,11 @@ class DfgToAstVisitor final : DfgVisitor {
return false; return false;
} }
AstNodeMath* convertSource(DfgVertex* vtxp) { AstNodeExpr* convertSource(DfgVertex* vtxp) {
if (inlineVertex(*vtxp)) { if (inlineVertex(*vtxp)) {
// Inlined vertices are simply recursively converted // Inlined vertices are simply recursively converted
UASSERT_OBJ(vtxp->hasSinks(), vtxp, "Must have one sink: " << vtxp->typeName()); UASSERT_OBJ(vtxp->hasSinks(), vtxp, "Must have one sink: " << vtxp->typeName());
return convertDfgVertexToAstNodeMath(vtxp); return convertDfgVertexToAstNodeExpr(vtxp);
} else { } else {
// Vertices that are not inlined need a variable, just return a reference // Vertices that are not inlined need a variable, just return a reference
return new AstVarRef{vtxp->fileline(), getResultVar(vtxp), VAccess::READ}; return new AstVarRef{vtxp->fileline(), getResultVar(vtxp), VAccess::READ};
@ -249,14 +249,14 @@ class DfgToAstVisitor final : DfgVisitor {
}; };
if (dfgVarp->isDrivenFullyByDfg()) { if (dfgVarp->isDrivenFullyByDfg()) {
// Whole variable is driven. Render driver and assign directly to whole variable. // 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); addResultEquation(dfgVarp->driverFileLine(0), wRef(), rhsp);
} else { } else {
// Variable is driven partially. Render each driver as a separate assignment. // Variable is driven partially. Render each driver as a separate assignment.
dfgVarp->forEachSourceEdge([&](const DfgEdge& edge, size_t idx) { dfgVarp->forEachSourceEdge([&](const DfgEdge& edge, size_t idx) {
UASSERT_OBJ(edge.sourcep(), dfgVarp, "Should have removed undriven sources"); UASSERT_OBJ(edge.sourcep(), dfgVarp, "Should have removed undriven sources");
// Render the rhs expression // Render the rhs expression
AstNodeMath* const rhsp = convertDfgVertexToAstNodeMath(edge.sourcep()); AstNodeExpr* const rhsp = convertDfgVertexToAstNodeExpr(edge.sourcep());
// Create select LValue // Create select LValue
FileLine* const flp = dfgVarp->driverFileLine(idx); FileLine* const flp = dfgVarp->driverFileLine(idx);
AstConst* const lsbp = new AstConst{flp, dfgVarp->driverLsb(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) { dfgVarp->forEachSourceEdge([&](const DfgEdge& edge, size_t idx) {
UASSERT_OBJ(edge.sourcep(), dfgVarp, "Should have removed undriven sources"); UASSERT_OBJ(edge.sourcep(), dfgVarp, "Should have removed undriven sources");
// Render the rhs expression // Render the rhs expression
AstNodeMath* const rhsp = convertDfgVertexToAstNodeMath(edge.sourcep()); AstNodeExpr* const rhsp = convertDfgVertexToAstNodeExpr(edge.sourcep());
// Create select LValue // Create select LValue
FileLine* const flp = dfgVarp->driverFileLine(idx); FileLine* const flp = dfgVarp->driverFileLine(idx);
AstVarRef* const refp = new AstVarRef{flp, dfgVarp->varp(), VAccess::WRITE}; AstVarRef* const refp = new AstVarRef{flp, dfgVarp->varp(), VAccess::WRITE};
@ -334,7 +334,7 @@ class DfgToAstVisitor final : DfgVisitor {
void visit(DfgSel* vtxp) override { void visit(DfgSel* vtxp) override {
FileLine* const flp = vtxp->fileline(); 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 lsbp = new AstConst{flp, vtxp->lsb()};
AstConst* const widthp = new AstConst{flp, vtxp->width()}; AstConst* const widthp = new AstConst{flp, vtxp->width()};
m_resultp = new AstSel{flp, fromp, lsbp, widthp}; m_resultp = new AstSel{flp, fromp, lsbp, widthp};
@ -342,8 +342,8 @@ class DfgToAstVisitor final : DfgVisitor {
void visit(DfgMux* vtxp) override { void visit(DfgMux* vtxp) override {
FileLine* const flp = vtxp->fileline(); FileLine* const flp = vtxp->fileline();
AstNodeMath* const fromp = convertSource(vtxp->fromp()); AstNodeExpr* const fromp = convertSource(vtxp->fromp());
AstNodeMath* const lsbp = convertSource(vtxp->lsbp()); AstNodeExpr* const lsbp = convertSource(vtxp->lsbp());
AstConst* const widthp = new AstConst{flp, vtxp->width()}; AstConst* const widthp = new AstConst{flp, vtxp->width()};
m_resultp = new AstSel{flp, fromp, lsbp, widthp}; m_resultp = new AstSel{flp, fromp, lsbp, widthp};
} }
@ -415,9 +415,9 @@ class DfgToAstVisitor final : DfgVisitor {
++m_ctx.m_intermediateVars; ++m_ctx.m_intermediateVars;
FileLine* const flp = vtxp->fileline(); FileLine* const flp = vtxp->fileline();
// Just render the logic // Just render the logic
AstNodeMath* const rhsp = convertDfgVertexToAstNodeMath(vtxp); AstNodeExpr* const rhsp = convertDfgVertexToAstNodeExpr(vtxp);
// The lhs is the temporary // 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 // Add assignment of the value to the variable
addResultEquation(flp, lhsp, rhsp); addResultEquation(flp, lhsp, rhsp);
} }

View File

@ -47,7 +47,7 @@ class DataflowExtractVisitor final : public VNVisitor {
// Expressions considered for extraction as separate assignment to gain more opportunities for // Expressions considered for extraction as separate assignment to gain more opportunities for
// optimization, together with the list of variables they read. // optimization, together with the list of variables they read.
using Candidates = std::vector<std::pair<AstNodeMath*, std::vector<const AstVar*>>>; using Candidates = std::vector<std::pair<AstNodeExpr*, std::vector<const AstVar*>>>;
// Expressions considered for extraction. All the candidates are pure expressions. // Expressions considered for extraction. All the candidates are pure expressions.
AstUser4Allocator<AstNodeModule, Candidates> m_extractionCandidates; AstUser4Allocator<AstNodeModule, Candidates> m_extractionCandidates;
@ -65,7 +65,7 @@ class DataflowExtractVisitor final : public VNVisitor {
// Node considered for extraction as a combinational equation. Trace variable usage/purity. // Node considered for extraction as a combinational equation. Trace variable usage/purity.
void iterateExtractionCandidate(AstNode* nodep) { 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)"); "Should not try to extract nested expressions (only root expressions)");
// Simple VarRefs should not be extracted, as they only yield trivial assignments. // 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; if (m_readVars.empty()) return;
// Add to candidate list // 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 // VISIT methods
@ -110,7 +110,7 @@ class DataflowExtractVisitor final : public VNVisitor {
if (!VN_IS(modp, Module)) continue; if (!VN_IS(modp, Module)) continue;
for (const auto& pair : m_extractionCandidates(modp)) { 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 // Do not extract expressions without any variable references
if (pair.second.empty()) continue; if (pair.second.empty()) continue;
@ -204,7 +204,7 @@ class DataflowExtractVisitor final : public VNVisitor {
m_inForceReleaseLhs = false; m_inForceReleaseLhs = false;
} }
void visit(AstNodeMath* nodep) override { iterateChildrenConst(nodep); } void visit(AstNodeExpr* nodep) override { iterateChildrenConst(nodep); }
void visit(AstNodeVarRef* nodep) override { void visit(AstNodeVarRef* nodep) override {
if (nodep->access().isWriteOrRW()) { if (nodep->access().isWriteOrRW()) {
@ -220,7 +220,7 @@ class DataflowExtractVisitor final : public VNVisitor {
void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
// Conservatively assume unhandled nodes are impure. This covers all AstNodeFTaskRef // 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; m_impure = true;
// Still need to gather all references/force/release, etc. // Still need to gather all references/force/release, etc.
iterateChildrenConst(nodep); iterateChildrenConst(nodep);

View File

@ -32,7 +32,7 @@ constexpr int VL_VALUE_STRING_MAX_WIDTH = 8192;
//###################################################################### //######################################################################
// EmitCFunc // 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)? // Can we put out a simple (A + B) instead of VL_ADD_III(A,B)?
if (nodep->emitSimpleOperator() == "") return false; if (nodep->emitSimpleOperator() == "") return false;
if (nodep->isWide()) return false; if (nodep->isWide()) return false;
@ -433,12 +433,7 @@ void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPoint
iterate(subnodep); iterate(subnodep);
comma = true; comma = true;
} }
if (VN_IS(nodep->backp(), NodeMath) || VN_IS(nodep->backp(), CReturn)) { puts(")");
// We should have a separate CCall for math and statement usage, but...
puts(")");
} else {
puts(");\n");
}
} }
void EmitCFunc::emitDereference(const string& pointer) { void EmitCFunc::emitDereference(const string& pointer) {

View File

@ -110,15 +110,15 @@ public:
void reset() { m_emitted.clear(); } void reset() { m_emitted.clear(); }
}; };
//###################################################################### // ######################################################################
// Emit statements and math operators // Emit statements and expressions
class EmitCFunc VL_NOT_FINAL : public EmitCConstInit { class EmitCFunc VL_NOT_FINAL : public EmitCConstInit {
private: private:
AstVarRef* m_wideTempRefp = nullptr; // Variable that _WW macros should be setting AstVarRef* m_wideTempRefp = nullptr; // Variable that _WW macros should be setting
int m_labelNum = 0; // Next label number int m_labelNum = 0; // Next label number
int m_splitSize = 0; // # of cfunc nodes placed into output file 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 bool m_emitConstInit = false; // Emitting constant initializer
// State associated with processing $display style string formatting // 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, void displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const string& vfmt, bool ignore,
char fmtLetter); char fmtLetter);
bool emitSimpleOk(AstNodeMath* nodep); bool emitSimpleOk(AstNodeExpr* nodep);
void emitIQW(AstNode* nodep) { void emitIQW(AstNode* nodep) {
// Other abbrevs: "C"har, "S"hort, "F"loat, "D"ouble, stri"N"g // Other abbrevs: "C"har, "S"hort, "F"loat, "D"ouble, stri"N"g
puts(nodep->dtypep()->charIQWN()); puts(nodep->dtypep()->charIQWN());
@ -330,7 +330,7 @@ public:
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
puts(", "); puts(", ");
} else if (nodep->isWide() && VN_IS(nodep->lhsp(), VarRef) // } 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(), CMethodHard) //
&& !VN_IS(nodep->rhsp(), VarRef) // && !VN_IS(nodep->rhsp(), VarRef) //
&& !VN_IS(nodep->rhsp(), AssocSel) // && !VN_IS(nodep->rhsp(), AssocSel) //
@ -415,7 +415,6 @@ public:
void visit(AstCAwait* nodep) override { void visit(AstCAwait* nodep) override {
puts("co_await "); puts("co_await ");
iterate(nodep->exprp()); iterate(nodep->exprp());
if (nodep->isStatement()) puts(";\n");
} }
void visit(AstCNew* nodep) override { void visit(AstCNew* nodep) override {
bool comma = false; bool comma = false;
@ -446,10 +445,6 @@ public:
comma = true; comma = true;
} }
puts(")"); 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(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); }
void visit(AstWith* nodep) override { void visit(AstWith* nodep) override {
@ -804,6 +799,10 @@ public:
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());
puts(")"); puts(")");
} }
void visit(AstStmtExpr* node) override {
iterate(node->exprp());
puts(";\n");
}
void visit(AstJumpBlock* nodep) override { void visit(AstJumpBlock* nodep) override {
nodep->labelNum(++m_labelNum); nodep->labelNum(++m_labelNum);
puts("{\n"); // Make it visually obvious label jumps outside these puts("{\n"); // Make it visually obvious label jumps outside these
@ -931,7 +930,7 @@ public:
putbs(""); putbs("");
iterateAndNextNull(nodep->exprsp()); iterateAndNextNull(nodep->exprsp());
} }
void visit(AstCMath* nodep) override { void visit(AstCExpr* nodep) override {
putbs(""); putbs("");
iterateAndNextNull(nodep->exprsp()); iterateAndNextNull(nodep->exprsp());
} }

View File

@ -26,8 +26,8 @@
VL_DEFINE_DEBUG_FUNCTIONS; VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### // ######################################################################
// Emit statements and math operators // Emit statements and expressions
class EmitMk final { class EmitMk final {
public: public:

View File

@ -28,8 +28,8 @@
VL_DEFINE_DEBUG_FUNCTIONS; VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### // ######################################################################
// Emit statements and math operators // Emit statements and expressions
class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
// MEMBERS // MEMBERS
@ -381,6 +381,10 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
} }
void visit(AstStop* nodep) override { putfs(nodep, "$stop;\n"); } void visit(AstStop* nodep) override { putfs(nodep, "$stop;\n"); }
void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\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 { void visit(AstNodeSimpleText* nodep) override {
if (nodep->tracking() || m_trackText) { if (nodep->tracking() || m_trackText) {
puts(nodep->text()); puts(nodep->text());
@ -405,8 +409,8 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
iterateAndNextConstNull(nodep->exprsp()); iterateAndNextConstNull(nodep->exprsp());
puts(");\n"); puts(");\n");
} }
void visit(AstCMath* nodep) override { void visit(AstCExpr* nodep) override {
putfs(nodep, "$_CMATH("); putfs(nodep, "$_CEXPR(");
iterateAndNextConstNull(nodep->exprsp()); iterateAndNextConstNull(nodep->exprsp());
puts(");\n"); puts(");\n");
} }

View File

@ -28,8 +28,8 @@
VL_DEFINE_DEBUG_FUNCTIONS; VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### // ######################################################################
// Emit statements and math operators // Emit statements and expressions
class EmitXmlFileVisitor final : public VNVisitor { class EmitXmlFileVisitor final : public VNVisitor {
// NODE STATE // NODE STATE

View File

@ -828,10 +828,6 @@ private:
void visit(AstNodeStmt* nodep) override { void visit(AstNodeStmt* nodep) override {
if (nodep->user1SetOnce()) return; // Process once if (nodep->user1SetOnce()) return; // Process once
if (!nodep->isStatement()) {
iterateChildren(nodep);
return;
}
m_stmtp = nodep; m_stmtp = nodep;
iterateChildren(nodep); iterateChildren(nodep);
m_stmtp = nullptr; m_stmtp = nullptr;

View File

@ -104,7 +104,7 @@ class ForceConvertVisitor final : public VNVisitor {
AstVarRef* const lhsp = new AstVarRef{flp, m_enVscp, VAccess::WRITE}; AstVarRef* const lhsp = new AstVarRef{flp, m_enVscp, VAccess::WRITE};
V3Number zero{m_enVscp, m_enVscp->width()}; V3Number zero{m_enVscp, m_enVscp->width()};
zero.setAllBits0(); zero.setAllBits0();
AstNodeMath* const rhsp = new AstConst{flp, zero}; AstNodeExpr* const rhsp = new AstConst{flp, zero};
AstAssign* const assignp = new AstAssign{flp, lhsp, rhsp}; AstAssign* const assignp = new AstAssign{flp, lhsp, rhsp};
AstActive* const activep = new AstActive{ AstActive* const activep = new AstActive{
flp, "force-init", flp, "force-init",

View File

@ -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 { class GateOkVisitor final : public VNVisitor {
private: private:
@ -801,7 +801,7 @@ private:
// comparing AstActive nodes, which are very likely not to compare equals (and for the // 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, // 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 // 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 // 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 // identical instances (otherwise if writing the condition between 2 ifs don't really
// merge). // merge).

View File

@ -183,8 +183,8 @@ private:
} }
//------------------------------------------------------------ //------------------------------------------------------------
// AstNodeMath // AstNodeExpr
void visit(AstNodeMath* nodep) override { void visit(AstNodeExpr* nodep) override {
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {});
} }
void visit(AstConst* nodep) override { void visit(AstConst* nodep) override {

View File

@ -296,7 +296,7 @@ class HierBlockUsageCollectVisitor final : public VNVisitor {
if (nodep->isGParam() && nodep->overriddenParam()) m_gparams.push_back(nodep); 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); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:

View File

@ -691,7 +691,7 @@ private:
cellp->addIntfRefsp(new AstIntfRef(varlp->fileline(), alias)); cellp->addIntfRefsp(new AstIntfRef(varlp->fileline(), alias));
} }
//-------------------- //--------------------
void visit(AstNodeMath*) override {} // Accelerate void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNodeStmt*) override {} // Accelerate void visit(AstNodeStmt*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }

View File

@ -124,7 +124,7 @@ private:
} }
// Save some time // Save some time
void visit(AstNodeMath*) override {} void visit(AstNodeExpr*) override {}
void visit(AstNodeAssign*) override {} void visit(AstNodeAssign*) override {}
void visit(AstAlways*) override {} void visit(AstAlways*) override {}
@ -153,7 +153,7 @@ private:
} }
iterateChildren(nodep); iterateChildren(nodep);
} }
void visit(AstNodeMath*) override {} // Accelerate void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:
@ -473,7 +473,7 @@ private:
} }
//-------------------- //--------------------
void visit(AstNodeMath*) override {} // Accelerate void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:

View File

@ -441,7 +441,7 @@ private:
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
iterateChildren(nodep); 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 m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
iterateChildren(nodep); iterateChildren(nodep);
} }
@ -494,7 +494,7 @@ private:
} }
void visit(AstVar*) override {} // Accelerate void visit(AstVar*) override {} // Accelerate
void visit(AstNodeStmt*) override {} // Accelerate void visit(AstNodeStmt*) override {} // Accelerate
void visit(AstNodeMath*) override {} // Accelerate void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:

View File

@ -2915,6 +2915,7 @@ private:
outp = AstNode::addNext(outp, addp); outp = AstNode::addNext(outp, addp);
} }
newp = new AstSysIgnore(nodep->fileline(), outp); newp = new AstSysIgnore(nodep->fileline(), outp);
newp->dtypep(nodep->dtypep());
} }
nodep->replaceWith(newp); nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);

View File

@ -175,10 +175,6 @@ private:
m_insStmtp = nullptr; m_insStmtp = nullptr;
} }
void visit(AstNodeStmt* nodep) override { void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
iterateChildren(nodep);
return;
}
m_insMode = IM_BEFORE; m_insMode = IM_BEFORE;
m_insStmtp = nodep; m_insStmtp = nodep;
iterateChildren(nodep); iterateChildren(nodep);

View File

@ -499,7 +499,7 @@ private:
if (nodep->modp()->modPublic()) m_modp->modPublic(true); if (nodep->modp()->modPublic()) m_modp->modPublic(true);
//** No iteration for speed //** No iteration for speed
} }
void visit(AstNodeMath*) override {} // Accelerate void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:

View File

@ -1242,9 +1242,10 @@ AstActive* OrderProcess::processMoveOneLogic(const OrderLogicVertex* lvertexp,
scopep->addBlocksp(newFuncpr); scopep->addBlocksp(newFuncpr);
// Create top call to it // Create top call to it
AstCCall* const callp = new AstCCall{nodep->fileline(), newFuncpr}; AstCCall* const callp = new AstCCall{nodep->fileline(), newFuncpr};
callp->dtypeSetVoid();
// Where will we be adding the call? // Where will we be adding the call?
AstActive* const newActivep = new AstActive{nodep->fileline(), name, domainp}; AstActive* const newActivep = new AstActive{nodep->fileline(), name, domainp};
newActivep->addStmtsp(callp); newActivep->addStmtsp(callp->makeStmt());
if (!activep) { if (!activep) {
activep = newActivep; activep = newActivep;
} else { } else {

View File

@ -3186,8 +3186,9 @@ static void addThreadStartToExecGraph(AstExecGraph* const execGraphp,
} else { } else {
// The last will run on the main thread. // The last will run on the main thread.
AstCCall* const callp = new AstCCall(fl, funcp); AstCCall* const callp = new AstCCall(fl, funcp);
callp->dtypeSetVoid();
callp->argTypes("vlSelf, vlSymsp->__Vm_even_cycle__" + tag); callp->argTypes("vlSelf, vlSymsp->__Vm_even_cycle__" + tag);
execGraphp->addStmtsp(callp); execGraphp->addStmtsp(callp->makeStmt());
addStrStmt("Verilated::mtaskId(0);\n"); addStrStmt("Verilated::mtaskId(0);\n");
} }
} }

View File

@ -46,7 +46,7 @@ constexpr int STATIC_CONST_MIN_WIDTH = 256; // Minimum size to extract to stati
class PremitVisitor final : public VNVisitor { class PremitVisitor final : public VNVisitor {
private: private:
// NODE STATE // NODE STATE
// AstNodeMath::user() -> bool. True if iterated already // AstNodeExpr::user() -> bool. True if iterated already
// AstShiftL::user2() -> bool. True if converted to conditional // AstShiftL::user2() -> bool. True if converted to conditional
// AstShiftR::user2() -> bool. True if converted to conditional // AstShiftR::user2() -> bool. True if converted to conditional
// *::user3() -> Used when visiting AstNodeAssign // *::user3() -> Used when visiting AstNodeAssign
@ -56,6 +56,7 @@ private:
// STATE // STATE
AstCFunc* m_cfuncp = nullptr; // Current block AstCFunc* m_cfuncp = nullptr; // Current block
AstNode* m_stmtp = nullptr; // Current statement AstNode* m_stmtp = nullptr; // Current statement
AstCCall* m_callp = nullptr; // Current AstCCall
AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions
AstTraceInc* m_inTracep = 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 bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts
@ -89,8 +90,7 @@ private:
&& VN_AS(nodep->backp(), Sel)->widthp() == nodep) { && VN_AS(nodep->backp(), Sel)->widthp() == nodep) {
// AstSel::width must remain a constant // AstSel::width must remain a constant
} else if ((nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), ArraySel)) } else if ((nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), ArraySel))
|| ((VN_IS(m_stmtp, CCall) || VN_IS(m_stmtp, CStmt)) || ((m_callp || VN_IS(m_stmtp, CStmt)) && VN_IS(nodep, ArraySel))) {
&& VN_IS(nodep, ArraySel))) {
// ArraySel's are pointer refs, ignore // ArraySel's are pointer refs, ignore
} else { } else {
UINFO(4, "Cre Temp: " << nodep << endl); UINFO(4, "Cre Temp: " << nodep << endl);
@ -208,10 +208,6 @@ private:
m_stmtp = nullptr; m_stmtp = nullptr;
} }
void visit(AstNodeStmt* nodep) override { void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
iterateChildren(nodep);
return;
}
UINFO(4, " STMT " << nodep << endl); UINFO(4, " STMT " << nodep << endl);
startStatement(nodep); startStatement(nodep);
iterateChildren(nodep); iterateChildren(nodep);
@ -337,6 +333,11 @@ private:
} }
checkNode(nodep); checkNode(nodep);
} }
void visit(AstCCall* nodep) override {
VL_RESTORER(m_callp);
m_callp = nodep;
iterateChildren(nodep);
}
// Autoflush // Autoflush
void visit(AstDisplay* nodep) override { void visit(AstDisplay* nodep) override {

View File

@ -172,7 +172,7 @@ private:
} }
return stmtsp; return stmtsp;
} else { } else {
AstNodeMath* valp; AstNodeExpr* valp;
if (auto* const enumDtp = VN_CAST(memberp ? memberp->subDTypep()->subDTypep() if (auto* const enumDtp = VN_CAST(memberp ? memberp->subDTypep()->subDTypep()
: varrefp->dtypep()->subDTypep(), : varrefp->dtypep()->subDTypep(),
EnumDType)) { EnumDType)) {

View File

@ -252,7 +252,7 @@ private:
} }
//-------------------- //--------------------
void visit(AstVar*) override {} // Accelerate void visit(AstVar*) override {} // Accelerate
void visit(AstNodeMath*) override {} // Accelerate void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:

View File

@ -146,7 +146,8 @@ void splitCheck(AstCFunc* ofuncp) {
ofuncp->scopep()->addBlocksp(funcp); ofuncp->scopep()->addBlocksp(funcp);
// //
AstCCall* const callp = new AstCCall{funcp->fileline(), funcp}; AstCCall* const callp = new AstCCall{funcp->fileline(), funcp};
ofuncp->addStmtsp(callp); callp->dtypeSetVoid();
ofuncp->addStmtsp(callp->makeStmt());
func_stmts = 0; func_stmts = 0;
} }
funcp->addStmtsp(itemp); funcp->addStmtsp(itemp);
@ -215,7 +216,9 @@ void orderSequentially(AstCFunc* funcp, const LogicByScope& lbs) {
subFuncp->slow(funcp->slow()); subFuncp->slow(funcp->slow());
scopep->addBlocksp(subFuncp); scopep->addBlocksp(subFuncp);
// Call it from the top function // 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; return subFuncp;
}; };
const VNUser1InUse user1InUse; // AstScope -> AstCFunc: the sub-function for the scope 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); }; const auto add = [&](const string& text) { blockp->addText(flp, text, true); };
add("#ifdef VL_DEBUG\n"); add("#ifdef VL_DEBUG\n");
add("if (VL_UNLIKELY(vlSymsp->_vm_contextp__->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("}\n");
add("#endif\n"); add("#endif\n");
} }
@ -520,8 +525,8 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp,
//============================================================================ //============================================================================
// Helpers to construct an evaluation loop. // Helpers to construct an evaluation loop.
AstNode* buildLoop(AstNetlist* netlistp, const string& name, AstNodeStmt* buildLoop(AstNetlist* netlistp, const string& name,
const std::function<void(AstVarScope*, AstWhile*)>& build) // const std::function<void(AstVarScope*, AstWhile*)>& build) //
{ {
AstTopScope* const topScopep = netlistp->topScopep(); AstTopScope* const topScopep = netlistp->topScopep();
AstScope* const scopeTopp = topScopep->scopep(); AstScope* const scopeTopp = topScopep->scopep();
@ -529,7 +534,7 @@ AstNode* buildLoop(AstNetlist* netlistp, const string& name,
// Create the loop condition variable // Create the loop condition variable
AstVarScope* const condp = scopeTopp->createTemp("__V" + name + "Continue", 1); AstVarScope* const condp = scopeTopp->createTemp("__V" + name + "Continue", 1);
// Initialize the loop condition variable to true // Initialize the loop condition variable to true
AstNode* const resp = setVar(condp, 1); AstNodeStmt* const resp = setVar(condp, 1);
// Add the loop // Add the loop
AstWhile* const loopp = new AstWhile{flp, new AstVarRef{flp, condp, VAccess::READ}}; AstWhile* const loopp = new AstWhile{flp, new AstVarRef{flp, condp, VAccess::READ}};
resp->addNext(loopp); resp->addNext(loopp);
@ -541,11 +546,11 @@ AstNode* buildLoop(AstNetlist* netlistp, const string& name,
return resp; return resp;
}; };
std::pair<AstVarScope*, AstNode*> makeEvalLoop(AstNetlist* netlistp, const string& tag, std::pair<AstVarScope*, AstNodeStmt*> makeEvalLoop(AstNetlist* netlistp, const string& tag,
const string& name, AstVarScope* trigVscp, const string& name, AstVarScope* trigVscp,
AstCFunc* trigDumpp, AstCFunc* trigDumpp,
std::function<AstNode*()> computeTriggers, std::function<AstNodeStmt*()> computeTriggers,
std::function<AstNode*()> makeBody) { std::function<AstNodeStmt*()> makeBody) {
UASSERT_OBJ(trigVscp->dtypep()->basicp()->isTriggerVec(), trigVscp, "Not TRIGGERVEC"); UASSERT_OBJ(trigVscp->dtypep()->basicp()->isTriggerVec(), trigVscp, "Not TRIGGERVEC");
AstTopScope* const topScopep = netlistp->topScopep(); AstTopScope* const topScopep = netlistp->topScopep();
AstScope* const scopeTopp = topScopep->scopep(); AstScope* const scopeTopp = topScopep->scopep();
@ -553,7 +558,7 @@ std::pair<AstVarScope*, AstNode*> makeEvalLoop(AstNetlist* netlistp, const strin
AstVarScope* const counterp = scopeTopp->createTemp("__V" + tag + "IterCount", 32); 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) { nodep->addNext(buildLoop(netlistp, tag, [&](AstVarScope* continuep, AstWhile* loopp) {
// Compute triggers // Compute triggers
loopp->addStmtsp(computeTriggers()); loopp->addStmtsp(computeTriggers());
@ -572,7 +577,7 @@ std::pair<AstVarScope*, AstNode*> makeEvalLoop(AstNetlist* netlistp, const strin
AstVarRef* const refp = new AstVarRef{flp, counterp, VAccess::READ}; AstVarRef* const refp = new AstVarRef{flp, counterp, VAccess::READ};
AstConst* const constp = new AstConst{flp, AstConst::DTyped{}, counterp->dtypep()}; AstConst* const constp = new AstConst{flp, AstConst::DTyped{}, counterp->dtypep()};
constp->num().setLong(limit); 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}; AstIf* const failp = new AstIf{flp, condp};
failp->branchPred(VBranchPred::BP_UNLIKELY); failp->branchPred(VBranchPred::BP_UNLIKELY);
ifp->addThensp(failp); ifp->addThensp(failp);
@ -583,7 +588,9 @@ std::pair<AstVarScope*, AstNode*> makeEvalLoop(AstNetlist* netlistp, const strin
const string& line = cvtToStr(locp->lineno()); const string& line = cvtToStr(locp->lineno());
const auto add = [&](const string& text) { blockp->addText(flp, text, true); }; const auto add = [&](const string& text) { blockp->addText(flp, text, true); };
add("#ifdef VL_DEBUG\n"); 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("#endif\n");
add("VL_FATAL_MT(\"" + file + "\", " + line + ", \"\", "); add("VL_FATAL_MT(\"" + file + "\", " + line + ", \"\", ");
add("\"" + name + " region did not converge.\");\n"); add("\"" + name + " region did not converge.\");\n");
@ -651,10 +658,14 @@ void createSettle(AstNetlist* netlistp, AstCFunc* const initFuncp, SenExprBuilde
const auto& pair = makeEvalLoop( const auto& pair = makeEvalLoop(
netlistp, "stl", "Settle", trig.m_vscp, trig.m_dumpp, netlistp, "stl", "Settle", trig.m_vscp, trig.m_dumpp,
[&]() { // Trigger [&]() { // 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 [&]() { // 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 // 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( const auto& pair = makeEvalLoop(
netlistp, "ico", "Input combinational", trig.m_vscp, trig.m_dumpp, netlistp, "ico", "Input combinational", trig.m_vscp, trig.m_dumpp,
[&]() { // Trigger [&]() { // 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 [&]() { // 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 // Add the first iteration trigger to the trigger computation function
@ -785,19 +800,28 @@ void createEval(AstNetlist* netlistp, //
}); });
// Create the active eval loop // Create the active eval loop
AstNode* const activeEvalLoopp AstNodeStmt* const activeEvalLoopp
= makeEvalLoop( = makeEvalLoop(
netlistp, "act", "Active", actTrig.m_vscp, actTrig.m_dumpp, netlistp, "act", "Active", actTrig.m_vscp, actTrig.m_dumpp,
[&]() { // Trigger [&]() { // Trigger
AstNode* const resultp = new AstCCall{flp, actTrig.m_funcp}; AstNodeStmt* resultp = nullptr;
// Commit trigger awaits from the previous iteration
if (AstNode* const commitp = timingKit.createCommit(netlistp)) { // Compute the current triggers
resultp->addNext(commitp); {
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; return resultp;
}, },
[&]() { // Body [&]() { // Body
AstNode* resultp = nullptr; AstNodeStmt* resultp = nullptr;
// Compute the pre triggers // Compute the pre triggers
{ {
@ -806,9 +830,8 @@ void createEval(AstNetlist* netlistp, //
AstVarRef* const opbp = new AstVarRef{flp, nbaTrigsp, VAccess::READ}; AstVarRef* const opbp = new AstVarRef{flp, nbaTrigsp, VAccess::READ};
opap->addNext(opbp); opap->addNext(opbp);
AstCMethodHard* const callp = new AstCMethodHard{flp, lhsp, "andNot", opap}; AstCMethodHard* const callp = new AstCMethodHard{flp, lhsp, "andNot", opap};
callp->statement(true);
callp->dtypeSetVoid(); callp->dtypeSetVoid();
resultp = AstNode::addNext(resultp, callp); resultp = AstNode::addNext(resultp, callp->makeStmt());
} }
// Latch the active trigger flags under the NBA trigger flags // 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 lhsp = new AstVarRef{flp, nbaTrigsp, VAccess::WRITE};
AstVarRef* const argp = new AstVarRef{flp, actTrig.m_vscp, VAccess::READ}; AstVarRef* const argp = new AstVarRef{flp, actTrig.m_vscp, VAccess::READ};
AstCMethodHard* const callp = new AstCMethodHard{flp, lhsp, "set", argp}; AstCMethodHard* const callp = new AstCMethodHard{flp, lhsp, "set", argp};
callp->statement(true);
callp->dtypeSetVoid(); callp->dtypeSetVoid();
resultp = AstNode::addNext(resultp, callp); resultp = AstNode::addNext(resultp, callp->makeStmt());
} }
// Resume triggered timing schedulers // Resume triggered timing schedulers
if (AstNode* const resumep = timingKit.createResume(netlistp)) { if (AstCCall* const resumep = timingKit.createResume(netlistp)) {
resultp = AstNode::addNext(resultp, resumep); resultp = AstNode::addNext(resultp, resumep->makeStmt());
} }
// Invoke body function // 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; .second;
// Create the NBA eval loop. This uses the Active eval loop in the trigger section. // Create the NBA eval loop. This uses the Active eval loop in the trigger section.
AstNode* const nbaEvalLoopp AstNodeStmt* const nbaEvalLoopp
= makeEvalLoop( = makeEvalLoop(
netlistp, "nba", "NBA", nbaTrigsp, nbaDumpp, netlistp, "nba", "NBA", nbaTrigsp, nbaDumpp,
[&]() { // Trigger [&]() { // Trigger
AstNode* resultp = nullptr; AstNodeStmt* resultp = nullptr;
// Reset NBA triggers // Reset NBA triggers
{ {
AstVarRef* const refp = new AstVarRef{flp, nbaTrigsp, VAccess::WRITE}; AstVarRef* const refp = new AstVarRef{flp, nbaTrigsp, VAccess::WRITE};
AstCMethodHard* const callp = new AstCMethodHard{flp, refp, "clear"}; AstCMethodHard* const callp = new AstCMethodHard{flp, refp, "clear"};
callp->statement(true);
callp->dtypeSetVoid(); callp->dtypeSetVoid();
resultp = AstNode::addNext(resultp, callp); resultp = AstNode::addNext(resultp, callp->makeStmt());
} }
// Run the Active eval loop // Run the Active eval loop
return AstNode::addNext(resultp, activeEvalLoopp); return AstNode::addNext(resultp, activeEvalLoopp);
}, },
[&]() { // Body [&]() { // Body
return new AstCCall{flp, nbaFuncp}; AstCCall* const callp = new AstCCall{flp, nbaFuncp};
callp->dtypeSetVoid();
return callp->makeStmt();
}) })
.second; .second;
@ -859,7 +888,11 @@ void createEval(AstNetlist* netlistp, //
funcp->addStmtsp(nbaEvalLoopp); funcp->addStmtsp(nbaEvalLoopp);
// Add the Postponed eval call // 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 } // namespace

View File

@ -75,7 +75,9 @@ AstCCall* TimingKit::createResume(AstNetlist* const netlistp) {
m_resumeFuncp->addStmtsp(activep); 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) { if (!m_commitFuncp) {
for (auto& p : m_lbs) { for (auto& p : m_lbs) {
AstActive* const activep = p.second; 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"); UASSERT_OBJ(!resumep->nextp(), resumep, "Should be the only statement here");
AstVarScope* const schedulerp = VN_AS(resumep->fromp(), VarRef)->varScopep(); AstVarScope* const schedulerp = VN_AS(resumep->fromp(), VarRef)->varScopep();
UASSERT_OBJ(schedulerp->dtypep()->basicp()->isDelayScheduler() UASSERT_OBJ(schedulerp->dtypep()->basicp()->isDelayScheduler()
@ -117,15 +119,16 @@ AstCCall* TimingKit::createCommit(AstNetlist* const netlistp) {
auto* const commitp = new AstCMethodHard{ auto* const commitp = new AstCMethodHard{
flp, new AstVarRef{flp, schedulerp, VAccess::READWRITE}, "commit"}; flp, new AstVarRef{flp, schedulerp, VAccess::READWRITE}, "commit"};
if (resumep->pinsp()) commitp->addPinsp(resumep->pinsp()->cloneTree(false)); if (resumep->pinsp()) commitp->addPinsp(resumep->pinsp()->cloneTree(false));
commitp->statement(true);
commitp->dtypeSetVoid(); commitp->dtypeSetVoid();
newactp->addStmtsp(commitp); newactp->addStmtsp(commitp->makeStmt());
m_commitFuncp->addStmtsp(newactp); m_commitFuncp->addStmtsp(newactp);
} }
// We still haven't created a commit function (no trigger schedulers), return null // We still haven't created a commit function (no trigger schedulers), return null
if (!m_commitFuncp) return nullptr; 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 // Create a resume() call on the timing scheduler
auto* const resumep = new AstCMethodHard{ auto* const resumep = new AstCMethodHard{
flp, new AstVarRef{flp, schedulerp, VAccess::READWRITE}, "resume"}; flp, new AstVarRef{flp, schedulerp, VAccess::READWRITE}, "resume"};
resumep->statement(true);
resumep->dtypeSetVoid(); resumep->dtypeSetVoid();
if (schedulerp->dtypep()->basicp()->isTriggerScheduler()) { if (schedulerp->dtypep()->basicp()->isTriggerScheduler()) {
if (methodp->pinsp()) resumep->addPinsp(methodp->pinsp()->cloneTree(false)); if (methodp->pinsp()) resumep->addPinsp(methodp->pinsp()->cloneTree(false));
} else if (schedulerp->dtypep()->basicp()->isDynamicTriggerScheduler()) { } else if (schedulerp->dtypep()->basicp()->isDynamicTriggerScheduler()) {
auto* const postp = resumep->cloneTree(false); auto* const postp = resumep->cloneTree(false);
postp->name("doPostUpdates"); 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 // Put it in an active and put that in the global resume function
auto* const activep = new AstActive{flp, "_timing", sensesp}; auto* const activep = new AstActive{flp, "_timing", sensesp};
activep->addStmtsp(resumep); activep->addStmtsp(resumep->makeStmt());
m_lbs.emplace_back(m_scopeTopp, activep); 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); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: 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 it's fork..join, we can refer to variables from the parent process
if (!m_funcp->user1SetOnce()) { // Only do this once per function if (!m_funcp->user1SetOnce()) { // Only do this once per function
// Move all locals to the heap before the fork // Move all locals to the heap before the fork
auto* const awaitp = new AstCAwait{ AstCExpr* const nowp
m_forkp->fileline(), new AstCStmt{m_forkp->fileline(), "VlNow{}"}}; = new AstCExpr{m_forkp->fileline(), "VlNow{}", 0, true};
awaitp->statement(true); nowp->dtypeSetVoid(); // TODO: this is sloppy but harmless
m_forkp->addHereThisAsNext(awaitp); AstCAwait* const awaitp = new AstCAwait{m_forkp->fileline(), nowp};
awaitp->dtypeSetVoid();
m_forkp->addHereThisAsNext(awaitp->makeStmt());
} }
} else { } else {
refp->v3warn(E_UNSUPPORTED, "Unsupported: variable local to a forking process " 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->isConst(m_funcp->isConst());
newfuncp->declPrivate(true); newfuncp->declPrivate(true);
// Replace the begin with a call to the newly created function // Replace the begin with a call to the newly created function
auto* const callp = new AstCCall{flp, newfuncp}; AstCCall* const callp = new AstCCall{flp, newfuncp};
nodep->replaceWith(callp); callp->dtypeSetVoid();
nodep->replaceWith(callp->makeStmt());
// If we're in a class, add a vlSymsp arg // If we're in a class, add a vlSymsp arg
if (m_inClass) { if (m_inClass) {
newfuncp->addInitsp(new AstCStmt{nodep->fileline(), "VL_KEEP_THIS;\n"}); 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); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:

View File

@ -141,8 +141,7 @@ class SenExprBuilder final {
if (AstUnpackArrayDType* const dtypep = VN_CAST(exprp->dtypep(), UnpackArrayDType)) { if (AstUnpackArrayDType* const dtypep = VN_CAST(exprp->dtypep(), UnpackArrayDType)) {
AstCMethodHard* const cmhp = new AstCMethodHard{flp, wrPrev(), "assign", rdCurr()}; AstCMethodHard* const cmhp = new AstCMethodHard{flp, wrPrev(), "assign", rdCurr()};
cmhp->dtypeSetVoid(); cmhp->dtypeSetVoid();
cmhp->statement(true); m_postUpdates.push_back(cmhp->makeStmt());
m_postUpdates.push_back(cmhp);
} else { } else {
m_postUpdates.push_back(new AstAssign{flp, wrPrev(), rdCurr()}); m_postUpdates.push_back(new AstAssign{flp, wrPrev(), rdCurr()});
} }
@ -157,7 +156,7 @@ class SenExprBuilder final {
const auto currp = [=]() { return getCurr(senp); }; const auto currp = [=]() { return getCurr(senp); };
const auto prevp = [=]() { return new AstVarRef{flp, getPrev(senp), VAccess::READ}; }; 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 // All event signals should be 1-bit at this point
switch (senItemp->edgeType()) { switch (senItemp->edgeType()) {
@ -188,9 +187,8 @@ class SenExprBuilder final {
// Clear 'fired' state when done // Clear 'fired' state when done
AstCMethodHard* const clearp = new AstCMethodHard{flp, currp(), "clearFired"}; AstCMethodHard* const clearp = new AstCMethodHard{flp, currp(), "clearFired"};
ifp->addThensp(clearp);
clearp->dtypeSetVoid(); clearp->dtypeSetVoid();
clearp->statement(true); ifp->addThensp(clearp->makeStmt());
// Enqueue for clearing 'triggered' state on next eval // Enqueue for clearing 'triggered' state on next eval
AstTextBlock* const blockp = new AstTextBlock{flp}; AstTextBlock* const blockp = new AstTextBlock{flp};

View File

@ -86,10 +86,6 @@ private:
} }
} }
void visit(AstNodeStmt* nodep) override { void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
iterateChildren(nodep);
return;
}
UINFO(6, " CL STMT " << nodep << endl); UINFO(6, " CL STMT " << nodep << endl);
const bool oldKeep = m_keepStmt; const bool oldKeep = m_keepStmt;
{ {
@ -179,8 +175,7 @@ private:
} }
} }
// Speedup; no always under math void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNodeMath*) override {}
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
public: public:

View File

@ -405,7 +405,7 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl {
VarSet m_foundTargetVar; VarSet m_foundTargetVar;
UnpackRefMap m_refs; UnpackRefMap m_refs;
AstNodeModule* m_modp = nullptr; AstNodeModule* m_modp = nullptr;
// AstNodeStmt, AstCell, AstNodeFTaskRef, or AstAlways(Public) for sensitivity // AstNodeStmt, AstCell, or AstAlways(Public) for sensitivity
AstNode* m_contextp = nullptr; AstNode* m_contextp = nullptr;
const AstNodeFTask* m_inFTask = nullptr; const AstNodeFTask* m_inFTask = nullptr;
size_t m_numSplit = 0; size_t m_numSplit = 0;
@ -492,38 +492,34 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl {
} }
} }
void visit(AstNodeFTaskRef* nodep) override { void visit(AstNodeFTaskRef* nodep) override {
VL_RESTORER(m_contextp); const AstNodeFTask* const ftaskp = nodep->taskp();
{ UASSERT_OBJ(ftaskp, nodep, "Unlinked");
m_contextp = nodep; // Iterate arguments of a function/task.
const AstNodeFTask* const ftaskp = nodep->taskp(); for (AstNode *argp = nodep->pinsp(), *paramp = ftaskp->stmtsp(); argp;
UASSERT_OBJ(ftaskp, nodep, "Unlinked"); argp = argp->nextp(), paramp = paramp ? paramp->nextp() : nullptr) {
// Iterate arguments of a function/task. const char* reason = nullptr;
for (AstNode *argp = nodep->pinsp(), *paramp = ftaskp->stmtsp(); argp; const AstVar* vparamp = nullptr;
argp = argp->nextp(), paramp = paramp ? paramp->nextp() : nullptr) { while (paramp) {
const char* reason = nullptr; vparamp = VN_CAST(paramp, Var);
const AstVar* vparamp = nullptr; if (vparamp && vparamp->isIO()) {
while (paramp) { reason = cannotSplitVarDirectionReason(vparamp->direction());
vparamp = VN_CAST(paramp, Var); break;
if (vparamp && vparamp->isIO()) {
reason = cannotSplitVarDirectionReason(vparamp->direction());
break;
}
paramp = paramp->nextp();
vparamp = nullptr;
} }
if (!reason && !vparamp) { paramp = paramp->nextp();
reason = "the number of argument to the task/function mismatches"; vparamp = nullptr;
}
m_foundTargetVar.clear();
iterate(argp);
if (reason) {
for (AstVar* const varp : m_foundTargetVar) {
warnNoSplit(varp, argp, reason);
m_refs.remove(varp);
}
}
m_foundTargetVar.clear();
} }
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 { void visit(AstPin* nodep) override {
@ -605,12 +601,6 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl {
iterateChildren(nodep); 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, AstVarRef* createTempVar(AstNode* context, AstNode* nodep, AstUnpackArrayDType* dtypep,
const std::string& name_prefix, std::vector<AstVar*>& vars, const std::string& name_prefix, std::vector<AstVar*>& vars,
int start_idx, bool lvalue, bool /*ftask*/) { int start_idx, bool lvalue, bool /*ftask*/) {
@ -640,7 +630,7 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl {
if (!lvalue) std::swap(lhsp, rhsp); if (!lvalue) std::swap(lhsp, rhsp);
AstNode* newassignp; AstNode* newassignp;
if (use_simple_assign) { if (use_simple_assign) {
AstNode* const insertp = toInsertPoint(context); AstNode* const insertp = context;
newassignp = new AstAssign{fl, lhsp, rhsp}; newassignp = new AstAssign{fl, lhsp, rhsp};
if (lvalue) { if (lvalue) {
// If varp is LHS, this assignment must appear after the original // 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<AstVar*>& vars, AstNode* insertp) { void connectPort(AstVar* varp, std::vector<AstVar*>& vars, AstNode* insertp) {
UASSERT_OBJ(varp->isIO(), varp, "must be port"); UASSERT_OBJ(varp->isIO(), varp, "must be port");
insertp = insertp ? toInsertPoint(insertp) : nullptr;
const bool lvalue = varp->direction().isWritable(); const bool lvalue = varp->direction().isWritable();
FileLine* const fl = varp->fileline(); FileLine* const fl = varp->fileline();
for (size_t i = 0; i < vars.size(); ++i) { 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<SplitNewVar>& vars, AstVar* portp, static void connectPortAndVar(const std::vector<SplitNewVar>& vars, AstVar* portp,
AstNode* insertp) { AstNode* insertp) {
for (; insertp; insertp = insertp->backp()) { for (; insertp; insertp = insertp->backp()) {
if (const AstNodeStmt* const stmtp = VN_CAST(insertp, NodeStmt)) { if (VN_IS(insertp, NodeStmt)) break;
if (stmtp->isStatement()) break;
}
} }
const bool in = portp->isReadOnly(); const bool in = portp->isReadOnly();
FileLine* const fl = portp->fileline(); FileLine* const fl = portp->fileline();

View File

@ -552,10 +552,12 @@ private:
cnewpr = cnewp; cnewpr = cnewp;
} else if (const AstMethodCall* const mrefp = VN_CAST(refp, MethodCall)) { } else if (const AstMethodCall* const mrefp = VN_CAST(refp, MethodCall)) {
ccallp = new AstCMethodCall(refp->fileline(), mrefp->fromp()->unlinkFrBack(), cfuncp); ccallp = new AstCMethodCall(refp->fileline(), mrefp->fromp()->unlinkFrBack(), cfuncp);
beginp->addNext(ccallp); ccallp->dtypeSetVoid();
beginp->addNext(ccallp->makeStmt());
} else { } else {
ccallp = new AstCCall(refp->fileline(), cfuncp); ccallp = new AstCCall(refp->fileline(), cfuncp);
beginp->addNext(ccallp); ccallp->dtypeSetVoid();
beginp->addNext(ccallp->makeStmt());
} }
// Convert complicated outputs to temp signals // Convert complicated outputs to temp signals
@ -617,7 +619,7 @@ private:
UASSERT_OBJ(snp, refp, "Missing scoping context"); UASSERT_OBJ(snp, refp, "Missing scoping context");
ccallp->addArgsp(snp); ccallp->addArgsp(snp);
// __Vfilenamep // __Vfilenamep
ccallp->addArgsp(new AstCMath(refp->fileline(), ccallp->addArgsp(new AstCExpr(refp->fileline(),
"\"" + refp->fileline()->filename() + "\"", 64, true)); "\"" + refp->fileline()->filename() + "\"", 64, true));
// __Vlineno // __Vlineno
ccallp->addArgsp(new AstConst(refp->fileline(), refp->fileline()->lineno())); ccallp->addArgsp(new AstConst(refp->fileline(), refp->fileline()->lineno()));
@ -701,7 +703,7 @@ private:
string frstmt; string frstmt;
string ket; string ket;
const bool useSetWSvlv = TaskDpiUtils::dpiToInternalFrStmt(portp, frName, frstmt, 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; int cwidth = VL_IDATASIZE;
if (!useSetWSvlv && portp->basicp()) { if (!useSetWSvlv && portp->basicp()) {
if (portp->basicp()->keyword().isBitLogic()) { if (portp->basicp()->keyword().isBitLogic()) {
@ -743,7 +745,7 @@ private:
} }
from += ket; from += ket;
AstNode* const rhsp = new AstSel( 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()); portp->width());
stmtp = new AstAssign(portp->fileline(), srcp, rhsp); stmtp = new AstAssign(portp->fileline(), srcp, rhsp);
} }
@ -1039,8 +1041,9 @@ private:
cfuncp->addStmtsp(new AstText(nodep->fileline(), stmt, /* tracking: */ true)); cfuncp->addStmtsp(new AstText(nodep->fileline(), stmt, /* tracking: */ true));
} }
AstCCall* const callp = new AstCCall(nodep->fileline(), dpiFuncp); AstCCall* const callp = new AstCCall(nodep->fileline(), dpiFuncp);
callp->dtypeSetVoid();
callp->argTypes(args); callp->argTypes(args);
cfuncp->addStmtsp(callp); cfuncp->addStmtsp(callp->makeStmt());
} }
// Convert output/inout arguments back to internal type // Convert output/inout arguments back to internal type
@ -1401,30 +1404,26 @@ private:
beginp = createInlinedFTask(nodep, namePrefix, outvscp); beginp = createInlinedFTask(nodep, namePrefix, outvscp);
} }
// Replace the ref // Replace the ref
AstNode* visitp = nullptr; AstNode* const visitp = insertBeforeStmt(nodep, beginp);
if (VN_IS(nodep, New)) { if (VN_IS(nodep, New)) {
UASSERT_OBJ(!nodep->isStatement(), nodep, "new is non-stmt");
UASSERT_OBJ(cnewp, nodep, "didn't create cnew for new"); UASSERT_OBJ(cnewp, nodep, "didn't create cnew for new");
nodep->replaceWith(cnewp); nodep->replaceWith(cnewp);
visitp = insertBeforeStmt(nodep, beginp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (!nodep->isStatement()) { } else if (!VN_IS(nodep->backp(), StmtExpr)) {
UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function"); UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function");
AstVarRef* const outrefp = new AstVarRef(nodep->fileline(), outvscp, VAccess::READ); AstVarRef* const outrefp = new AstVarRef(nodep->fileline(), outvscp, VAccess::READ);
nodep->replaceWith(outrefp); nodep->replaceWith(outrefp);
// Insert new statements VL_DO_DANGLING(nodep->deleteTree(), nodep);
visitp = insertBeforeStmt(nodep, beginp);
} else { } else {
if (nodep->taskp()->isFunction()) { if (nodep->taskp()->isFunction()) {
nodep->v3warn( nodep->v3warn(
IGNOREDRETURN, IGNOREDRETURN,
"Ignoring return value of non-void function (IEEE 1800-2017 13.4.1)"); "Ignoring return value of non-void function (IEEE 1800-2017 13.4.1)");
} }
// outvscp maybe non-nullptr if calling a function in a taskref, nodep->unlinkFrBack();
// but if so we want to ignore the function result VL_DO_DANGLING(nodep->deleteTree(), nodep);
nodep->replaceWith(beginp);
} }
// Cleanup
VL_DO_DANGLING(nodep->deleteTree(), nodep);
UINFO(4, " FTask REF Done.\n"); UINFO(4, " FTask REF Done.\n");
// Visit nodes that normal iteration won't find // Visit nodes that normal iteration won't find
if (visitp) iterateAndNextNull(visitp); if (visitp) iterateAndNextNull(visitp);
@ -1519,15 +1518,18 @@ private:
"For statements should have been converted to while statements in V3Begin.cpp"); "For statements should have been converted to while statements in V3Begin.cpp");
} }
void visit(AstNodeStmt* nodep) override { void visit(AstNodeStmt* nodep) override {
if (!nodep->isStatement()) {
iterateChildren(nodep);
return;
}
m_insMode = IM_BEFORE; m_insMode = IM_BEFORE;
m_insStmtp = nodep; m_insStmtp = nodep;
iterateChildren(nodep); iterateChildren(nodep);
m_insStmtp = nullptr; // Next thing should be new statement 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 { void visit(AstSenItem* nodep) override {
UASSERT_OBJ(!m_inSensesp, nodep, "Senitem under senitem?"); UASSERT_OBJ(!m_inSensesp, nodep, "Senitem under senitem?");
VL_RESTORER(m_inSensesp); VL_RESTORER(m_inSensesp);

View File

@ -341,9 +341,8 @@ private:
auto* const donep = new AstCMethodHard{ auto* const donep = new AstCMethodHard{
beginp->fileline(), new AstVarRef{flp, forkVscp, VAccess::WRITE}, "done"}; beginp->fileline(), new AstVarRef{flp, forkVscp, VAccess::WRITE}, "done"};
donep->dtypeSetVoid(); donep->dtypeSetVoid();
donep->statement(true);
addDebugInfo(donep); addDebugInfo(donep);
beginp->addStmtsp(donep); beginp->addStmtsp(donep->makeStmt());
} }
// Handle the 'join' part of a fork..join // Handle the 'join' part of a fork..join
void makeForkJoin(AstFork* const forkp) { void makeForkJoin(AstFork* const forkp) {
@ -364,16 +363,15 @@ private:
auto* const initp = new AstCMethodHard{flp, new AstVarRef{flp, forkVscp, VAccess::WRITE}, auto* const initp = new AstCMethodHard{flp, new AstVarRef{flp, forkVscp, VAccess::WRITE},
"init", new AstConst{flp, joinCount}}; "init", new AstConst{flp, joinCount}};
initp->dtypeSetVoid(); initp->dtypeSetVoid();
initp->statement(true); forkp->addHereThisAsNext(initp->makeStmt());
forkp->addHereThisAsNext(initp);
// Await the join at the end // Await the join at the end
auto* const joinp auto* const joinp
= new AstCMethodHard{flp, new AstVarRef{flp, forkVscp, VAccess::WRITE}, "join"}; = new AstCMethodHard{flp, new AstVarRef{flp, forkVscp, VAccess::WRITE}, "join"};
joinp->dtypeSetVoid(); joinp->dtypeSetVoid();
addDebugInfo(joinp); addDebugInfo(joinp);
auto* const awaitp = new AstCAwait{flp, joinp}; AstCAwait* const awaitp = new AstCAwait{flp, joinp};
awaitp->statement(true); awaitp->dtypeSetVoid();
forkp->addNextHere(awaitp); forkp->addNextHere(awaitp->makeStmt());
} }
// VISITORS // VISITORS
@ -476,7 +474,9 @@ private:
if (nodep->funcp()->user2()) { // If suspendable if (nodep->funcp()->user2()) { // If suspendable
VNRelinker relinker; VNRelinker relinker;
nodep->unlinkFrBack(&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 { } else {
// Add our process/func as the CFunc's dependency as we might have to put an await here // Add our process/func as the CFunc's dependency as we might have to put an await here
DependencyVertex* const procVxp = getDependencyVertex(m_procp); DependencyVertex* const procVxp = getDependencyVertex(m_procp);
@ -515,13 +515,15 @@ private:
delayMethodp->dtypeSetVoid(); delayMethodp->dtypeSetVoid();
addDebugInfo(delayMethodp); addDebugInfo(delayMethodp);
// Create the co_await // Create the co_await
auto* const awaitp = new AstCAwait{flp, delayMethodp, getCreateDelaySenTree()}; AstCAwait* const awaitp = new AstCAwait{flp, delayMethodp, getCreateDelaySenTree()};
awaitp->statement(true); awaitp->dtypeSetVoid();
AstStmtExpr* const awaitStmtp = awaitp->makeStmt();
// Relink child statements after the co_await // Relink child statements after the co_await
if (nodep->stmtsp()) { if (nodep->stmtsp()) {
AstNode::addNext<AstNode, AstNode>(awaitp, nodep->stmtsp()->unlinkFrBackWithNext()); AstNode::addNext<AstNode, AstNode>(awaitStmtp,
nodep->stmtsp()->unlinkFrBackWithNext());
} }
nodep->replaceWith(awaitp); nodep->replaceWith(awaitStmtp);
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} }
void visit(AstEventControl* nodep) override { void visit(AstEventControl* nodep) override {
@ -552,9 +554,9 @@ private:
auto* const sensesp = nodep->sensesp(); auto* const sensesp = nodep->sensesp();
addEventDebugInfo(evalMethodp, sensesp); addEventDebugInfo(evalMethodp, sensesp);
// Create the co_await // Create the co_await
auto* const awaitEvalp AstCAwait* const awaitEvalp
= new AstCAwait{flp, evalMethodp, getCreateDynamicTriggerSenTree()}; = new AstCAwait{flp, evalMethodp, getCreateDynamicTriggerSenTree()};
awaitEvalp->statement(true); awaitEvalp->dtypeSetVoid();
// Construct the sen expression for this sentree // Construct the sen expression for this sentree
SenExprBuilder senExprBuilder{m_scopep}; SenExprBuilder senExprBuilder{m_scopep};
auto* const assignp = new AstAssign{flp, new AstVarRef{flp, trigvscp, VAccess::WRITE}, 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 // Create the trigger eval loop, which will await the evaluation step and check the
// trigger // trigger
auto* const loopp = new AstWhile{ AstWhile* const loopp = new AstWhile{
flp, new AstLogNot{flp, new AstVarRef{flp, trigvscp, VAccess::READ}}, awaitEvalp}; flp, new AstLogNot{flp, new AstVarRef{flp, trigvscp, VAccess::READ}},
awaitEvalp->makeStmt()};
// Put pre updates before the trigger check and assignment // Put pre updates before the trigger check and assignment
for (AstNodeStmt* const stmtp : senExprBuilder.getAndClearPreUpdates()) { for (AstNodeStmt* const stmtp : senExprBuilder.getAndClearPreUpdates()) {
loopp->addStmtsp(stmtp); loopp->addStmtsp(stmtp);
@ -579,18 +582,18 @@ private:
// If the post update is destructive (e.g. event vars are cleared), create an await for // If the post update is destructive (e.g. event vars are cleared), create an await for
// the post update step // the post update step
if (destructivePostUpdate(sensesp)) { if (destructivePostUpdate(sensesp)) {
auto* const awaitPostUpdatep = awaitEvalp->cloneTree(false); AstCAwait* const awaitPostUpdatep = awaitEvalp->cloneTree(false);
VN_AS(awaitPostUpdatep->exprp(), CMethodHard)->name("postUpdate"); VN_AS(awaitPostUpdatep->exprp(), CMethodHard)->name("postUpdate");
loopp->addStmtsp(awaitPostUpdatep); loopp->addStmtsp(awaitPostUpdatep->makeStmt());
} }
// Put the post updates at the end of the loop // Put the post updates at the end of the loop
for (AstNodeStmt* const stmtp : senExprBuilder.getAndClearPostUpdates()) { for (AstNodeStmt* const stmtp : senExprBuilder.getAndClearPostUpdates()) {
loopp->addStmtsp(stmtp); loopp->addStmtsp(stmtp);
} }
// Finally, await the resumption step in 'act' // 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"); VN_AS(awaitResumep->exprp(), CMethodHard)->name("resumption");
AstNode::addNext<AstNode, AstNode>(loopp, awaitResumep); AstNode::addNext<AstNodeStmt, AstNodeStmt>(loopp, awaitResumep->makeStmt());
// Replace the event control with the loop // Replace the event control with the loop
nodep->replaceWith(loopp); nodep->replaceWith(loopp);
} else { } else {
@ -605,9 +608,9 @@ private:
triggerMethodp->dtypeSetVoid(); triggerMethodp->dtypeSetVoid();
addEventDebugInfo(triggerMethodp, sensesp); addEventDebugInfo(triggerMethodp, sensesp);
// Create the co_await // Create the co_await
auto* const awaitp = new AstCAwait{flp, triggerMethodp, sensesp}; AstCAwait* const awaitp = new AstCAwait{flp, triggerMethodp, sensesp};
awaitp->statement(true); awaitp->dtypeSetVoid();
nodep->replaceWith(awaitp); nodep->replaceWith(awaitp->makeStmt());
} }
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} }
@ -700,9 +703,11 @@ private:
if (constp->isZero()) { if (constp->isZero()) {
// We have to await forever instead of simply returning in case we're deep in a // We have to await forever instead of simply returning in case we're deep in a
// callstack // callstack
auto* const awaitp = new AstCAwait{flp, new AstCStmt{flp, "VlForever{}"}}; AstCExpr* const foreverp = new AstCExpr{flp, "VlForever{}", 0, true};
awaitp->statement(true); foreverp->dtypeSetVoid(); // TODO: this is sloppy but harmless
nodep->replaceWith(awaitp); AstCAwait* const awaitp = new AstCAwait{flp, foreverp};
awaitp->dtypeSetVoid();
nodep->replaceWith(awaitp->makeStmt());
if (stmtsp) VL_DO_DANGLING(stmtsp->deleteTree(), stmtsp); if (stmtsp) VL_DO_DANGLING(stmtsp->deleteTree(), stmtsp);
} else if (stmtsp) { } else if (stmtsp) {
// Just put the statements there // 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(AstVar*) override {}
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }

View File

@ -163,7 +163,7 @@ private:
// AstCFunc::user1() // V3GraphVertex* for this node // AstCFunc::user1() // V3GraphVertex* for this node
// AstTraceDecl::user1() // V3GraphVertex* for this node // AstTraceDecl::user1() // V3GraphVertex* for this node
// AstVarScope::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 // Ast*::user3() // TraceActivityVertex* for this node
const VNUser1InUse m_inuser1; const VNUser1InUse m_inuser1;
const VNUser2InUse m_inuser2; const VNUser2InUse m_inuser2;
@ -429,13 +429,15 @@ private:
FileLine* const fl = insertp->fileline(); FileLine* const fl = insertp->fileline();
AstAssign* const setterp = new AstAssign(fl, selectActivity(fl, code, VAccess::WRITE), AstAssign* const setterp = new AstAssign(fl, selectActivity(fl, code, VAccess::WRITE),
new AstConst(fl, AstConst::BitTrue())); new AstConst(fl, AstConst::BitTrue()));
if (AstCCall* const callp = VN_CAST(insertp, CCall)) { if (AstStmtExpr* const stmtp = VN_CAST(insertp, StmtExpr)) {
callp->addNextHere(setterp); stmtp->addNextHere(setterp);
} else if (AstCFunc* const funcp = VN_CAST(insertp, CFunc)) { } else if (AstCFunc* const funcp = VN_CAST(insertp, CFunc)) {
// If there are awaits, insert the setter after each await // If there are awaits, insert the setter after each await
if (funcp->isCoroutine() && funcp->stmtsp()) { if (funcp->isCoroutine() && funcp->stmtsp()) {
funcp->stmtsp()->foreachAndNext([&](AstCAwait* awaitp) { 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); funcp->addStmtsp(setterp);
@ -550,8 +552,9 @@ private:
} }
// Add call to top function // Add call to top function
AstCCall* const callp = new AstCCall(funcp->fileline(), funcp); AstCCall* const callp = new AstCCall(funcp->fileline(), funcp);
callp->dtypeSetVoid();
callp->argTypes("bufp"); callp->argTypes("bufp");
topFuncp->addStmtsp(callp); topFuncp->addStmtsp(callp->makeStmt());
} }
// Done // Done
UINFO(5, " newCFunc " << funcp << endl); UINFO(5, " newCFunc " << funcp << endl);
@ -822,20 +825,24 @@ private:
if (nodep->isTop()) m_topModp = nodep; if (nodep->isTop()) m_topModp = nodep;
iterateChildren(nodep); iterateChildren(nodep);
} }
void visit(AstCCall* nodep) override { void visit(AstStmtExpr* nodep) override {
UINFO(8, " CCALL " << nodep << endl);
if (!m_finding && !nodep->user2()) { if (!m_finding && !nodep->user2()) {
// See if there are other calls in same statement list; if (AstCCall* const callp = VN_CAST(nodep->exprp(), CCall)) {
// If so, all funcs might share the same activity code UINFO(8, " CCALL " << callp << endl);
TraceActivityVertex* const activityVtxp // See if there are other calls in same statement list;
= getActivityVertexp(nodep, nodep->funcp()->slow()); // If so, all funcs might share the same activity code
for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) { TraceActivityVertex* const activityVtxp
if (AstCCall* const ccallp = VN_CAST(nextp, CCall)) { = getActivityVertexp(nodep, callp->funcp()->slow());
ccallp->user2(true); // Processed for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) {
UINFO(8, " SubCCALL " << ccallp << endl); if (AstStmtExpr* const stmtp = VN_CAST(nextp, StmtExpr)) {
V3GraphVertex* const ccallFuncVtxp = getCFuncVertexp(ccallp->funcp()); if (AstCCall* const ccallp = VN_CAST(stmtp->exprp(), CCall)) {
activityVtxp->slow(ccallp->funcp()->slow()); stmtp->user2(true); // Processed
new V3GraphEdge(&m_graph, activityVtxp, ccallFuncVtxp, 1); UINFO(8, " SubCCALL " << ccallp << endl);
V3GraphVertex* const ccallFuncVtxp = getCFuncVertexp(ccallp->funcp());
activityVtxp->slow(ccallp->funcp()->slow());
new V3GraphEdge(&m_graph, activityVtxp, ccallFuncVtxp, 1);
}
}
} }
} }
} }

View File

@ -489,8 +489,9 @@ public:
// Call all sub functions for this path // Call all sub functions for this path
for (AstCFunc* const subFuncp : item.second) { for (AstCFunc* const subFuncp : item.second) {
AstCCall* const callp = new AstCCall{flp, subFuncp}; AstCCall* const callp = new AstCCall{flp, subFuncp};
callp->dtypeSetVoid();
callp->argTypes("tracep"); callp->argTypes("tracep");
addToTopFunc(callp); addToTopFunc(callp->makeStmt());
} }
} }
pathAdjustor.unwind(); pathAdjustor.unwind();
@ -503,8 +504,9 @@ public:
AstCFunc* const topFuncp = newCFunc(flp, ""); AstCFunc* const topFuncp = newCFunc(flp, "");
for (AstCFunc* funcp : m_topFuncps) { for (AstCFunc* funcp : m_topFuncps) {
AstCCall* const callp = new AstCCall{flp, funcp}; AstCCall* const callp = new AstCCall{flp, funcp};
callp->dtypeSetVoid();
callp->argTypes("tracep"); callp->argTypes("tracep");
topFuncp->addStmtsp(callp); topFuncp->addStmtsp(callp->makeStmt());
} }
m_topFuncps.clear(); m_topFuncps.clear();
m_topFuncps.push_back(topFuncp); m_topFuncps.push_back(topFuncp);

View File

@ -308,11 +308,11 @@ private:
// Widths: out width = lhs width = rhs width // Widths: out width = lhs width = rhs width
// Signed: Output signed iff LHS & RHS signed. // Signed: Output signed iff LHS & RHS signed.
// Real: Not allowed // Real: Not allowed
void visit(AstAnd* nodep) override { visit_boolmath_and_or(nodep); } void visit(AstAnd* nodep) override { visit_boolexpr_and_or(nodep); }
void visit(AstOr* nodep) override { visit_boolmath_and_or(nodep); } void visit(AstOr* nodep) override { visit_boolexpr_and_or(nodep); }
void visit(AstXor* nodep) override { visit_boolmath_and_or(nodep); } void visit(AstXor* nodep) override { visit_boolexpr_and_or(nodep); }
void visit(AstBufIf1* nodep) override { void visit(AstBufIf1* nodep) override {
visit_boolmath_and_or(nodep); visit_boolexpr_and_or(nodep);
} // Signed behavior changing in 3.814 } // Signed behavior changing in 3.814
// Width: Max(Lhs,Rhs) sort of. // Width: Max(Lhs,Rhs) sort of.
// Real: If either side real // Real: If either side real
@ -2856,12 +2856,12 @@ private:
if (!nodep->pinsp()) { if (!nodep->pinsp()) {
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"clear"}; "clear"};
newp->makeStatement(); newp->dtypeSetVoid();
} else { } else {
AstNode* const index_exprp = methodCallWildcardIndexExpr(nodep, adtypep); AstNode* const index_exprp = methodCallWildcardIndexExpr(nodep, adtypep);
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"erase", index_exprp->unlinkFrBack()}; "erase", index_exprp->unlinkFrBack()};
newp->makeStatement(); newp->dtypeSetVoid();
} }
} else if (nodep->name() == "sort" || nodep->name() == "rsort" } else if (nodep->name() == "sort" || nodep->name() == "rsort"
|| nodep->name() == "reverse" || nodep->name() == "shuffle") { || nodep->name() == "reverse" || nodep->name() == "shuffle") {
@ -2878,14 +2878,14 @@ private:
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"r_" + nodep->name(), withp}; "r_" + nodep->name(), withp};
newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); 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") { } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique") {
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name()}; nodep->name()};
newp->dtypeFrom(adtypep); newp->dtypeFrom(adtypep);
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else if (nodep->name() == "find" || nodep->name() == "find_first" } else if (nodep->name() == "find" || nodep->name() == "find_first"
|| nodep->name() == "find_last") { || nodep->name() == "find_last") {
AstWith* const withp AstWith* const withp
@ -2896,7 +2896,7 @@ private:
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), withp}; nodep->name(), withp};
newp->dtypeFrom(adtypep); newp->dtypeFrom(adtypep);
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else { } else {
nodep->v3error("Unknown wildcard associative array method " << nodep->prettyNameQ()); nodep->v3error("Unknown wildcard associative array method " << nodep->prettyNameQ());
nodep->dtypeFrom(adtypep->subDTypep()); // Best guess nodep->dtypeFrom(adtypep->subDTypep()); // Best guess
@ -2926,7 +2926,7 @@ private:
nodep->name(), // first/last/next/prev nodep->name(), // first/last/next/prev
index_exprp->unlinkFrBack()); index_exprp->unlinkFrBack());
newp->dtypeSetSigned32(); newp->dtypeSetSigned32();
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else if (nodep->name() == "exists") { // function int exists(input index) } else if (nodep->name() == "exists") { // function int exists(input index)
// IEEE really should have made this a "bit" return // IEEE really should have made this a "bit" return
methodOkArguments(nodep, 1, 1); methodOkArguments(nodep, 1, 1);
@ -2941,12 +2941,12 @@ private:
if (!nodep->pinsp()) { if (!nodep->pinsp()) {
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"clear"); "clear");
newp->makeStatement(); newp->dtypeSetVoid();
} else { } else {
AstNode* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep); AstNode* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"erase", index_exprp->unlinkFrBack()); "erase", index_exprp->unlinkFrBack());
newp->makeStatement(); newp->dtypeSetVoid();
} }
} else if (nodep->name() == "sort" || nodep->name() == "rsort" } else if (nodep->name() == "sort" || nodep->name() == "rsort"
|| nodep->name() == "reverse" || nodep->name() == "shuffle") { || nodep->name() == "reverse" || nodep->name() == "shuffle") {
@ -2962,7 +2962,7 @@ private:
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"r_" + nodep->name(), withp); "r_" + nodep->name(), withp);
newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); 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" } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
|| nodep->name() == "unique_index") { || nodep->name() == "unique_index") {
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
@ -2974,7 +2974,7 @@ private:
} else { } else {
newp->dtypeFrom(adtypep); newp->dtypeFrom(adtypep);
} }
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else if (nodep->name() == "find" || nodep->name() == "find_first" } else if (nodep->name() == "find" || nodep->name() == "find_first"
|| nodep->name() == "find_last") { || nodep->name() == "find_last") {
AstWith* const withp = methodWithArgument(nodep, true, false, nodep->findBitDType(), AstWith* const withp = methodWithArgument(nodep, true, false, nodep->findBitDType(),
@ -2984,7 +2984,7 @@ private:
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), withp); nodep->name(), withp);
newp->dtypeFrom(adtypep); newp->dtypeFrom(adtypep);
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
|| nodep->name() == "find_last_index") { || nodep->name() == "find_last_index") {
AstWith* const withp = methodWithArgument(nodep, true, false, nodep->findBitDType(), AstWith* const withp = methodWithArgument(nodep, true, false, nodep->findBitDType(),
@ -2994,7 +2994,7 @@ private:
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), withp); nodep->name(), withp);
newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep())); newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep()));
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else { } else {
nodep->v3error("Unknown built-in associative array method " << nodep->prettyNameQ()); nodep->v3error("Unknown built-in associative array method " << nodep->prettyNameQ());
nodep->dtypeFrom(adtypep->subDTypep()); // Best guess nodep->dtypeFrom(adtypep->subDTypep()); // Best guess
@ -3048,7 +3048,7 @@ private:
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear"); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear");
newp->makeStatement(); newp->dtypeSetVoid();
} else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor"
|| nodep->name() == "sum" || nodep->name() == "product") { || nodep->name() == "sum" || nodep->name() == "product") {
// All value return // All value return
@ -3060,7 +3060,7 @@ private:
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"r_" + nodep->name(), withp); "r_" + nodep->name(), withp);
newp->dtypeFrom(adtypep->subDTypep()); newp->dtypeFrom(adtypep->subDTypep());
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else if (nodep->name() == "reverse" || nodep->name() == "shuffle" } else if (nodep->name() == "reverse" || nodep->name() == "shuffle"
|| nodep->name() == "sort" || nodep->name() == "rsort") { || nodep->name() == "sort" || nodep->name() == "rsort") {
AstWith* withp = nullptr; AstWith* withp = nullptr;
@ -3072,7 +3072,7 @@ private:
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), withp); nodep->name(), withp);
newp->makeStatement(); newp->dtypeSetVoid();
} else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
|| nodep->name() == "unique_index") { || nodep->name() == "unique_index") {
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
@ -3084,7 +3084,7 @@ private:
} else { } else {
newp->dtypeFrom(adtypep); newp->dtypeFrom(adtypep);
} }
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else if (nodep->name() == "find" || nodep->name() == "find_first" } else if (nodep->name() == "find" || nodep->name() == "find_first"
|| nodep->name() == "find_last" || nodep->name() == "find_index") { || nodep->name() == "find_last" || nodep->name() == "find_index") {
AstWith* const withp AstWith* const withp
@ -3095,7 +3095,7 @@ private:
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), withp); nodep->name(), withp);
newp->dtypeFrom(adtypep); newp->dtypeFrom(adtypep);
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
|| nodep->name() == "find_last_index") { || nodep->name() == "find_last_index") {
AstWith* const withp AstWith* const withp
@ -3106,7 +3106,7 @@ private:
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), withp); nodep->name(), withp);
newp->dtypep(newp->findQueueIndexDType()); newp->dtypep(newp->findQueueIndexDType());
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else { } else {
nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in dynamic array method " nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in dynamic array method "
<< nodep->prettyNameQ()); << nodep->prettyNameQ());
@ -3137,18 +3137,18 @@ private:
if (!nodep->pinsp()) { if (!nodep->pinsp()) {
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"clear"); "clear");
newp->makeStatement(); newp->dtypeSetVoid();
} else { } else {
AstNode* const index_exprp = methodCallQueueIndexExpr(nodep); AstNode* const index_exprp = methodCallQueueIndexExpr(nodep);
if (index_exprp->isZero()) { // delete(0) is a pop_front if (index_exprp->isZero()) { // delete(0) is a pop_front
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"pop_front"); "pop_front");
newp->dtypeFrom(adtypep->subDTypep()); newp->dtypeFrom(adtypep->subDTypep());
newp->makeStatement(); newp->dtypeSetVoid();
} else { } else {
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"erase", index_exprp->unlinkFrBack()); "erase", index_exprp->unlinkFrBack());
newp->makeStatement(); newp->dtypeSetVoid();
} }
} }
} else if (nodep->name() == "insert") { } else if (nodep->name() == "insert") {
@ -3160,12 +3160,12 @@ private:
if (index_exprp->isZero()) { // insert(0, ...) is a push_front if (index_exprp->isZero()) { // insert(0, ...) is a push_front
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"push_front", argp->exprp()->unlinkFrBack()); "push_front", argp->exprp()->unlinkFrBack());
newp->makeStatement(); newp->dtypeSetVoid();
} else { } else {
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), index_exprp->unlinkFrBack()); nodep->name(), index_exprp->unlinkFrBack());
newp->addPinsp(argp->exprp()->unlinkFrBack()); newp->addPinsp(argp->exprp()->unlinkFrBack());
newp->makeStatement(); newp->dtypeSetVoid();
} }
} else if (nodep->name() == "pop_front" || nodep->name() == "pop_back") { } else if (nodep->name() == "pop_front" || nodep->name() == "pop_back") {
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
@ -3174,9 +3174,7 @@ private:
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name()); nodep->name());
newp->dtypeFrom(adtypep->subDTypep()); newp->dtypeFrom(adtypep->subDTypep());
// Because queue methods pop_front() or pop_back() can be void cast, if (nodep->isStandaloneBodyStmt()) newp->dtypeSetVoid();
// they use makeStatement to check if they need the c++ ";" added.
if (nodep->isStandaloneBodyStmt()) newp->makeStatement();
} else if (nodep->name() == "push_back" || nodep->name() == "push_front") { } else if (nodep->name() == "push_back" || nodep->name() == "push_front") {
methodOkArguments(nodep, 1, 1); methodOkArguments(nodep, 1, 1);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
@ -3184,7 +3182,7 @@ private:
iterateCheckTyped(nodep, "push value", argp->exprp(), adtypep->subDTypep(), BOTH); iterateCheckTyped(nodep, "push value", argp->exprp(), adtypep->subDTypep(), BOTH);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), argp->exprp()->unlinkFrBack()); nodep->name(), argp->exprp()->unlinkFrBack());
newp->makeStatement(); newp->dtypeSetVoid();
} else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor"
|| nodep->name() == "sum" || nodep->name() == "product") { || nodep->name() == "sum" || nodep->name() == "product") {
AstWith* const withp AstWith* const withp
@ -3195,7 +3193,7 @@ private:
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"r_" + nodep->name(), withp); "r_" + nodep->name(), withp);
newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); 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" } else if (nodep->name() == "reverse" || nodep->name() == "shuffle"
|| nodep->name() == "sort" || nodep->name() == "rsort") { || nodep->name() == "sort" || nodep->name() == "rsort") {
AstWith* withp = nullptr; AstWith* withp = nullptr;
@ -3207,7 +3205,7 @@ private:
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), withp); nodep->name(), withp);
newp->makeStatement(); newp->dtypeSetVoid();
} else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
|| nodep->name() == "unique_index") { || nodep->name() == "unique_index") {
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
@ -3219,7 +3217,7 @@ private:
} else { } else {
newp->dtypeFrom(adtypep); newp->dtypeFrom(adtypep);
} }
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else if (nodep->name() == "find" || nodep->name() == "find_first" } else if (nodep->name() == "find" || nodep->name() == "find_first"
|| nodep->name() == "find_last") { || nodep->name() == "find_last") {
AstWith* const withp AstWith* const withp
@ -3230,7 +3228,7 @@ private:
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), withp); nodep->name(), withp);
newp->dtypeFrom(adtypep); newp->dtypeFrom(adtypep);
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
|| nodep->name() == "find_last_index") { || nodep->name() == "find_last_index") {
AstWith* const withp AstWith* const withp
@ -3241,7 +3239,7 @@ private:
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), withp); nodep->name(), withp);
newp->dtypep(newp->findQueueIndexDType()); newp->dtypep(newp->findQueueIndexDType());
if (!nodep->firstAbovep()) newp->makeStatement(); if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else { } else {
nodep->v3warn(E_UNSUPPORTED, nodep->v3warn(E_UNSUPPORTED,
"Unsupported/unknown built-in queue method " << nodep->prettyNameQ()); "Unsupported/unknown built-in queue method " << nodep->prettyNameQ());
@ -3289,7 +3287,7 @@ private:
nodep->taskp(ftaskp); nodep->taskp(ftaskp);
nodep->dtypeFrom(ftaskp); nodep->dtypeFrom(ftaskp);
nodep->classOrPackagep(classp); nodep->classOrPackagep(classp);
if (VN_IS(ftaskp, Task)) nodep->makeStatement(); if (VN_IS(ftaskp, Task)) nodep->dtypeSetVoid();
processFTaskRefArgs(nodep); processFTaskRefArgs(nodep);
} }
return; return;
@ -3432,8 +3430,8 @@ private:
AstNode* const newp = new AstAssign( AstNode* const newp = new AstAssign(
nodep->fileline(), fromp, new AstPutcN(nodep->fileline(), varrefp, rhsp, thsp)); nodep->fileline(), fromp, new AstPutcN(nodep->fileline(), varrefp, rhsp, thsp));
fromp->access(VAccess::WRITE); fromp->access(VAccess::WRITE);
nodep->replaceWith(newp); pushDeletep(nodep->backp());
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->backp()->replaceWith(newp), nodep);
} else if (nodep->name() == "getc") { } else if (nodep->name() == "getc") {
methodOkArguments(nodep, 1, 1); methodOkArguments(nodep, 1, 1);
AstArg* const arg0p = VN_AS(nodep->pinsp(), Arg); AstArg* const arg0p = VN_AS(nodep->pinsp(), Arg);
@ -4351,8 +4349,8 @@ private:
} }
AstMethodCall* const newp = new AstMethodCall{ AstMethodCall* const newp = new AstMethodCall{
nodep->fileline(), nodep->lhsp()->unlinkFrBack(), "delete", nullptr}; nodep->fileline(), nodep->lhsp()->unlinkFrBack(), "delete", nullptr};
newp->makeStatement(); newp->dtypeSetVoid();
nodep->replaceWith(newp); nodep->replaceWith(newp->makeStmt());
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
// Need to now convert it // Need to now convert it
visit(newp); visit(newp);
@ -4371,8 +4369,8 @@ private:
} }
newp->didWidth(true); newp->didWidth(true);
newp->protect(false); newp->protect(false);
newp->makeStatement(); newp->dtypeSetVoid();
nodep->replaceWith(newp); nodep->replaceWith(newp->makeStmt());
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
// return; // return;
} }
@ -4440,8 +4438,8 @@ private:
newFormat += "%@"; newFormat += "%@";
VNRelinker handle; VNRelinker handle;
argp->unlinkFrBack(&handle); argp->unlinkFrBack(&handle);
AstCMath* const newp AstCExpr* const newp
= new AstCMath(nodep->fileline(), "VL_TO_STRING(", 0, true); = new AstCExpr(nodep->fileline(), "VL_TO_STRING(", 0, true);
newp->addExprsp(argp); newp->addExprsp(argp);
newp->addExprsp(new AstText(nodep->fileline(), ")", true)); newp->addExprsp(new AstText(nodep->fileline(), ")", true));
newp->dtypeSetString(); newp->dtypeSetString();
@ -5274,7 +5272,7 @@ private:
//-------------------- //--------------------
// Default // Default
void visit(AstNodeMath* nodep) override { void visit(AstNodeExpr* nodep) override {
if (!nodep->didWidth()) { if (!nodep->didWidth()) {
nodep->v3fatalSrc( nodep->v3fatalSrc(
"Visit function missing? Widthed function missing for math node: " << nodep); "Visit function missing? Widthed function missing for math node: " << nodep);
@ -5623,7 +5621,7 @@ private:
return nodep; // May edit return nodep; // May edit
} }
void visit_boolmath_and_or(AstNodeBiop* nodep) { void visit_boolexpr_and_or(AstNodeBiop* nodep) {
// CALLER: And, Or, Xor, ... // CALLER: And, Or, Xor, ...
// Lint widths: out width = lhs width = rhs width // Lint widths: out width = lhs width = rhs width
// Signed: if lhs & rhs signed // Signed: if lhs & rhs signed
@ -6452,8 +6450,8 @@ private:
nodep->fileline(), fromp, nodep->fileline(), fromp,
new AstSFormatF(nodep->fileline(), format, false, argp->exprp()->unlinkFrBack())); new AstSFormatF(nodep->fileline(), format, false, argp->exprp()->unlinkFrBack()));
fromp->access(VAccess::WRITE); fromp->access(VAccess::WRITE);
nodep->replaceWith(newp); pushDeletep(nodep->backp());
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(nodep->backp()->replaceWith(newp), newp);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------

View File

@ -463,7 +463,7 @@ static void process() {
// Bits between widthMin() and width() are irrelevant, but may be non zero. // Bits between widthMin() and width() are irrelevant, but may be non zero.
v3Global.widthMinUsage(VWidthMinUsage::VERILOG_WIDTH); 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()); V3Clean::cleanAll(v3Global.rootp());
// Move wide constants to BLOCK temps / ConstPool. // Move wide constants to BLOCK temps / ConstPool.

View File

@ -1196,7 +1196,7 @@ def write_dfg_dfg_to_ast(filename):
"void visit(Dfg{t}* vtxp) override {{\n".format(t=node.name)) "void visit(Dfg{t}* vtxp) override {{\n".format(t=node.name))
for i in range(node.arity): for i in range(node.arity):
fh.write( 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)) .format(i=i, j=i + 1))
fh.write( fh.write(
" m_resultp = makeNode<Ast{t}>(vtxp".format(t=node.name)) " m_resultp = makeNode<Ast{t}>(vtxp".format(t=node.name))

View File

@ -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
// Blank lines for type insertion // Blank lines for type insertion
// Blank lines for type insertion
%start source_text %start source_text
@ -2689,7 +2690,7 @@ genvar_iteration<nodep>: // ==IEEE: genvar_iteration
| varRefBase yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); } | 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)); } | varRefBase yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
// // inc_or_dec_operator // // 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 | yP_PLUSPLUS varRefBase
{ $$ = new AstAssign{$1, $2, new AstAdd{$1, $2->cloneTree(true), { $$ = new AstAssign{$1, $2, new AstAdd{$1, $2->cloneTree(true),
new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; } new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; }
@ -3284,23 +3285,27 @@ statement_item<nodep>: // IEEE: statement_item
{ $$ = $4; { $$ = $4;
FileLine* const newfl = new FileLine{$$->fileline()}; FileLine* const newfl = new FileLine{$$->fileline()};
newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true); 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 ')' ';' | yVOID yP_TICK '(' expr '.' task_subroutine_callNoMethod ')' ';'
{ $$ = new AstDot{$5, false, $4, $6}; { $$ = new AstDot{$5, false, $4, $6};
FileLine* const newfl = new FileLine{$6->fileline()}; FileLine* const newfl = new FileLine{$6->fileline()};
newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true); 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 included here to resolve our not knowing what is a method call
// // Expr here must result in a subroutine_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 } //UNSUP fexpr '.' array_methodNoRoot ';' { UNSUP }
| fexpr '.' task_subroutine_callNoMethod ';' { $$ = new AstDot($<fl>2, false, $1, $3); } | fexpr '.' task_subroutine_callNoMethod ';' { $$ = (new AstDot{$<fl>2, false, $1, $3})->makeStmt(); }
//UNSUP fexprScope ';' { UNSUP } //UNSUP fexprScope ';' { UNSUP }
// // Not here in IEEE; from class_constructor_declaration // // Not here in IEEE; from class_constructor_declaration
// // Because we've joined class_constructor_declaration into generic functions // // Because we've joined class_constructor_declaration into generic functions
// // Way over-permissive; // // Way over-permissive;
// // IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ] // // IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ]
| fexpr '.' class_new ';' { $$ = new AstDot($<fl>2, false, $1, $3); } | fexpr '.' class_new ';' { $$ = (new AstDot{$<fl>2, false, $1, $3})->makeStmt(); }
// //
| statementVerilatorPragmas { $$ = $1; } | statementVerilatorPragmas { $$ = $1; }
// //
@ -3426,7 +3431,7 @@ foperator_assignment<nodep>: // IEEE: operator_assignment (for first part of
//UNSUP BISONPRE_COPY(operator_assignment,{s/~f~/f/g}) // {copied} //UNSUP BISONPRE_COPY(operator_assignment,{s/~f~/f/g}) // {copied}
; ;
inc_or_dec_expression<nodep>: // ==IEEE: inc_or_dec_expression inc_or_dec_expression<nodeExprp>: // ==IEEE: inc_or_dec_expression
// // Need fexprScope instead of variable_lvalue to prevent conflict // // Need fexprScope instead of variable_lvalue to prevent conflict
~l~exprScope yP_PLUSPLUS ~l~exprScope yP_PLUSPLUS
{ $<fl>$ = $<fl>1; $$ = new AstPostAdd{$2, new AstConst{$2, AstConst::StringToParse(), "'b1"}, $1, $1->cloneTree(true)}; } { $<fl>$ = $<fl>1; $$ = new AstPostAdd{$2, new AstConst{$2, AstConst::StringToParse(), "'b1"}, $1, $1->cloneTree(true)}; }
@ -3439,7 +3444,7 @@ inc_or_dec_expression<nodep>: // ==IEEE: inc_or_dec_expression
{ $<fl>$ = $<fl>1; $$ = new AstPreSub{$1, new AstConst{$1, AstConst::StringToParse(), "'b1"}, $2, $2->cloneTree(true)}; } { $<fl>$ = $<fl>1; $$ = new AstPreSub{$1, new AstConst{$1, AstConst::StringToParse(), "'b1"}, $2, $2->cloneTree(true)}; }
; ;
finc_or_dec_expression<nodep>: // ==IEEE: inc_or_dec_expression finc_or_dec_expression<nodeExprp>: // ==IEEE: inc_or_dec_expression
BISONPRE_COPY(inc_or_dec_expression,{s/~l~/f/g}) // {copied} BISONPRE_COPY(inc_or_dec_expression,{s/~l~/f/g}) // {copied}
; ;
@ -3684,14 +3689,14 @@ loop_variables<nodep>: // IEEE: loop_variables
//************************************************ //************************************************
// Functions/tasks // Functions/tasks
taskRef<nodep>: // IEEE: part of tf_call taskRef<nodeExprp>: // IEEE: part of tf_call
id { $$ = new AstTaskRef($<fl>1,*$1,nullptr); } id { $$ = new AstTaskRef($<fl>1,*$1,nullptr); }
| id '(' list_of_argumentsE ')' { $$ = new AstTaskRef($<fl>1,*$1,$3); } | id '(' list_of_argumentsE ')' { $$ = new AstTaskRef($<fl>1,*$1,$3); }
| packageClassScope id '(' list_of_argumentsE ')' | packageClassScope id '(' list_of_argumentsE ')'
{ $$ = AstDot::newIfPkg($<fl>2, $1, new AstTaskRef($<fl>2, *$2, $4)); } { $$ = AstDot::newIfPkg($<fl>2, $1, new AstTaskRef($<fl>2, *$2, $4)); }
; ;
funcRef<nodep>: // IEEE: part of tf_call funcRef<nodeExprp>: // IEEE: part of tf_call
// // package_scope/hierarchical_... is part of expr, so just need ID // // package_scope/hierarchical_... is part of expr, so just need ID
// // making-a id-is-a // // making-a id-is-a
// // ----------------- ------------------ // // ----------------- ------------------
@ -3713,9 +3718,9 @@ task_subroutine_callNoMethod<nodep>: // function_subroutine_callNoMethod (as
// // IEEE: tf_call // // IEEE: tf_call
taskRef { $$ = $1; } taskRef { $$ = $1; }
// // funcref below not task ref to avoid conflict, must later handle either // // 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 // // can call as method and yWITH without parenthesis
| id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, true, new AstFuncRef($<fl>1, *$1, nullptr), $4); } | id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse{$2, new AstFuncRef{$<fl>1, *$1, nullptr}, $4}; }
| system_t_call { $$ = $1; } | system_t_call { $$ = $1; }
// // IEEE: method_call requires a "." so is in expr // // IEEE: method_call requires a "." so is in expr
// // IEEE: ['std::'] not needed, as normal std package resolution will find it // // IEEE: ['std::'] not needed, as normal std package resolution will find it
@ -3725,12 +3730,12 @@ task_subroutine_callNoMethod<nodep>: // function_subroutine_callNoMethod (as
//UNSUP funcRef yWITH__CUR constraint_block { } //UNSUP funcRef yWITH__CUR constraint_block { }
; ;
function_subroutine_callNoMethod<nodep>: // IEEE: function_subroutine_call (as function) function_subroutine_callNoMethod<nodeExprp>: // IEEE: function_subroutine_call (as function)
// // IEEE: tf_call // // IEEE: tf_call
funcRef { $$ = $1; } 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 // // can call as method and yWITH without parenthesis
| id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, false, new AstFuncRef($<fl>1, *$1, nullptr), $4); } | id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse{$2, new AstFuncRef{$<fl>1, *$1, nullptr}, $4}; }
| system_f_call { $$ = $1; } | system_f_call { $$ = $1; }
// // IEEE: method_call requires a "." so is in expr // // IEEE: method_call requires a "." so is in expr
// // IEEE: ['std::'] not needed, as normal std package resolution will find it // // IEEE: ['std::'] not needed, as normal std package resolution will find it
@ -3739,7 +3744,7 @@ function_subroutine_callNoMethod<nodep>: // IEEE: function_subroutine_cal
// // Note yNULL is already part of expressions, so they come for free // // Note yNULL is already part of expressions, so they come for free
| funcRef yWITH__CUR constraint_block | funcRef yWITH__CUR constraint_block
{ $$ = $1; BBUNSUP($2, "Unsupported: randomize() 'with' constraint"); } { $$ = $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<nodep>: // IEEE: system_tf_call (as task) system_t_call<nodep>: // IEEE: system_tf_call (as task)
@ -3872,7 +3877,7 @@ system_t_call<nodep>: // IEEE: system_tf_call (as task)
| system_f_call_or_t { $$ = new AstSysFuncAsTask($<fl>1, $1); } | system_f_call_or_t { $$ = new AstSysFuncAsTask($<fl>1, $1); }
; ;
system_f_call<nodep>: // IEEE: system_tf_call (as func) system_f_call<nodeExprp>: // IEEE: system_tf_call (as func)
yaD_PLI systemDpiArgsE { $$ = new AstFuncRef($<fl>1, *$1, $2); VN_CAST($$, FuncRef)->pli(true); } yaD_PLI systemDpiArgsE { $$ = new AstFuncRef($<fl>1, *$1, $2); VN_CAST($$, FuncRef)->pli(true); }
// //
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? nullptr : new AstUCFunc($1,$3)); } | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? nullptr : new AstUCFunc($1,$3)); }
@ -3887,7 +3892,7 @@ systemDpiArgsE<nodep>: // IEEE: part of system_if_call for aruments of
| '(' exprList ')' { $$ = GRAMMARP->argWrapList($2); } | '(' exprList ')' { $$ = GRAMMARP->argWrapList($2); }
; ;
system_f_call_or_t<nodep>: // IEEE: part of system_tf_call (can be task or func) system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task or func)
yD_ACOS '(' expr ')' { $$ = new AstAcosD($1,$3); } yD_ACOS '(' expr ')' { $$ = new AstAcosD($1,$3); }
| yD_ACOSH '(' expr ')' { $$ = new AstAcoshD($1,$3); } | yD_ACOSH '(' expr ')' { $$ = new AstAcoshD($1,$3); }
| yD_ASIN '(' expr ')' { $$ = new AstAsinD($1,$3); } | yD_ASIN '(' expr ')' { $$ = new AstAsinD($1,$3); }
@ -4276,9 +4281,9 @@ array_methodNoRoot<nodeFTaskRefp>:
array_methodWith<nodep>: array_methodWith<nodep>:
array_methodNoRoot parenE { $$ = $1; } array_methodNoRoot parenE { $$ = $1; }
| array_methodNoRoot parenE yWITH__PAREN '(' expr ')' | array_methodNoRoot parenE yWITH__PAREN '(' expr ')'
{ $$ = new AstWithParse($3, false, $1, $5); } { $$ = new AstWithParse{$3, $1, $5}; }
| array_methodNoRoot '(' expr ')' yWITH__PAREN '(' expr ')' | array_methodNoRoot '(' expr ')' yWITH__PAREN '(' expr ')'
{ $$ = new AstWithParse($5, false, $1, $7); $1->addPinsp(new AstArg($<fl>3, "", $3)); } { $$ = new AstWithParse{$5, $1, $7}; $1->addPinsp(new AstArg($<fl>3, "", $3)); }
; ;
dpi_import_export<nodep>: // ==IEEE: dpi_import_export dpi_import_export<nodep>: // ==IEEE: dpi_import_export
@ -4350,11 +4355,11 @@ exprOrDataTypeEqE<nodep>: // IEEE: optional '=' expression (part of param_
| '=' exprOrDataType { $$ = $2; } | '=' exprOrDataType { $$ = $2; }
; ;
constExpr<nodep>: constExpr<nodeExprp>:
expr { $$ = $1; } expr { $$ = $1; }
; ;
expr<nodep>: // IEEE: part of expression/constant_expression/primary expr<nodeExprp>: // IEEE: part of expression/constant_expression/primary
// *SEE BELOW* // IEEE: primary/constant_primary // *SEE BELOW* // IEEE: primary/constant_primary
// //
// // IEEE: unary_operator primary // // IEEE: unary_operator primary
@ -4522,7 +4527,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/
| ~l~expr yDIST '{' dist_list '}' { $$ = $1; BBUNSUP($2, "Unsupported: dist"); } | ~l~expr yDIST '{' dist_list '}' { $$ = $1; BBUNSUP($2, "Unsupported: dist"); }
; ;
fexpr<nodep>: // For use as first part of statement (disambiguates <=) fexpr<nodeExprp>: // 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} BISONPRE_COPY(expr,{s/~l~/f/g; s/~r~/f/g; s/~f__IGNORE~/__IGNORE/g;}) // {copied}
; ;
@ -4555,11 +4560,11 @@ fexpr<nodep>: // For use as first part of statement (disambigu
//UNSUP | '(' event_expression ':' expr ':' expr ')' { $<fl>$ = $<fl>1; $$ = "(...)"; } //UNSUP | '(' event_expression ':' expr ':' expr ')' { $<fl>$ = $<fl>1; $$ = "(...)"; }
//UNSUP ; //UNSUP ;
exprNoStr<nodep>: // expression with string removed exprNoStr<nodeExprp>: // expression with string removed
BISONPRE_COPY(expr,{s/~noStr__IGNORE~/Ignore/g;}) // {copied} BISONPRE_COPY(expr,{s/~noStr__IGNORE~/Ignore/g;}) // {copied}
; ;
exprOkLvalue<nodep>: // expression that's also OK to use as a variable_lvalue exprOkLvalue<nodeExprp>: // expression that's also OK to use as a variable_lvalue
~l~exprScope { $$ = $1; } ~l~exprScope { $$ = $1; }
// // IEEE: concatenation/constant_concatenation // // IEEE: concatenation/constant_concatenation
// // Replicate(1) required as otherwise "{a}" would not be self-determined // // Replicate(1) required as otherwise "{a}" would not be self-determined
@ -4581,7 +4586,7 @@ exprOkLvalue<nodep>: // expression that's also OK to use as a variabl
| streaming_concatenation { $$ = $1; } | streaming_concatenation { $$ = $1; }
; ;
fexprOkLvalue<nodep>: // exprOkLValue, For use as first part of statement (disambiguates <=) fexprOkLvalue<nodeExprp>: // exprOkLValue, For use as first part of statement (disambiguates <=)
BISONPRE_COPY(exprOkLvalue,{s/~l~/f/g}) // {copied} BISONPRE_COPY(exprOkLvalue,{s/~l~/f/g}) // {copied}
; ;
@ -4601,11 +4606,11 @@ fexprOkLvalue<nodep>: // exprOkLValue, For use as first part of statem
//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/pev_/g}) // {copied} //UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/pev_/g}) // {copied}
//UNSUP ; //UNSUP ;
fexprLvalue<nodep>: // For use as first part of statement (disambiguates <=) fexprLvalue<nodeExprp>: // For use as first part of statement (disambiguates <=)
fexprOkLvalue { $<fl>$ = $<fl>1; $$ = $1; } fexprOkLvalue { $<fl>$ = $<fl>1; $$ = $1; }
; ;
exprScope<nodep>: // scope and variable for use to inside an expression exprScope<nodeExprp>: // scope and variable for use to inside an expression
// // Here we've split method_call_root | implicit_class_handle | class_scope | package_scope // // 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. // // 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) // // (note method_call_root was simplified to require a primary in 1800-2009)
@ -4624,7 +4629,7 @@ exprScope<nodep>: // scope and variable for use to inside an expre
| ySUPER { $$ = new AstParseRef($<fl>1, VParseRefExp::PX_ROOT, "super"); } | ySUPER { $$ = new AstParseRef($<fl>1, VParseRefExp::PX_ROOT, "super"); }
; ;
fexprScope<nodep>: // exprScope, For use as first part of statement (disambiguates <=) fexprScope<nodeExprp>: // exprScope, For use as first part of statement (disambiguates <=)
BISONPRE_COPY(exprScope,{s/~l~/f/g}) // {copied} BISONPRE_COPY(exprScope,{s/~l~/f/g}) // {copied}
; ;
@ -4656,23 +4661,23 @@ cStrList<nodep>:
| exprStrText ',' cStrList { $$ = $1->addNext($3); } | exprStrText ',' cStrList { $$ = $1->addNext($3); }
; ;
cateList<nodep>: cateList<nodeExprp>:
// // Not just 'expr' to prevent conflict via stream_concOrExprOrType // // Not just 'expr' to prevent conflict via stream_concOrExprOrType
stream_expression { $$ = $1; } stream_expression { $$ = $1; }
| cateList ',' stream_expression { $$ = new AstConcat($2,$1,$3); } | cateList ',' stream_expression { $$ = new AstConcat($2,$1,$3); }
; ;
exprListE<nodep>: exprListE<nodeExprp>:
/* empty */ { $$ = nullptr; } /* empty */ { $$ = nullptr; }
| exprList { $$ = $1; } | exprList { $$ = $1; }
; ;
exprList<nodep>: exprList<nodeExprp>:
expr { $$ = $1; } expr { $$ = $1; }
| exprList ',' expr { $$ = $1->addNext($3); } | exprList ',' expr { $$ = $1->addNext($3); }
; ;
exprDispList<nodep>: // exprList for within $display exprDispList<nodeExprp>: // exprList for within $display
expr { $$ = $1; } expr { $$ = $1; }
| exprDispList ',' expr { $$ = $1->addNext($3); } | exprDispList ',' expr { $$ = $1->addNext($3); }
// // ,, creates a space in $display // // ,, creates a space in $display
@ -4735,7 +4740,7 @@ argsDotted<nodep>: // IEEE: part of list_of_arguments
//UNSUP | '.' idAny '(' pev_expr ')' { $$ = new AstArg($<fl>2, *$2, $4); } //UNSUP | '.' idAny '(' pev_expr ')' { $$ = new AstArg($<fl>2, *$2, $4); }
//UNSUP ; //UNSUP ;
streaming_concatenation<nodep>: // ==IEEE: streaming_concatenation streaming_concatenation<nodeExprp>: // ==IEEE: streaming_concatenation
// // Need to disambiguate {<< expr-{ ... expr-} stream_concat } // // Need to disambiguate {<< expr-{ ... expr-} stream_concat }
// // From {<< stream-{ ... stream-} } // // From {<< stream-{ ... stream-} }
// // Likewise simple_type's idScoped from constExpr's idScope // // Likewise simple_type's idScoped from constExpr's idScope
@ -4758,7 +4763,7 @@ stream_concatenation<nodep>: // ==IEEE: stream_concatenation
'{' cateList '}' { $$ = $2; } '{' cateList '}' { $$ = $2; }
; ;
stream_expression<nodep>: // ==IEEE: stream_expression stream_expression<nodeExprp>: // ==IEEE: stream_expression
// // IEEE: array_range_expression expanded below // // IEEE: array_range_expression expanded below
expr { $$ = $1; } expr { $$ = $1; }
//UNSUP expr yWITH__BRA '[' expr ']' { UNSUP } //UNSUP expr yWITH__BRA '[' expr ']' { UNSUP }
@ -5077,7 +5082,7 @@ idSVKwd<strp>: // Warn about non-forward compatible Verilog 200
{ static string s = "final"; $$ = &s; ERRSVKWD($1,*$$); $<fl>$ = $<fl>1; } { static string s = "final"; $$ = &s; ERRSVKWD($1,*$$); $<fl>$ = $<fl>1; }
; ;
variable_lvalue<nodep>: // IEEE: variable_lvalue or net_lvalue variable_lvalue<nodeExprp>: // IEEE: variable_lvalue or net_lvalue
// // Note many variable_lvalue's must use exprOkLvalue when arbitrary expressions may also exist // // Note many variable_lvalue's must use exprOkLvalue when arbitrary expressions may also exist
idClassSel { $$ = $1; } idClassSel { $$ = $1; }
| '{' variable_lvalueConcList '}' { $$ = $2; } | '{' variable_lvalueConcList '}' { $$ = $2; }
@ -5089,7 +5094,7 @@ variable_lvalue<nodep>: // IEEE: variable_lvalue or net_lvalue
| streaming_concatenation { $$ = $1; } | streaming_concatenation { $$ = $1; }
; ;
variable_lvalueConcList<nodep>: // IEEE: part of variable_lvalue: '{' variable_lvalue { ',' variable_lvalue } '}' variable_lvalueConcList<nodeExprp>: // IEEE: part of variable_lvalue: '{' variable_lvalue { ',' variable_lvalue } '}'
variable_lvalue { $$ = $1; } variable_lvalue { $$ = $1; }
| variable_lvalueConcList ',' variable_lvalue { $$ = new AstConcat($2,$1,$3); } | variable_lvalueConcList ',' variable_lvalue { $$ = new AstConcat($2,$1,$3); }
; ;
@ -5100,7 +5105,7 @@ variable_lvalueConcList<nodep>: // IEEE: part of variable_lvalue: '{' variable_l
//UNSUP ; //UNSUP ;
// VarRef to dotted, and/or arrayed, and/or bit-ranged variable // VarRef to dotted, and/or arrayed, and/or bit-ranged variable
idClassSel<nodep>: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable idClassSel<nodeExprp>: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable
idDotted { $$ = $1; } idDotted { $$ = $1; }
// // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select
| yTHIS '.' idDotted | yTHIS '.' idDotted
@ -5124,7 +5129,7 @@ idClassSelForeach<nodep>:
| packageClassScope idDottedForeach { $$ = new AstDot($<fl>2, true, $1, $2); } | packageClassScope idDottedForeach { $$ = new AstDot($<fl>2, true, $1, $2); }
; ;
idDotted<nodep>: idDotted<nodeExprp>:
yD_ROOT '.' idDottedMore yD_ROOT '.' idDottedMore
{ $$ = new AstDot($2, false, new AstParseRef($<fl>1, VParseRefExp::PX_ROOT, "$root"), $3); } { $$ = new AstDot($2, false, new AstParseRef($<fl>1, VParseRefExp::PX_ROOT, "$root"), $3); }
| idDottedMore { $$ = $1; } | idDottedMore { $$ = $1; }
@ -5136,7 +5141,7 @@ idDottedForeach<nodep>:
| idDottedMoreForeach { $$ = $1; } | idDottedMoreForeach { $$ = $1; }
; ;
idDottedMore<nodep>: idDottedMore<nodeExprp>:
idArrayed { $$ = $1; } idArrayed { $$ = $1; }
| idDottedMore '.' idArrayed { $$ = new AstDot($2, false, $1, $3); } | idDottedMore '.' idArrayed { $$ = new AstDot($2, false, $1, $3); }
; ;
@ -5151,7 +5156,7 @@ idDottedMoreForeach<nodep>:
// we'll assume so and cleanup later. // we'll assume so and cleanup later.
// id below includes: // id below includes:
// enum_identifier // enum_identifier
idArrayed<nodep>: // IEEE: id + select idArrayed<nodeExprp>: // IEEE: id + select
id id
{ $$ = new AstParseRef($<fl>1, VParseRefExp::PX_TEXT, *$1, nullptr, nullptr); } { $$ = new AstParseRef($<fl>1, VParseRefExp::PX_TEXT, *$1, nullptr, nullptr); }
// // IEEE: id + part_select_range/constant_part_select_range // // IEEE: id + part_select_range/constant_part_select_range
@ -5174,9 +5179,9 @@ idArrayedForeach<nodep>: // IEEE: id + select (under foreach expression)
// // IEEE: loop_variables (under foreach expression) // // IEEE: loop_variables (under foreach expression)
// // To avoid conflicts we allow expr as first element, must post-check // // To avoid conflicts we allow expr as first element, must post-check
| idArrayed '[' expr ',' loop_variables ']' | idArrayed '[' expr ',' loop_variables ']'
{ $3 = addNextNull($3, $5); $$ = new AstSelLoopVars($2, $1, $3); } { $$ = new AstSelLoopVars{$2, $1, addNextNull(static_cast<AstNode*>($3), $5)}; }
| idArrayed '[' ',' loop_variables ']' | idArrayed '[' ',' loop_variables ']'
{ $4 = addNextNull(static_cast<AstNode*>(new AstEmpty{$3}), $4); $$ = new AstSelLoopVars($2, $1, $4); } { $$ = new AstSelLoopVars{$2, $1, addNextNull(static_cast<AstNode*>(new AstEmpty{$3}), $4)}; }
; ;
// VarRef without any dots or vectorizaion // VarRef without any dots or vectorizaion
@ -5195,7 +5200,7 @@ str<strp>: // yaSTRING but with \{escapes} need decoded
yaSTRING { $$ = PARSEP->newString(GRAMMARP->deQuote($<fl>1,*$1)); } yaSTRING { $$ = PARSEP->newString(GRAMMARP->deQuote($<fl>1,*$1)); }
; ;
strAsInt<nodep>: strAsInt<nodeExprp>:
yaSTRING yaSTRING
{ if ($1->empty()) { { if ($1->empty()) {
// else "" is not representable as number as is width 0 // else "" is not representable as number as is width 0
@ -5208,7 +5213,7 @@ strAsInt<nodep>:
} }
; ;
strAsIntIgnore<nodep>: // strAsInt, but never matches for when expr shouldn't parse strings strAsIntIgnore<nodeExprp>: // strAsInt, but never matches for when expr shouldn't parse strings
yaSTRING__IGNORE { $$ = nullptr; yyerror("Impossible token"); } yaSTRING__IGNORE { $$ = nullptr; yyerror("Impossible token"); }
; ;
@ -6563,7 +6568,7 @@ constraintStaticE<cbool>: // IEEE: part of extern_constraint_declaration
//********************************************************************** //**********************************************************************
// Constants // Constants
timeNumAdjusted<nodep>: // Time constant, adjusted to module's time units/precision timeNumAdjusted<nodeExprp>: // Time constant, adjusted to module's time units/precision
yaTIMENUM yaTIMENUM
{ $$ = new AstTimeImport($<fl>1, new AstConst($<fl>1, AstConst::RealDouble(), $1)); } { $$ = new AstTimeImport($<fl>1, new AstConst($<fl>1, AstConst::RealDouble(), $1)); }
; ;

View File

@ -148,7 +148,8 @@ module Vt_debug_emitv_t;
other = f(i); other = f(i);
$display("stmt %~ %~", $display("stmt %~ %~",
iother, other); iother, other);
t()end t();
end
i = (i + 'h1); i = (i + 'h1);
end end
end end
@ -189,7 +190,8 @@ module Vt_debug_emitv_t;
cyc <= (cyc + 'sh1); cyc <= (cyc + 'sh1);
r <= (r + 0.01); r <= (r + 0.01);
fo = cyc; fo = cyc;
sub.inc(fosum)sum = sub.f(sum); sub.inc(fosum);
sum = sub.f(sum);
$display("[%0t] sum = %~", $timesum, sum); $display("[%0t] sum = %~", $timesum, sum);
$display("a?= %d", ($c('sh1) ? $c('sh14) $display("a?= %d", ($c('sh1) ? $c('sh14)
: $c('sh1e))); : $c('sh1e)));

View File

@ -2,7 +2,7 @@
16 | foo(bus_we_select_from[2]); 16 | foo(bus_we_select_from[2]);
| ^ | ^
... For error description see https://verilator.org/warn/TASKNSVAR?v=latest ... 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; 10 | sig = '1;
| ^~~ | ^~~
... See the manual at https://verilator.org/verilator_doc.html for more assistance. ... See the manual at https://verilator.org/verilator_doc.html for more assistance.

File diff suppressed because it is too large Load Diff

View File

@ -40,11 +40,13 @@
</func> </func>
<initial loc="d,39,4,39,11"> <initial loc="d,39,4,39,11">
<begin loc="d,39,12,39,17"> <begin loc="d,39,12,39,17">
<taskref loc="d,41,7,41,8" name="f"> <stmtexpr loc="d,41,7,41,8">
<arg loc="d,41,9,41,736"> <taskref loc="d,41,7,41,8" name="f" dtype_id="8">
<const loc="d,41,9,41,736" name="&quot;&#1;&#2;&#3;&#4;&#5;&#6;&#7;&#8;&#9;&#10;&#11;&#12;&#13;&#14;&#15;&#16;&#17;&#18;&#19;&#20;&#21;&#22;&#23;&#24;&#25;&#26;&#27;&#28;&#29;&#30;&#31; !&quot;#$%&amp;&apos;()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~&#127;&#128;&#129;&#130;&#131;&#132;&#133;&#134;&#135;&#136;&#137;&#138;&#139;&#140;&#141;&#142;&#143;&#144;&#145;&#146;&#147;&#148;&#149;&#150;&#151;&#152;&#153;&#154;&#155;&#156;&#157;&#158;&#159;&#160;&#161;&#162;&#163;&#164;&#165;&#166;&#167;&#168;&#169;&#170;&#171;&#172;&#173;&#174;&#175;&#176;&#177;&#178;&#179;&#180;&#181;&#182;&#183;&#184;&#185;&#186;&#187;&#188;&#189;&#190;&#191;&#192;&#193;&#194;&#195;&#196;&#197;&#198;&#199;&#200;&#201;&#202;&#203;&#204;&#205;&#206;&#207;&#208;&#209;&#210;&#211;&#212;&#213;&#214;&#215;&#216;&#217;&#218;&#219;&#220;&#221;&#222;&#223;&#224;&#225;&#226;&#227;&#228;&#229;&#230;&#231;&#232;&#233;&#234;&#235;&#236;&#237;&#238;&#239;&#240;&#241;&#242;&#243;&#244;&#245;&#246;&#247;&#248;&#249;&#250;&#251;&#252;&#253;&#254;&#255;&quot;" dtype_id="7"/> <arg loc="d,41,9,41,736">
</arg> <const loc="d,41,9,41,736" name="&quot;&#1;&#2;&#3;&#4;&#5;&#6;&#7;&#8;&#9;&#10;&#11;&#12;&#13;&#14;&#15;&#16;&#17;&#18;&#19;&#20;&#21;&#22;&#23;&#24;&#25;&#26;&#27;&#28;&#29;&#30;&#31; !&quot;#$%&amp;&apos;()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~&#127;&#128;&#129;&#130;&#131;&#132;&#133;&#134;&#135;&#136;&#137;&#138;&#139;&#140;&#141;&#142;&#143;&#144;&#145;&#146;&#147;&#148;&#149;&#150;&#151;&#152;&#153;&#154;&#155;&#156;&#157;&#158;&#159;&#160;&#161;&#162;&#163;&#164;&#165;&#166;&#167;&#168;&#169;&#170;&#171;&#172;&#173;&#174;&#175;&#176;&#177;&#178;&#179;&#180;&#181;&#182;&#183;&#184;&#185;&#186;&#187;&#188;&#189;&#190;&#191;&#192;&#193;&#194;&#195;&#196;&#197;&#198;&#199;&#200;&#201;&#202;&#203;&#204;&#205;&#206;&#207;&#208;&#209;&#210;&#211;&#212;&#213;&#214;&#215;&#216;&#217;&#218;&#219;&#220;&#221;&#222;&#223;&#224;&#225;&#226;&#227;&#228;&#229;&#230;&#231;&#232;&#233;&#234;&#235;&#236;&#237;&#238;&#239;&#240;&#241;&#242;&#243;&#244;&#245;&#246;&#247;&#248;&#249;&#250;&#251;&#252;&#253;&#254;&#255;&quot;" dtype_id="7"/>
</taskref> </arg>
</taskref>
</stmtexpr>
</begin> </begin>
</initial> </initial>
</module> </module>
@ -55,21 +57,22 @@
</modport> </modport>
</iface> </iface>
<typetable loc="a,0,0,0,0"> <typetable loc="a,0,0,0,0">
<voiddtype loc="d,41,7,41,8" id="8"/>
<basicdtype loc="d,8,4,8,11" id="6" name="integer" left="31" right="0" signed="true"/> <basicdtype loc="d,8,4,8,11" id="6" name="integer" left="31" right="0" signed="true"/>
<basicdtype loc="d,14,11,14,17" id="1" name="logic"/> <basicdtype loc="d,14,11,14,17" id="1" name="logic"/>
<basicdtype loc="d,21,7,21,12" id="8" name="logic"/> <basicdtype loc="d,21,7,21,12" id="9" name="logic"/>
<basicdtype loc="d,22,7,22,12" id="9" name="logic"/> <basicdtype loc="d,22,7,22,12" id="10" name="logic"/>
<basicdtype loc="d,23,7,23,12" id="10" name="logic"/> <basicdtype loc="d,23,7,23,12" id="11" name="logic"/>
<basicdtype loc="d,24,7,24,12" id="11" name="logic"/> <basicdtype loc="d,24,7,24,12" id="12" name="logic"/>
<structdtype loc="d,20,12,20,18" id="2" name="m.my_struct"> <structdtype loc="d,20,12,20,18" id="2" name="m.my_struct">
<memberdtype loc="d,21,19,21,22" id="12" name="clk" tag="this is clk" sub_dtype_id="8"/> <memberdtype loc="d,21,19,21,22" id="13" name="clk" tag="this is clk" sub_dtype_id="9"/>
<memberdtype loc="d,22,19,22,20" id="13" name="k" sub_dtype_id="9"/> <memberdtype loc="d,22,19,22,20" id="14" name="k" sub_dtype_id="10"/>
<memberdtype loc="d,23,19,23,25" id="14" name="enable" tag="enable" sub_dtype_id="10"/> <memberdtype loc="d,23,19,23,25" id="15" name="enable" tag="enable" sub_dtype_id="11"/>
<memberdtype loc="d,24,19,24,23" id="15" name="data" tag="data" sub_dtype_id="11"/> <memberdtype loc="d,24,19,24,23" id="16" name="data" tag="data" sub_dtype_id="12"/>
</structdtype> </structdtype>
<ifacerefdtype loc="d,29,8,29,12" id="3" modportname=""/> <ifacerefdtype loc="d,29,8,29,12" id="3" modportname=""/>
<basicdtype loc="d,31,27,31,28" id="5" name="logic" left="31" right="0"/> <basicdtype loc="d,31,27,31,28" id="5" name="logic" left="31" right="0"/>
<refdtype loc="d,31,4,31,13" id="16" name="my_struct" sub_dtype_id="2"/> <refdtype loc="d,31,4,31,13" id="17" name="my_struct" sub_dtype_id="2"/>
<unpackarraydtype loc="d,31,26,31,27" id="4" sub_dtype_id="2"> <unpackarraydtype loc="d,31,26,31,27" id="4" sub_dtype_id="2">
<range loc="d,31,26,31,27"> <range loc="d,31,26,31,27">
<const loc="d,31,27,31,28" name="32&apos;h0" dtype_id="5"/> <const loc="d,31,27,31,28" name="32&apos;h0" dtype_id="5"/>