parent
14ec6258d9
commit
c33f2b42aa
|
|
@ -1863,6 +1863,7 @@ class AstVar final : public AstNode {
|
||||||
bool m_isHideProtected : 1; // Verilog protected
|
bool m_isHideProtected : 1; // Verilog protected
|
||||||
bool m_noReset : 1; // Do not do automated reset/randomization
|
bool m_noReset : 1; // Do not do automated reset/randomization
|
||||||
bool m_noSubst : 1; // Do not substitute out references
|
bool m_noSubst : 1; // Do not substitute out references
|
||||||
|
bool m_substConstOnly : 1; // Only substitute if constant
|
||||||
bool m_overridenParam : 1; // Overridden parameter by #(...) or defparam
|
bool m_overridenParam : 1; // Overridden parameter by #(...) or defparam
|
||||||
bool m_trace : 1; // Trace this variable
|
bool m_trace : 1; // Trace this variable
|
||||||
bool m_isLatched : 1; // Not assigned in all control paths of combo always
|
bool m_isLatched : 1; // Not assigned in all control paths of combo always
|
||||||
|
|
@ -1912,6 +1913,7 @@ class AstVar final : public AstNode {
|
||||||
m_isHideProtected = false;
|
m_isHideProtected = false;
|
||||||
m_noReset = false;
|
m_noReset = false;
|
||||||
m_noSubst = false;
|
m_noSubst = false;
|
||||||
|
m_substConstOnly = false;
|
||||||
m_overridenParam = false;
|
m_overridenParam = false;
|
||||||
m_trace = false;
|
m_trace = false;
|
||||||
m_isLatched = false;
|
m_isLatched = false;
|
||||||
|
|
@ -2068,6 +2070,8 @@ public:
|
||||||
bool noReset() const { return m_noReset; }
|
bool noReset() const { return m_noReset; }
|
||||||
void noSubst(bool flag) { m_noSubst = flag; }
|
void noSubst(bool flag) { m_noSubst = flag; }
|
||||||
bool noSubst() const { return m_noSubst; }
|
bool noSubst() const { return m_noSubst; }
|
||||||
|
void substConstOnly(bool flag) { m_substConstOnly = flag; }
|
||||||
|
bool substConstOnly() const { return m_substConstOnly; }
|
||||||
void overriddenParam(bool flag) { m_overridenParam = flag; }
|
void overriddenParam(bool flag) { m_overridenParam = flag; }
|
||||||
bool overriddenParam() const { return m_overridenParam; }
|
bool overriddenParam() const { return m_overridenParam; }
|
||||||
void trace(bool flag) { m_trace = flag; }
|
void trace(bool flag) { m_trace = flag; }
|
||||||
|
|
|
||||||
244
src/V3Expand.cpp
244
src/V3Expand.cpp
|
|
@ -77,10 +77,14 @@ class ExpandVisitor final : public VNVisitor {
|
||||||
AstNode* m_stmtp = nullptr; // Current statement
|
AstNode* m_stmtp = nullptr; // Current statement
|
||||||
|
|
||||||
// STATE - across all visitors
|
// STATE - across all visitors
|
||||||
|
AstCFunc* m_funcp = nullptr; // Current function
|
||||||
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
|
||||||
|
|
||||||
|
// STATE - for current function
|
||||||
|
size_t m_nTmps = 0; // Sequence numbers for temopraries
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
// Use state that ExpandOkVisitor calculated
|
// Use state that ExpandOkVisitor calculated
|
||||||
bool isImpure(AstNode* nodep) {
|
bool isImpure(AstNode* nodep) {
|
||||||
|
|
@ -147,6 +151,19 @@ class ExpandVisitor final : public VNVisitor {
|
||||||
addWordAssign(placep, word, placep->lhsp(), rhsp);
|
addWordAssign(placep, word, placep->lhsp(), rhsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstVar* addLocalTmp(AstNode* placep, const char* namep, AstNodeExpr* valuep) {
|
||||||
|
const std::string name = "__V"s + namep + "_"s + std::to_string(m_nTmps);
|
||||||
|
FileLine* const flp = placep->fileline();
|
||||||
|
AstVar* const tmpp = new AstVar{flp, VVarType::STMTTEMP, name, valuep->dtypep()};
|
||||||
|
tmpp->funcLocal(true);
|
||||||
|
tmpp->isInternal(true);
|
||||||
|
tmpp->noReset(true);
|
||||||
|
tmpp->substConstOnly(true);
|
||||||
|
m_funcp->addInitsp(tmpp);
|
||||||
|
insertBefore(placep, new AstAssign{flp, new AstVarRef{flp, tmpp, VAccess::WRITE}, valuep});
|
||||||
|
return tmpp;
|
||||||
|
}
|
||||||
|
|
||||||
static void fixCloneLvalue(AstNode* nodep) {
|
static void fixCloneLvalue(AstNode* nodep) {
|
||||||
// In AstSel transforms, we call clone() on VarRefs that were lvalues,
|
// In AstSel transforms, we call clone() on VarRefs that were lvalues,
|
||||||
// but are now being used on the RHS of the assignment
|
// but are now being used on the RHS of the assignment
|
||||||
|
|
@ -213,31 +230,54 @@ class ExpandVisitor final : public VNVisitor {
|
||||||
return newp;
|
return newp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AstNodeExpr* newWordSel(FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* lsbp,
|
// Return expression indexing the word that contains 'lsbp' + the given word offset
|
||||||
uint32_t wordOffset = 0) {
|
static AstNodeExpr* newWordIndex(AstNodeExpr* lsbp, uint32_t wordOffset = 0) {
|
||||||
// Return equation to get the VL_BITWORD of a constant or non-constant
|
// This is indexing a WordSel, so a 32 bit constants are fine
|
||||||
UASSERT_OBJ(fromp->isWide(), fromp, "Only need AstWordSel on wide from's");
|
FileLine* const flp = lsbp->fileline();
|
||||||
if (wordOffset >= static_cast<uint32_t>(fromp->widthWords())) {
|
if (AstConst* constp = VN_CAST(lsbp, Const)) {
|
||||||
// e.g. "logic [95:0] var[0]; logic [0] sel; out = var[sel];"
|
return new AstConst{flp, wordOffset + VL_BITWORD_E(constp->toUInt())};
|
||||||
// Squash before C++ to avoid getting a C++ compiler warning
|
|
||||||
// (even though code would be unreachable as presumably a
|
|
||||||
// AstCond is protecting above this node.
|
|
||||||
return new AstConst{fl, AstConst::SizedEData{}, 0};
|
|
||||||
} else {
|
|
||||||
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())};
|
|
||||||
} else {
|
|
||||||
wordp = new AstShiftR{lfl, lsbp->cloneTreePure(true),
|
|
||||||
new AstConst{lfl, VL_EDATASIZE_LOG2}, VL_EDATASIZE};
|
|
||||||
if (wordOffset
|
|
||||||
!= 0) { // This is indexing a arraysel, so a 32 bit constant is fine
|
|
||||||
wordp = new AstAdd{lfl, new AstConst{lfl, wordOffset}, wordp};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new AstWordSel{fl, fromp, wordp};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lsbp->backp()) lsbp = lsbp->cloneTreePure(false);
|
||||||
|
AstNodeExpr* const wwl2p = new AstConst{flp, VL_EDATASIZE_LOG2}; // Word width log 2
|
||||||
|
AstNodeExpr* indexp = new AstShiftR{flp, lsbp, wwl2p, VL_EDATASIZE};
|
||||||
|
if (wordOffset) indexp = new AstAdd{flp, new AstConst{flp, wordOffset}, indexp};
|
||||||
|
return indexp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return word of fromp that contains word indexp + the given word offset.
|
||||||
|
static AstNodeExpr* newWordSelWord(FileLine* flp, AstNodeExpr* fromp, AstNodeExpr* indexp,
|
||||||
|
uint32_t wordOffset = 0) {
|
||||||
|
UASSERT_OBJ(fromp->isWide(), fromp, "Only need AstWordSel on wide from's");
|
||||||
|
|
||||||
|
if (AstConst* const constp = VN_CAST(indexp, Const)) {
|
||||||
|
indexp = nullptr;
|
||||||
|
wordOffset += constp->toUInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// e.g. "logic [95:0] var[0]; logic [0] sel; out = var[sel];"
|
||||||
|
// Squash before C++ to avoid getting a C++ compiler warning
|
||||||
|
// (even though code would be unreachable as presumably a
|
||||||
|
// AstCond is protecting above this node.
|
||||||
|
if (wordOffset >= static_cast<uint32_t>(fromp->widthWords())) {
|
||||||
|
return new AstConst{flp, AstConst::SizedEData{}, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromp->backp()) fromp = fromp->cloneTreePure(false);
|
||||||
|
|
||||||
|
// If indexp was constant, just use it
|
||||||
|
if (!indexp) return new AstWordSel{flp, fromp, new AstConst{flp, wordOffset}};
|
||||||
|
|
||||||
|
// Otherwise compute at runtime
|
||||||
|
if (indexp->backp()) indexp = indexp->cloneTreePure(false);
|
||||||
|
if (wordOffset) indexp = new AstAdd{flp, new AstConst{flp, wordOffset}, indexp};
|
||||||
|
return new AstWordSel{flp, fromp, indexp};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return word of fromp that contains bit lsbp + the given word offset.
|
||||||
|
static AstNodeExpr* newWordSelBit(FileLine* flp, AstNodeExpr* fromp, AstNodeExpr* lsbp,
|
||||||
|
uint32_t wordOffset = 0) {
|
||||||
|
return newWordSelWord(flp, fromp, newWordIndex(lsbp, wordOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
static AstNodeExpr* newSelBitBit(AstNodeExpr* lsbp) {
|
static AstNodeExpr* newSelBitBit(AstNodeExpr* lsbp) {
|
||||||
|
|
@ -346,6 +386,10 @@ class ExpandVisitor final : public VNVisitor {
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstCFunc* nodep) override {
|
void visit(AstCFunc* nodep) override {
|
||||||
|
VL_RESTORER(m_funcp);
|
||||||
|
VL_RESTORER(m_nTmps);
|
||||||
|
m_funcp = nodep;
|
||||||
|
m_nTmps = 0;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|
||||||
// Constant fold here, as Ast size can likely be reduced
|
// Constant fold here, as Ast size can likely be reduced
|
||||||
|
|
@ -414,8 +458,7 @@ class ExpandVisitor final : public VNVisitor {
|
||||||
FileLine* const nfl = nodep->fileline();
|
FileLine* const nfl = nodep->fileline();
|
||||||
FileLine* const lfl = nodep->lsbp()->fileline();
|
FileLine* const lfl = nodep->lsbp()->fileline();
|
||||||
FileLine* const ffl = nodep->fromp()->fileline();
|
FileLine* const ffl = nodep->fromp()->fileline();
|
||||||
AstNodeExpr* lowwordp
|
AstNodeExpr* lowwordp = newWordSelBit(ffl, nodep->fromp(), nodep->lsbp());
|
||||||
= newWordSel(ffl, nodep->fromp()->cloneTreePure(true), nodep->lsbp());
|
|
||||||
if (nodep->isQuad() && !lowwordp->isQuad()) {
|
if (nodep->isQuad() && !lowwordp->isQuad()) {
|
||||||
lowwordp = new AstCCast{nfl, lowwordp, nodep};
|
lowwordp = new AstCCast{nfl, lowwordp, nodep};
|
||||||
}
|
}
|
||||||
|
|
@ -428,10 +471,8 @@ class ExpandVisitor final : public VNVisitor {
|
||||||
= 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()->cloneTreePure(true)};
|
nodep->lsbp()->cloneTreePure(true)};
|
||||||
AstNodeExpr* midwordp = // SEL(from,[midwordnum])
|
AstNodeExpr* midwordp = newWordSelBit(ffl, nodep->fromp(), midMsbp, 0);
|
||||||
newWordSel(ffl, nodep->fromp()->cloneTreePure(true), midMsbp, 0);
|
if (!midMsbp->backp()) VL_DO_DANGLING(midMsbp->deleteTree(), midMsbp);
|
||||||
// newWordSel clones the index, so delete it
|
|
||||||
VL_DO_DANGLING(midMsbp->deleteTree(), midMsbp);
|
|
||||||
if (nodep->isQuad() && !midwordp->isQuad()) {
|
if (nodep->isQuad() && !midwordp->isQuad()) {
|
||||||
midwordp = new AstCCast{nfl, midwordp, nodep};
|
midwordp = new AstCCast{nfl, midwordp, nodep};
|
||||||
}
|
}
|
||||||
|
|
@ -455,10 +496,8 @@ class ExpandVisitor final : public VNVisitor {
|
||||||
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()->cloneTreePure(true)};
|
nodep->lsbp()->cloneTreePure(true)};
|
||||||
AstNodeExpr* hiwordp = // SEL(from,[hiwordnum])
|
AstNodeExpr* hiwordp = newWordSelBit(ffl, nodep->fromp(), hiMsbp);
|
||||||
newWordSel(ffl, nodep->fromp()->cloneTreePure(true), hiMsbp);
|
if (!hiMsbp->backp()) VL_DO_DANGLING(hiMsbp->deleteTree(), hiMsbp);
|
||||||
// newWordSel clones the index, so delete it
|
|
||||||
VL_DO_DANGLING(hiMsbp->deleteTree(), hiMsbp);
|
|
||||||
if (nodep->isQuad() && !hiwordp->isQuad()) {
|
if (nodep->isQuad() && !hiwordp->isQuad()) {
|
||||||
hiwordp = new AstCCast{nfl, hiwordp, nodep};
|
hiwordp = new AstCCast{nfl, hiwordp, nodep};
|
||||||
}
|
}
|
||||||
|
|
@ -497,40 +536,109 @@ class ExpandVisitor final : public VNVisitor {
|
||||||
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 (!doExpandWide(nodep)) return false;
|
if (!doExpandWide(nodep)) return false;
|
||||||
if (VN_IS(rhsp->lsbp(), Const) && VL_BITBIT_E(rhsp->lsbConst()) == 0) {
|
|
||||||
const int lsb = rhsp->lsbConst();
|
// Simplify the index, in case it becomes a constant
|
||||||
UINFO(8, " Wordize ASSIGN(SEL,align) " << nodep);
|
V3Const::constifyEditCpp(rhsp->lsbp());
|
||||||
for (int w = 0; w < nodep->widthWords(); ++w) {
|
|
||||||
addWordAssign(nodep, w, newAstWordSelClone(rhsp->fromp(), w + VL_BITWORD_E(lsb)));
|
// If it's a constant select and aligned, we can just copy the words
|
||||||
|
if (AstConst* const lsbConstp = VN_CAST(rhsp->lsbp(), Const)) {
|
||||||
|
const uint32_t lsb = lsbConstp->toUInt();
|
||||||
|
if (VL_BITBIT_E(lsb) == 0) {
|
||||||
|
UINFO(8, " Wordize ASSIGN(SEL,align) " << nodep);
|
||||||
|
const uint32_t word = VL_BITWORD_E(lsb);
|
||||||
|
for (int w = 0; w < nodep->widthWords(); ++w) {
|
||||||
|
addWordAssign(nodep, w, newAstWordSelClone(rhsp->fromp(), w + word));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
UINFO(8, " Wordize ASSIGN(EXTRACT,misalign) " << nodep);
|
|
||||||
FileLine* const nfl = nodep->fileline();
|
|
||||||
FileLine* const rfl = rhsp->fileline();
|
|
||||||
FileLine* const ffl = rhsp->fromp()->fileline();
|
|
||||||
FileLine* const lfl = rhsp->lsbp()->fileline();
|
|
||||||
for (int w = 0; w < nodep->widthWords(); ++w) {
|
|
||||||
// Grab lowest bits
|
|
||||||
AstNodeExpr* const lowwordp
|
|
||||||
= newWordSel(rfl, rhsp->fromp()->cloneTreePure(true), rhsp->lsbp(), w);
|
|
||||||
AstNodeExpr* const lowp
|
|
||||||
= new AstShiftR{rfl, lowwordp, newSelBitBit(rhsp->lsbp()), VL_EDATASIZE};
|
|
||||||
// Upper bits
|
|
||||||
const V3Number zero{nodep, VL_EDATASIZE, 0};
|
|
||||||
AstNodeExpr* const midwordp = // SEL(from,[1+wordnum])
|
|
||||||
newWordSel(ffl, rhsp->fromp()->cloneTreePure(true), rhsp->lsbp(), w + 1);
|
|
||||||
AstNodeExpr* const midshiftp
|
|
||||||
= new AstSub{lfl, new AstConst{lfl, VL_EDATASIZE}, newSelBitBit(rhsp->lsbp())};
|
|
||||||
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};
|
|
||||||
AstNodeExpr* const newp = new AstOr{nfl, midp, lowp};
|
|
||||||
addWordAssign(nodep, w, newp);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINFO(8, " Wordize ASSIGN(EXTRACT,misalign) " << nodep);
|
||||||
|
FileLine* const flp = rhsp->fileline();
|
||||||
|
|
||||||
|
// Use fresh set of temporaries
|
||||||
|
++m_nTmps;
|
||||||
|
|
||||||
|
// Compute word index of LSB, store to temporary if not constant
|
||||||
|
AstNodeExpr* wordIdxp = newWordIndex(rhsp->lsbp()->cloneTreePure(false));
|
||||||
|
wordIdxp = V3Const::constifyEditCpp(wordIdxp);
|
||||||
|
if (!VN_IS(wordIdxp, Const)) {
|
||||||
|
AstVar* const tmpp = addLocalTmp(nodep, "ExpandSel_WordIdx", wordIdxp);
|
||||||
|
wordIdxp = new AstVarRef{flp, tmpp, VAccess::READ};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute shift amounts and mask, store to temporaries if not constants
|
||||||
|
AstNodeExpr* loShftp = nullptr;
|
||||||
|
AstNodeExpr* hiShftp = nullptr;
|
||||||
|
AstNodeExpr* hiMaskp = nullptr;
|
||||||
|
if (AstConst* const lsbConstp = VN_CAST(rhsp->lsbp(), Const)) {
|
||||||
|
const uint32_t bitOffset = VL_BITBIT_E(lsbConstp->toUInt());
|
||||||
|
// Must be unaligned, otherwise we would have handled it above
|
||||||
|
UASSERT_OBJ(bitOffset, nodep, "Missed aligned wide select");
|
||||||
|
loShftp = new AstConst{flp, bitOffset};
|
||||||
|
hiShftp = new AstConst{flp, VL_EDATASIZE - bitOffset};
|
||||||
|
hiMaskp = nullptr;
|
||||||
|
} else {
|
||||||
|
// Compute Low word shift amount: bottom bits of lsb index
|
||||||
|
AstNodeExpr* const lsbp = rhsp->lsbp()->cloneTreePure(false);
|
||||||
|
loShftp = new AstAnd{flp, new AstConst{flp, VL_SIZEBITS_E}, lsbp};
|
||||||
|
AstVar* const loTmpp = addLocalTmp(nodep, "ExpandSel_LoShift", loShftp);
|
||||||
|
loShftp = new AstVarRef{flp, loTmpp, VAccess::READ};
|
||||||
|
|
||||||
|
// Compute if aligned: Low word shift amount is 0
|
||||||
|
AstNodeExpr* const zerop = new AstConst{flp, 0};
|
||||||
|
AstNodeExpr* alignedp = new AstEq{flp, zerop, loShftp->cloneTreePure(false)};
|
||||||
|
AstVar* const alignedTmpp = addLocalTmp(nodep, "ExpandSel_Aligned", alignedp);
|
||||||
|
alignedp = new AstVarRef{flp, alignedTmpp, VAccess::READ};
|
||||||
|
|
||||||
|
// Computed High word shift amount: 0 if aligned else VL_EDATASIZE - Low word shift
|
||||||
|
AstNodeExpr* const edsp = new AstConst{flp, VL_EDATASIZE};
|
||||||
|
AstNodeExpr* const subp = new AstSub{flp, edsp, loShftp->cloneTreePure(false)};
|
||||||
|
hiShftp = new AstCond{flp, alignedp, new AstConst{flp, 0}, subp};
|
||||||
|
AstVar* const hiTmpp = addLocalTmp(nodep, "ExpandSel_HiShift", hiShftp);
|
||||||
|
hiShftp = new AstVarRef{flp, hiTmpp, VAccess::READ};
|
||||||
|
|
||||||
|
// Compute the High word mask: 0 if aligned, ones otherwise
|
||||||
|
hiMaskp = new AstCond{flp, alignedp->cloneTreePure(false),
|
||||||
|
new AstConst{flp, AstConst::SizedEData{}, 0},
|
||||||
|
new AstConst{flp, AstConst::SizedEData{}, -1ULL}};
|
||||||
|
AstVar* const maskTmpp = addLocalTmp(nodep, "ExpandSel_HiMask", hiMaskp);
|
||||||
|
hiMaskp = new AstVarRef{flp, maskTmpp, VAccess::READ};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create each word of the selected result
|
||||||
|
AstNodeExpr* const fromp = rhsp->fromp();
|
||||||
|
const int selWords = nodep->widthWords();
|
||||||
|
for (int w = 0; w < selWords; ++w) {
|
||||||
|
// Grab bits from word 'VL_BITWORD_E(lsb) + w'
|
||||||
|
AstNodeExpr* const loWordp = newWordSelWord(fromp->fileline(), fromp, wordIdxp, w);
|
||||||
|
AstNodeExpr* const loShftClonep = loShftp->cloneTreePure(false);
|
||||||
|
AstNodeExpr* const lop = new AstShiftR{flp, loWordp, loShftClonep, VL_EDATASIZE};
|
||||||
|
// Grab bits from word 'VL_BITWORD_E(lsb) + w + 1'
|
||||||
|
AstNodeExpr* hiWordp = newWordSelWord(fromp->fileline(), fromp, wordIdxp, w + 1);
|
||||||
|
// For the last word of the result, avoid an OOB access when the Sel is not OOB
|
||||||
|
if (w == selWords - 1) {
|
||||||
|
const uint32_t max = fromp->widthWords() - w - 1;
|
||||||
|
AstNodeExpr* const maxp = new AstConst{flp, max};
|
||||||
|
AstNodeExpr* const condp = new AstGte{flp, wordIdxp->cloneTreePure(false), maxp};
|
||||||
|
AstNodeExpr* const zerop = new AstConst{flp, AstConst::SizedEData{}, 0};
|
||||||
|
hiWordp = new AstCond{flp, condp, zerop, hiWordp};
|
||||||
|
}
|
||||||
|
AstNodeExpr* const hiShftClonep = hiShftp->cloneTreePure(false);
|
||||||
|
AstNodeExpr* const hiPartp = new AstShiftL{flp, hiWordp, hiShftClonep, VL_EDATASIZE};
|
||||||
|
AstNodeExpr* const hip
|
||||||
|
= hiMaskp ? new AstAnd{flp, hiPartp, hiMaskp->cloneTreePure(false)} : hiPartp;
|
||||||
|
// Combine them
|
||||||
|
addWordAssign(nodep, w, new AstOr{nodep->fileline(), hip, lop});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete parts not captured during construction
|
||||||
|
if (!wordIdxp->backp()) VL_DO_DANGLING(wordIdxp->deleteTree(), wordIdxp);
|
||||||
|
if (!loShftp->backp()) VL_DO_DANGLING(loShftp->deleteTree(), loShftp);
|
||||||
|
if (!hiShftp->backp()) VL_DO_DANGLING(hiShftp->deleteTree(), hiShftp);
|
||||||
|
if (hiMaskp && !hiMaskp->backp()) VL_DO_DANGLING(hiMaskp->deleteTree(), hiMaskp);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool expandLhs(AstNodeAssign* nodep, AstSel* lhsp) {
|
bool expandLhs(AstNodeAssign* nodep, AstSel* lhsp) {
|
||||||
|
|
@ -614,7 +722,7 @@ class ExpandVisitor final : public VNVisitor {
|
||||||
UINFO(8, " ASSIGNSEL(varlsb,wide,1bit) " << nodep);
|
UINFO(8, " ASSIGNSEL(varlsb,wide,1bit) " << nodep);
|
||||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||||
AstNodeExpr* const destp = lhsp->fromp()->unlinkFrBack();
|
AstNodeExpr* const destp = lhsp->fromp()->unlinkFrBack();
|
||||||
AstNodeExpr* oldvalp = newWordSel(lfl, destp->cloneTreePure(true), lhsp->lsbp());
|
AstNodeExpr* oldvalp = newWordSelBit(lfl, destp, lhsp->lsbp());
|
||||||
fixCloneLvalue(oldvalp);
|
fixCloneLvalue(oldvalp);
|
||||||
if (!ones) {
|
if (!ones) {
|
||||||
oldvalp = new AstAnd{
|
oldvalp = new AstAnd{
|
||||||
|
|
@ -631,7 +739,7 @@ class ExpandVisitor final : public VNVisitor {
|
||||||
AstNodeExpr* const shiftp = new AstAnd{nfl, lhsp->lsbp()->cloneTreePure(true),
|
AstNodeExpr* const shiftp = new AstAnd{nfl, lhsp->lsbp()->cloneTreePure(true),
|
||||||
new AstConst{nfl, VL_EDATASIZE - 1}};
|
new AstConst{nfl, VL_EDATASIZE - 1}};
|
||||||
AstNode* const newp = new AstAssign{
|
AstNode* const newp = new AstAssign{
|
||||||
nfl, newWordSel(nfl, destp, lhsp->lsbp()),
|
nfl, newWordSelBit(nfl, destp, lhsp->lsbp()),
|
||||||
new AstOr{lfl, oldvalp, new AstShiftL{lfl, rhsp, shiftp, VL_EDATASIZE}}};
|
new AstOr{lfl, oldvalp, new AstShiftL{lfl, rhsp, shiftp, VL_EDATASIZE}}};
|
||||||
insertBefore(nodep, newp);
|
insertBefore(nodep, newp);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -118,15 +118,21 @@ public:
|
||||||
}
|
}
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
AstNodeExpr* substWhole(AstNode* errp) {
|
AstNodeExpr* substWhole(AstNode* errp) {
|
||||||
if (!m_varp->isWide() && !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) {
|
if (m_varp->isWide()) return nullptr;
|
||||||
const AstNodeAssign* const assp = m_whole.m_assignp;
|
if (m_whole.m_complex) return nullptr;
|
||||||
UASSERT_OBJ(assp, errp, "Reading whole that was never assigned");
|
if (!m_whole.m_assignp) return nullptr;
|
||||||
// AstCvtPackedToArray can't be anywhere else than on the RHS of assignment
|
if (m_wordAssign) return nullptr;
|
||||||
if (VN_IS(assp->rhsp(), CvtPackedToArray)) return nullptr;
|
|
||||||
return assp->rhsp();
|
const AstNodeAssign* const assp = m_whole.m_assignp;
|
||||||
} else {
|
UASSERT_OBJ(assp, errp, "Reading whole that was never assigned");
|
||||||
return nullptr;
|
AstNodeExpr* const rhsp = assp->rhsp();
|
||||||
}
|
|
||||||
|
// AstCvtPackedToArray can't be anywhere else than on the RHS of assignment
|
||||||
|
if (VN_IS(rhsp, CvtPackedToArray)) return nullptr;
|
||||||
|
// Check if only substitute if constant
|
||||||
|
if (m_varp->substConstOnly() && !VN_IS(rhsp, Const)) return nullptr;
|
||||||
|
// Substitute it
|
||||||
|
return rhsp;
|
||||||
}
|
}
|
||||||
// Return what to substitute given word number for
|
// Return what to substitute given word number for
|
||||||
AstNodeExpr* substWord(AstNode* errp, int word) {
|
AstNodeExpr* substWord(AstNode* errp, int word) {
|
||||||
|
|
@ -227,7 +233,7 @@ class SubstVisitor final : public VNVisitor {
|
||||||
int m_ops = 0; // Number of operators on assign rhs
|
int m_ops = 0; // Number of operators on assign rhs
|
||||||
int m_assignStep = 0; // Assignment number to determine var lifetime
|
int m_assignStep = 0; // Assignment number to determine var lifetime
|
||||||
const AstCFunc* m_funcp = nullptr; // Current function we are under
|
const AstCFunc* m_funcp = nullptr; // Current function we are under
|
||||||
VDouble0 m_statSubsts; // Statistic tracking
|
size_t m_nSubst = 0; // Number of substitutions performed
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in
|
SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in
|
||||||
|
|
@ -251,7 +257,10 @@ class SubstVisitor final : public VNVisitor {
|
||||||
VL_RESTORER(m_ops);
|
VL_RESTORER(m_ops);
|
||||||
m_ops = 0;
|
m_ops = 0;
|
||||||
m_assignStep++;
|
m_assignStep++;
|
||||||
|
const size_t nSubstBefore = m_nSubst;
|
||||||
iterateAndNextNull(nodep->rhsp());
|
iterateAndNextNull(nodep->rhsp());
|
||||||
|
if (nSubstBefore != m_nSubst) V3Const::constifyEditCpp(nodep->rhsp());
|
||||||
|
if (VN_IS(nodep->rhsp(), Const)) m_ops = 0;
|
||||||
bool hit = false;
|
bool hit = false;
|
||||||
if (AstVarRef* const varrefp = VN_CAST(nodep->lhsp(), VarRef)) {
|
if (AstVarRef* const varrefp = VN_CAST(nodep->lhsp(), VarRef)) {
|
||||||
if (isSubstVar(varrefp->varp())) {
|
if (isSubstVar(varrefp->varp())) {
|
||||||
|
|
@ -292,11 +301,14 @@ class SubstVisitor final : public VNVisitor {
|
||||||
UINFOTREE(6, newp, "", "w_new");
|
UINFOTREE(6, newp, "", "w_new");
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||||
++m_statSubsts;
|
++m_nSubst;
|
||||||
}
|
}
|
||||||
void visit(AstWordSel* nodep) override {
|
void visit(AstWordSel* nodep) override {
|
||||||
if (!m_funcp) return;
|
if (!m_funcp) return;
|
||||||
|
const size_t nSubstBefore = m_nSubst;
|
||||||
iterate(nodep->bitp());
|
iterate(nodep->bitp());
|
||||||
|
// Simplify in case it was substituted and became constant
|
||||||
|
if (nSubstBefore != m_nSubst) V3Const::constifyEditCpp(nodep->bitp());
|
||||||
AstVarRef* const varrefp = VN_CAST(nodep->fromp(), VarRef);
|
AstVarRef* const varrefp = VN_CAST(nodep->fromp(), VarRef);
|
||||||
const AstConst* const constp = VN_CAST(nodep->bitp(), Const);
|
const AstConst* const constp = VN_CAST(nodep->bitp(), Const);
|
||||||
if (varrefp && isSubstVar(varrefp->varp()) && varrefp->access().isReadOnly() && constp) {
|
if (varrefp && isSubstVar(varrefp->varp()) && varrefp->access().isReadOnly() && constp) {
|
||||||
|
|
@ -380,7 +392,7 @@ public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
explicit SubstVisitor(AstNode* nodep) { iterate(nodep); }
|
explicit SubstVisitor(AstNode* nodep) { iterate(nodep); }
|
||||||
~SubstVisitor() override {
|
~SubstVisitor() override {
|
||||||
V3Stats::addStat("Optimizations, Substituted temps", m_statSubsts);
|
V3Stats::addStat("Optimizations, Substituted temps", m_nSubst);
|
||||||
UASSERT(m_entries.empty(), "References outside functions");
|
UASSERT(m_entries.empty(), "References outside functions");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue