Strengthen AstNode types to AstNodeExpr
Declare every AstNode children and variables as AstNodeExpr where we statically know this is the appropriate sub-type.
This commit is contained in:
parent
352d0b4582
commit
3abb65d732
|
|
@ -59,8 +59,8 @@ private:
|
|||
nodep->displayType(VDisplayType::DT_WRITE);
|
||||
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
|
||||
// cppcheck-suppress nullPointer
|
||||
AstNode* const timenewp = new AstTime{nodep->fileline(), m_modp->timeunit()};
|
||||
if (AstNode* const timesp = nodep->fmtp()->exprsp()) {
|
||||
AstNodeExpr* const timenewp = new AstTime{nodep->fileline(), m_modp->timeunit()};
|
||||
if (AstNodeExpr* const timesp = nodep->fmtp()->exprsp()) {
|
||||
timesp->unlinkFrBackWithNext();
|
||||
timenewp->addNext(timesp);
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ private:
|
|||
nodep->fmtp()->scopeNamep(new AstScopeName{nodep->fileline(), true});
|
||||
}
|
||||
}
|
||||
AstSampled* newSampledExpr(AstNode* nodep) {
|
||||
AstSampled* newSampledExpr(AstNodeExpr* nodep) {
|
||||
const auto sampledp = new AstSampled{nodep->fileline(), nodep};
|
||||
sampledp->dtypeFrom(nodep);
|
||||
return sampledp;
|
||||
|
|
@ -98,16 +98,16 @@ private:
|
|||
// Add a internal if to check assertions are on.
|
||||
// Don't make this a AND term, as it's unlikely to need to test this.
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeIf* const newp = new AstIf{
|
||||
fl,
|
||||
(force ? new AstConst{fl, AstConst::BitTrue{}}
|
||||
: // If assertions are off, have constant propagation rip them out later
|
||||
// This allows syntax errors and such to be detected normally.
|
||||
(v3Global.opt.assertOn()
|
||||
? static_cast<AstNode*>(
|
||||
new AstCExpr{fl, "vlSymsp->_vm_contextp__->assertOn()", 1})
|
||||
: static_cast<AstNode*>(new AstConst{fl, AstConst::BitFalse{}}))),
|
||||
nodep};
|
||||
|
||||
// If assertions are off, have constant propagation rip them out later
|
||||
// This allows syntax errors and such to be detected normally.
|
||||
AstNodeExpr* const condp
|
||||
= force ? static_cast<AstNodeExpr*>(new AstConst{fl, AstConst::BitTrue{}})
|
||||
: v3Global.opt.assertOn()
|
||||
? static_cast<AstNodeExpr*>(
|
||||
new AstCExpr{fl, "vlSymsp->_vm_contextp__->assertOn()", 1})
|
||||
: static_cast<AstNodeExpr*>(new AstConst{fl, AstConst::BitFalse{}});
|
||||
AstNodeIf* const newp = new AstIf{fl, condp, nodep};
|
||||
newp->isBoundsCheck(true); // To avoid LATCH warning
|
||||
newp->user1(true); // Don't assert/cover this if
|
||||
return newp;
|
||||
|
|
@ -133,7 +133,7 @@ private:
|
|||
void newPslAssertion(AstNodeCoverOrAssert* nodep, AstNode* failsp) {
|
||||
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
|
||||
|
||||
AstNode* const propp = nodep->propp()->unlinkFrBackWithNext();
|
||||
AstNodeExpr* const propp = VN_AS(nodep->propp()->unlinkFrBackWithNext(), NodeExpr);
|
||||
AstSenTree* const sentreep = nodep->sentreep();
|
||||
const string& message = nodep->name();
|
||||
AstNode* passsp = nodep->passsp();
|
||||
|
|
@ -211,7 +211,7 @@ private:
|
|||
if (nodep->user1SetOnce()) return;
|
||||
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||
const AstNodeIf* ifp = nodep;
|
||||
AstNode* propp = nullptr;
|
||||
AstNodeExpr* propp = nullptr;
|
||||
bool hasDefaultElse = false;
|
||||
do {
|
||||
// If this statement ends with 'else if', then nextIf will point to the
|
||||
|
|
@ -228,7 +228,7 @@ private:
|
|||
}
|
||||
|
||||
// Build a bitmask of the true predicates
|
||||
AstNode* const predp = ifp->condp()->cloneTree(false);
|
||||
AstNodeExpr* const predp = ifp->condp()->cloneTree(false);
|
||||
if (propp) {
|
||||
propp = new AstConcat{nodep->fileline(), predp, propp};
|
||||
} else {
|
||||
|
|
@ -249,10 +249,10 @@ private:
|
|||
|
||||
// Note: if this ends with an 'else', then we don't need to validate that one of the
|
||||
// predicates evaluates to true.
|
||||
AstNode* const ohot
|
||||
AstNodeExpr* const ohot
|
||||
= ((allow_none || hasDefaultElse)
|
||||
? static_cast<AstNode*>(new AstOneHot0{nodep->fileline(), propp})
|
||||
: static_cast<AstNode*>(new AstOneHot{nodep->fileline(), propp}));
|
||||
? static_cast<AstNodeExpr*>(new AstOneHot0{nodep->fileline(), propp})
|
||||
: static_cast<AstNodeExpr*>(new AstOneHot{nodep->fileline(), propp}));
|
||||
AstIf* const checkifp
|
||||
= new AstIf{nodep->fileline(), new AstLogNot{nodep->fileline(), ohot},
|
||||
newFireAssert(nodep, "'unique if' statement violated"), newifp};
|
||||
|
|
@ -290,11 +290,12 @@ private:
|
|||
if (!has_default && !nodep->itemsp()) {
|
||||
// Not parallel, but harmlessly so.
|
||||
} else {
|
||||
AstNode* propp = nullptr;
|
||||
AstNodeExpr* propp = nullptr;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
|
||||
AstNode* onep;
|
||||
for (AstNodeExpr* icondp = itemp->condsp(); icondp;
|
||||
icondp = VN_AS(icondp->nextp(), NodeExpr)) {
|
||||
AstNodeExpr* onep;
|
||||
if (AstInsideRange* const rcondp = VN_CAST(icondp, InsideRange)) {
|
||||
onep = rcondp->newAndFromInside(nodep->exprp(),
|
||||
rcondp->lhsp()->cloneTree(true),
|
||||
|
|
@ -319,10 +320,11 @@ private:
|
|||
if (!propp) propp = new AstConst{nodep->fileline(), AstConst::BitFalse{}};
|
||||
|
||||
const bool allow_none = has_default || nodep->unique0Pragma();
|
||||
AstNode* const ohot
|
||||
= (allow_none
|
||||
? static_cast<AstNode*>(new AstOneHot0{nodep->fileline(), propp})
|
||||
: static_cast<AstNode*>(new AstOneHot{nodep->fileline(), propp}));
|
||||
AstNodeExpr* const ohot
|
||||
= (allow_none ? static_cast<AstNodeExpr*>(
|
||||
new AstOneHot0{nodep->fileline(), propp})
|
||||
: static_cast<AstNodeExpr*>(
|
||||
new AstOneHot{nodep->fileline(), propp}));
|
||||
AstIf* const ifp = new AstIf{
|
||||
nodep->fileline(), new AstLogNot{nodep->fileline(), ohot},
|
||||
newFireAssert(nodep,
|
||||
|
|
@ -345,8 +347,8 @@ private:
|
|||
ticks = VN_AS(nodep->ticksp(), Const)->toUInt();
|
||||
}
|
||||
UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width");
|
||||
AstNode* const exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNode* inp = newSampledExpr(exprp);
|
||||
AstNodeExpr* const exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* inp = newSampledExpr(exprp);
|
||||
AstVar* invarp = nullptr;
|
||||
AstSenTree* const sentreep = nodep->sentreep();
|
||||
sentreep->unlinkFrBack();
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ private:
|
|||
// Reset each always:
|
||||
AstSenItem* m_seniAlwaysp = nullptr; // Last sensitivity in always
|
||||
// Reset each assertion:
|
||||
AstNode* m_disablep = nullptr; // Last disable
|
||||
AstNodeExpr* m_disablep = nullptr; // Last disable
|
||||
|
||||
// METHODS
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ private:
|
|||
}
|
||||
// If disable iff is in outer property, move it to inner
|
||||
if (nodep->disablep()) {
|
||||
AstNode* const disablep = nodep->disablep()->unlinkFrBack();
|
||||
AstNodeExpr* const disablep = nodep->disablep()->unlinkFrBack();
|
||||
propExprp->disablep(disablep);
|
||||
}
|
||||
|
||||
|
|
@ -170,9 +170,9 @@ private:
|
|||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
|
||||
AstNode* const past = new AstPast(fl, exprp, nullptr);
|
||||
AstNodeExpr* const past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false)));
|
||||
exprp->dtypeSetBit();
|
||||
|
|
@ -189,9 +189,9 @@ private:
|
|||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
|
||||
AstNode* const past = new AstPast(fl, exprp, nullptr);
|
||||
AstNodeExpr* const past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false));
|
||||
exprp->dtypeSetBit();
|
||||
|
|
@ -203,8 +203,8 @@ private:
|
|||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNode* const past = new AstPast(fl, exprp, nullptr);
|
||||
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* const past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstEq(fl, past, exprp->cloneTree(false));
|
||||
exprp->dtypeSetBit();
|
||||
|
|
@ -217,14 +217,14 @@ private:
|
|||
if (nodep->sentreep()) return; // Already processed
|
||||
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
|
||||
if (m_disablep) lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp);
|
||||
|
||||
AstNode* const past = new AstPast(fl, lhsp, nullptr);
|
||||
AstNodeExpr* const past = new AstPast(fl, lhsp, nullptr);
|
||||
past->dtypeFrom(lhsp);
|
||||
AstNode* const exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
|
||||
AstNodeExpr* const exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
|
|
@ -238,8 +238,8 @@ private:
|
|||
if (m_senip)
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Only one PSL clock allowed per assertion");
|
||||
// Block is the new expression to evaluate
|
||||
AstNode* blockp = nodep->propp()->unlinkFrBack();
|
||||
if (AstNode* const disablep = nodep->disablep()) {
|
||||
AstNodeExpr* blockp = VN_AS(nodep->propp()->unlinkFrBack(), NodeExpr);
|
||||
if (AstNodeExpr* const disablep = nodep->disablep()) {
|
||||
m_disablep = disablep->cloneTree(false);
|
||||
if (VN_IS(nodep->backp(), Cover)) {
|
||||
blockp = new AstAnd(disablep->fileline(),
|
||||
|
|
|
|||
|
|
@ -1877,8 +1877,8 @@ public:
|
|||
void addNextHere(AstNode* newp); // Insert newp at this->nextp
|
||||
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
||||
void replaceWith(AstNode* newp); // Replace current node in tree with new node
|
||||
AstNode* unlinkFrBack(VNRelinker* linkerp
|
||||
= nullptr); // Unlink this from whoever points to it.
|
||||
// Unlink this from whoever points to it.
|
||||
AstNode* unlinkFrBack(VNRelinker* linkerp = nullptr);
|
||||
// Unlink this from whoever points to it, keep entire next list with unlinked node
|
||||
AstNode* unlinkFrBackWithNext(VNRelinker* linkerp = nullptr);
|
||||
void swapWith(AstNode* bp);
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ bool AstBasicDType::littleEndian() const {
|
|||
bool AstActive::hasClocked() const { return m_sensesp->hasClocked(); }
|
||||
bool AstActive::hasCombo() const { return m_sensesp->hasCombo(); }
|
||||
|
||||
AstElabDisplay::AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNode* exprsp)
|
||||
AstElabDisplay::AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr* exprsp)
|
||||
: ASTGEN_SUPER_ElabDisplay(fl) {
|
||||
addFmtp(new AstSFormatF{fl, AstSFormatF::NoFormat(), exprsp});
|
||||
m_displayType = dispType;
|
||||
|
|
|
|||
|
|
@ -261,13 +261,13 @@ public:
|
|||
// === AstNode ===
|
||||
class AstEnumItem final : public AstNode {
|
||||
// @astgen op1 := rangep : Optional[AstRange] // Range for name appending
|
||||
// @astgen op2 := valuep : Optional[AstNode]
|
||||
// @astgen op2 := valuep : Optional[AstNodeExpr]
|
||||
private:
|
||||
string m_name;
|
||||
|
||||
public:
|
||||
// Parents: ENUM
|
||||
AstEnumItem(FileLine* fl, const string& name, AstRange* rangep, AstNode* valuep)
|
||||
AstEnumItem(FileLine* fl, const string& name, AstRange* rangep, AstNodeExpr* valuep)
|
||||
: ASTGEN_SUPER_EnumItem(fl)
|
||||
, m_name{name} {
|
||||
this->rangep(rangep);
|
||||
|
|
@ -972,18 +972,18 @@ public:
|
|||
class AstQueueDType final : public AstNodeDType {
|
||||
// Queue array data type, ie "[ $ ]"
|
||||
// @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width
|
||||
// @astgen op2 := boundp : Optional[AstNode]
|
||||
// @astgen op2 := boundp : Optional[AstNodeExpr]
|
||||
private:
|
||||
AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing)
|
||||
public:
|
||||
AstQueueDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* boundp)
|
||||
AstQueueDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNodeExpr* boundp)
|
||||
: ASTGEN_SUPER_QueueDType(fl) {
|
||||
this->childDTypep(dtp);
|
||||
this->boundp(boundp);
|
||||
refDTypep(nullptr);
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp)
|
||||
AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNodeExpr* boundp)
|
||||
: ASTGEN_SUPER_QueueDType(fl) {
|
||||
this->boundp(boundp);
|
||||
refDTypep(dtp);
|
||||
|
|
@ -1032,7 +1032,7 @@ public:
|
|||
};
|
||||
class AstRefDType final : public AstNodeDType {
|
||||
// @astgen op1 := typeofp : Optional[AstNode]
|
||||
// @astgen op2 := classOrPackageOpp : Optional[AstNode]
|
||||
// @astgen op2 := classOrPackageOpp : Optional[AstNodeExpr]
|
||||
// @astgen op3 := paramsp : List[AstPin]
|
||||
private:
|
||||
// Pre-Width must reference the Typeref, not what it points to, as some child
|
||||
|
|
@ -1046,7 +1046,7 @@ public:
|
|||
AstRefDType(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_RefDType(fl)
|
||||
, m_name{name} {}
|
||||
AstRefDType(FileLine* fl, const string& name, AstNode* classOrPackagep, AstPin* paramsp)
|
||||
AstRefDType(FileLine* fl, const string& name, AstNodeExpr* classOrPackagep, AstPin* paramsp)
|
||||
: ASTGEN_SUPER_RefDType(fl)
|
||||
, m_name{name} {
|
||||
this->classOrPackageOpp(classOrPackagep);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -310,11 +310,11 @@ public:
|
|||
};
|
||||
class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt {
|
||||
// Iteration is in order, and we want rhsp to be visited first (which is the execution order)
|
||||
// @astgen op1 := rhsp : AstNode
|
||||
// @astgen op2 := lhsp : AstNode
|
||||
// @astgen op1 := rhsp : AstNodeExpr
|
||||
// @astgen op2 := lhsp : AstNodeExpr
|
||||
// @astgen op3 := timingControlp : Optional[AstNode]
|
||||
protected:
|
||||
AstNodeAssign(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp,
|
||||
AstNodeAssign(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
|
||||
AstNode* timingControlp = nullptr)
|
||||
: AstNodeStmt{t, fl} {
|
||||
this->rhsp(rhsp);
|
||||
|
|
@ -326,7 +326,7 @@ protected:
|
|||
public:
|
||||
ASTGEN_MEMBERS_AstNodeAssign;
|
||||
// Clone single node, just get same type back.
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0;
|
||||
virtual AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) = 0;
|
||||
bool hasDType() const override { return true; }
|
||||
virtual bool cleanRhs() const { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
|
|
@ -336,11 +336,11 @@ public:
|
|||
virtual bool brokeLhsMustBeLvalue() const = 0;
|
||||
};
|
||||
class AstNodeCase VL_NOT_FINAL : public AstNodeStmt {
|
||||
// @astgen op1 := exprp : AstNode // Condition (scurtinee) expression
|
||||
// @astgen op1 := exprp : AstNodeExpr // Condition (scurtinee) expression
|
||||
// @astgen op2 := itemsp : List[AstCaseItem]
|
||||
// @astgen op3 := notParallelp : List[AstNode] // assertion code for non-full case's
|
||||
protected:
|
||||
AstNodeCase(VNType t, FileLine* fl, AstNode* exprp, AstCaseItem* itemsp)
|
||||
AstNodeCase(VNType t, FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp)
|
||||
: AstNodeStmt{t, fl} {
|
||||
this->exprp(exprp);
|
||||
this->addItemsp(itemsp);
|
||||
|
|
@ -377,11 +377,11 @@ public:
|
|||
};
|
||||
class AstNodeFor VL_NOT_FINAL : public AstNodeStmt {
|
||||
// @astgen op1 := initsp : List[AstNode]
|
||||
// @astgen op2 := condp : AstNode
|
||||
// @astgen op2 := condp : AstNodeExpr
|
||||
// @astgen op3 := incsp : List[AstNode]
|
||||
// @astgen op4 := stmtsp : List[AstNode]
|
||||
protected:
|
||||
AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp,
|
||||
AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp,
|
||||
AstNode* stmtsp)
|
||||
: AstNodeStmt{t, fl} {
|
||||
this->addInitsp(initsp);
|
||||
|
|
@ -397,14 +397,14 @@ public:
|
|||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstNodeIf VL_NOT_FINAL : public AstNodeStmt {
|
||||
// @astgen op1 := condp : AstNode
|
||||
// @astgen op1 := condp : AstNodeExpr
|
||||
// @astgen op2 := thensp : List[AstNode]
|
||||
// @astgen op3 := elsesp : List[AstNode]
|
||||
private:
|
||||
VBranchPred m_branchPred; // Branch prediction as taken/untaken?
|
||||
bool m_isBoundsCheck; // True if this if node is for assertion/bounds checking
|
||||
protected:
|
||||
AstNodeIf(VNType t, FileLine* fl, AstNode* condp, AstNode* thensp, AstNode* elsesp)
|
||||
AstNodeIf(VNType t, FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
|
||||
: AstNodeStmt{t, fl} {
|
||||
this->condp(condp);
|
||||
this->addThensp(thensp);
|
||||
|
|
@ -427,15 +427,15 @@ public:
|
|||
}
|
||||
};
|
||||
class AstNodeReadWriteMem VL_NOT_FINAL : public AstNodeStmt {
|
||||
// @astgen op1 := filenamep : AstNode
|
||||
// @astgen op2 := memp : AstNode
|
||||
// @astgen op3 := lsbp : Optional[AstNode]
|
||||
// @astgen op4 := msbp : Optional[AstNode]
|
||||
// @astgen op1 := filenamep : AstNodeExpr
|
||||
// @astgen op2 := memp : AstNodeExpr
|
||||
// @astgen op3 := lsbp : Optional[AstNodeExpr]
|
||||
// @astgen op4 := msbp : Optional[AstNodeExpr]
|
||||
|
||||
const bool m_isHex; // readmemh, not readmemb
|
||||
public:
|
||||
AstNodeReadWriteMem(VNType t, FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp,
|
||||
AstNode* lsbp, AstNode* msbp)
|
||||
AstNodeReadWriteMem(VNType t, FileLine* fl, bool hex, AstNodeExpr* filenamep,
|
||||
AstNodeExpr* memp, AstNodeExpr* lsbp, AstNodeExpr* msbp)
|
||||
: AstNodeStmt(t, fl)
|
||||
, m_isHex(hex) {
|
||||
this->filenamep(filenamep);
|
||||
|
|
@ -518,21 +518,6 @@ public:
|
|||
inline bool hasClocked() const;
|
||||
inline bool hasCombo() const;
|
||||
};
|
||||
class AstArg final : public AstNode {
|
||||
// An argument to a function/task
|
||||
// @astgen op1 := exprp : Optional[AstNode] // nullptr if omitted
|
||||
string m_name; // Pin name, or "" for number based interconnect
|
||||
public:
|
||||
AstArg(FileLine* fl, const string& name, AstNode* exprp)
|
||||
: ASTGEN_SUPER_Arg(fl)
|
||||
, m_name{name} {
|
||||
this->exprp(exprp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstArg;
|
||||
string name() const override { return m_name; } // * = Pin name, ""=go by number
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); }
|
||||
};
|
||||
class AstBind final : public AstNode {
|
||||
// Parents: MODULE
|
||||
// Children: CELL
|
||||
|
|
@ -718,10 +703,10 @@ public:
|
|||
};
|
||||
class AstCaseItem final : public AstNode {
|
||||
// Single item of a case statement
|
||||
// @astgen op1 := condsp : List[AstNode]
|
||||
// @astgen op1 := condsp : List[AstNodeExpr]
|
||||
// @astgen op2 := stmtsp : List[AstNode]
|
||||
public:
|
||||
AstCaseItem(FileLine* fl, AstNode* condsp, AstNode* stmtsp)
|
||||
AstCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* stmtsp)
|
||||
: ASTGEN_SUPER_CaseItem(fl) {
|
||||
this->addCondsp(condsp);
|
||||
this->addStmtsp(stmtsp);
|
||||
|
|
@ -731,23 +716,6 @@ public:
|
|||
bool isDefault() const { return condsp() == nullptr; }
|
||||
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
||||
};
|
||||
class AstCastSize final : public AstNode {
|
||||
// Cast to specific size; signed/twostate inherited from lower element per IEEE
|
||||
// @astgen op1 := lhsp : AstNode
|
||||
// @astgen op2 := rhsp : AstNode
|
||||
public:
|
||||
AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp)
|
||||
: ASTGEN_SUPER_CastSize(fl) {
|
||||
this->lhsp(lhsp);
|
||||
this->rhsp(rhsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCastSize;
|
||||
// No hasDType because widthing removes this node before the hasDType check
|
||||
virtual string emitVerilog() { return "((%r)'(%l))"; }
|
||||
virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); }
|
||||
virtual bool cleanLhs() const { return true; }
|
||||
virtual bool sizeMattersLhs() const { return false; }
|
||||
};
|
||||
class AstCell final : public AstNode {
|
||||
// A instantiation cell or interface call (don't know which until link)
|
||||
// @astgen op1 := pinsp : List[AstPin] // List of port assignments
|
||||
|
|
@ -799,20 +767,6 @@ public:
|
|||
void recursive(bool flag) { m_recursive = flag; }
|
||||
bool recursive() const { return m_recursive; }
|
||||
};
|
||||
class AstCellArrayRef final : public AstNode {
|
||||
// As-of-yet unlinkable reference into an array of cells
|
||||
// @astgen op1 := selp : List[AstNode] // Select expression
|
||||
string m_name; // Array name
|
||||
public:
|
||||
AstCellArrayRef(FileLine* fl, const string& name, AstNode* selp)
|
||||
: ASTGEN_SUPER_CellArrayRef(fl)
|
||||
, m_name{name} {
|
||||
this->addSelp(selp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCellArrayRef;
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Array name
|
||||
};
|
||||
class AstCellInline final : public AstNode {
|
||||
// A instantiation cell that was removed by inlining
|
||||
// For communication between V3Inline and V3LinkDot,
|
||||
|
|
@ -844,23 +798,6 @@ public:
|
|||
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
||||
VTimescale timeunit() const { return m_timeunit; }
|
||||
};
|
||||
class AstCellRef final : public AstNode {
|
||||
// As-of-yet unlinkable reference into a cell
|
||||
// @astgen op1 := cellp : AstNode
|
||||
// @astgen op2 := exprp : AstNode
|
||||
private:
|
||||
string m_name; // Cell name
|
||||
public:
|
||||
AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNode* exprp)
|
||||
: ASTGEN_SUPER_CellRef(fl)
|
||||
, m_name{name} {
|
||||
this->cellp(cellp);
|
||||
this->exprp(exprp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCellRef;
|
||||
// ACCESSORS
|
||||
string name() const override { return m_name; } // * = Array name
|
||||
};
|
||||
class AstClassExtends final : public AstNode {
|
||||
// Children: List of AstParseRef for packages/classes
|
||||
// during early parse, then moves to dtype
|
||||
|
|
@ -876,43 +813,6 @@ public:
|
|||
string verilogKwd() const override { return "extends"; }
|
||||
AstClass* classp() const; // Class being extended (after link)
|
||||
};
|
||||
class AstClassOrPackageRef final : public AstNode {
|
||||
// @astgen op1 := paramsp : List[AstPin]
|
||||
private:
|
||||
string m_name;
|
||||
// Node not NodeModule to appease some early parser usage
|
||||
AstNode* m_classOrPackageNodep; // Package hierarchy
|
||||
public:
|
||||
AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep,
|
||||
AstPin* paramsp)
|
||||
: ASTGEN_SUPER_ClassOrPackageRef(fl)
|
||||
, m_name{name}
|
||||
, m_classOrPackageNodep{classOrPackageNodep} {
|
||||
this->addParamsp(paramsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstClassOrPackageRef;
|
||||
// METHODS
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(m_classOrPackageNodep && !m_classOrPackageNodep->brokeExists());
|
||||
return nullptr;
|
||||
}
|
||||
void cloneRelink() override {
|
||||
if (m_classOrPackageNodep && m_classOrPackageNodep->clonep()) {
|
||||
m_classOrPackageNodep = m_classOrPackageNodep->clonep();
|
||||
}
|
||||
}
|
||||
bool same(const AstNode* samep) const override {
|
||||
return (m_classOrPackageNodep
|
||||
== static_cast<const AstClassOrPackageRef*>(samep)->m_classOrPackageNodep);
|
||||
}
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; }
|
||||
void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; }
|
||||
AstNodeModule* classOrPackagep() const;
|
||||
AstPackage* packagep() const { return VN_CAST(classOrPackageNodep(), Package); }
|
||||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackageNodep = (AstNode*)nodep; }
|
||||
};
|
||||
class AstClocking final : public AstNode {
|
||||
// Set default clock region
|
||||
// Parents: MODULE
|
||||
|
|
@ -934,7 +834,7 @@ class AstConstPool final : public AstNode {
|
|||
AstModule* const m_modp; // The Module holding the Scope below ...
|
||||
AstScope* const m_scopep; // Scope holding the constant variables
|
||||
|
||||
AstVarScope* createNewEntry(const string& name, AstNode* initp);
|
||||
AstVarScope* createNewEntry(const string& name, AstNodeExpr* initp);
|
||||
|
||||
public:
|
||||
explicit AstConstPool(FileLine* fl);
|
||||
|
|
@ -960,11 +860,11 @@ public:
|
|||
class AstDefParam final : public AstNode {
|
||||
// A defparam assignment
|
||||
// Parents: MODULE
|
||||
// @astgen op1 := rhsp : AstNode
|
||||
// @astgen op1 := rhsp : AstNodeExpr
|
||||
string m_name; // Name of variable getting set
|
||||
string m_path; // Dotted cellname to set parameter of
|
||||
public:
|
||||
AstDefParam(FileLine* fl, const string& path, const string& name, AstNode* rhsp)
|
||||
AstDefParam(FileLine* fl, const string& path, const string& name, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_DefParam(fl)
|
||||
, m_name{name}
|
||||
, m_path{path} {
|
||||
|
|
@ -1000,7 +900,7 @@ private:
|
|||
VDisplayType m_displayType;
|
||||
|
||||
public:
|
||||
inline AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNode* exprsp);
|
||||
inline AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr* exprsp);
|
||||
ASTGEN_MEMBERS_AstElabDisplay;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!fmtp());
|
||||
|
|
@ -1064,50 +964,14 @@ public:
|
|||
}
|
||||
ASTGEN_MEMBERS_AstImplicit;
|
||||
};
|
||||
class AstInitArray final : public AstNode {
|
||||
// Set a var to a map of values
|
||||
// The list of initsp() is not relevant
|
||||
// If default is specified, the vector may be sparse, and not provide each value.
|
||||
// Key values are C++ array style, with lo() at index 0
|
||||
// Parents: ASTVAR::init()
|
||||
// @astgen op1 := defaultp : Optional[AstNode] // Default, if sparse
|
||||
// @astgen op2 := initsp : List[AstNode] // Initial value expressions
|
||||
//
|
||||
public:
|
||||
using KeyItemMap = std::map<uint64_t, AstInitItem*>;
|
||||
|
||||
private:
|
||||
KeyItemMap m_map; // Node value for each array index
|
||||
public:
|
||||
AstInitArray(FileLine* fl, AstNodeDType* newDTypep, AstNode* defaultp)
|
||||
: ASTGEN_SUPER_InitArray(fl) {
|
||||
dtypep(newDTypep);
|
||||
this->defaultp(defaultp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstInitArray;
|
||||
void dump(std::ostream& str) const override;
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
bool hasDType() const override { return true; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
// Only works if exact same children, instead should override comparison
|
||||
// of children list, and instead use map-vs-map key/value compare
|
||||
return m_map == static_cast<const AstInitArray*>(samep)->m_map;
|
||||
}
|
||||
void addValuep(AstNode* newp) { addIndexValuep(m_map.size(), newp); }
|
||||
const KeyItemMap& map() const { return m_map; }
|
||||
void addIndexValuep(uint64_t index, AstNode* newp);
|
||||
AstNode* getIndexValuep(uint64_t index) const;
|
||||
AstNode* getIndexDefaultedValuep(uint64_t index) const;
|
||||
};
|
||||
class AstInitItem final : public AstNode {
|
||||
// Container for a item in an init array
|
||||
// This container is present so that the value underneath may get replaced with a new nodep
|
||||
// and the upper AstInitArray's map will remain correct (pointing to this InitItem)
|
||||
// @astgen op1 := valuep : AstNode
|
||||
// @astgen op1 := valuep : AstNodeExpr
|
||||
public:
|
||||
// Parents: INITARRAY
|
||||
AstInitItem(FileLine* fl, AstNode* valuep)
|
||||
AstInitItem(FileLine* fl, AstNodeExpr* valuep)
|
||||
: ASTGEN_SUPER_InitItem(fl) {
|
||||
this->valuep(valuep);
|
||||
}
|
||||
|
|
@ -1317,7 +1181,7 @@ public:
|
|||
};
|
||||
class AstPin final : public AstNode {
|
||||
// A port or parameter assignment on an instantiaton
|
||||
// @astgen op1 := exprp : Optional[AstNode] // Expression connected (nullptr if unconnected)
|
||||
// @astgen op1 := exprp : Optional[AstNode] // NodeExpr or NodeDType (nullptr if unconnected)
|
||||
private:
|
||||
int m_pinNum; // Pin number
|
||||
string m_name; // Pin name, or "" for number based interconnect
|
||||
|
|
@ -1353,7 +1217,7 @@ public:
|
|||
};
|
||||
class AstPort final : public AstNode {
|
||||
// A port (in/out/inout) on a module
|
||||
// @astgen op1 := exprp : Optional[AstNode] // Expression connected to port
|
||||
// @astgen op1 := exprp : Optional[AstNodeExpr] // Expression connected to port
|
||||
const int m_pinNum; // Pin number
|
||||
const string m_name; // Name of pin
|
||||
public:
|
||||
|
|
@ -1385,10 +1249,10 @@ class AstPropSpec final : public AstNode {
|
|||
// Parents: ASSERT|COVER (property)
|
||||
// Children: SENITEM, Properties
|
||||
// @astgen op1 := sensesp : Optional[AstSenItem]
|
||||
// @astgen op2 := disablep : Optional[AstNode]
|
||||
// @astgen op2 := disablep : Optional[AstNodeExpr]
|
||||
// @astgen op3 := propp : AstNode
|
||||
public:
|
||||
AstPropSpec(FileLine* fl, AstSenItem* sensesp, AstNode* disablep, AstNode* propp)
|
||||
AstPropSpec(FileLine* fl, AstSenItem* sensesp, AstNodeExpr* disablep, AstNode* propp)
|
||||
: ASTGEN_SUPER_PropSpec(fl) {
|
||||
this->sensesp(sensesp);
|
||||
this->disablep(disablep);
|
||||
|
|
@ -1400,12 +1264,12 @@ public:
|
|||
} // Used under Cover, which expects a bool child
|
||||
};
|
||||
class AstPull final : public AstNode {
|
||||
// @astgen op1 := lhsp : AstNode
|
||||
// @astgen op1 := lhsp : AstNodeExpr
|
||||
|
||||
const bool m_direction;
|
||||
|
||||
public:
|
||||
AstPull(FileLine* fl, AstNode* lhsp, bool direction)
|
||||
AstPull(FileLine* fl, AstNodeExpr* lhsp, bool direction)
|
||||
: ASTGEN_SUPER_Pull(fl)
|
||||
, m_direction{direction} {
|
||||
this->lhsp(lhsp);
|
||||
|
|
@ -1455,24 +1319,9 @@ public:
|
|||
AstVarScope* createTemp(const string& name, AstNodeDType* dtypep);
|
||||
AstVarScope* createTempLike(const string& name, AstVarScope* vscp);
|
||||
};
|
||||
class AstSelLoopVars final : public AstNode {
|
||||
// Parser only concept "[id, id, id]" for a foreach statement
|
||||
// Unlike normal selects elements is a list
|
||||
// @astgen op1 := fromp : AstNode
|
||||
// @astgen op2 := elementsp : List[AstNode]
|
||||
public:
|
||||
AstSelLoopVars(FileLine* fl, AstNode* fromp, AstNode* elementsp)
|
||||
: ASTGEN_SUPER_SelLoopVars(fl) {
|
||||
this->fromp(fromp);
|
||||
this->addElementsp(elementsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstSelLoopVars;
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
bool maybePointedTo() const override { return false; }
|
||||
};
|
||||
class AstSenItem final : public AstNode {
|
||||
// Parents: SENTREE
|
||||
// @astgen op1 := sensp : Optional[AstNode] // Sensitivity expression
|
||||
// @astgen op1 := sensp : Optional[AstNodeExpr] // Sensitivity expression
|
||||
VEdgeType m_edgeType; // Edge type
|
||||
public:
|
||||
class Combo {}; // for constructor type-overload selection
|
||||
|
|
@ -1481,7 +1330,7 @@ public:
|
|||
class Initial {}; // for constructor type-overload selection
|
||||
class Final {}; // for constructor type-overload selection
|
||||
class Never {}; // for constructor type-overload selection
|
||||
AstSenItem(FileLine* fl, VEdgeType edgeType, AstNode* senp)
|
||||
AstSenItem(FileLine* fl, VEdgeType edgeType, AstNodeExpr* senp)
|
||||
: ASTGEN_SUPER_SenItem(fl)
|
||||
, m_edgeType{edgeType} {
|
||||
this->sensp(senp);
|
||||
|
|
@ -1695,7 +1544,7 @@ class AstVar final : public AstNode {
|
|||
// @astgen op2 := delayp : Optional[AstDelay] // Net delay
|
||||
// Initial value that never changes (static const), or constructor argument for
|
||||
// MTASKSTATE variables
|
||||
// @astgen op3 := valuep : Optional[AstNode]
|
||||
// @astgen op3 := valuep : Optional[AstNode] // May be a DType for type parameter defaults
|
||||
// @astgen op4 := attrsp : List[AstNode] // Attributes during early parse
|
||||
|
||||
string m_name; // Name of variable
|
||||
|
|
@ -2381,7 +2230,7 @@ public:
|
|||
class AstBracketRange final : public AstNodeRange {
|
||||
// Parser only concept "[lhsp]", a AstUnknownRange, QueueRange or Range,
|
||||
// unknown until lhsp type is determined
|
||||
// @astgen op1 := elementsp : AstNode
|
||||
// @astgen op1 := elementsp : AstNode // Expr or DType
|
||||
public:
|
||||
AstBracketRange(FileLine* fl, AstNode* elementsp)
|
||||
: ASTGEN_SUPER_BracketRange(fl) {
|
||||
|
|
@ -2397,10 +2246,10 @@ public:
|
|||
};
|
||||
class AstRange final : public AstNodeRange {
|
||||
// Range specification, for use under variables and cells
|
||||
// @astgen op1 := leftp : AstNode
|
||||
// @astgen op2 := rightp : AstNode
|
||||
// @astgen op1 := leftp : AstNodeExpr
|
||||
// @astgen op2 := rightp : AstNodeExpr
|
||||
public:
|
||||
AstRange(FileLine* fl, AstNode* leftp, AstNode* rightp)
|
||||
AstRange(FileLine* fl, AstNodeExpr* leftp, AstNodeExpr* rightp)
|
||||
: ASTGEN_SUPER_Range(fl) {
|
||||
this->leftp(leftp);
|
||||
this->rightp(rightp);
|
||||
|
|
@ -2490,9 +2339,9 @@ public:
|
|||
};
|
||||
class AstCReturn final : public AstNodeStmt {
|
||||
// C++ return from a function
|
||||
// @astgen op1 := lhsp : AstNode
|
||||
// @astgen op1 := lhsp : AstNodeExpr
|
||||
public:
|
||||
AstCReturn(FileLine* fl, AstNode* lhsp)
|
||||
AstCReturn(FileLine* fl, AstNodeExpr* lhsp)
|
||||
: ASTGEN_SUPER_CReturn(fl) {
|
||||
this->lhsp(lhsp);
|
||||
}
|
||||
|
|
@ -2516,7 +2365,6 @@ public:
|
|||
};
|
||||
class AstComment final : public AstNodeStmt {
|
||||
// Some comment to put into the output stream
|
||||
// Parents: {statement list}
|
||||
const string m_name; // Text of comment
|
||||
const bool m_showAt; // Show "at <fileline>"
|
||||
public:
|
||||
|
|
@ -2541,9 +2389,6 @@ public:
|
|||
};
|
||||
class AstCoverDecl final : public AstNodeStmt {
|
||||
// Coverage analysis point declaration
|
||||
// Parents: {statement list}
|
||||
// Children: none
|
||||
private:
|
||||
AstCoverDecl* m_dataDeclp = nullptr; // [After V3CoverageJoin] Pointer to duplicate
|
||||
// declaration to get data from instead
|
||||
string m_page;
|
||||
|
|
@ -2597,9 +2442,6 @@ public:
|
|||
};
|
||||
class AstCoverInc final : public AstNodeStmt {
|
||||
// Coverage analysis point; increment coverage count
|
||||
// Parents: {statement list}
|
||||
// Children: none
|
||||
private:
|
||||
AstCoverDecl* m_declp; // [After V3Coverage] Pointer to declaration
|
||||
public:
|
||||
AstCoverInc(FileLine* fl, AstCoverDecl* declp)
|
||||
|
|
@ -2628,10 +2470,10 @@ class AstCoverToggle final : public AstNodeStmt {
|
|||
// Toggle analysis of given signal
|
||||
// Parents: MODULE
|
||||
// @astgen op1 := incp : AstCoverInc
|
||||
// @astgen op2 := origp : AstNode
|
||||
// @astgen op3 := changep : AstNode
|
||||
// @astgen op2 := origp : AstNodeExpr
|
||||
// @astgen op3 := changep : AstNodeExpr
|
||||
public:
|
||||
AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNode* origp, AstNode* changep)
|
||||
AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNodeExpr* origp, AstNodeExpr* changep)
|
||||
: ASTGEN_SUPER_CoverToggle(fl) {
|
||||
this->incp(incp);
|
||||
this->origp(origp);
|
||||
|
|
@ -2649,10 +2491,10 @@ public:
|
|||
};
|
||||
class AstDelay final : public AstNodeStmt {
|
||||
// Delay statement
|
||||
// @astgen op1 := lhsp : AstNode // Delay value
|
||||
// @astgen op1 := lhsp : AstNodeExpr // Delay value
|
||||
// @astgen op2 := stmtsp : List[AstNode] // Statements under delay
|
||||
public:
|
||||
AstDelay(FileLine* fl, AstNode* lhsp)
|
||||
AstDelay(FileLine* fl, AstNodeExpr* lhsp)
|
||||
: ASTGEN_SUPER_Delay(fl) {
|
||||
this->lhsp(lhsp);
|
||||
}
|
||||
|
|
@ -2661,7 +2503,6 @@ public:
|
|||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstDisable final : public AstNodeStmt {
|
||||
private:
|
||||
string m_name; // Name of block
|
||||
public:
|
||||
AstDisable(FileLine* fl, const string& name)
|
||||
|
|
@ -2684,19 +2525,19 @@ public:
|
|||
class AstDisplay final : public AstNodeStmt {
|
||||
// Parents: stmtlist
|
||||
// @astgen op1 := fmtp : AstSFormatF
|
||||
// @astgen op2 := filep : Optional[AstNode] // file (must be a VarRef)
|
||||
// @astgen op2 := filep : Optional[AstNodeExpr] // file (must resolve to a VarRef)
|
||||
private:
|
||||
VDisplayType m_displayType;
|
||||
|
||||
public:
|
||||
AstDisplay(FileLine* fl, VDisplayType dispType, const string& text, AstNode* filep,
|
||||
AstNode* exprsp, char missingArgChar = 'd')
|
||||
AstDisplay(FileLine* fl, VDisplayType dispType, const string& text, AstNodeExpr* filep,
|
||||
AstNodeExpr* exprsp, char missingArgChar = 'd')
|
||||
: ASTGEN_SUPER_Display(fl)
|
||||
, m_displayType{dispType} {
|
||||
this->fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
|
||||
this->filep(filep);
|
||||
}
|
||||
AstDisplay(FileLine* fl, VDisplayType dispType, AstNode* filep, AstNode* exprsp,
|
||||
AstDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr* filep, AstNodeExpr* exprsp,
|
||||
char missingArgChar = 'd')
|
||||
: ASTGEN_SUPER_Display(fl)
|
||||
, m_displayType{dispType} {
|
||||
|
|
@ -2729,11 +2570,11 @@ public:
|
|||
};
|
||||
class AstDoWhile final : public AstNodeStmt {
|
||||
// @astgen op1 := precondsp : List[AstNode]
|
||||
// @astgen op2 := condp : AstNode
|
||||
// @astgen op2 := condp : AstNodeExpr
|
||||
// @astgen op3 := stmtsp : List[AstNode]
|
||||
// @astgen op4 := incsp : List[AstNode]
|
||||
public:
|
||||
AstDoWhile(FileLine* fl, AstNode* conditionp, AstNode* stmtsp = nullptr,
|
||||
AstDoWhile(FileLine* fl, AstNodeExpr* conditionp, AstNode* stmtsp = nullptr,
|
||||
AstNode* incsp = nullptr)
|
||||
: ASTGEN_SUPER_DoWhile(fl) {
|
||||
condp(conditionp);
|
||||
|
|
@ -2750,10 +2591,10 @@ public:
|
|||
class AstDumpCtl final : public AstNodeStmt {
|
||||
// $dumpon etc
|
||||
// Parents: expr
|
||||
// @astgen op1 := exprp : Optional[AstNode] // Expression based on type of control statement
|
||||
// @astgen op1 := exprp : Optional[AstNodeExpr] // Expression based on type of statement
|
||||
const VDumpCtlType m_ctlType; // Type of operation
|
||||
public:
|
||||
AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNode* exprp = nullptr)
|
||||
AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNodeExpr* exprp = nullptr)
|
||||
: ASTGEN_SUPER_DumpCtl(fl)
|
||||
, m_ctlType{ctlType} {
|
||||
this->exprp(exprp);
|
||||
|
|
@ -2784,9 +2625,9 @@ public:
|
|||
};
|
||||
class AstFClose final : public AstNodeStmt {
|
||||
// Parents: stmtlist
|
||||
// @astgen op1 := filep : AstNode // file (must be a VarRef)
|
||||
// @astgen op1 := filep : AstNodeExpr // file (must be a VarRef)
|
||||
public:
|
||||
AstFClose(FileLine* fl, AstNode* filep)
|
||||
AstFClose(FileLine* fl, AstNodeExpr* filep)
|
||||
: ASTGEN_SUPER_FClose(fl) {
|
||||
this->filep(filep);
|
||||
}
|
||||
|
|
@ -2801,9 +2642,9 @@ public:
|
|||
};
|
||||
class AstFFlush final : public AstNodeStmt {
|
||||
// Parents: stmtlist
|
||||
// @astgen op1 := filep : Optional[AstNode] // file (must be a VarRef)
|
||||
// @astgen op1 := filep : Optional[AstNodeExpr] // file (must be a VarRef)
|
||||
public:
|
||||
AstFFlush(FileLine* fl, AstNode* filep)
|
||||
AstFFlush(FileLine* fl, AstNodeExpr* filep)
|
||||
: ASTGEN_SUPER_FFlush(fl) {
|
||||
this->filep(filep);
|
||||
}
|
||||
|
|
@ -2818,11 +2659,11 @@ public:
|
|||
};
|
||||
class AstFOpen final : public AstNodeStmt {
|
||||
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
|
||||
// @astgen op1 := filep : AstNode
|
||||
// @astgen op2 := filenamep : AstNode
|
||||
// @astgen op3 := modep : AstNode
|
||||
// @astgen op1 := filep : AstNodeExpr
|
||||
// @astgen op2 := filenamep : AstNodeExpr
|
||||
// @astgen op3 := modep : AstNodeExpr
|
||||
public:
|
||||
AstFOpen(FileLine* fl, AstNode* filep, AstNode* filenamep, AstNode* modep)
|
||||
AstFOpen(FileLine* fl, AstNodeExpr* filep, AstNodeExpr* filenamep, AstNodeExpr* modep)
|
||||
: ASTGEN_SUPER_FOpen(fl) {
|
||||
this->filep(filep);
|
||||
this->filenamep(filenamep);
|
||||
|
|
@ -2839,10 +2680,10 @@ public:
|
|||
};
|
||||
class AstFOpenMcd final : public AstNodeStmt {
|
||||
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
|
||||
// @astgen op1 := filep : AstNode
|
||||
// @astgen op2 := filenamep : AstNode
|
||||
// @astgen op1 := filep : AstNodeExpr
|
||||
// @astgen op2 := filenamep : AstNodeExpr
|
||||
public:
|
||||
AstFOpenMcd(FileLine* fl, AstNode* filep, AstNode* filenamep)
|
||||
AstFOpenMcd(FileLine* fl, AstNodeExpr* filep, AstNodeExpr* filenamep)
|
||||
: ASTGEN_SUPER_FOpenMcd(fl) {
|
||||
this->filep(filep);
|
||||
this->filenamep(filenamep);
|
||||
|
|
@ -2871,10 +2712,10 @@ public:
|
|||
};
|
||||
class AstFireEvent final : public AstNodeStmt {
|
||||
// '-> _' and '->> _' event trigger statements
|
||||
// @astgen op1 := operandp : AstNode
|
||||
// @astgen op1 := operandp : AstNodeExpr
|
||||
const bool m_delayed; // Delayed (->>) vs non-delayed (->)
|
||||
public:
|
||||
AstFireEvent(FileLine* fl, AstNode* operandp, bool delayed)
|
||||
AstFireEvent(FileLine* fl, AstNodeExpr* operandp, bool delayed)
|
||||
: ASTGEN_SUPER_FireEvent(fl)
|
||||
, m_delayed{delayed} {
|
||||
this->operandp(operandp);
|
||||
|
|
@ -3026,19 +2867,19 @@ public:
|
|||
};
|
||||
class AstRelease final : public AstNodeStmt {
|
||||
// Procedural 'release' statement
|
||||
// @astgen op1 := lhsp : AstNode
|
||||
// @astgen op1 := lhsp : AstNodeExpr
|
||||
public:
|
||||
AstRelease(FileLine* fl, AstNode* lhsp)
|
||||
AstRelease(FileLine* fl, AstNodeExpr* lhsp)
|
||||
: ASTGEN_SUPER_Release(fl) {
|
||||
this->lhsp(lhsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstRelease;
|
||||
};
|
||||
class AstRepeat final : public AstNodeStmt {
|
||||
// @astgen op1 := countp : AstNode
|
||||
// @astgen op1 := countp : AstNodeExpr
|
||||
// @astgen op2 := stmtsp : List[AstNode]
|
||||
public:
|
||||
AstRepeat(FileLine* fl, AstNode* countp, AstNode* stmtsp)
|
||||
AstRepeat(FileLine* fl, AstNodeExpr* countp, AstNode* stmtsp)
|
||||
: ASTGEN_SUPER_Repeat(fl) {
|
||||
this->countp(countp);
|
||||
this->addStmtsp(stmtsp);
|
||||
|
|
@ -3050,9 +2891,9 @@ public:
|
|||
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
||||
};
|
||||
class AstReturn final : public AstNodeStmt {
|
||||
// @astgen op1 := lhsp : Optional[AstNode]
|
||||
// @astgen op1 := lhsp : Optional[AstNodeExpr]
|
||||
public:
|
||||
explicit AstReturn(FileLine* fl, AstNode* lhsp = nullptr)
|
||||
explicit AstReturn(FileLine* fl, AstNodeExpr* lhsp = nullptr)
|
||||
: ASTGEN_SUPER_Return(fl) {
|
||||
this->lhsp(lhsp);
|
||||
}
|
||||
|
|
@ -3065,15 +2906,15 @@ public:
|
|||
class AstSFormat final : public AstNodeStmt {
|
||||
// Parents: statement container
|
||||
// @astgen op1 := fmtp : AstSFormatF
|
||||
// @astgen op2 := lhsp : AstNode
|
||||
// @astgen op2 := lhsp : AstNodeExpr
|
||||
public:
|
||||
AstSFormat(FileLine* fl, AstNode* lhsp, const string& text, AstNode* exprsp,
|
||||
AstSFormat(FileLine* fl, AstNodeExpr* lhsp, const string& text, AstNodeExpr* exprsp,
|
||||
char missingArgChar = 'd')
|
||||
: ASTGEN_SUPER_SFormat(fl) {
|
||||
this->fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar});
|
||||
this->lhsp(lhsp);
|
||||
}
|
||||
AstSFormat(FileLine* fl, AstNode* lhsp, AstNode* exprsp, char missingArgChar = 'd')
|
||||
AstSFormat(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* exprsp, char missingArgChar = 'd')
|
||||
: ASTGEN_SUPER_SFormat(fl) {
|
||||
this->fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat(), exprsp, missingArgChar});
|
||||
this->lhsp(lhsp);
|
||||
|
|
@ -3130,10 +2971,11 @@ public:
|
|||
bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); }
|
||||
};
|
||||
class AstSysFuncAsTask final : public AstNodeStmt {
|
||||
// TODO: This is superseded by AstStmtExpr, remove
|
||||
// Call what is normally a system function (with a return) in a non-return context
|
||||
// @astgen op1 := lhsp : AstNode
|
||||
// @astgen op1 := lhsp : AstNodeExpr
|
||||
public:
|
||||
AstSysFuncAsTask(FileLine* fl, AstNode* lhsp)
|
||||
AstSysFuncAsTask(FileLine* fl, AstNodeExpr* lhsp)
|
||||
: ASTGEN_SUPER_SysFuncAsTask(fl) {
|
||||
this->lhsp(lhsp);
|
||||
}
|
||||
|
|
@ -3148,9 +2990,9 @@ public:
|
|||
};
|
||||
class AstSystemT final : public AstNodeStmt {
|
||||
// $system used as task
|
||||
// @astgen op1 := lhsp : AstNode
|
||||
// @astgen op1 := lhsp : AstNodeExpr
|
||||
public:
|
||||
AstSystemT(FileLine* fl, AstNode* lhsp)
|
||||
AstSystemT(FileLine* fl, AstNodeExpr* lhsp)
|
||||
: ASTGEN_SUPER_SystemT(fl) {
|
||||
this->lhsp(lhsp);
|
||||
}
|
||||
|
|
@ -3165,13 +3007,13 @@ public:
|
|||
};
|
||||
class AstTimeFormat final : public AstNodeStmt {
|
||||
// Parents: stmtlist
|
||||
// @astgen op1 := unitsp : AstNode
|
||||
// @astgen op2 := precisionp : AstNode
|
||||
// @astgen op3 := suffixp : AstNode
|
||||
// @astgen op4 := widthp : AstNode
|
||||
// @astgen op1 := unitsp : AstNodeExpr
|
||||
// @astgen op2 := precisionp : AstNodeExpr
|
||||
// @astgen op3 := suffixp : AstNodeExpr
|
||||
// @astgen op4 := widthp : AstNodeExpr
|
||||
public:
|
||||
AstTimeFormat(FileLine* fl, AstNode* unitsp, AstNode* precisionp, AstNode* suffixp,
|
||||
AstNode* widthp)
|
||||
AstTimeFormat(FileLine* fl, AstNodeExpr* unitsp, AstNodeExpr* precisionp, AstNodeExpr* suffixp,
|
||||
AstNodeExpr* widthp)
|
||||
: ASTGEN_SUPER_TimeFormat(fl) {
|
||||
this->unitsp(unitsp);
|
||||
this->precisionp(precisionp);
|
||||
|
|
@ -3191,7 +3033,7 @@ class AstTraceDecl final : public AstNodeStmt {
|
|||
// Separate from AstTraceInc; as a declaration can't be deleted
|
||||
// Parents: {statement list}
|
||||
// Expression being traced - Moved to AstTraceInc by V3Trace
|
||||
// @astgen op1 := valuep : Optional[AstNode]
|
||||
// @astgen op1 := valuep : Optional[AstNodeExpr]
|
||||
private:
|
||||
uint32_t m_code = 0; // Trace identifier code; converted to ASCII by trace routines
|
||||
const string m_showname; // Name of variable
|
||||
|
|
@ -3204,7 +3046,7 @@ private:
|
|||
public:
|
||||
AstTraceDecl(FileLine* fl, const string& showname,
|
||||
AstVar* varp, // For input/output state etc
|
||||
AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange)
|
||||
AstNodeExpr* valuep, const VNumRange& bitRange, const VNumRange& arrayRange)
|
||||
: ASTGEN_SUPER_TraceDecl(fl)
|
||||
, m_showname{showname}
|
||||
, m_bitRange{bitRange}
|
||||
|
|
@ -3239,7 +3081,7 @@ public:
|
|||
class AstTraceInc final : public AstNodeStmt {
|
||||
// Trace point dump
|
||||
// @astgen op1 := precondsp : List[AstNode] // Statements to emit before this node
|
||||
// @astgen op2 := valuep : AstNode // Expression being traced (from decl)
|
||||
// @astgen op2 := valuep : AstNodeExpr // Expression being traced (from decl)
|
||||
|
||||
private:
|
||||
AstTraceDecl* m_declp; // Pointer to declaration
|
||||
|
|
@ -3300,7 +3142,7 @@ public:
|
|||
};
|
||||
class AstUCStmt final : public AstNodeStmt {
|
||||
// User $c statement
|
||||
// @astgen op1 := exprsp : List[AstNode]
|
||||
// @astgen op1 := exprsp : List[AstNode] // (some are AstText)
|
||||
public:
|
||||
AstUCStmt(FileLine* fl, AstNode* exprsp)
|
||||
: ASTGEN_SUPER_UCStmt(fl) {
|
||||
|
|
@ -3314,10 +3156,10 @@ public:
|
|||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstWait final : public AstNodeStmt {
|
||||
// @astgen op1 := condp : AstNode
|
||||
// @astgen op1 := condp : AstNodeExpr
|
||||
// @astgen op2 := stmtsp : List[AstNode]
|
||||
public:
|
||||
AstWait(FileLine* fl, AstNode* condp, AstNode* stmtsp)
|
||||
AstWait(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp)
|
||||
: ASTGEN_SUPER_Wait(fl) {
|
||||
this->condp(condp);
|
||||
this->addStmtsp(stmtsp);
|
||||
|
|
@ -3335,11 +3177,11 @@ public:
|
|||
};
|
||||
class AstWhile final : public AstNodeStmt {
|
||||
// @astgen op1 := precondsp : List[AstNode]
|
||||
// @astgen op2 := condp : AstNode
|
||||
// @astgen op2 := condp : AstNodeExpr
|
||||
// @astgen op3 := stmtsp : List[AstNode]
|
||||
// @astgen op4 := incsp : List[AstNode]
|
||||
public:
|
||||
AstWhile(FileLine* fl, AstNode* condp, AstNode* stmtsp = nullptr, AstNode* incsp = nullptr)
|
||||
AstWhile(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp = nullptr, AstNode* incsp = nullptr)
|
||||
: ASTGEN_SUPER_While(fl) {
|
||||
this->condp(condp);
|
||||
this->addStmtsp(stmtsp);
|
||||
|
|
@ -3355,43 +3197,17 @@ public:
|
|||
void addNextStmt(AstNode* newp, AstNode* belowp) override;
|
||||
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
||||
};
|
||||
class AstWith final : public AstNodeStmt {
|
||||
// Used as argument to method, then to AstCMethodHard
|
||||
// dtypep() contains the with lambda's return dtype
|
||||
// Parents: funcref (similar to AstArg)
|
||||
// Children: LambdaArgRef that declares the item variable
|
||||
// Children: LambdaArgRef that declares the item.index variable
|
||||
// Children: expression (equation establishing the with)
|
||||
// @astgen op1 := indexArgRefp : AstLambdaArgRef
|
||||
// @astgen op2 := valueArgRefp : AstLambdaArgRef
|
||||
// @astgen op3 := exprp : AstNode
|
||||
public:
|
||||
AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp,
|
||||
AstNode* exprp)
|
||||
: ASTGEN_SUPER_With(fl) {
|
||||
this->indexArgRefp(indexArgRefp);
|
||||
this->valueArgRefp(valueArgRefp);
|
||||
this->exprp(exprp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstWith;
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!indexArgRefp()); // varp needed to know lambda's arg dtype
|
||||
BROKEN_RTN(!valueArgRefp()); // varp needed to know lambda's arg dtype
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// === AstNodeAssign ===
|
||||
class AstAssign final : public AstNodeAssign {
|
||||
public:
|
||||
AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr)
|
||||
AstAssign(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
|
||||
AstNode* timingControlp = nullptr)
|
||||
: ASTGEN_SUPER_Assign(fl, lhsp, rhsp, timingControlp) {
|
||||
dtypeFrom(lhsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstAssign;
|
||||
AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr;
|
||||
return new AstAssign{fileline(), lhsp, rhsp, controlp};
|
||||
}
|
||||
|
|
@ -3402,17 +3218,20 @@ class AstAssignAlias final : public AstNodeAssign {
|
|||
// If both sides are wires, there's no LHS vs RHS,
|
||||
public:
|
||||
AstAssignAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp)
|
||||
: ASTGEN_SUPER_AssignAlias(fl, (AstNode*)lhsp, (AstNode*)rhsp) {}
|
||||
: ASTGEN_SUPER_AssignAlias(fl, (AstNodeExpr*)lhsp, (AstNodeExpr*)rhsp) {}
|
||||
ASTGEN_MEMBERS_AstAssignAlias;
|
||||
AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { V3ERROR_NA_RETURN(nullptr); }
|
||||
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
V3ERROR_NA_RETURN(nullptr);
|
||||
}
|
||||
bool brokeLhsMustBeLvalue() const override { return false; }
|
||||
};
|
||||
class AstAssignDly final : public AstNodeAssign {
|
||||
public:
|
||||
AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr)
|
||||
AstAssignDly(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
|
||||
AstNode* timingControlp = nullptr)
|
||||
: ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp, timingControlp) {}
|
||||
ASTGEN_MEMBERS_AstAssignDly;
|
||||
AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr;
|
||||
return new AstAssignDly{fileline(), lhsp, rhsp, controlp};
|
||||
}
|
||||
|
|
@ -3423,10 +3242,10 @@ public:
|
|||
class AstAssignForce final : public AstNodeAssign {
|
||||
// Procedural 'force' statement
|
||||
public:
|
||||
AstAssignForce(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
AstAssignForce(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_AssignForce(fl, lhsp, rhsp) {}
|
||||
ASTGEN_MEMBERS_AstAssignForce;
|
||||
AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
return new AstAssignForce{fileline(), lhsp, rhsp};
|
||||
}
|
||||
bool brokeLhsMustBeLvalue() const override { return true; }
|
||||
|
|
@ -3434,10 +3253,10 @@ public:
|
|||
class AstAssignPost final : public AstNodeAssign {
|
||||
// Like Assign, but predelayed assignment requiring special order handling
|
||||
public:
|
||||
AstAssignPost(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
AstAssignPost(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_AssignPost(fl, lhsp, rhsp) {}
|
||||
ASTGEN_MEMBERS_AstAssignPost;
|
||||
AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
return new AstAssignPost{fileline(), lhsp, rhsp};
|
||||
}
|
||||
bool brokeLhsMustBeLvalue() const override { return true; }
|
||||
|
|
@ -3445,10 +3264,10 @@ public:
|
|||
class AstAssignPre final : public AstNodeAssign {
|
||||
// Like Assign, but predelayed assignment requiring special order handling
|
||||
public:
|
||||
AstAssignPre(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
AstAssignPre(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_AssignPre(fl, lhsp, rhsp) {}
|
||||
ASTGEN_MEMBERS_AstAssignPre;
|
||||
AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
return new AstAssignPre{fileline(), lhsp, rhsp};
|
||||
}
|
||||
bool brokeLhsMustBeLvalue() const override { return true; }
|
||||
|
|
@ -3456,12 +3275,12 @@ public:
|
|||
class AstAssignVarScope final : public AstNodeAssign {
|
||||
// Assign two VarScopes to each other
|
||||
public:
|
||||
AstAssignVarScope(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
AstAssignVarScope(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_AssignVarScope(fl, lhsp, rhsp) {
|
||||
dtypeFrom(rhsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstAssignVarScope;
|
||||
AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
return new AstAssignVarScope{fileline(), lhsp, rhsp};
|
||||
}
|
||||
bool brokeLhsMustBeLvalue() const override { return false; }
|
||||
|
|
@ -3470,10 +3289,11 @@ class AstAssignW final : public AstNodeAssign {
|
|||
// Like assign, but wire/assign's in verilog, the only setting of the specified variable
|
||||
// @astgen op4 := strengthSpecp : Optional[AstStrengthSpec]
|
||||
public:
|
||||
AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr)
|
||||
AstAssignW(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
|
||||
AstNode* timingControlp = nullptr)
|
||||
: ASTGEN_SUPER_AssignW(fl, lhsp, rhsp, timingControlp) {}
|
||||
ASTGEN_MEMBERS_AstAssignW;
|
||||
AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
AstNodeAssign* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr;
|
||||
return new AstAssignW{fileline(), lhsp, rhsp, controlp};
|
||||
}
|
||||
|
|
@ -3489,8 +3309,6 @@ public:
|
|||
// === AstNodeCase ===
|
||||
class AstCase final : public AstNodeCase {
|
||||
// Case statement
|
||||
// Parents: {statement list}
|
||||
private:
|
||||
VCaseType m_casex; // 0=case, 1=casex, 2=casez
|
||||
bool m_fullPragma = false; // Synthesis full_case
|
||||
bool m_parallelPragma = false; // Synthesis parallel_case
|
||||
|
|
@ -3498,7 +3316,7 @@ private:
|
|||
bool m_unique0Pragma = false; // unique0 case
|
||||
bool m_priorityPragma = false; // priority case
|
||||
public:
|
||||
AstCase(FileLine* fl, VCaseType casex, AstNode* exprp, AstCaseItem* itemsp)
|
||||
AstCase(FileLine* fl, VCaseType casex, AstNodeExpr* exprp, AstCaseItem* itemsp)
|
||||
: ASTGEN_SUPER_Case(fl, exprp, itemsp)
|
||||
, m_casex{casex} {}
|
||||
ASTGEN_MEMBERS_AstCase;
|
||||
|
|
@ -3524,9 +3342,8 @@ public:
|
|||
};
|
||||
class AstGenCase final : public AstNodeCase {
|
||||
// Generate Case statement
|
||||
// Parents: {statement list}
|
||||
public:
|
||||
AstGenCase(FileLine* fl, AstNode* exprp, AstCaseItem* itemsp)
|
||||
AstGenCase(FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp)
|
||||
: ASTGEN_SUPER_GenCase(fl, exprp, itemsp) {}
|
||||
ASTGEN_MEMBERS_AstGenCase;
|
||||
};
|
||||
|
|
@ -3572,7 +3389,7 @@ public:
|
|||
// === AstNodeFor ===
|
||||
class AstGenFor final : public AstNodeFor {
|
||||
public:
|
||||
AstGenFor(FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* stmtsp)
|
||||
AstGenFor(FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp, AstNode* stmtsp)
|
||||
: ASTGEN_SUPER_GenFor(fl, initsp, condp, incsp, stmtsp) {}
|
||||
ASTGEN_MEMBERS_AstGenFor;
|
||||
};
|
||||
|
|
@ -3580,7 +3397,7 @@ public:
|
|||
// === AstNodeIf ===
|
||||
class AstGenIf final : public AstNodeIf {
|
||||
public:
|
||||
AstGenIf(FileLine* fl, AstNode* condp, AstNode* thensp, AstNode* elsesp)
|
||||
AstGenIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
|
||||
: ASTGEN_SUPER_GenIf(fl, condp, thensp, elsesp) {}
|
||||
ASTGEN_MEMBERS_AstGenIf;
|
||||
};
|
||||
|
|
@ -3590,7 +3407,7 @@ private:
|
|||
bool m_unique0Pragma = false; // unique0 case
|
||||
bool m_priorityPragma = false; // priority case
|
||||
public:
|
||||
AstIf(FileLine* fl, AstNode* condp, AstNode* thensp = nullptr, AstNode* elsesp = nullptr)
|
||||
AstIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp = nullptr, AstNode* elsesp = nullptr)
|
||||
: ASTGEN_SUPER_If(fl, condp, thensp, elsesp) {}
|
||||
ASTGEN_MEMBERS_AstIf;
|
||||
bool uniquePragma() const { return m_uniquePragma; }
|
||||
|
|
@ -3604,8 +3421,8 @@ public:
|
|||
// === AstNodeReadWriteMem ===
|
||||
class AstReadMem final : public AstNodeReadWriteMem {
|
||||
public:
|
||||
AstReadMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp,
|
||||
AstNode* msbp)
|
||||
AstReadMem(FileLine* fl, bool hex, AstNodeExpr* filenamep, AstNodeExpr* memp,
|
||||
AstNodeExpr* lsbp, AstNodeExpr* msbp)
|
||||
: ASTGEN_SUPER_ReadMem(fl, hex, filenamep, memp, lsbp, msbp) {}
|
||||
ASTGEN_MEMBERS_AstReadMem;
|
||||
string verilogKwd() const override { return (isHex() ? "$readmemh" : "$readmemb"); }
|
||||
|
|
@ -3613,8 +3430,8 @@ public:
|
|||
};
|
||||
class AstWriteMem final : public AstNodeReadWriteMem {
|
||||
public:
|
||||
AstWriteMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp,
|
||||
AstNode* msbp)
|
||||
AstWriteMem(FileLine* fl, bool hex, AstNodeExpr* filenamep, AstNodeExpr* memp,
|
||||
AstNodeExpr* lsbp, AstNodeExpr* msbp)
|
||||
: ASTGEN_SUPER_WriteMem(fl, hex, filenamep, memp, lsbp, msbp) {}
|
||||
ASTGEN_MEMBERS_AstWriteMem;
|
||||
string verilogKwd() const override { return (isHex() ? "$writememh" : "$writememb"); }
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ int AstNodeUOrStructDType::widthAlignBytes() const {
|
|||
}
|
||||
}
|
||||
|
||||
AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
||||
AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) {
|
||||
if (lhsp->isString() && rhsp->isString()) {
|
||||
return new AstEqN(fl, lhsp, rhsp);
|
||||
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
||||
|
|
@ -262,7 +262,7 @@ AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
|||
}
|
||||
}
|
||||
|
||||
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
||||
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) {
|
||||
if (lhsp->isString() && rhsp->isString()) {
|
||||
return new AstEqN(fl, lhsp, rhsp);
|
||||
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
||||
|
|
@ -279,13 +279,13 @@ AstExecGraph::AstExecGraph(FileLine* fileline, const string& name)
|
|||
|
||||
AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); }
|
||||
|
||||
AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp) {
|
||||
AstNode* const ap = new AstGte(fileline(), exprp->cloneTree(true), lhsp);
|
||||
AstNode* const bp = new AstLte(fileline(), exprp->cloneTree(true), rhsp);
|
||||
AstNodeExpr* AstInsideRange::newAndFromInside(AstNodeExpr* exprp, AstNodeExpr* lhsp,
|
||||
AstNodeExpr* rhsp) {
|
||||
AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTree(true), lhsp};
|
||||
AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTree(true), rhsp};
|
||||
ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true);
|
||||
bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true);
|
||||
AstNode* const newp = new AstAnd(fileline(), ap, bp);
|
||||
return newp;
|
||||
return new AstAnd(fileline(), ap, bp);
|
||||
}
|
||||
|
||||
AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
|
||||
|
|
@ -1122,7 +1122,7 @@ const char* AstConstPool::broken() const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) {
|
||||
AstVarScope* AstConstPool::createNewEntry(const string& name, AstNodeExpr* initp) {
|
||||
FileLine* const fl = initp->fileline();
|
||||
AstVar* const varp = new AstVar(fl, VVarType::MODULETEMP, name, initp->dtypep());
|
||||
varp->isConst(true);
|
||||
|
|
@ -1575,7 +1575,7 @@ void AstInitArray::cloneRelink() {
|
|||
if (it->second->clonep()) it->second = it->second->clonep();
|
||||
}
|
||||
}
|
||||
void AstInitArray::addIndexValuep(uint64_t index, AstNode* newp) {
|
||||
void AstInitArray::addIndexValuep(uint64_t index, AstNodeExpr* newp) {
|
||||
const auto it = m_map.find(index);
|
||||
if (it != m_map.end()) {
|
||||
it->second->valuep(newp);
|
||||
|
|
@ -1585,7 +1585,7 @@ void AstInitArray::addIndexValuep(uint64_t index, AstNode* newp) {
|
|||
addInitsp(itemp);
|
||||
}
|
||||
}
|
||||
AstNode* AstInitArray::getIndexValuep(uint64_t index) const {
|
||||
AstNodeExpr* AstInitArray::getIndexValuep(uint64_t index) const {
|
||||
const auto it = m_map.find(index);
|
||||
if (it == m_map.end()) {
|
||||
return nullptr;
|
||||
|
|
@ -1593,8 +1593,8 @@ AstNode* AstInitArray::getIndexValuep(uint64_t index) const {
|
|||
return it->second->valuep();
|
||||
}
|
||||
}
|
||||
AstNode* AstInitArray::getIndexDefaultedValuep(uint64_t index) const {
|
||||
AstNode* valuep = getIndexValuep(index);
|
||||
AstNodeExpr* AstInitArray::getIndexDefaultedValuep(uint64_t index) const {
|
||||
AstNodeExpr* valuep = getIndexValuep(index);
|
||||
if (!valuep) valuep = defaultp();
|
||||
return valuep;
|
||||
}
|
||||
|
|
@ -2302,8 +2302,8 @@ void AstCUse::dump(std::ostream& str) const {
|
|||
|
||||
AstAlways* AstAssignW::convertToAlways() {
|
||||
const bool hasTimingControl = isTimingControl();
|
||||
AstNode* const lhs1p = lhsp()->unlinkFrBack();
|
||||
AstNode* const rhs1p = rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lhs1p = lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhs1p = rhsp()->unlinkFrBack();
|
||||
AstNode* const controlp = timingControlp() ? timingControlp()->unlinkFrBack() : nullptr;
|
||||
FileLine* const flp = fileline();
|
||||
AstNode* bodysp = new AstAssign{flp, lhs1p, rhs1p, controlp};
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ void V3CCtors::evalAsserts() {
|
|||
AstVarRef* const vrefp
|
||||
= new AstVarRef{varp->fileline(), varp, VAccess::READ};
|
||||
vrefp->selfPointer("this");
|
||||
AstNode* newp = vrefp;
|
||||
AstNodeExpr* newp = vrefp;
|
||||
if (varp->isWide()) {
|
||||
newp = new AstWordSel{
|
||||
varp->fileline(), newp,
|
||||
|
|
@ -167,8 +167,7 @@ void V3CCtors::evalAsserts() {
|
|||
new AstCStmt{varp->fileline(), "Verilated::overWidthError(\""
|
||||
+ varp->prettyName() + "\");"}};
|
||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
newp = ifp;
|
||||
funcp->addStmtsp(newp);
|
||||
funcp->addStmtsp(ifp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ private:
|
|||
return true; // All is fine
|
||||
}
|
||||
|
||||
AstNode* replaceCaseFastRecurse(AstNode* cexprp, int msb, uint32_t upperValue) {
|
||||
AstNode* replaceCaseFastRecurse(AstNodeExpr* cexprp, int msb, uint32_t upperValue) {
|
||||
if (msb < 0) {
|
||||
// There's no space for a IF. We know upperValue is thus down to a specific
|
||||
// exact value, so just return the tree value
|
||||
|
|
@ -290,9 +290,9 @@ private:
|
|||
// V3Number nummask (cexprp, cexprp->width(), (1UL<<msb));
|
||||
// AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
|
||||
// new AstConst(cexprp->fileline(), nummask));
|
||||
AstNode* const and1p
|
||||
AstNodeExpr* const and1p
|
||||
= new AstSel(cexprp->fileline(), cexprp->cloneTree(false), msb, 1);
|
||||
AstNode* const eqp
|
||||
AstNodeExpr* const eqp
|
||||
= new AstNeq(cexprp->fileline(), new AstConst(cexprp->fileline(), 0), and1p);
|
||||
AstIf* const ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
|
||||
ifp->user3(1); // So we don't bother to clone it
|
||||
|
|
@ -304,7 +304,7 @@ private:
|
|||
// CASEx(cexpr,....
|
||||
// -> tree of IF(msb, IF(msb-1, 11, 10)
|
||||
// IF(msb-1, 01, 00))
|
||||
AstNode* const cexprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* const cexprp = nodep->exprp()->unlinkFrBack();
|
||||
|
||||
if (debug() >= 9) { // LCOV_EXCL_START
|
||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
|
||||
|
|
@ -337,7 +337,7 @@ private:
|
|||
// -> IF((cexpr==icond1),istmts1,
|
||||
// IF((EQ (AND MASK cexpr) (AND MASK icond1)
|
||||
// ,istmts2, istmts3
|
||||
AstNode* const cexprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* const cexprp = nodep->exprp()->unlinkFrBack();
|
||||
// We'll do this in two stages. First stage, convert the conditions to
|
||||
// the appropriate IF AND terms.
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " _comp_IN: ");
|
||||
|
|
@ -350,13 +350,13 @@ private:
|
|||
hadDefault = true;
|
||||
} else {
|
||||
// Expressioned clause
|
||||
AstNode* icondNextp = nullptr;
|
||||
AstNode* ifexprp = nullptr; // If expression to test
|
||||
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondNextp) {
|
||||
icondNextp = icondp->nextp();
|
||||
AstNodeExpr* icondNextp = nullptr;
|
||||
AstNodeExpr* ifexprp = nullptr; // If expression to test
|
||||
for (AstNodeExpr* icondp = itemp->condsp(); icondp; icondp = icondNextp) {
|
||||
icondNextp = VN_AS(icondp->nextp(), NodeExpr);
|
||||
icondp->unlinkFrBack();
|
||||
|
||||
AstNode* condp = nullptr; // Default is to use and1p/and2p
|
||||
AstNodeExpr* condp = nullptr; // Default is to use and1p/and2p
|
||||
AstConst* const iconstp = VN_CAST(icondp, Const);
|
||||
if (iconstp && neverItem(nodep, iconstp)) {
|
||||
// X in casez can't ever be executed
|
||||
|
|
@ -375,10 +375,10 @@ private:
|
|||
nummask.opBitsNonX(iconstp->num());
|
||||
V3Number numval(itemp, iconstp->width());
|
||||
numval.opBitsOne(iconstp->num());
|
||||
AstNode* const and1p
|
||||
AstNodeExpr* const and1p
|
||||
= new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
AstNode* const and2p = new AstAnd(
|
||||
AstNodeExpr* const and2p = new AstAnd(
|
||||
itemp->fileline(), new AstConst(itemp->fileline(), numval),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
VL_DO_DANGLING(icondp->deleteTree(), icondp);
|
||||
|
|
@ -386,8 +386,8 @@ private:
|
|||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
} else {
|
||||
// Not a caseX mask, we can build CASEEQ(cexpr icond)
|
||||
AstNode* const and1p = cexprp->cloneTree(false);
|
||||
AstNode* const and2p = icondp;
|
||||
AstNodeExpr* const and1p = cexprp->cloneTree(false);
|
||||
AstNodeExpr* const and2p = icondp;
|
||||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
}
|
||||
if (!ifexprp) {
|
||||
|
|
@ -423,7 +423,7 @@ private:
|
|||
AstNode* const istmtsp = itemp->stmtsp(); // Maybe null -- no action.
|
||||
if (istmtsp) istmtsp->unlinkFrBackWithNext();
|
||||
// Expressioned clause
|
||||
AstNode* const ifexprp = itemp->condsp()->unlinkFrBack();
|
||||
AstNodeExpr* const ifexprp = itemp->condsp()->unlinkFrBack();
|
||||
{ // Prepare for next group
|
||||
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
|
||||
if (depth == 1) { // First group or starting new group
|
||||
|
|
@ -436,13 +436,13 @@ private:
|
|||
}
|
||||
groupnextp = newp;
|
||||
} else { // Continue group, modify if condition to OR in this new condition
|
||||
AstNode* const condp = groupnextp->condp()->unlinkFrBack();
|
||||
AstNodeExpr* const condp = groupnextp->condp()->unlinkFrBack();
|
||||
groupnextp->condp(
|
||||
new AstOr(ifexprp->fileline(), condp, ifexprp->cloneTree(true)));
|
||||
}
|
||||
}
|
||||
{ // Make the new lower IF and attach in the tree
|
||||
AstNode* itemexprp = ifexprp;
|
||||
AstNodeExpr* itemexprp = ifexprp;
|
||||
VL_DANGLING(ifexprp);
|
||||
if (depth == CASE_ENCODER_GROUP_DEPTH) { // End of group - can skip the condition
|
||||
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ private:
|
|||
|
||||
// METHODS
|
||||
|
||||
void insertCast(AstNode* nodep, int needsize) { // We'll insert ABOVE passed node
|
||||
void insertCast(AstNodeExpr* nodep, int needsize) { // We'll insert ABOVE passed node
|
||||
UINFO(4, " NeedCast " << nodep << endl);
|
||||
VNRelinker relinkHandle;
|
||||
nodep->unlinkFrBack(&relinkHandle);
|
||||
|
|
@ -87,7 +87,7 @@ private:
|
|||
return VL_IDATASIZE;
|
||||
}
|
||||
}
|
||||
void ensureCast(AstNode* nodep) {
|
||||
void ensureCast(AstNodeExpr* nodep) {
|
||||
if (castSize(nodep->backp()) != castSize(nodep) || !nodep->user1()) {
|
||||
insertCast(nodep, castSize(nodep->backp()));
|
||||
}
|
||||
|
|
@ -101,13 +101,12 @@ private:
|
|||
insertCast(nodep->lhsp(), VL_IDATASIZE);
|
||||
}
|
||||
}
|
||||
void ensureNullChecked(AstNode* nodep) {
|
||||
void ensureNullChecked(AstNodeExpr* nodep) {
|
||||
// TODO optimize to track null checked values and avoid where possible
|
||||
if (!VN_IS(nodep->backp(), NullCheck)) {
|
||||
VNRelinker relinkHandle;
|
||||
nodep->unlinkFrBack(&relinkHandle);
|
||||
AstNode* const newp = new AstNullCheck{nodep->fileline(), nodep};
|
||||
relinkHandle.relink(newp);
|
||||
relinkHandle.relink(new AstNullCheck{nodep->fileline(), nodep});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ private:
|
|||
}
|
||||
|
||||
// Operate on nodes
|
||||
void insertClean(AstNode* nodep) { // We'll insert ABOVE passed node
|
||||
void insertClean(AstNodeExpr* nodep) { // We'll insert ABOVE passed node
|
||||
UINFO(4, " NeedClean " << nodep << endl);
|
||||
VNRelinker relinkHandle;
|
||||
nodep->unlinkFrBack(&relinkHandle);
|
||||
|
|
@ -134,14 +134,14 @@ private:
|
|||
cleanp->dtypeFrom(nodep); // Otherwise the AND normally picks LHS
|
||||
relinkHandle.relink(cleanp);
|
||||
}
|
||||
void ensureClean(AstNode* nodep) {
|
||||
void ensureClean(AstNodeExpr* nodep) {
|
||||
computeCppWidth(nodep);
|
||||
if (!isClean(nodep)) insertClean(nodep);
|
||||
}
|
||||
void ensureCleanAndNext(AstNode* nodep) {
|
||||
void ensureCleanAndNext(AstNodeExpr* nodep) {
|
||||
// Editing list, careful looping!
|
||||
for (AstNode* exprp = nodep; exprp;) {
|
||||
AstNode* const nextp = exprp->nextp();
|
||||
for (AstNodeExpr* exprp = nodep; exprp;) {
|
||||
AstNodeExpr* const nextp = VN_AS(exprp->nextp(), NodeExpr);
|
||||
ensureClean(exprp);
|
||||
exprp = nextp;
|
||||
}
|
||||
|
|
@ -237,7 +237,9 @@ private:
|
|||
setClean(nodep, false);
|
||||
// We always clean, as we don't trust those pesky users.
|
||||
if (!VN_IS(nodep->backp(), And)) insertClean(nodep);
|
||||
ensureCleanAndNext(nodep->exprsp());
|
||||
for (AstNode* argp = nodep->exprsp(); argp; argp = argp->nextp()) {
|
||||
if (AstNodeExpr* const exprp = VN_CAST(argp, NodeExpr)) ensureClean(exprp);
|
||||
}
|
||||
}
|
||||
void visit(AstTraceDecl* nodep) override {
|
||||
// No cleaning, or would loose pointer to enum
|
||||
|
|
@ -277,7 +279,9 @@ private:
|
|||
}
|
||||
void visit(AstUCStmt* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
ensureCleanAndNext(nodep->exprsp());
|
||||
for (AstNode* argp = nodep->exprsp(); argp; argp = argp->nextp()) {
|
||||
if (AstNodeExpr* const exprp = VN_CAST(argp, NodeExpr)) ensureClean(exprp);
|
||||
}
|
||||
}
|
||||
void visit(AstNodeCCall* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
|
|
|
|||
|
|
@ -46,11 +46,11 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
class ConvertWriteRefsToRead final : public VNVisitor {
|
||||
private:
|
||||
// MEMBERS
|
||||
AstNode* m_result = nullptr;
|
||||
AstNodeExpr* m_result = nullptr;
|
||||
|
||||
// CONSTRUCTORS
|
||||
explicit ConvertWriteRefsToRead(AstNode* nodep) {
|
||||
m_result = iterateSubtreeReturnEdits(nodep);
|
||||
explicit ConvertWriteRefsToRead(AstNodeExpr* nodep) {
|
||||
m_result = VN_AS(iterateSubtreeReturnEdits(nodep), NodeExpr);
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
|
|
@ -65,7 +65,7 @@ private:
|
|||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
static AstNode* main(AstNode* nodep) { return ConvertWriteRefsToRead(nodep).m_result; }
|
||||
static AstNodeExpr* main(AstNodeExpr* nodep) { return ConvertWriteRefsToRead(nodep).m_result; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
@ -82,11 +82,11 @@ private:
|
|||
|
||||
// METHODS
|
||||
|
||||
AstNode* createSenseEquation(AstSenItem* nodesp) {
|
||||
AstNode* senEqnp = nullptr;
|
||||
AstNodeExpr* createSenseEquation(AstSenItem* nodesp) {
|
||||
AstNodeExpr* senEqnp = nullptr;
|
||||
for (AstSenItem* senp = nodesp; senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
||||
UASSERT_OBJ(senp->edgeType() == VEdgeType::ET_TRUE, senp, "Should have been lowered");
|
||||
AstNode* const senOnep = senp->sensp()->cloneTree(false);
|
||||
AstNodeExpr* const senOnep = senp->sensp()->cloneTree(false);
|
||||
senEqnp = senEqnp ? new AstOr{senp->fileline(), senEqnp, senOnep} : senOnep;
|
||||
}
|
||||
return senEqnp;
|
||||
|
|
@ -111,7 +111,7 @@ private:
|
|||
return newvscp;
|
||||
}
|
||||
AstIf* makeActiveIf(AstSenTree* sensesp) {
|
||||
AstNode* const senEqnp = createSenseEquation(sensesp->sensesp());
|
||||
AstNodeExpr* const senEqnp = createSenseEquation(sensesp->sensesp());
|
||||
UASSERT_OBJ(senEqnp, sensesp, "No sense equation, shouldn't be in sequent activation.");
|
||||
AstIf* const newifp = new AstIf{sensesp->fileline(), senEqnp};
|
||||
return newifp;
|
||||
|
|
@ -126,9 +126,9 @@ private:
|
|||
// COVERTOGGLE(INC, ORIG, CHANGE) ->
|
||||
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
|
||||
AstNode* const incp = nodep->incp()->unlinkFrBack();
|
||||
AstNode* const origp = nodep->origp()->unlinkFrBack();
|
||||
AstNode* const changeWrp = nodep->changep()->unlinkFrBack();
|
||||
AstNode* const changeRdp = ConvertWriteRefsToRead::main(changeWrp->cloneTree(false));
|
||||
AstNodeExpr* const origp = nodep->origp()->unlinkFrBack();
|
||||
AstNodeExpr* const changeWrp = nodep->changep()->unlinkFrBack();
|
||||
AstNodeExpr* const changeRdp = ConvertWriteRefsToRead::main(changeWrp->cloneTree(false));
|
||||
AstIf* const newp
|
||||
= new AstIf{nodep->fileline(), new AstXor{nodep->fileline(), origp, changeRdp}, incp};
|
||||
// We could add another IF to detect posedges, and only increment if so.
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ static void makeVlToString(AstClass* nodep) {
|
|||
funcp->isConst(false);
|
||||
funcp->isStatic(false);
|
||||
funcp->protect(false);
|
||||
AstNode* const exprp = new AstCExpr{nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0};
|
||||
AstNodeExpr* 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 +56,7 @@ static void makeVlToString(AstIface* nodep) {
|
|||
funcp->isConst(false);
|
||||
funcp->isStatic(false);
|
||||
funcp->protect(false);
|
||||
AstNode* const exprp = new AstCExpr{nodep->fileline(), "obj ? obj->name() : \"null\"", 0};
|
||||
AstNodeExpr* const exprp = new AstCExpr{nodep->fileline(), "obj ? obj->name() : \"null\"", 0};
|
||||
exprp->dtypeSetString();
|
||||
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
|
||||
nodep->addStmtsp(funcp);
|
||||
|
|
@ -65,7 +66,7 @@ static void makeToString(AstClass* nodep) {
|
|||
funcp->isConst(true);
|
||||
funcp->isStatic(false);
|
||||
funcp->protect(false);
|
||||
AstNode* const exprp
|
||||
AstCExpr* const exprp
|
||||
= new AstCExpr{nodep->fileline(), R"(std::string{"'{"} + to_string_middle() + "}")", 0};
|
||||
exprp->dtypeSetString();
|
||||
funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp});
|
||||
|
|
|
|||
370
src/V3Const.cpp
370
src/V3Const.cpp
|
|
@ -80,7 +80,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
|
||||
// Holds a node to be added as a term in the reduction tree, it's equivalent op count, and a
|
||||
// bool indicating if the term is clean (0/1 value, or if the top bits might be dirty)
|
||||
using ResultTerm = std::tuple<AstNode*, unsigned, bool>;
|
||||
using ResultTerm = std::tuple<AstNodeExpr*, unsigned, bool>;
|
||||
|
||||
class LeafInfo final { // Leaf node (either AstConst or AstVarRef)
|
||||
// MEMBERS
|
||||
|
|
@ -243,7 +243,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
FileLine* const fl = m_refp->fileline();
|
||||
|
||||
// Get the term we are referencing (the WordSel, if wide, otherwise just the VarRef)
|
||||
AstNode* srcp = VN_CAST(m_refp->backp(), WordSel);
|
||||
AstNodeExpr* srcp = VN_CAST(m_refp->backp(), WordSel);
|
||||
if (!srcp) srcp = m_refp;
|
||||
srcp = srcp->cloneTree(false);
|
||||
|
||||
|
|
@ -260,7 +260,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
UASSERT(maskVal != 0, "Should have been recognized as having const 0 result");
|
||||
|
||||
// Parts of the return value
|
||||
AstNode* resultp = srcp; // The tree for this term
|
||||
AstNodeExpr* resultp = srcp; // The tree for this term
|
||||
unsigned ops = 0; // Number of ops in this term
|
||||
bool clean = false; // Whether the term is clean (has value 0 or 1)
|
||||
|
||||
|
|
@ -344,9 +344,9 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
unsigned m_ops; // Number of operations such as And, Or, Xor, Sel...
|
||||
int m_lsb = 0; // Current LSB
|
||||
LeafInfo* m_leafp = nullptr; // AstConst or AstVarRef that currently looking for
|
||||
const AstNode* const m_rootp; // Root of this AST subtree
|
||||
const AstNodeExpr* const m_rootp; // Root of this AST subtree
|
||||
|
||||
std::vector<std::pair<AstNode*, FrozenNodeInfo>>
|
||||
std::vector<std::pair<AstNodeExpr*, FrozenNodeInfo>>
|
||||
m_frozenNodes; // Nodes that cannot be optimized
|
||||
std::vector<BitPolarityEntry> m_bitPolarities; // Polarity of bits found during iterate()
|
||||
std::vector<std::unique_ptr<VarInfo>> m_varInfos; // VarInfo for each variable, [0] is nullptr
|
||||
|
|
@ -529,7 +529,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
Restorer restorer{*this};
|
||||
LeafInfo leafInfo{m_lsb};
|
||||
m_leafp = &leafInfo;
|
||||
AstNode* opp = right ? nodep->rhsp() : nodep->lhsp();
|
||||
AstNodeExpr* opp = right ? nodep->rhsp() : nodep->lhsp();
|
||||
const bool origFailed = m_failed;
|
||||
iterate(opp);
|
||||
if (leafInfo.constp() || m_failed) {
|
||||
|
|
@ -625,7 +625,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
// CONSTRUCTORS
|
||||
ConstBitOpTreeVisitor(AstNode* nodep, unsigned externalOps)
|
||||
ConstBitOpTreeVisitor(AstNodeExpr* nodep, unsigned externalOps)
|
||||
: m_ops{externalOps}
|
||||
, m_rootp{nodep} {
|
||||
// Fill nullptr at [0] because AstVarScope::user4 is 0 by default
|
||||
|
|
@ -656,8 +656,8 @@ public:
|
|||
// (3'b000 != (3'b011 & v)) | v[2] => 3'b000 != (3'b111 & v)
|
||||
// Reduction ops are transformed in the same way.
|
||||
// &{v[0], v[1]} => 2'b11 == (2'b11 & v)
|
||||
static AstNode* simplify(AstNode* nodep, int resultWidth, unsigned externalOps,
|
||||
VDouble0& reduction) {
|
||||
static AstNodeExpr* simplify(AstNodeExpr* nodep, int resultWidth, unsigned externalOps,
|
||||
VDouble0& reduction) {
|
||||
UASSERT_OBJ(1 <= resultWidth && resultWidth <= 64, nodep, "resultWidth out of range");
|
||||
|
||||
// Walk tree, gathering all terms referenced in expression
|
||||
|
|
@ -673,7 +673,7 @@ public:
|
|||
// whether we have clean/dirty terms. visitor.m_varInfos appears in deterministic order,
|
||||
// so the optimized tree is deterministic as well.
|
||||
|
||||
std::vector<AstNode*> termps;
|
||||
std::vector<AstNodeExpr*> termps;
|
||||
termps.reserve(visitor.m_varInfos.size() - 1);
|
||||
unsigned resultOps = 0;
|
||||
bool hasCleanTerm = false;
|
||||
|
|
@ -683,7 +683,7 @@ public:
|
|||
if (!v) continue; // Skip nullptr at m_varInfos[0]
|
||||
if (v->hasConstResult()) {
|
||||
// If a constant term is known, we can either drop it or the whole tree is constant
|
||||
AstNode* resultp = nullptr;
|
||||
AstNodeExpr* resultp = nullptr;
|
||||
if (v->getConstResult()) {
|
||||
UASSERT_OBJ(visitor.isOrTree(), nodep,
|
||||
"Only OR tree can yield known 1 result");
|
||||
|
|
@ -715,10 +715,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
std::map<FrozenNodeInfo, std::vector<AstNode*>> frozenNodes; // Group by FrozenNodeInfo
|
||||
// Group by FrozenNodeInfo
|
||||
std::map<FrozenNodeInfo, std::vector<AstNodeExpr*>> frozenNodes;
|
||||
// Check if frozen terms are clean or not
|
||||
for (const auto& frozenInfo : visitor.m_frozenNodes) {
|
||||
AstNode* const termp = frozenInfo.first;
|
||||
AstNodeExpr* const termp = frozenInfo.first;
|
||||
// Comparison operators are clean
|
||||
if ((VN_IS(termp, Eq) || VN_IS(termp, Neq) || VN_IS(termp, Lt) || VN_IS(termp, Lte)
|
||||
|| VN_IS(termp, Gt) || VN_IS(termp, Gte))
|
||||
|
|
@ -752,8 +753,8 @@ public:
|
|||
|
||||
if (debug() >= 9) { // LCOV_EXCL_START
|
||||
cout << "Bitop tree considered: " << endl;
|
||||
for (AstNode* const termp : termps) termp->dumpTree("Reduced term: ");
|
||||
for (const std::pair<AstNode*, FrozenNodeInfo>& termp : visitor.m_frozenNodes) {
|
||||
for (AstNodeExpr* const termp : termps) termp->dumpTree("Reduced term: ");
|
||||
for (const std::pair<AstNodeExpr*, FrozenNodeInfo>& termp : visitor.m_frozenNodes) {
|
||||
termp.first->dumpTree("Frozen term with lsb " + std::to_string(termp.second.m_lsb)
|
||||
+ " polarity " + std::to_string(termp.second.m_polarity)
|
||||
+ ": ");
|
||||
|
|
@ -767,8 +768,8 @@ public:
|
|||
// (all of which were zeroes)
|
||||
if (termps.empty() && visitor.m_frozenNodes.empty()) {
|
||||
reduction += visitor.m_ops;
|
||||
AstNode* const resultp = needsFlip ? new AstConst{fl, AstConst::BitTrue{}}
|
||||
: new AstConst{fl, AstConst::BitFalse{}};
|
||||
AstNodeExpr* const resultp = needsFlip ? new AstConst{fl, AstConst::BitTrue{}}
|
||||
: new AstConst{fl, AstConst::BitFalse{}};
|
||||
resultp->dtypeChgWidth(resultWidth, 1);
|
||||
return resultp;
|
||||
}
|
||||
|
|
@ -783,7 +784,7 @@ public:
|
|||
reduction += visitor.m_ops - resultOps;
|
||||
|
||||
// Reduction op to combine terms
|
||||
const auto reduce = [&visitor, fl](AstNode* lhsp, AstNode* rhsp) -> AstNode* {
|
||||
const auto reduce = [&visitor, fl](AstNodeExpr* lhsp, AstNodeExpr* rhsp) -> AstNodeExpr* {
|
||||
if (!lhsp) return rhsp;
|
||||
if (visitor.isAndTree()) {
|
||||
return new AstAnd{fl, lhsp, rhsp};
|
||||
|
|
@ -795,15 +796,15 @@ public:
|
|||
};
|
||||
|
||||
// Compute result by reducing all terms
|
||||
AstNode* resultp = nullptr;
|
||||
for (AstNode* const termp : termps) { //
|
||||
AstNodeExpr* resultp = nullptr;
|
||||
for (AstNodeExpr* const termp : termps) { //
|
||||
resultp = reduce(resultp, termp);
|
||||
}
|
||||
// Add any frozen terms to the reduction
|
||||
for (auto&& nodes : frozenNodes) {
|
||||
// nodes.second has same lsb and polarity
|
||||
AstNode* termp = nullptr;
|
||||
for (AstNode* const itemp : nodes.second) {
|
||||
AstNodeExpr* termp = nullptr;
|
||||
for (AstNodeExpr* const itemp : nodes.second) {
|
||||
termp = reduce(termp, itemp->unlinkFrBack());
|
||||
}
|
||||
if (nodes.first.m_lsb > 0) { // LSB is not 0, so shiftR
|
||||
|
|
@ -961,7 +962,7 @@ private:
|
|||
// When bool is casted to int, the value is either 0 or 1
|
||||
AstConst* const constp = VN_AS(andp->lhsp(), Const);
|
||||
UASSERT_OBJ(constp && constp->isOne(), andp->lhsp(), "TRREEOPC must meet this condition");
|
||||
AstNode* const rhsp = andp->rhsp();
|
||||
AstNodeExpr* const rhsp = andp->rhsp();
|
||||
AstCCast* ccastp = nullptr;
|
||||
const auto isEqOrNeq
|
||||
= [](AstNode* nodep) -> bool { return VN_IS(nodep, Eq) || VN_IS(nodep, Neq); };
|
||||
|
|
@ -999,7 +1000,7 @@ private:
|
|||
// Someday we'll sort the biops completely and this can be simplified
|
||||
// This often results from our simplified clock generation:
|
||||
// if (rst) ... else if (enable)... -> OR(rst,AND(!rst,enable))
|
||||
AstNode* ap;
|
||||
AstNodeExpr* ap;
|
||||
AstNodeBiop* andp;
|
||||
if (VN_IS(nodep->lhsp(), And)) {
|
||||
andp = VN_AS(nodep->lhsp(), And);
|
||||
|
|
@ -1011,7 +1012,7 @@ private:
|
|||
return false;
|
||||
}
|
||||
const AstNodeUniop* notp;
|
||||
AstNode* cp;
|
||||
AstNodeExpr* cp;
|
||||
if (VN_IS(andp->lhsp(), Not)) {
|
||||
notp = VN_AS(andp->lhsp(), Not);
|
||||
cp = andp->rhsp();
|
||||
|
|
@ -1021,7 +1022,7 @@ private:
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
AstNode* const bp = notp->lhsp();
|
||||
AstNodeExpr* const bp = notp->lhsp();
|
||||
if (!operandsSame(ap, bp)) return false;
|
||||
// Do it
|
||||
cp->unlinkFrBack();
|
||||
|
|
@ -1140,7 +1141,7 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool matchBitOpTree(AstNode* nodep) {
|
||||
bool matchBitOpTree(AstNodeExpr* nodep) {
|
||||
if (nodep->widthMin() != 1) return false;
|
||||
if (!v3Global.opt.fConstBitOpTree()) return false;
|
||||
|
||||
|
|
@ -1277,8 +1278,8 @@ private:
|
|||
&& nodep->lsbConst() == 0))
|
||||
return false;
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "SEL(BI)-in:");
|
||||
AstNode* const bilhsp = bip->lhsp()->unlinkFrBack();
|
||||
AstNode* const birhsp = bip->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const bilhsp = bip->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const birhsp = bip->rhsp()->unlinkFrBack();
|
||||
bip->lhsp(new AstSel(nodep->fileline(), bilhsp, 0, nodep->widthConst()));
|
||||
bip->rhsp(new AstSel(nodep->fileline(), birhsp, 0, nodep->widthConst()));
|
||||
if (debug() >= 9) bip->dumpTree(cout, "SEL(BI)-ou:");
|
||||
|
|
@ -1294,7 +1295,7 @@ private:
|
|||
&& VN_IS(nodep->widthp(), Const))) {
|
||||
return false;
|
||||
}
|
||||
AstNode* const ap = shiftp->lhsp();
|
||||
AstNodeExpr* const ap = shiftp->lhsp();
|
||||
AstConst* const bp = VN_AS(shiftp->rhsp(), Const);
|
||||
AstConst* const lp = VN_AS(nodep->lsbp(), Const);
|
||||
if (bp->isWide() || bp->num().isFourState() || bp->num().isNegative() || lp->isWide()
|
||||
|
|
@ -1321,7 +1322,7 @@ private:
|
|||
// would be incorrect. See also operandBiExtendConst
|
||||
AstExtend* const extendp = VN_CAST(nodep->rhsp(), Extend);
|
||||
if (!extendp) return false;
|
||||
AstNode* const smallerp = extendp->lhsp();
|
||||
AstNodeExpr* const smallerp = extendp->lhsp();
|
||||
const int subsize = smallerp->width();
|
||||
AstConst* const constp = VN_CAST(nodep->lhsp(), Const);
|
||||
if (!constp) return false;
|
||||
|
|
@ -1477,7 +1478,7 @@ private:
|
|||
const int rend = (rstart->toSInt() + rwidth->toSInt());
|
||||
return (rend == lstart->toSInt());
|
||||
}
|
||||
bool ifMergeAdjacent(AstNode* lhsp, AstNode* rhsp) {
|
||||
bool ifMergeAdjacent(AstNodeExpr* lhsp, AstNodeExpr* rhsp) {
|
||||
// called by concatmergeable to determine if {lhsp, rhsp} make sense
|
||||
if (!v3Global.opt.fAssemble()) return false; // opt disabled
|
||||
// two same varref
|
||||
|
|
@ -1514,7 +1515,7 @@ private:
|
|||
if (rend == rfromp->width() && lstart->toSInt() == 0) return true;
|
||||
return false;
|
||||
}
|
||||
bool concatMergeable(const AstNode* lhsp, const AstNode* rhsp, unsigned depth) {
|
||||
bool concatMergeable(const AstNodeExpr* lhsp, const AstNodeExpr* rhsp, unsigned depth) {
|
||||
// determine if {a OP b, c OP d} => {a, c} OP {b, d} is advantageous
|
||||
if (!v3Global.opt.fAssemble()) return false; // opt disabled
|
||||
if (lhsp->type() != rhsp->type()) return false;
|
||||
|
|
@ -1575,7 +1576,7 @@ private:
|
|||
VL_DO_DANGLING(replaceNum(nodep, val), nodep);
|
||||
}
|
||||
void replaceZero(AstNode* nodep) { VL_DO_DANGLING(replaceNum(nodep, 0), nodep); }
|
||||
void replaceZeroChkPure(AstNode* nodep, AstNode* checkp) {
|
||||
void replaceZeroChkPure(AstNode* nodep, AstNodeExpr* checkp) {
|
||||
// For example, "0 * n" -> 0 if n has no side effects
|
||||
// Else strength reduce it to 0 & n.
|
||||
// If ever change the operation note AstAnd rule specially ignores this created pattern
|
||||
|
|
@ -1637,7 +1638,7 @@ private:
|
|||
// Replacement functions.
|
||||
// These all take a node and replace it with something else
|
||||
|
||||
void replaceWChild(AstNode* nodep, AstNode* childp) {
|
||||
void replaceWChild(AstNode* nodep, AstNodeExpr* childp) {
|
||||
// NODE(..., CHILD(...)) -> CHILD(...)
|
||||
childp->unlinkFrBackWithNext();
|
||||
// If replacing a SEL for example, the data type comes from the parent (is less wide).
|
||||
|
|
@ -1646,7 +1647,7 @@ private:
|
|||
nodep->replaceWith(childp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void replaceWChildBool(AstNode* nodep, AstNode* childp) {
|
||||
void replaceWChildBool(AstNode* nodep, AstNodeExpr* childp) {
|
||||
// NODE(..., CHILD(...)) -> REDOR(CHILD(...))
|
||||
childp->unlinkFrBack();
|
||||
if (childp->width1()) {
|
||||
|
|
@ -1688,10 +1689,10 @@ private:
|
|||
// BIASV(CONSTa, BIASV(CONSTb, c)) -> BIASV( BIASV_CONSTED(a,b), c)
|
||||
// BIASV(SAMEa, BIASV(SAMEb, c)) -> BIASV( BIASV(SAMEa,SAMEb), c)
|
||||
// nodep->dumpTree(cout, " repAsvConst_old: ");
|
||||
AstNode* const ap = nodep->lhsp();
|
||||
AstNodeExpr* const ap = nodep->lhsp();
|
||||
AstNodeBiop* const rp = VN_AS(nodep->rhsp(), NodeBiop);
|
||||
AstNode* const bp = rp->lhsp();
|
||||
AstNode* const cp = rp->rhsp();
|
||||
AstNodeExpr* const bp = rp->lhsp();
|
||||
AstNodeExpr* const cp = rp->rhsp();
|
||||
ap->unlinkFrBack();
|
||||
bp->unlinkFrBack();
|
||||
cp->unlinkFrBack();
|
||||
|
|
@ -1706,9 +1707,9 @@ private:
|
|||
void replaceAsvLUp(AstNodeBiop* nodep) {
|
||||
// BIASV(BIASV(CONSTll,lr),r) -> BIASV(CONSTll,BIASV(lr,r))
|
||||
AstNodeBiop* const lp = VN_AS(nodep->lhsp()->unlinkFrBack(), NodeBiop);
|
||||
AstNode* const llp = lp->lhsp()->unlinkFrBack();
|
||||
AstNode* const lrp = lp->rhsp()->unlinkFrBack();
|
||||
AstNode* const rp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const llp = lp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lrp = lp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rp = nodep->rhsp()->unlinkFrBack();
|
||||
nodep->lhsp(llp);
|
||||
nodep->rhsp(lp);
|
||||
lp->lhsp(lrp);
|
||||
|
|
@ -1717,10 +1718,10 @@ private:
|
|||
}
|
||||
void replaceAsvRUp(AstNodeBiop* nodep) {
|
||||
// BIASV(l,BIASV(CONSTrl,rr)) -> BIASV(CONSTrl,BIASV(l,rr))
|
||||
AstNode* const lp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeBiop* const rp = VN_AS(nodep->rhsp()->unlinkFrBack(), NodeBiop);
|
||||
AstNode* const rlp = rp->lhsp()->unlinkFrBack();
|
||||
AstNode* const rrp = rp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rlp = rp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rrp = rp->rhsp()->unlinkFrBack();
|
||||
nodep->lhsp(rlp);
|
||||
nodep->rhsp(rp);
|
||||
rp->lhsp(lp);
|
||||
|
|
@ -1733,11 +1734,11 @@ private:
|
|||
// nodep ^lp ^llp ^lrp ^rp ^rlp ^rrp
|
||||
// (Or/And may also be reversed)
|
||||
AstNodeBiop* const lp = VN_AS(nodep->lhsp()->unlinkFrBack(), NodeBiop);
|
||||
AstNode* const llp = lp->lhsp()->unlinkFrBack();
|
||||
AstNode* const lrp = lp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const llp = lp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lrp = lp->rhsp()->unlinkFrBack();
|
||||
AstNodeBiop* const rp = VN_AS(nodep->rhsp()->unlinkFrBack(), NodeBiop);
|
||||
AstNode* const rlp = rp->lhsp()->unlinkFrBack();
|
||||
AstNode* const rrp = rp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rlp = rp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rrp = rp->rhsp()->unlinkFrBack();
|
||||
nodep->replaceWith(lp);
|
||||
if (operandsSame(llp, rlp)) {
|
||||
lp->lhsp(llp);
|
||||
|
|
@ -1764,11 +1765,11 @@ private:
|
|||
// Or(Shift(ll,CONSTlr),Shift(rl,CONSTrr==lr)) -> Shift(Or(ll,rl),CONSTlr)
|
||||
// (Or/And may also be reversed)
|
||||
AstNodeBiop* const lp = VN_AS(nodep->lhsp()->unlinkFrBack(), NodeBiop);
|
||||
AstNode* const llp = lp->lhsp()->unlinkFrBack();
|
||||
AstNode* const lrp = lp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const llp = lp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lrp = lp->rhsp()->unlinkFrBack();
|
||||
AstNodeBiop* const rp = VN_AS(nodep->rhsp()->unlinkFrBack(), NodeBiop);
|
||||
AstNode* const rlp = rp->lhsp()->unlinkFrBack();
|
||||
AstNode* const rrp = rp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rlp = rp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rrp = rp->rhsp()->unlinkFrBack();
|
||||
nodep->replaceWith(lp);
|
||||
lp->lhsp(nodep);
|
||||
lp->rhsp(lrp);
|
||||
|
|
@ -1803,10 +1804,10 @@ private:
|
|||
void replaceConcatMerge(AstConcat* nodep) {
|
||||
AstNodeBiop* const lp = VN_AS(nodep->lhsp(), NodeBiop);
|
||||
AstNodeBiop* const rp = VN_AS(nodep->rhsp(), NodeBiop);
|
||||
AstNode* const llp = lp->lhsp()->cloneTree(false);
|
||||
AstNode* const lrp = lp->rhsp()->cloneTree(false);
|
||||
AstNode* const rlp = rp->lhsp()->cloneTree(false);
|
||||
AstNode* const rrp = rp->rhsp()->cloneTree(false);
|
||||
AstNodeExpr* const llp = lp->lhsp()->cloneTree(false);
|
||||
AstNodeExpr* const lrp = lp->rhsp()->cloneTree(false);
|
||||
AstNodeExpr* const rlp = rp->lhsp()->cloneTree(false);
|
||||
AstNodeExpr* const rrp = rp->rhsp()->cloneTree(false);
|
||||
if (concatMergeable(lp, rp, 0)) {
|
||||
AstConcat* const newlp = new AstConcat(rlp->fileline(), llp, rlp);
|
||||
AstConcat* const newrp = new AstConcat(rrp->fileline(), lrp, rrp);
|
||||
|
|
@ -1824,21 +1825,21 @@ private:
|
|||
nodep->v3fatalSrc("tried to merge two Concat which are not adjacent");
|
||||
}
|
||||
}
|
||||
void replaceExtend(AstNode* nodep, AstNode* arg0p) {
|
||||
void replaceExtend(AstNode* nodep, AstNodeExpr* arg0p) {
|
||||
// -> EXTEND(nodep)
|
||||
// like a AstExtend{$rhsp}, but we need to set the width correctly from base node
|
||||
arg0p->unlinkFrBack();
|
||||
AstNode* const newp
|
||||
AstNodeExpr* const newp
|
||||
= (VN_IS(nodep, ExtendS)
|
||||
? static_cast<AstNode*>(new AstExtendS{nodep->fileline(), arg0p})
|
||||
: static_cast<AstNode*>(new AstExtend{nodep->fileline(), arg0p}));
|
||||
? static_cast<AstNodeExpr*>(new AstExtendS{nodep->fileline(), arg0p})
|
||||
: static_cast<AstNodeExpr*>(new AstExtend{nodep->fileline(), arg0p}));
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void replacePowShift(AstNodeBiop* nodep) { // Pow or PowS
|
||||
UINFO(5, "POW(2,b)->SHIFTL(1,b) " << nodep << endl);
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstShiftL* const newp
|
||||
= new AstShiftL(nodep->fileline(), new AstConst(nodep->fileline(), 1), rhsp);
|
||||
newp->dtypeFrom(nodep);
|
||||
|
|
@ -1849,7 +1850,7 @@ private:
|
|||
void replaceMulShift(AstMul* nodep) { // Mul, but not MulS as not simple shift
|
||||
UINFO(5, "MUL(2^n,b)->SHIFTL(b,n) " << nodep << endl);
|
||||
const int amount = VN_AS(nodep->lhsp(), Const)->num().mostSetBitP1() - 1; // 2^n->n+1
|
||||
AstNode* const opp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const opp = nodep->rhsp()->unlinkFrBack();
|
||||
AstShiftL* const newp
|
||||
= new AstShiftL(nodep->fileline(), opp, new AstConst(nodep->fileline(), amount));
|
||||
newp->dtypeFrom(nodep);
|
||||
|
|
@ -1859,7 +1860,7 @@ private:
|
|||
void replaceDivShift(AstDiv* nodep) { // Mul, but not MulS as not simple shift
|
||||
UINFO(5, "DIV(b,2^n)->SHIFTR(b,n) " << nodep << endl);
|
||||
const int amount = VN_AS(nodep->rhsp(), Const)->num().mostSetBitP1() - 1; // 2^n->n+1
|
||||
AstNode* const opp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const opp = nodep->lhsp()->unlinkFrBack();
|
||||
AstShiftR* const newp
|
||||
= new AstShiftR(nodep->fileline(), opp, new AstConst(nodep->fileline(), amount));
|
||||
newp->dtypeFrom(nodep);
|
||||
|
|
@ -1871,7 +1872,7 @@ private:
|
|||
const int amount = VN_AS(nodep->rhsp(), Const)->num().mostSetBitP1() - 1; // 2^n->n+1
|
||||
V3Number mask(nodep, nodep->width());
|
||||
mask.setMask(amount);
|
||||
AstNode* const opp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const opp = nodep->lhsp()->unlinkFrBack();
|
||||
AstAnd* const newp
|
||||
= new AstAnd(nodep->fileline(), opp, new AstConst(nodep->fileline(), mask));
|
||||
newp->dtypeFrom(nodep);
|
||||
|
|
@ -1884,9 +1885,9 @@ private:
|
|||
nodep->unlinkFrBack(&handle);
|
||||
AstNodeBiop* const lhsp = VN_AS(nodep->lhsp(), NodeBiop);
|
||||
lhsp->unlinkFrBack();
|
||||
AstNode* const shiftp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* const ap = lhsp->lhsp()->unlinkFrBack();
|
||||
AstNode* const bp = lhsp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const shiftp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const ap = lhsp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const bp = lhsp->rhsp()->unlinkFrBack();
|
||||
AstNodeBiop* const shift1p = nodep;
|
||||
AstNodeBiop* const shift2p = nodep->cloneTree(true);
|
||||
shift1p->lhsp(ap);
|
||||
|
|
@ -1904,9 +1905,9 @@ private:
|
|||
if (debug() >= 9) nodep->dumpTree(cout, " repShiftShift_old: ");
|
||||
AstNodeBiop* const lhsp = VN_AS(nodep->lhsp(), NodeBiop);
|
||||
lhsp->unlinkFrBack();
|
||||
AstNode* const ap = lhsp->lhsp()->unlinkFrBack();
|
||||
AstNode* const shift1p = lhsp->rhsp()->unlinkFrBack();
|
||||
AstNode* const shift2p = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const ap = lhsp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const shift1p = lhsp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const shift2p = nodep->rhsp()->unlinkFrBack();
|
||||
// Shift1p and shift2p may have different sizes, both are
|
||||
// self-determined so sum with infinite width
|
||||
if (nodep->type() == lhsp->type()) {
|
||||
|
|
@ -1927,7 +1928,7 @@ private:
|
|||
const int newshift = shift1 + shift2;
|
||||
VL_DO_DANGLING(shift1p->deleteTree(), shift1p);
|
||||
VL_DO_DANGLING(shift2p->deleteTree(), shift2p);
|
||||
AstNode* newp;
|
||||
AstNodeExpr* newp;
|
||||
V3Number mask1(nodep, nodep->width());
|
||||
V3Number ones(nodep, nodep->width());
|
||||
ones.setMask(nodep->width());
|
||||
|
|
@ -1999,9 +2000,9 @@ private:
|
|||
UINFO(4, " && " << nextp << endl);
|
||||
// nodep->dumpTree(cout, "comb1: ");
|
||||
// nextp->dumpTree(cout, "comb2: ");
|
||||
AstNode* const rhs1p = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* const rhs2p = nextp->rhsp()->unlinkFrBack();
|
||||
AstNode* newp;
|
||||
AstNodeExpr* const rhs1p = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhs2p = nextp->rhsp()->unlinkFrBack();
|
||||
AstNodeAssign* newp;
|
||||
if (lsbFirstAssign) {
|
||||
newp = nodep->cloneType(new AstSel(sel1p->fileline(), varref1p->unlinkFrBack(),
|
||||
sel1p->lsbConst(), sel1p->width() + sel2p->width()),
|
||||
|
|
@ -2072,11 +2073,11 @@ private:
|
|||
}
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " Ass_old: ");
|
||||
// Unlink the stuff
|
||||
AstNode* const lc1p = VN_AS(nodep->lhsp(), Concat)->lhsp()->unlinkFrBack();
|
||||
AstNode* const lc2p = VN_AS(nodep->lhsp(), Concat)->rhsp()->unlinkFrBack();
|
||||
AstNode* const conp = VN_AS(nodep->lhsp(), Concat)->unlinkFrBack();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* const rhs2p = rhsp->cloneTree(false);
|
||||
AstNodeExpr* const lc1p = VN_AS(nodep->lhsp(), Concat)->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lc2p = VN_AS(nodep->lhsp(), Concat)->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const conp = VN_AS(nodep->lhsp(), Concat)->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhs2p = rhsp->cloneTree(false);
|
||||
// Calc widths
|
||||
const int lsb2 = 0;
|
||||
const int msb2 = lsb2 + lc2p->width() - 1;
|
||||
|
|
@ -2090,8 +2091,8 @@ private:
|
|||
//*** Not cloneTree; just one node.
|
||||
AstNodeAssign* newp = nullptr;
|
||||
if (!need_temp) {
|
||||
AstNodeAssign* const asn1ap = VN_AS(nodep->cloneType(lc1p, sel1p), NodeAssign);
|
||||
AstNodeAssign* const asn2ap = VN_AS(nodep->cloneType(lc2p, sel2p), NodeAssign);
|
||||
AstNodeAssign* const asn1ap = nodep->cloneType(lc1p, sel1p);
|
||||
AstNodeAssign* const asn2ap = nodep->cloneType(lc2p, sel2p);
|
||||
asn1ap->dtypeFrom(sel1p);
|
||||
asn2ap->dtypeFrom(sel2p);
|
||||
newp = AstNode::addNext(newp, asn1ap);
|
||||
|
|
@ -2103,29 +2104,21 @@ private:
|
|||
// We could create just one temp variable, but we'll get better optimization
|
||||
// if we make one per term.
|
||||
AstVar* const temp1p
|
||||
= new AstVar(sel1p->fileline(), VVarType::BLOCKTEMP,
|
||||
m_concswapNames.get(sel1p), VFlagLogicPacked(), msb1 - lsb1 + 1);
|
||||
= new AstVar{sel1p->fileline(), VVarType::BLOCKTEMP,
|
||||
m_concswapNames.get(sel1p), VFlagLogicPacked(), msb1 - lsb1 + 1};
|
||||
AstVar* const temp2p
|
||||
= new AstVar(sel2p->fileline(), VVarType::BLOCKTEMP,
|
||||
m_concswapNames.get(sel2p), VFlagLogicPacked(), msb2 - lsb2 + 1);
|
||||
= new AstVar{sel2p->fileline(), VVarType::BLOCKTEMP,
|
||||
m_concswapNames.get(sel2p), VFlagLogicPacked(), msb2 - lsb2 + 1};
|
||||
m_modp->addStmtsp(temp1p);
|
||||
m_modp->addStmtsp(temp2p);
|
||||
AstNodeAssign* const asn1ap
|
||||
= VN_AS(nodep->cloneType(
|
||||
new AstVarRef(sel1p->fileline(), temp1p, VAccess::WRITE), sel1p),
|
||||
NodeAssign);
|
||||
AstNodeAssign* const asn2ap
|
||||
= VN_AS(nodep->cloneType(
|
||||
new AstVarRef(sel2p->fileline(), temp2p, VAccess::WRITE), sel2p),
|
||||
NodeAssign);
|
||||
AstNodeAssign* const asn1bp
|
||||
= VN_AS(nodep->cloneType(
|
||||
lc1p, new AstVarRef(sel1p->fileline(), temp1p, VAccess::READ)),
|
||||
NodeAssign);
|
||||
AstNodeAssign* const asn2bp
|
||||
= VN_AS(nodep->cloneType(
|
||||
lc2p, new AstVarRef(sel2p->fileline(), temp2p, VAccess::READ)),
|
||||
NodeAssign);
|
||||
AstNodeAssign* const asn1ap = nodep->cloneType(
|
||||
new AstVarRef{sel1p->fileline(), temp1p, VAccess::WRITE}, sel1p);
|
||||
AstNodeAssign* const asn2ap = nodep->cloneType(
|
||||
new AstVarRef{sel2p->fileline(), temp2p, VAccess::WRITE}, sel2p);
|
||||
AstNodeAssign* const asn1bp = nodep->cloneType(
|
||||
lc1p, new AstVarRef{sel1p->fileline(), temp1p, VAccess::READ});
|
||||
AstNodeAssign* const asn2bp = nodep->cloneType(
|
||||
lc2p, new AstVarRef{sel2p->fileline(), temp2p, VAccess::READ});
|
||||
asn1ap->dtypeFrom(temp1p);
|
||||
asn1bp->dtypeFrom(temp1p);
|
||||
asn2ap->dtypeFrom(temp2p);
|
||||
|
|
@ -2147,9 +2140,9 @@ private:
|
|||
// The right-streaming operator on rhs of assignment does not
|
||||
// change the order of bits. Eliminate stream but keep its lhsp
|
||||
// Unlink the stuff
|
||||
AstNode* const srcp = VN_AS(nodep->rhsp(), StreamR)->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const srcp = VN_AS(nodep->rhsp(), StreamR)->lhsp()->unlinkFrBack();
|
||||
AstNode* const sizep = VN_AS(nodep->rhsp(), StreamR)->rhsp()->unlinkFrBack();
|
||||
AstNode* const streamp = VN_AS(nodep->rhsp(), StreamR)->unlinkFrBack();
|
||||
AstNodeExpr* const streamp = VN_AS(nodep->rhsp(), StreamR)->unlinkFrBack();
|
||||
nodep->rhsp(srcp);
|
||||
// Cleanup
|
||||
VL_DO_DANGLING(sizep->deleteTree(), sizep);
|
||||
|
|
@ -2161,9 +2154,9 @@ private:
|
|||
const int dWidth = VN_AS(nodep->lhsp(), StreamL)->lhsp()->width();
|
||||
const int sWidth = nodep->rhsp()->width();
|
||||
// Unlink the stuff
|
||||
AstNode* const dstp = VN_AS(nodep->lhsp(), StreamL)->lhsp()->unlinkFrBack();
|
||||
AstNode* streamp = VN_AS(nodep->lhsp(), StreamL)->unlinkFrBack();
|
||||
AstNode* const srcp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const dstp = VN_AS(nodep->lhsp(), StreamL)->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* streamp = VN_AS(nodep->lhsp(), StreamL)->unlinkFrBack();
|
||||
AstNodeExpr* const srcp = nodep->rhsp()->unlinkFrBack();
|
||||
// Connect the rhs to the stream operator and update its width
|
||||
VN_AS(streamp, StreamL)->lhsp(srcp);
|
||||
streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), VSigning::UNSIGNED);
|
||||
|
|
@ -2182,10 +2175,10 @@ private:
|
|||
const int dWidth = VN_AS(nodep->lhsp(), StreamR)->lhsp()->width();
|
||||
const int sWidth = nodep->rhsp()->width();
|
||||
// Unlink the stuff
|
||||
AstNode* const dstp = VN_AS(nodep->lhsp(), StreamR)->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const dstp = VN_AS(nodep->lhsp(), StreamR)->lhsp()->unlinkFrBack();
|
||||
AstNode* const sizep = VN_AS(nodep->lhsp(), StreamR)->rhsp()->unlinkFrBack();
|
||||
AstNode* const streamp = VN_AS(nodep->lhsp(), StreamR)->unlinkFrBack();
|
||||
AstNode* srcp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const streamp = VN_AS(nodep->lhsp(), StreamR)->unlinkFrBack();
|
||||
AstNodeExpr* srcp = nodep->rhsp()->unlinkFrBack();
|
||||
if (sWidth > dWidth) {
|
||||
srcp = new AstSel(streamp->fileline(), srcp, sWidth - dWidth, dWidth);
|
||||
}
|
||||
|
|
@ -2218,7 +2211,8 @@ private:
|
|||
void replaceBoolShift(AstNode* nodep) {
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " bshft_old: ");
|
||||
AstConst* const andConstp = VN_AS(VN_AS(nodep, And)->lhsp(), Const);
|
||||
AstNode* const fromp = VN_AS(VN_AS(nodep, And)->rhsp(), ShiftR)->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const fromp
|
||||
= VN_AS(VN_AS(nodep, And)->rhsp(), ShiftR)->lhsp()->unlinkFrBack();
|
||||
AstConst* const shiftConstp
|
||||
= VN_AS(VN_AS(VN_AS(nodep, And)->rhsp(), ShiftR)->rhsp(), Const);
|
||||
V3Number val(andConstp, andConstp->width());
|
||||
|
|
@ -2296,8 +2290,8 @@ private:
|
|||
void swapSides(AstNodeBiCom* nodep) {
|
||||
// COMMUTATIVE({a},CONST) -> COMMUTATIVE(CONST,{a})
|
||||
// This simplifies later optimizations
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBackWithNext();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBackWithNext();
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBackWithNext();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBackWithNext();
|
||||
nodep->lhsp(rhsp);
|
||||
nodep->rhsp(lhsp);
|
||||
iterate(nodep); // Again?
|
||||
|
|
@ -2333,8 +2327,8 @@ private:
|
|||
const AstConcat* const bcConcp = VN_CAST(nodep->rhsp(), Concat);
|
||||
if (!abConcp && !bcConcp) return 0;
|
||||
if (bcConcp) {
|
||||
AstNode* const ap = nodep->lhsp();
|
||||
AstNode* const bp = bcConcp->lhsp();
|
||||
AstNodeExpr* const ap = nodep->lhsp();
|
||||
AstNodeExpr* const bp = bcConcp->lhsp();
|
||||
// If a+b == 32,64,96 etc, then we want to have a+b together on LHS
|
||||
if (VL_BITBIT_I(ap->width() + bp->width()) == 0) return 2; // Transform 2: to abConc
|
||||
} else { // abConcp
|
||||
|
|
@ -2352,11 +2346,11 @@ private:
|
|||
// like that, so on 32 bit boundaries, we'll do the opposite form.
|
||||
UINFO(4, "Move concat: " << nodep << endl);
|
||||
if (operandConcatMove(nodep) > 1) {
|
||||
AstNode* const ap = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const ap = nodep->lhsp()->unlinkFrBack();
|
||||
AstConcat* const bcConcp = VN_AS(nodep->rhsp(), Concat);
|
||||
bcConcp->unlinkFrBack();
|
||||
AstNode* const bp = bcConcp->lhsp()->unlinkFrBack();
|
||||
AstNode* const cp = bcConcp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const bp = bcConcp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const cp = bcConcp->rhsp()->unlinkFrBack();
|
||||
AstConcat* const abConcp = new AstConcat(bcConcp->fileline(), ap, bp);
|
||||
nodep->lhsp(abConcp);
|
||||
nodep->rhsp(cp);
|
||||
|
|
@ -2367,9 +2361,9 @@ private:
|
|||
} else {
|
||||
AstConcat* const abConcp = VN_AS(nodep->lhsp(), Concat);
|
||||
abConcp->unlinkFrBack();
|
||||
AstNode* const ap = abConcp->lhsp()->unlinkFrBack();
|
||||
AstNode* const bp = abConcp->rhsp()->unlinkFrBack();
|
||||
AstNode* const cp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const ap = abConcp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const bp = abConcp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const cp = nodep->rhsp()->unlinkFrBack();
|
||||
AstConcat* const bcConcp = new AstConcat(abConcp->fileline(), bp, cp);
|
||||
nodep->lhsp(ap);
|
||||
nodep->rhsp(bcConcp);
|
||||
|
|
@ -2393,8 +2387,8 @@ private:
|
|||
|
||||
void replaceLogEq(AstLogEq* nodep) {
|
||||
// LOGEQ(a,b) => AstLogAnd{AstLogOr{AstLogNot{a},b},AstLogOr{AstLogNot{b},a}}
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
// Do exactly as IEEE says, might result in extra terms, so in future may do differently
|
||||
AstLogAnd* const newp = new AstLogAnd(
|
||||
nodep->fileline(),
|
||||
|
|
@ -2410,13 +2404,13 @@ private:
|
|||
void replaceSelSel(AstSel* nodep) {
|
||||
// SEL(SEL({x},a,b),c,d) => SEL({x},a+c,d)
|
||||
AstSel* const belowp = VN_AS(nodep->fromp(), Sel);
|
||||
AstNode* const fromp = belowp->fromp()->unlinkFrBack();
|
||||
AstNode* const widthp = nodep->widthp()->unlinkFrBack();
|
||||
AstNode* const lsb1p = nodep->lsbp()->unlinkFrBack();
|
||||
AstNode* const lsb2p = belowp->lsbp()->unlinkFrBack();
|
||||
AstNodeExpr* const fromp = belowp->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* const widthp = nodep->widthp()->unlinkFrBack();
|
||||
AstNodeExpr* const lsb1p = nodep->lsbp()->unlinkFrBack();
|
||||
AstNodeExpr* const lsb2p = belowp->lsbp()->unlinkFrBack();
|
||||
// Eliminate lower range
|
||||
UINFO(4, "Elim Lower range: " << nodep << endl);
|
||||
AstNode* newlsbp;
|
||||
AstNodeExpr* newlsbp;
|
||||
if (VN_IS(lsb1p, Const) && VN_IS(lsb2p, Const)) {
|
||||
newlsbp = new AstConst(lsb1p->fileline(),
|
||||
VN_AS(lsb1p, Const)->toUInt() + VN_AS(lsb2p, Const)->toUInt());
|
||||
|
|
@ -2427,13 +2421,13 @@ private:
|
|||
// potentially smaller lsb1p's width, but don't insert a redundant AstExtend.
|
||||
// Note that due to some sloppiness in earlier passes, lsb1p might actually be wider,
|
||||
// so extend to the wider type.
|
||||
AstNode* const widep = lsb1p->width() > lsb2p->width() ? lsb1p : lsb2p;
|
||||
AstNode* const lhsp = widep->width() > lsb2p->width()
|
||||
? new AstExtend{lsb2p->fileline(), lsb2p}
|
||||
: lsb2p;
|
||||
AstNode* const rhsp = widep->width() > lsb1p->width()
|
||||
? new AstExtend{lsb1p->fileline(), lsb1p}
|
||||
: lsb1p;
|
||||
AstNodeExpr* const widep = lsb1p->width() > lsb2p->width() ? lsb1p : lsb2p;
|
||||
AstNodeExpr* const lhsp = widep->width() > lsb2p->width()
|
||||
? new AstExtend{lsb2p->fileline(), lsb2p}
|
||||
: lsb2p;
|
||||
AstNodeExpr* const rhsp = widep->width() > lsb1p->width()
|
||||
? new AstExtend{lsb1p->fileline(), lsb1p}
|
||||
: lsb1p;
|
||||
lhsp->dtypeFrom(widep);
|
||||
rhsp->dtypeFrom(widep);
|
||||
newlsbp = new AstAdd{lsb1p->fileline(), lhsp, rhsp};
|
||||
|
|
@ -2447,8 +2441,8 @@ private:
|
|||
void replaceSelConcat(AstSel* nodep) {
|
||||
// SEL(CONCAT(a,b),c,d) => SEL(a or b, . .)
|
||||
AstConcat* const conp = VN_AS(nodep->fromp(), Concat);
|
||||
AstNode* const conLhsp = conp->lhsp();
|
||||
AstNode* const conRhsp = conp->rhsp();
|
||||
AstNodeExpr* const conLhsp = conp->lhsp();
|
||||
AstNodeExpr* const conRhsp = conp->rhsp();
|
||||
if (static_cast<int>(nodep->lsbConst()) >= conRhsp->width()) {
|
||||
conLhsp->unlinkFrBack();
|
||||
AstSel* const newp
|
||||
|
|
@ -2478,10 +2472,10 @@ private:
|
|||
// SEL(REPLICATE(from,rep),lsb,width) => SEL(from,0,width) as long
|
||||
// as SEL's width <= b's width
|
||||
AstReplicate* const repp = VN_AS(nodep->fromp(), Replicate);
|
||||
AstNode* const fromp = repp->lhsp();
|
||||
AstNodeExpr* const fromp = repp->lhsp();
|
||||
AstConst* const lsbp = VN_CAST(nodep->lsbp(), Const);
|
||||
if (!lsbp) return false;
|
||||
AstNode* const widthp = nodep->widthp();
|
||||
AstNodeExpr* const widthp = nodep->widthp();
|
||||
if (!VN_IS(widthp, Const)) return false;
|
||||
UASSERT_OBJ(fromp->width(), nodep, "Not widthed");
|
||||
if ((lsbp->toUInt() / fromp->width())
|
||||
|
|
@ -2502,7 +2496,7 @@ private:
|
|||
bool operandRepRep(AstReplicate* nodep) {
|
||||
// REPLICATE(REPLICATE2(from2,cnt2),cnt1) => REPLICATE(from2,(cnt1+cnt2))
|
||||
AstReplicate* const rep2p = VN_AS(nodep->lhsp(), Replicate);
|
||||
AstNode* const from2p = rep2p->lhsp();
|
||||
AstNodeExpr* const from2p = rep2p->lhsp();
|
||||
AstConst* const cnt1p = VN_CAST(nodep->rhsp(), Const);
|
||||
if (!cnt1p) return false;
|
||||
AstConst* const cnt2p = VN_CAST(rep2p->rhsp(), Const);
|
||||
|
|
@ -2523,9 +2517,9 @@ private:
|
|||
// CONCAT(REP(fromp,cnt1),fromp) -> REPLICATE(fromp,cnt1+1)
|
||||
// CONCAT(fromp,REP(fromp,cnt1)) -> REPLICATE(fromp,1+cnt1)
|
||||
// CONCAT(REP(fromp,cnt1),REP(fromp,cnt2)) -> REPLICATE(fromp,cnt1+cnt2)
|
||||
AstNode* from1p = nodep->lhsp();
|
||||
AstNodeExpr* from1p = nodep->lhsp();
|
||||
uint32_t cnt1 = 1;
|
||||
AstNode* from2p = nodep->rhsp();
|
||||
AstNodeExpr* from2p = nodep->rhsp();
|
||||
uint32_t cnt2 = 1;
|
||||
if (VN_IS(from1p, Replicate)) {
|
||||
AstConst* const cnt1p = VN_CAST(VN_CAST(from1p, Replicate)->rhsp(), Const);
|
||||
|
|
@ -2552,11 +2546,11 @@ private:
|
|||
// SEL(BUFIF1(a,b),1,bit) => BUFIF1(SEL(a,1,bit),SEL(b,1,bit))
|
||||
AstNodeBiop* const fromp = VN_AS(nodep->fromp()->unlinkFrBack(), NodeBiop);
|
||||
UASSERT_OBJ(fromp, nodep, "Called on non biop");
|
||||
AstNode* const lsbp = nodep->lsbp()->unlinkFrBack();
|
||||
AstNode* const widthp = nodep->widthp()->unlinkFrBack();
|
||||
AstNodeExpr* const lsbp = nodep->lsbp()->unlinkFrBack();
|
||||
AstNodeExpr* const widthp = nodep->widthp()->unlinkFrBack();
|
||||
//
|
||||
AstNode* const bilhsp = fromp->lhsp()->unlinkFrBack();
|
||||
AstNode* const birhsp = fromp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const bilhsp = fromp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const birhsp = fromp->rhsp()->unlinkFrBack();
|
||||
//
|
||||
fromp->lhsp(
|
||||
new AstSel(nodep->fileline(), bilhsp, lsbp->cloneTree(true), widthp->cloneTree(true)));
|
||||
|
|
@ -2569,10 +2563,10 @@ private:
|
|||
// SEL(NOT(a),1,bit) => NOT(SEL(a,bit))
|
||||
AstNodeUniop* const fromp = VN_AS(nodep->fromp()->unlinkFrBack(), NodeUniop);
|
||||
UASSERT_OBJ(fromp, nodep, "Called on non biop");
|
||||
AstNode* const lsbp = nodep->lsbp()->unlinkFrBack();
|
||||
AstNode* const widthp = nodep->widthp()->unlinkFrBack();
|
||||
AstNodeExpr* const lsbp = nodep->lsbp()->unlinkFrBack();
|
||||
AstNodeExpr* const widthp = nodep->widthp()->unlinkFrBack();
|
||||
//
|
||||
AstNode* const bilhsp = fromp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const bilhsp = fromp->lhsp()->unlinkFrBack();
|
||||
//
|
||||
fromp->lhsp(new AstSel(nodep->fileline(), bilhsp, lsbp, widthp));
|
||||
fromp->dtypeFrom(nodep);
|
||||
|
|
@ -2901,7 +2895,7 @@ private:
|
|||
// ASSIGNW (VARREF, const) -> INITIAL ( ASSIGN (VARREF, const) )
|
||||
UINFO(4, "constAssignW " << nodep << endl);
|
||||
// Make a initial assignment
|
||||
AstNode* const exprp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const exprp = nodep->rhsp()->unlinkFrBack();
|
||||
varrefp->unlinkFrBack();
|
||||
AstInitial* const newinitp = new AstInitial(
|
||||
nodep->fileline(), new AstAssign(nodep->fileline(), varrefp, exprp));
|
||||
|
|
@ -2957,7 +2951,7 @@ private:
|
|||
}
|
||||
} else if (!afterComment(nodep->thensp())) {
|
||||
UINFO(4, "IF({x}) nullptr {...} => IF(NOT{x}}: " << nodep << endl);
|
||||
AstNode* const condp = nodep->condp();
|
||||
AstNodeExpr* const condp = nodep->condp();
|
||||
AstNode* const elsesp = nodep->elsesp();
|
||||
condp->unlinkFrBackWithNext();
|
||||
elsesp->unlinkFrBackWithNext();
|
||||
|
|
@ -2971,7 +2965,7 @@ private:
|
|||
|| VN_IS(nodep->condp(), LogNot))
|
||||
&& nodep->thensp() && nodep->elsesp()) {
|
||||
UINFO(4, "IF(NOT {x}) => IF(x) swapped if/else" << nodep << endl);
|
||||
AstNode* const condp
|
||||
AstNodeExpr* const condp
|
||||
= VN_AS(nodep->condp(), NodeUniop)->lhsp()->unlinkFrBackWithNext();
|
||||
AstNode* const thensp = nodep->thensp()->unlinkFrBackWithNext();
|
||||
AstNode* const elsesp = nodep->elsesp()->unlinkFrBackWithNext();
|
||||
|
|
@ -2986,9 +2980,9 @@ private:
|
|||
AstNodeAssign* const thensp = VN_AS(nodep->thensp(), NodeAssign);
|
||||
AstNodeAssign* const elsesp = VN_AS(nodep->elsesp(), NodeAssign);
|
||||
thensp->unlinkFrBack();
|
||||
AstNode* const condp = nodep->condp()->unlinkFrBack();
|
||||
AstNode* const truep = thensp->rhsp()->unlinkFrBack();
|
||||
AstNode* const falsep = elsesp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const condp = nodep->condp()->unlinkFrBack();
|
||||
AstNodeExpr* const truep = thensp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const falsep = elsesp->rhsp()->unlinkFrBack();
|
||||
thensp->rhsp(new AstCond(truep->fileline(), condp, truep, falsep));
|
||||
nodep->replaceWith(thensp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -2997,9 +2991,9 @@ private:
|
|||
&& operandIfIf(nodep)) {
|
||||
UINFO(9, "IF({a}) IF({b}) => IF({a} && {b})" << endl);
|
||||
AstNodeIf* const lowerIfp = VN_AS(nodep->thensp(), NodeIf);
|
||||
AstNode* const condp = nodep->condp()->unlinkFrBack();
|
||||
AstNodeExpr* const condp = nodep->condp()->unlinkFrBack();
|
||||
AstNode* const lowerThensp = lowerIfp->thensp()->unlinkFrBackWithNext();
|
||||
AstNode* const lowerCondp = lowerIfp->condp()->unlinkFrBackWithNext();
|
||||
AstNodeExpr* const lowerCondp = lowerIfp->condp()->unlinkFrBackWithNext();
|
||||
nodep->condp(new AstLogAnd(lowerIfp->fileline(), condp, lowerCondp));
|
||||
lowerIfp->replaceWith(lowerThensp);
|
||||
VL_DO_DANGLING(lowerIfp->deleteTree(), lowerIfp);
|
||||
|
|
@ -3355,7 +3349,7 @@ private:
|
|||
// This visit function here must allow for short-circuiting.
|
||||
TREEOPS("AstCond {$lhsp.isZero}", "replaceWIteratedThs(nodep)");
|
||||
TREEOPS("AstCond {$lhsp.isNeqZero}", "replaceWIteratedRhs(nodep)");
|
||||
TREEOP ("AstCond{$condp.castNot, $thenp, $elsep}", "AstCond{$condp->op1p(), $elsep, $thenp}");
|
||||
TREEOP ("AstCond{$condp.castNot, $thenp, $elsep}", "AstCond{$condp->castNot()->lhsp(), $elsep, $thenp}");
|
||||
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isAllOnes, $elsep}", "AstLogOr {$condp, $elsep}"); // a?1:b == a||b
|
||||
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isZero}", "AstLogAnd{$condp, $thenp}"); // a?b:0 == a&&b
|
||||
TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isAllOnes}", "AstLogOr {AstNot{$condp}, $thenp}"); // a?b:1 == ~a||b
|
||||
|
|
@ -3386,36 +3380,36 @@ private:
|
|||
TREEOP1("AstLt {$lhsp.isAllOnes, $rhsp, $lhsp->width()==$rhsp->width()}", "replaceNumLimited(nodep,0)");
|
||||
TREEOP1("AstGte {$lhsp.isAllOnes, $rhsp, $lhsp->width()==$rhsp->width()}", "replaceNumLimited(nodep,1)");
|
||||
// Two level bubble pushing
|
||||
TREEOP ("AstNot {$lhsp.castNot, $lhsp->width()==VN_AS($lhsp,,Not)->lhsp()->width()}", "replaceWChild(nodep, $lhsp->op1p())"); // NOT(NOT(x))->x
|
||||
TREEOP ("AstLogNot{$lhsp.castLogNot}", "replaceWChild(nodep, $lhsp->op1p())"); // LOGNOT(LOGNOT(x))->x
|
||||
TREEOPV("AstNot {$lhsp.castEqCase, $lhsp.width1}","AstNeqCase{$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castEqCase}", "AstNeqCase{$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castNeqCase, $lhsp.width1}","AstEqCase {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castNeqCase}", "AstEqCase {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castEqWild, $lhsp.width1}","AstNeqWild{$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castEqWild}", "AstNeqWild{$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castNeqWild, $lhsp.width1}","AstEqWild {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castNeqWild}", "AstEqWild {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castEq, $lhsp.width1}", "AstNeq {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castEq}", "AstNeq {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castNeq, $lhsp.width1}", "AstEq {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castNeq}", "AstEq {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castLt, $lhsp.width1}", "AstGte {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castLt}", "AstGte {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castLtS, $lhsp.width1}", "AstGteS{$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castLtS}", "AstGteS{$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castLte, $lhsp.width1}", "AstGt {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castLte}", "AstGt {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castLteS, $lhsp.width1}", "AstGtS {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castLteS}", "AstGtS {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castGt, $lhsp.width1}", "AstLte {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castGt}", "AstLte {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castGtS, $lhsp.width1}", "AstLteS{$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castGtS}", "AstLteS{$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castGte, $lhsp.width1}", "AstLt {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castGte}", "AstLt {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOPV("AstNot {$lhsp.castGteS, $lhsp.width1}", "AstLtS {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castGteS}", "AstLtS {$lhsp->op1p(),$lhsp->op2p()}");
|
||||
TREEOP ("AstNot {$lhsp.castNot, $lhsp->width()==VN_AS($lhsp,,Not)->lhsp()->width()}", "replaceWChild(nodep, $lhsp->castNot()->lhsp())"); // NOT(NOT(x))->x
|
||||
TREEOP ("AstLogNot{$lhsp.castLogNot}", "replaceWChild(nodep, $lhsp->castLogNot()->lhsp())"); // LOGNOT(LOGNOT(x))->x
|
||||
TREEOPV("AstNot {$lhsp.castEqCase, $lhsp.width1}","AstNeqCase{$lhsp->castEqCase()->lhsp(),$lhsp->castEqCase()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castEqCase}", "AstNeqCase{$lhsp->castEqCase()->lhsp(),$lhsp->castEqCase()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castNeqCase, $lhsp.width1}","AstEqCase{$lhsp->castNeqCase()->lhsp(),$lhsp->castNeqCase()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castNeqCase}", "AstEqCase {$lhsp->castNeqCase()->lhsp(),$lhsp->castNeqCase()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castEqWild, $lhsp.width1}","AstNeqWild{$lhsp->castEqWild()->lhsp(),$lhsp->castEqWild()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castEqWild}", "AstNeqWild{$lhsp->castEqWild()->lhsp(),$lhsp->castEqWild()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castNeqWild, $lhsp.width1}","AstEqWild{$lhsp->castNeqWild()->lhsp(),$lhsp->castNeqWild()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castNeqWild}", "AstEqWild {$lhsp->castNeqWild()->lhsp(),$lhsp->castNeqWild()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castEq, $lhsp.width1}", "AstNeq {$lhsp->castEq()->lhsp(),$lhsp->castEq()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castEq}", "AstNeq {$lhsp->castEq()->lhsp(),$lhsp->castEq()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castNeq, $lhsp.width1}", "AstEq {$lhsp->castNeq()->lhsp(),$lhsp->castNeq()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castNeq}", "AstEq {$lhsp->castNeq()->lhsp(),$lhsp->castNeq()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castLt, $lhsp.width1}", "AstGte {$lhsp->castLt()->lhsp(),$lhsp->castLt()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castLt}", "AstGte {$lhsp->castLt()->lhsp(),$lhsp->castLt()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castLtS, $lhsp.width1}", "AstGteS{$lhsp->castLtS()->lhsp(),$lhsp->castLtS()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castLtS}", "AstGteS{$lhsp->castLtS()->lhsp(),$lhsp->castLtS()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castLte, $lhsp.width1}", "AstGt {$lhsp->castLte()->lhsp(),$lhsp->castLte()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castLte}", "AstGt {$lhsp->castLte()->lhsp(),$lhsp->castLte()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castLteS, $lhsp.width1}", "AstGtS {$lhsp->castLteS()->lhsp(),$lhsp->castLteS()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castLteS}", "AstGtS {$lhsp->castLteS()->lhsp(),$lhsp->castLteS()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castGt, $lhsp.width1}", "AstLte {$lhsp->castGt()->lhsp(),$lhsp->castGt()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castGt}", "AstLte {$lhsp->castGt()->lhsp(),$lhsp->castGt()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castGtS, $lhsp.width1}", "AstLteS{$lhsp->castGtS()->lhsp(),$lhsp->castGtS()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castGtS}", "AstLteS{$lhsp->castGtS()->lhsp(),$lhsp->castGtS()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castGte, $lhsp.width1}", "AstLt {$lhsp->castGte()->lhsp(),$lhsp->castGte()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castGte}", "AstLt {$lhsp->castGte()->lhsp(),$lhsp->castGte()->rhsp()}");
|
||||
TREEOPV("AstNot {$lhsp.castGteS, $lhsp.width1}", "AstLtS {$lhsp->castGteS()->lhsp(),$lhsp->castGteS()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castGteS}", "AstLtS {$lhsp->castGteS()->lhsp(),$lhsp->castGteS()->rhsp()}");
|
||||
// Not common, but avoids compiler warnings about over shifting
|
||||
TREEOP ("AstShiftL{operandHugeShiftL(nodep)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstShiftR{operandHugeShiftR(nodep)}", "replaceZero(nodep)");
|
||||
|
|
|
|||
|
|
@ -20,14 +20,16 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
class AstNetlist;
|
||||
class AstNode;
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Const final {
|
||||
public:
|
||||
static AstNode* constifyParamsEdit(AstNode* nodep);
|
||||
static AstNodeExpr* constifyParamsEdit(AstNodeExpr* exprp) {
|
||||
return VN_AS(constifyParamsEdit(static_cast<AstNode*>(exprp)), NodeExpr);
|
||||
}
|
||||
static AstNode* constifyGenerateParamsEdit(AstNode* nodep);
|
||||
// Only do constant pushing, without removing dead logic
|
||||
static void constifyAllLive(AstNetlist* nodep);
|
||||
|
|
@ -40,9 +42,15 @@ public:
|
|||
// Only the current node and lower
|
||||
// Return new node that may have replaced nodep
|
||||
static AstNode* constifyEditCpp(AstNode* nodep);
|
||||
static AstNodeExpr* constifyEditCpp(AstNodeExpr* exprp) {
|
||||
return VN_AS(constifyEditCpp(static_cast<AstNode*>(exprp)), NodeExpr);
|
||||
}
|
||||
// Only the current node and lower
|
||||
// Return new node that may have replaced nodep
|
||||
static AstNode* constifyEdit(AstNode* nodep);
|
||||
static AstNodeExpr* constifyEdit(AstNodeExpr* exprp) {
|
||||
return VN_AS(constifyEdit(static_cast<AstNode*>(exprp)), NodeExpr);
|
||||
}
|
||||
// Only the current node and lower, with special SenTree optimization
|
||||
// Return new node that may have replaced nodep
|
||||
static AstNode* constifyExpensiveEdit(AstNode* nodep);
|
||||
|
|
|
|||
|
|
@ -47,9 +47,9 @@ private:
|
|||
|
||||
struct ToggleEnt {
|
||||
const string m_comment; // Comment for coverage dump
|
||||
AstNode* m_varRefp; // How to get to this element
|
||||
AstNode* m_chgRefp; // How to get to this element
|
||||
ToggleEnt(const string& comment, AstNode* vp, AstNode* cp)
|
||||
AstNodeExpr* m_varRefp; // How to get to this element
|
||||
AstNodeExpr* m_chgRefp; // How to get to this element
|
||||
ToggleEnt(const string& comment, AstNodeExpr* vp, AstNodeExpr* cp)
|
||||
: m_comment{comment}
|
||||
, m_varRefp{vp}
|
||||
, m_chgRefp{cp} {}
|
||||
|
|
|
|||
|
|
@ -215,12 +215,12 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
AstNode* createDlyOnSet(AstAssignDly* nodep, AstNode* lhsp) {
|
||||
AstNodeExpr* createDlyOnSet(AstAssignDly* nodep, AstNodeExpr* lhsp) {
|
||||
// Create delayed assignment
|
||||
// See top of this file for transformation
|
||||
// Return the new LHS for the assignment, Null = unlink
|
||||
// Find selects
|
||||
AstNode* newlhsp = nullptr; // nullptr = unlink old assign
|
||||
AstNodeExpr* newlhsp = nullptr; // nullptr = unlink old assign
|
||||
const AstSel* bitselp = nullptr;
|
||||
AstArraySel* arrayselp = nullptr;
|
||||
AstVarRef* varrefp = nullptr;
|
||||
|
|
@ -242,10 +242,10 @@ private:
|
|||
UINFO(4, "AssignDlyOnSet: " << nodep << endl);
|
||||
}
|
||||
//=== Dimensions: __Vdlyvdim__
|
||||
std::deque<AstNode*> dimvalp; // Assignment value for each dimension of assignment
|
||||
std::deque<AstNodeExpr*> dimvalp; // Assignment value for each dimension of assignment
|
||||
AstNode* dimselp = arrayselp;
|
||||
for (; VN_IS(dimselp, ArraySel); dimselp = VN_AS(dimselp, ArraySel)->fromp()) {
|
||||
AstNode* const valp = VN_AS(dimselp, ArraySel)->bitp()->unlinkFrBack();
|
||||
AstNodeExpr* const valp = VN_AS(dimselp, ArraySel)->bitp()->unlinkFrBack();
|
||||
dimvalp.push_front(valp);
|
||||
}
|
||||
if (dimselp) varrefp = VN_AS(dimselp, VarRef);
|
||||
|
|
@ -255,9 +255,9 @@ private:
|
|||
const AstVar* const oldvarp = varrefp->varp();
|
||||
const int modVecNum = m_scopeVecMap[varrefp->varScopep()]++;
|
||||
//
|
||||
std::deque<AstNode*> dimreadps; // Read value for each dimension of assignment
|
||||
std::deque<AstNodeExpr*> dimreadps; // Read value for each dimension of assignment
|
||||
for (unsigned dimension = 0; dimension < dimvalp.size(); dimension++) {
|
||||
AstNode* const dimp = dimvalp[dimension];
|
||||
AstNodeExpr* const dimp = dimvalp[dimension];
|
||||
if (VN_IS(dimp, Const)) { // bit = const, can just use it
|
||||
dimreadps.push_front(dimp);
|
||||
} else {
|
||||
|
|
@ -274,9 +274,9 @@ private:
|
|||
}
|
||||
//
|
||||
//=== Bitselect: __Vdlyvlsb__
|
||||
AstNode* bitreadp = nullptr; // Code to read Vdlyvlsb
|
||||
AstNodeExpr* bitreadp = nullptr; // Code to read Vdlyvlsb
|
||||
if (bitselp) {
|
||||
AstNode* const lsbvaluep = bitselp->lsbp()->unlinkFrBack();
|
||||
AstNodeExpr* const lsbvaluep = bitselp->lsbp()->unlinkFrBack();
|
||||
if (VN_IS(bitselp->fromp(), Const)) {
|
||||
// vlsb = constant, can just push constant into where we use it
|
||||
bitreadp = lsbvaluep;
|
||||
|
|
@ -294,7 +294,7 @@ private:
|
|||
}
|
||||
//
|
||||
//=== Value: __Vdlyvval__
|
||||
AstNode* valreadp; // Code to read Vdlyvval
|
||||
AstNodeExpr* valreadp; // Code to read Vdlyvval
|
||||
if (VN_IS(nodep->rhsp(), Const)) {
|
||||
// vval = constant, can just push constant into where we use it
|
||||
valreadp = nodep->rhsp()->unlinkFrBack();
|
||||
|
|
@ -342,7 +342,7 @@ private:
|
|||
// This ensures that multiple assignments to the same memory will result
|
||||
// in correctly ordered code - the last assignment must be last.
|
||||
// It also has the nice side effect of assisting cache locality.
|
||||
AstNode* selectsp = varrefp;
|
||||
AstNodeExpr* selectsp = varrefp;
|
||||
for (int dimension = int(dimreadps.size()) - 1; dimension >= 0; --dimension) {
|
||||
selectsp = new AstArraySel(nodep->fileline(), selectsp, dimreadps[dimension]);
|
||||
}
|
||||
|
|
@ -519,8 +519,8 @@ private:
|
|||
|| (VN_IS(nodep->lhsp(), Sel)
|
||||
&& VN_IS(VN_AS(nodep->lhsp(), Sel)->fromp(), ArraySel));
|
||||
if (m_procp->isSuspendable() || isArray) {
|
||||
AstNode* const lhsp = nodep->lhsp();
|
||||
AstNode* const newlhsp = createDlyOnSet(nodep, lhsp);
|
||||
AstNodeExpr* const lhsp = nodep->lhsp();
|
||||
AstNodeExpr* const newlhsp = createDlyOnSet(nodep, lhsp);
|
||||
if (m_inLoop && isArray) {
|
||||
nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for "
|
||||
"loops (non-delayed is ok - see docs)");
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ private:
|
|||
|
||||
// METHODS
|
||||
|
||||
void createDeepTemp(AstNode* nodep) {
|
||||
void createDeepTemp(AstNodeExpr* nodep) {
|
||||
UINFO(6, " Deep " << nodep << endl);
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, "deep:");
|
||||
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::STMTTEMP,
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
});
|
||||
}
|
||||
|
||||
void addResultEquation(FileLine* flp, AstNode* lhsp, AstNode* rhsp) {
|
||||
void addResultEquation(FileLine* flp, AstNodeExpr* lhsp, AstNodeExpr* rhsp) {
|
||||
m_modp->addStmtsp(new AstAssignW{flp, lhsp, rhsp});
|
||||
++m_ctx.m_resultEquations;
|
||||
}
|
||||
|
|
|
|||
170
src/V3Expand.cpp
170
src/V3Expand.cpp
|
|
@ -92,17 +92,19 @@ private:
|
|||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
static AstNode* newWordAssign(AstNodeAssign* placep, int word, AstNode* lhsp, AstNode* rhsp) {
|
||||
static AstNode* newWordAssign(AstNodeAssign* placep, int word, AstNodeExpr* lhsp,
|
||||
AstNodeExpr* rhsp) {
|
||||
FileLine* const fl = placep->fileline();
|
||||
return new AstAssign{fl,
|
||||
new AstWordSel{fl, lhsp->cloneTree(true),
|
||||
new AstConst{fl, static_cast<uint32_t>(word)}},
|
||||
rhsp};
|
||||
}
|
||||
static void addWordAssign(AstNodeAssign* placep, int word, AstNode* lhsp, AstNode* rhsp) {
|
||||
static void addWordAssign(AstNodeAssign* placep, int word, AstNodeExpr* lhsp,
|
||||
AstNodeExpr* rhsp) {
|
||||
insertBefore(placep, newWordAssign(placep, word, lhsp, rhsp));
|
||||
}
|
||||
static void addWordAssign(AstNodeAssign* placep, int word, AstNode* rhsp) {
|
||||
static void addWordAssign(AstNodeAssign* placep, int word, AstNodeExpr* rhsp) {
|
||||
addWordAssign(placep, word, placep->lhsp(), rhsp);
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +119,7 @@ private:
|
|||
if (nodep->op4p()) fixCloneLvalue(nodep->op4p());
|
||||
}
|
||||
|
||||
static AstNode* newAstWordSelClone(AstNode* nodep, int word) {
|
||||
static AstNodeExpr* newAstWordSelClone(AstNodeExpr* nodep, int word) {
|
||||
// Get the specified word number from a wide array
|
||||
// Or, if it's a long/quad, do appropriate conversion to wide
|
||||
// Concat may pass negative word numbers, that means it wants a zero
|
||||
|
|
@ -126,11 +128,11 @@ private:
|
|||
return new AstWordSel{fl, nodep->cloneTree(true),
|
||||
new AstConst{fl, static_cast<uint32_t>(word)}};
|
||||
} else if (nodep->isQuad() && word == 0) {
|
||||
AstNode* const quadfromp = nodep->cloneTree(true);
|
||||
AstNodeExpr* const quadfromp = nodep->cloneTree(true);
|
||||
quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(), VSigning::UNSIGNED);
|
||||
return new AstCCast{fl, quadfromp, VL_EDATASIZE};
|
||||
} else if (nodep->isQuad() && word == 1) {
|
||||
AstNode* const quadfromp = nodep->cloneTree(true);
|
||||
AstNodeExpr* const quadfromp = nodep->cloneTree(true);
|
||||
quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(), VSigning::UNSIGNED);
|
||||
return new AstCCast{
|
||||
fl, new AstShiftR{fl, quadfromp, new AstConst{fl, VL_EDATASIZE}, VL_EDATASIZE},
|
||||
|
|
@ -142,16 +144,16 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
static AstNode* newWordGrabShift(FileLine* fl, int word, AstNode* lhsp, int shift) {
|
||||
static AstNodeExpr* newWordGrabShift(FileLine* fl, int word, AstNodeExpr* lhsp, int shift) {
|
||||
// Extract the expression to grab the value for the specified word, if it's the shift
|
||||
// of shift bits from lhsp
|
||||
AstNode* newp;
|
||||
AstNodeExpr* newp;
|
||||
// Negative word numbers requested for lhs when it's "before" what we want.
|
||||
// We get a 0 then.
|
||||
const int othword = word - shift / VL_EDATASIZE;
|
||||
AstNode* const llowp = newAstWordSelClone(lhsp, othword);
|
||||
AstNodeExpr* const llowp = newAstWordSelClone(lhsp, othword);
|
||||
if (const int loffset = VL_BITBIT_E(shift)) {
|
||||
AstNode* const lhip = newAstWordSelClone(lhsp, othword - 1);
|
||||
AstNodeExpr* const lhip = newAstWordSelClone(lhsp, othword - 1);
|
||||
const int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword
|
||||
newp = new AstOr{
|
||||
fl,
|
||||
|
|
@ -170,8 +172,8 @@ private:
|
|||
return newp;
|
||||
}
|
||||
|
||||
static AstNode* newWordSel(FileLine* fl, AstNode* fromp, AstNode* lsbp,
|
||||
uint32_t wordOffset = 0) {
|
||||
static AstNodeExpr* newWordSel(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* lsbp,
|
||||
uint32_t wordOffset = 0) {
|
||||
// Return equation to get the VL_BITWORD of a constant or non-constant
|
||||
UASSERT_OBJ(fromp->isWide(), fromp, "Only need AstWordSel on wide from's");
|
||||
if (wordOffset >= static_cast<uint32_t>(fromp->widthWords())) {
|
||||
|
|
@ -181,7 +183,7 @@ private:
|
|||
// AstCondBound is protecting above this node.
|
||||
return new AstConst{fl, AstConst::SizedEData(), 0};
|
||||
} else {
|
||||
AstNode* wordp;
|
||||
AstNodeExpr* wordp;
|
||||
FileLine* const lfl = lsbp->fileline();
|
||||
if (VN_IS(lsbp, Const)) {
|
||||
wordp = new AstConst{lfl, wordOffset + VL_BITWORD_E(VN_AS(lsbp, Const)->toUInt())};
|
||||
|
|
@ -197,7 +199,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
static AstNode* dropCondBound(AstNode* nodep) {
|
||||
static AstNodeExpr* dropCondBound(AstNodeExpr* nodep) {
|
||||
// Experimental only...
|
||||
// If there's a CONDBOUND safety to keep arrays in bounds,
|
||||
// we're going to AND it to a value that always fits inside a
|
||||
|
|
@ -208,7 +210,7 @@ private:
|
|||
return nodep;
|
||||
}
|
||||
|
||||
static AstNode* newSelBitBit(AstNode* lsbp) {
|
||||
static AstNodeExpr* newSelBitBit(AstNodeExpr* lsbp) {
|
||||
// Return equation to get the VL_BITBIT of a constant or non-constant
|
||||
FileLine* const fl = lsbp->fileline();
|
||||
if (VN_IS(lsbp, Const)) {
|
||||
|
|
@ -320,8 +322,8 @@ private:
|
|||
if (nodep->isWide()) {
|
||||
// See under ASSIGN(EXTEND)
|
||||
} else {
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* newp = lhsp;
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* newp = lhsp;
|
||||
if (nodep->isQuad()) {
|
||||
if (lhsp->isQuad()) {
|
||||
lhsp->dtypeFrom(nodep); // Just mark it, else nop
|
||||
|
|
@ -359,28 +361,29 @@ private:
|
|||
FileLine* const nfl = nodep->fileline();
|
||||
FileLine* const lfl = nodep->lsbp()->fileline();
|
||||
FileLine* const ffl = nodep->fromp()->fileline();
|
||||
AstNode* lowwordp = newWordSel(ffl, nodep->fromp()->cloneTree(true), nodep->lsbp());
|
||||
AstNodeExpr* lowwordp
|
||||
= newWordSel(ffl, nodep->fromp()->cloneTree(true), nodep->lsbp());
|
||||
if (nodep->isQuad() && !lowwordp->isQuad()) {
|
||||
lowwordp = new AstCCast{nfl, lowwordp, nodep};
|
||||
}
|
||||
AstNode* const lowp
|
||||
AstNodeExpr* const lowp
|
||||
= new AstShiftR{nfl, lowwordp, newSelBitBit(nodep->lsbp()), nodep->width()};
|
||||
// If > 1 bit, we might be crossing the word boundary
|
||||
AstNode* midp = nullptr;
|
||||
AstNodeExpr* midp = nullptr;
|
||||
if (nodep->widthConst() > 1) {
|
||||
const uint32_t midMsbOffset
|
||||
= std::min<uint32_t>(nodep->widthConst(), VL_EDATASIZE) - 1;
|
||||
AstNode* const midMsbp = new AstAdd{lfl, new AstConst{lfl, midMsbOffset},
|
||||
nodep->lsbp()->cloneTree(false)};
|
||||
AstNode* midwordp = // SEL(from,[midwordnum])
|
||||
AstNodeExpr* const midMsbp = new AstAdd{lfl, new AstConst{lfl, midMsbOffset},
|
||||
nodep->lsbp()->cloneTree(false)};
|
||||
AstNodeExpr* midwordp = // SEL(from,[midwordnum])
|
||||
newWordSel(ffl, nodep->fromp()->cloneTree(true), midMsbp, 0);
|
||||
// newWordSel clones the index, so delete it
|
||||
VL_DO_DANGLING(midMsbp->deleteTree(), midMsbp);
|
||||
if (nodep->isQuad() && !midwordp->isQuad()) {
|
||||
midwordp = new AstCCast{nfl, midwordp, nodep};
|
||||
}
|
||||
AstNode* const midshiftp = new AstSub{lfl, new AstConst{lfl, VL_EDATASIZE},
|
||||
newSelBitBit(nodep->lsbp())};
|
||||
AstNodeExpr* const midshiftp = new AstSub{lfl, new AstConst{lfl, VL_EDATASIZE},
|
||||
newSelBitBit(nodep->lsbp())};
|
||||
// If we're selecting bit zero, then all 32 bits in the mid word
|
||||
// get shifted << by 32 bits, so ignore them.
|
||||
const V3Number zero{nodep, longOrQuadWidth(nodep)};
|
||||
|
|
@ -395,19 +398,19 @@ private:
|
|||
new AstShiftL{nfl, midwordp, midshiftp, nodep->width()}};
|
||||
}
|
||||
// If > 32 bits, we might be crossing the second word boundary
|
||||
AstNode* hip = nullptr;
|
||||
AstNodeExpr* hip = nullptr;
|
||||
if (nodep->widthConst() > VL_EDATASIZE) {
|
||||
const uint32_t hiMsbOffset = nodep->widthConst() - 1;
|
||||
AstNode* const hiMsbp = new AstAdd{lfl, new AstConst{lfl, hiMsbOffset},
|
||||
nodep->lsbp()->cloneTree(false)};
|
||||
AstNode* hiwordp = // SEL(from,[hiwordnum])
|
||||
AstNodeExpr* const hiMsbp = new AstAdd{lfl, new AstConst{lfl, hiMsbOffset},
|
||||
nodep->lsbp()->cloneTree(false)};
|
||||
AstNodeExpr* hiwordp = // SEL(from,[hiwordnum])
|
||||
newWordSel(ffl, nodep->fromp()->cloneTree(true), hiMsbp);
|
||||
// newWordSel clones the index, so delete it
|
||||
VL_DO_DANGLING(hiMsbp->deleteTree(), hiMsbp);
|
||||
if (nodep->isQuad() && !hiwordp->isQuad()) {
|
||||
hiwordp = new AstCCast{nfl, hiwordp, nodep};
|
||||
}
|
||||
AstNode* const hishiftp = new AstCond{
|
||||
AstNodeExpr* const hishiftp = new AstCond{
|
||||
nfl,
|
||||
// lsb % VL_EDATASIZE == 0 ?
|
||||
new AstEq{nfl, new AstConst{nfl, 0}, newSelBitBit(nodep->lsbp())},
|
||||
|
|
@ -418,7 +421,7 @@ private:
|
|||
hip = new AstShiftL{nfl, hiwordp, hishiftp, nodep->width()};
|
||||
}
|
||||
|
||||
AstNode* newp = lowp;
|
||||
AstNodeExpr* newp = lowp;
|
||||
if (midp) newp = new AstOr{nfl, midp, newp};
|
||||
if (hip) newp = new AstOr{nfl, hip, newp};
|
||||
newp->dtypeFrom(nodep);
|
||||
|
|
@ -426,11 +429,11 @@ private:
|
|||
} else { // Long/Quad from Long/Quad
|
||||
UINFO(8, " SEL->SHIFT " << nodep << endl);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* fromp = nodep->fromp()->unlinkFrBack();
|
||||
AstNode* const lsbp = nodep->lsbp()->unlinkFrBack();
|
||||
AstNodeExpr* fromp = nodep->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* const lsbp = nodep->lsbp()->unlinkFrBack();
|
||||
if (nodep->isQuad() && !fromp->isQuad()) { fromp = new AstCCast{fl, fromp, nodep}; }
|
||||
// {large}>>32 requires 64-bit shift operation; then cast
|
||||
AstNode* newp = new AstShiftR{fl, fromp, dropCondBound(lsbp), fromp->width()};
|
||||
AstNodeExpr* newp = new AstShiftR{fl, fromp, dropCondBound(lsbp), fromp->width()};
|
||||
newp->dtypeFrom(fromp);
|
||||
if (!nodep->isQuad() && fromp->isQuad()) { newp = new AstCCast{fl, newp, nodep}; }
|
||||
newp->dtypeFrom(nodep);
|
||||
|
|
@ -456,21 +459,21 @@ private:
|
|||
FileLine* const lfl = rhsp->lsbp()->fileline();
|
||||
for (int w = 0; w < nodep->widthWords(); ++w) {
|
||||
// Grab lowest bits
|
||||
AstNode* const lowwordp
|
||||
AstNodeExpr* const lowwordp
|
||||
= newWordSel(rfl, rhsp->fromp()->cloneTree(true), rhsp->lsbp(), w);
|
||||
AstNode* const lowp
|
||||
AstNodeExpr* const lowp
|
||||
= new AstShiftR{rfl, lowwordp, newSelBitBit(rhsp->lsbp()), VL_EDATASIZE};
|
||||
// Upper bits
|
||||
const V3Number zero{nodep, VL_EDATASIZE, 0};
|
||||
AstNode* const midwordp = // SEL(from,[1+wordnum])
|
||||
AstNodeExpr* const midwordp = // SEL(from,[1+wordnum])
|
||||
newWordSel(ffl, rhsp->fromp()->cloneTree(true), rhsp->lsbp(), w + 1);
|
||||
AstNode* const midshiftp
|
||||
AstNodeExpr* const midshiftp
|
||||
= new AstSub{lfl, new AstConst{lfl, VL_EDATASIZE}, newSelBitBit(rhsp->lsbp())};
|
||||
AstNode* const midmayp = new AstShiftL{rfl, midwordp, midshiftp, VL_EDATASIZE};
|
||||
AstNode* const midp = new AstCond{
|
||||
AstNodeExpr* const midmayp = new AstShiftL{rfl, midwordp, midshiftp, VL_EDATASIZE};
|
||||
AstNodeExpr* const midp = new AstCond{
|
||||
rfl, new AstEq{rfl, new AstConst{rfl, 0}, newSelBitBit(rhsp->lsbp())},
|
||||
new AstConst{rfl, zero}, midmayp};
|
||||
AstNode* const newp = new AstOr{nfl, midp, lowp};
|
||||
AstNodeExpr* const newp = new AstOr{nfl, midp, lowp};
|
||||
addWordAssign(nodep, w, newp);
|
||||
}
|
||||
return true;
|
||||
|
|
@ -491,8 +494,8 @@ private:
|
|||
if (VN_IS(lhsp->lsbp(), Const)) {
|
||||
// The code should work without this constant test, but it won't
|
||||
// constify as nicely as we'd like.
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* const destp = lhsp->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const destp = lhsp->fromp()->unlinkFrBack();
|
||||
const int lsb = lhsp->lsbConst();
|
||||
const int msb = lhsp->msbConst();
|
||||
V3Number maskset{nodep, destp->widthMin()};
|
||||
|
|
@ -504,7 +507,7 @@ private:
|
|||
for (int w = 0; w < destp->widthWords(); ++w) {
|
||||
if (w >= VL_BITWORD_E(lsb) && w <= VL_BITWORD_E(msb)) {
|
||||
// else we would just be setting it to the same exact value
|
||||
AstNode* oldvalp = newAstWordSelClone(destp, w);
|
||||
AstNodeExpr* oldvalp = newAstWordSelClone(destp, w);
|
||||
fixCloneLvalue(oldvalp);
|
||||
if (!ones) {
|
||||
oldvalp = new AstAnd{
|
||||
|
|
@ -514,7 +517,7 @@ private:
|
|||
}
|
||||
|
||||
// Appropriate word of new value to insert:
|
||||
AstNode* newp = newWordGrabShift(lfl, w, rhsp, lsb);
|
||||
AstNodeExpr* newp = newWordGrabShift(lfl, w, rhsp, lsb);
|
||||
|
||||
// Apply cleaning at the top word of the destination
|
||||
// (no cleaning to do if dst's width is a whole number
|
||||
|
|
@ -524,7 +527,7 @@ private:
|
|||
cleanmask.setMask(VL_BITBIT_E(destp->widthMin()));
|
||||
newp = new AstAnd{lfl, newp, new AstConst{lfl, cleanmask}};
|
||||
}
|
||||
AstNode* const orp
|
||||
AstNodeExpr* const orp
|
||||
= V3Const::constifyEditCpp(new AstOr{lfl, oldvalp, newp});
|
||||
addWordAssign(nodep, w, destp, orp);
|
||||
}
|
||||
|
|
@ -534,7 +537,7 @@ private:
|
|||
} else {
|
||||
UINFO(8, " ASSIGNSEL(const,narrow) " << nodep << endl);
|
||||
if (destp->isQuad() && !rhsp->isQuad()) { rhsp = new AstCCast{nfl, rhsp, nodep}; }
|
||||
AstNode* oldvalp = destp->cloneTree(true);
|
||||
AstNodeExpr* oldvalp = destp->cloneTree(true);
|
||||
fixCloneLvalue(oldvalp);
|
||||
if (!ones) { oldvalp = new AstAnd{lfl, new AstConst{lfl, maskold}, oldvalp}; }
|
||||
|
||||
|
|
@ -543,20 +546,21 @@ private:
|
|||
// valid range of nodep which we apply to the new shifted RHS.
|
||||
V3Number cleanmask{nodep, destp->widthMin()};
|
||||
cleanmask.setMask(destp->widthMin());
|
||||
AstNode* const shifted = new AstShiftL{
|
||||
AstNodeExpr* const shifted = new AstShiftL{
|
||||
lfl, rhsp, new AstConst{lfl, static_cast<uint32_t>(lsb)}, destp->width()};
|
||||
AstNode* const cleaned = new AstAnd{lfl, shifted, new AstConst{lfl, cleanmask}};
|
||||
AstNode* const orp = V3Const::constifyEditCpp(new AstOr{lfl, oldvalp, cleaned});
|
||||
AstNode* newp = new AstAssign{nfl, destp, orp};
|
||||
insertBefore(nodep, newp);
|
||||
AstNodeExpr* const cleaned
|
||||
= new AstAnd{lfl, shifted, new AstConst{lfl, cleanmask}};
|
||||
AstNodeExpr* const orp
|
||||
= V3Const::constifyEditCpp(new AstOr{lfl, oldvalp, cleaned});
|
||||
insertBefore(nodep, new AstAssign{nfl, destp, orp});
|
||||
}
|
||||
return true;
|
||||
} else { // non-const select offset
|
||||
if (destwide && lhsp->widthConst() == 1) {
|
||||
UINFO(8, " ASSIGNSEL(varlsb,wide,1bit) " << nodep << endl);
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* const destp = lhsp->fromp()->unlinkFrBack();
|
||||
AstNode* oldvalp = newWordSel(lfl, destp->cloneTree(true), lhsp->lsbp());
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const destp = lhsp->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* oldvalp = newWordSel(lfl, destp->cloneTree(true), lhsp->lsbp());
|
||||
fixCloneLvalue(oldvalp);
|
||||
if (!ones) {
|
||||
oldvalp = new AstAnd{
|
||||
|
|
@ -570,8 +574,8 @@ private:
|
|||
oldvalp};
|
||||
}
|
||||
// Restrict the shift amount to 0-31, see bug804.
|
||||
AstNode* const shiftp = new AstAnd{nfl, lhsp->lsbp()->cloneTree(true),
|
||||
new AstConst{nfl, VL_EDATASIZE - 1}};
|
||||
AstNodeExpr* const shiftp = new AstAnd{nfl, lhsp->lsbp()->cloneTree(true),
|
||||
new AstConst{nfl, VL_EDATASIZE - 1}};
|
||||
AstNode* const newp = new AstAssign{
|
||||
nfl, newWordSel(nfl, destp, lhsp->lsbp()),
|
||||
new AstOr{lfl, oldvalp, new AstShiftL{lfl, rhsp, shiftp, VL_EDATASIZE}}};
|
||||
|
|
@ -592,9 +596,9 @@ private:
|
|||
} else {
|
||||
UINFO(8, " ASSIGNSEL(varlsb,narrow) " << nodep << endl);
|
||||
// nodep->dumpTree(cout, "- old: ");
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* const destp = lhsp->fromp()->unlinkFrBack();
|
||||
AstNode* oldvalp = destp->cloneTree(true);
|
||||
AstNodeExpr* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const destp = lhsp->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* oldvalp = destp->cloneTree(true);
|
||||
fixCloneLvalue(oldvalp);
|
||||
|
||||
V3Number maskwidth{nodep, destp->widthMin()};
|
||||
|
|
@ -609,7 +613,7 @@ private:
|
|||
lhsp->lsbp()->cloneTree(true), destp->width()}},
|
||||
oldvalp};
|
||||
}
|
||||
AstNode* newp
|
||||
AstNodeExpr* newp
|
||||
= new AstShiftL{lfl, rhsp, lhsp->lsbp()->cloneTree(true), destp->width()};
|
||||
// Apply cleaning to the new value being inserted. Mask is
|
||||
// slightly wider than necessary to avoid an AND with all ones
|
||||
|
|
@ -621,9 +625,7 @@ private:
|
|||
newp = new AstAnd{lfl, newp, new AstConst{lfl, cleanmask}};
|
||||
}
|
||||
|
||||
newp = new AstAssign{nfl, destp, new AstOr{lfl, oldvalp, newp}};
|
||||
// newp->dumpTree(cout, "- new: ");
|
||||
insertBefore(nodep, newp);
|
||||
insertBefore(nodep, new AstAssign{nfl, destp, new AstOr{lfl, oldvalp, newp}});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -637,12 +639,12 @@ private:
|
|||
} else {
|
||||
UINFO(8, " CONCAT " << nodep << endl);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
const uint32_t rhsshift = rhsp->widthMin();
|
||||
if (nodep->isQuad() && !lhsp->isQuad()) { lhsp = new AstCCast{fl, lhsp, nodep}; }
|
||||
if (nodep->isQuad() && !rhsp->isQuad()) { rhsp = new AstCCast{fl, rhsp, nodep}; }
|
||||
AstNode* const newp = new AstOr{
|
||||
AstNodeExpr* const newp = new AstOr{
|
||||
fl, new AstShiftL{fl, lhsp, new AstConst{fl, rhsshift}, nodep->width()}, rhsp};
|
||||
newp->dtypeFrom(nodep); // Unsigned
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
|
|
@ -673,8 +675,8 @@ private:
|
|||
// See under ASSIGN(WIDE)
|
||||
} else {
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* newp;
|
||||
AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* newp;
|
||||
const int lhswidth = lhsp->widthMin();
|
||||
if (lhswidth == 1) {
|
||||
UINFO(8, " REPLICATE(w1) " << nodep << endl);
|
||||
|
|
@ -707,13 +709,13 @@ private:
|
|||
UINFO(8, " Wordize ASSIGN(REPLICATE) " << nodep << endl);
|
||||
if (!doExpand(rhsp)) return false;
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* const lhsp = rhsp->lhsp();
|
||||
AstNodeExpr* const lhsp = rhsp->lhsp();
|
||||
const int lhswidth = lhsp->widthMin();
|
||||
const AstConst* const constp = VN_AS(rhsp->rhsp(), Const);
|
||||
UASSERT_OBJ(constp, rhsp, "Replication value isn't a constant. Checked earlier!");
|
||||
const uint32_t times = constp->toUInt();
|
||||
for (int w = 0; w < rhsp->widthWords(); ++w) {
|
||||
AstNode* newp;
|
||||
AstNodeExpr* newp;
|
||||
if (lhswidth == 1) {
|
||||
newp = new AstNegate{fl, lhsp->cloneTree(true)};
|
||||
// Replicate always unsigned
|
||||
|
|
@ -737,10 +739,10 @@ private:
|
|||
UINFO(8, " Wordize EQ/NEQ " << nodep << endl);
|
||||
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* newp = nullptr;
|
||||
AstNodeExpr* newp = nullptr;
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); ++w) {
|
||||
AstNode* const eqp = new AstXor{fl, newAstWordSelClone(nodep->lhsp(), w),
|
||||
newAstWordSelClone(nodep->rhsp(), w)};
|
||||
AstNodeExpr* const eqp = new AstXor{fl, newAstWordSelClone(nodep->lhsp(), w),
|
||||
newAstWordSelClone(nodep->rhsp(), w)};
|
||||
newp = newp ? new AstOr{fl, newp, eqp} : eqp;
|
||||
}
|
||||
if (VN_IS(nodep, Neq)) {
|
||||
|
|
@ -761,17 +763,17 @@ private:
|
|||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8, " Wordize REDOR " << nodep << endl);
|
||||
// -> (0!={or{for each_word{WORDSEL(lhs,#)}}}
|
||||
AstNode* newp = nullptr;
|
||||
AstNodeExpr* newp = nullptr;
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); ++w) {
|
||||
AstNode* const eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
AstNodeExpr* const eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
newp = newp ? new AstOr{fl, newp, eqp} : eqp;
|
||||
}
|
||||
newp = new AstNeq{fl, new AstConst{fl, AstConst::SizedEData(), 0}, newp};
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
} else {
|
||||
UINFO(8, " REDOR->EQ " << nodep << endl);
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* const newp = new AstNeq{
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const newp = new AstNeq{
|
||||
fl, new AstConst{fl, AstConst::WidthedValue(), longOrQuadWidth(nodep), 0}, lhsp};
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
|
|
@ -783,9 +785,9 @@ private:
|
|||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8, " Wordize REDAND " << nodep << endl);
|
||||
// -> (0!={and{for each_word{WORDSEL(lhs,#)}}}
|
||||
AstNode* newp = nullptr;
|
||||
AstNodeExpr* newp = nullptr;
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); ++w) {
|
||||
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
AstNodeExpr* eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
if (w == nodep->lhsp()->widthWords() - 1) {
|
||||
// Rather than doing a (slowish) ==##, we OR in the
|
||||
// bits that aren't part of the mask
|
||||
|
|
@ -801,8 +803,8 @@ private:
|
|||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
} else {
|
||||
UINFO(8, " REDAND->EQ " << nodep << endl);
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* const newp = new AstEq{fl, new AstConst{fl, wordMask(lhsp)}, lhsp};
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const newp = new AstEq{fl, new AstConst{fl, wordMask(lhsp)}, lhsp};
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
|
|
@ -813,9 +815,9 @@ private:
|
|||
UINFO(8, " Wordize REDXOR " << nodep << endl);
|
||||
// -> (0!={redxor{for each_word{XOR(WORDSEL(lhs,#))}}}
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* newp = nullptr;
|
||||
AstNodeExpr* newp = nullptr;
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); ++w) {
|
||||
AstNode* const eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
AstNodeExpr* const eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
newp = newp ? new AstXor{fl, newp, eqp} : eqp;
|
||||
}
|
||||
newp = new AstRedXor{fl, newp};
|
||||
|
|
|
|||
|
|
@ -174,8 +174,8 @@ class ForceConvertVisitor final : public VNVisitor {
|
|||
pushDeletep(nodep);
|
||||
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstNode* const lhsp = nodep->lhsp(); // The LValue we are forcing
|
||||
AstNode* const rhsp = nodep->rhsp(); // The value we are forcing it to
|
||||
AstNodeExpr* const lhsp = nodep->lhsp(); // The LValue we are forcing
|
||||
AstNodeExpr* const rhsp = nodep->rhsp(); // The value we are forcing it to
|
||||
|
||||
// Set corresponding enable signals to ones
|
||||
V3Number ones{lhsp, lhsp->width()};
|
||||
|
|
@ -210,7 +210,7 @@ class ForceConvertVisitor final : public VNVisitor {
|
|||
pushDeletep(nodep);
|
||||
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstNode* const lhsp = nodep->lhsp(); // The LValue we are releasing
|
||||
AstNodeExpr* const lhsp = nodep->lhsp(); // The LValue we are releasing
|
||||
|
||||
// Set corresponding enable signals to zero
|
||||
V3Number zero{lhsp, lhsp->width()};
|
||||
|
|
|
|||
|
|
@ -70,14 +70,14 @@ private:
|
|||
// Use user1p on the PIN to indicate we created an assign for this pin
|
||||
if (!nodep->user1SetOnce()) {
|
||||
// Make an ASSIGNW (expr, pin)
|
||||
AstNode* const exprp = nodep->exprp()->cloneTree(false);
|
||||
AstNodeExpr* const exprp = VN_AS(nodep->exprp(), NodeExpr)->cloneTree(false);
|
||||
UASSERT_OBJ(exprp->width() == nodep->modVarp()->width(), nodep,
|
||||
"Width mismatch, should have been handled in pinReconnectSimple");
|
||||
if (nodep->modVarp()->isInoutish()) {
|
||||
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
|
||||
} else if (nodep->modVarp()->isWritable()) {
|
||||
AstNode* const rhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(),
|
||||
m_cellp->name(), VAccess::READ);
|
||||
AstNodeExpr* const rhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(),
|
||||
m_cellp->name(), VAccess::READ);
|
||||
AstAssignW* const assp = new AstAssignW(exprp->fileline(), exprp, rhsp);
|
||||
m_cellp->addNextHere(assp);
|
||||
} else if (nodep->modVarp()->isNonOutput()) {
|
||||
|
|
@ -97,8 +97,8 @@ private:
|
|||
IfaceRefDType))) {
|
||||
// Create an AstAssignVarScope for Vars to Cells so we can
|
||||
// link with their scope later
|
||||
AstNode* const lhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(),
|
||||
m_cellp->name(), VAccess::READ);
|
||||
AstNodeExpr* const lhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(),
|
||||
m_cellp->name(), VAccess::READ);
|
||||
const AstVarRef* const refp = VN_CAST(exprp, VarRef);
|
||||
const AstVarXRef* const xrefp = VN_CAST(exprp, VarXRef);
|
||||
UASSERT_OBJ(refp || xrefp, exprp,
|
||||
|
|
@ -334,7 +334,7 @@ private:
|
|||
const int arraySelNum = rangep->littleEndian()
|
||||
? (rangep->elementsConst() - 1 - m_instSelNum)
|
||||
: m_instSelNum;
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* exprp = VN_AS(nodep->exprp(), NodeExpr)->unlinkFrBack();
|
||||
exprp = new AstArraySel(exprp->fileline(), exprp, arraySelNum);
|
||||
nodep->exprp(exprp);
|
||||
} else if (expwidth == modwidth) {
|
||||
|
|
@ -348,7 +348,7 @@ private:
|
|||
<< m_cellRangep->leftConst() << ":"
|
||||
<< m_cellRangep->rightConst() << "]");
|
||||
}
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* exprp = VN_AS(nodep->exprp(), NodeExpr)->unlinkFrBack();
|
||||
const bool inputPin = nodep->modVarp()->isNonOutput();
|
||||
if (!inputPin
|
||||
&& !VN_IS(exprp, VarRef)
|
||||
|
|
@ -489,10 +489,10 @@ class InstStatic final {
|
|||
private:
|
||||
InstStatic() = default; // Static class
|
||||
|
||||
static AstNode* extendOrSel(FileLine* fl, AstNode* rhsp, AstNode* cmpWidthp) {
|
||||
static AstNodeExpr* extendOrSel(FileLine* fl, AstNodeExpr* rhsp, AstNode* cmpWidthp) {
|
||||
if (cmpWidthp->width() > rhsp->width()) {
|
||||
rhsp = (rhsp->isSigned() ? static_cast<AstNode*>(new AstExtendS{fl, rhsp})
|
||||
: static_cast<AstNode*>(new AstExtend{fl, rhsp}));
|
||||
rhsp = (rhsp->isSigned() ? static_cast<AstNodeExpr*>(new AstExtendS{fl, rhsp})
|
||||
: static_cast<AstNodeExpr*>(new AstExtend{fl, rhsp}));
|
||||
// Need proper widthMin, which may differ from AstSel created above
|
||||
rhsp->dtypeFrom(cmpWidthp);
|
||||
} else if (cmpWidthp->width() < rhsp->width()) {
|
||||
|
|
@ -553,7 +553,7 @@ public:
|
|||
// Make a new temp wire
|
||||
// if (1 || debug() >= 9) pinp->dumpTree(cout, "-in_pin:");
|
||||
V3Inst::checkOutputShort(pinp);
|
||||
AstNode* const pinexprp = pinp->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* const pinexprp = VN_AS(pinp->exprp(), NodeExpr)->unlinkFrBack();
|
||||
const string newvarname
|
||||
= (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
|
||||
// Prevent name conflict if both tri & non-tri add signals
|
||||
|
|
@ -568,12 +568,12 @@ public:
|
|||
" direct one-to-one connection (without any expression)");
|
||||
} else if (pinVarp->isWritable()) {
|
||||
// See also V3Inst
|
||||
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, VAccess::READ);
|
||||
AstNodeExpr* rhsp = new AstVarRef(pinp->fileline(), newvarp, VAccess::READ);
|
||||
UINFO(5, "pinRecon width " << pinVarp->width() << " >? " << rhsp->width() << " >? "
|
||||
<< pinexprp->width() << endl);
|
||||
rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp);
|
||||
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, VAccess::WRITE));
|
||||
AstNode* const rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp);
|
||||
AstNodeExpr* const rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp);
|
||||
assignp = new AstAssignW(pinp->fileline(), pinexprp, rhsSelp);
|
||||
} else {
|
||||
// V3 width should have range/extended to make the widths correct
|
||||
|
|
|
|||
|
|
@ -1223,7 +1223,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
// new value.
|
||||
if (v3Global.opt.hasParameter(nodep->name())) {
|
||||
const string svalue = v3Global.opt.parameter(nodep->name());
|
||||
if (AstNode* const valuep
|
||||
if (AstConst* const valuep
|
||||
= AstConst::parseParamLiteral(nodep->fileline(), svalue)) {
|
||||
UINFO(9, " replace parameter " << nodep << endl);
|
||||
UINFO(9, " with " << valuep << endl);
|
||||
|
|
@ -1366,7 +1366,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
// DOT(x, SELLOOPVARS(var, loops)) -> SELLOOPVARS(DOT(x, var), loops)
|
||||
if (AstDot* const dotp = VN_CAST(nodep->arrayp(), Dot)) {
|
||||
if (AstSelLoopVars* const loopvarsp = VN_CAST(dotp->rhsp(), SelLoopVars)) {
|
||||
AstNode* const fromp = loopvarsp->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* const fromp = loopvarsp->fromp()->unlinkFrBack();
|
||||
loopvarsp->unlinkFrBack();
|
||||
dotp->replaceWith(loopvarsp);
|
||||
dotp->rhsp(fromp);
|
||||
|
|
@ -1540,7 +1540,7 @@ private:
|
|||
if (!cellp) {
|
||||
nodep->v3error("In defparam, instance " << nodep->path() << " never declared");
|
||||
} else {
|
||||
AstNode* const exprp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const exprp = nodep->rhsp()->unlinkFrBack();
|
||||
UINFO(9, "Defparam cell " << nodep->path() << "." << nodep->name() << " attach-to "
|
||||
<< cellp << " <= " << exprp << endl);
|
||||
// Don't need to check the name of the defparam exists. V3Param does.
|
||||
|
|
@ -2295,7 +2295,7 @@ private:
|
|||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else { // Dot midpoint
|
||||
AstNode* newp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* newp = nodep->rhsp()->unlinkFrBack();
|
||||
if (m_ds.m_unresolved) {
|
||||
AstCellRef* const crp = new AstCellRef(nodep->fileline(), nodep->name(),
|
||||
nodep->lhsp()->unlinkFrBack(), newp);
|
||||
|
|
@ -2358,8 +2358,8 @@ private:
|
|||
return;
|
||||
} else if (m_ds.m_dotPos == DP_MEMBER) {
|
||||
// Found a Var, everything following is membership. {scope}.{var}.HERE {member}
|
||||
AstNode* const varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
|
||||
AstNode* const newp
|
||||
AstNodeExpr* const varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const newp
|
||||
= new AstMemberSel(nodep->fileline(), varEtcp, VFlagChildDType(), nodep->name());
|
||||
if (m_ds.m_dotErr) {
|
||||
nodep->unlinkFrBack(); // Avoid circular node loop on errors
|
||||
|
|
@ -2545,7 +2545,8 @@ private:
|
|||
m_ds.m_dotPos = DP_SCOPE;
|
||||
UINFO(9, " modport -> iface varref " << foundp->nodep() << endl);
|
||||
// We lose the modport name here, so we cannot detect mismatched modports.
|
||||
AstNode* newp = new AstVarRef{nodep->fileline(), ifaceRefVarp, VAccess::READ};
|
||||
AstNodeExpr* newp
|
||||
= new AstVarRef{nodep->fileline(), ifaceRefVarp, VAccess::READ};
|
||||
auto* const cellarrayrefp = VN_CAST(m_ds.m_unlinkedScopep, CellArrayRef);
|
||||
if (cellarrayrefp) {
|
||||
// iface[vec].modport became CellArrayRef(iface, lsb)
|
||||
|
|
@ -2811,8 +2812,8 @@ private:
|
|||
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) {
|
||||
// Found a Var, everything following is method call.
|
||||
// {scope}.{var}.HERE {method} ( ARGS )
|
||||
AstNode* const varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
|
||||
AstNode* argsp = nullptr;
|
||||
AstNodeExpr* const varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* argsp = nullptr;
|
||||
if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext();
|
||||
AstNode* const newp = new AstMethodCall(nodep->fileline(), varEtcp, VFlagChildDType(),
|
||||
nodep->name(), argsp);
|
||||
|
|
@ -2965,7 +2966,7 @@ private:
|
|||
}
|
||||
}
|
||||
if (m_ds.m_unresolved && m_ds.m_dotPos == DP_SCOPE) {
|
||||
AstNode* const exprp = nodep->bitp()->unlinkFrBack();
|
||||
AstNodeExpr* const exprp = nodep->bitp()->unlinkFrBack();
|
||||
AstCellArrayRef* const newp
|
||||
= new AstCellArrayRef(nodep->fileline(), nodep->fromp()->name(), exprp);
|
||||
nodep->replaceWith(newp);
|
||||
|
|
|
|||
|
|
@ -205,8 +205,8 @@ private:
|
|||
UASSERT_OBJ(nodep, constp, "Expecting CONST");
|
||||
AstConst* const newconstp = constp->cloneTree(true);
|
||||
|
||||
AstNode* const storetop = nodep->thsp();
|
||||
AstNode* const valuep = nodep->rhsp();
|
||||
AstNodeExpr* const storetop = nodep->thsp();
|
||||
AstNodeExpr* const valuep = nodep->rhsp();
|
||||
|
||||
storetop->unlinkFrBack();
|
||||
valuep->unlinkFrBack();
|
||||
|
|
@ -247,7 +247,7 @@ private:
|
|||
insertBeforeStmt(nodep, varp);
|
||||
|
||||
// Define what operation will we be doing
|
||||
AstNode* operp;
|
||||
AstNodeExpr* operp;
|
||||
if (VN_IS(nodep, PostSub) || VN_IS(nodep, PreSub)) {
|
||||
operp = new AstSub(fl, new AstVarRef(fl, varrefp->varp(), VAccess::READ), newconstp);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ private:
|
|||
// So later optimizations don't need to deal with them,
|
||||
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
||||
// Note var can be signed or unsigned based on original number.
|
||||
AstNode* const countp = nodep->countp()->unlinkFrBackWithNext();
|
||||
AstNodeExpr* const countp = nodep->countp()->unlinkFrBackWithNext();
|
||||
const string name = string("__Vrepeat") + cvtToStr(m_modRepeatNum++);
|
||||
// Spec says value is integral, if negative is ignored
|
||||
AstVar* const varp
|
||||
|
|
@ -172,8 +172,8 @@ private:
|
|||
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE),
|
||||
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::READ),
|
||||
new AstConst(nodep->fileline(), 1)));
|
||||
AstNode* const zerosp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0);
|
||||
AstNode* const condp = new AstGtS(
|
||||
AstNodeExpr* const zerosp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0);
|
||||
AstNodeExpr* const condp = new AstGtS(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::READ), zerosp);
|
||||
AstNode* const bodysp = nodep->stmtsp();
|
||||
if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
|
|
@ -210,7 +210,7 @@ private:
|
|||
m_loopInc = true;
|
||||
iterateAndNextNull(nodep->incsp());
|
||||
}
|
||||
AstNode* const condp = nodep->condp() ? nodep->condp()->unlinkFrBack() : nullptr;
|
||||
AstNodeExpr* const condp = nodep->condp() ? nodep->condp()->unlinkFrBack() : nullptr;
|
||||
AstNode* const bodyp = nodep->stmtsp() ? nodep->stmtsp()->unlinkFrBack() : nullptr;
|
||||
AstNode* const incsp = nodep->incsp() ? nodep->incsp()->unlinkFrBack() : nullptr;
|
||||
AstWhile* const whilep = new AstWhile{nodep->fileline(), condp, bodyp, incsp};
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ private:
|
|||
FileLine* const flp = nodep->fileline();
|
||||
for (int i = left; i != (right + increment); i += increment, offset_from_init++) {
|
||||
const string name = nodep->name() + cvtToStr(i);
|
||||
AstNode* valuep = nullptr;
|
||||
AstNodeExpr* valuep = nullptr;
|
||||
if (nodep->valuep()) {
|
||||
valuep
|
||||
= new AstAdd(flp, nodep->valuep()->cloneTree(true),
|
||||
|
|
@ -266,7 +266,7 @@ private:
|
|||
newfl->warnOff(V3ErrorCode::PROCASSWIRE, true);
|
||||
auto* const assp
|
||||
= new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), VAccess::WRITE),
|
||||
nodep->valuep()->unlinkFrBack());
|
||||
VN_AS(nodep->valuep()->unlinkFrBack(), NodeExpr));
|
||||
if (nodep->lifetime().isAutomatic()) {
|
||||
nodep->addNextHere(new AstInitialAutomatic{newfl, assp});
|
||||
} else {
|
||||
|
|
@ -274,9 +274,9 @@ private:
|
|||
}
|
||||
} // 4. Under blocks, it's an initial value to be under an assign
|
||||
else {
|
||||
nodep->addNextHere(new AstAssign(fl,
|
||||
new AstVarRef(fl, nodep->name(), VAccess::WRITE),
|
||||
nodep->valuep()->unlinkFrBack()));
|
||||
nodep->addNextHere(
|
||||
new AstAssign(fl, new AstVarRef(fl, nodep->name(), VAccess::WRITE),
|
||||
VN_AS(nodep->valuep()->unlinkFrBack(), NodeExpr)));
|
||||
}
|
||||
}
|
||||
if (nodep->isIfaceRef() && !nodep->isIfaceParent() && !v3Global.opt.topIfacesSupported()) {
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ bool areDisjoint(const std::set<const AstVar*>& a, const std::set<const AstVar*>
|
|||
// Structure containing information required for code motion/merging
|
||||
|
||||
struct StmtProperties {
|
||||
AstNode* m_condp = nullptr; // The condition expression, if a conditional node
|
||||
AstNodeExpr* m_condp = nullptr; // The condition expression, if a conditional node
|
||||
std::set<const AstVar*> m_rdVars; // Variables read by this statement
|
||||
std::set<const AstVar*> m_wrVars; // Variables writen by this statement
|
||||
bool m_isFence = false; // Nothing should move across this statement, nor should it be merged
|
||||
|
|
@ -178,8 +178,8 @@ class CodeMotionAnalysisVisitor final : public VNVisitor {
|
|||
StmtProperties* m_propsp = nullptr; // StmtProperties structure of current AstNodeStmt
|
||||
|
||||
// Extract condition expression from a megeable conditional statement, if any
|
||||
static AstNode* extractCondition(const AstNodeStmt* nodep) {
|
||||
AstNode* conditionp = nullptr;
|
||||
static AstNodeExpr* extractCondition(const AstNodeStmt* nodep) {
|
||||
AstNodeExpr* conditionp = nullptr;
|
||||
if (const AstNodeAssign* const assignp = VN_CAST(nodep, NodeAssign)) {
|
||||
if (AstNodeCond* const conditionalp = extractCondFromRhs(assignp->rhsp())) {
|
||||
conditionp = conditionalp->condp();
|
||||
|
|
@ -199,7 +199,7 @@ class CodeMotionAnalysisVisitor final : public VNVisitor {
|
|||
m_propsp = &m_stmtProperties(nodep);
|
||||
|
||||
// Extract condition from statement
|
||||
if (AstNode* const condp = extractCondition(nodep)) {
|
||||
if (AstNodeExpr* const condp = extractCondition(nodep)) {
|
||||
// Remember condition node. We always need this as it is used in the later
|
||||
// traversal.
|
||||
m_propsp->m_condp = condp;
|
||||
|
|
@ -447,7 +447,7 @@ private:
|
|||
VDouble0 m_statLongestList; // Statistic tracking
|
||||
|
||||
AstNode* m_mgFirstp = nullptr; // First node in merged sequence
|
||||
AstNode* m_mgCondp = nullptr; // The condition of the first node
|
||||
AstNodeExpr* m_mgCondp = nullptr; // The condition of the first node
|
||||
const AstNode* m_mgLastp = nullptr; // Last node in merged sequence
|
||||
const AstNode* m_mgNextp = nullptr; // Next node in list being examined
|
||||
uint32_t m_listLenght = 0; // Length of current list
|
||||
|
|
@ -578,10 +578,10 @@ private:
|
|||
// Apply (1'b1 & _) cleaning mask if necessary. This is required because this pass is after
|
||||
// V3Clean, and sometimes we have an AstAnd with a 1-bit condition on one side, but a more
|
||||
// than 1-bit value on the other side, so we need to keep only the LSB.
|
||||
static AstNode* maskLsb(AstNode* nodep) {
|
||||
static AstNodeExpr* maskLsb(AstNodeExpr* nodep) {
|
||||
if (yieldsOneOrZero(nodep)) return nodep;
|
||||
// Otherwise apply masking
|
||||
AstNode* const maskp = new AstConst{nodep->fileline(), AstConst::BitTrue()};
|
||||
AstConst* const maskp = new AstConst{nodep->fileline(), AstConst::BitTrue()};
|
||||
// Mask on left, as conventional
|
||||
return new AstAnd{nodep->fileline(), maskp, nodep};
|
||||
}
|
||||
|
|
@ -589,11 +589,11 @@ private:
|
|||
// Fold the RHS expression of an assignment assuming the given condition state.
|
||||
// Unlink bits from the RHS which is only used once, and can be reused (is an unomdified
|
||||
// sub-tree). What remains of the RHS is expected to be deleted by the caller.
|
||||
AstNode* foldAndUnlink(AstNode* rhsp, bool condTrue) {
|
||||
AstNodeExpr* foldAndUnlink(AstNodeExpr* rhsp, bool condTrue) {
|
||||
if (rhsp->sameTree(m_mgCondp)) {
|
||||
return new AstConst{rhsp->fileline(), AstConst::BitTrue{}, condTrue};
|
||||
} else if (const AstNodeCond* const condp = extractCondFromRhs(rhsp)) {
|
||||
AstNode* const resp
|
||||
AstNodeExpr* const resp
|
||||
= condTrue ? condp->thenp()->unlinkFrBack() : condp->elsep()->unlinkFrBack();
|
||||
if (condp == rhsp) return resp;
|
||||
if (const AstAnd* const andp = VN_CAST(rhsp, And)) {
|
||||
|
|
@ -671,7 +671,7 @@ private:
|
|||
++m_statMergedItems;
|
||||
if (AstNodeAssign* const assignp = VN_CAST(currp, NodeAssign)) {
|
||||
// Unlink RHS and clone to get the 2 assignments (reusing assignp)
|
||||
AstNode* const rhsp = assignp->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = assignp->rhsp()->unlinkFrBack();
|
||||
AstNodeAssign* const thenp = assignp;
|
||||
AstNodeAssign* const elsep = assignp->cloneTree(false);
|
||||
// Construct the new RHSs and add to branches
|
||||
|
|
@ -739,7 +739,7 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool addToList(AstNodeStmt* nodep, AstNode* condp) {
|
||||
bool addToList(AstNodeStmt* nodep, AstNodeExpr* condp) {
|
||||
// Set up head of new list if node is first in list
|
||||
if (!m_mgFirstp) {
|
||||
UASSERT_OBJ(condp, nodep, "Cannot start new list without condition");
|
||||
|
|
@ -825,7 +825,7 @@ private:
|
|||
|
||||
// VISITORS
|
||||
void visit(AstNodeAssign* nodep) override {
|
||||
if (AstNode* const condp = (*m_stmtPropertiesp)(nodep).m_condp) {
|
||||
if (AstNodeExpr* const condp = (*m_stmtPropertiesp)(nodep).m_condp) {
|
||||
// Check if mergeable
|
||||
if (!checkOrMakeMergeable(nodep)) return;
|
||||
// Close potentially incompatible pending merge
|
||||
|
|
|
|||
|
|
@ -69,14 +69,14 @@ void V3ParseImp::parserClear() {
|
|||
//======================================================================
|
||||
// V3ParseGrammar functions requiring bison state
|
||||
|
||||
AstArg* V3ParseGrammar::argWrapList(AstNode* nodep) {
|
||||
AstArg* V3ParseGrammar::argWrapList(AstNodeExpr* nodep) {
|
||||
// Convert list of expressions to list of arguments
|
||||
if (!nodep) return nullptr;
|
||||
AstArg* outp = nullptr;
|
||||
AstBegin* const tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", nodep};
|
||||
while (nodep) {
|
||||
AstNode* const nextp = nodep->nextp();
|
||||
AstNode* const exprp = nodep->unlinkFrBack();
|
||||
AstNodeExpr* const nextp = VN_AS(nodep->nextp(), NodeExpr);
|
||||
AstNodeExpr* const exprp = nodep->unlinkFrBack();
|
||||
nodep = nextp;
|
||||
outp = AstNode::addNext(outp, new AstArg{exprp->fileline(), "", exprp});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ private:
|
|||
return (VN_IS(nodep->lhsp(), VarRef) && !AstVar::scVarRecurse(nodep->lhsp())
|
||||
&& VN_IS(nodep->rhsp(), Const));
|
||||
}
|
||||
void checkNode(AstNode* nodep) {
|
||||
void checkNode(AstNodeExpr* nodep) {
|
||||
// Consider adding a temp for this expression.
|
||||
// We need to avoid adding temps to the following:
|
||||
// ASSIGN(x, *here*)
|
||||
|
|
@ -116,7 +116,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void createDeepTemp(AstNode* nodep, bool noSubst) {
|
||||
void createDeepTemp(AstNodeExpr* nodep, bool noSubst) {
|
||||
if (nodep->user1SetOnce()) return; // Only add another assignment for this node
|
||||
|
||||
VNRelinker relinker;
|
||||
|
|
@ -236,7 +236,7 @@ private:
|
|||
&& nodep->width() < (1LL << nodep->rhsp()->widthMin())) {
|
||||
VNRelinker replaceHandle;
|
||||
nodep->unlinkFrBack(&replaceHandle);
|
||||
AstNode* constzerop;
|
||||
AstNodeExpr* constzerop;
|
||||
const int m1value
|
||||
= nodep->widthMin() - 1; // Constant of width-1; not changing dtype width
|
||||
if (nodep->signedFlavor()) {
|
||||
|
|
@ -253,7 +253,7 @@ private:
|
|||
}
|
||||
constzerop->dtypeFrom(nodep); // unsigned
|
||||
|
||||
AstNode* const constwidthp
|
||||
AstNodeExpr* const constwidthp
|
||||
= new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
nodep->rhsp()->widthMin(), m1value);
|
||||
constwidthp->dtypeFrom(nodep->rhsp()); // unsigned
|
||||
|
|
@ -352,8 +352,9 @@ private:
|
|||
// There's another display next; we can just wait to flush
|
||||
} else {
|
||||
UINFO(4, "Autoflush " << nodep << endl);
|
||||
nodep->addNextHere(new AstFFlush(nodep->fileline(),
|
||||
AstNode::cloneTreeNull(nodep->filep(), true)));
|
||||
nodep->addNextHere(
|
||||
new AstFFlush{nodep->fileline(),
|
||||
VN_AS(AstNode::cloneTreeNull(nodep->filep(), true), NodeExpr)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -361,7 +362,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
// Any strings sent to a display must be var of string data type,
|
||||
// to avoid passing a pointer to a temporary.
|
||||
for (AstNode* expp = nodep->exprsp(); expp; expp = expp->nextp()) {
|
||||
for (AstNodeExpr* expp = nodep->exprsp(); expp; expp = VN_AS(expp->nextp(), NodeExpr)) {
|
||||
if (expp->dtypep()->basicp() && expp->dtypep()->basicp()->isString()
|
||||
&& !VN_IS(expp, VarRef)) {
|
||||
createDeepTemp(expp, true);
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ private:
|
|||
= new AstVarRef{fl, enumValueTabp(enumDtp), VAccess::READ};
|
||||
tabRefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
|
||||
AstRand* const randp = new AstRand{fl, nullptr, false};
|
||||
AstNode* const moddivp = new AstModDiv{
|
||||
AstNodeExpr* const moddivp = new AstModDiv{
|
||||
fl, randp, new AstConst{fl, static_cast<uint32_t>(enumDtp->itemCount())}};
|
||||
randp->dtypep(varrefp->findBasicDType(VBasicDTypeKwd::UINT32));
|
||||
moddivp->dtypep(enumDtp);
|
||||
|
|
@ -296,7 +296,7 @@ private:
|
|||
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
AstNode* const condp = itemp->condsp()->unlinkFrBack();
|
||||
AstNodeExpr* const condp = itemp->condsp()->unlinkFrBack();
|
||||
sump
|
||||
= new AstAdd{condp->fileline(), sump, new AstExtend{itemp->fileline(), condp, 64}};
|
||||
AstNode* const stmtsp
|
||||
|
|
@ -318,7 +318,7 @@ private:
|
|||
ifsp->addElsesp(dispp);
|
||||
|
||||
AstNode* newp = randVarp;
|
||||
AstNode* randp = new AstRand{fl, nullptr, false};
|
||||
AstNodeExpr* randp = new AstRand{fl, nullptr, false};
|
||||
randp->dtypeSetUInt64();
|
||||
newp->addNext(new AstAssign{fl, new AstVarRef{fl, randVarp, VAccess::WRITE},
|
||||
new AstAdd{fl, new AstConst{fl, AstConst::Unsized64{}, 1},
|
||||
|
|
|
|||
|
|
@ -107,8 +107,8 @@ private:
|
|||
|
||||
AstNode* const initp = new AstAssign(fl, new AstVarRef(fl, itp, VAccess::WRITE),
|
||||
new AstConst(fl, m_mgIndexLo));
|
||||
AstNode* const condp = new AstLte(fl, new AstVarRef(fl, itp, VAccess::READ),
|
||||
new AstConst(fl, m_mgIndexHi));
|
||||
AstNodeExpr* const condp = new AstLte(fl, new AstVarRef(fl, itp, VAccess::READ),
|
||||
new AstConst(fl, m_mgIndexHi));
|
||||
AstNode* const incp = new AstAssign(
|
||||
fl, new AstVarRef(fl, itp, VAccess::WRITE),
|
||||
new AstAdd(fl, new AstConst(fl, 1), new AstVarRef(fl, itp, VAccess::READ)));
|
||||
|
|
@ -118,15 +118,15 @@ private:
|
|||
whilep->addStmtsp(bodyp);
|
||||
|
||||
// Replace constant index with new loop index
|
||||
AstNode* const offsetp
|
||||
AstNodeExpr* const offsetp
|
||||
= m_mgOffset == 0 ? nullptr : new AstConst(fl, std::abs(m_mgOffset));
|
||||
AstNode* const lbitp = m_mgSelLp->bitp();
|
||||
AstNode* const lvrefp = new AstVarRef(fl, itp, VAccess::READ);
|
||||
AstNodeExpr* const lbitp = m_mgSelLp->bitp();
|
||||
AstNodeExpr* const lvrefp = new AstVarRef(fl, itp, VAccess::READ);
|
||||
lbitp->replaceWith(m_mgOffset > 0 ? new AstAdd(fl, lvrefp, offsetp) : lvrefp);
|
||||
VL_DO_DANGLING(lbitp->deleteTree(), lbitp);
|
||||
if (m_mgSelRp) { // else constant and no replace
|
||||
AstNode* const rbitp = m_mgSelRp->bitp();
|
||||
AstNode* const rvrefp = new AstVarRef(fl, itp, VAccess::READ);
|
||||
AstNodeExpr* const rbitp = m_mgSelRp->bitp();
|
||||
AstNodeExpr* const rvrefp = new AstVarRef(fl, itp, VAccess::READ);
|
||||
rbitp->replaceWith(m_mgOffset < 0 ? new AstAdd(fl, rvrefp, offsetp) : rvrefp);
|
||||
VL_DO_DANGLING(rbitp->deleteTree(), lbitp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class SenExprBuilder final {
|
|||
}
|
||||
|
||||
// METHODS
|
||||
AstNode* getCurr(AstNode* exprp) {
|
||||
AstNodeExpr* getCurr(AstNodeExpr* exprp) {
|
||||
// For simple expressions like varrefs or selects, just use them directly
|
||||
if (isSimpleExpr(exprp)) return exprp->cloneTree(false);
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ class SenExprBuilder final {
|
|||
}
|
||||
return new AstVarRef{flp, currp, VAccess::READ};
|
||||
}
|
||||
AstVarScope* getPrev(AstNode* exprp) {
|
||||
AstVarScope* getPrev(AstNodeExpr* exprp) {
|
||||
FileLine* const flp = exprp->fileline();
|
||||
const auto rdCurr = [=]() { return getCurr(exprp); };
|
||||
|
||||
|
|
@ -150,9 +150,9 @@ class SenExprBuilder final {
|
|||
return prevp;
|
||||
}
|
||||
|
||||
std::pair<AstNode*, bool> createTerm(AstSenItem* senItemp) {
|
||||
std::pair<AstNodeExpr*, bool> createTerm(AstSenItem* senItemp) {
|
||||
FileLine* const flp = senItemp->fileline();
|
||||
AstNode* const senp = senItemp->sensp();
|
||||
AstNodeExpr* const senp = senItemp->sensp();
|
||||
|
||||
const auto currp = [=]() { return getCurr(senp); };
|
||||
const auto prevp = [=]() { return new AstVarRef{flp, getPrev(senp), VAccess::READ}; };
|
||||
|
|
@ -215,14 +215,14 @@ class SenExprBuilder final {
|
|||
public:
|
||||
// Returns the expression computing the trigger, and a bool indicating that
|
||||
// this trigger should be fired on the first evaluation (at initialization)
|
||||
std::pair<AstNode*, bool> build(const AstSenTree* senTreep) {
|
||||
std::pair<AstNodeExpr*, bool> build(const AstSenTree* senTreep) {
|
||||
FileLine* const flp = senTreep->fileline();
|
||||
AstNode* resultp = nullptr;
|
||||
AstNodeExpr* resultp = nullptr;
|
||||
bool firedAtInitialization = false;
|
||||
for (AstSenItem* senItemp = senTreep->sensesp(); senItemp;
|
||||
senItemp = VN_AS(senItemp->nextp(), SenItem)) {
|
||||
const auto& pair = createTerm(senItemp);
|
||||
if (AstNode* const termp = pair.first) {
|
||||
if (AstNodeExpr* const termp = pair.first) {
|
||||
resultp = resultp ? new AstOr{flp, resultp, termp} : termp;
|
||||
firedAtInitialization |= pair.second;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ public:
|
|||
for (V3TaskConnects::iterator conIt = tconnects->begin();
|
||||
conIt != tconnects->end(); ++conIt) {
|
||||
AstVar* const portp = conIt->first;
|
||||
AstNode* const pinp = conIt->second->exprp();
|
||||
AstNodeExpr* const pinp = conIt->second->exprp();
|
||||
AstNodeDType* const dtypep = pinp->dtypep();
|
||||
if (AstConst* const valp = fetchConstNull(pinp)) {
|
||||
stack << "\n " << portp->prettyName() << " = "
|
||||
|
|
@ -248,26 +248,26 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
void newValue(AstNode* nodep, const AstNode* valuep) {
|
||||
void newValue(AstNode* nodep, const AstNodeExpr* valuep) {
|
||||
if (const AstConst* const constp = VN_CAST(valuep, Const)) {
|
||||
newConst(nodep)->num().opAssign(constp->num());
|
||||
} else if (fetchValueNull(nodep) != valuep) {
|
||||
// const_cast, as clonep() is set on valuep, but nothing should care
|
||||
setValue(nodep, newTrackedClone(const_cast<AstNode*>(valuep)));
|
||||
setValue(nodep, newTrackedClone(const_cast<AstNodeExpr*>(valuep)));
|
||||
}
|
||||
}
|
||||
void newOutValue(AstNode* nodep, const AstNode* valuep) {
|
||||
void newOutValue(AstNode* nodep, const AstNodeExpr* valuep) {
|
||||
if (const AstConst* const constp = VN_CAST(valuep, Const)) {
|
||||
newOutConst(nodep)->num().opAssign(constp->num());
|
||||
} else if (fetchOutValueNull(nodep) != valuep) {
|
||||
// const_cast, as clonep() is set on valuep, but nothing should care
|
||||
setOutValue(nodep, newTrackedClone(const_cast<AstNode*>(valuep)));
|
||||
setOutValue(nodep, newTrackedClone(const_cast<AstNodeExpr*>(valuep)));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
AstNode* newTrackedClone(AstNode* nodep) {
|
||||
AstNode* const newp = nodep->cloneTree(false);
|
||||
AstNodeExpr* newTrackedClone(AstNodeExpr* nodep) {
|
||||
AstNodeExpr* const newp = nodep->cloneTree(false);
|
||||
m_reclaimValuesp.push_back(newp);
|
||||
return newp;
|
||||
}
|
||||
|
|
@ -293,16 +293,16 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
AstNode* fetchValueNull(AstNode* nodep) { return nodep->user3p(); }
|
||||
AstNodeExpr* fetchValueNull(AstNode* nodep) { return VN_AS(nodep->user3p(), NodeExpr); }
|
||||
|
||||
private:
|
||||
AstNode* fetchOutValueNull(AstNode* nodep) { return nodep->user2p(); }
|
||||
AstNodeExpr* fetchOutValueNull(AstNode* nodep) { return VN_AS(nodep->user2p(), NodeExpr); }
|
||||
AstConst* fetchConstNull(AstNode* nodep) { return VN_CAST(fetchValueNull(nodep), Const); }
|
||||
AstConst* fetchOutConstNull(AstNode* nodep) {
|
||||
return VN_CAST(fetchOutValueNull(nodep), Const);
|
||||
}
|
||||
AstNode* fetchValue(AstNode* nodep) {
|
||||
AstNode* const valuep = fetchValueNull(nodep);
|
||||
AstNodeExpr* fetchValue(AstNode* nodep) {
|
||||
AstNodeExpr* const valuep = fetchValueNull(nodep);
|
||||
UASSERT_OBJ(valuep, nodep, "No value found for node.");
|
||||
// UINFO(9, " fetch val " << *valuep << " on " << nodep << endl);
|
||||
return valuep;
|
||||
|
|
@ -332,12 +332,12 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void setValue(AstNode* nodep, const AstNode* valuep) {
|
||||
void setValue(AstNode* nodep, const AstNodeExpr* valuep) {
|
||||
UASSERT_OBJ(valuep, nodep, "Simulate setting null value");
|
||||
UINFO(9, " set val " << valuep->name() << " on " << nodep << endl);
|
||||
nodep->user3p((void*)valuep);
|
||||
}
|
||||
void setOutValue(AstNode* nodep, const AstNode* valuep) {
|
||||
void setOutValue(AstNode* nodep, const AstNodeExpr* valuep) {
|
||||
UASSERT_OBJ(valuep, nodep, "Simulate setting null value");
|
||||
UINFO(9, " set oval " << valuep->name() << " on " << nodep << endl);
|
||||
nodep->user2p((void*)valuep);
|
||||
|
|
@ -386,7 +386,7 @@ private:
|
|||
// True to jump over this node - all visitors must call this up front
|
||||
return (m_jumpp && m_jumpp->labelp() != nodep);
|
||||
}
|
||||
void assignOutValue(AstNodeAssign* nodep, AstNode* vscp, const AstNode* valuep) {
|
||||
void assignOutValue(AstNodeAssign* nodep, AstNode* vscp, const AstNodeExpr* valuep) {
|
||||
if (VN_IS(nodep, AssignDly)) {
|
||||
// Don't do setValue, as value isn't yet visible to following statements
|
||||
newOutValue(vscp, valuep);
|
||||
|
|
@ -443,10 +443,10 @@ private:
|
|||
}
|
||||
vscp->user1(vscp->user1() | VU_RV);
|
||||
const bool isConst = nodep->varp()->isParam() && nodep->varp()->valuep();
|
||||
AstNode* const valuep
|
||||
AstNodeExpr* const valuep
|
||||
= isConst ? fetchValueNull(nodep->varp()->valuep()) : nullptr;
|
||||
if (isConst
|
||||
&& valuep) { // Propagate PARAM constants for constant function analysis
|
||||
// Propagate PARAM constants for constant function analysis
|
||||
if (isConst && valuep) {
|
||||
if (!m_checkOnly && optimizable()) newValue(vscp, valuep);
|
||||
} else {
|
||||
if (m_checkOnly) varRefCb(nodep);
|
||||
|
|
@ -458,7 +458,7 @@ private:
|
|||
"LHS varref should be handled in AstAssign visitor.");
|
||||
{
|
||||
// Return simulation value - copy by reference instead of value for speed
|
||||
AstNode* valuep = fetchValueNull(vscp);
|
||||
AstNodeExpr* valuep = fetchValueNull(vscp);
|
||||
if (!valuep) {
|
||||
if (m_params) {
|
||||
clearOptimizable(
|
||||
|
|
@ -697,7 +697,7 @@ private:
|
|||
m_reclaimValuesp.push_back(initp);
|
||||
}
|
||||
const uint32_t index = fetchConst(selp->bitp())->toUInt();
|
||||
AstNode* const valuep = newTrackedClone(fetchValue(nodep->rhsp()));
|
||||
AstNodeExpr* const valuep = newTrackedClone(fetchValue(nodep->rhsp()));
|
||||
UINFO(9, " set val[" << index << "] = " << valuep << endl);
|
||||
// Values are in the "real" tree under the InitArray so can eventually extract it,
|
||||
// Not in the usual setValue (pointed to by user2/3p)
|
||||
|
|
@ -803,7 +803,7 @@ private:
|
|||
if (AstInitArray* const initp = VN_CAST(fetchValueNull(nodep->fromp()), InitArray)) {
|
||||
AstConst* const indexp = fetchConst(nodep->bitp());
|
||||
const uint32_t offset = indexp->num().toUInt();
|
||||
AstNode* const itemp = initp->getIndexDefaultedValuep(offset);
|
||||
AstNodeExpr* const itemp = initp->getIndexDefaultedValuep(offset);
|
||||
if (!itemp) {
|
||||
clearOptimizable(nodep, "Array initialization has too few elements, need element "
|
||||
+ cvtToStr(offset));
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class SliceVisitor final : public VNVisitor {
|
|||
bool m_assignError = false; // True if the current assign already has an error
|
||||
|
||||
// METHODS
|
||||
AstNode* cloneAndSel(AstNode* nodep, int elements, int offset) {
|
||||
AstNodeExpr* cloneAndSel(AstNode* nodep, int elements, int offset) {
|
||||
// Insert an ArraySel, except for a few special cases
|
||||
const AstUnpackArrayDType* const arrayp
|
||||
= VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType);
|
||||
|
|
@ -73,7 +73,8 @@ class SliceVisitor final : public VNVisitor {
|
|||
V3Error::incErrors(); // Otherwise might infinite loop
|
||||
}
|
||||
m_assignError = true;
|
||||
return nodep->cloneTree(false); // Likely will cause downstream errors
|
||||
// Likely will cause downstream errors
|
||||
return VN_AS(nodep, NodeExpr)->cloneTree(false);
|
||||
}
|
||||
if (arrayp->rangep()->elementsConst() != elements) {
|
||||
if (!m_assignError) {
|
||||
|
|
@ -85,19 +86,18 @@ class SliceVisitor final : public VNVisitor {
|
|||
elements = 1;
|
||||
offset = 0;
|
||||
}
|
||||
AstNode* newp;
|
||||
AstNodeExpr* newp;
|
||||
if (const AstInitArray* const initp = VN_CAST(nodep, InitArray)) {
|
||||
UINFO(9, " cloneInitArray(" << elements << "," << offset << ") " << nodep << endl);
|
||||
const int leOffset = !arrayp->rangep()->littleEndian()
|
||||
? arrayp->rangep()->elementsConst() - 1 - offset
|
||||
: offset;
|
||||
AstNode* itemp = initp->getIndexDefaultedValuep(leOffset);
|
||||
AstNodeExpr* const itemp = initp->getIndexDefaultedValuep(leOffset);
|
||||
if (!itemp) {
|
||||
nodep->v3error("Array initialization has too few elements, need element "
|
||||
<< offset);
|
||||
itemp = initp->initsp();
|
||||
}
|
||||
newp = itemp->cloneTree(false);
|
||||
newp = itemp ? itemp->cloneTree(false) : new AstConst{nodep->fileline(), 0};
|
||||
} else if (AstNodeCond* const snodep = VN_CAST(nodep, NodeCond)) {
|
||||
UINFO(9, " cloneCond(" << elements << "," << offset << ") " << nodep << endl);
|
||||
return snodep->cloneType(snodep->condp()->cloneTree(false),
|
||||
|
|
@ -116,14 +116,16 @@ class SliceVisitor final : public VNVisitor {
|
|||
const int leOffset = !arrayp->rangep()->littleEndian()
|
||||
? arrayp->rangep()->elementsConst() - 1 - offset
|
||||
: offset;
|
||||
newp = new AstArraySel{nodep->fileline(), nodep->cloneTree(false), leOffset};
|
||||
newp = new AstArraySel{nodep->fileline(), VN_AS(nodep, NodeExpr)->cloneTree(false),
|
||||
leOffset};
|
||||
} else {
|
||||
if (!m_assignError) {
|
||||
nodep->v3error(nodep->prettyTypeName()
|
||||
<< " unexpected in assignment to unpacked array");
|
||||
}
|
||||
m_assignError = true;
|
||||
newp = nodep->cloneTree(false); // Likely will cause downstream errors
|
||||
// Likely will cause downstream errors
|
||||
newp = VN_AS(nodep, NodeExpr)->cloneTree(false);
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
|
|
@ -143,9 +145,8 @@ class SliceVisitor final : public VNVisitor {
|
|||
const int elements = arrayp->rangep()->elementsConst();
|
||||
for (int offset = 0; offset < elements; ++offset) {
|
||||
AstNodeAssign* const newp
|
||||
= VN_AS(nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, offset),
|
||||
cloneAndSel(nodep->rhsp(), elements, offset)),
|
||||
NodeAssign);
|
||||
= nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, offset),
|
||||
cloneAndSel(nodep->rhsp(), elements, offset));
|
||||
if (debug() >= 9) newp->dumpTree(cout, "-new ");
|
||||
newlistp = AstNode::addNext(newlistp, newp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ struct SplitVarImpl {
|
|||
// AstNodeModule::user1() -> Block number counter for generating unique names
|
||||
const VNUser1InUse m_user1InUse; // Only used in SplitUnpackedVarVisitor
|
||||
|
||||
static AstNodeAssign* newAssign(FileLine* fileline, AstNode* lhsp, AstNode* rhsp,
|
||||
static AstNodeAssign* newAssign(FileLine* fileline, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
|
||||
const AstVar* varp) {
|
||||
if (varp->isFuncLocal() || varp->isFuncReturn()) {
|
||||
return new AstAssign{fileline, lhsp, rhsp};
|
||||
|
|
@ -621,9 +621,9 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl {
|
|||
= (context && VN_IS(context, NodeFTaskRef)) || (assignp && VN_IS(assignp, Assign));
|
||||
|
||||
for (int i = 0; i < dtypep->elementsConst(); ++i) {
|
||||
AstNode* lhsp
|
||||
AstNodeExpr* lhsp
|
||||
= newVarRef(fl, vars.at(start_idx + i), lvalue ? VAccess::WRITE : VAccess::READ);
|
||||
AstNode* rhsp = new AstArraySel{
|
||||
AstNodeExpr* rhsp = new AstArraySel{
|
||||
fl, newVarRef(fl, varp, !lvalue ? VAccess::WRITE : VAccess::READ), i};
|
||||
AstNode* const refp = lhsp;
|
||||
UINFO(9, "Creating assign idx:" << i << " + " << start_idx << "\n");
|
||||
|
|
@ -655,12 +655,12 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl {
|
|||
const bool lvalue = varp->direction().isWritable();
|
||||
FileLine* const fl = varp->fileline();
|
||||
for (size_t i = 0; i < vars.size(); ++i) {
|
||||
AstNode* const nodes[] = {
|
||||
AstNodeExpr* const nodes[] = {
|
||||
new AstArraySel{fl, newVarRef(fl, varp, lvalue ? VAccess::WRITE : VAccess::READ),
|
||||
static_cast<int>(i)},
|
||||
newVarRef(fl, vars.at(i), !lvalue ? VAccess::WRITE : VAccess::READ)};
|
||||
AstNode* const lhsp = nodes[lvalue ? 0 : 1];
|
||||
AstNode* const rhsp = nodes[lvalue ? 1 : 0];
|
||||
AstNodeExpr* const lhsp = nodes[lvalue ? 0 : 1];
|
||||
AstNodeExpr* const rhsp = nodes[lvalue ? 1 : 0];
|
||||
AstNodeAssign* const assignp = newAssign(fl, lhsp, rhsp, varp);
|
||||
if (insertp) {
|
||||
if (lvalue) { // Just after writing to the temporary variable
|
||||
|
|
@ -1025,8 +1025,8 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl {
|
|||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
// Extract necessary bit range from a newly created variable to meet ref
|
||||
static AstNode* extractBits(const PackedVarRefEntry& ref, const SplitNewVar& var,
|
||||
const VAccess access) {
|
||||
static AstNodeExpr* extractBits(const PackedVarRefEntry& ref, const SplitNewVar& var,
|
||||
const VAccess access) {
|
||||
FileLine* const fl = ref.nodep()->fileline();
|
||||
AstVarRef* const refp = new AstVarRef{fl, var.varp(), access};
|
||||
if (ref.lsb() <= var.lsb() && var.msb() <= ref.msb()) { // Use the entire bits
|
||||
|
|
@ -1049,10 +1049,10 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl {
|
|||
const bool in = portp->isReadOnly();
|
||||
FileLine* const fl = portp->fileline();
|
||||
for (const SplitNewVar& var : vars) {
|
||||
AstNode* rhsp
|
||||
AstNodeExpr* rhsp
|
||||
= new AstSel{fl, new AstVarRef{fl, portp, !in ? VAccess::WRITE : VAccess::READ},
|
||||
var.lsb(), var.bitwidth()};
|
||||
AstNode* lhsp = new AstVarRef{fl, var.varp(), in ? VAccess::WRITE : VAccess::READ};
|
||||
AstNodeExpr* lhsp = new AstVarRef{fl, var.varp(), in ? VAccess::WRITE : VAccess::READ};
|
||||
if (!in) std::swap(lhsp, rhsp);
|
||||
AstNodeAssign* const assignp = newAssign(fl, lhsp, rhsp, portp);
|
||||
if (insertp) {
|
||||
|
|
@ -1134,9 +1134,10 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl {
|
|||
new AstVarRef{senitemp->fileline(), varit->varp(), VAccess::READ}};
|
||||
senitemp->addNextHere(prevp);
|
||||
} else {
|
||||
AstNode* const bitsp
|
||||
AstNodeExpr* const bitsp
|
||||
= extractBits(ref, *varit, lvalue ? VAccess::WRITE : VAccess::READ);
|
||||
prevp = new AstConcat{ref.nodep()->fileline(), bitsp, prevp};
|
||||
prevp = new AstConcat{ref.nodep()->fileline(), bitsp,
|
||||
VN_AS(prevp, NodeExpr)};
|
||||
}
|
||||
}
|
||||
// If varp is an argument of task/func, need to update temporary var
|
||||
|
|
@ -1174,8 +1175,8 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl {
|
|||
connectPortAndVar(vars, varp, nullptr);
|
||||
} else if (varp->isTrace()) {
|
||||
// Let's reuse the original variable for tracing
|
||||
AstNode* rhsp = new AstVarRef{vars.front().varp()->fileline(), vars.front().varp(),
|
||||
VAccess::READ};
|
||||
AstNodeExpr* rhsp = new AstVarRef{vars.front().varp()->fileline(),
|
||||
vars.front().varp(), VAccess::READ};
|
||||
FileLine* const fl = varp->fileline();
|
||||
for (size_t i = 1; i < vars.size(); ++i) {
|
||||
rhsp = new AstConcat{fl, new AstVarRef{fl, vars[i].varp(), VAccess::READ},
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ public:
|
|||
m_wordUse = true;
|
||||
}
|
||||
// ACCESSORS
|
||||
AstNode* substWhole(AstNode* errp) {
|
||||
AstNodeExpr* substWhole(AstNode* errp) {
|
||||
if (!m_varp->isWide() && !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) {
|
||||
const AstNodeAssign* const assp = m_whole.m_assignp;
|
||||
UASSERT_OBJ(assp, errp, "Reading whole that was never assigned");
|
||||
|
|
@ -129,7 +129,7 @@ public:
|
|||
}
|
||||
}
|
||||
// Return what to substitute given word number for
|
||||
AstNode* substWord(AstNode* errp, int word) {
|
||||
AstNodeExpr* substWord(AstNode* errp, int word) {
|
||||
if (!m_whole.m_complex && !m_whole.m_assignp && !m_words[word].m_complex) {
|
||||
const AstNodeAssign* const assp = getWordAssignp(word);
|
||||
UASSERT_OBJ(assp, errp, "Reading a word that was never assigned, or bad word #");
|
||||
|
|
@ -287,9 +287,9 @@ private:
|
|||
}
|
||||
if (!hit) iterate(nodep->lhsp());
|
||||
}
|
||||
void replaceSubstEtc(AstNode* nodep, AstNode* substp) {
|
||||
void replaceSubstEtc(AstNode* nodep, AstNodeExpr* substp) {
|
||||
if (debug() > 5) nodep->dumpTree(cout, " substw_old: ");
|
||||
AstNode* newp = substp->cloneTree(true);
|
||||
AstNodeExpr* newp = substp->cloneTree(true);
|
||||
if (!nodep->isQuad() && newp->isQuad()) {
|
||||
newp = new AstCCast{newp->fileline(), newp, nodep};
|
||||
}
|
||||
|
|
@ -308,7 +308,7 @@ private:
|
|||
const int word = constp->toUInt();
|
||||
UINFO(8, " USEword" << word << " " << varrefp << endl);
|
||||
SubstVarEntry* const entryp = getEntryp(varrefp);
|
||||
if (AstNode* const substp = entryp->substWord(nodep, word)) {
|
||||
if (AstNodeExpr* const substp = entryp->substWord(nodep, word)) {
|
||||
// Check that the RHS hasn't changed value since we recorded it.
|
||||
const SubstUseVisitor visitor{substp, entryp->getWordStep(word)};
|
||||
if (visitor.ok()) {
|
||||
|
|
@ -335,7 +335,7 @@ private:
|
|||
if (nodep->access().isWriteOrRW()) {
|
||||
UINFO(8, " ASSIGNcpx " << nodep << endl);
|
||||
entryp->assignComplex();
|
||||
} else if (AstNode* const substp = entryp->substWhole(nodep)) {
|
||||
} else if (AstNodeExpr* const substp = entryp->substWhole(nodep)) {
|
||||
// Check that the RHS hasn't changed value since we recorded it.
|
||||
const SubstUseVisitor visitor{substp, entryp->getWholeStep()};
|
||||
if (visitor.ok()) {
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ private:
|
|||
AstNode* createLookupInput(FileLine* fl, AstVarScope* indexVscp) {
|
||||
// Concat inputs into a single temp variable (inside always)
|
||||
// First var in inVars becomes the LSB of the concat
|
||||
AstNode* concatp = nullptr;
|
||||
AstNodeExpr* concatp = nullptr;
|
||||
for (AstVarScope* invscp : m_inVarps) {
|
||||
AstVarRef* const refp = new AstVarRef{fl, invscp, VAccess::READ};
|
||||
if (concatp) {
|
||||
|
|
@ -359,8 +359,8 @@ private:
|
|||
AstVarScope* outputAssignedTableVscp) {
|
||||
FileLine* const fl = nodep->fileline();
|
||||
for (TableOutputVar& tov : m_outVarps) {
|
||||
AstNode* const alhsp = new AstVarRef{fl, tov.varScopep(), VAccess::WRITE};
|
||||
AstNode* const arhsp = select(fl, tov.tabeVarScopep(), indexVscp);
|
||||
AstNodeExpr* const alhsp = new AstVarRef{fl, tov.varScopep(), VAccess::WRITE};
|
||||
AstNodeExpr* const arhsp = select(fl, tov.tabeVarScopep(), indexVscp);
|
||||
AstNode* outsetp = m_assignDly
|
||||
? static_cast<AstNode*>(new AstAssignDly{fl, alhsp, arhsp})
|
||||
: static_cast<AstNode*>(new AstAssign{fl, alhsp, arhsp});
|
||||
|
|
@ -369,7 +369,7 @@ private:
|
|||
if (tov.mayBeUnassigned()) {
|
||||
V3Number outputChgMask{nodep, static_cast<int>(m_outVarps.size()), 0};
|
||||
outputChgMask.setBit(tov.ord(), 1);
|
||||
AstNode* const condp
|
||||
AstNodeExpr* const condp
|
||||
= new AstAnd{fl, select(fl, outputAssignedTableVscp, indexVscp),
|
||||
new AstConst{fl, outputChgMask}};
|
||||
outsetp = new AstIf{fl, condp, outsetp};
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ private:
|
|||
for (const auto& itr : tconnects) {
|
||||
AstVar* const portp = itr.first;
|
||||
AstArg* const argp = itr.second;
|
||||
AstNode* const pinp = argp->exprp();
|
||||
AstNodeExpr* const pinp = argp->exprp();
|
||||
portp->unlinkFrBack();
|
||||
pushDeletep(portp); // Remove it from the clone (not original)
|
||||
if (!pinp) {
|
||||
|
|
@ -564,7 +564,7 @@ private:
|
|||
const V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp());
|
||||
for (const auto& itr : tconnects) {
|
||||
AstVar* const portp = itr.first;
|
||||
AstNode* const pinp = itr.second->exprp();
|
||||
AstNodeExpr* const pinp = itr.second->exprp();
|
||||
if (!pinp) {
|
||||
// Too few arguments in function call
|
||||
} else {
|
||||
|
|
@ -615,7 +615,7 @@ private:
|
|||
|
||||
if (refp->taskp()->dpiContext()) {
|
||||
// __Vscopep
|
||||
AstNode* const snp = refp->scopeNamep()->unlinkFrBack();
|
||||
AstScopeName* const snp = refp->scopeNamep()->unlinkFrBack();
|
||||
UASSERT_OBJ(snp, refp, "Missing scoping context");
|
||||
ccallp->addArgsp(snp);
|
||||
// __Vfilenamep
|
||||
|
|
@ -630,7 +630,7 @@ private:
|
|||
for (AstNode* pinp = refp->pinsp(); pinp; pinp = nextpinp) {
|
||||
nextpinp = pinp->nextp();
|
||||
// Move pin to the CCall, removing all Arg's
|
||||
AstNode* const exprp = VN_AS(pinp, Arg)->exprp();
|
||||
AstNodeExpr* const exprp = VN_AS(pinp, Arg)->exprp();
|
||||
exprp->unlinkFrBack();
|
||||
ccallp->addArgsp(exprp);
|
||||
}
|
||||
|
|
@ -721,7 +721,7 @@ private:
|
|||
AstNode* newp = nullptr;
|
||||
const int widthWords = portp->basicp()->widthWords();
|
||||
for (int i = 0; i < total; ++i) {
|
||||
AstNode* srcp = new AstVarRef(portvscp->fileline(), portvscp, VAccess::WRITE);
|
||||
AstNodeExpr* srcp = new AstVarRef(portvscp->fileline(), portvscp, VAccess::WRITE);
|
||||
// extract a scalar from multi-dimensional array (internal format)
|
||||
for (auto&& dimStride : dimStrides) {
|
||||
const size_t dimIdx = (i / dimStride.second) % dimStride.first->elementsConst();
|
||||
|
|
@ -744,7 +744,7 @@ private:
|
|||
from += "[" + cvtToStr(i * coef) + "]";
|
||||
}
|
||||
from += ket;
|
||||
AstNode* const rhsp = new AstSel(
|
||||
AstNodeExpr* const rhsp = new AstSel(
|
||||
portp->fileline(), new AstCExpr(portp->fileline(), from, cwidth, false), 0,
|
||||
portp->width());
|
||||
stmtp = new AstAssign(portp->fileline(), srcp, rhsp);
|
||||
|
|
@ -1629,7 +1629,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
|
|||
for (int i = 0; i < tpinnum; ++i) {
|
||||
AstVar* const portp = tconnects[i].first;
|
||||
if (!tconnects[i].second || !tconnects[i].second->exprp()) {
|
||||
AstNode* newvaluep = nullptr;
|
||||
AstNodeExpr* newvaluep = nullptr;
|
||||
if (!portp->valuep()) {
|
||||
nodep->v3error("Missing argument on non-defaulted argument "
|
||||
<< portp->prettyNameQ() << " in function call to "
|
||||
|
|
@ -1639,7 +1639,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
|
|||
// The default value for this port might be a constant
|
||||
// expression that hasn't been folded yet. Try folding it
|
||||
// now; we don't have much to lose if it fails.
|
||||
newvaluep = V3Const::constifyParamsEdit(portp->valuep());
|
||||
newvaluep = V3Const::constifyParamsEdit(VN_AS(portp->valuep(), NodeExpr));
|
||||
if (!VN_IS(newvaluep, Const)) {
|
||||
// Problem otherwise is we might have a varref, task
|
||||
// call, or something else that only makes sense in the
|
||||
|
|
@ -1653,7 +1653,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
|
|||
newvaluep = newvaluep->cloneTree(true);
|
||||
}
|
||||
} else {
|
||||
newvaluep = portp->valuep()->cloneTree(true);
|
||||
newvaluep = VN_AS(portp->valuep(), NodeExpr)->cloneTree(true);
|
||||
}
|
||||
// To avoid problems with callee needing to know to deleteTree
|
||||
// or not, we make this into a pin
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ private:
|
|||
// to this sentree
|
||||
// Ast{NodeProcedure,CFunc,Begin}::user2() -> bool. Set true if process/task is
|
||||
// suspendable
|
||||
// AstSenTree::user2() -> AstText*. Debug info passed to the
|
||||
// AstSenTree::user2() -> AstCExpr*. Debug info passed to the
|
||||
// timing schedulers
|
||||
// Ast{NodeProcedure,CFunc,Begin}::user3() -> DependencyVertex*. Vertex in m_depGraph
|
||||
const VNUser1InUse m_user1InUse;
|
||||
|
|
@ -286,24 +286,29 @@ private:
|
|||
return VN_AS(sensesp->user1p(), VarScope);
|
||||
}
|
||||
// Creates a string describing the sentree
|
||||
AstText* createEventDescription(AstSenTree* const sensesp) const {
|
||||
AstCExpr* createEventDescription(AstSenTree* const sensesp) const {
|
||||
if (!sensesp->user2p()) {
|
||||
std::stringstream ss;
|
||||
ss << '"';
|
||||
V3EmitV::verilogForTree(sensesp, ss);
|
||||
ss << '"';
|
||||
auto* const commentp = new AstText{sensesp->fileline(), ss.str()};
|
||||
auto* const commentp = new AstCExpr{sensesp->fileline(), ss.str(), 0};
|
||||
commentp->dtypeSetString();
|
||||
sensesp->user2p(commentp);
|
||||
return commentp;
|
||||
}
|
||||
return VN_AS(sensesp->user2p(), Text)->cloneTree(false);
|
||||
return VN_AS(sensesp->user2p(), CExpr)->cloneTree(false);
|
||||
}
|
||||
// Adds debug info to a hardcoded method call
|
||||
void addDebugInfo(AstCMethodHard* const methodp) const {
|
||||
if (v3Global.opt.protectIds()) return;
|
||||
FileLine* const flp = methodp->fileline();
|
||||
methodp->addPinsp(new AstText{flp, '"' + flp->filename() + '"'});
|
||||
methodp->addPinsp(new AstText{flp, cvtToStr(flp->lineno())});
|
||||
AstCExpr* const ap = new AstCExpr{flp, '"' + flp->filename() + '"', 0};
|
||||
ap->dtypeSetString();
|
||||
methodp->addPinsp(ap);
|
||||
AstCExpr* const bp = new AstCExpr{flp, cvtToStr(flp->lineno()), 0};
|
||||
bp->dtypeSetString();
|
||||
methodp->addPinsp(bp);
|
||||
}
|
||||
// Adds debug info to a trigSched.trigger() call
|
||||
void addEventDebugInfo(AstCMethodHard* const methodp, AstSenTree* const sensesp) const {
|
||||
|
|
@ -491,7 +496,7 @@ private:
|
|||
}
|
||||
void visit(AstDelay* nodep) override {
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstNode* valuep = V3Const::constifyEdit(nodep->lhsp()->unlinkFrBack());
|
||||
AstNodeExpr* valuep = V3Const::constifyEdit(nodep->lhsp()->unlinkFrBack());
|
||||
auto* const constp = VN_CAST(valuep, Const);
|
||||
if (constp && constp->isZero()) {
|
||||
nodep->v3warn(ZERODLY, "Unsupported: #0 delays do not schedule process resumption in "
|
||||
|
|
@ -632,7 +637,8 @@ private:
|
|||
// do that. These intra-assignment vars will later be passed to forked processes by value.
|
||||
AstNode* const insertBeforep = VN_IS(m_procp, CFunc) ? controlp : nullptr;
|
||||
// Function for replacing values with intermediate variables
|
||||
const auto replaceWithIntermediate = [&](AstNode* const valuep, const std::string& name) {
|
||||
const auto replaceWithIntermediate = [&](AstNodeExpr* const valuep,
|
||||
const std::string& name) {
|
||||
AstVarScope* const newvscp = createTemp(flp, name, valuep->dtypep(), insertBeforep);
|
||||
valuep->replaceWith(new AstVarRef{flp, newvscp, VAccess::READ});
|
||||
controlp->addHereThisAsNext(
|
||||
|
|
@ -665,7 +671,7 @@ private:
|
|||
// TODO: Find a way to do this without introducing this var. Perhaps make
|
||||
// V3SchedAcyclic recognize awaits and prevent it from treating this kind of logic as
|
||||
// cyclic
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
std::string varname;
|
||||
if (auto* const refp = VN_CAST(lhsp, VarRef)) {
|
||||
varname = m_contAssignVarNames.get(refp->name());
|
||||
|
|
@ -696,7 +702,7 @@ private:
|
|||
FileLine* const flp = nodep->fileline();
|
||||
AstNode* const stmtsp = nodep->stmtsp();
|
||||
if (stmtsp) stmtsp->unlinkFrBackWithNext();
|
||||
AstNode* const condp = V3Const::constifyEdit(nodep->condp()->unlinkFrBack());
|
||||
AstNodeExpr* const condp = V3Const::constifyEdit(nodep->condp()->unlinkFrBack());
|
||||
auto* const constp = VN_CAST(condp, Const);
|
||||
if (constp) {
|
||||
condp->v3warn(WAITCONST, "Wait statement condition is constant");
|
||||
|
|
|
|||
|
|
@ -421,7 +421,7 @@ private:
|
|||
graphSimplify(false);
|
||||
}
|
||||
|
||||
AstNode* selectActivity(FileLine* flp, uint32_t acode, const VAccess& access) {
|
||||
AstNodeExpr* selectActivity(FileLine* flp, uint32_t acode, const VAccess& access) {
|
||||
return new AstArraySel(flp, new AstVarRef(flp, m_activityVscp, access), acode);
|
||||
}
|
||||
|
||||
|
|
@ -667,12 +667,12 @@ private:
|
|||
if (!prevActSet || actSet != *prevActSet) {
|
||||
FileLine* const flp = m_topScopep->fileline();
|
||||
const bool always = actSet.count(TraceActivityVertex::ACTIVITY_ALWAYS) != 0;
|
||||
AstNode* condp = nullptr;
|
||||
AstNodeExpr* condp = nullptr;
|
||||
if (always) {
|
||||
condp = new AstConst(flp, 1); // Always true, will be folded later
|
||||
} else {
|
||||
for (const uint32_t actCode : actSet) {
|
||||
AstNode* const selp = selectActivity(flp, actCode, VAccess::READ);
|
||||
AstNodeExpr* const selp = selectActivity(flp, actCode, VAccess::READ);
|
||||
condp = condp ? new AstOr(flp, condp, selp) : selp;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ private:
|
|||
};
|
||||
std::vector<Signal> m_signals; // Signals under current scope
|
||||
AstVarScope* m_traVscp = nullptr; // Current AstVarScope we are constructing AstTraceDecls for
|
||||
AstNode* m_traValuep = nullptr; // Value expression for current signal
|
||||
AstNodeExpr* m_traValuep = nullptr; // Value expression for current signal
|
||||
string m_traName; // Name component for current signal
|
||||
|
||||
VDouble0 m_statSigs; // Statistic tracking
|
||||
|
|
|
|||
|
|
@ -465,7 +465,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
AstConst* const newp = new AstConst{nodep->fileline(), num};
|
||||
return newp;
|
||||
}
|
||||
AstNode* getEnp(AstNode* nodep) {
|
||||
AstNodeExpr* getEnp(AstNode* nodep) {
|
||||
if (nodep->user1p()) {
|
||||
if (AstVarRef* const refp = VN_CAST(nodep, VarRef)) {
|
||||
if (refp->varp()->isIO()) {
|
||||
|
|
@ -480,7 +480,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
nodep->user1p(newAllZerosOrOnes(nodep, true));
|
||||
}
|
||||
// Otherwise return the previous output enable
|
||||
return nodep->user1p();
|
||||
return VN_AS(nodep->user1p(), NodeExpr);
|
||||
}
|
||||
AstVar* getCreateEnVarp(AstVar* invarp) {
|
||||
// Return the master __en for the specified input variable
|
||||
|
|
@ -501,7 +501,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
numz0.opNot(numz); // Z->0, else 1
|
||||
return new AstConst{fl, numz0};
|
||||
}
|
||||
AstNode* getEnExprBasedOnOriginalp(AstNode* const nodep) {
|
||||
AstNodeExpr* getEnExprBasedOnOriginalp(AstNodeExpr* const nodep) {
|
||||
if (AstVarRef* const varrefp = VN_CAST(nodep, VarRef)) {
|
||||
return new AstVarRef{varrefp->fileline(), getCreateEnVarp(varrefp->varp()),
|
||||
VAccess::READ};
|
||||
|
|
@ -514,17 +514,17 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
// whole extend.
|
||||
|
||||
// Unlink lhsp before copying to save unnecessary copy of lhsp
|
||||
AstNode* const lhsp = extendp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lhsp = extendp->lhsp()->unlinkFrBack();
|
||||
AstExtend* const enExtendp = extendp->cloneTree(false);
|
||||
extendp->lhsp(lhsp);
|
||||
AstNode* const enLhsp = getEnExprBasedOnOriginalp(lhsp);
|
||||
AstNodeExpr* const enLhsp = getEnExprBasedOnOriginalp(lhsp);
|
||||
enExtendp->lhsp(new AstNot{enLhsp->fileline(), enLhsp});
|
||||
return new AstNot{enExtendp->fileline(), enExtendp};
|
||||
} else if (AstSel* const selp = VN_CAST(nodep, Sel)) {
|
||||
AstNode* const fromp = selp->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* const fromp = selp->fromp()->unlinkFrBack();
|
||||
AstSel* const enSelp = selp->cloneTree(false);
|
||||
selp->fromp(fromp);
|
||||
AstNode* const enFromp = getEnExprBasedOnOriginalp(fromp);
|
||||
AstNodeExpr* const enFromp = getEnExprBasedOnOriginalp(fromp);
|
||||
enSelp->fromp(enFromp);
|
||||
return enSelp;
|
||||
} else {
|
||||
|
|
@ -566,10 +566,10 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
AstNode* newEnableDeposit(AstSel* selp, AstNode* enp) {
|
||||
AstNodeExpr* newEnableDeposit(AstSel* selp, AstNodeExpr* enp) {
|
||||
// Form a "deposit" instruction for given enable, using existing select as a template.
|
||||
// Would be nicer if we made this a new AST type
|
||||
AstNode* const newp = new AstShiftL(
|
||||
AstNodeExpr* const newp = new AstShiftL(
|
||||
selp->fileline(), new AstExtend(selp->fileline(), enp, selp->fromp()->width()),
|
||||
selp->lsbp()->cloneTree(false), selp->fromp()->width());
|
||||
return newp;
|
||||
|
|
@ -659,8 +659,8 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
// For each driver seperate variables (normal and __en) are created and initialized with
|
||||
// values. In case of normal variable, the original expression is reused. Their values are
|
||||
// aggregated using | to form one expression, which are assigned to varp end envarp.
|
||||
AstNode* orp = nullptr;
|
||||
AstNode* enp = nullptr;
|
||||
AstNodeExpr* orp = nullptr;
|
||||
AstNodeExpr* enp = nullptr;
|
||||
|
||||
for (auto it = beginStrength; it != endStrength; it++) {
|
||||
AstVarRef* refp = it->m_varrefp;
|
||||
|
|
@ -689,14 +689,14 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
nodep->addStmtsp(enLhspAssignp);
|
||||
|
||||
// now append this driver to the driver logic.
|
||||
AstNode* const ref1p = new AstVarRef{refp->fileline(), newLhsp, VAccess::READ};
|
||||
AstNode* const ref2p = new AstVarRef{refp->fileline(), newEnLhsp, VAccess::READ};
|
||||
AstNode* const andp = new AstAnd{refp->fileline(), ref1p, ref2p};
|
||||
AstNodeExpr* const ref1p = new AstVarRef{refp->fileline(), newLhsp, VAccess::READ};
|
||||
AstNodeExpr* const ref2p = new AstVarRef{refp->fileline(), newEnLhsp, VAccess::READ};
|
||||
AstNodeExpr* const andp = new AstAnd{refp->fileline(), ref1p, ref2p};
|
||||
|
||||
// or this to the others
|
||||
orp = (!orp) ? andp : new AstOr{refp->fileline(), orp, andp};
|
||||
|
||||
AstNode* const ref3p = new AstVarRef{refp->fileline(), newEnLhsp, VAccess::READ};
|
||||
AstNodeExpr* const ref3p = new AstVarRef{refp->fileline(), newEnLhsp, VAccess::READ};
|
||||
enp = (!enp) ? ref3p : new AstOr{ref3p->fileline(), enp, ref3p};
|
||||
}
|
||||
AstNode* const assp = new AstAssignW{
|
||||
|
|
@ -742,8 +742,8 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
envarp = VN_AS(invarp->user1p(), Var); // From CASEEQ, foo === 1'bz
|
||||
}
|
||||
|
||||
AstNode* orp = nullptr;
|
||||
AstNode* enp = nullptr;
|
||||
AstNodeExpr* orp = nullptr;
|
||||
AstNodeExpr* enp = nullptr;
|
||||
const int w = lhsp->width();
|
||||
|
||||
std::sort(refsp->begin(), refsp->end(),
|
||||
|
|
@ -774,7 +774,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
aggregateTriSameStrength(nodep, varStrengthp, enVarStrengthp, beginStrength,
|
||||
endStrength);
|
||||
|
||||
AstNode* exprCurrentStrengthp;
|
||||
AstNodeExpr* exprCurrentStrengthp;
|
||||
if (enp) {
|
||||
// If weaker driver should be overwritten by a stronger, replace its value with z
|
||||
exprCurrentStrengthp
|
||||
|
|
@ -785,7 +785,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
}
|
||||
orp = (!orp) ? exprCurrentStrengthp : new AstOr{fl, orp, exprCurrentStrengthp};
|
||||
|
||||
AstNode* enVarStrengthRefp = new AstVarRef{fl, enVarStrengthp, VAccess::READ};
|
||||
AstNodeExpr* enVarStrengthRefp = new AstVarRef{fl, enVarStrengthp, VAccess::READ};
|
||||
|
||||
enp = (!enp) ? enVarStrengthRefp : new AstOr{fl, enp, enVarStrengthRefp};
|
||||
|
||||
|
|
@ -798,7 +798,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
const AstPull* const pullp = static_cast<AstPull*>(lhsp->user3p());
|
||||
bool pull1 = pullp && pullp->direction() == 1; // Else default is down
|
||||
|
||||
AstNode* undrivenp;
|
||||
AstNodeExpr* undrivenp;
|
||||
if (envarp) {
|
||||
undrivenp = new AstNot{envarp->fileline(),
|
||||
new AstVarRef{envarp->fileline(), envarp, VAccess::READ}};
|
||||
|
|
@ -1033,20 +1033,20 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
// expression 1 or 2 have an output enable '__en' signal. If the
|
||||
// condition has an enable, not sure what to do, so generate an
|
||||
// error.
|
||||
AstNode* const condp = nodep->condp();
|
||||
AstNodeExpr* const condp = nodep->condp();
|
||||
if (condp->user1p()) {
|
||||
condp->v3warn(E_UNSUPPORTED, "Unsupported: don't know how to deal with "
|
||||
"tristate logic in the conditional expression");
|
||||
}
|
||||
AstNode* const thenp = nodep->thenp();
|
||||
AstNode* const elsep = nodep->elsep();
|
||||
AstNodeExpr* const thenp = nodep->thenp();
|
||||
AstNodeExpr* const elsep = nodep->elsep();
|
||||
if (thenp->user1p() || elsep->user1p()) { // else no tristates
|
||||
m_tgraph.didProcess(nodep);
|
||||
AstNode* const en1p = getEnp(thenp);
|
||||
AstNode* const en2p = getEnp(elsep);
|
||||
AstNodeExpr* const en1p = getEnp(thenp);
|
||||
AstNodeExpr* const en2p = getEnp(elsep);
|
||||
// The output enable of a cond is a cond of the output enable of the
|
||||
// two expressions with the same conditional.
|
||||
AstNode* const enp
|
||||
AstNodeExpr* const enp
|
||||
= new AstCond(nodep->fileline(), condp->cloneTree(false), en1p, en2p);
|
||||
UINFO(9, " newcond " << enp << endl);
|
||||
nodep->user1p(enp); // propagate up COND(lhsp->enable, rhsp->enable)
|
||||
|
|
@ -1069,7 +1069,8 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
UINFO(9, dbgState() << nodep << endl);
|
||||
if (nodep->user1p()) {
|
||||
// Form a "deposit" instruction. Would be nicer if we made this a new AST type
|
||||
AstNode* const newp = newEnableDeposit(nodep, nodep->user1p());
|
||||
AstNodeExpr* const newp
|
||||
= newEnableDeposit(nodep, VN_AS(nodep->user1p(), NodeExpr));
|
||||
nodep->fromp()->user1p(newp); // Push to varref (etc)
|
||||
if (debug() >= 9) newp->dumpTree(cout, "-assign-sel; ");
|
||||
m_tgraph.didProcess(nodep);
|
||||
|
|
@ -1083,8 +1084,8 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
<< nodep->prettyTypeName());
|
||||
}
|
||||
if (nodep->fromp()->user1p()) { // SEL(VARREF, lsb)
|
||||
AstNode* const en1p = getEnp(nodep->fromp());
|
||||
AstNode* const enp
|
||||
AstNodeExpr* const en1p = getEnp(nodep->fromp());
|
||||
AstNodeExpr* const enp
|
||||
= new AstSel(nodep->fileline(), en1p, nodep->lsbp()->cloneTree(true),
|
||||
nodep->widthp()->cloneTree(true));
|
||||
UINFO(9, " newsel " << enp << endl);
|
||||
|
|
@ -1110,7 +1111,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
UINFO(9, dbgState() << nodep << endl);
|
||||
if (nodep->user1p()) {
|
||||
// Each half of the concat gets a select of the enable expression
|
||||
AstNode* const enp = nodep->user1p();
|
||||
AstNodeExpr* const enp = VN_AS(nodep->user1p(), NodeExpr);
|
||||
nodep->user1p(nullptr);
|
||||
nodep->lhsp()->user1p(new AstSel(nodep->fileline(), enp->cloneTree(true),
|
||||
nodep->rhsp()->width(),
|
||||
|
|
@ -1125,13 +1126,13 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
UINFO(9, dbgState() << nodep << endl);
|
||||
// Generate the new output enable signal, just as a concat
|
||||
// identical to the data concat
|
||||
AstNode* const expr1p = nodep->lhsp();
|
||||
AstNode* const expr2p = nodep->rhsp();
|
||||
AstNodeExpr* const expr1p = nodep->lhsp();
|
||||
AstNodeExpr* const expr2p = nodep->rhsp();
|
||||
if (expr1p->user1p() || expr2p->user1p()) { // else no tristates
|
||||
m_tgraph.didProcess(nodep);
|
||||
AstNode* const en1p = getEnp(expr1p);
|
||||
AstNode* const en2p = getEnp(expr2p);
|
||||
AstNode* const enp = new AstConcat(nodep->fileline(), en1p, en2p);
|
||||
AstNodeExpr* const en1p = getEnp(expr1p);
|
||||
AstNodeExpr* const en2p = getEnp(expr2p);
|
||||
AstNodeExpr* const enp = new AstConcat(nodep->fileline(), en1p, en2p);
|
||||
UINFO(9, " newconc " << enp << endl);
|
||||
nodep->user1p(enp); // propagate up CONCAT(lhsp->enable, rhsp->enable)
|
||||
expr1p->user1p(nullptr);
|
||||
|
|
@ -1156,10 +1157,10 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
return;
|
||||
}
|
||||
m_tgraph.didProcess(nodep);
|
||||
AstNode* const expr1p = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* const expr2p = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* enp;
|
||||
if (AstNode* const en2p = expr2p->user1p()) {
|
||||
AstNodeExpr* const expr1p = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const expr2p = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* enp;
|
||||
if (AstNodeExpr* const en2p = VN_AS(expr2p->user1p(), NodeExpr)) {
|
||||
enp = new AstAnd(nodep->fileline(), expr1p, en2p);
|
||||
} else {
|
||||
enp = expr1p;
|
||||
|
|
@ -1199,22 +1200,22 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
// have to define what is means to OR 1'bz with other
|
||||
// expressions. Here I take the approach that when one expression
|
||||
// is 0, that is passes the other.
|
||||
AstNode* const expr1p = nodep->lhsp();
|
||||
AstNode* const expr2p = nodep->rhsp();
|
||||
AstNodeExpr* const expr1p = nodep->lhsp();
|
||||
AstNodeExpr* const expr2p = nodep->rhsp();
|
||||
if (!expr1p->user1p() && !expr2p->user1p()) {
|
||||
return; // no tristates in either expression, so nothing to do
|
||||
}
|
||||
m_tgraph.didProcess(nodep);
|
||||
AstNode* const en1p = getEnp(expr1p);
|
||||
AstNode* const en2p = getEnp(expr2p);
|
||||
AstNode* subexpr1p = expr1p->cloneTree(false);
|
||||
AstNode* subexpr2p = expr2p->cloneTree(false);
|
||||
AstNodeExpr* const en1p = getEnp(expr1p);
|
||||
AstNodeExpr* const en2p = getEnp(expr2p);
|
||||
AstNodeExpr* subexpr1p = expr1p->cloneTree(false);
|
||||
AstNodeExpr* subexpr2p = expr2p->cloneTree(false);
|
||||
if (isAnd) {
|
||||
subexpr1p = new AstNot(nodep->fileline(), subexpr1p);
|
||||
subexpr2p = new AstNot(nodep->fileline(), subexpr2p);
|
||||
}
|
||||
// calc new output enable
|
||||
AstNode* const enp = new AstOr(
|
||||
AstNodeExpr* const enp = new AstOr(
|
||||
nodep->fileline(), new AstAnd(nodep->fileline(), en1p, en2p),
|
||||
new AstOr(nodep->fileline(),
|
||||
new AstAnd(nodep->fileline(), en1p->cloneTree(false), subexpr1p),
|
||||
|
|
@ -1301,12 +1302,12 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
AstConst* const constp = VN_CAST(nodep->lhsp(), Const);
|
||||
if (constp && constp->user1p()) {
|
||||
// 3'b1z0 -> ((3'b101 == in__en) && (3'b100 == in))
|
||||
AstNode* const rhsp = nodep->rhsp();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp();
|
||||
rhsp->unlinkFrBack();
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* enRhsp;
|
||||
AstNodeExpr* enRhsp;
|
||||
if (rhsp->user1p()) {
|
||||
enRhsp = rhsp->user1p();
|
||||
enRhsp = VN_AS(rhsp->user1p(), NodeExpr);
|
||||
rhsp->user1p(nullptr);
|
||||
} else {
|
||||
enRhsp = getEnExprBasedOnOriginalp(rhsp);
|
||||
|
|
@ -1315,7 +1316,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
= VN_AS(constp->user1p(), Const)
|
||||
->num(); // visit(AstConst) already split into en/ones
|
||||
const V3Number& oneIfEnOne = constp->num();
|
||||
AstNode* newp
|
||||
AstNodeExpr* newp
|
||||
= new AstLogAnd{fl, new AstEq{fl, new AstConst{fl, oneIfEn}, enRhsp},
|
||||
// Keep the caseeq if there are X's present
|
||||
new AstEqCase{fl, new AstConst{fl, oneIfEnOne}, rhsp}};
|
||||
|
|
@ -1328,11 +1329,12 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
} else if (constp && nodep->rhsp()->user1p()) {
|
||||
FileLine* const fl = nodep->fileline();
|
||||
constp->unlinkFrBack();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* newp = new AstLogAnd{
|
||||
fl, new AstEq{fl, newAllZerosOrOnes(constp, false), rhsp->user1p()},
|
||||
// Keep the caseeq if there are X's present
|
||||
new AstEqCase{fl, constp, rhsp}};
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* newp = new AstLogAnd{fl,
|
||||
new AstEq{fl, newAllZerosOrOnes(constp, false),
|
||||
VN_AS(rhsp->user1p(), NodeExpr)},
|
||||
// Keep the caseeq if there are X's present
|
||||
new AstEqCase{fl, constp, rhsp}};
|
||||
if (neq) newp = new AstLogNot{fl, newp};
|
||||
rhsp->user1p(nullptr);
|
||||
UINFO(9, " newceq " << newp << endl);
|
||||
|
|
@ -1376,7 +1378,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
if (!dropop[1]) iterateAndNextNull(nodep->thsp());
|
||||
if (!dropop[2]) iterateAndNextNull(nodep->fhsp());
|
||||
} else {
|
||||
AstNode* nonXp = nullptr;
|
||||
AstNodeExpr* nonXp = nullptr;
|
||||
if (!dropop[0]) {
|
||||
nonXp = nodep->rhsp();
|
||||
} else if (!dropop[1]) {
|
||||
|
|
@ -1400,7 +1402,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
UINFO(4, " COUNTBITS('z)-> " << nodep << endl);
|
||||
VNRelinker relinkHandle;
|
||||
nodep->unlinkFrBack(&relinkHandle);
|
||||
AstNode* newp = new AstCountOnes(
|
||||
AstNodeExpr* newp = new AstCountOnes(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), envarp, VAccess::READ));
|
||||
if (nonXp) { // Need to still count '0 or '1 or 'x's
|
||||
if (dropop[0]) {
|
||||
|
|
@ -1545,7 +1547,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
// Therefore, create the enable, output and separate input pin,
|
||||
// then pinReconnectSimple all
|
||||
// Create the output enable pin, connect to new signal
|
||||
AstNode* enrefp;
|
||||
AstNodeExpr* enrefp;
|
||||
{
|
||||
AstVar* const enVarp = new AstVar(nodep->fileline(), VVarType::MODULETEMP,
|
||||
nodep->name() + "__en" + cvtToStr(m_unique++),
|
||||
|
|
@ -1580,8 +1582,8 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
<< nodep->prettyNameQ());
|
||||
}
|
||||
} else {
|
||||
AstNode* const outexprp
|
||||
= nodep->exprp()->cloneTree(false); // Note has lvalue() set
|
||||
AstNodeExpr* const outexprp
|
||||
= VN_AS(nodep->exprp(), NodeExpr)->cloneTree(false); // Note has lvalue() set
|
||||
outpinp = new AstPin(nodep->fileline(), nodep->pinNum(),
|
||||
outModVarp->name(), // should be {var}"__out"
|
||||
outexprp);
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ private:
|
|||
|
||||
// METHODS
|
||||
|
||||
void replaceBoundLvalue(AstNode* nodep, AstNode* condp) {
|
||||
void replaceBoundLvalue(AstNodeExpr* nodep, AstNodeExpr* condp) {
|
||||
// Spec says a out-of-range LHS SEL results in a NOP.
|
||||
// This is a PITA. We could:
|
||||
// 1. IF(...) around an ASSIGN,
|
||||
|
|
@ -101,11 +101,11 @@ private:
|
|||
m_assigndlyp->replaceWith(newp);
|
||||
VL_DO_CLEAR(pushDeletep(m_assigndlyp), m_assigndlyp = nullptr);
|
||||
}
|
||||
AstNode* prep = nodep;
|
||||
AstNodeExpr* prep = nodep;
|
||||
|
||||
// Scan back to put the condlvalue above all selects (IE top of the lvalue)
|
||||
while (VN_IS(prep->backp(), NodeSel) || VN_IS(prep->backp(), Sel)) {
|
||||
prep = prep->backp();
|
||||
prep = VN_AS(prep->backp(), NodeExpr);
|
||||
}
|
||||
FileLine* const fl = nodep->fileline();
|
||||
VL_DANGLING(nodep); // Zap it so we don't use it by mistake - use prep
|
||||
|
|
@ -115,8 +115,8 @@ private:
|
|||
if (const AstIf* const ifp = VN_AS(prep->user2p(), If)) {
|
||||
UASSERT_OBJ(!needDly, prep, "Should have already converted to non-delay");
|
||||
VNRelinker replaceHandle;
|
||||
AstNode* const earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle);
|
||||
AstNode* const newp = new AstLogAnd(condp->fileline(), condp, earliercondp);
|
||||
AstNodeExpr* const earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle);
|
||||
AstNodeExpr* const newp = new AstLogAnd(condp->fileline(), condp, earliercondp);
|
||||
UINFO(4, "Edit BOUNDLVALUE " << newp << endl);
|
||||
replaceHandle.relink(newp);
|
||||
} else {
|
||||
|
|
@ -207,9 +207,9 @@ private:
|
|||
VL_DO_DANGLING(V3Const::constifyEdit(nodep), nodep);
|
||||
return;
|
||||
} else {
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* newp;
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* newp;
|
||||
// If we got ==1'bx it can never be true (but 1'bx==1'bx can be!)
|
||||
if (((VN_IS(lhsp, Const) && VN_AS(lhsp, Const)->num().isFourState())
|
||||
|| (VN_IS(rhsp, Const) && VN_AS(rhsp, Const)->num().isFourState()))) {
|
||||
|
|
@ -239,9 +239,9 @@ private:
|
|||
VL_DO_DANGLING(V3Const::constifyEdit(nodep), nodep);
|
||||
return;
|
||||
} else {
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* newp;
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* newp;
|
||||
if (!VN_IS(rhsp, Const)) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: RHS of ==? or !=? must be "
|
||||
"constant to be synthesizable"); // Says spec.
|
||||
|
|
@ -253,9 +253,9 @@ private:
|
|||
nummask.opBitsNonX(VN_AS(rhsp, Const)->num());
|
||||
V3Number numval(rhsp, rhsp->width());
|
||||
numval.opBitsOne(VN_AS(rhsp, Const)->num());
|
||||
AstNode* const and1p = new AstAnd(nodep->fileline(), lhsp,
|
||||
new AstConst(nodep->fileline(), nummask));
|
||||
AstNode* const and2p = new AstConst(nodep->fileline(), numval);
|
||||
AstNodeExpr* const and1p = new AstAnd(nodep->fileline(), lhsp,
|
||||
new AstConst(nodep->fileline(), nummask));
|
||||
AstNodeExpr* const and2p = new AstConst(nodep->fileline(), numval);
|
||||
if (VN_IS(nodep, EqWild)) {
|
||||
newp = new AstEq(nodep->fileline(), and1p, and2p);
|
||||
} else {
|
||||
|
|
@ -290,7 +290,7 @@ private:
|
|||
dropop[2] = VN_IS(nodep->fhsp(), Const) && VN_AS(nodep->fhsp(), Const)->num().isAnyX();
|
||||
UINFO(4, " COUNTBITS(" << dropop[0] << dropop[1] << dropop[2] << " " << nodep << endl);
|
||||
|
||||
AstNode* nonXp = nullptr;
|
||||
AstNodeExpr* nonXp = nullptr;
|
||||
if (!dropop[0]) {
|
||||
nonXp = nodep->rhsp();
|
||||
} else if (!dropop[1]) {
|
||||
|
|
@ -394,10 +394,11 @@ private:
|
|||
if (debug() >= 9) nodep->dumpTree(cout, "sel_old: ");
|
||||
|
||||
// If (maxmsb >= selected), we're in bound
|
||||
AstNode* condp = new AstGte(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
nodep->lsbp()->width(), maxmsb),
|
||||
nodep->lsbp()->cloneTree(false));
|
||||
AstNodeExpr* condp
|
||||
= new AstGte(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
nodep->lsbp()->width(), maxmsb),
|
||||
nodep->lsbp()->cloneTree(false));
|
||||
// See if the condition is constant true (e.g. always in bound due to constant select)
|
||||
// Note below has null backp(); the Edit function knows how to deal with that.
|
||||
condp = V3Const::constifyEdit(condp);
|
||||
|
|
@ -452,10 +453,11 @@ private:
|
|||
if (debug() >= 9) nodep->dumpTree(cout, "arraysel_old: ");
|
||||
|
||||
// See if the condition is constant true
|
||||
AstNode* condp = new AstGte(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
nodep->bitp()->width(), declElements - 1),
|
||||
nodep->bitp()->cloneTree(false));
|
||||
AstNodeExpr* condp
|
||||
= new AstGte(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
nodep->bitp()->width(), declElements - 1),
|
||||
nodep->bitp()->cloneTree(false));
|
||||
// Note below has null backp(); the Edit function knows how to deal with that.
|
||||
condp = V3Const::constifyEdit(condp);
|
||||
if (condp->isOne()) {
|
||||
|
|
@ -483,8 +485,8 @@ private:
|
|||
} else if (!lvalue) { // Mid-multidimension read, just use zero
|
||||
// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
|
||||
VNRelinker replaceHandle;
|
||||
AstNode* const bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
|
||||
AstNode* const newp = new AstCondBound(
|
||||
AstNodeExpr* const bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
|
||||
AstNodeExpr* const newp = new AstCondBound(
|
||||
bitp->fileline(), condp, bitp,
|
||||
new AstConst(bitp->fileline(), AstConst::WidthedValue(), bitp->width(), 0));
|
||||
// Added X's, tristate them too
|
||||
|
|
|
|||
299
src/V3Width.cpp
299
src/V3Width.cpp
|
|
@ -770,22 +770,10 @@ private:
|
|||
iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
|
||||
V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change
|
||||
const AstConst* const constp = VN_CAST(nodep->rhsp(), Const);
|
||||
AstBasicDType* const basicp = VN_CAST(nodep->rhsp(), BasicDType);
|
||||
if (!constp && !basicp) {
|
||||
nodep->v3error("Slice size isn't a constant or basic data type.");
|
||||
return;
|
||||
}
|
||||
if (basicp) { // Convert data type to a constant size
|
||||
AstConst* const newp = new AstConst(basicp->fileline(), basicp->width());
|
||||
nodep->rhsp()->replaceWith(newp);
|
||||
pushDeletep(basicp);
|
||||
if (const AstConst* const constp = VN_CAST(nodep->rhsp(), Const)) {
|
||||
if (constp->toUInt() == 0) nodep->v3error("Slice size cannot be zero.");
|
||||
} else {
|
||||
const uint32_t sliceSize = constp->toUInt();
|
||||
if (!sliceSize) {
|
||||
nodep->v3error("Slice size cannot be zero.");
|
||||
return;
|
||||
}
|
||||
nodep->v3error("Slice size isn't a constant or basic data type.");
|
||||
}
|
||||
nodep->dtypeSetLogicUnsized(nodep->lhsp()->width(), nodep->lhsp()->widthMin(),
|
||||
VSigning::UNSIGNED);
|
||||
|
|
@ -1444,8 +1432,8 @@ private:
|
|||
if (VN_IS(dtypep, QueueDType)) {
|
||||
switch (nodep->attrType()) {
|
||||
case VAttrType::DIM_SIZE: {
|
||||
AstNode* const newp = new AstCMethodHard(
|
||||
nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size");
|
||||
AstNodeExpr* const fromp = VN_AS(nodep->fromp()->unlinkFrBack(), NodeExpr);
|
||||
AstNode* const newp = new AstCMethodHard{nodep->fileline(), fromp, "size"};
|
||||
newp->dtypeSetSigned32();
|
||||
newp->didWidth(true);
|
||||
newp->protect(false);
|
||||
|
|
@ -1462,8 +1450,9 @@ private:
|
|||
}
|
||||
case VAttrType::DIM_RIGHT:
|
||||
case VAttrType::DIM_HIGH: {
|
||||
AstNode* const sizep = new AstCMethodHard(
|
||||
nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size");
|
||||
AstNodeExpr* const fromp = VN_AS(nodep->fromp()->unlinkFrBack(), NodeExpr);
|
||||
AstNodeExpr* const sizep
|
||||
= new AstCMethodHard{nodep->fileline(), fromp, "size"};
|
||||
sizep->dtypeSetSigned32();
|
||||
sizep->didWidth(true);
|
||||
sizep->protect(false);
|
||||
|
|
@ -1475,7 +1464,7 @@ private:
|
|||
break;
|
||||
}
|
||||
case VAttrType::DIM_INCREMENT: {
|
||||
AstNode* const newp
|
||||
AstNodeExpr* const newp
|
||||
= new AstConst(nodep->fileline(), AstConst::Signed32(), -1);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -1493,9 +1482,9 @@ private:
|
|||
if (!nodep->dimp() || msbdim < 1) {
|
||||
if (VN_IS(dtypep, BasicDType) && dtypep->basicp()->isString()) {
|
||||
// IEEE undocumented but $bits(string) must give length(string) * 8
|
||||
AstNodeExpr* const fromp = VN_AS(nodep->fromp()->unlinkFrBack(), NodeExpr);
|
||||
AstNode* const newp = new AstShiftL{
|
||||
nodep->fileline(),
|
||||
new AstLenN{nodep->fileline(), nodep->fromp()->unlinkFrBack()},
|
||||
nodep->fileline(), new AstLenN{nodep->fileline(), fromp},
|
||||
new AstConst{nodep->fileline(), 3}, // * 8
|
||||
32};
|
||||
nodep->replaceWith(newp);
|
||||
|
|
@ -1516,8 +1505,8 @@ private:
|
|||
} else { // Need a runtime lookup table. Yuk.
|
||||
UASSERT_OBJ(nodep->fromp() && dtypep, nodep, "Unsized expression");
|
||||
AstVar* const varp = dimensionVarp(dtypep, nodep->attrType(), msbdim);
|
||||
AstNode* const dimp = nodep->dimp()->unlinkFrBack();
|
||||
AstNode* const newp
|
||||
AstNodeExpr* const dimp = nodep->dimp()->unlinkFrBack();
|
||||
AstNodeExpr* const newp
|
||||
= new AstArraySel{nodep->fileline(), newVarRefDollarUnit(varp), dimp};
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -1610,7 +1599,7 @@ private:
|
|||
newp = new AstUnpackArrayDType(
|
||||
nodep->fileline(), VFlagChildDType(), childp,
|
||||
new AstRange(nodep->fileline(), new AstConst(elementsp->fileline(), 0),
|
||||
new AstSub(elementsp->fileline(), elementsp,
|
||||
new AstSub(elementsp->fileline(), VN_AS(elementsp, NodeExpr),
|
||||
new AstConst(elementsp->fileline(), 1))));
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
|
|
@ -1769,7 +1758,7 @@ private:
|
|||
UASSERT_OBJ(enumDtp, nodep, "$cast determined as enum, but not enum type");
|
||||
const uint64_t maxval = enumMaxValue(nodep, enumDtp);
|
||||
const bool assoc = maxval > ENUM_LOOKUP_BITS;
|
||||
AstNode* testp = nullptr;
|
||||
AstNodeExpr* testp = nullptr;
|
||||
FileLine* const fl_novalue = new FileLine{fl};
|
||||
fl_novalue->warnOff(V3ErrorCode::ENUMVALUE, true);
|
||||
if (assoc) {
|
||||
|
|
@ -1881,7 +1870,7 @@ private:
|
|||
// For now, replace it ASAP, so widthing can propagate easily
|
||||
// The cast may change signing, but we don't know the sign yet. Make it so.
|
||||
// Note we don't sign fromp() that would make the algorithm O(n^2) if lots of casting.
|
||||
AstNode* newp = nullptr;
|
||||
AstNodeExpr* newp = nullptr;
|
||||
if (bad) {
|
||||
} else if (const AstBasicDType* const basicp = toDtp->basicp()) {
|
||||
if (!basicp->isDouble() && !fromDtp->isDouble()) {
|
||||
|
|
@ -1942,10 +1931,9 @@ private:
|
|||
void visit(AstCastSize* nodep) override {
|
||||
// IEEE: Signedness of result is same as self-determined signedness
|
||||
// However, the result is same as BITSEL, so we do not sign extend the LHS
|
||||
UASSERT_OBJ(VN_IS(nodep->rhsp(), Const), nodep, "Unsupported: Non-const cast of size");
|
||||
// if (debug()) nodep->dumpTree(cout, " CastSizePre: ");
|
||||
if (m_vup->prelim()) {
|
||||
int width = VN_AS(nodep->rhsp(), Const)->toSInt();
|
||||
int width = nodep->rhsp()->toSInt();
|
||||
if (width < 1) {
|
||||
nodep->v3error("Size-changing cast to zero or negative size");
|
||||
width = 1;
|
||||
|
|
@ -1996,7 +1984,8 @@ private:
|
|||
: nodep->findBitDType(width, width, underDtp->numeric()));
|
||||
nodep->dtypep(outDtp);
|
||||
// We ignore warnings as that is sort of the point of a cast
|
||||
widthCheckSized(nodep, "Cast expr", underp, outDtp, EXTEND_EXP, false);
|
||||
widthCheckSized(nodep, "Cast expr", VN_AS(underp, NodeExpr), outDtp, EXTEND_EXP,
|
||||
false);
|
||||
VL_DANGLING(underp);
|
||||
}
|
||||
}
|
||||
|
|
@ -2403,10 +2392,10 @@ private:
|
|||
nodep->dtypeSetBit();
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "-inside-in: ");
|
||||
// Now rip out the inside and replace with simple math
|
||||
AstNode* newp = nullptr;
|
||||
for (AstNode *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
|
||||
nextip = itemp->nextp(); // Will be unlinking
|
||||
AstNode* inewp;
|
||||
AstNodeExpr* newp = nullptr;
|
||||
for (AstNodeExpr *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
|
||||
nextip = VN_AS(itemp->nextp(), NodeExpr); // Will be unlinking
|
||||
AstNodeExpr* inewp;
|
||||
const AstNodeDType* const itemDtp = itemp->dtypep()->skipRefp();
|
||||
if (AstInsideRange* const irangep = VN_CAST(itemp, InsideRange)) {
|
||||
// Similar logic in V3Case
|
||||
|
|
@ -2878,7 +2867,7 @@ private:
|
|||
} else if (nodep->name() == "exists") { // function int exists(input index)
|
||||
// IEEE really should have made this a "bit" return
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
AstNode* const index_exprp = methodCallWildcardIndexExpr(nodep, adtypep);
|
||||
AstNodeExpr* const index_exprp = methodCallWildcardIndexExpr(nodep, adtypep);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "exists",
|
||||
index_exprp->unlinkFrBack()};
|
||||
newp->dtypeSetSigned32();
|
||||
|
|
@ -2891,7 +2880,7 @@ private:
|
|||
"clear"};
|
||||
newp->dtypeSetVoid();
|
||||
} else {
|
||||
AstNode* const index_exprp = methodCallWildcardIndexExpr(nodep, adtypep);
|
||||
AstNodeExpr* const index_exprp = methodCallWildcardIndexExpr(nodep, adtypep);
|
||||
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"erase", index_exprp->unlinkFrBack()};
|
||||
newp->dtypeSetVoid();
|
||||
|
|
@ -2954,7 +2943,7 @@ private:
|
|||
|| nodep->name() == "next" //
|
||||
|| nodep->name() == "prev") {
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
AstNode* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep);
|
||||
AstNodeExpr* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), // first/last/next/prev
|
||||
index_exprp->unlinkFrBack());
|
||||
|
|
@ -2963,7 +2952,7 @@ private:
|
|||
} else if (nodep->name() == "exists") { // function int exists(input index)
|
||||
// IEEE really should have made this a "bit" return
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
AstNode* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep);
|
||||
AstNodeExpr* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "exists",
|
||||
index_exprp->unlinkFrBack());
|
||||
newp->dtypeSetSigned32();
|
||||
|
|
@ -2976,7 +2965,7 @@ private:
|
|||
"clear");
|
||||
newp->dtypeSetVoid();
|
||||
} else {
|
||||
AstNode* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep);
|
||||
AstNodeExpr* const index_exprp = methodCallAssocIndexExpr(nodep, adtypep);
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"erase", index_exprp->unlinkFrBack());
|
||||
newp->dtypeSetVoid();
|
||||
|
|
@ -3039,14 +3028,15 @@ private:
|
|||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
AstNode* methodCallAssocIndexExpr(AstMethodCall* nodep, AstAssocArrayDType* adtypep) {
|
||||
AstNodeExpr* methodCallAssocIndexExpr(AstMethodCall* nodep, AstAssocArrayDType* adtypep) {
|
||||
AstNode* const index_exprp = VN_CAST(nodep->pinsp(), Arg)->exprp();
|
||||
iterateCheck(nodep, "index", index_exprp, CONTEXT_DET, FINAL, adtypep->keyDTypep(),
|
||||
EXTEND_EXP);
|
||||
VL_DANGLING(index_exprp); // May have been edited
|
||||
return VN_AS(nodep->pinsp(), Arg)->exprp();
|
||||
}
|
||||
AstNode* methodCallWildcardIndexExpr(AstMethodCall* nodep, AstWildcardArrayDType* adtypep) {
|
||||
AstNodeExpr* methodCallWildcardIndexExpr(AstMethodCall* nodep,
|
||||
AstWildcardArrayDType* adtypep) {
|
||||
AstNode* const index_exprp = VN_CAST(nodep->pinsp(), Arg)->exprp();
|
||||
iterateCheck(nodep, "index", index_exprp, CONTEXT_DET, FINAL, adtypep->findStringDType(),
|
||||
EXTEND_EXP);
|
||||
|
|
@ -3172,7 +3162,7 @@ private:
|
|||
"clear");
|
||||
newp->dtypeSetVoid();
|
||||
} else {
|
||||
AstNode* const index_exprp = methodCallQueueIndexExpr(nodep);
|
||||
AstNodeExpr* 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");
|
||||
|
|
@ -3187,7 +3177,7 @@ private:
|
|||
} else if (nodep->name() == "insert") {
|
||||
methodOkArguments(nodep, 2, 2);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
|
||||
AstNode* const index_exprp = methodCallQueueIndexExpr(nodep);
|
||||
AstNodeExpr* const index_exprp = methodCallQueueIndexExpr(nodep);
|
||||
AstArg* const argp = VN_AS(nodep->pinsp()->nextp(), Arg);
|
||||
iterateCheckTyped(nodep, "insert value", argp->exprp(), adtypep->subDTypep(), BOTH);
|
||||
if (index_exprp->isZero()) { // insert(0, ...) is a push_front
|
||||
|
|
@ -3285,7 +3275,7 @@ private:
|
|||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
AstNode* methodCallQueueIndexExpr(AstMethodCall* nodep) {
|
||||
AstNodeExpr* methodCallQueueIndexExpr(AstMethodCall* nodep) {
|
||||
AstNode* const index_exprp = VN_AS(nodep->pinsp(), Arg)->exprp();
|
||||
iterateCheckSigned32(nodep, "index", index_exprp, BOTH);
|
||||
VL_DANGLING(index_exprp); // May have been edited
|
||||
|
|
@ -3304,7 +3294,7 @@ private:
|
|||
= VN_CAST(classp->findMember(nodep->name()), NodeFTask)) {
|
||||
userIterate(ftaskp, nullptr);
|
||||
if (ftaskp->lifetime().isStatic()) {
|
||||
AstNode* argsp = nullptr;
|
||||
AstNodeExpr* argsp = nullptr;
|
||||
if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext();
|
||||
AstNodeFTaskRef* newp = nullptr;
|
||||
if (VN_IS(ftaskp, Task)) {
|
||||
|
|
@ -3369,10 +3359,10 @@ private:
|
|||
if (methodId) {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* newp = nullptr;
|
||||
AstNodeExpr* newp = nullptr;
|
||||
for (int i = 0; i < adtypep->elementsConst(); ++i) {
|
||||
AstNode* const arrayRef = nodep->fromp()->cloneTree(false);
|
||||
AstNode* const selector = new AstArraySel(fl, arrayRef, i);
|
||||
AstNodeExpr* const arrayRef = nodep->fromp()->cloneTree(false);
|
||||
AstNodeExpr* const selector = new AstArraySel(fl, arrayRef, i);
|
||||
if (!newp) {
|
||||
newp = selector;
|
||||
} else {
|
||||
|
|
@ -3446,8 +3436,8 @@ private:
|
|||
const bool ignoreCase = nodep->name()[0] == 'i';
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
AstArg* const argp = VN_AS(nodep->pinsp(), Arg);
|
||||
AstNode* const lhs = nodep->fromp()->unlinkFrBack();
|
||||
AstNode* const rhs = argp->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* const lhs = nodep->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhs = argp->exprp()->unlinkFrBack();
|
||||
AstNode* const newp = new AstCompareNN(nodep->fileline(), lhs, rhs, ignoreCase);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -3456,8 +3446,8 @@ private:
|
|||
AstArg* const arg0p = VN_AS(nodep->pinsp(), Arg);
|
||||
AstArg* const arg1p = VN_AS(arg0p->nextp(), Arg);
|
||||
AstNodeVarRef* const fromp = VN_AS(nodep->fromp()->unlinkFrBack(), VarRef);
|
||||
AstNode* const rhsp = arg0p->exprp()->unlinkFrBack();
|
||||
AstNode* const thsp = arg1p->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = arg0p->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* const thsp = arg1p->exprp()->unlinkFrBack();
|
||||
AstVarRef* const varrefp
|
||||
= new AstVarRef(nodep->fileline(), fromp->varp(), VAccess::READ);
|
||||
AstNode* const newp = new AstAssign(
|
||||
|
|
@ -3468,19 +3458,19 @@ private:
|
|||
} else if (nodep->name() == "getc") {
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
AstArg* const arg0p = VN_AS(nodep->pinsp(), Arg);
|
||||
AstNode* const lhsp = nodep->fromp()->unlinkFrBack();
|
||||
AstNode* const rhsp = arg0p->exprp()->unlinkFrBack();
|
||||
AstNode* const newp = new AstGetcN(nodep->fileline(), lhsp, rhsp);
|
||||
AstNodeExpr* const lhsp = nodep->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = arg0p->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* const newp = new AstGetcN(nodep->fileline(), lhsp, rhsp);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (nodep->name() == "substr") {
|
||||
methodOkArguments(nodep, 2, 2);
|
||||
AstArg* const arg0p = VN_AS(nodep->pinsp(), Arg);
|
||||
AstArg* const arg1p = VN_AS(arg0p->nextp(), Arg);
|
||||
AstNode* const lhsp = nodep->fromp()->unlinkFrBack();
|
||||
AstNode* const rhsp = arg0p->exprp()->unlinkFrBack();
|
||||
AstNode* const thsp = arg1p->exprp()->unlinkFrBack();
|
||||
AstNode* const newp = new AstSubstrN(nodep->fileline(), lhsp, rhsp, thsp);
|
||||
AstNodeExpr* const lhsp = nodep->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = arg0p->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* const thsp = arg1p->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* const newp = new AstSubstrN(nodep->fileline(), lhsp, rhsp, thsp);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (nodep->name() == "atobin" || nodep->name() == "atohex"
|
||||
|
|
@ -3628,7 +3618,7 @@ private:
|
|||
// So detach, add next and reattach
|
||||
VNRelinker relinkHandle;
|
||||
patp->unlinkFrBack(&relinkHandle);
|
||||
while (AstNode* const movep = patp->lhssp()->nextp()) {
|
||||
while (AstNodeExpr* const movep = VN_AS(patp->lhssp()->nextp(), NodeExpr)) {
|
||||
movep->unlinkFrBack(); // Not unlinkFrBackWithNext, just one
|
||||
AstNode* newkeyp = nullptr;
|
||||
if (patp->keyp()) newkeyp = patp->keyp()->cloneTree(true);
|
||||
|
|
@ -3743,7 +3733,7 @@ private:
|
|||
if (patp) patp = VN_AS(patp->nextp(), PatMember);
|
||||
}
|
||||
}
|
||||
AstNode* newp = nullptr;
|
||||
AstNodeExpr* newp = nullptr;
|
||||
for (AstMemberDType* memp = vdtypep->membersp(); memp;
|
||||
memp = VN_AS(memp->nextp(), MemberDType)) {
|
||||
const auto it = patmap.find(memp);
|
||||
|
|
@ -3773,9 +3763,9 @@ private:
|
|||
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
|
||||
}
|
||||
|
||||
AstNode* nestedvalueConcat_patternUOrStruct(AstNodeUOrStructDType* memp_vdtypep,
|
||||
AstPatMember* defaultp, AstNode* newp,
|
||||
AstPattern* nodep, DTypeMap dtypemap) {
|
||||
AstNodeExpr* nestedvalueConcat_patternUOrStruct(AstNodeUOrStructDType* memp_vdtypep,
|
||||
AstPatMember* defaultp, AstNodeExpr* newp,
|
||||
AstPattern* nodep, DTypeMap dtypemap) {
|
||||
AstPatMember* patp = nullptr;
|
||||
for (AstMemberDType* memp_nested = memp_vdtypep->membersp(); memp_nested;
|
||||
memp_nested = VN_AS(memp_nested->nextp(), MemberDType)) {
|
||||
|
|
@ -3816,11 +3806,11 @@ private:
|
|||
return patp;
|
||||
}
|
||||
|
||||
AstNode* valueConcat_patternUOrStruct(AstPatMember* patp, AstNode* newp, AstMemberDType* memp,
|
||||
AstPattern* nodep) {
|
||||
AstNodeExpr* valueConcat_patternUOrStruct(AstPatMember* patp, AstNodeExpr* newp,
|
||||
AstMemberDType* memp, AstPattern* nodep) {
|
||||
if (patp) {
|
||||
patp->dtypep(memp);
|
||||
AstNode* const valuep = patternMemberValueIterate(patp);
|
||||
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
||||
if (!newp) {
|
||||
newp = valuep;
|
||||
} else {
|
||||
|
|
@ -3858,11 +3848,11 @@ private:
|
|||
if (patp) {
|
||||
// Don't want the RHS an array
|
||||
patp->dtypep(arrayDtp->subDTypep());
|
||||
AstNode* const valuep = patternMemberValueIterate(patp);
|
||||
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
||||
if (VN_IS(arrayDtp, UnpackArrayDType)) {
|
||||
if (!newp) {
|
||||
AstInitArray* const newap
|
||||
= new AstInitArray(nodep->fileline(), arrayDtp, nullptr);
|
||||
= new AstInitArray{nodep->fileline(), arrayDtp, nullptr};
|
||||
newp = newap;
|
||||
}
|
||||
VN_AS(newp, InitArray)->addIndexValuep(ent - range.lo(), valuep);
|
||||
|
|
@ -3870,7 +3860,8 @@ private:
|
|||
if (!newp) {
|
||||
newp = valuep;
|
||||
} else {
|
||||
AstConcat* const concatp = new AstConcat(patp->fileline(), newp, valuep);
|
||||
AstConcat* const concatp
|
||||
= new AstConcat{patp->fileline(), VN_AS(newp, NodeExpr), valuep};
|
||||
newp = concatp;
|
||||
newp->dtypeSetLogicSized(concatp->lhsp()->width()
|
||||
+ concatp->rhsp()->width(),
|
||||
|
|
@ -3892,12 +3883,12 @@ private:
|
|||
void patternAssoc(AstPattern* nodep, AstAssocArrayDType* arrayDtp, AstPatMember* defaultp) {
|
||||
AstNode* defaultValuep = nullptr;
|
||||
if (defaultp) defaultValuep = defaultp->lhssp()->unlinkFrBack();
|
||||
AstNode* newp = new AstConsAssoc(nodep->fileline(), defaultValuep);
|
||||
AstNodeExpr* newp = new AstConsAssoc(nodep->fileline(), defaultValuep);
|
||||
newp->dtypeFrom(arrayDtp);
|
||||
for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
|
||||
patp = VN_AS(patp->nextp(), PatMember)) {
|
||||
patp->dtypep(arrayDtp->subDTypep());
|
||||
AstNode* const valuep = patternMemberValueIterate(patp);
|
||||
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
||||
AstNode* const keyp = patp->keyp();
|
||||
auto* const newap
|
||||
= new AstSetAssoc(nodep->fileline(), newp, keyp->unlinkFrBack(), valuep);
|
||||
|
|
@ -3917,7 +3908,7 @@ private:
|
|||
for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
|
||||
patp = VN_AS(patp->nextp(), PatMember)) {
|
||||
patp->dtypep(arrayDtp->subDTypep());
|
||||
AstNode* const valuep = patternMemberValueIterate(patp);
|
||||
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
||||
AstNode* const keyp = patp->keyp();
|
||||
auto* const newap
|
||||
= new AstSetWildcard{nodep->fileline(), newp, keyp->unlinkFrBack(), valuep};
|
||||
|
|
@ -3934,7 +3925,7 @@ private:
|
|||
for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
|
||||
patp = VN_AS(patp->nextp(), PatMember)) {
|
||||
patp->dtypep(arrayp->subDTypep());
|
||||
AstNode* const valuep = patternMemberValueIterate(patp);
|
||||
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
||||
auto* const newap = new AstConsDynArray(nodep->fileline(), valuep, newp);
|
||||
newap->dtypeFrom(arrayp);
|
||||
newp = newap;
|
||||
|
|
@ -3949,7 +3940,7 @@ private:
|
|||
for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp;
|
||||
patp = VN_AS(patp->nextp(), PatMember)) {
|
||||
patp->dtypep(arrayp->subDTypep());
|
||||
AstNode* const valuep = patternMemberValueIterate(patp);
|
||||
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
||||
auto* const newap = new AstConsQueue(nodep->fileline(), valuep, newp);
|
||||
newap->dtypeFrom(arrayp);
|
||||
newp = newap;
|
||||
|
|
@ -3963,7 +3954,7 @@ private:
|
|||
const VNumRange range = bdtypep->declRange();
|
||||
PatVecMap patmap = patVectorMap(nodep, range);
|
||||
UINFO(9, "ent " << range.hi() << " to " << range.lo() << endl);
|
||||
AstNode* newp = nullptr;
|
||||
AstNodeExpr* newp = nullptr;
|
||||
for (int ent = range.hi(); ent >= range.lo(); --ent) {
|
||||
AstPatMember* newpatp = nullptr;
|
||||
AstPatMember* patp = nullptr;
|
||||
|
|
@ -3983,7 +3974,7 @@ private:
|
|||
// Determine initial values
|
||||
vdtypep = nodep->findBitDType();
|
||||
patp->dtypep(vdtypep);
|
||||
AstNode* const valuep = patternMemberValueIterate(patp);
|
||||
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
||||
{ // Packed. Convert to concat for now.
|
||||
if (!newp) {
|
||||
newp = valuep;
|
||||
|
|
@ -4007,15 +3998,15 @@ private:
|
|||
// if (debug() >= 9) newp->dumpTree("-apat-out: ");
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
|
||||
}
|
||||
AstNode* patternMemberValueIterate(AstPatMember* patp) {
|
||||
AstNodeExpr* patternMemberValueIterate(AstPatMember* patp) {
|
||||
// Determine values - might be another InitArray
|
||||
userIterate(patp, WidthVP(patp->dtypep(), BOTH).p());
|
||||
// Convert to InitArray or constify immediately
|
||||
AstNode* valuep = patp->lhssp()->unlinkFrBack();
|
||||
AstNodeExpr* valuep = patp->lhssp()->unlinkFrBack();
|
||||
if (VN_IS(valuep, Const)) {
|
||||
// Forming a AstConcat will cause problems with
|
||||
// unsized (uncommitted sized) constants
|
||||
if (AstNode* const newp
|
||||
if (AstConst* const newp
|
||||
= WidthCommitVisitor::newIfConstCommitSize(VN_AS(valuep, Const))) {
|
||||
VL_DO_DANGLING(pushDeletep(valuep), valuep);
|
||||
valuep = newp;
|
||||
|
|
@ -4179,7 +4170,7 @@ private:
|
|||
UASSERT_OBJ(loopsp, nodep, "No loop variables under foreach");
|
||||
// if (debug()) nodep->dumpTree(cout, "-foreach-old: ");
|
||||
userIterateAndNext(loopsp->fromp(), WidthVP(SELF, BOTH).p());
|
||||
AstNode* const fromp = loopsp->fromp();
|
||||
AstNodeExpr* const fromp = loopsp->fromp();
|
||||
UASSERT_OBJ(fromp->dtypep(), fromp, "Missing data type");
|
||||
AstNodeDType* fromDtp = fromp->dtypep()->skipRefp();
|
||||
// Split into for loop
|
||||
|
|
@ -4248,10 +4239,11 @@ private:
|
|||
sizep->dtypeSetSigned32();
|
||||
sizep->didWidth(true);
|
||||
sizep->protect(false);
|
||||
AstNode* const condp
|
||||
AstNodeExpr* const condp
|
||||
= new AstLt{fl, new AstVarRef{fl, varp, VAccess::READ}, sizep};
|
||||
AstNode* const incp = new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1},
|
||||
new AstVarRef{fl, varp, VAccess::READ}};
|
||||
AstNodeExpr* const incp
|
||||
= new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1},
|
||||
new AstVarRef{fl, varp, VAccess::READ}};
|
||||
loopp = createForeachLoop(nodep, bodyPointp, varp, leftp, condp, incp);
|
||||
}
|
||||
// Prep for next
|
||||
|
|
@ -4267,10 +4259,10 @@ private:
|
|||
AstVar* const first_varp = new AstVar{
|
||||
fl, VVarType::BLOCKTEMP, varp->name() + "__Vfirst", VFlagBitPacked{}, 1};
|
||||
first_varp->usedLoopIdx(true);
|
||||
AstNode* const firstp = new AstMethodCall{
|
||||
AstNodeExpr* const firstp = new AstMethodCall{
|
||||
fl, fromp->cloneTree(false), "first",
|
||||
new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}};
|
||||
AstNode* const nextp = new AstMethodCall{
|
||||
AstNodeExpr* const nextp = new AstMethodCall{
|
||||
fl, fromp->cloneTree(false), "next",
|
||||
new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}};
|
||||
AstNode* const first_clearp
|
||||
|
|
@ -4322,10 +4314,10 @@ private:
|
|||
AstNode* createForeachLoopRanged(AstForeach* nodep, AstNode* bodysp, AstVar* varp,
|
||||
const VNumRange& declRange) {
|
||||
FileLine* const fl = varp->fileline();
|
||||
auto* const leftp = new AstConst{fl, AstConst::Signed32{}, declRange.left()};
|
||||
auto* const rightp = new AstConst{fl, AstConst::Signed32{}, declRange.right()};
|
||||
AstNode* condp;
|
||||
AstNode* incp;
|
||||
AstNodeExpr* const leftp = new AstConst{fl, AstConst::Signed32{}, declRange.left()};
|
||||
AstNodeExpr* const rightp = new AstConst{fl, AstConst::Signed32{}, declRange.right()};
|
||||
AstNodeExpr* condp;
|
||||
AstNodeExpr* incp;
|
||||
if (declRange.left() < declRange.right()) {
|
||||
condp = new AstLte{fl, new AstVarRef{fl, varp, VAccess::READ}, rightp};
|
||||
incp = new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1},
|
||||
|
|
@ -4337,8 +4329,8 @@ private:
|
|||
}
|
||||
return createForeachLoop(nodep, bodysp, varp, leftp, condp, incp);
|
||||
}
|
||||
AstNode* createForeachLoop(AstForeach* nodep, AstNode* bodysp, AstVar* varp, AstNode* leftp,
|
||||
AstNode* condp, AstNode* incp) {
|
||||
AstNode* createForeachLoop(AstForeach* nodep, AstNode* bodysp, AstVar* varp,
|
||||
AstNodeExpr* leftp, AstNodeExpr* condp, AstNodeExpr* incp) {
|
||||
FileLine* const fl = varp->fileline();
|
||||
auto* const whilep = new AstWhile{
|
||||
fl, condp, bodysp, new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, incp}};
|
||||
|
|
@ -4454,7 +4446,7 @@ private:
|
|||
UINFO(9, " Display in " << nodep->text() << endl);
|
||||
string newFormat;
|
||||
bool inPct = false;
|
||||
AstNode* argp = nodep->exprsp();
|
||||
AstNodeExpr* argp = nodep->exprsp();
|
||||
const string txt = nodep->text();
|
||||
string fmt;
|
||||
for (char ch : txt) {
|
||||
|
|
@ -4472,7 +4464,7 @@ private:
|
|||
case 'l': break; // %m - auto insert "library"
|
||||
case 'd': { // Convert decimal to either 'd' or '#'
|
||||
if (argp) {
|
||||
AstNode* const nextp = argp->nextp();
|
||||
AstNodeExpr* const nextp = VN_AS(argp->nextp(), NodeExpr);
|
||||
if (argp->isDouble()) {
|
||||
spliceCvtS(argp, true, 64);
|
||||
ch = '~';
|
||||
|
|
@ -4501,14 +4493,18 @@ private:
|
|||
newFormat += "%@";
|
||||
VNRelinker handle;
|
||||
argp->unlinkFrBack(&handle);
|
||||
AstCExpr* const newp
|
||||
= new AstCExpr(nodep->fileline(), "VL_TO_STRING(", 0, true);
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstCExpr* const newp = new AstCExpr{flp, nullptr};
|
||||
newp->addExprsp(new AstText{flp, "VL_TO_STRING(", true});
|
||||
newp->addExprsp(argp);
|
||||
newp->addExprsp(new AstText(nodep->fileline(), ")", true));
|
||||
newp->addExprsp(new AstText{flp, ")", true});
|
||||
newp->dtypeSetString();
|
||||
newp->pure(true);
|
||||
newp->protect(false);
|
||||
handle.relink(newp);
|
||||
// Set argp to what we replaced it with, as we will keep processing the
|
||||
// next argument.
|
||||
argp = newp;
|
||||
} else {
|
||||
added = true;
|
||||
if (fmt == "%0") {
|
||||
|
|
@ -4517,19 +4513,19 @@ private:
|
|||
newFormat += "%d";
|
||||
}
|
||||
}
|
||||
if (argp) argp = argp->nextp();
|
||||
if (argp) argp = VN_AS(argp->nextp(), NodeExpr);
|
||||
break;
|
||||
}
|
||||
case 's': { // Convert string to pack string
|
||||
if (argp && argp->dtypep()->basicp()->isString()) { // Convert it
|
||||
ch = '@';
|
||||
}
|
||||
if (argp) argp = argp->nextp();
|
||||
if (argp) argp = VN_AS(argp->nextp(), NodeExpr);
|
||||
break;
|
||||
}
|
||||
case 't': { // Convert decimal time to realtime
|
||||
if (argp) {
|
||||
AstNode* const nextp = argp->nextp();
|
||||
AstNodeExpr* const nextp = VN_AS(argp->nextp(), NodeExpr);
|
||||
if (argp->isDouble()) ch = '^'; // Convert it
|
||||
if (nodep->timeunit().isNone()) {
|
||||
nodep->v3fatalSrc("display %t has no time units");
|
||||
|
|
@ -4541,7 +4537,7 @@ private:
|
|||
case 'f': // FALLTHRU
|
||||
case 'g': {
|
||||
if (argp) {
|
||||
AstNode* const nextp = argp->nextp();
|
||||
AstNodeExpr* const nextp = VN_AS(argp->nextp(), NodeExpr);
|
||||
if (!argp->isDouble()) {
|
||||
iterateCheckReal(nodep, "Display argument", argp, BOTH);
|
||||
}
|
||||
|
|
@ -4559,11 +4555,11 @@ private:
|
|||
} else {
|
||||
ch = nodep->missingArgChar();
|
||||
}
|
||||
if (argp) argp = argp->nextp();
|
||||
if (argp) argp = VN_AS(argp->nextp(), NodeExpr);
|
||||
break;
|
||||
}
|
||||
default: { // Most operators, just move to next argument
|
||||
if (argp) argp = argp->nextp();
|
||||
if (argp) argp = VN_AS(argp->nextp(), NodeExpr);
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
|
|
@ -5124,7 +5120,7 @@ private:
|
|||
for (const auto& tconnect : tconnects) {
|
||||
const AstVar* const portp = tconnect.first;
|
||||
AstArg* const argp = tconnect.second;
|
||||
AstNode* pinp = argp->exprp();
|
||||
AstNodeExpr* pinp = argp->exprp();
|
||||
if (!pinp) continue; // Argument error we'll find later
|
||||
// Prelim may cause the node to get replaced; we've lost our
|
||||
// pointer, so need to iterate separately later
|
||||
|
|
@ -5133,11 +5129,10 @@ private:
|
|||
UINFO(4, " sformat via metacomment: " << nodep << endl);
|
||||
VNRelinker handle;
|
||||
argp->unlinkFrBackWithNext(&handle); // Format + additional args, if any
|
||||
AstNode* argsp = nullptr;
|
||||
AstNodeExpr* argsp = nullptr;
|
||||
while (AstArg* const nextargp = VN_AS(argp->nextp(), Arg)) {
|
||||
argsp = AstNode::addNext(
|
||||
argsp, nextargp->exprp()
|
||||
->unlinkFrBackWithNext()); // Expression goes to SFormatF
|
||||
// Expression goes to SFormatF
|
||||
argsp = argsp->addNext(nextargp->exprp()->unlinkFrBackWithNext());
|
||||
nextargp->unlinkFrBack()->deleteTree(); // Remove the call's Arg wrapper
|
||||
}
|
||||
string format;
|
||||
|
|
@ -5167,7 +5162,7 @@ private:
|
|||
UINFO(4, " Add CvtPackString: " << pinp << endl);
|
||||
VNRelinker handle;
|
||||
pinp->unlinkFrBack(&handle); // No next, that's the next pin
|
||||
AstNode* const newp = new AstCvtPackString(pinp->fileline(), pinp);
|
||||
AstNodeExpr* const newp = new AstCvtPackString(pinp->fileline(), pinp);
|
||||
handle.relink(newp);
|
||||
pinp = newp;
|
||||
}
|
||||
|
|
@ -5181,7 +5176,7 @@ private:
|
|||
for (const auto& tconnect : tconnects) {
|
||||
AstVar* const portp = tconnect.first;
|
||||
const AstArg* const argp = tconnect.second;
|
||||
AstNode* const pinp = argp->exprp();
|
||||
AstNodeExpr* const pinp = argp->exprp();
|
||||
if (!pinp) continue; // Argument error we'll find later
|
||||
// Change data types based on above accept completion
|
||||
if (nodep->taskp()->dpiImport()) checkUnpackedArrayArgs(portp, pinp);
|
||||
|
|
@ -5194,7 +5189,7 @@ private:
|
|||
for (const auto& tconnect : tconnects) {
|
||||
const AstVar* const portp = tconnect.first;
|
||||
const AstArg* const argp = tconnect.second;
|
||||
AstNode* const pinp = argp->exprp();
|
||||
AstNodeExpr* const pinp = argp->exprp();
|
||||
if (!pinp) continue; // Argument error we'll find later
|
||||
// Do PRELIM again, because above accept may have exited early
|
||||
// due to node replacement
|
||||
|
|
@ -5827,7 +5822,7 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
void fixWidthExtend(AstNode* nodep, AstNodeDType* expDTypep, ExtendRule extendRule) {
|
||||
void fixWidthExtend(AstNodeExpr* nodep, AstNodeDType* expDTypep, ExtendRule extendRule) {
|
||||
// Fix the width mismatch by extending or truncating bits
|
||||
// *ONLY* call this from checkWidth()
|
||||
// Truncation is rarer, but can occur: parameter [3:0] FOO = 64'h12312;
|
||||
|
|
@ -5848,7 +5843,7 @@ private:
|
|||
V3Number num(nodep, expWidth);
|
||||
num.opAssign(constp->num());
|
||||
num.isSigned(false);
|
||||
AstNode* const newp = new AstConst(nodep->fileline(), num);
|
||||
AstNodeExpr* const newp = new AstConst(nodep->fileline(), num);
|
||||
constp->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(constp), constp);
|
||||
VL_DANGLING(nodep);
|
||||
|
|
@ -5857,7 +5852,7 @@ private:
|
|||
// Trunc - Extract
|
||||
VNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
AstNode* const newp = new AstSel(nodep->fileline(), nodep, 0, expWidth);
|
||||
AstNodeExpr* const newp = new AstSel(nodep->fileline(), nodep, 0, expWidth);
|
||||
newp->didWidth(true); // Don't replace dtype with unsigned
|
||||
linker.relink(newp);
|
||||
nodep = newp;
|
||||
|
|
@ -5872,9 +5867,9 @@ private:
|
|||
case EXTEND_LHS: doSigned = nodep->isSigned(); break;
|
||||
default: nodep->v3fatalSrc("bad case");
|
||||
}
|
||||
AstNode* const newp
|
||||
= (doSigned ? static_cast<AstNode*>(new AstExtendS{nodep->fileline(), nodep})
|
||||
: static_cast<AstNode*>(new AstExtend{nodep->fileline(), nodep}));
|
||||
AstNodeExpr* const newp
|
||||
= (doSigned ? static_cast<AstNodeExpr*>(new AstExtendS{nodep->fileline(), nodep})
|
||||
: static_cast<AstNodeExpr*>(new AstExtend{nodep->fileline(), nodep}));
|
||||
linker.relink(newp);
|
||||
nodep = newp;
|
||||
}
|
||||
|
|
@ -5882,14 +5877,14 @@ private:
|
|||
// For AstVar init() among others
|
||||
// TODO do all to-real and to-integer conversions in this function
|
||||
// rather than in callers
|
||||
AstNode* const newp = spliceCvtD(nodep);
|
||||
AstNodeExpr* const newp = spliceCvtD(nodep);
|
||||
nodep = newp;
|
||||
}
|
||||
nodep->dtypeFrom(expDTypep);
|
||||
UINFO(4, " _new: " << nodep << endl);
|
||||
}
|
||||
|
||||
void fixWidthReduce(AstNode* nodep) {
|
||||
void fixWidthReduce(AstNodeExpr* nodep) {
|
||||
// Fix the width mismatch by adding a reduction OR operator
|
||||
// IF (A(CONSTwide)) becomes IF (A(CONSTreduced))
|
||||
// IF (A(somewide)) becomes IF (A(REDOR(somewide)))
|
||||
|
|
@ -5902,7 +5897,7 @@ private:
|
|||
V3Number num(nodep, expWidth);
|
||||
num.opRedOr(constp->num());
|
||||
num.isSigned(expSigned);
|
||||
AstNode* const newp = new AstConst(nodep->fileline(), num);
|
||||
AstNodeExpr* const newp = new AstConst(nodep->fileline(), num);
|
||||
constp->replaceWith(newp);
|
||||
VL_DO_DANGLING(constp->deleteTree(), constp);
|
||||
VL_DANGLING(nodep);
|
||||
|
|
@ -5910,7 +5905,7 @@ private:
|
|||
} else {
|
||||
VNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
AstNode* const newp = new AstRedOr(nodep->fileline(), nodep);
|
||||
AstNodeExpr* const newp = new AstRedOr(nodep->fileline(), nodep);
|
||||
linker.relink(newp);
|
||||
nodep = newp;
|
||||
}
|
||||
|
|
@ -5918,14 +5913,14 @@ private:
|
|||
UINFO(4, " _new: " << nodep << endl);
|
||||
}
|
||||
|
||||
bool fixAutoExtend(AstNode*& nodepr, int expWidth) {
|
||||
bool fixAutoExtend(AstNodeExpr*& nodepr, int expWidth) {
|
||||
// For SystemVerilog '0,'1,'x,'z, autoextend and don't warn
|
||||
if (AstConst* const constp = VN_CAST(nodepr, Const)) {
|
||||
if (constp->num().autoExtend() && !constp->num().sized() && constp->width() == 1) {
|
||||
// Make it the proper size. Careful of proper extension of 0's/1's
|
||||
V3Number num(constp, expWidth);
|
||||
num.opRepl(constp->num(), expWidth); // {width{'1}}
|
||||
AstNode* const newp = new AstConst(constp->fileline(), num);
|
||||
AstNodeExpr* const newp = new AstConst(constp->fileline(), num);
|
||||
// Spec says always unsigned with proper width
|
||||
if (debug() > 4) constp->dumpTree(cout, " fixAutoExtend_old: ");
|
||||
if (debug() > 4) newp->dumpTree(cout, " _new: ");
|
||||
|
|
@ -5943,7 +5938,7 @@ private:
|
|||
<< expWidth << " bits: " << constp->prettyName());
|
||||
V3Number num(constp, expWidth);
|
||||
num.opExtendXZ(constp->num(), constp->width());
|
||||
AstNode* const newp = new AstConst(constp->fileline(), num);
|
||||
AstNodeExpr* const newp = new AstConst(constp->fileline(), num);
|
||||
// Spec says always unsigned with proper width
|
||||
if (debug() > 4) constp->dumpTree(cout, " fixUnszExtend_old: ");
|
||||
if (debug() > 4) newp->dumpTree(cout, " _new: ");
|
||||
|
|
@ -6037,7 +6032,7 @@ private:
|
|||
if (stage & PRELIM) {
|
||||
underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p());
|
||||
}
|
||||
underp = checkCvtUS(underp);
|
||||
underp = VN_IS(underp, NodeExpr) ? checkCvtUS(VN_AS(underp, NodeExpr)) : underp;
|
||||
AstNodeDType* const expDTypep = underp->dtypep();
|
||||
underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP);
|
||||
if (underp) {} // cppcheck
|
||||
|
|
@ -6076,14 +6071,14 @@ private:
|
|||
VNRelinker linker;
|
||||
underp->unlinkFrBack(&linker);
|
||||
AstNode* const newp
|
||||
= new AstNeqD(nodep->fileline(), underp,
|
||||
= new AstNeqD(nodep->fileline(), VN_AS(underp, NodeExpr),
|
||||
new AstConst(nodep->fileline(), AstConst::RealDouble(), 0.0));
|
||||
linker.relink(newp);
|
||||
} else if (VN_IS(underVDTypep, ClassRefDType)
|
||||
|| (VN_IS(underVDTypep, BasicDType)
|
||||
&& VN_AS(underVDTypep, BasicDType)->keyword() == VBasicDTypeKwd::CHANDLE)) {
|
||||
// Allow warning-free "if (handle)"
|
||||
VL_DO_DANGLING(fixWidthReduce(underp), underp); // Changed
|
||||
VL_DO_DANGLING(fixWidthReduce(VN_AS(underp, NodeExpr)), underp); // Changed
|
||||
} else if (!underVDTypep->basicp()) {
|
||||
nodep->v3error("Logical operator " << nodep->prettyTypeName()
|
||||
<< " expects a non-complex data type on the "
|
||||
|
|
@ -6105,7 +6100,7 @@ private:
|
|||
: "")
|
||||
<< " bits.");
|
||||
}
|
||||
VL_DO_DANGLING(fixWidthReduce(underp), underp); // Changed
|
||||
VL_DO_DANGLING(fixWidthReduce(VN_AS(underp, NodeExpr)), underp); // Changed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6131,17 +6126,17 @@ private:
|
|||
} else if (expDTypep->isDouble() && !underp->isDouble()) {
|
||||
AstNode* const oldp
|
||||
= underp; // Need FINAL on children; otherwise splice would block it
|
||||
underp = spliceCvtD(underp);
|
||||
underp = spliceCvtD(VN_AS(underp, NodeExpr));
|
||||
underp = userIterateSubtreeReturnEdits(oldp, WidthVP(SELF, FINAL).p());
|
||||
} else if (!expDTypep->isDouble() && underp->isDouble()) {
|
||||
AstNode* const oldp
|
||||
= underp; // Need FINAL on children; otherwise splice would block it
|
||||
underp = spliceCvtS(underp, true, expDTypep->width()); // Round RHS
|
||||
underp = spliceCvtS(VN_AS(underp, NodeExpr), true, expDTypep->width()); // Round RHS
|
||||
underp = userIterateSubtreeReturnEdits(oldp, WidthVP(SELF, FINAL).p());
|
||||
} else if (expDTypep->isString() && !underp->dtypep()->isString()) {
|
||||
AstNode* const oldp
|
||||
= underp; // Need FINAL on children; otherwise splice would block it
|
||||
underp = spliceCvtString(underp);
|
||||
underp = spliceCvtString(VN_AS(underp, NodeExpr));
|
||||
underp = userIterateSubtreeReturnEdits(oldp, WidthVP(SELF, FINAL).p());
|
||||
} else {
|
||||
const AstBasicDType* const expBasicp = expDTypep->basicp();
|
||||
|
|
@ -6185,7 +6180,8 @@ private:
|
|||
}
|
||||
// Note the check uses the expected size, not the child's subDTypep as we want the
|
||||
// child node's width to end up correct for the assignment (etc)
|
||||
widthCheckSized(nodep, side, underp, expDTypep, extendRule, warnOn);
|
||||
widthCheckSized(nodep, side, VN_AS(underp, NodeExpr), expDTypep, extendRule,
|
||||
warnOn);
|
||||
} else if (!VN_IS(expDTypep->skipRefp(), IfaceRefDType)
|
||||
&& VN_IS(underp->dtypep()->skipRefp(), IfaceRefDType)) {
|
||||
underp->v3error(ucfirst(nodep->prettyOperatorName())
|
||||
|
|
@ -6226,9 +6222,10 @@ private:
|
|||
return underp;
|
||||
}
|
||||
|
||||
void widthCheckSized(AstNode* nodep, const char* side,
|
||||
AstNode* underp, // Node to be checked or have typecast added in front of
|
||||
AstNodeDType* expDTypep, ExtendRule extendRule, bool warnOn = true) {
|
||||
void
|
||||
widthCheckSized(AstNode* nodep, const char* side,
|
||||
AstNodeExpr* underp, // Node to be checked or have typecast added in front of
|
||||
AstNodeDType* expDTypep, ExtendRule extendRule, bool warnOn = true) {
|
||||
// Issue warnings on sized number width mismatches, then do appropriate size extension
|
||||
// Generally iterateCheck is what is wanted instead of this
|
||||
// UINFO(9,"wchk "<<side<<endl<<" "<<nodep<<endl<<" "<<underp<<endl<<" e="<<expDTypep<<"
|
||||
|
|
@ -6305,7 +6302,7 @@ private:
|
|||
//----------------------------------------------------------------------
|
||||
// SIGNED/DOUBLE METHODS
|
||||
|
||||
AstNode* checkCvtUS(AstNode* nodep) {
|
||||
AstNodeExpr* checkCvtUS(AstNodeExpr* nodep) {
|
||||
if (nodep && nodep->isDouble()) {
|
||||
nodep->v3error("Expected integral (non-" << nodep->dtypep()->prettyDTypeName()
|
||||
<< ") input to "
|
||||
|
|
@ -6315,14 +6312,14 @@ private:
|
|||
return nodep;
|
||||
}
|
||||
|
||||
AstNode* spliceCvtD(AstNode* nodep) {
|
||||
AstNodeExpr* spliceCvtD(AstNodeExpr* nodep) {
|
||||
// For integer used in REAL context, convert to real
|
||||
// We don't warn here, "2.0 * 2" is common and reasonable
|
||||
if (nodep && !nodep->dtypep()->skipRefp()->isDouble()) {
|
||||
UINFO(6, " spliceCvtD: " << nodep << endl);
|
||||
VNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
AstNode* newp;
|
||||
AstNodeExpr* newp;
|
||||
if (nodep->dtypep()->skipRefp()->isSigned()) {
|
||||
newp = new AstISToRD(nodep->fileline(), nodep);
|
||||
} else {
|
||||
|
|
@ -6334,7 +6331,7 @@ private:
|
|||
return nodep;
|
||||
}
|
||||
}
|
||||
AstNode* spliceCvtS(AstNode* nodep, bool warnOn, int width) {
|
||||
AstNodeExpr* spliceCvtS(AstNodeExpr* nodep, bool warnOn, int width) {
|
||||
// IEEE-2012 11.8.1: Signed: Type coercion creates signed
|
||||
// 11.8.2: Argument to convert is self-determined
|
||||
if (nodep && nodep->dtypep()->skipRefp()->isDouble()) {
|
||||
|
|
@ -6352,7 +6349,7 @@ private:
|
|||
}
|
||||
}
|
||||
if (warnOn) nodep->v3warn(REALCVT, "Implicit conversion of real to integer");
|
||||
AstNode* const newp = new AstRToIRoundS(nodep->fileline(), nodep);
|
||||
AstNodeExpr* const newp = new AstRToIRoundS(nodep->fileline(), nodep);
|
||||
linker.relink(newp);
|
||||
newp->dtypeSetBitSized(width, VSigning::SIGNED);
|
||||
return newp;
|
||||
|
|
@ -6360,14 +6357,14 @@ private:
|
|||
return nodep;
|
||||
}
|
||||
}
|
||||
AstNode* spliceCvtString(AstNode* nodep) {
|
||||
AstNodeExpr* spliceCvtString(AstNodeExpr* nodep) {
|
||||
// IEEE-2012 11.8.1: Signed: Type coercion creates signed
|
||||
// 11.8.2: Argument to convert is self-determined
|
||||
if (nodep && !(nodep->dtypep()->basicp() && nodep->dtypep()->basicp()->isString())) {
|
||||
UINFO(6, " spliceCvtString: " << nodep << endl);
|
||||
VNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
AstNode* const newp = new AstCvtPackString(nodep->fileline(), nodep);
|
||||
AstNodeExpr* const newp = new AstCvtPackString(nodep->fileline(), nodep);
|
||||
linker.relink(newp);
|
||||
return newp;
|
||||
} else {
|
||||
|
|
@ -6393,8 +6390,8 @@ private:
|
|||
default: break;
|
||||
}
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeBiop* newp = nullptr;
|
||||
switch (nodep->type()) {
|
||||
case VNType::atGt: newp = new AstGtS(fl, lhsp, rhsp); break;
|
||||
|
|
@ -6428,8 +6425,8 @@ private:
|
|||
// Return new node or nullptr if nothing
|
||||
if (nodep->doubleFlavor()) return nullptr;
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeBiop* newp = nullptr;
|
||||
// No width change on output;... // All below have bool or double outputs
|
||||
switch (nodep->type()) {
|
||||
|
|
@ -6467,8 +6464,8 @@ private:
|
|||
// Return new node or nullptr if nothing
|
||||
if (nodep->stringFlavor()) return nullptr;
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeBiop* newp = nullptr;
|
||||
// No width change on output;... // All below have bool or double outputs
|
||||
switch (nodep->type()) {
|
||||
|
|
@ -6499,7 +6496,7 @@ private:
|
|||
// Return new node or nullptr if nothing
|
||||
if (nodep->doubleFlavor()) return nullptr;
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNodeUniop* newp = nullptr;
|
||||
switch (nodep->type()) {
|
||||
case VNType::atNegate: newp = new AstNegateD(fl, lhsp); break;
|
||||
|
|
@ -6744,7 +6741,7 @@ private:
|
|||
|
||||
// Find valid values and populate
|
||||
UASSERT_OBJ(nodep->itemsp(), nodep, "enum without items");
|
||||
std::map<uint64_t, AstNode*> values;
|
||||
std::map<uint64_t, AstNodeExpr*> values;
|
||||
{
|
||||
AstEnumItem* const firstp = nodep->itemsp();
|
||||
const AstEnumItem* prevp = firstp; // Prev must start with last item
|
||||
|
|
@ -6942,7 +6939,7 @@ private:
|
|||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
AstNode* newVarRefDollarUnit(AstVar* nodep) {
|
||||
AstVarRef* newVarRefDollarUnit(AstVar* nodep) {
|
||||
AstVarRef* const varrefp = new AstVarRef{nodep->fileline(), nodep, VAccess::READ};
|
||||
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
|
||||
return varrefp;
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ private:
|
|||
return FromData(errp, ddtypep, fromRange);
|
||||
}
|
||||
|
||||
AstNode* newSubNeg(AstNode* lhsp, int32_t rhs) {
|
||||
AstNodeExpr* newSubNeg(AstNodeExpr* lhsp, int32_t rhs) {
|
||||
// Return lhs-rhs, but if rhs is negative use an add, so we won't
|
||||
// have to deal with signed math and related 32bit sign extension problems
|
||||
if (rhs == 0) {
|
||||
|
|
@ -126,17 +126,16 @@ private:
|
|||
V3Number num(lhsp, lhsp->width());
|
||||
num.opSub(VN_AS(lhsp, Const)->num(), V3Number(lhsp, 32, rhs));
|
||||
num.isSigned(lhsp->isSigned());
|
||||
AstNode* const newp = new AstConst(lhsp->fileline(), num);
|
||||
return newp;
|
||||
return new AstConst(lhsp->fileline(), num);
|
||||
} else if (rhs > 0) {
|
||||
AstNode* const newp
|
||||
AstNodeExpr* const newp
|
||||
= new AstSub(lhsp->fileline(), lhsp,
|
||||
new AstConst(lhsp->fileline(), AstConst::Unsized32(), rhs));
|
||||
// We must make sure sub gets sign of original value, not from the constant
|
||||
newp->dtypeFrom(lhsp);
|
||||
return newp;
|
||||
} else { // rhs < 0;
|
||||
AstNode* const newp
|
||||
AstNodeExpr* const newp
|
||||
= new AstAdd(lhsp->fileline(), lhsp,
|
||||
new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs));
|
||||
// We must make sure sub gets sign of original value, not from the constant
|
||||
|
|
@ -144,16 +143,16 @@ private:
|
|||
return newp;
|
||||
}
|
||||
}
|
||||
AstNode* newSubNeg(int32_t lhs, AstNode* rhsp) {
|
||||
AstNodeExpr* newSubNeg(int32_t lhs, AstNodeExpr* rhsp) {
|
||||
// Return lhs-rhs
|
||||
// We must make sure sub gets sign of original value
|
||||
AstNode* const newp = new AstSub(
|
||||
AstNodeExpr* const newp = new AstSub(
|
||||
rhsp->fileline(), new AstConst(rhsp->fileline(), AstConst::Unsized32(), lhs), rhsp);
|
||||
newp->dtypeFrom(rhsp); // Important as AstSub default is lhs's sign
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstNode* newSubLsbOf(AstNode* underp, const VNumRange& fromRange) {
|
||||
AstNodeExpr* newSubLsbOf(AstNodeExpr* underp, const VNumRange& fromRange) {
|
||||
// Account for a variable's LSB in bit selections
|
||||
// Will likely become SUB(underp, lsb_of_signal).
|
||||
// Don't report WIDTH warnings etc here, as may be inside a
|
||||
|
|
@ -165,12 +164,10 @@ private:
|
|||
} else {
|
||||
if (fromRange.littleEndian()) {
|
||||
// reg [1:3] was swapped to [3:1] (lsbEndianedp==3) and needs a SUB(3,under)
|
||||
AstNode* const newp = newSubNeg(fromRange.hi(), underp);
|
||||
return newp;
|
||||
return newSubNeg(fromRange.hi(), underp);
|
||||
} else {
|
||||
// reg [3:1] needs a SUB(under,1)
|
||||
AstNode* const newp = newSubNeg(underp, fromRange.lo());
|
||||
return newp;
|
||||
return newSubNeg(underp, fromRange.lo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -209,8 +206,8 @@ private:
|
|||
UINFO(6, "SELBIT " << nodep << endl);
|
||||
if (debug() >= 9) nodep->backp()->dumpTree(cout, "--SELBT0: ");
|
||||
// lhsp/rhsp do not need to be constant
|
||||
AstNode* const fromp = nodep->fromp()->unlinkFrBack();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack(); // bit we're extracting
|
||||
AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack(); // bit we're extracting
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "--SELBT2: ");
|
||||
const FromData fromdata = fromDataForArray(nodep, fromp);
|
||||
AstNodeDType* const ddtypep = fromdata.m_dtypep;
|
||||
|
|
@ -218,7 +215,7 @@ private:
|
|||
UINFO(6, " ddtypep " << ddtypep << endl);
|
||||
if (const AstUnpackArrayDType* const adtypep = VN_CAST(ddtypep, UnpackArrayDType)) {
|
||||
// SELBIT(array, index) -> ARRAYSEL(array, index)
|
||||
AstNode* subp = rhsp;
|
||||
AstNodeExpr* subp = rhsp;
|
||||
if (fromRange.lo() != 0 || fromRange.hi() < 0) {
|
||||
subp = newSubNeg(subp, fromRange.lo());
|
||||
}
|
||||
|
|
@ -229,7 +226,7 @@ private:
|
|||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (const AstPackArrayDType* const adtypep = VN_CAST(ddtypep, PackArrayDType)) {
|
||||
// SELBIT(array, index) -> SEL(array, index*width-of-subindex, width-of-subindex)
|
||||
AstNode* subp = rhsp;
|
||||
AstNodeExpr* subp = rhsp;
|
||||
if (fromRange.littleEndian()) {
|
||||
subp = newSubNeg(fromRange.hi(), subp);
|
||||
} else {
|
||||
|
|
@ -253,7 +250,7 @@ private:
|
|||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (const AstAssocArrayDType* const adtypep = VN_CAST(ddtypep, AssocArrayDType)) {
|
||||
// SELBIT(array, index) -> ASSOCSEL(array, index)
|
||||
AstNode* const subp = rhsp;
|
||||
AstNodeExpr* const subp = rhsp;
|
||||
AstAssocSel* const newp = new AstAssocSel(nodep->fileline(), fromp, subp);
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
|
|
@ -262,7 +259,7 @@ private:
|
|||
} else if (const AstWildcardArrayDType* const adtypep
|
||||
= VN_CAST(ddtypep, WildcardArrayDType)) {
|
||||
// SELBIT(array, index) -> WILDCARDSEL(array, index)
|
||||
AstNode* const subp = rhsp;
|
||||
AstNodeExpr* const subp = rhsp;
|
||||
AstWildcardSel* const newp = new AstWildcardSel{nodep->fileline(), fromp, subp};
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
|
|
@ -270,7 +267,7 @@ private:
|
|||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (const AstDynArrayDType* const adtypep = VN_CAST(ddtypep, DynArrayDType)) {
|
||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||
AstNode* const subp = rhsp;
|
||||
AstNodeExpr* const subp = rhsp;
|
||||
AstCMethodHard* const newp = new AstCMethodHard(nodep->fileline(), fromp, "at", subp);
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTq: ");
|
||||
|
|
@ -278,7 +275,7 @@ private:
|
|||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (const AstQueueDType* const adtypep = VN_CAST(ddtypep, QueueDType)) {
|
||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||
AstNode* const subp = rhsp;
|
||||
AstNodeExpr* const subp = rhsp;
|
||||
AstCMethodHard* const newp = new AstCMethodHard(nodep->fileline(), fromp, "at", subp);
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTq: ");
|
||||
|
|
@ -291,7 +288,7 @@ private:
|
|||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: String array operation on non-variable");
|
||||
}
|
||||
AstNode* newp;
|
||||
AstNodeExpr* newp;
|
||||
if (varrefp && varrefp->access().isReadOnly()) {
|
||||
newp = new AstGetcN(nodep->fileline(), fromp, rhsp);
|
||||
} else {
|
||||
|
|
@ -345,9 +342,9 @@ private:
|
|||
"First value of [a:b] isn't a constant, maybe you want +: or -:");
|
||||
checkConstantOrReplace(nodep->rightp(),
|
||||
"Second value of [a:b] isn't a constant, maybe you want +: or -:");
|
||||
AstNode* const fromp = nodep->fromp()->unlinkFrBack();
|
||||
AstNode* const msbp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* const lsbp = nodep->thsp()->unlinkFrBack();
|
||||
AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* const msbp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const lsbp = nodep->thsp()->unlinkFrBack();
|
||||
int32_t msb = VN_AS(msbp, Const)->toSInt();
|
||||
int32_t lsb = VN_AS(lsbp, Const)->toSInt();
|
||||
const int32_t elem = (msb > lsb) ? (msb - lsb + 1) : (lsb - msb + 1);
|
||||
|
|
@ -424,7 +421,7 @@ private:
|
|||
msb = lsb;
|
||||
lsb = x;
|
||||
}
|
||||
AstNode* const widthp
|
||||
AstNodeExpr* const widthp
|
||||
= new AstConst(msbp->fileline(),
|
||||
AstConst::Unsized32(), // Unsized so width from user
|
||||
msb + 1 - lsb);
|
||||
|
|
@ -447,7 +444,7 @@ private:
|
|||
msb = lsb;
|
||||
lsb = x;
|
||||
}
|
||||
AstNode* const widthp
|
||||
AstNodeExpr* const widthp
|
||||
= new AstConst(msbp->fileline(),
|
||||
AstConst::Unsized32(), // Unsized so width from user
|
||||
msb + 1 - lsb);
|
||||
|
|
@ -493,9 +490,9 @@ private:
|
|||
checkConstantOrReplace(nodep->thsp(), "Width of :+ or :- bit extract isn't a constant");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "--SELPM3: ");
|
||||
// Now replace it with an AstSel
|
||||
AstNode* const fromp = nodep->fromp()->unlinkFrBack();
|
||||
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* const widthp = nodep->thsp()->unlinkFrBack();
|
||||
AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const widthp = nodep->thsp()->unlinkFrBack();
|
||||
warnTri(rhsp);
|
||||
const int width = VN_AS(widthp, Const)->toSInt();
|
||||
if (width > (1 << 28)) {
|
||||
|
|
@ -536,13 +533,13 @@ private:
|
|||
|| (VN_IS(ddtypep, NodeUOrStructDType)
|
||||
&& VN_AS(ddtypep, NodeUOrStructDType)->packedUnsup())) {
|
||||
int elwidth = 1;
|
||||
AstNode* newwidthp = widthp;
|
||||
AstNodeExpr* newwidthp = widthp;
|
||||
if (const AstPackArrayDType* const adtypep = VN_CAST(ddtypep, PackArrayDType)) {
|
||||
elwidth = adtypep->width() / fromRange.elements();
|
||||
newwidthp
|
||||
= new AstConst(nodep->fileline(), AstConst::Unsized32(), width * elwidth);
|
||||
}
|
||||
AstNode* newlsbp = nullptr;
|
||||
AstNodeExpr* newlsbp = nullptr;
|
||||
if (VN_IS(nodep, SelPlus)) {
|
||||
if (fromRange.littleEndian()) {
|
||||
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
|
||||
|
|
|
|||
15
src/astgen
15
src/astgen
|
|
@ -425,9 +425,10 @@ class Cpt:
|
|||
key=lambda val: self._exec_syms[val]):
|
||||
argnp = self._exec_syms[sym]
|
||||
arg = self.add_nodep(sym)
|
||||
out += "AstNode* " + argnp + " = " + arg + "->unlinkFrBack();\n"
|
||||
out += "AstNodeExpr* " + argnp + " = " + arg + "->unlinkFrBack();\n"
|
||||
|
||||
out += "AstNode* newp = " + self._exec_new_recurse(aref) + ";\n"
|
||||
out += "AstNodeExpr* newp = " + self._exec_new_recurse(
|
||||
aref) + ";\n"
|
||||
out += "nodep->replaceWith(newp);"
|
||||
out += "VL_DO_DANGLING(nodep->deleteTree(), nodep);"
|
||||
elif func == "NEVER":
|
||||
|
|
@ -918,12 +919,18 @@ def write_ast_macros(filename):
|
|||
for node in AstNodeList:
|
||||
fh.write("#define ASTGEN_MEMBERS_Ast{t} \\\n".format(t=node.name))
|
||||
emitBlock('''\
|
||||
static Ast{t}* cloneTreeNull(Ast{t}* nodep, bool cloneNextLink) {{
|
||||
return nodep ? nodep->cloneTree(cloneNextLink) : nullptr;
|
||||
Ast{t}* unlinkFrBack(VNRelinker* linkerp = nullptr) {{
|
||||
return static_cast<Ast{t}*>(AstNode::unlinkFrBack(linkerp));
|
||||
}}
|
||||
Ast{t}* unlinkFrBackWithNext(VNRelinker* linkerp = nullptr) {{
|
||||
return static_cast<Ast{t}*>(AstNode::unlinkFrBackWithNext(linkerp));
|
||||
}}
|
||||
Ast{t}* cloneTree(bool cloneNext) {{
|
||||
return static_cast<Ast{t}*>(AstNode::cloneTree(cloneNext));
|
||||
}}
|
||||
static Ast{t}* cloneTreeNull(Ast{t}* nodep, bool cloneNextLink) {{
|
||||
return nodep ? nodep->cloneTree(cloneNextLink) : nullptr;
|
||||
}}
|
||||
Ast{t}* clonep() const VL_MT_SAFE {{ return static_cast<Ast{t}*>(AstNode::clonep()); }}
|
||||
Ast{t}* addNext(Ast{t}* nodep) {{ return static_cast<Ast{t}*>(AstNode::addNext(this, nodep)); }}
|
||||
''',
|
||||
|
|
|
|||
113
src/verilog.y
113
src/verilog.y
|
|
@ -112,7 +112,7 @@ public:
|
|||
}
|
||||
|
||||
// METHODS
|
||||
AstArg* argWrapList(AstNode* nodep);
|
||||
AstArg* argWrapList(AstNodeExpr* nodep);
|
||||
bool allTracingOn(FileLine* fl) {
|
||||
return v3Global.opt.trace() && m_tracingParse && fl->tracingOn();
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ public:
|
|||
AstNode::addNext<AstNode, AstNode>(nodep, new AstStop(fileline, true));
|
||||
return nodep;
|
||||
}
|
||||
AstNode* createGatePin(AstNode* exprp) {
|
||||
AstNodeExpr* createGatePin(AstNodeExpr* exprp) {
|
||||
AstRange* const rangep = m_gateRangep;
|
||||
if (!rangep) {
|
||||
return exprp;
|
||||
|
|
@ -2238,7 +2238,7 @@ enumNameRangeE<rangep>: // IEEE: second part of enum_name_declaration
|
|||
{ $$ = new AstRange{$1, $2, $4}; }
|
||||
;
|
||||
|
||||
enumNameStartE<nodep>: // IEEE: third part of enum_name_declaration
|
||||
enumNameStartE<nodeExprp>: // IEEE: third part of enum_name_declaration
|
||||
/* empty */ { $$ = nullptr; }
|
||||
| '=' constExpr { $$ = $2; }
|
||||
;
|
||||
|
|
@ -2790,7 +2790,7 @@ delay_control<delayp>: //== IEEE: delay_control
|
|||
{ $$ = new AstDelay{$<fl>1, $3}; RISEFALLDLYUNSUP($3); DEL($5); DEL($7); }
|
||||
;
|
||||
|
||||
delay_value<nodep>: // ==IEEE:delay_value
|
||||
delay_value<nodeExprp>: // ==IEEE:delay_value
|
||||
// // IEEE: ps_identifier
|
||||
packageClassScopeE varRefBase { $$ = AstDot::newIfPkg($<fl>2, $1, $2); }
|
||||
| yaINTNUM { $$ = new AstConst($<fl>1, *$1); }
|
||||
|
|
@ -2798,11 +2798,11 @@ delay_value<nodep>: // ==IEEE:delay_value
|
|||
| timeNumAdjusted { $$ = $1; }
|
||||
;
|
||||
|
||||
delayExpr<nodep>:
|
||||
delayExpr<nodeExprp>:
|
||||
expr { $$ = $1; }
|
||||
;
|
||||
|
||||
minTypMax<nodep>: // IEEE: mintypmax_expression and constant_mintypmax_expression
|
||||
minTypMax<nodeExprp>: // IEEE: mintypmax_expression and constant_mintypmax_expression
|
||||
delayExpr { $$ = $1; }
|
||||
| delayExpr ':' delayExpr ':' delayExpr { $$ = $3; MINTYPMAXDLYUNSUP($3); DEL($1); DEL($5); }
|
||||
;
|
||||
|
|
@ -3312,20 +3312,24 @@ statement_item<nodep>: // IEEE: statement_item
|
|||
FileLine* const newfl = new FileLine{$$->fileline()};
|
||||
newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true);
|
||||
$$->fileline(newfl);
|
||||
if (AstNodeExpr* const exprp = VN_CAST($$, NodeExpr)) $$ = exprp->makeStmt(); }
|
||||
$$ = VN_AS($$, NodeExpr)->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);
|
||||
if (AstNodeExpr* const exprp = VN_CAST($$, NodeExpr)) $$ = exprp->makeStmt(); }
|
||||
$$ = VN_AS($$, NodeExpr)->makeStmt(); }
|
||||
| yVOID yP_TICK '(' system_t_call ')' ';'
|
||||
{ $$ = $4;
|
||||
FileLine* const newfl = new FileLine{$$->fileline()};
|
||||
newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true);
|
||||
$$->fileline(newfl); }
|
||||
// // 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;
|
||||
if (AstNodeExpr* const exprp = VN_CAST($$, NodeExpr)) $$ = exprp->makeStmt(); }
|
||||
| task_subroutine_callNoMethod ';' { $$ = $1->makeStmt(); }
|
||||
//UNSUP fexpr '.' array_methodNoRoot ';' { UNSUP }
|
||||
| fexpr '.' task_subroutine_callNoMethod ';' { $$ = (new AstDot{$<fl>2, false, $1, $3})->makeStmt(); }
|
||||
| system_t_call ';' { $$ = $1; }
|
||||
//UNSUP fexprScope ';' { UNSUP }
|
||||
// // Not here in IEEE; from class_constructor_declaration
|
||||
// // Because we've joined class_constructor_declaration into generic functions
|
||||
|
|
@ -3496,14 +3500,14 @@ finc_or_dec_expression<nodeExprp>: // ==IEEE: inc_or_dec_expression
|
|||
//UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/pev_/g}) // {copied}
|
||||
//UNSUP ;
|
||||
|
||||
class_new<nodep>: // ==IEEE: class_new
|
||||
class_new<nodeExprp>: // ==IEEE: class_new
|
||||
// // Special precence so (...) doesn't match expr
|
||||
yNEW__ETC { $$ = new AstNew($1, nullptr); }
|
||||
| yNEW__ETC expr { $$ = new AstNewCopy($1, $2); }
|
||||
| yNEW__PAREN '(' list_of_argumentsE ')' { $$ = new AstNew($1, $3); }
|
||||
;
|
||||
|
||||
dynamic_array_new<nodep>: // ==IEEE: dynamic_array_new
|
||||
dynamic_array_new<nodeExprp>: // ==IEEE: dynamic_array_new
|
||||
yNEW__ETC '[' expr ']' { $$ = new AstNewDynamic($1, $3, nullptr); }
|
||||
| yNEW__ETC '[' expr ']' '(' expr ')' { $$ = new AstNewDynamic($1, $3, $6); }
|
||||
;
|
||||
|
|
@ -3569,16 +3573,16 @@ rand_case_itemList<caseItemp>: // IEEE: { rand_case_item + ... }
|
|||
| rand_case_itemList expr colon stmtBlock { $$ = $1->addNext(new AstCaseItem{$3, $2, $4}); }
|
||||
;
|
||||
|
||||
open_range_list<nodep>: // ==IEEE: open_range_list + open_value_range
|
||||
open_range_list<nodeExprp>: // ==IEEE: open_range_list + open_value_range
|
||||
open_value_range { $$ = $1; }
|
||||
| open_range_list ',' open_value_range { $$ = $1->addNext($3); }
|
||||
;
|
||||
|
||||
open_value_range<nodep>: // ==IEEE: open_value_range
|
||||
open_value_range<nodeExprp>: // ==IEEE: open_value_range
|
||||
value_range { $$ = $1; }
|
||||
;
|
||||
|
||||
value_range<nodep>: // ==IEEE: value_range
|
||||
value_range<nodeExprp>: // ==IEEE: value_range
|
||||
expr { $$ = $1; }
|
||||
| '[' expr ':' expr ']' { $$ = new AstInsideRange($1, $2, $4); }
|
||||
;
|
||||
|
|
@ -3588,7 +3592,7 @@ value_range<nodep>: // ==IEEE: value_range
|
|||
//UNSUP | '[' cgexpr ':' cgexpr ']' { }
|
||||
//UNSUP ;
|
||||
|
||||
caseCondList<nodep>: // IEEE: part of case_item
|
||||
caseCondList<nodeExprp>: // IEEE: part of case_item
|
||||
expr { $$ = $1; }
|
||||
| caseCondList ',' expr { $$ = $1->addNext($3); }
|
||||
;
|
||||
|
|
@ -3752,14 +3756,13 @@ funcRef<nodeExprp>: // IEEE: part of tf_call
|
|||
//UNSUP: idDotted is really just id to allow dotted method calls
|
||||
;
|
||||
|
||||
task_subroutine_callNoMethod<nodep>: // function_subroutine_callNoMethod (as task)
|
||||
task_subroutine_callNoMethod<nodeExprp>: // function_subroutine_callNoMethod (as task)
|
||||
// // IEEE: tf_call
|
||||
taskRef { $$ = $1; }
|
||||
// // funcref below not task ref to avoid conflict, must later handle either
|
||||
| funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse{$2, $1, $4}; }
|
||||
// // can call as method and yWITH without parenthesis
|
||||
| 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
|
||||
// // IEEE: randomize_call
|
||||
|
|
@ -3785,9 +3788,11 @@ function_subroutine_callNoMethod<nodeExprp>: // IEEE: function_subroutine
|
|||
| funcRef yWITH__CUR '{' '}' { $$ = new AstWithParse{$2, $1, nullptr}; }
|
||||
;
|
||||
|
||||
system_t_call<nodep>: // IEEE: system_tf_call (as task)
|
||||
system_t_call<nodeStmtp>: // IEEE: system_tf_call (as task)
|
||||
//
|
||||
yaD_PLI systemDpiArgsE { $$ = new AstTaskRef($<fl>1, *$1, $2); VN_CAST($$, TaskRef)->pli(true); }
|
||||
yaD_PLI systemDpiArgsE { AstTaskRef* const refp = new AstTaskRef{$<fl>1, *$1, $2};
|
||||
refp->pli(true);
|
||||
$$ = refp->makeStmt(); }
|
||||
//
|
||||
| yD_DUMPPORTS '(' idDotted ',' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::FILE, $5); DEL($3);
|
||||
$$->addNext(new AstDumpCtl($<fl>1, VDumpCtlType::VARS,
|
||||
|
|
@ -3928,7 +3933,7 @@ system_f_call<nodeExprp>: // IEEE: system_tf_call (as func)
|
|||
| system_f_call_or_t { $$ = $1; }
|
||||
;
|
||||
|
||||
systemDpiArgsE<nodep>: // IEEE: part of system_if_call for aruments of $dpi call
|
||||
systemDpiArgsE<argp>: // IEEE: part of system_if_call for aruments of $dpi call
|
||||
parenE { $$ = nullptr; }
|
||||
| '(' exprList ')' { $$ = GRAMMARP->argWrapList($2); }
|
||||
;
|
||||
|
|
@ -4088,7 +4093,7 @@ exprOrDataType<nodep>: // expr | data_type: combined to prevent conflic
|
|||
//UNSUP | exprOrDataTypeList ',' exprOrDataType { $$ = addNextNull($1, $3); }
|
||||
//UNSUP ;
|
||||
|
||||
list_of_argumentsE<nodep>: // IEEE: [list_of_arguments]
|
||||
list_of_argumentsE<nodeExprp>: // IEEE: [list_of_arguments]
|
||||
argsDottedList { $$ = $1; }
|
||||
| argsExprListE
|
||||
{ if (VN_IS($1, Arg) && VN_CAST($1, Arg)->emptyConnectNoNext()) {
|
||||
|
|
@ -4325,7 +4330,7 @@ array_methodNoRoot<nodeFTaskRefp>:
|
|||
| yUNIQUE { $$ = new AstFuncRef($1, "unique", nullptr); }
|
||||
;
|
||||
|
||||
array_methodWith<nodep>:
|
||||
array_methodWith<nodeExprp>:
|
||||
array_methodNoRoot parenE { $$ = $1; }
|
||||
| array_methodNoRoot parenE yWITH__PAREN '(' expr ')'
|
||||
{ $$ = new AstWithParse{$3, $1, $5}; }
|
||||
|
|
@ -4390,7 +4395,7 @@ dpi_tf_TraceInitE<cbool>: // Verilator extension
|
|||
// ~p~ means this is a (p)arenthetized expression
|
||||
// it will get replaced by "", or "s"equence
|
||||
|
||||
exprEqE<nodep>: // IEEE: optional '=' expression (part of param_assignment)
|
||||
exprEqE<nodeExprp>: // IEEE: optional '=' expression (part of param_assignment)
|
||||
// // constant_param_expression: '$' is in expr
|
||||
/*empty*/ { $$ = nullptr; }
|
||||
| '=' expr { $$ = $2; }
|
||||
|
|
@ -4766,12 +4771,12 @@ commaVRDListE<nodep>:
|
|||
| ',' vrdList { $$ = $2; }
|
||||
;
|
||||
|
||||
argsExprList<nodep>: // IEEE: part of list_of_arguments (used where ,, isn't legal)
|
||||
argsExprList<nodeExprp>: // IEEE: part of list_of_arguments (used where ,, isn't legal)
|
||||
expr { $$ = $1; }
|
||||
| argsExprList ',' expr { $$ = $1->addNext($3); }
|
||||
;
|
||||
|
||||
argsExprListE<nodep>: // IEEE: part of list_of_arguments
|
||||
argsExprListE<nodeExprp>: // IEEE: part of list_of_arguments
|
||||
argsExprOneE { $$ = $1; }
|
||||
| argsExprListE ',' argsExprOneE { $$ = $1->addNext($3); }
|
||||
;
|
||||
|
|
@ -4781,7 +4786,7 @@ argsExprListE<nodep>: // IEEE: part of list_of_arguments
|
|||
//UNSUP | pev_argsExprListE ',' pev_argsExprOneE { $$ = addNextNull($1, $3); }
|
||||
//UNSUP ;
|
||||
|
||||
argsExprOneE<nodep>: // IEEE: part of list_of_arguments
|
||||
argsExprOneE<nodeExprp>: // IEEE: part of list_of_arguments
|
||||
/*empty*/ { $$ = new AstArg(CRELINE(), "", nullptr); }
|
||||
| expr { $$ = new AstArg($1->fileline(), "", $1); }
|
||||
;
|
||||
|
|
@ -4791,7 +4796,7 @@ argsExprOneE<nodep>: // IEEE: part of list_of_arguments
|
|||
//UNSUP | pev_expr { $$ = $1; }
|
||||
//UNSUP ;
|
||||
|
||||
argsDottedList<nodep>: // IEEE: part of list_of_arguments
|
||||
argsDottedList<nodeExprp>: // IEEE: part of list_of_arguments
|
||||
argsDotted { $$ = $1; }
|
||||
| argsDottedList ',' argsDotted { $$ = addNextNull($1, $3); }
|
||||
;
|
||||
|
|
@ -4801,7 +4806,7 @@ argsDottedList<nodep>: // IEEE: part of list_of_arguments
|
|||
//UNSUP | pev_argsDottedList ',' pev_argsDotted { $$ = addNextNull($1, $3); }
|
||||
//UNSUP ;
|
||||
|
||||
argsDotted<nodep>: // IEEE: part of list_of_arguments
|
||||
argsDotted<nodeExprp>: // IEEE: part of list_of_arguments
|
||||
'.' idAny '(' ')' { $$ = new AstArg($<fl>2, *$2, nullptr); }
|
||||
| '.' idAny '(' expr ')' { $$ = new AstArg($<fl>2, *$2, $4); }
|
||||
;
|
||||
|
|
@ -4811,7 +4816,7 @@ argsDotted<nodep>: // IEEE: part of list_of_arguments
|
|||
//UNSUP | '.' idAny '(' pev_expr ')' { $$ = new AstArg($<fl>2, *$2, $4); }
|
||||
//UNSUP ;
|
||||
|
||||
streaming_concatenation<nodeExprp>: // ==IEEE: streaming_concatenation
|
||||
streaming_concatenation<nodeStreamp>: // ==IEEE: streaming_concatenation
|
||||
// // Need to disambiguate {<< expr-{ ... expr-} stream_concat }
|
||||
// // From {<< stream-{ ... stream-} }
|
||||
// // Likewise simple_type's idScoped from constExpr's idScope
|
||||
|
|
@ -4824,12 +4829,16 @@ streaming_concatenation<nodeExprp>: // ==IEEE: streaming_concatenation
|
|||
| '{' yP_SRIGHT stream_concatenation '}'
|
||||
{ $$ = new AstStreamR($2, $3, new AstConst($2, 1)); }
|
||||
| '{' yP_SLEFT stream_expressionOrDataType stream_concatenation '}'
|
||||
{ $$ = new AstStreamL($2, $4, $3); }
|
||||
{ AstNodeExpr* const bitsp = VN_IS($3, NodeExpr) ? VN_AS($3, NodeExpr)
|
||||
: new AstAttrOf{$1, VAttrType::DIM_BITS, $3};
|
||||
$$ = new AstStreamL($2, $4, bitsp); }
|
||||
| '{' yP_SRIGHT stream_expressionOrDataType stream_concatenation '}'
|
||||
{ $$ = new AstStreamR($2, $4, $3); }
|
||||
{ AstNodeExpr* const bitsp = VN_IS($3, NodeExpr) ? VN_AS($3, NodeExpr)
|
||||
: new AstAttrOf{$1, VAttrType::DIM_BITS, $3};
|
||||
$$ = new AstStreamR($2, $4, bitsp); }
|
||||
;
|
||||
|
||||
stream_concatenation<nodep>: // ==IEEE: stream_concatenation
|
||||
stream_concatenation<nodeExprp>: // ==IEEE: stream_concatenation
|
||||
// // '{' { stream_expression } '}'
|
||||
'{' cateList '}' { $$ = $2; }
|
||||
;
|
||||
|
|
@ -5017,24 +5026,24 @@ gateFront<nodep>:
|
|||
| gateRangeE '(' { $$ = $1; $<fl>$ = $<fl>2; }
|
||||
;
|
||||
|
||||
gateAndPinList<nodep>:
|
||||
gateAndPinList<nodeExprp>:
|
||||
gatePinExpr { $$ = $1; }
|
||||
| gateAndPinList ',' gatePinExpr { $$ = new AstAnd($2,$1,$3); }
|
||||
;
|
||||
gateOrPinList<nodep>:
|
||||
gateOrPinList<nodeExprp>:
|
||||
gatePinExpr { $$ = $1; }
|
||||
| gateOrPinList ',' gatePinExpr { $$ = new AstOr($2,$1,$3); }
|
||||
;
|
||||
gateXorPinList<nodep>:
|
||||
gateXorPinList<nodeExprp>:
|
||||
gatePinExpr { $$ = $1; }
|
||||
| gateXorPinList ',' gatePinExpr { $$ = new AstXor($2,$1,$3); }
|
||||
;
|
||||
gateUnsupPinList<nodep>:
|
||||
gateUnsupPinList<nodeExprp>:
|
||||
gatePinExpr { $$ = $1; }
|
||||
| gateUnsupPinList ',' gatePinExpr { $$ = $1->addNext($3); }
|
||||
;
|
||||
|
||||
gatePinExpr<nodep>:
|
||||
gatePinExpr<nodeExprp>:
|
||||
expr { $$ = GRAMMARP->createGatePin($1); }
|
||||
;
|
||||
|
||||
|
|
@ -5188,7 +5197,7 @@ idClassSel<nodeExprp>: // Misc Ref to dotted, and/or arraye
|
|||
| packageClassScope idDotted { $$ = new AstDot($<fl>2, true, $1, $2); }
|
||||
;
|
||||
|
||||
idClassSelForeach<nodep>:
|
||||
idClassSelForeach<nodeExprp>:
|
||||
idDottedForeach { $$ = $1; }
|
||||
// // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select
|
||||
| yTHIS '.' idDottedForeach
|
||||
|
|
@ -5206,7 +5215,7 @@ idDotted<nodeExprp>:
|
|||
| idDottedMore { $$ = $1; }
|
||||
;
|
||||
|
||||
idDottedForeach<nodep>:
|
||||
idDottedForeach<nodeExprp>:
|
||||
yD_ROOT '.' idDottedMoreForeach
|
||||
{ $$ = new AstDot($2, false, new AstParseRef($<fl>1, VParseRefExp::PX_ROOT, "$root"), $3); }
|
||||
| idDottedMoreForeach { $$ = $1; }
|
||||
|
|
@ -5217,7 +5226,7 @@ idDottedMore<nodeExprp>:
|
|||
| idDottedMore '.' idArrayed { $$ = new AstDot($2, false, $1, $3); }
|
||||
;
|
||||
|
||||
idDottedMoreForeach<nodep>:
|
||||
idDottedMoreForeach<nodeExprp>:
|
||||
idArrayedForeach { $$ = $1; }
|
||||
| idDottedMoreForeach '.' idArrayedForeach { $$ = new AstDot($2, false, $1, $3); }
|
||||
;
|
||||
|
|
@ -5238,7 +5247,7 @@ idArrayed<nodeExprp>: // IEEE: id + select
|
|||
| idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2, $1, $3, $5); }
|
||||
;
|
||||
|
||||
idArrayedForeach<nodep>: // IEEE: id + select (under foreach expression)
|
||||
idArrayedForeach<nodeExprp>: // IEEE: id + select (under foreach expression)
|
||||
id
|
||||
{ $$ = new AstParseRef($<fl>1, VParseRefExp::PX_TEXT, *$1, nullptr, nullptr); }
|
||||
// // IEEE: id + part_select_range/constant_part_select_range
|
||||
|
|
@ -5607,7 +5616,7 @@ sequence_formal_typeNoDt<nodeDTypep>: // ==IEEE: sequence_formal_type (w/o data
|
|||
//UNSUP | sexpr ';' { $$ = $1; }
|
||||
//UNSUP ;
|
||||
|
||||
property_spec<nodep>: // IEEE: property_spec
|
||||
property_spec<propSpecp>: // IEEE: property_spec
|
||||
//UNSUP: This rule has been super-specialized to what is supported now
|
||||
//UNSUP remove below
|
||||
'@' '(' senitemEdge ')' yDISABLE yIFF '(' expr ')' pexpr
|
||||
|
|
@ -5686,7 +5695,7 @@ property_spec<nodep>: // IEEE: property_spec
|
|||
//UNSUP | BISONPRE_COPY_ONCE(expr,{s/~l~/pev_/g; s/~p~/pev_/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied}
|
||||
//UNSUP ;
|
||||
|
||||
pexpr<nodep>: // IEEE: property_expr (The name pexpr is important as regexps just add an "p" to expr.)
|
||||
pexpr<nodeExprp>: // IEEE: property_expr (The name pexpr is important as regexps just add an "p" to expr.)
|
||||
//UNSUP: This rule has been super-specialized to what is supported now
|
||||
//UNSUP remove below
|
||||
//
|
||||
|
|
@ -5701,7 +5710,7 @@ pexpr<nodep>: // IEEE: property_expr (The name pexpr is important as regexps j
|
|||
| expr { $$ = $1; }
|
||||
;
|
||||
|
||||
complex_pexpr<nodep>: // IEEE: part of property_expr, see comments there
|
||||
complex_pexpr<nodeExprp>: // IEEE: part of property_expr, see comments there
|
||||
expr yP_ORMINUSGT pexpr { $$ = new AstLogOr($2, new AstLogNot($2, $1), $3); }
|
||||
| expr yP_OREQGT pexpr { $$ = new AstImplication($2, $1, $3); }
|
||||
| yNOT pexpr %prec prNEGATION { $$ = new AstLogNot{$1, $2}; }
|
||||
|
|
@ -6406,7 +6415,7 @@ packageClassScopeNoId<nodep>: // IEEE: [package_scope] not followed by yaID
|
|||
packageClassScope { $$ = $1; $<scp>$ = $<scp>1; SYMP->nextId(nullptr); }
|
||||
;
|
||||
|
||||
packageClassScopeE<nodep>: // IEEE: [package_scope]
|
||||
packageClassScopeE<nodeExprp>: // IEEE: [package_scope]
|
||||
// // IMPORTANT: The lexer will parse the following ID to be in the found package
|
||||
// // if not needed must use packageClassScopeNoId
|
||||
// // TODO: To support classes should return generic type, not packagep
|
||||
|
|
@ -6415,7 +6424,7 @@ packageClassScopeE<nodep>: // IEEE: [package_scope]
|
|||
| packageClassScope { $$ = $1; $<scp>$ = $<scp>1; }
|
||||
;
|
||||
|
||||
packageClassScope<nodep>: // IEEE: class_scope
|
||||
packageClassScope<nodeExprp>: // IEEE: class_scope
|
||||
// // IEEE: "class_type yP_COLONCOLON"
|
||||
// // IMPORTANT: The lexer will parse the following ID to be in the found package
|
||||
// // if not needed must use packageClassScopeNoId
|
||||
|
|
@ -6428,7 +6437,7 @@ packageClassScope<nodep>: // IEEE: class_scope
|
|||
{ $$ = new AstDot($2, true, $1, $3); $<scp>$ = $<scp>3; }
|
||||
;
|
||||
|
||||
packageClassScopeList<nodep>: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE
|
||||
packageClassScopeList<nodeExprp>: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE
|
||||
// // Or IEEE: [package_scope]
|
||||
// // IMPORTANT: The lexer will parse the following ID to be in the found package
|
||||
// // if not needed must use packageClassScopeNoId
|
||||
|
|
@ -6439,7 +6448,7 @@ packageClassScopeList<nodep>: // IEEE: class_type: "id [ parameter_value_assig
|
|||
{ $$ = new AstDot($<fl>2, true, $1, $2); $<scp>$ = $<scp>2; }
|
||||
;
|
||||
|
||||
packageClassScopeItem<nodep>: // IEEE: package_scope or [package_scope]::[class_scope]
|
||||
packageClassScopeItem<nodeExprp>: // IEEE: package_scope or [package_scope]::[class_scope]
|
||||
// // IMPORTANT: The lexer will parse the following ID to be in the found package
|
||||
// // if not needed must use packageClassScopeNoId
|
||||
// // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE
|
||||
|
|
@ -6455,7 +6464,7 @@ packageClassScopeItem<nodep>: // IEEE: package_scope or [package_scope]::[clas
|
|||
{ $$ = new AstClassOrPackageRef($<fl>1, *$1, $<scp>1, $2); $<scp>$ = $<scp>1; }
|
||||
;
|
||||
|
||||
dollarUnitNextId<nodep>: // $unit
|
||||
dollarUnitNextId<nodeExprp>: // $unit
|
||||
// // IMPORTANT: The lexer will parse the following ID to be in the found package
|
||||
// // if not needed must use packageClassScopeNoId
|
||||
// // Must call nextId without any additional tokens following
|
||||
|
|
@ -6464,7 +6473,7 @@ dollarUnitNextId<nodep>: // $unit
|
|||
SYMP->nextId(PARSEP->rootp()); }
|
||||
;
|
||||
|
||||
localNextId<nodep>: // local
|
||||
localNextId<nodeExprp>: // local
|
||||
// // IMPORTANT: The lexer will parse the following ID to be in the found package
|
||||
// // if not needed must use packageClassScopeNoId
|
||||
// // Must call nextId without any additional tokens following
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
%Error: t/t_stream_bad.v:12:32: Expecting expression to be constant, but can't convert a RAND to constant.
|
||||
: ... In instance t
|
||||
12 | initial packed_data_32 = {<<$random{byte_in}};
|
||||
| ^~~~~~~
|
||||
%Error: t/t_stream_bad.v:12:30: Slice size isn't a constant or basic data type.
|
||||
: ... In instance t
|
||||
12 | initial packed_data_32 = {<<$random{byte_in}};
|
||||
| ^~
|
||||
%Warning-WIDTH: t/t_stream_bad.v:12:27: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits.
|
||||
: ... In instance t
|
||||
12 | initial packed_data_32 = {<<$random{byte_in}};
|
||||
| ^
|
||||
... For warning description see https://verilator.org/warn/WIDTH?v=latest
|
||||
... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message.
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
lint(
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2022 by Geza Lore.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
|
||||
logic [31:0] packed_data_32;
|
||||
byte byte_in[4];
|
||||
|
||||
initial packed_data_32 = {<<$random{byte_in}};
|
||||
|
||||
endmodule
|
||||
|
|
@ -72,63 +72,115 @@
|
|||
: ... In instance t
|
||||
136 | {<<32{reg_out}} = v_packed_data_128;
|
||||
| ^
|
||||
%Error: t/t_stream_integer_type.v:150:33: Operator STREAML expected non-datatype RHS but 'byte' is a datatype.
|
||||
: ... In instance t
|
||||
150 | packed_data_32 = {<<byte{byte_in}};
|
||||
| ^~~~
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:150:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits.
|
||||
: ... In instance t
|
||||
150 | packed_data_32 = {<<byte{byte_in}};
|
||||
| ^
|
||||
%Error: t/t_stream_integer_type.v:151:33: Operator STREAML expected non-datatype RHS but 'shortint' is a datatype.
|
||||
: ... In instance t
|
||||
151 | packed_data_64 = {<<shortint{shortint_in}};
|
||||
| ^~~~~~~~
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:151:28: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's STREAML generates 16 bits.
|
||||
: ... In instance t
|
||||
151 | packed_data_64 = {<<shortint{shortint_in}};
|
||||
| ^
|
||||
%Error: t/t_stream_integer_type.v:152:33: Operator STREAML expected non-datatype RHS but 'int' is a datatype.
|
||||
: ... In instance t
|
||||
152 | packed_data_128 = {<<int{int_in}};
|
||||
| ^~~
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:152:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits.
|
||||
: ... In instance t
|
||||
152 | packed_data_128 = {<<int{int_in}};
|
||||
| ^
|
||||
%Error: t/t_stream_integer_type.v:153:33: Operator STREAML expected non-datatype RHS but 'integer' is a datatype.
|
||||
: ... In instance t
|
||||
153 | packed_data_128_i = {<<integer{integer_in}};
|
||||
| ^~~~~~~
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:153:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits.
|
||||
: ... In instance t
|
||||
153 | packed_data_128_i = {<<integer{integer_in}};
|
||||
| ^
|
||||
%Error: t/t_stream_integer_type.v:154:33: Operator STREAML expected non-datatype RHS but 'longint' is a datatype.
|
||||
: ... In instance t
|
||||
154 | packed_data_256 = {<<longint{longint_in}};
|
||||
| ^~~~~~~
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:154:28: Operator ASSIGN expects 256 bits on the Assign RHS, but Assign RHS's STREAML generates 64 bits.
|
||||
: ... In instance t
|
||||
154 | packed_data_256 = {<<longint{longint_in}};
|
||||
| ^
|
||||
%Error: t/t_stream_integer_type.v:155:33: Operator STREAML expected non-datatype RHS but 'time' is a datatype.
|
||||
: ... In instance t
|
||||
155 | packed_time_256 = {<<time{time_in}};
|
||||
| ^~~~
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:155:28: Operator ASSIGN expects 256 bits on the Assign RHS, but Assign RHS's STREAML generates 64 bits.
|
||||
: ... In instance t
|
||||
155 | packed_time_256 = {<<time{time_in}};
|
||||
| ^
|
||||
%Error: t/t_stream_integer_type.v:156:33: Operator STREAML expected non-datatype RHS but 'test_byte' is a datatype.
|
||||
: ... In instance t
|
||||
156 | v_packed_data_32 = {<<test_byte{bit_in}};
|
||||
| ^~~~~~~~~
|
||||
%Error: t/t_stream_integer_type.v:156:31: Slice size isn't a constant or basic data type.
|
||||
: ... In instance t
|
||||
156 | v_packed_data_32 = {<<test_byte{bit_in}};
|
||||
| ^~
|
||||
%Error: Internal Error: t/t_stream_integer_type.v:156:28: ../V3Width.cpp:#: Node has no type
|
||||
: ... In instance t
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:156:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits.
|
||||
: ... In instance t
|
||||
156 | v_packed_data_32 = {<<test_byte{bit_in}};
|
||||
| ^
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:157:28: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's STREAML generates 16 bits.
|
||||
: ... In instance t
|
||||
157 | v_packed_data_64 = {<<test_short{logic_in}};
|
||||
| ^
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:158:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits.
|
||||
: ... In instance t
|
||||
158 | v_packed_data_128 = {<<test_word{reg_in}};
|
||||
| ^
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:160:37: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_32' generates 32 bits.
|
||||
: ... In instance t
|
||||
160 | {<<byte{byte_out}} = packed_data_32;
|
||||
| ^
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:161:37: Operator ASSIGN expects 16 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_64' generates 64 bits.
|
||||
: ... In instance t
|
||||
161 | {<<shortint{shortint_out}} = packed_data_64;
|
||||
| ^
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:162:37: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_128' generates 128 bits.
|
||||
: ... In instance t
|
||||
162 | {<<int{int_out}} = packed_data_128;
|
||||
| ^
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:163:37: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_128_i' generates 128 bits.
|
||||
: ... In instance t
|
||||
163 | {<<integer{integer_out}} = packed_data_128_i;
|
||||
| ^
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:164:37: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_256' generates 256 bits.
|
||||
: ... In instance t
|
||||
164 | {<<longint{longint_out}} = packed_data_256;
|
||||
| ^
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:165:37: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's VARREF 'packed_time_256' generates 256 bits.
|
||||
: ... In instance t
|
||||
165 | {<<time{time_out}} = packed_time_256;
|
||||
| ^
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:166:37: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_32' generates 32 bits.
|
||||
: ... In instance t
|
||||
166 | {<<test_byte{bit_out}} = v_packed_data_32;
|
||||
| ^
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:167:37: Operator ASSIGN expects 16 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_64' generates 64 bits.
|
||||
: ... In instance t
|
||||
167 | {<<test_short{logic_out}} = v_packed_data_64;
|
||||
| ^
|
||||
%Warning-WIDTH: t/t_stream_integer_type.v:168:37: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_128' generates 128 bits.
|
||||
: ... In instance t
|
||||
168 | {<<test_word{reg_out}} = v_packed_data_128;
|
||||
| ^
|
||||
%Error: t/t_stream_integer_type.v:128:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
128 | {<<8{byte_out}} = packed_data_32;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:129:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
129 | {<<16{shortint_out}} = packed_data_64;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:130:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
130 | {<<32{int_out}} = packed_data_128;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:131:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
131 | {<<32{integer_out}} = packed_data_128_i;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:132:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
132 | {<<64{longint_out}} = packed_data_256;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:133:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
133 | {<<64{time_out}} = packed_time_256;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:134:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
134 | {<<8{bit_out}} = v_packed_data_32;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:135:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
135 | {<<16{logic_out}} = v_packed_data_64;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:136:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
136 | {<<32{reg_out}} = v_packed_data_128;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:160:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
160 | {<<byte{byte_out}} = packed_data_32;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:161:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
161 | {<<shortint{shortint_out}} = packed_data_64;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:162:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
162 | {<<int{int_out}} = packed_data_128;
|
||||
| ^~
|
||||
%Error: t/t_stream_integer_type.v:163:11: SEL is not an unpacked array, but is in an unpacked array context
|
||||
163 | {<<integer{integer_out}} = packed_data_128_i;
|
||||
| ^~
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
Loading…
Reference in New Issue