diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 2e68fa96d..fa6b52144 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -932,7 +932,11 @@ private: } std::cerr< -// logic [1:0] unpcked_array_var[0:3]; /*verilator split_var*/ -// always_comb begin -// unpacked_array_var[1] = unpacked_array_var[0]; // UNOPTFLAT warning -// unpacked_array_var[2] = unpacked_array_var[1]; -// unpacked_array_var[3] = unpacked_array_var[2]; -// end -// logic [3:0] packed_var; /*verilator split_var*/ -// always_comb begin -// if (some_cond) begin -// packed_var = 4'b0; -// end else begin -// packed_var[3] = some_input0; -// packed_var[2:0] = some_input1; -// end -// end -// +// logic [1:0] unpcked_array_var[0:1]; /*verilator split_var*/ +// always_comb begin +// unpacked_array_var[1] = unpacked_array_var[0]; // UNOPTFLAT warning +// end +// logic [3:0] packed_var; /*verilator split_var*/ +// always_comb begin +// if (some_cond) begin +// packed_var = 4'b0; +// end else begin +// packed_var[3] = some_input0; +// packed_var[2:0] = some_input1; +// end +// end // // is converted to // -//
-// logic [1:0] unpcked_array_var0;
-// logic [1:0] unpcked_array_var1;
-// logic [1:0] unpcked_array_var2;
-// logic [1:0] unpcked_array_var3;
-// always_comb begin
-//    unpacked_array_var1 = unpacked_array_var0;
-//    unpacked_array_var2 = unpacked_array_var1;
-//    unpacked_array_var3 = unpacked_array_var2;
-// end
-// logic       packed_var__BRA__3__KET__;
-// logic [2:0] packed_var__BRA__2_0__KET__;
-// always_comb begin
-//    if (some_cond) begin
-//        {packed_var__BRA__3__KET__, packed_var__BRA__2_0__KET__} = 4'b0;
-//    end else begin
-//        packed_var__BRA__3__KET__   = some_input0;
-//        packed_var__BRA__2_0__KET__ = some_input1;
-//    end
-// end
+//     logic [1:0] unpcked_array_var0;
+//     logic [1:0] unpcked_array_var1;
+//     always_comb begin
+//        unpacked_array_var1 = unpacked_array_var0;
+//     end
+//     logic       packed_var__BRA__3__KET__;
+//     logic [2:0] packed_var__BRA__2_0__KET__;
+//     always_comb begin
+//        if (some_cond) begin
+//            {packed_var__BRA__3__KET__, packed_var__BRA__2_0__KET__} = 4'b0;
+//        end else begin
+//            packed_var__BRA__3__KET__   = some_input0;
+//            packed_var__BRA__2_0__KET__ = some_input1;
+//        end
+//     end
 // 
// // @@ -89,29 +80,6 @@ #include VL_INCLUDE_UNORDERED_MAP #include VL_INCLUDE_UNORDERED_SET -static AstConst* constifyIfNot(AstNode* nodep) { - AstConst* constp = VN_CAST(nodep, Const); - if (!constp) { - UINFO(4, nodep << " is expected to be constant, but not\n"); - AstNode* const constified = V3Const::constifyEdit(nodep); - UINFO(4, "After constified:" << constified << '\n'); - constp = VN_CAST(constified, Const); - } - return constp; -} - -// returns of outer most dimension of an unpacked array -static std::pair outerMostSizeOfUnpackedArray(AstVar* nodep) { - AstUnpackArrayDType* const dtypep = VN_CAST(nodep->dtypep(), UnpackArrayDType); - AstConst* const lsbp = constifyIfNot(dtypep->rangep()->lsbp()); - AstConst* const msbp = constifyIfNot(dtypep->rangep()->msbp()); - UASSERT_OBJ(lsbp, dtypep->rangep()->lsbp(), "must be constant"); - UASSERT_OBJ(msbp, dtypep->rangep()->msbp(), "must be constant"); - const vlsint32_t lsb = lsbp->toSInt(), msb = msbp->toSInt(); - UASSERT_OBJ(lsb <= msb, dtypep->rangep(), "lsb must not greater than msb"); - return std::make_pair(msb, lsb); -} - //###################################################################### // Find a variable with pragma @@ -165,18 +133,36 @@ class SplitUnpackedVarVisitor : public AstNVisitor { // key:variable to be split. value:location where the variable is referenced. vl_unordered_map > m_refs; + // This visitor is used before V3Const::constifyAllLint(), + // some parameters need to be resolved here, but don't abuse this function. + static AstConst* constifyIfNot(AstNode* nodep) { + AstConst* constp = VN_CAST(nodep, Const); + if (!constp) { + UINFO(4, nodep << " is expected to be constant, but not\n"); + AstNode* constified = V3Const::constifyEdit(nodep); + UINFO(4, "After constified:" << constified << '\n'); + constp = VN_CAST(constified, Const); + } + return constp; + } + static int outerMostSizeOfUnpackedArray(AstVar* nodep) { + AstUnpackArrayDType* dtypep = VN_CAST(nodep->dtypep(), UnpackArrayDType); + UASSERT_OBJ(dtypep, nodep, "Must be unapcked array"); + return dtypep->msb() - dtypep->lsb() + 1; + } + virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { UASSERT_OBJ(m_modp == NULL, m_modp, "Nested module declration"); m_modp = nodep; std::vector > vars = ScanPragmaVisitor::scan(nodep); for (size_t i = 0; i < vars.size(); ++i) { - AstPragma* const pragmap = vars[i].first; - AstVar* const varp = vars[i].second; + AstPragma* pragmap = vars[i].first; + AstVar* varp = vars[i].second; if (pragmap->pragType() != AstPragmaType::SPLIT_VAR) continue; // nothing to do bool keepPragma = false; if (!varp) { - pragmap->v3warn(SPLITVAR, "Stray pragma of split_var is detected."); + pragmap->v3warn(SPLITVAR, "Unexpected location for split_var pragma."); } else if (!canSplit(varp)) { // maybe packed variable which will be split later. keepPragma = true; // SplitPackedVarVisitor will read this pragma again later. @@ -185,8 +171,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor { m_refs.insert(std::make_pair(varp, std::vector())); } if (!keepPragma) { - pragmap->unlinkFrBack()->deleteTree(); - VL_DANGLING(vars[i].first); + pragmap->unlinkFrBack()->deleteTree(); VL_DANGLING(vars[i].first); } } iterateChildren(nodep); @@ -194,7 +179,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor { m_modp = NULL; } virtual void visit(AstVarRef* nodep) VL_OVERRIDE { - AstVar* const varp = nodep->varp(); + AstVar* varp = nodep->varp(); if (m_refs.find(varp) == m_refs.end()) return; // variable without split_var pragma if (m_firstRun) @@ -206,12 +191,13 @@ class SplitUnpackedVarVisitor : public AstNVisitor { m_refs.erase(varp); } - static void splitSimpleAssign(AstNodeAssign* asnp, AstVarRef* lhsp, AstVarRef *rhsp, int lstart, int rstart, int num) { + static void splitSimpleAssign(AstNodeAssign* asnp, AstVarRef* lhsp, AstVarRef* rhsp, + int lstart, int rstart, int num) { for (int i = 0; i < num; ++i) { - AstVarRef* const lrefp = new AstVarRef(lhsp->fileline(), lhsp->varp(), true); - AstVarRef* const rrefp = new AstVarRef(rhsp->fileline(), rhsp->varp(), false); - AstArraySel* const lselp = new AstArraySel(lhsp->fileline(), lrefp, lstart + i); - AstArraySel* const rselp = new AstArraySel(rhsp->fileline(), rrefp, rstart + i); + AstVarRef* lrefp = new AstVarRef(lhsp->fileline(), lhsp->varp(), true); + AstVarRef* rrefp = new AstVarRef(rhsp->fileline(), rhsp->varp(), false); + AstArraySel* lselp = new AstArraySel(lhsp->fileline(), lrefp, lstart + i); + AstArraySel* rselp = new AstArraySel(rhsp->fileline(), rrefp, rstart + i); // the added new assignment statement will be visited later. asnp->addNext(asnp->cloneType(lselp, rselp)); } @@ -221,8 +207,8 @@ class SplitUnpackedVarVisitor : public AstNVisitor { virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { AstSliceSel* lsel = VN_CAST(nodep->lhsp(), SliceSel); AstSliceSel* rsel = VN_CAST(nodep->rhsp(), SliceSel); - AstVarRef* const lhsp = VN_CAST(lsel ? lsel->fromp() : nodep->lhsp(), VarRef); - AstVarRef* const rhsp = VN_CAST(rsel ? rsel->fromp() : nodep->rhsp(), VarRef); + AstVarRef* lhsp = VN_CAST(lsel ? lsel->fromp() : nodep->lhsp(), VarRef); + AstVarRef* rhsp = VN_CAST(rsel ? rsel->fromp() : nodep->rhsp(), VarRef); // unless simple assignment, nothing to do in this function if (!lhsp || !rhsp) { iterateChildren(nodep); @@ -230,43 +216,40 @@ class SplitUnpackedVarVisitor : public AstNVisitor { } // if nodep is a simple assignment of variables without split_var pragma, quick exit - if (m_refs.find(lhsp->varp()) == m_refs.end() && - m_refs.find(rhsp->varp()) == m_refs.end()) return; + if (m_refs.find(lhsp->varp()) == m_refs.end() && m_refs.find(rhsp->varp()) == m_refs.end()) + return; int lstart, lnum, rstart, rnum; if (lsel) { lstart = lsel->declRange().lo(); lnum = lsel->declRange().elements(); } else { // LHS is entire array - const std::pair lrange = outerMostSizeOfUnpackedArray(lhsp->varp()); lstart = 0; - lnum = lrange.first - lrange.second + 1; + lnum = outerMostSizeOfUnpackedArray(lhsp->varp()); } if (rsel) { rstart = rsel->declRange().lo(); rnum = rsel->declRange().elements(); } else { // RHS is entire array - const std::pair rrange = outerMostSizeOfUnpackedArray(rhsp->varp()); rstart = 0; - rnum = rrange.first - rrange.second + 1; + rnum = outerMostSizeOfUnpackedArray(rhsp->varp()); } if (lnum != rnum) return; // strange. V3Slice will show proper diagnosis splitSimpleAssign(nodep, lhsp, rhsp, lstart, rstart, lnum); - nodep->unlinkFrBack()->deleteTree(); - VL_DANGLING(nodep); + nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); } virtual void visit(AstArraySel* nodep) VL_OVERRIDE { - AstVarRef* const vrefp = VN_CAST(nodep->fromp(), VarRef); + AstVarRef* vrefp = VN_CAST(nodep->fromp(), VarRef); if (!vrefp) { iterateChildren(nodep); return; } - AstVar* const varp = vrefp->varp(); + AstVar* varp = vrefp->varp(); if (m_refs.find(varp) == m_refs.end()) return; // variable without split_var pragma - AstConst* const indexp = constifyIfNot(nodep->bitp()); + AstConst* indexp = constifyIfNot(nodep->bitp()); if (indexp) { // OK m_refs[varp].push_back(nodep); @@ -290,16 +273,14 @@ class SplitUnpackedVarVisitor : public AstNVisitor { << " refs will be split.\n"); AstVar* varp = it->first; AstNode* insertp = varp; - AstUnpackArrayDType* const dtypep = VN_CAST(varp->dtypep(), UnpackArrayDType); + AstUnpackArrayDType* dtypep = VN_CAST(varp->dtypep(), UnpackArrayDType); std::vector vars; // Add the split variables - const std::pair arraySize = outerMostSizeOfUnpackedArray(varp); - const int msb = arraySize.first, lsb = arraySize.second; - for (vlsint32_t i = 0; i <= msb - lsb; ++i) { - // const std::string name = varp->name() + "__BRA__" + AstNode::encodeNumber(i + lsb) + "__KET__"; + for (vlsint32_t i = 0; i <= dtypep->msb() - dtypep->lsb(); ++i) { + // const std::string name = varp->name() + "__BRA__" + AstNode::encodeNumber(i + dtypep->lsb()) + "__KET__"; // unpacked array is traced as var(idx). - const std::string name = varp->name() + AstNode::encodeName('(' + cvtToStr(i + lsb) + ')'); - AstVar* const newp = new AstVar(varp->fileline(), varp->varType(), name, dtypep->subDTypep()); + const std::string name = varp->name() + AstNode::encodeName('(' + cvtToStr(i + dtypep->lsb()) + ')'); + AstVar* newp = new AstVar(varp->fileline(), varp->varType(), name, dtypep->subDTypep()); newp->trace(varp->isTrace()); insertp->addNextHere(newp); if (newp->width() == 1) { // no need to try splitting @@ -313,18 +294,16 @@ class SplitUnpackedVarVisitor : public AstNVisitor { // refer the split variable for (size_t i = 0; i < it->second.size(); ++i) { AstArraySel* selp = it->second[i]; - AstVarRef* const vrefp = VN_CAST(selp->fromp(), VarRef); - AstConst* const indexp = VN_CAST(selp->bitp(), Const); + AstVarRef* vrefp = VN_CAST(selp->fromp(), VarRef); + AstConst* indexp = VN_CAST(selp->bitp(), Const); UASSERT_OBJ(vrefp && indexp, selp, "already checked"); const uint32_t idx = indexp->toUInt(); // V3Width:width() removes VAR_BASE attribute and make index 0-origin. - AstVarRef* const new_vref = new AstVarRef(selp->fileline(), vars.at(idx), vrefp->lvalue()); + AstVarRef* new_vref = new AstVarRef(selp->fileline(), vars.at(idx), vrefp->lvalue()); selp->replaceWith(new_vref); - selp->deleteTree(); - VL_DANGLING(selp); + selp->deleteTree(); VL_DANGLING(selp); } - varp->unlinkFrBack()->deleteTree(); - VL_DANGLING(varp); + varp->unlinkFrBack()->deleteTree(); VL_DANGLING(varp); ++m_numSplit; } m_refs.clear(); // done @@ -339,7 +318,7 @@ public: } ~SplitUnpackedVarVisitor() { UASSERT(m_refs.empty(), "Don't forget to call split()"); - if (m_firstRun) V3Stats::addStat("SplitVar, Split Unpacked Array", m_numSplit); + if (m_firstRun) V3Stats::addStat("SplitVar, Split unpacked arrays", m_numSplit); } int numSplit() const { return m_numSplit; } VL_DEBUG_FUNC; // Declare debug() @@ -384,53 +363,50 @@ public: }; }; +// one Entry instance for an AstVarRef instance +class PackedVarRefEntry { + AstNode* m_nodep; // either AstSel or AstVarRef is expected. + int m_lsb; + int m_bitwidth; + +public: + PackedVarRefEntry(AstSel* selp, int lsb, int bitwidth) + : m_nodep(selp) + , m_lsb(lsb) + , m_bitwidth(bitwidth) {} + PackedVarRefEntry(AstVarRef* refp, int lsb, int bitwidth) + : m_nodep(refp) + , m_lsb(lsb) + , m_bitwidth(bitwidth) {} + AstNode* nodep() const { return m_nodep; } + int lsb() const { return m_lsb; } + int msb() const { return m_lsb + m_bitwidth - 1; } + int bitwidth() const { return m_bitwidth; } + void replaceNodeWith(AstNode* nodep) { + m_nodep->replaceWith(nodep); + m_nodep->deleteTree(); VL_DANGLING(m_nodep); + } +}; + // How a variable is used class PackedVarRef { -public: - // one Entry instance for an AstVarRef instance - class Entry { - AstNode* m_nodep; // either AstSel or AstVarRef is expected. - int m_lsb; - int m_bitwidth; - - public: - Entry(AstSel* selp, int lsb, int bitwidth) - : m_nodep(selp) - , m_lsb(lsb) - , m_bitwidth(bitwidth) {} - Entry(AstVarRef* refp, int lsb, int bitwidth) - : m_nodep(refp) - , m_lsb(lsb) - , m_bitwidth(bitwidth) {} - AstNode* nodep() const { return m_nodep; } - int lsb() const { return m_lsb; } - int msb() const { return m_lsb + m_bitwidth - 1; } - int bitwidth() const { return m_bitwidth; } - void replaceNodeWith(AstNode* nodep) { - m_nodep->replaceWith(nodep); - m_nodep->deleteTree(); - VL_DANGLING(m_nodep); - } - }; - -private: struct SortByFirst { bool operator()(const std::pair& a, const std::pair& b) const { if (a.first == b.first) return a.second < b.second; return a.first < b.first; } }; - std::vector m_lhs, m_rhs; + std::vector m_lhs, m_rhs; AstBasicDType* m_basicp; // cache the ptr since varp->dtypep()->basicp() is expensive public: - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; - std::vector& lhs() { return m_lhs; } - std::vector& rhs() { return m_rhs; } + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + std::vector& lhs() { return m_lhs; } + std::vector& rhs() { return m_rhs; } explicit PackedVarRef(AstVar* varp) : m_basicp(varp->dtypep()->basicp()) {} - void append(const Entry& e, bool lvalue) { + void append(const PackedVarRefEntry& e, bool lvalue) { if (lvalue) m_lhs.push_back(e); else @@ -442,7 +418,7 @@ public: std::vector splitPlan(bool skipUnused) const { std::vector plan; std::vector > points; // - points.reserve(m_lhs.size() * 2 + 2); // 2 points will be added per one Entry + points.reserve(m_lhs.size() * 2 + 2); // 2 points will be added per one PackedVarRefEntry for (const_iterator it = m_lhs.begin(), itend = m_lhs.end(); it != itend; ++it) { points.push_back(std::make_pair(it->lsb(), false)); // start of a region points.push_back(std::make_pair(it->msb() + 1, true)); // end of a region @@ -488,14 +464,7 @@ class SplitPackedVarVisitor : public AstNVisitor { // key:variable to be split. value:location where the variable is referenced. vl_unordered_map m_refs; virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } - virtual void visit(AstAssign* nodep) VL_OVERRIDE { - UASSERT_OBJ(m_isLhs == false, nodep, "unexpected nested assign"); - m_isLhs = true; - iterate(nodep->lhsp()); - m_isLhs = false; - iterate(nodep->rhsp()); - } - virtual void visit(AstAssignW* nodep) VL_OVERRIDE { + virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE { UASSERT_OBJ(m_isLhs == false, nodep, "unexpected nested assign"); m_isLhs = true; iterate(nodep->lhsp()); @@ -508,13 +477,13 @@ class SplitPackedVarVisitor : public AstNVisitor { UINFO(3, "Start analyzing module " << nodep->prettyName() << '\n'); std::vector > vars = ScanPragmaVisitor::scan(nodep); for (size_t i = 0; i < vars.size(); ++i) { - AstPragma* const pragmap = vars[i].first; - AstVar* const varp = vars[i].second; + AstPragma* pragmap = vars[i].first; + AstVar* varp = vars[i].second; if (pragmap->pragType() != AstPragmaType::SPLIT_VAR) continue; // nothing to do UASSERT_OBJ(varp, pragmap, - "Stray pragma must have been consumed in SplitUnpackedVarVisitor"); + "Unexpected pragma must have been consumed in SplitUnpackedVarVisitor"); if (!canSplit(varp, true)) { - pragmap->v3warn(SPLITVAR, + varp->v3warn(SPLITVAR, "Pragma split_var is specified on a variable whose type is " "unsupported or public. " "Packed portion must be an aggregate type of bit or logic."); @@ -522,48 +491,49 @@ class SplitPackedVarVisitor : public AstNVisitor { UINFO(3, varp->prettyNameQ() << " is added to candidate list.\n"); m_refs.insert(std::make_pair(varp, PackedVarRef(varp))); } - pragmap->unlinkFrBack()->deleteTree(); // consume the pragma here anyway. - VL_DANGLING(vars[i].first); + // consume the pragma here anyway. + pragmap->unlinkFrBack()->deleteTree(); VL_DANGLING(vars[i].first); } iterateChildren(nodep); split(); m_modp = NULL; } virtual void visit(AstVarRef* nodep) VL_OVERRIDE { - AstVar* const varp = nodep->varp(); + AstVar* varp = nodep->varp(); vl_unordered_map::iterator refit = m_refs.find(varp); if (refit == m_refs.end()) return; // variable without split_var pragma UASSERT_OBJ(nodep->lvalue() == m_isLhs, nodep, (m_isLhs ? 'l' : 'r') << "value is expected"); - const AstBasicDType* const basicp = refit->second.basicp(); - refit->second.append(PackedVarRef::Entry(nodep, basicp->lsb(), basicp->width()), m_isLhs); + const AstBasicDType* basicp = refit->second.basicp(); + refit->second.append(PackedVarRefEntry(nodep, basicp->lsb(), basicp->width()), m_isLhs); } virtual void visit(AstSel* nodep) VL_OVERRIDE { - AstVarRef* const vrefp = VN_CAST(nodep->fromp(), VarRef); + AstVarRef* vrefp = VN_CAST(nodep->fromp(), VarRef); if (!vrefp) return; - AstVar* const varp = vrefp->varp(); + AstVar* varp = vrefp->varp(); vl_unordered_map::iterator refit = m_refs.find(varp); if (refit == m_refs.end()) return; // variable without split_var pragma - AstConst* const consts[2] = {constifyIfNot(nodep->lsbp()), constifyIfNot(nodep->widthp())}; - + AstConst* consts[2] = {VN_CAST(nodep->lsbp(), Const), VN_CAST(nodep->widthp(), Const)}; if (consts[0] && consts[1]) { // OK refit->second.append( - PackedVarRef::Entry(nodep, consts[0]->toSInt() + refit->second.basicp()->lsb(), - consts[1]->toUInt()), + PackedVarRefEntry(nodep, consts[0]->toSInt() + refit->second.basicp()->lsb(), + consts[1]->toUInt()), m_isLhs); } else { nodep->v3warn(SPLITVAR, "Variable " << vrefp->prettyNameQ() << " will not be split" " because bit range cannot be determined statically."); + if(!consts[0]) UINFO(4, "LSB " << nodep->lsbp() << " is expected to be constant, but not\n"); + if(!consts[1]) UINFO(4, "WIDTH " << nodep->widthp() << " is expected to be constant, but not\n"); m_refs.erase(varp); } } // extract necessary bit range from a newly created variable to meet ref - static AstNode* extractBits(const PackedVarRef::Entry& ref, const SplitNewVar& var, bool lvalue) { - AstVarRef* const refp = new AstVarRef(ref.nodep()->fileline(), var.varp(), lvalue); + static AstNode* extractBits(const PackedVarRefEntry& ref, const SplitNewVar& var, bool lvalue) { + AstVarRef* refp = new AstVarRef(ref.nodep()->fileline(), var.varp(), lvalue); if (ref.lsb() <= var.lsb() && var.msb() <= ref.msb()) { // use the entire bits return refp; } else { // use slice @@ -573,7 +543,7 @@ class SplitPackedVarVisitor : public AstNVisitor { UINFO(4, var.varp()->prettyNameQ() << "[" << msb << ":" << lsb << "] used for " << ref.nodep()->prettyNameQ() << '\n'); // LSB of varp is always 0. "lsb - var.lsb()" means this. see also SplitNewVar - AstSel* const selp = new AstSel(ref.nodep()->fileline(), refp, lsb - var.lsb(), bitwidth); + AstSel* selp = new AstSel(ref.nodep()->fileline(), refp, lsb - var.lsb(), bitwidth); return selp; } } @@ -583,7 +553,7 @@ class SplitPackedVarVisitor : public AstNVisitor { it_end = m_refs.end(); it != it_end; ++it) { AstVar* varp = it->first; - const AstBasicDType* const basicp = it->second.basicp(); + const AstBasicDType* basicp = it->second.basicp(); UINFO(3, "In module " << m_modp->name() << " var " << varp->prettyNameQ() << " which has " << it->second.lhs().size() << " lhs refs and " << it->second.rhs().size() << " rhs refs will be split.\n"); @@ -592,47 +562,51 @@ class SplitPackedVarVisitor : public AstNVisitor { if (vars.empty()) continue; // Add the split variables for (size_t i = 0; i < vars.size(); ++i) { - SplitNewVar& var = vars[i]; - int left = var.msb(), right = var.lsb(); + SplitNewVar* newvarp = &vars[i]; + int left = newvarp->msb(), right = newvarp->lsb(); if (basicp->littleEndian()) std::swap(left, right); const std::string name = varp->name() + "__BRA__" + AstNode::encodeNumber(left) + AstNode::encodeName(":") + AstNode::encodeNumber(right) + "__KET__"; AstBasicDType* dtypep; - switch (basicp->keyword().m_e) { + switch (basicp->keyword()) { case AstBasicDTypeKwd::BIT: - dtypep = new AstBasicDType(varp->subDTypep()->fileline(), VFlagBitPacked(), var.bitwidth()); + dtypep = new AstBasicDType(varp->subDTypep()->fileline(), VFlagBitPacked(), + newvarp->bitwidth()); break; case AstBasicDTypeKwd::LOGIC: - dtypep = new AstBasicDType(varp->subDTypep()->fileline(), VFlagLogicPacked(), var.bitwidth()); + dtypep = new AstBasicDType(varp->subDTypep()->fileline(), VFlagLogicPacked(), + newvarp->bitwidth()); break; default: UASSERT_OBJ(false, basicp, "Only bit and logic are allowed"); } - dtypep->rangep(new AstRange(varp->fileline(), var.msb(), var.lsb())); + dtypep->rangep(new AstRange(varp->fileline(), newvarp->msb(), newvarp->lsb())); dtypep->rangep()->littleEndian(basicp->littleEndian()); - var.varp(new AstVar(varp->fileline(), varp->varType(), name, dtypep)); - // var.varp()->trace(varp->isTrace()); // enable this line to trace split variable directly + newvarp->varp(new AstVar(varp->fileline(), varp->varType(), name, dtypep)); + // newvarp->varp()->trace(varp->isTrace()); // enable this line to trace split variable directly m_netp->typeTablep()->addTypesp(dtypep); - varp->addNextHere(var.varp()); - UINFO(4, var.varp()->prettyNameQ() + varp->addNextHere(newvarp->varp()); + UINFO(4, newvarp->varp()->prettyNameQ() << " is added for " << varp->prettyNameQ() << '\n'); } for (int lvalue = 0; lvalue <= 1; ++lvalue) { // refer the new split variables - std::vector& refs = lvalue ? it->second.lhs() : it->second.rhs(); + std::vector& refs = lvalue ? it->second.lhs() : it->second.rhs(); for (PackedVarRef::iterator refit = refs.begin(), refitend = refs.end(); refit != refitend; ++refit) { NewVars::const_iterator varit = std::upper_bound( vars.begin(), vars.end(), refit->lsb(), SplitNewVar::Match()); UASSERT_OBJ(varit != vars.end(), refit->nodep(), "Not found"); - UASSERT(!(varit->msb() < refit->lsb() || refit->msb() < varit->lsb()), "wrong search result"); + UASSERT(!(varit->msb() < refit->lsb() || refit->msb() < varit->lsb()), + "wrong search result"); AstNode* prev = extractBits(*refit, *varit, lvalue); for (int residue = refit->msb() - varit->msb(); residue > 0; residue -= varit->bitwidth()) { ++varit; - UASSERT_OBJ(varit != vars.end(), refit->nodep(), "not enough split variables"); - AstNode* const bitsp = extractBits(*refit, *varit, lvalue); + UASSERT_OBJ(varit != vars.end(), refit->nodep(), + "not enough split variables"); + AstNode* bitsp = extractBits(*refit, *varit, lvalue); prev = new AstConcat(refit->nodep()->fileline(), bitsp, prev); } refit->replaceNodeWith(prev); @@ -643,7 +617,7 @@ class SplitPackedVarVisitor : public AstNVisitor { vars.front().varp()->trace(varp->isTrace()); } else if (varp->isTrace()) { // Let's create a dedicated variable for trace which is concat of split variables - AstVar* const traceVar = new AstVar(varp->fileline(), varp->varType(), varp->name(), varp->dtypep()); + AstVar* traceVar = new AstVar(varp->fileline(), varp->varType(), varp->name(), varp->dtypep()); traceVar->trace(true); varp->addNextHere(traceVar); AstNode* rhs = new AstVarRef(vars.front().varp()->fileline(), vars.front().varp(), false); @@ -655,8 +629,7 @@ class SplitPackedVarVisitor : public AstNVisitor { AstAssignW* assignp = new AstAssignW(varp->fileline(), new AstVarRef(varp->fileline(), traceVar, true), rhs); traceVar->addNextHere(assignp); } - varp->unlinkFrBack()->deleteTree(); - VL_DANGLING(varp); + varp->unlinkFrBack()->deleteTree(); VL_DANGLING(varp); ++m_numSplit; } m_refs.clear(); // done @@ -672,7 +645,7 @@ public: } ~SplitPackedVarVisitor() { UASSERT(m_refs.empty(), "Don't forget to call split()"); - V3Stats::addStat("SplitVar, Split Packed variables", m_numSplit); + V3Stats::addStat("SplitVar, Split packed variables", m_numSplit); } // Check if the passed variable can be split. @@ -680,11 +653,11 @@ public: // when the access to the variable cannot be determined statically. static bool canSplit(const AstVar* nodep, bool checkUnpacked) { if (AstBasicDType* const basicp = nodep->dtypep()->basicp()) { - // floating point, string are not supported const std::pair dim = nodep->dtypep()->dimensions(false); // unpacked array will be split in SplitUnpackedVarVisitor() beforehand. return (!checkUnpacked || dim.second == 0) && nodep->dtypep()->widthMin() > 1 - && basicp->isBitLogic() && !nodep->isSigPublic(); + && basicp->isBitLogic() // floating point and string are not supported + && !nodep->isSigPublic(); } return false; } @@ -702,7 +675,7 @@ void V3SplitVar::splitUnpackedVariable(AstNetlist* nodep) { UINFO(3, visitor.numSplit() << " variables are split in trial " << trial << '\n'); if (visitor.numSplit() == 0) done = 1; // nothing to do anymore } // Destruct before checking - V3Global::dumpCheckGlobalTree("split_var", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("split_var", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 9); } } @@ -711,7 +684,7 @@ void V3SplitVar::splitPackedVariable(AstNetlist* nodep) { { SplitPackedVarVisitor visitor(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("split_var", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("split_var", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 9); } bool V3SplitVar::canSplitVar(const AstVar* varp) { diff --git a/src/verilog.y b/src/verilog.y index ee6317613..807f2dffd 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1932,7 +1932,7 @@ non_port_module_item: // ==IEEE: non_port_module_item | yVL_INLINE_MODULE { $$ = new AstPragma($1,AstPragmaType::INLINE_MODULE); } | yVL_NO_INLINE_MODULE { $$ = new AstPragma($1,AstPragmaType::NO_INLINE_MODULE); } | yVL_PUBLIC_MODULE { $$ = new AstPragma($1,AstPragmaType::PUBLIC_MODULE); v3Global.dpi(true); } - | yVL_SPLIT_VAR { $$ = new AstPragma($1,AstPragmaType::SPLIT_VAR); } + | yVL_SPLIT_VAR { $$ = new AstPragma($1,AstPragmaType::SPLIT_VAR); } ; module_or_generate_item: // ==IEEE: module_or_generate_item diff --git a/test_regress/t/t_split_var_0.pl b/test_regress/t/t_split_var_0.pl index 89a4e77d9..6f8bdaa6c 100755 --- a/test_regress/t/t_split_var_0.pl +++ b/test_regress/t/t_split_var_0.pl @@ -10,11 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags2 => ['--stats '], ); execute( check_finished => 1, ); +file_grep($Self->{stats}, qr/SplitVar,\s+Split packed variables\s+(\d+)/i, 80); +file_grep($Self->{stats}, qr/SplitVar,\s+Split unpacked arrays\s+(\d+)/i, 12); ok(1); 1; diff --git a/test_regress/t/t_split_var_0.v b/test_regress/t/t_split_var_0.v index 72097ac56..4dfb24034 100644 --- a/test_regress/t/t_split_var_0.v +++ b/test_regress/t/t_split_var_0.v @@ -1,3 +1,7 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Yutetsu TAKATSUKASA. // If split_var pragma is removed, UNOPTFLAT appears. diff --git a/test_regress/t/t_split_var_1_bad.out b/test_regress/t/t_split_var_1_bad.out index 2f0000b65..7085a600d 100644 --- a/test_regress/t/t_split_var_1_bad.out +++ b/test_regress/t/t_split_var_1_bad.out @@ -1,26 +1,26 @@ -%Warning-SPLITVAR: t/t_split_var_1_bad.v:2: Stray pragma of split_var is detected. +%Warning-SPLITVAR: t/t_split_var_1_bad.v:7: Unexpected location for split_var pragma. : ... In instance t /*verilator split_var*/ ^~~~~~~~~~~~~~~~~~~~~~~ ... Use "/* verilator lint_off SPLITVAR */" and lint_on around source to disable this message. -%Warning-SPLITVAR: t/t_split_var_1_bad.v:28: Variable 'cannot_split' will not be split because index cannot be determined statically. +%Warning-SPLITVAR: t/t_split_var_1_bad.v:33: Variable 'cannot_split' will not be split because index cannot be determined statically. : ... In instance t.i_sub0 rd_data = cannot_split[addr]; ^~~~ -%Warning-SPLITVAR: t/t_split_var_1_bad.v:5: Pragma split_var is specified on a variable whose type is unsupported or public. Packed portion must be an aggregate type of bit or logic. - : ... In instance t +%Warning-SPLITVAR: t/t_split_var_1_bad.v:10: Pragma split_var is specified on a variable whose type is unsupported or public. Packed portion must be an aggregate type of bit or logic. + : ... In instance t real should_show_warning0; /*verilator split_var*/ - ^~~~~~~~~~~~~~~~~~~~~~~ -%Warning-SPLITVAR: t/t_split_var_1_bad.v:6: Pragma split_var is specified on a variable whose type is unsupported or public. Packed portion must be an aggregate type of bit or logic. - : ... In instance t + ^~~~~~~~~~~~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:11: Pragma split_var is specified on a variable whose type is unsupported or public. Packed portion must be an aggregate type of bit or logic. + : ... In instance t string should_show_warning1[0:2]; /*verilator split_var*/ ^~~~~~~~~~~~~~~~~~~~ -%Warning-SPLITVAR: t/t_split_var_1_bad.v:7: Pragma split_var is specified on a variable whose type is unsupported or public. Packed portion must be an aggregate type of bit or logic. - : ... In instance t +%Warning-SPLITVAR: t/t_split_var_1_bad.v:12: Pragma split_var is specified on a variable whose type is unsupported or public. Packed portion must be an aggregate type of bit or logic. + : ... In instance t wire should_show_warning2; /*verilator split_var*/ - ^~~~~~~~~~~~~~~~~~~~~~~ -%Warning-SPLITVAR: t/t_split_var_1_bad.v:37: Variable 'cannot_split' will not be split because bit range cannot be determined statically. - : ... In instance t.i_sub2 + ^~~~~~~~~~~~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:42: Variable 'cannot_split' will not be split because bit range cannot be determined statically. + : ... In instance t.i_sub1 rd_data = cannot_split[addr]; ^ %Error: Exiting due to diff --git a/test_regress/t/t_split_var_1_bad.pl b/test_regress/t/t_split_var_1_bad.pl index d2a983b22..d476b3e5a 100755 --- a/test_regress/t/t_split_var_1_bad.pl +++ b/test_regress/t/t_split_var_1_bad.pl @@ -11,8 +11,11 @@ scenarios(simulator => 1); compile( fails => 1, + verilator_flags2 => ['--stats '], expect_filename => $Self->{golden_filename}, ); +file_grep($Self->{stats}, qr/SplitVar,\s+Split packed variables\s+(\d+)/i, 0); +file_grep($Self->{stats}, qr/SplitVar,\s+Split unpacked arrays\s+(\d+)/i, 0); ok(1); 1; diff --git a/test_regress/t/t_split_var_1_bad.v b/test_regress/t/t_split_var_1_bad.v index 80f1bafa5..8ede96633 100644 --- a/test_regress/t/t_split_var_1_bad.v +++ b/test_regress/t/t_split_var_1_bad.v @@ -1,3 +1,8 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Yutetsu TAKATSUKASA. + module t(); /*stray pragma */ /*verilator split_var*/ @@ -10,7 +15,7 @@ module t(); logic [7:0] rd_data0, rd_data1, rd_data2; sub0 i_sub0(.addr(addr), .rd_data(rd_data0)); - sub2 i_sub2(.addr(addr), .rd_data(rd_data2)); + sub1 i_sub1(.addr(addr), .rd_data(rd_data2)); initial begin addr = 0; @@ -30,7 +35,7 @@ module sub0(input [3:0]addr, output logic [7:0] rd_data); endmodule -module sub2(input [3:0]addr, output logic [7:0] rd_data); +module sub1(input [3:0]addr, output logic [7:0] rd_data); logic [15:0] [7:0] cannot_split; /*verilator split_var*/ always_comb diff --git a/test_regress/t/t_split_var_2_trace.pl b/test_regress/t/t_split_var_2_trace.pl index 973a6a53a..329c4afde 100755 --- a/test_regress/t/t_split_var_2_trace.pl +++ b/test_regress/t/t_split_var_2_trace.pl @@ -14,7 +14,7 @@ top_filename("t/t_split_var_0.v"); # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # So use 4 threads here though it's not optimal in performace wise, but ok. compile( - verilator_flags2 => [$Self->{vltmt} ? '--cc --trace --threads 4' : '--cc --trace ' ], + verilator_flags2 => ['--cc --trace --stats ' . ($Self->{vltmt} ? '--threads 4' : '')], ); execute( @@ -22,6 +22,8 @@ execute( ); vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); +file_grep($Self->{stats}, qr/SplitVar,\s+Split packed variables\s+(\d+)/i, 92); +file_grep($Self->{stats}, qr/SplitVar,\s+Split unpacked arrays\s+(\d+)/i, 12); ok(1); 1; diff --git a/test_regress/t/t_unoptflat_simple_2_bad.out b/test_regress/t/t_unoptflat_simple_2_bad.out index e70cb6859..4af6d3bb2 100644 --- a/test_regress/t/t_unoptflat_simple_2_bad.out +++ b/test_regress/t/t_unoptflat_simple_2_bad.out @@ -9,5 +9,5 @@ %Warning-UNOPTFLAT: t/t_unoptflat_simple_2.v:14: t.x, width 3, fanout 12, can be split %Warning-UNOPTFLAT: Most fanned out candidate vars to split: %Warning-UNOPTFLAT: t/t_unoptflat_simple_2.v:14: t.x, width 3, fanout 12, can be split --Info: Adding /*verilator split_var*/ to variables above may resolve this warning. +%Warning-UNOPTFLAT: Adding /*verilator split_var*/ to variables above may resolve this warning. %Error: Exiting due to