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:
parent
cf4c00e3b4
commit
65e08f4dbf
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 := \
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@
|
|||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
// Emit statements and math operators
|
||||
// ######################################################################
|
||||
// Emit statements and expressions
|
||||
|
||||
class EmitMk final {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@
|
|||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
// Emit statements and math operators
|
||||
// ######################################################################
|
||||
// Emit statements and expressions
|
||||
|
||||
class EmitXmlFileVisitor final : public VNVisitor {
|
||||
// NODE STATE
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
107
src/V3Sched.cpp
107
src/V3Sched.cpp
|
|
@ -146,7 +146,8 @@ void splitCheck(AstCFunc* ofuncp) {
|
|||
ofuncp->scopep()->addBlocksp(funcp);
|
||||
//
|
||||
AstCCall* const callp = new AstCCall{funcp->fileline(), funcp};
|
||||
ofuncp->addStmtsp(callp);
|
||||
callp->dtypeSetVoid();
|
||||
ofuncp->addStmtsp(callp->makeStmt());
|
||||
func_stmts = 0;
|
||||
}
|
||||
funcp->addStmtsp(itemp);
|
||||
|
|
@ -215,7 +216,9 @@ void orderSequentially(AstCFunc* funcp, const LogicByScope& lbs) {
|
|||
subFuncp->slow(funcp->slow());
|
||||
scopep->addBlocksp(subFuncp);
|
||||
// Call it from the top function
|
||||
funcp->addStmtsp(new AstCCall{scopep->fileline(), subFuncp});
|
||||
AstCCall* const callp = new AstCCall{scopep->fileline(), subFuncp};
|
||||
callp->dtypeSetVoid();
|
||||
funcp->addStmtsp(callp->makeStmt());
|
||||
return subFuncp;
|
||||
};
|
||||
const VNUser1InUse user1InUse; // AstScope -> AstCFunc: the sub-function for the scope
|
||||
|
|
@ -506,7 +509,9 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
|||
const auto add = [&](const string& text) { blockp->addText(flp, text, true); };
|
||||
add("#ifdef VL_DEBUG\n");
|
||||
add("if (VL_UNLIKELY(vlSymsp->_vm_contextp__->debug())) {\n");
|
||||
blockp->addNodesp(new AstCCall{flp, dumpp});
|
||||
AstCCall* const callp = new AstCCall{flp, dumpp};
|
||||
callp->dtypeSetVoid();
|
||||
blockp->addNodesp(callp->makeStmt());
|
||||
add("}\n");
|
||||
add("#endif\n");
|
||||
}
|
||||
|
|
@ -520,8 +525,8 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
|||
//============================================================================
|
||||
// Helpers to construct an evaluation loop.
|
||||
|
||||
AstNode* buildLoop(AstNetlist* netlistp, const string& name,
|
||||
const std::function<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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)); }
|
||||
;
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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=""	   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"" 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=""	   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"" 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'h0" dtype_id="5"/>
|
||||
|
|
|
|||
Loading…
Reference in New Issue