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
pointer to the ``AstNode`` currently being processed.
There are notable sub-hierarchies of the ``AstNode`` sub-types, namely:
1. All AST nodes representing data types derive from ``AstNodeDType``.
2. All AST nodes representing expressions (i.e.: anything that stands for,
or evaluates to a value) derive from ``AstNodeExpr``.
``VNVisitor``
^^^^^^^^^^^^^^^
@ -205,7 +212,7 @@ writing DFG passes easier.
The ``DfgGraph`` represents combinational logic equations as a graph of
``DfgVertex`` vertices. Each sub-class of ``DfgVertex`` corresponds to an
expression (a sub-class of ``AstNodeMath``), a constanat, or a variable
expression (a sub-class of ``AstNodeExpr``), a constanat, or a variable
reference. LValues and RValues referencing the same storage location are
represented by the same ``DfgVertex``. Consumers of such vertices read as the
LValue, writers of such vertices write the RValue. The bulk of the final
@ -1117,7 +1124,7 @@ will be used as the base name of the generated operand accessors, and
An example of the full syntax of the directive is
``@astgen op1 := lhsp : AstNodeMath``.
``@astgen op1 := lhsp : AstNodeExpr``.
``astnode`` generates accessors for the child nodes based on these directives.
For non-list children, the names of the getter and setter both are that of the

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,
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
static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP const lwp) VL_MT_SAFE {
@ -1917,7 +1917,7 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, WDataOutP owp, WDataIn
}
//======================================================================
// Math needing insert/select
// Expressions needing insert/select
// Return QData from double (numeric)
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real

View File

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

View File

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

View File

@ -105,7 +105,7 @@ private:
// This allows syntax errors and such to be detected normally.
(v3Global.opt.assertOn()
? 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{}}))),
nodep};
newp->isBoundsCheck(true); // To avoid LATCH warning

View File

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

View File

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

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; }
VOptionBool unconnectedDrive() const { return m_unconnectedDrive; }
};
class AstNodePreSel VL_NOT_FINAL : public AstNode {
// Something that becomes an AstSel
// @astgen op1 := fromp : AstNode
// @astgen op2 := rhsp : AstNode
// @astgen op3 := thsp : Optional[AstNode]
// @astgen op4 := attrp : Optional[AstAttrOf]
protected:
AstNodePreSel(VNType t, FileLine* fl, AstNode* fromp, AstNode* rhsp, AstNode* thsp)
: AstNode{t, fl} {
this->fromp(fromp);
this->rhsp(rhsp);
this->thsp(thsp);
}
public:
ASTGEN_MEMBERS_AstNodePreSel;
// METHODS
bool same(const AstNode*) const override { return true; }
};
class AstNodeProcedure VL_NOT_FINAL : public AstNode {
// IEEE procedure: initial, final, always
// @astgen op2 := stmtsp : List[AstNode] // Note: op1 is used in some sub-types only
@ -312,18 +293,14 @@ public:
void dump(std::ostream& str) const override;
};
class AstNodeStmt VL_NOT_FINAL : public AstNode {
// Statement -- anything that's directly under a function
bool m_statement; // Really a statement (e.g. not a function with return)
// Procedural statement
protected:
AstNodeStmt(VNType t, FileLine* fl, bool statement = true)
: AstNode{t, fl}
, m_statement{statement} {}
AstNodeStmt(VNType t, FileLine* fl)
: AstNode{t, fl} {}
public:
ASTGEN_MEMBERS_AstNodeStmt;
// METHODS
bool isStatement() const { return m_statement; } // Really a statement
void statement(bool flag) { m_statement = flag; }
void addNextStmt(AstNode* newp,
AstNode* belowp) override; // Stop statement searchback here
void addBeforeStmt(AstNode* newp,
@ -357,40 +334,6 @@ public:
bool isTimingControl() const override { return timingControlp(); }
virtual bool brokeLhsMustBeLvalue() const = 0;
};
class AstNodeCCall VL_NOT_FINAL : public AstNodeStmt {
// A call of a C++ function, perhaps a AstCFunc or perhaps globally named
// @astgen op2 := argsp : List[AstNode] // Note: op1 used by some sub-types only
//
// Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal.
AstCFunc* m_funcp;
string m_argTypes;
protected:
AstNodeCCall(VNType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr)
: AstNodeStmt{t, fl, true}
, m_funcp{funcp} {
addArgsp(argsp);
}
public:
ASTGEN_MEMBERS_AstNodeCCall;
void dump(std::ostream& str = std::cout) const override;
void cloneRelink() override;
const char* broken() const override;
int instrCount() const override { return INSTR_COUNT_CALL; }
bool same(const AstNode* samep) const override {
const AstNodeCCall* const asamep = static_cast<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 {
// @astgen op1 := exprp : AstNode // Condition (scurtinee) expression
// @astgen op2 := itemsp : List[AstCaseItem]
@ -431,52 +374,6 @@ public:
void dump(std::ostream& str = std::cout) const override;
bool immediate() const { return m_immediate; }
};
class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeStmt {
// A reference to a task (or function)
// @astgen op1 := namep : Optional[AstNode]
// op2 used by some sub-types only
// @astgen op3 := pinsp : List[AstNode]
// @astgen op4 := scopeNamep : Optional[AstScopeName]
//
// Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal.
private:
AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
string m_name; // Name of variable
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out
bool m_pli = false; // Pli system call ($name)
protected:
AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp)
: AstNodeStmt{t, fl, statement} {
this->namep(namep);
this->addPinsp(pinsp);
}
AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp)
: AstNodeStmt{t, fl, statement}
, m_name{name} {
this->addPinsp(pinsp);
}
public:
ASTGEN_MEMBERS_AstNodeFTaskRef;
const char* broken() const override;
void cloneRelink() override;
void dump(std::ostream& str = std::cout) const override;
string name() const override { return m_name; } // * = Var name
bool isGateOptimizable() const override { return m_taskp && m_taskp->isGateOptimizable(); }
string dotted() const { return m_dotted; } // * = Scope name or ""
string inlinedDots() const { return m_inlinedDots; }
void inlinedDots(const string& flag) { m_inlinedDots = flag; }
AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable
void taskp(AstNodeFTask* taskp) { m_taskp = taskp; }
void name(const string& name) override { m_name = name; }
void dotted(const string& name) { m_dotted = name; }
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
bool pli() const { return m_pli; }
void pli(bool flag) { m_pli = flag; }
};
class AstNodeFor VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := initsp : List[AstNode]
// @astgen op2 := condp : AstNode
@ -635,22 +532,6 @@ public:
void name(const string& name) override { m_name = name; }
bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); }
};
class AstAttrOf final : public AstNode {
// Return a value of a attribute, for example a LSB or array LSB of a signal
// @astgen op1 := fromp : Optional[AstNode]
// @astgen op2 := dimp : Optional[AstNode]
VAttrType m_attrType; // What sort of extraction
public:
AstAttrOf(FileLine* fl, VAttrType attrtype, AstNode* fromp = nullptr, AstNode* dimp = nullptr)
: ASTGEN_SUPER_AttrOf(fl) {
this->fromp(fromp);
this->dimp(dimp);
m_attrType = attrtype;
}
ASTGEN_MEMBERS_AstAttrOf;
VAttrType attrType() const { return m_attrType; }
void dump(std::ostream& str = std::cout) const override;
};
class AstBind final : public AstNode {
// Parents: MODULE
// Children: CELL
@ -849,48 +730,6 @@ public:
bool isDefault() const { return condsp() == nullptr; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
class AstCast final : public AstNode {
// Cast to appropriate data type
// @astgen op1 := fromp : AstNode
// @astgen op2 := childDTypep : Optional[AstNodeDType]
public:
AstCast(FileLine* fl, AstNode* fromp, VFlagChildDType, AstNodeDType* dtp)
: ASTGEN_SUPER_Cast(fl) {
this->fromp(fromp);
this->childDTypep(dtp);
dtypeFrom(dtp);
}
AstCast(FileLine* fl, AstNode* fromp, AstNodeDType* dtp)
: ASTGEN_SUPER_Cast(fl) {
this->fromp(fromp);
dtypeFrom(dtp);
}
ASTGEN_MEMBERS_AstCast;
bool hasDType() const override { return true; }
virtual string emitVerilog() { return "((%d)'(%l))"; }
virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); }
virtual bool cleanLhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
};
class AstCastParse final : public AstNode {
// Cast to appropriate type, where we haven't determined yet what the data type is
// @astgen op1 := lhsp : AstNode
// @astgen op2 := dtp : AstNode
public:
AstCastParse(FileLine* fl, AstNode* lhsp, AstNode* dtp)
: ASTGEN_SUPER_CastParse(fl) {
this->lhsp(lhsp);
this->dtp(dtp);
}
ASTGEN_MEMBERS_AstCastParse;
virtual string emitVerilog() { return "((%d)'(%l))"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); }
virtual bool cleanLhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
};
class AstCastSize final : public AstNode {
// Cast to specific size; signed/twostate inherited from lower element per IEEE
// @astgen op1 := lhsp : AstNode
@ -1135,28 +974,6 @@ public:
bool same(const AstNode*) const override { return true; }
string path() const { return m_path; }
};
class AstDot final : public AstNode {
// A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef
// These are eliminated in the link stage
// @astgen op1 := lhsp : AstNode
// @astgen op2 := rhsp : AstNode
const bool m_colon; // Is a "::" instead of a "." (lhs must be package/class)
public:
AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp)
: ASTGEN_SUPER_Dot(fl)
, m_colon{colon} {
this->lhsp(lhsp);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstDot;
// For parser, make only if non-null package
static AstNode* newIfPkg(FileLine* fl, AstNode* packageOrClassp, AstNode* rhsp) {
if (!packageOrClassp) return rhsp;
return new AstDot(fl, true, packageOrClassp, rhsp);
}
void dump(std::ostream& str) const override;
bool colon() const { return m_colon; }
};
class AstDpiExport final : public AstNode {
// We could put an AstNodeFTaskRef instead of the verilog function name,
// however we're not *calling* it, so that seems somehow wrong.
@ -1497,37 +1314,6 @@ public:
AstPackage* packagep() const { return m_packagep; }
void packagep(AstPackage* nodep) { m_packagep = nodep; }
};
class AstParseRef final : public AstNode {
// A reference to a variable, function or task
// We don't know which at parse time due to bison constraints
// The link stages will replace this with AstVarRef, or AstTaskRef, etc.
// Parents: math|stmt
// @astgen op1 := lhsp : Optional[AstNode]
// @astgen op2 := ftaskrefp : Optional[AstNodeFTaskRef]
VParseRefExp m_expect; // Type we think it should resolve to
string m_name;
public:
AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp = nullptr,
AstNodeFTaskRef* ftaskrefp = nullptr)
: ASTGEN_SUPER_ParseRef(fl)
, m_expect{expect}
, m_name{name} {
this->lhsp(lhsp);
this->ftaskrefp(ftaskrefp);
}
ASTGEN_MEMBERS_AstParseRef;
void dump(std::ostream& str) const override;
string name() const override { return m_name; } // * = Var name
bool same(const AstNode* samep) const override {
const AstParseRef* const asamep = static_cast<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 {
// A port or parameter assignment on an instantiaton
// @astgen op1 := exprp : Optional[AstNode] // Expression connected (nullptr if unconnected)
@ -1629,58 +1415,6 @@ public:
}
uint32_t direction() const { return (uint32_t)m_direction; }
};
class AstSFormatF final : public AstNode {
// Convert format to string, generally under an AstDisplay or AstSFormat
// Also used as "real" function for /*verilator sformat*/ functions
// @astgen op1 := exprsp : List[AstNode]
// @astgen op2 := scopeNamep : Optional[AstScopeName]
string m_text;
const bool m_hidden; // Under display, etc
bool m_hasFormat; // Has format code
const char m_missingArgChar; // Format code when argument without format, 'h'/'o'/'b'
VTimescale m_timeunit; // Parent module time unit
public:
class NoFormat {};
AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp,
char missingArgChar = 'd')
: ASTGEN_SUPER_SFormatF(fl)
, m_text{text}
, m_hidden{hidden}
, m_hasFormat{true}
, m_missingArgChar{missingArgChar} {
dtypeSetString();
addExprsp(exprsp);
}
AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd',
bool hidden = true)
: ASTGEN_SUPER_SFormatF(fl)
, m_text{""}
, m_hidden{hidden}
, m_hasFormat{false}
, m_missingArgChar{missingArgChar} {
dtypeSetString();
addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstSFormatF;
string name() const override { return m_text; }
int instrCount() const override { return INSTR_COUNT_PLI; }
bool hasDType() const override { return true; }
bool same(const AstNode* samep) const override {
return text() == static_cast<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 {
// A particular usage of a cell
// Parents: MODULE
@ -1952,21 +1686,6 @@ public:
string name() const override { return m_text; }
string text() const { return m_text; }
};
class AstUnlinkedRef final : public AstNode {
// As-of-yet unlinkable Ref
// @astgen op1 := refp : AstNode
// @astgen op2 := cellrefp : AstNode
string m_name; // Var name // TODO: There is no way to access this, fix or remove
public:
AstUnlinkedRef(FileLine* fl, AstNode* refp, const string& name, AstNode* cellrefp)
: ASTGEN_SUPER_UnlinkedRef(fl)
, m_name{name} {
this->refp(refp);
this->cellrefp(cellrefp);
}
ASTGEN_MEMBERS_AstUnlinkedRef;
};
class AstVar final : public AstNode {
// A variable (in/out/wire/reg/param) inside a module
//
@ -2593,49 +2312,6 @@ public:
bool timescaleMatters() const override { return false; }
};
// === AstNodePreSel ===
class AstSelBit final : public AstNodePreSel {
// Single bit range extraction, perhaps with non-constant selection or array selection
// Gets replaced during link with AstArraySel or AstSel
public:
AstSelBit(FileLine* fl, AstNode* fromp, AstNode* bitp)
: ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) {
UASSERT_OBJ(!v3Global.assertDTypesResolved(), this,
"not coded to create after dtypes resolved");
}
ASTGEN_MEMBERS_AstSelBit;
AstNode* bitp() const { return rhsp(); }
};
class AstSelExtract final : public AstNodePreSel {
// Range extraction, gets replaced with AstSel
public:
AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp)
: ASTGEN_SUPER_SelExtract(fl, fromp, msbp, lsbp) {}
ASTGEN_MEMBERS_AstSelExtract;
AstNode* leftp() const { return rhsp(); }
AstNode* rightp() const { return thsp(); }
};
class AstSelMinus final : public AstNodePreSel {
// -: range extraction, perhaps with non-constant selection
// Gets replaced during link with AstSel
public:
AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
: ASTGEN_SUPER_SelMinus(fl, fromp, bitp, widthp) {}
ASTGEN_MEMBERS_AstSelMinus;
AstNode* bitp() const { return rhsp(); }
AstNode* widthp() const { return thsp(); }
};
class AstSelPlus final : public AstNodePreSel {
// +: range extraction, perhaps with non-constant selection
// Gets replaced during link with AstSel
public:
AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
: ASTGEN_SUPER_SelPlus(fl, fromp, bitp, widthp) {}
ASTGEN_MEMBERS_AstSelPlus;
AstNode* bitp() const { return rhsp(); }
AstNode* widthp() const { return thsp(); }
};
// === AstNodeProcedure ===
class AstAlways final : public AstNodeProcedure {
// @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list iff clocked
@ -2797,70 +2473,6 @@ public:
return true; // SPECIAL: We don't process code after breaks
}
};
class AstCAwait final : public AstNodeStmt {
// Emit C++'s co_await statement
// @astgen op1 := exprp : AstNode
AstSenTree* m_sensesp; // Sentree related to this await
public:
AstCAwait(FileLine* fl, AstNode* exprp, AstSenTree* sensesp = nullptr)
: ASTGEN_SUPER_CAwait(fl)
, m_sensesp{sensesp} {
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstCAwait;
bool isTimingControl() const override { return true; }
const char* broken() const override {
BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists());
return nullptr;
}
void cloneRelink() override {
if (m_sensesp && m_sensesp->clonep()) m_sensesp = m_sensesp->clonep();
}
void dump(std::ostream& str) const override;
AstSenTree* sensesp() const { return m_sensesp; }
void clearSensesp() { m_sensesp = nullptr; }
};
class AstCMethodHard final : public AstNodeStmt {
// A reference to a "C" hardcoded member task (or function)
// PARENTS: stmt/math
// Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal.
// @astgen op1 := fromp : AstNode // Subject of method call
// @astgen op2 := pinsp : List[AstNode] // Arguments
private:
string m_name; // Name of method
bool m_pure = false; // Pure optimizable
public:
AstCMethodHard(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name,
AstNode* pinsp = nullptr)
: ASTGEN_SUPER_CMethodHard(fl, false)
, m_name{name} {
// TODO: this constructor is exactly the same as the other, bar the ignored tag argument
this->fromp(fromp);
this->addPinsp(pinsp);
dtypep(nullptr); // V3Width will resolve
}
AstCMethodHard(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp = nullptr)
: ASTGEN_SUPER_CMethodHard(fl, false)
, m_name{name} {
this->fromp(fromp);
this->addPinsp(pinsp);
}
ASTGEN_MEMBERS_AstCMethodHard;
string name() const override { return m_name; } // * = Var name
bool hasDType() const override { return true; }
void name(const string& name) override { m_name = name; }
bool same(const AstNode* samep) const override {
const AstCMethodHard* asamep = static_cast<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 {
// Reset variable at startup
// @astgen op1 := varrefp : AstVarRef
@ -3448,6 +3060,16 @@ public:
int instrCount() const override { return INSTR_COUNT_PLI; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstStmtExpr final : public AstNodeStmt {
// Expression in statement position
// @astgen op1 := exprp : AstNodeExpr
public:
AstStmtExpr(FileLine* fl, AstNodeExpr* exprp)
: ASTGEN_SUPER_StmtExpr(fl) {
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstStmtExpr;
};
class AstStop final : public AstNodeStmt {
public:
AstStop(FileLine* fl, bool maybe)
@ -3478,21 +3100,6 @@ public:
int instrCount() const override { return 0; }
bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstSysIgnore final : public AstNodeStmt {
// @astgen op1 := exprsp : List[AstNode] // Expressions to output (???)
public:
AstSysIgnore(FileLine* fl, AstNode* exprsp)
: ASTGEN_SUPER_SysIgnore(fl) {
this->addExprsp(exprsp);
}
ASTGEN_MEMBERS_AstSysIgnore;
string verilogKwd() const override { return "$ignored"; }
bool isGateOptimizable() const override { return false; } // Though deleted before opt
bool isPredictOptimizable() const override { return false; } // Though deleted before opt
bool isPure() const override { return false; } // Though deleted before opt
bool isOutputter() const override { return true; } // Though deleted before opt
int instrCount() const override { return INSTR_COUNT_PLI; }
};
class AstSystemT final : public AstNodeStmt {
// $system used as task
// @astgen op1 := lhsp : AstNode
@ -3708,7 +3315,7 @@ class AstWith final : public AstNodeStmt {
// Parents: funcref (similar to AstArg)
// Children: LambdaArgRef that declares the item variable
// Children: LambdaArgRef that declares the item.index variable
// Children: math (equation establishing the with)
// Children: expression (equation establishing the with)
// @astgen op1 := indexArgRefp : AstLambdaArgRef
// @astgen op2 := valueArgRefp : AstLambdaArgRef
// @astgen op3 := exprp : AstNode
@ -3729,23 +3336,6 @@ public:
return nullptr;
}
};
class AstWithParse final : public AstNodeStmt {
// In early parse, FUNC(index) WITH equation-using-index
// Replaced with AstWith
// Parents: math|stmt
// Children: funcref, math
// @astgen op1 := funcrefp : AstNode
// @astgen op2 := exprp : Optional[AstNode]
public:
AstWithParse(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* exprp)
: ASTGEN_SUPER_WithParse(fl) {
statement(stmt);
this->funcrefp(funcrefp);
this->exprp(exprp);
}
ASTGEN_MEMBERS_AstWithParse;
bool same(const AstNode* /*samep*/) const override { return true; }
};
// === AstNodeAssign ===
class AstAssign final : public AstNodeAssign {
@ -3850,52 +3440,6 @@ public:
AstAlways* convertToAlways();
};
// === AstNodeCCall ===
class AstCCall final : public AstNodeCCall {
// C++ function call
// Parents: Anything above a statement
// Children: Args to the function
string m_selfPointer; // Output code object pointer (e.g.: 'this')
public:
AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr)
: ASTGEN_SUPER_CCall(fl, funcp, argsp) {}
ASTGEN_MEMBERS_AstCCall;
string selfPointer() const { return m_selfPointer; }
void selfPointer(const string& value) { m_selfPointer = value; }
string selfPointerProtect(bool useSelfForThis) const;
};
class AstCMethodCall final : public AstNodeCCall {
// C++ method call
// Parents: Anything above a statement
// @astgen op1 := fromp : AstNode
public:
AstCMethodCall(FileLine* fl, AstNode* fromp, AstCFunc* funcp, AstNode* argsp = nullptr)
: ASTGEN_SUPER_CMethodCall(fl, funcp, argsp) {
this->fromp(fromp);
}
ASTGEN_MEMBERS_AstCMethodCall;
const char* broken() const override {
BROKEN_BASE_RTN(AstNodeCCall::broken());
BROKEN_RTN(!fromp());
return nullptr;
}
};
class AstCNew final : public AstNodeCCall {
// C++ new() call
// Parents: Anything above an expression
// Children: Args to the function
public:
AstCNew(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr)
: ASTGEN_SUPER_CNew(fl, funcp, argsp) {
statement(false);
}
bool hasDType() const override { return true; }
ASTGEN_MEMBERS_AstCNew;
};
// === AstNodeCase ===
class AstCase final : public AstNodeCase {
// Case statement
@ -3979,74 +3523,6 @@ public:
: ASTGEN_SUPER_Restrict(fl, propp, nullptr, false, "") {}
};
// === AstNodeFTaskRef ===
class AstFuncRef final : public AstNodeFTaskRef {
// A reference to a function
public:
AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
: ASTGEN_SUPER_FuncRef(fl, false, namep, pinsp) {}
AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp)
: ASTGEN_SUPER_FuncRef(fl, false, name, pinsp) {}
ASTGEN_MEMBERS_AstFuncRef;
bool hasDType() const override { return true; }
};
class AstMethodCall final : public AstNodeFTaskRef {
// A reference to a member task (or function)
// PARENTS: stmt/math
// Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal.
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
// @astgen op2 := fromp : AstNode
//
public:
AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name,
AstNode* pinsp)
: ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) {
this->fromp(fromp);
dtypep(nullptr); // V3Width will resolve
}
AstMethodCall(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp)
: ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) {
this->fromp(fromp);
}
ASTGEN_MEMBERS_AstMethodCall;
const char* broken() const override {
BROKEN_BASE_RTN(AstNodeFTaskRef::broken());
BROKEN_RTN(!fromp());
return nullptr;
}
void dump(std::ostream& str) const override;
bool hasDType() const override { return true; }
void makeStatement() {
statement(true);
dtypeSetVoid();
}
};
class AstNew final : public AstNodeFTaskRef {
// New as constructor
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
// Parents: math|stmt
// Children: varref|arraysel, math
public:
AstNew(FileLine* fl, AstNode* pinsp)
: ASTGEN_SUPER_New(fl, false, "new", pinsp) {}
ASTGEN_MEMBERS_AstNew;
virtual bool cleanOut() const { return true; }
bool same(const AstNode* /*samep*/) const override { return true; }
bool hasDType() const override { return true; }
int instrCount() const override { return widthInstrs(); }
};
class AstTaskRef final : public AstNodeFTaskRef {
// A reference to a task
public:
AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
: ASTGEN_SUPER_TaskRef(fl, true, namep, pinsp) {
statement(true);
}
AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp)
: ASTGEN_SUPER_TaskRef(fl, true, name, pinsp) {}
ASTGEN_MEMBERS_AstTaskRef;
};
// === AstNodeFor ===
class AstGenFor final : public AstNodeFor {
public:

View File

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

View File

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

View File

@ -16,9 +16,9 @@
// V3Cast's Transformations:
//
// Each module:
// For each math operator, if above operator requires 32 bits,
// For each expression, if above expression requires 32 bits,
// and this isn't, cast to 32 bits.
// Likewise for 64 bit operators.
// Likewise for 64 bit expressions.
//
// C++ rules:
// Integral promotions allow conversion to larger int. Unsigned is only
@ -158,7 +158,8 @@ private:
}
void visit(AstVarRef* nodep) override {
const AstNode* const backp = nodep->backp();
if (nodep->access().isReadOnly() && !VN_IS(backp, CCast) && VN_IS(backp, NodeMath)
if (nodep->access().isReadOnly() && VN_IS(backp, NodeExpr) && !VN_IS(backp, CCast)
&& !VN_IS(backp, NodeCCall) && !VN_IS(backp, CMethodHard) && !VN_IS(backp, SFormatF)
&& !VN_IS(backp, ArraySel) && !VN_IS(backp, RedXor)
&& (nodep->varp()->basicp() && !nodep->varp()->basicp()->isTriggerVec()
&& !nodep->varp()->basicp()->isForkSync())

View File

@ -697,7 +697,7 @@ private:
void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); }
void visit(AstAssignW* nodep) override { iterateNewStmt(nodep); }
// Math that shouldn't cause us to clear hazard
// Expressions that shouldn't cause us to clear hazard
void visit(AstConst*) override {}
void visit(AstReplicate* nodep) override { iterateChildren(nodep); }
void visit(AstConcat* nodep) override { iterateChildren(nodep); }
@ -721,7 +721,7 @@ private:
//--------------------
// Default
void visit(AstNodeMath* nodep) override {
void visit(AstNodeExpr* nodep) override {
setNodeHazard(nodep);
iterateChildren(nodep);
}

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(AstNode* nodep) override { iterateChildren(nodep); }

View File

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

View File

@ -69,7 +69,9 @@ class CombineVisitor final : VNVisitor {
if (funcp->emptyBody()) {
// Delete call sites
for (AstCCall* const callp : m_callSites(funcp)) {
VL_DO_DANGLING(callp->unlinkFrBack()->deleteTree(), callp);
UASSERT_OBJ(VN_IS(callp->backp(), StmtExpr), callp,
"Deleting non-statement call");
VL_DO_DANGLING(callp->backp()->unlinkFrBack()->deleteTree(), callp);
}
m_callSites(funcp).clear();
// Remove from list

View File

@ -42,7 +42,7 @@ static void makeVlToString(AstClass* nodep) {
funcp->isConst(false);
funcp->isStatic(false);
funcp->protect(false);
AstNode* const exprp = new AstCMath{nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0};
AstNode* const exprp = new AstCExpr{nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0};
exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
nodep->addStmtsp(funcp);
@ -55,7 +55,7 @@ static void makeVlToString(AstIface* nodep) {
funcp->isConst(false);
funcp->isStatic(false);
funcp->protect(false);
AstNode* const exprp = new AstCMath{nodep->fileline(), "obj ? obj->name() : \"null\"", 0};
AstNode* const exprp = new AstCExpr{nodep->fileline(), "obj ? obj->name() : \"null\"", 0};
exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
nodep->addStmtsp(funcp);
@ -66,7 +66,7 @@ static void makeToString(AstClass* nodep) {
funcp->isStatic(false);
funcp->protect(false);
AstNode* const exprp
= new AstCMath{nodep->fileline(), R"(std::string{"'{"} + to_string_middle() + "}")", 0};
= new AstCExpr{nodep->fileline(), R"(std::string{"'{"} + to_string_middle() + "}")", 0};
exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
nodep->addStmtsp(funcp);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -870,7 +870,7 @@ public:
// DfgVertex subclasses
#include "V3DfgVertices.h"
// The rest of the DfgVertex subclasses are generated by 'astgen' from AstNodeMath nodes
// The rest of the DfgVertex subclasses are generated by 'astgen' from AstNodeExpr nodes
#include "V3Dfg__gen_auto_classes.h"
DfgVertexVar* DfgGraph::varVerticesBeginp() const {

View File

@ -39,7 +39,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
namespace {
// Create a DfgVertex out of a AstNodeMath. For most AstNodeMath subtypes, this can be done
// Create a DfgVertex out of a AstNodeExpr. For most AstNodeExpr subtypes, this can be done
// automatically. For the few special cases, we provide specializations below
template <typename Vertex, typename Node>
Vertex* makeVertex(const Node* nodep, DfgGraph& dfg) {
@ -132,7 +132,7 @@ class AstToDfgVisitor final : public VNVisitor {
}
// Returns true if the expression cannot (or should not) be represented by DFG
bool unhandled(AstNodeMath* nodep) {
bool unhandled(AstNodeExpr* nodep) {
// Short-circuiting if something was already unhandled
if (!m_foundUnhandled) {
// Impure nodes cannot be represented

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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 {
private:
@ -801,7 +801,7 @@ private:
// comparing AstActive nodes, which are very likely not to compare equals (and for the
// purposes of V3Gate, we probably only care about them either being identical instances,
// or having the same sensitivities anyway, so if this becomes a problem, it can be
// improved which should also speed things up), and AstNodeMath for if conditions, which
// improved which should also speed things up), and AstNodeExpr for if conditions, which
// are hopefully small, and to be safe they should probably be only considered same when
// identical instances (otherwise if writing the condition between 2 ifs don't really
// merge).

View File

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

View File

@ -296,7 +296,7 @@ class HierBlockUsageCollectVisitor final : public VNVisitor {
if (nodep->isGParam() && nodep->overriddenParam()) m_gparams.push_back(nodep);
}
void visit(AstNodeMath*) override {} // Accelerate
void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -463,7 +463,7 @@ static void process() {
// Bits between widthMin() and width() are irrelevant, but may be non zero.
v3Global.widthMinUsage(VWidthMinUsage::VERILOG_WIDTH);
// Make all math operations either 8, 16, 32 or 64 bits
// Make all expressions either 8, 16, 32 or 64 bits
V3Clean::cleanAll(v3Global.rootp());
// Move wide constants to BLOCK temps / ConstPool.

View File

@ -1196,7 +1196,7 @@ def write_dfg_dfg_to_ast(filename):
"void visit(Dfg{t}* vtxp) override {{\n".format(t=node.name))
for i in range(node.arity):
fh.write(
" AstNodeMath* const op{j}p = convertSource(vtxp->source<{i}>());\n"
" AstNodeExpr* const op{j}p = convertSource(vtxp->source<{i}>());\n"
.format(i=i, j=i + 1))
fh.write(
" m_resultp = makeNode<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
%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_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
// // inc_or_dec_operator
// When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstNodeMathStmt?
// When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstNodeExprStmt?
| yP_PLUSPLUS varRefBase
{ $$ = new AstAssign{$1, $2, new AstAdd{$1, $2->cloneTree(true),
new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; }
@ -3284,23 +3285,27 @@ statement_item<nodep>: // IEEE: statement_item
{ $$ = $4;
FileLine* const newfl = new FileLine{$$->fileline()};
newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true);
$$->fileline(newfl); }
$$->fileline(newfl);
if (AstNodeExpr* const exprp = VN_CAST($$, NodeExpr)) $$ = exprp->makeStmt(); }
| yVOID yP_TICK '(' expr '.' task_subroutine_callNoMethod ')' ';'
{ $$ = new AstDot{$5, false, $4, $6};
FileLine* const newfl = new FileLine{$6->fileline()};
newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true);
$6->fileline(newfl); }
$6->fileline(newfl);
if (AstNodeExpr* const exprp = VN_CAST($$, NodeExpr)) $$ = exprp->makeStmt(); }
// // Expr included here to resolve our not knowing what is a method call
// // Expr here must result in a subroutine_call
| task_subroutine_callNoMethod ';' { $$ = $1; }
| task_subroutine_callNoMethod ';'
{ $$ = $1;
if (AstNodeExpr* const exprp = VN_CAST($$, NodeExpr)) $$ = exprp->makeStmt(); }
//UNSUP fexpr '.' array_methodNoRoot ';' { UNSUP }
| fexpr '.' task_subroutine_callNoMethod ';' { $$ = new AstDot($<fl>2, false, $1, $3); }
| fexpr '.' task_subroutine_callNoMethod ';' { $$ = (new AstDot{$<fl>2, false, $1, $3})->makeStmt(); }
//UNSUP fexprScope ';' { UNSUP }
// // Not here in IEEE; from class_constructor_declaration
// // Because we've joined class_constructor_declaration into generic functions
// // Way over-permissive;
// // IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ]
| fexpr '.' class_new ';' { $$ = new AstDot($<fl>2, false, $1, $3); }
| fexpr '.' class_new ';' { $$ = (new AstDot{$<fl>2, false, $1, $3})->makeStmt(); }
//
| 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}
;
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
~l~exprScope yP_PLUSPLUS
{ $<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)}; }
;
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}
;
@ -3684,14 +3689,14 @@ loop_variables<nodep>: // IEEE: loop_variables
//************************************************
// Functions/tasks
taskRef<nodep>: // IEEE: part of tf_call
taskRef<nodeExprp>: // IEEE: part of tf_call
id { $$ = new AstTaskRef($<fl>1,*$1,nullptr); }
| id '(' list_of_argumentsE ')' { $$ = new AstTaskRef($<fl>1,*$1,$3); }
| packageClassScope id '(' list_of_argumentsE ')'
{ $$ = 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
// // making-a id-is-a
// // ----------------- ------------------
@ -3713,9 +3718,9 @@ task_subroutine_callNoMethod<nodep>: // function_subroutine_callNoMethod (as
// // IEEE: tf_call
taskRef { $$ = $1; }
// // funcref below not task ref to avoid conflict, must later handle either
| funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, true, $1, $4); }
| funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse{$2, $1, $4}; }
// // can call as method and yWITH without parenthesis
| id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, true, new AstFuncRef($<fl>1, *$1, nullptr), $4); }
| id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse{$2, new AstFuncRef{$<fl>1, *$1, nullptr}, $4}; }
| system_t_call { $$ = $1; }
// // IEEE: method_call requires a "." so is in expr
// // IEEE: ['std::'] not needed, as normal std package resolution will find it
@ -3725,12 +3730,12 @@ task_subroutine_callNoMethod<nodep>: // function_subroutine_callNoMethod (as
//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
funcRef { $$ = $1; }
| funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, false, $1, $4); }
| funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse{$2, $1, $4}; }
// // can call as method and yWITH without parenthesis
| id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, false, new AstFuncRef($<fl>1, *$1, nullptr), $4); }
| id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse{$2, new AstFuncRef{$<fl>1, *$1, nullptr}, $4}; }
| system_f_call { $$ = $1; }
// // IEEE: method_call requires a "." so is in expr
// // IEEE: ['std::'] not needed, as normal std package resolution will find it
@ -3739,7 +3744,7 @@ function_subroutine_callNoMethod<nodep>: // IEEE: function_subroutine_cal
// // Note yNULL is already part of expressions, so they come for free
| funcRef yWITH__CUR constraint_block
{ $$ = $1; BBUNSUP($2, "Unsupported: randomize() 'with' constraint"); }
| funcRef yWITH__CUR '{' '}' { $$ = new AstWithParse($2, false, $1, nullptr); }
| funcRef yWITH__CUR '{' '}' { $$ = new AstWithParse{$2, $1, nullptr}; }
;
system_t_call<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<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); }
//
| 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); }
;
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_ACOSH '(' expr ')' { $$ = new AstAcoshD($1,$3); }
| yD_ASIN '(' expr ')' { $$ = new AstAsinD($1,$3); }
@ -4276,9 +4281,9 @@ array_methodNoRoot<nodeFTaskRefp>:
array_methodWith<nodep>:
array_methodNoRoot parenE { $$ = $1; }
| array_methodNoRoot parenE yWITH__PAREN '(' expr ')'
{ $$ = new AstWithParse($3, false, $1, $5); }
{ $$ = new AstWithParse{$3, $1, $5}; }
| array_methodNoRoot '(' expr ')' yWITH__PAREN '(' expr ')'
{ $$ = new AstWithParse($5, false, $1, $7); $1->addPinsp(new AstArg($<fl>3, "", $3)); }
{ $$ = new AstWithParse{$5, $1, $7}; $1->addPinsp(new AstArg($<fl>3, "", $3)); }
;
dpi_import_export<nodep>: // ==IEEE: dpi_import_export
@ -4350,11 +4355,11 @@ exprOrDataTypeEqE<nodep>: // IEEE: optional '=' expression (part of param_
| '=' exprOrDataType { $$ = $2; }
;
constExpr<nodep>:
constExpr<nodeExprp>:
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
//
// // 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"); }
;
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}
;
@ -4555,11 +4560,11 @@ fexpr<nodep>: // For use as first part of statement (disambigu
//UNSUP | '(' event_expression ':' expr ':' expr ')' { $<fl>$ = $<fl>1; $$ = "(...)"; }
//UNSUP ;
exprNoStr<nodep>: // expression with string removed
exprNoStr<nodeExprp>: // expression with string removed
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; }
// // IEEE: concatenation/constant_concatenation
// // 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; }
;
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}
;
@ -4601,11 +4606,11 @@ fexprOkLvalue<nodep>: // exprOkLValue, For use as first part of statem
//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/pev_/g}) // {copied}
//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; }
;
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
// // from the object being called and let expr's "." deal with resolving it.
// // (note method_call_root was simplified to require a primary in 1800-2009)
@ -4624,7 +4629,7 @@ exprScope<nodep>: // scope and variable for use to inside an expre
| 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}
;
@ -4656,23 +4661,23 @@ cStrList<nodep>:
| exprStrText ',' cStrList { $$ = $1->addNext($3); }
;
cateList<nodep>:
cateList<nodeExprp>:
// // Not just 'expr' to prevent conflict via stream_concOrExprOrType
stream_expression { $$ = $1; }
| cateList ',' stream_expression { $$ = new AstConcat($2,$1,$3); }
;
exprListE<nodep>:
exprListE<nodeExprp>:
/* empty */ { $$ = nullptr; }
| exprList { $$ = $1; }
;
exprList<nodep>:
exprList<nodeExprp>:
expr { $$ = $1; }
| exprList ',' expr { $$ = $1->addNext($3); }
;
exprDispList<nodep>: // exprList for within $display
exprDispList<nodeExprp>: // exprList for within $display
expr { $$ = $1; }
| exprDispList ',' expr { $$ = $1->addNext($3); }
// // ,, 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 ;
streaming_concatenation<nodep>: // ==IEEE: streaming_concatenation
streaming_concatenation<nodeExprp>: // ==IEEE: streaming_concatenation
// // Need to disambiguate {<< expr-{ ... expr-} stream_concat }
// // From {<< stream-{ ... stream-} }
// // Likewise simple_type's idScoped from constExpr's idScope
@ -4758,7 +4763,7 @@ stream_concatenation<nodep>: // ==IEEE: stream_concatenation
'{' cateList '}' { $$ = $2; }
;
stream_expression<nodep>: // ==IEEE: stream_expression
stream_expression<nodeExprp>: // ==IEEE: stream_expression
// // IEEE: array_range_expression expanded below
expr { $$ = $1; }
//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; }
;
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
idClassSel { $$ = $1; }
| '{' variable_lvalueConcList '}' { $$ = $2; }
@ -5089,7 +5094,7 @@ variable_lvalue<nodep>: // IEEE: variable_lvalue or net_lvalue
| 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_lvalueConcList ',' variable_lvalue { $$ = new AstConcat($2,$1,$3); }
;
@ -5100,7 +5105,7 @@ variable_lvalueConcList<nodep>: // IEEE: part of variable_lvalue: '{' variable_l
//UNSUP ;
// 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; }
// // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select
| yTHIS '.' idDotted
@ -5124,7 +5129,7 @@ idClassSelForeach<nodep>:
| packageClassScope idDottedForeach { $$ = new AstDot($<fl>2, true, $1, $2); }
;
idDotted<nodep>:
idDotted<nodeExprp>:
yD_ROOT '.' idDottedMore
{ $$ = new AstDot($2, false, new AstParseRef($<fl>1, VParseRefExp::PX_ROOT, "$root"), $3); }
| idDottedMore { $$ = $1; }
@ -5136,7 +5141,7 @@ idDottedForeach<nodep>:
| idDottedMoreForeach { $$ = $1; }
;
idDottedMore<nodep>:
idDottedMore<nodeExprp>:
idArrayed { $$ = $1; }
| idDottedMore '.' idArrayed { $$ = new AstDot($2, false, $1, $3); }
;
@ -5151,7 +5156,7 @@ idDottedMoreForeach<nodep>:
// we'll assume so and cleanup later.
// id below includes:
// enum_identifier
idArrayed<nodep>: // IEEE: id + select
idArrayed<nodeExprp>: // IEEE: id + select
id
{ $$ = new AstParseRef($<fl>1, VParseRefExp::PX_TEXT, *$1, nullptr, nullptr); }
// // 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)
// // To avoid conflicts we allow expr as first element, must post-check
| idArrayed '[' expr ',' loop_variables ']'
{ $3 = addNextNull($3, $5); $$ = new AstSelLoopVars($2, $1, $3); }
{ $$ = new AstSelLoopVars{$2, $1, addNextNull(static_cast<AstNode*>($3), $5)}; }
| 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
@ -5195,7 +5200,7 @@ str<strp>: // yaSTRING but with \{escapes} need decoded
yaSTRING { $$ = PARSEP->newString(GRAMMARP->deQuote($<fl>1,*$1)); }
;
strAsInt<nodep>:
strAsInt<nodeExprp>:
yaSTRING
{ if ($1->empty()) {
// 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"); }
;
@ -6563,7 +6568,7 @@ constraintStaticE<cbool>: // IEEE: part of extern_constraint_declaration
//**********************************************************************
// Constants
timeNumAdjusted<nodep>: // Time constant, adjusted to module's time units/precision
timeNumAdjusted<nodeExprp>: // Time constant, adjusted to module's time units/precision
yaTIMENUM
{ $$ = 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);
$display("stmt %~ %~",
iother, other);
t()end
t();
end
i = (i + 'h1);
end
end
@ -189,7 +190,8 @@ module Vt_debug_emitv_t;
cyc <= (cyc + 'sh1);
r <= (r + 0.01);
fo = cyc;
sub.inc(fosum)sum = sub.f(sum);
sub.inc(fosum);
sum = sub.f(sum);
$display("[%0t] sum = %~", $timesum, sum);
$display("a?= %d", ($c('sh1) ? $c('sh14)
: $c('sh1e)));

View File

@ -2,7 +2,7 @@
16 | foo(bus_we_select_from[2]);
| ^
... For error description see https://verilator.org/warn/TASKNSVAR?v=latest
%Error: Internal Error: t/t_func_tasknsvar_bad.v:10:7: ../V3Broken.cpp:#: Broken link in node (or something without maybePointedTo): 'm_varp && !m_varp->brokeExists()' @ ../V3AstNodes.cpp:64
%Error: Internal Error: t/t_func_tasknsvar_bad.v:10:7: ../V3Broken.cpp:#: Broken link in node (or something without maybePointedTo): 'm_varp && !m_varp->brokeExists()' @ ../V3AstNodes.cpp:66
10 | sig = '1;
| ^~~
... See the manual at https://verilator.org/verilator_doc.html for more assistance.

File diff suppressed because it is too large Load Diff

View File

@ -40,11 +40,13 @@
</func>
<initial loc="d,39,4,39,11">
<begin loc="d,39,12,39,17">
<taskref loc="d,41,7,41,8" name="f">
<arg loc="d,41,9,41,736">
<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>
</taskref>
<stmtexpr loc="d,41,7,41,8">
<taskref loc="d,41,7,41,8" name="f" dtype_id="8">
<arg loc="d,41,9,41,736">
<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>
</taskref>
</stmtexpr>
</begin>
</initial>
</module>
@ -55,21 +57,22 @@
</modport>
</iface>
<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,14,11,14,17" id="1" name="logic"/>
<basicdtype loc="d,21,7,21,12" id="8" name="logic"/>
<basicdtype loc="d,22,7,22,12" id="9" name="logic"/>
<basicdtype loc="d,23,7,23,12" id="10" name="logic"/>
<basicdtype loc="d,24,7,24,12" id="11" name="logic"/>
<basicdtype loc="d,21,7,21,12" id="9" name="logic"/>
<basicdtype loc="d,22,7,22,12" id="10" name="logic"/>
<basicdtype loc="d,23,7,23,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">
<memberdtype loc="d,21,19,21,22" id="12" name="clk" tag="this is clk" sub_dtype_id="8"/>
<memberdtype loc="d,22,19,22,20" id="13" name="k" sub_dtype_id="9"/>
<memberdtype loc="d,23,19,23,25" id="14" name="enable" tag="enable" sub_dtype_id="10"/>
<memberdtype loc="d,24,19,24,23" id="15" name="data" tag="data" sub_dtype_id="11"/>
<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="14" name="k" 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="16" name="data" tag="data" sub_dtype_id="12"/>
</structdtype>
<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"/>
<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">
<range loc="d,31,26,31,27">
<const loc="d,31,27,31,28" name="32&apos;h0" dtype_id="5"/>