Fix V3Expand ignoring side effects
This commit is contained in:
parent
140994d2c4
commit
8e0682f442
101
src/V3Expand.cpp
101
src/V3Expand.cpp
|
|
@ -39,6 +39,38 @@
|
||||||
|
|
||||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
// Find nodes with side effects, to mark as non-expandable
|
||||||
|
|
||||||
|
class ExpandOkVisitor final : public VNVisitor {
|
||||||
|
private:
|
||||||
|
// NODE STATE
|
||||||
|
// AstNode::user2() -> bool. Is pure (along with all children)
|
||||||
|
const VNUser2InUse m_inuser2;
|
||||||
|
|
||||||
|
// STATE - for current visit position (use VL_RESTORER)
|
||||||
|
// Tracks similar to AstNode::isTreePureRecurse(), but avoid O(n^2)
|
||||||
|
// False = pure, as nodes that ExpandVisitor inserts preserve pureness
|
||||||
|
bool m_isImpure = true; // Currently pure
|
||||||
|
|
||||||
|
void visit(AstNode* nodep) override {
|
||||||
|
bool selfImpure = !nodep->isPure();
|
||||||
|
{
|
||||||
|
VL_RESTORER(m_isImpure);
|
||||||
|
m_isImpure = false;
|
||||||
|
iterateChildren(nodep);
|
||||||
|
selfImpure |= m_isImpure;
|
||||||
|
nodep->user2(selfImpure);
|
||||||
|
}
|
||||||
|
m_isImpure |= selfImpure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// CONSTRUCTORS
|
||||||
|
explicit ExpandOkVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||||
|
~ExpandOkVisitor() = default;
|
||||||
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Expand state, as a visitor of each AstNode
|
// Expand state, as a visitor of each AstNode
|
||||||
|
|
||||||
|
|
@ -48,15 +80,24 @@ private:
|
||||||
// AstNode::user1() -> bool. Processed
|
// AstNode::user1() -> bool. Processed
|
||||||
const VNUser1InUse m_inuser1;
|
const VNUser1InUse m_inuser1;
|
||||||
|
|
||||||
// STATE
|
// STATE - for current visit position (use VL_RESTORER)
|
||||||
AstNode* m_stmtp = nullptr; // Current statement
|
AstNode* m_stmtp = nullptr; // Current statement
|
||||||
|
|
||||||
|
// STATE - across all visitors
|
||||||
VDouble0 m_statWides; // Statistic tracking
|
VDouble0 m_statWides; // Statistic tracking
|
||||||
VDouble0 m_statWideWords; // Statistic tracking
|
VDouble0 m_statWideWords; // Statistic tracking
|
||||||
VDouble0 m_statWideLimited; // Statistic tracking
|
VDouble0 m_statWideLimited; // Statistic tracking
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
// Use state that ExpandOkVisitor calculated
|
||||||
|
bool isImpure(AstNode* nodep) {
|
||||||
|
const bool impure = nodep->user2();
|
||||||
|
if (impure) UINFO(9, " impure " << nodep << endl);
|
||||||
|
return impure;
|
||||||
|
}
|
||||||
|
|
||||||
bool doExpand(AstNode* nodep) {
|
bool doExpandWide(AstNode* nodep) {
|
||||||
|
if (isImpure(nodep)) return false;
|
||||||
++m_statWides;
|
++m_statWides;
|
||||||
if (nodep->widthWords() <= v3Global.opt.expandLimit()) {
|
if (nodep->widthWords() <= v3Global.opt.expandLimit()) {
|
||||||
m_statWideWords += nodep->widthWords();
|
m_statWideWords += nodep->widthWords();
|
||||||
|
|
@ -225,7 +266,7 @@ private:
|
||||||
|
|
||||||
bool expandWide(AstNodeAssign* nodep, AstConst* rhsp) {
|
bool expandWide(AstNodeAssign* nodep, AstConst* rhsp) {
|
||||||
UINFO(8, " Wordize ASSIGN(CONST) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(CONST) " << nodep << endl);
|
||||||
if (!doExpand(nodep)) return false;
|
if (!doExpandWide(nodep)) return false;
|
||||||
// -> {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}}
|
// -> {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}}
|
||||||
if (rhsp->num().isFourState()) {
|
if (rhsp->num().isFourState()) {
|
||||||
rhsp->v3warn(E_UNSUPPORTED, // LCOV_EXCL_LINE // impossible?
|
rhsp->v3warn(E_UNSUPPORTED, // LCOV_EXCL_LINE // impossible?
|
||||||
|
|
@ -241,7 +282,7 @@ private:
|
||||||
//-------- Uniops
|
//-------- Uniops
|
||||||
bool expandWide(AstNodeAssign* nodep, AstVarRef* rhsp) {
|
bool expandWide(AstNodeAssign* nodep, AstVarRef* rhsp) {
|
||||||
UINFO(8, " Wordize ASSIGN(VARREF) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(VARREF) " << nodep << endl);
|
||||||
if (!doExpand(nodep)) return false;
|
if (!doExpandWide(nodep)) return false;
|
||||||
for (int w = 0; w < nodep->widthWords(); ++w) {
|
for (int w = 0; w < nodep->widthWords(); ++w) {
|
||||||
addWordAssign(nodep, w, newAstWordSelClone(rhsp, w));
|
addWordAssign(nodep, w, newAstWordSelClone(rhsp, w));
|
||||||
}
|
}
|
||||||
|
|
@ -251,7 +292,7 @@ private:
|
||||||
UINFO(8, " Wordize ASSIGN(ARRAYSEL) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(ARRAYSEL) " << nodep << endl);
|
||||||
UASSERT_OBJ(!VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType), nodep,
|
UASSERT_OBJ(!VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType), nodep,
|
||||||
"ArraySel with unpacked arrays should have been removed in V3Slice");
|
"ArraySel with unpacked arrays should have been removed in V3Slice");
|
||||||
if (!doExpand(nodep)) return false;
|
if (!doExpandWide(nodep)) return false;
|
||||||
for (int w = 0; w < nodep->widthWords(); ++w) {
|
for (int w = 0; w < nodep->widthWords(); ++w) {
|
||||||
addWordAssign(nodep, w, newAstWordSelClone(rhsp, w));
|
addWordAssign(nodep, w, newAstWordSelClone(rhsp, w));
|
||||||
}
|
}
|
||||||
|
|
@ -260,7 +301,7 @@ private:
|
||||||
bool expandWide(AstNodeAssign* nodep, AstNot* rhsp) {
|
bool expandWide(AstNodeAssign* nodep, AstNot* rhsp) {
|
||||||
UINFO(8, " Wordize ASSIGN(NOT) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(NOT) " << nodep << endl);
|
||||||
// -> {for each_word{ ASSIGN(WORDSEL(wide,#),NOT(WORDSEL(lhs,#))) }}
|
// -> {for each_word{ ASSIGN(WORDSEL(wide,#),NOT(WORDSEL(lhs,#))) }}
|
||||||
if (!doExpand(nodep)) return false;
|
if (!doExpandWide(nodep)) return false;
|
||||||
FileLine* const fl = rhsp->fileline();
|
FileLine* const fl = rhsp->fileline();
|
||||||
for (int w = 0; w < nodep->widthWords(); ++w) {
|
for (int w = 0; w < nodep->widthWords(); ++w) {
|
||||||
addWordAssign(nodep, w, new AstNot{fl, newAstWordSelClone(rhsp->lhsp(), w)});
|
addWordAssign(nodep, w, new AstNot{fl, newAstWordSelClone(rhsp->lhsp(), w)});
|
||||||
|
|
@ -270,7 +311,7 @@ private:
|
||||||
//-------- Biops
|
//-------- Biops
|
||||||
bool expandWide(AstNodeAssign* nodep, AstAnd* rhsp) {
|
bool expandWide(AstNodeAssign* nodep, AstAnd* rhsp) {
|
||||||
UINFO(8, " Wordize ASSIGN(AND) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(AND) " << nodep << endl);
|
||||||
if (!doExpand(nodep)) return false;
|
if (!doExpandWide(nodep)) return false;
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
for (int w = 0; w < nodep->widthWords(); ++w) {
|
for (int w = 0; w < nodep->widthWords(); ++w) {
|
||||||
addWordAssign(nodep, w,
|
addWordAssign(nodep, w,
|
||||||
|
|
@ -281,7 +322,7 @@ private:
|
||||||
}
|
}
|
||||||
bool expandWide(AstNodeAssign* nodep, AstOr* rhsp) {
|
bool expandWide(AstNodeAssign* nodep, AstOr* rhsp) {
|
||||||
UINFO(8, " Wordize ASSIGN(OR) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(OR) " << nodep << endl);
|
||||||
if (!doExpand(nodep)) return false;
|
if (!doExpandWide(nodep)) return false;
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
for (int w = 0; w < nodep->widthWords(); ++w) {
|
for (int w = 0; w < nodep->widthWords(); ++w) {
|
||||||
addWordAssign(nodep, w,
|
addWordAssign(nodep, w,
|
||||||
|
|
@ -292,7 +333,7 @@ private:
|
||||||
}
|
}
|
||||||
bool expandWide(AstNodeAssign* nodep, AstXor* rhsp) {
|
bool expandWide(AstNodeAssign* nodep, AstXor* rhsp) {
|
||||||
UINFO(8, " Wordize ASSIGN(XOR) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(XOR) " << nodep << endl);
|
||||||
if (!doExpand(nodep)) return false;
|
if (!doExpandWide(nodep)) return false;
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
for (int w = 0; w < nodep->widthWords(); ++w) {
|
for (int w = 0; w < nodep->widthWords(); ++w) {
|
||||||
addWordAssign(nodep, w,
|
addWordAssign(nodep, w,
|
||||||
|
|
@ -304,7 +345,7 @@ private:
|
||||||
//-------- Triops
|
//-------- Triops
|
||||||
bool expandWide(AstNodeAssign* nodep, AstNodeCond* rhsp) {
|
bool expandWide(AstNodeAssign* nodep, AstNodeCond* rhsp) {
|
||||||
UINFO(8, " Wordize ASSIGN(COND) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(COND) " << nodep << endl);
|
||||||
if (!doExpand(nodep)) return false;
|
if (!doExpandWide(nodep)) return false;
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
for (int w = 0; w < nodep->widthWords(); ++w) {
|
for (int w = 0; w < nodep->widthWords(); ++w) {
|
||||||
addWordAssign(nodep, w,
|
addWordAssign(nodep, w,
|
||||||
|
|
@ -322,6 +363,7 @@ private:
|
||||||
if (nodep->isWide()) {
|
if (nodep->isWide()) {
|
||||||
// See under ASSIGN(EXTEND)
|
// See under ASSIGN(EXTEND)
|
||||||
} else {
|
} else {
|
||||||
|
if (isImpure(nodep)) return;
|
||||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||||
AstNodeExpr* newp = lhsp;
|
AstNodeExpr* newp = lhsp;
|
||||||
if (nodep->isQuad()) {
|
if (nodep->isQuad()) {
|
||||||
|
|
@ -343,7 +385,7 @@ private:
|
||||||
}
|
}
|
||||||
bool expandWide(AstNodeAssign* nodep, AstExtend* rhsp) {
|
bool expandWide(AstNodeAssign* nodep, AstExtend* rhsp) {
|
||||||
UINFO(8, " Wordize ASSIGN(EXTEND) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(EXTEND) " << nodep << endl);
|
||||||
if (!doExpand(nodep)) return false;
|
if (!doExpandWide(nodep)) return false;
|
||||||
AstNodeExpr* const rlhsp = rhsp->lhsp();
|
AstNodeExpr* const rlhsp = rhsp->lhsp();
|
||||||
for (int w = 0; w < rlhsp->widthWords(); ++w) {
|
for (int w = 0; w < rlhsp->widthWords(); ++w) {
|
||||||
addWordAssign(nodep, w, newAstWordSelClone(rlhsp, w));
|
addWordAssign(nodep, w, newAstWordSelClone(rlhsp, w));
|
||||||
|
|
@ -365,6 +407,7 @@ private:
|
||||||
} else if (nodep->isWide()) {
|
} else if (nodep->isWide()) {
|
||||||
// See under ASSIGN(WIDE)
|
// See under ASSIGN(WIDE)
|
||||||
} else if (nodep->fromp()->isWide()) {
|
} else if (nodep->fromp()->isWide()) {
|
||||||
|
if (isImpure(nodep)) return;
|
||||||
UINFO(8, " SEL(wide) " << nodep << endl);
|
UINFO(8, " SEL(wide) " << nodep << endl);
|
||||||
UASSERT_OBJ(nodep->widthConst() <= 64, nodep, "Inconsistent width");
|
UASSERT_OBJ(nodep->widthConst() <= 64, nodep, "Inconsistent width");
|
||||||
// Selection amounts
|
// Selection amounts
|
||||||
|
|
@ -386,7 +429,7 @@ private:
|
||||||
const uint32_t midMsbOffset
|
const uint32_t midMsbOffset
|
||||||
= std::min<uint32_t>(nodep->widthConst(), VL_EDATASIZE) - 1;
|
= std::min<uint32_t>(nodep->widthConst(), VL_EDATASIZE) - 1;
|
||||||
AstNodeExpr* const midMsbp = new AstAdd{lfl, new AstConst{lfl, midMsbOffset},
|
AstNodeExpr* const midMsbp = new AstAdd{lfl, new AstConst{lfl, midMsbOffset},
|
||||||
nodep->lsbp()->cloneTree(false)};
|
nodep->lsbp()->cloneTree(true)};
|
||||||
AstNodeExpr* midwordp = // SEL(from,[midwordnum])
|
AstNodeExpr* midwordp = // SEL(from,[midwordnum])
|
||||||
newWordSel(ffl, nodep->fromp()->cloneTree(true), midMsbp, 0);
|
newWordSel(ffl, nodep->fromp()->cloneTree(true), midMsbp, 0);
|
||||||
// newWordSel clones the index, so delete it
|
// newWordSel clones the index, so delete it
|
||||||
|
|
@ -414,7 +457,7 @@ private:
|
||||||
if (nodep->widthConst() > VL_EDATASIZE) {
|
if (nodep->widthConst() > VL_EDATASIZE) {
|
||||||
const uint32_t hiMsbOffset = nodep->widthConst() - 1;
|
const uint32_t hiMsbOffset = nodep->widthConst() - 1;
|
||||||
AstNodeExpr* const hiMsbp = new AstAdd{lfl, new AstConst{lfl, hiMsbOffset},
|
AstNodeExpr* const hiMsbp = new AstAdd{lfl, new AstConst{lfl, hiMsbOffset},
|
||||||
nodep->lsbp()->cloneTree(false)};
|
nodep->lsbp()->cloneTree(true)};
|
||||||
AstNodeExpr* hiwordp = // SEL(from,[hiwordnum])
|
AstNodeExpr* hiwordp = // SEL(from,[hiwordnum])
|
||||||
newWordSel(ffl, nodep->fromp()->cloneTree(true), hiMsbp);
|
newWordSel(ffl, nodep->fromp()->cloneTree(true), hiMsbp);
|
||||||
// newWordSel clones the index, so delete it
|
// newWordSel clones the index, so delete it
|
||||||
|
|
@ -439,15 +482,16 @@ private:
|
||||||
newp->dtypeFrom(nodep);
|
newp->dtypeFrom(nodep);
|
||||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||||
} else { // Long/Quad from Long/Quad
|
} else { // Long/Quad from Long/Quad
|
||||||
|
// No isImpure() check - can handle side effects in below
|
||||||
UINFO(8, " SEL->SHIFT " << nodep << endl);
|
UINFO(8, " SEL->SHIFT " << nodep << endl);
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
AstNodeExpr* fromp = nodep->fromp()->unlinkFrBack();
|
AstNodeExpr* fromp = nodep->fromp()->unlinkFrBack();
|
||||||
AstNodeExpr* const lsbp = nodep->lsbp()->unlinkFrBack();
|
AstNodeExpr* const lsbp = nodep->lsbp()->unlinkFrBack();
|
||||||
if (nodep->isQuad() && !fromp->isQuad()) { fromp = new AstCCast{fl, fromp, nodep}; }
|
if (nodep->isQuad() && !fromp->isQuad()) fromp = new AstCCast{fl, fromp, nodep};
|
||||||
// {large}>>32 requires 64-bit shift operation; then cast
|
// {large}>>32 requires 64-bit shift operation; then cast
|
||||||
AstNodeExpr* newp = new AstShiftR{fl, fromp, dropCondBound(lsbp), fromp->width()};
|
AstNodeExpr* newp = new AstShiftR{fl, fromp, dropCondBound(lsbp), fromp->width()};
|
||||||
newp->dtypeFrom(fromp);
|
newp->dtypeFrom(fromp);
|
||||||
if (!nodep->isQuad() && fromp->isQuad()) { newp = new AstCCast{fl, newp, nodep}; }
|
if (!nodep->isQuad() && fromp->isQuad()) newp = new AstCCast{fl, newp, nodep};
|
||||||
newp->dtypeFrom(nodep);
|
newp->dtypeFrom(nodep);
|
||||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||||
}
|
}
|
||||||
|
|
@ -455,7 +499,7 @@ private:
|
||||||
|
|
||||||
bool expandWide(AstNodeAssign* nodep, AstSel* rhsp) {
|
bool expandWide(AstNodeAssign* nodep, AstSel* rhsp) {
|
||||||
UASSERT_OBJ(nodep->widthMin() == rhsp->widthConst(), nodep, "Width mismatch");
|
UASSERT_OBJ(nodep->widthMin() == rhsp->widthConst(), nodep, "Width mismatch");
|
||||||
if (!doExpand(nodep)) return false;
|
if (!doExpandWide(nodep)) return false;
|
||||||
if (VN_IS(rhsp->lsbp(), Const) && VL_BITBIT_E(rhsp->lsbConst()) == 0) {
|
if (VN_IS(rhsp->lsbp(), Const) && VL_BITBIT_E(rhsp->lsbConst()) == 0) {
|
||||||
const int lsb = rhsp->lsbConst();
|
const int lsb = rhsp->lsbConst();
|
||||||
UINFO(8, " Wordize ASSIGN(SEL,align) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(SEL,align) " << nodep << endl);
|
||||||
|
|
@ -499,6 +543,7 @@ private:
|
||||||
// rhsp: may be allones and can remove AND NOT gate
|
// rhsp: may be allones and can remove AND NOT gate
|
||||||
// lsbp: constant or variable
|
// lsbp: constant or variable
|
||||||
// Yuk.
|
// Yuk.
|
||||||
|
if (isImpure(nodep)) return false;
|
||||||
FileLine* const nfl = nodep->fileline();
|
FileLine* const nfl = nodep->fileline();
|
||||||
FileLine* const lfl = lhsp->fileline();
|
FileLine* const lfl = lhsp->fileline();
|
||||||
const bool destwide = lhsp->fromp()->isWide();
|
const bool destwide = lhsp->fromp()->isWide();
|
||||||
|
|
@ -649,13 +694,14 @@ private:
|
||||||
if (nodep->isWide()) {
|
if (nodep->isWide()) {
|
||||||
// See under ASSIGN(WIDE)
|
// See under ASSIGN(WIDE)
|
||||||
} else {
|
} else {
|
||||||
|
// No isImpure() check - can handle side effects in below
|
||||||
UINFO(8, " CONCAT " << nodep << endl);
|
UINFO(8, " CONCAT " << nodep << endl);
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack();
|
AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||||
AstNodeExpr* rhsp = nodep->rhsp()->unlinkFrBack();
|
AstNodeExpr* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||||
const uint32_t rhsshift = rhsp->widthMin();
|
const uint32_t rhsshift = rhsp->widthMin();
|
||||||
if (nodep->isQuad() && !lhsp->isQuad()) { lhsp = new AstCCast{fl, lhsp, nodep}; }
|
if (nodep->isQuad() && !lhsp->isQuad()) lhsp = new AstCCast{fl, lhsp, nodep};
|
||||||
if (nodep->isQuad() && !rhsp->isQuad()) { rhsp = new AstCCast{fl, rhsp, nodep}; }
|
if (nodep->isQuad() && !rhsp->isQuad()) rhsp = new AstCCast{fl, rhsp, nodep};
|
||||||
AstNodeExpr* const newp = new AstOr{
|
AstNodeExpr* const newp = new AstOr{
|
||||||
fl, new AstShiftL{fl, lhsp, new AstConst{fl, rhsshift}, nodep->width()}, rhsp};
|
fl, new AstShiftL{fl, lhsp, new AstConst{fl, rhsshift}, nodep->width()}, rhsp};
|
||||||
newp->dtypeFrom(nodep); // Unsigned
|
newp->dtypeFrom(nodep); // Unsigned
|
||||||
|
|
@ -664,7 +710,7 @@ private:
|
||||||
}
|
}
|
||||||
bool expandWide(AstNodeAssign* nodep, AstConcat* rhsp) {
|
bool expandWide(AstNodeAssign* nodep, AstConcat* rhsp) {
|
||||||
UINFO(8, " Wordize ASSIGN(CONCAT) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(CONCAT) " << nodep << endl);
|
||||||
if (!doExpand(rhsp)) return false;
|
if (!doExpandWide(rhsp)) return false;
|
||||||
FileLine* const fl = rhsp->fileline();
|
FileLine* const fl = rhsp->fileline();
|
||||||
// Lhs or Rhs may be word, long, or quad.
|
// Lhs or Rhs may be word, long, or quad.
|
||||||
// newAstWordSelClone nicely abstracts the difference.
|
// newAstWordSelClone nicely abstracts the difference.
|
||||||
|
|
@ -686,6 +732,7 @@ private:
|
||||||
if (nodep->isWide()) {
|
if (nodep->isWide()) {
|
||||||
// See under ASSIGN(WIDE)
|
// See under ASSIGN(WIDE)
|
||||||
} else {
|
} else {
|
||||||
|
if (isImpure(nodep)) return;
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack();
|
AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||||
AstNodeExpr* newp;
|
AstNodeExpr* newp;
|
||||||
|
|
@ -719,7 +766,7 @@ private:
|
||||||
}
|
}
|
||||||
bool expandWide(AstNodeAssign* nodep, AstReplicate* rhsp) {
|
bool expandWide(AstNodeAssign* nodep, AstReplicate* rhsp) {
|
||||||
UINFO(8, " Wordize ASSIGN(REPLICATE) " << nodep << endl);
|
UINFO(8, " Wordize ASSIGN(REPLICATE) " << nodep << endl);
|
||||||
if (!doExpand(rhsp)) return false;
|
if (!doExpandWide(rhsp)) return false;
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
AstNodeExpr* const lhsp = rhsp->lhsp();
|
AstNodeExpr* const lhsp = rhsp->lhsp();
|
||||||
const int lhswidth = lhsp->widthMin();
|
const int lhswidth = lhsp->widthMin();
|
||||||
|
|
@ -748,6 +795,7 @@ private:
|
||||||
if (nodep->user1SetOnce()) return; // Process once
|
if (nodep->user1SetOnce()) return; // Process once
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (nodep->lhsp()->isWide()) {
|
if (nodep->lhsp()->isWide()) {
|
||||||
|
if (isImpure(nodep)) return;
|
||||||
UINFO(8, " Wordize EQ/NEQ " << nodep << endl);
|
UINFO(8, " Wordize EQ/NEQ " << nodep << endl);
|
||||||
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
|
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
|
|
@ -773,6 +821,7 @@ private:
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
if (nodep->lhsp()->isWide()) {
|
if (nodep->lhsp()->isWide()) {
|
||||||
|
if (isImpure(nodep)) return;
|
||||||
UINFO(8, " Wordize REDOR " << nodep << endl);
|
UINFO(8, " Wordize REDOR " << nodep << endl);
|
||||||
// -> (0!={or{for each_word{WORDSEL(lhs,#)}}}
|
// -> (0!={or{for each_word{WORDSEL(lhs,#)}}}
|
||||||
AstNodeExpr* newp = nullptr;
|
AstNodeExpr* newp = nullptr;
|
||||||
|
|
@ -783,6 +832,7 @@ private:
|
||||||
newp = new AstNeq{fl, new AstConst{fl, AstConst::SizedEData{}, 0}, newp};
|
newp = new AstNeq{fl, new AstConst{fl, AstConst::SizedEData{}, 0}, newp};
|
||||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||||
} else {
|
} else {
|
||||||
|
// No isImpure() check - can handle side effects in below
|
||||||
UINFO(8, " REDOR->EQ " << nodep << endl);
|
UINFO(8, " REDOR->EQ " << nodep << endl);
|
||||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||||
AstNodeExpr* const newp = new AstNeq{
|
AstNodeExpr* const newp = new AstNeq{
|
||||||
|
|
@ -795,6 +845,7 @@ private:
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
if (nodep->lhsp()->isWide()) {
|
if (nodep->lhsp()->isWide()) {
|
||||||
|
if (isImpure(nodep)) return;
|
||||||
UINFO(8, " Wordize REDAND " << nodep << endl);
|
UINFO(8, " Wordize REDAND " << nodep << endl);
|
||||||
// -> (0!={and{for each_word{WORDSEL(lhs,#)}}}
|
// -> (0!={and{for each_word{WORDSEL(lhs,#)}}}
|
||||||
AstNodeExpr* newp = nullptr;
|
AstNodeExpr* newp = nullptr;
|
||||||
|
|
@ -814,6 +865,7 @@ private:
|
||||||
newp};
|
newp};
|
||||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||||
} else {
|
} else {
|
||||||
|
// No isImpure() check - can handle side effects in below
|
||||||
UINFO(8, " REDAND->EQ " << nodep << endl);
|
UINFO(8, " REDAND->EQ " << nodep << endl);
|
||||||
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||||
AstNodeExpr* const newp = new AstEq{fl, new AstConst{fl, wordMask(lhsp)}, lhsp};
|
AstNodeExpr* const newp = new AstEq{fl, new AstConst{fl, wordMask(lhsp)}, lhsp};
|
||||||
|
|
@ -824,6 +876,7 @@ private:
|
||||||
if (nodep->user1SetOnce()) return; // Process once
|
if (nodep->user1SetOnce()) return; // Process once
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (nodep->lhsp()->isWide()) {
|
if (nodep->lhsp()->isWide()) {
|
||||||
|
if (isImpure(nodep)) return;
|
||||||
UINFO(8, " Wordize REDXOR " << nodep << endl);
|
UINFO(8, " Wordize REDXOR " << nodep << endl);
|
||||||
// -> (0!={redxor{for each_word{XOR(WORDSEL(lhs,#))}}}
|
// -> (0!={redxor{for each_word{XOR(WORDSEL(lhs,#))}}}
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
|
|
@ -906,14 +959,14 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
|
||||||
// Top loop
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Expand class functions
|
// Expand class functions
|
||||||
|
|
||||||
void V3Expand::expandAll(AstNetlist* nodep) {
|
void V3Expand::expandAll(AstNetlist* nodep) {
|
||||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||||
{ ExpandVisitor{nodep}; } // Destruct before checking
|
{
|
||||||
|
ExpandOkVisitor okVisitor{nodep};
|
||||||
|
ExpandVisitor{nodep};
|
||||||
|
} // Destruct before checking
|
||||||
V3Global::dumpCheckGlobalTree("expand", 0, dumpTreeLevel() >= 3);
|
V3Global::dumpCheckGlobalTree("expand", 0, dumpTreeLevel() >= 3);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue