diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2f8816345..814244829 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -75,6 +75,7 @@ set(HEADERS V3Dfg.h V3DfgCache.h V3DfgContext.h + V3DfgDataType.h V3DfgOptimizer.h V3DfgPasses.h V3DfgPatternStats.h @@ -237,6 +238,7 @@ set(COMMON_SOURCES V3DfgCache.cpp V3DfgColorSCCs.cpp V3DfgCse.cpp + V3DfgDataType.cpp V3DfgDecomposition.cpp V3DfgDfgToAst.cpp V3DfgOptimizer.cpp diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index c71d7faf7..8b00b1567 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -247,6 +247,7 @@ RAW_OBJS_PCH_ASTNOMT = \ V3DfgCache.o \ V3DfgColorSCCs.o \ V3DfgCse.o \ + V3DfgDataType.o \ V3DfgDecomposition.o \ V3DfgDfgToAst.o \ V3DfgOptimizer.o \ diff --git a/src/V3Dfg.cpp b/src/V3Dfg.cpp index 90cef90c0..784fbf552 100644 --- a/src/V3Dfg.cpp +++ b/src/V3Dfg.cpp @@ -23,34 +23,6 @@ VL_DEFINE_DEBUG_FUNCTIONS; -//------------------------------------------------------------------------------ -// V3Dfg - -// predicate for supported data types -static bool dfgGraphIsSupportedDTypePacked(const AstNodeDType* dtypep) { - dtypep = dtypep->skipRefp(); - if (const AstBasicDType* const typep = VN_CAST(dtypep, BasicDType)) { - return typep->keyword().isIntNumeric(); - } - if (const AstPackArrayDType* const typep = VN_CAST(dtypep, PackArrayDType)) { - return dfgGraphIsSupportedDTypePacked(typep->subDTypep()); - } - if (const AstNodeUOrStructDType* const typep = VN_CAST(dtypep, NodeUOrStructDType)) { - return typep->packed(); - } - return false; -} - -bool V3Dfg::isSupported(const AstNodeDType* dtypep) { - dtypep = dtypep->skipRefp(); - // Support 1 dimensional unpacked arrays of packed types - if (const AstUnpackArrayDType* const typep = VN_CAST(dtypep, UnpackArrayDType)) { - return dfgGraphIsSupportedDTypePacked(typep->subDTypep()); - } - // Support packed types - return dfgGraphIsSupportedDTypePacked(dtypep); -} - //------------------------------------------------------------------------------ // DfgGraph @@ -113,28 +85,28 @@ std::unique_ptr DfgGraph::clone() const { switch (vtx.type()) { #include "V3Dfg__gen_clone_cases.h" // From ./astgen case VDfgType::Sel: { - DfgSel* const cp = new DfgSel{*clonep, vtx.fileline(), vtx.dtypep()}; + DfgSel* const cp = new DfgSel{*clonep, vtx.fileline(), vtx.dtype()}; cp->lsb(vtx.as()->lsb()); vtxp2clonep.emplace(&vtx, cp); break; } case VDfgType::UnitArray: { - DfgUnitArray* const cp = new DfgUnitArray{*clonep, vtx.fileline(), vtx.dtypep()}; + DfgUnitArray* const cp = new DfgUnitArray{*clonep, vtx.fileline(), vtx.dtype()}; vtxp2clonep.emplace(&vtx, cp); break; } case VDfgType::Mux: { - DfgMux* const cp = new DfgMux{*clonep, vtx.fileline(), vtx.dtypep()}; + DfgMux* const cp = new DfgMux{*clonep, vtx.fileline(), vtx.dtype()}; vtxp2clonep.emplace(&vtx, cp); break; } case VDfgType::SpliceArray: { - DfgSpliceArray* const cp = new DfgSpliceArray{*clonep, vtx.fileline(), vtx.dtypep()}; + DfgSpliceArray* const cp = new DfgSpliceArray{*clonep, vtx.fileline(), vtx.dtype()}; vtxp2clonep.emplace(&vtx, cp); break; } case VDfgType::SplicePacked: { - DfgSplicePacked* const cp = new DfgSplicePacked{*clonep, vtx.fileline(), vtx.dtypep()}; + DfgSplicePacked* const cp = new DfgSplicePacked{*clonep, vtx.fileline(), vtx.dtype()}; vtxp2clonep.emplace(&vtx, cp); break; } @@ -265,13 +237,13 @@ std::string DfgGraph::makeUniqueName(const std::string& prefix, size_t n) { return "__Vdfg" + prefix + m_tmpNameStub + std::to_string(n); } -DfgVertexVar* DfgGraph::makeNewVar(FileLine* flp, const std::string& name, AstNodeDType* dtypep, - AstScope* scopep) { +DfgVertexVar* DfgGraph::makeNewVar(FileLine* flp, const std::string& name, + const DfgDataType& dtype, AstScope* scopep) { UASSERT_OBJ(!!scopep != !!modulep(), flp, "makeNewVar scopep should only be provided for a scoped DfgGraph"); // Create AstVar - AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, dtypep}; + AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, dtype.astDtypep()}; if (scopep) { // Add AstVar to the scope's module @@ -281,13 +253,13 @@ DfgVertexVar* DfgGraph::makeNewVar(FileLine* flp, const std::string& name, AstNo // Add to scope scopep->addVarsp(vscp); // Create and return the corresponding variable vertex - if (VN_IS(varp->dtypeSkipRefp(), UnpackArrayDType)) return new DfgVarArray{*this, vscp}; + if (dtype.isArray()) return new DfgVarArray{*this, vscp}; return new DfgVarPacked{*this, vscp}; } else { // Add AstVar to containing module modulep()->addStmtsp(varp); // Create and return the corresponding variable vertex - if (VN_IS(varp->dtypeSkipRefp(), UnpackArrayDType)) return new DfgVarArray{*this, varp}; + if (dtype.isArray()) return new DfgVarArray{*this, varp}; return new DfgVarPacked{*this, varp}; } } @@ -314,7 +286,7 @@ static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) { } // Type and fanout os << '\n'; - varVtxp->dtypep()->dumpSmall(os); + varVtxp->dtype().astDtypep()->dumpSmall(os); os << " / F" << varVtxp->fanout(); // End 'label' os << '"'; @@ -371,7 +343,7 @@ static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) { os << toDotId(vtx); os << " [label=\"SEL _[" << msb << ":" << lsb << "]\n"; os << cvtToHex(selVtxp) << '\n'; - vtx.dtypep()->dumpSmall(os); + vtx.dtype().astDtypep()->dumpSmall(os); os << " / F" << vtx.fanout() << '"'; if (vtx.hasMultipleSinks()) { os << ", shape=doublecircle"; @@ -386,7 +358,7 @@ static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) { os << toDotId(vtx); os << " [label=\"" << vtx.typeName() << '\n'; os << cvtToHex(&vtx) << '\n'; - vtx.dtypep()->dumpSmall(os); + vtx.dtype().astDtypep()->dumpSmall(os); os << " / F" << vtx.fanout() << '"'; if (vtx.hasMultipleSinks()) { os << ", shape=doubleoctagon"; @@ -423,7 +395,7 @@ static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) { os << toDotId(vtx); os << " [label=\"" << vtx.typeName() << '\n'; os << cvtToHex(&vtx) << '\n'; - vtx.dtypep()->dumpSmall(os); + vtx.dtype().astDtypep()->dumpSmall(os); os << " / F" << vtx.fanout() << '"'; if (vtx.hasMultipleSinks()) { os << ", shape=doublecircle"; @@ -554,9 +526,9 @@ DfgGraph::sinkCone(const std::vector& vtxps) const { //------------------------------------------------------------------------------ // DfgVertex -DfgVertex::DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep) +DfgVertex::DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dt) : m_filelinep{flp} - , m_dtypep{dtypep} + , m_dtype{dt} , m_type{type} { dfg.addVertex(*this); } diff --git a/src/V3Dfg.h b/src/V3Dfg.h index 997d11cbf..3bd212e91 100644 --- a/src/V3Dfg.h +++ b/src/V3Dfg.h @@ -35,6 +35,7 @@ #include "V3Ast.h" #include "V3Cfg.h" +#include "V3DfgDataType.h" #include "V3Error.h" #include "V3Global.h" #include "V3Hash.h" @@ -71,16 +72,13 @@ namespace V3Dfg { //----------------------------------------------------------------------- // Functions for compatibility tests -// Returns true if the given data type can be represented in the graph -bool isSupported(const AstNodeDType* dtypep) VL_MT_DISABLED; - // Returns true if variable can be represented in the graph inline bool isSupported(const AstVar* varp) { if (varp->isIfaceRef()) return false; // Cannot handle interface references if (varp->delayp()) return false; // Cannot handle delayed variables if (varp->isSc()) return false; // SystemC variables are special and rare, we can ignore if (varp->dfgMultidriven()) return false; // Discovered as multidriven on earlier DFG run - return isSupported(varp->dtypep()); + return DfgDataType::fromAst(varp->dtypep()); } // Returns true if variable can be represented in the graph @@ -99,38 +97,6 @@ inline bool isSupported(const AstVarScope* vscp) { return isSupported(vscp->varp()); } -//----------------------------------------------------------------------- -// Functions for data types - -// Some data types are interned, in order to facilitate type comparison -// via pointer compariosn. These are functoins to construct the canonical -// DFG data types - -// Returns data type used to represent any packed value of the given 'width'. -inline AstNodeDType* dtypePacked(uint32_t width) { - return v3Global.rootp()->typeTablep()->findLogicDType(width, width, VSigning::UNSIGNED); -} - -// Returns data type used to represent any array with the given type and number of elements. -inline AstNodeDType* dtypeArray(AstNodeDType* subDtypep, uint32_t size) { - UASSERT_OBJ(isSupported(subDtypep), subDtypep, "Unsupported element type"); - FileLine* const flp = subDtypep->fileline(); - AstRange* const rangep = new AstRange{flp, static_cast(size - 1), 0}; - AstNodeDType* const dtypep = new AstUnpackArrayDType{flp, subDtypep, rangep}; - v3Global.rootp()->typeTablep()->addTypesp(dtypep); - return dtypep; -} - -// Return data type used to represent the type of 'nodep' when converted to a DfgVertex -inline AstNodeDType* toDfgDType(const AstNodeDType* dtypep) { - dtypep = dtypep->skipRefp(); - UASSERT_OBJ(isSupported(dtypep), dtypep, "Unsupported dtype"); - // For simplicity, all packed types are represented with a fixed type - if (const AstUnpackArrayDType* const uatp = VN_CAST(dtypep, UnpackArrayDType)) { - return dtypeArray(toDfgDType(uatp->subDTypep()), uatp->elementsConst()); - } - return dtypePacked(dtypep->width()); -} } //namespace V3Dfg //------------------------------------------------------------------------------ @@ -199,7 +165,7 @@ class DfgVertex VL_NOT_FINAL { DfgEdge::List m_sinks; // List of sink edges of this vertex FileLine* const m_filelinep; // Source location - AstNodeDType* m_dtypep; // Data type of the result of this vertex - mutable for efficiency + const DfgDataType& m_dtype; // Data type of the result of this vertex const VDfgType m_type; // Vertex type tag // The only way to access thes is via DfgUserMap, so mutable is appropriate, @@ -225,7 +191,7 @@ public: protected: // CONSTRUCTOR - DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep) VL_MT_DISABLED; + DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dt) VL_MT_DISABLED; // Use unlinkDelete instead virtual ~DfgVertex() VL_MT_DISABLED = default; @@ -250,20 +216,15 @@ public: // Source location FileLine* fileline() const { return m_filelinep; } // The data type of the result of the vertex - AstNodeDType* dtypep() const { return m_dtypep; } - // Is it a packed type - bool isPacked() const { return VN_IS(dtypep(), BasicDType); } - // Is it an array type - bool isArray() const { return !isPacked(); } - // Width of result + const DfgDataType& dtype() const { return m_dtype; } + // Shorthands for accessors of 'dtype()' + bool isPacked() const { return m_dtype.isPacked(); } + bool isArray() const { return m_dtype.isArray(); } + uint32_t size() const { return m_dtype.size(); } + // Type check + size uint32_t width() const { - UASSERT_OBJ(isPacked(), this, "non-packed has no 'width()'"); - return dtypep()->width(); - } - // Number of sub-elements in result vertex - uint32_t size() const { - if (isPacked()) return dtypep()->width(); - return VN_AS(dtypep(), UnpackArrayDType)->elementsConst(); + UASSERT_OBJ(m_dtype.isPacked(), this, "Non packed vertex has no 'width'"); + return m_dtype.size(); } // Predicate: has 1 or more sinks @@ -304,6 +265,8 @@ public: // Relink all sinks to be driven from the given new source void replaceWith(DfgVertex* vtxp) { + UASSERT_OBJ(vtxp != this, this, "Replacing DfgVertex with itself"); + UASSERT_OBJ(vtxp->dtype() == dtype(), this, "Replacement DfgVertex has different type"); while (!m_sinks.empty()) m_sinks.frontp()->relinkSrcp(vtxp); } @@ -553,7 +516,7 @@ public: // Create a new variable with the given name and data type. For a Scoped // Dfg, the AstScope where the corresponding AstVarScope will be inserted // must be provided - DfgVertexVar* makeNewVar(FileLine*, const std::string& name, AstNodeDType*, + DfgVertexVar* makeNewVar(FileLine*, const std::string& name, const DfgDataType&, AstScope*) VL_MT_DISABLED; // Split this graph into individual components (unique sub-graphs with no edges between them). diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp index bdc190394..2914234d8 100644 --- a/src/V3DfgAstToDfg.cpp +++ b/src/V3DfgAstToDfg.cpp @@ -84,6 +84,7 @@ class AstToDfgVisitor final : public VNVisitor { DfgVertexVar* getVarVertex(Variable* varp) { if (!varp->user2p()) { + // TODO: fix this up when removing the different flavours of DfgVar const AstNodeDType* const dtypep = varp->dtypep()->skipRefp(); DfgVertexVar* const vtxp = VN_IS(dtypep, UnpackArrayDType) diff --git a/src/V3DfgBreakCycles.cpp b/src/V3DfgBreakCycles.cpp index c043ebdc0..bdc2558f8 100644 --- a/src/V3DfgBreakCycles.cpp +++ b/src/V3DfgBreakCycles.cpp @@ -123,8 +123,7 @@ class TraceDriver final : public DfgVisitor { // Vertex is DfgConst, in which case this code is unreachable ... using Vtx = typename std::conditional::value, DfgSel, Vertex>::type; - AstNodeDType* const dtypep = V3Dfg::dtypePacked(width); - Vtx* const vtxp = new Vtx{m_dfg, refp->fileline(), dtypep}; + Vtx* const vtxp = new Vtx{m_dfg, refp->fileline(), DfgDataType::packed(width)}; m_vtx2Scc[vtxp] = 0; m_newVtxps.emplace_back(vtxp); return reinterpret_cast(vtxp); @@ -137,10 +136,9 @@ class TraceDriver final : public DfgVisitor { if (!nodep) nodep = v3Global.rootp(); const std::string name = m_dfg.makeUniqueName(prefix, nodep->user2Inc()); FileLine* const flp = vtxp->fileline(); - AstNodeDType* const dtypep = vtxp->dtypep(); DfgVertex::ScopeCache scopeCache; AstScope* const scopep = m_dfg.modulep() ? nullptr : vtxp->scopep(scopeCache); - DfgVertexVar* const varp = m_dfg.makeNewVar(flp, name, dtypep, scopep); + DfgVertexVar* const varp = m_dfg.makeNewVar(flp, name, vtxp->dtype(), scopep); varp->varp()->isInternal(true); varp->tmpForp(varp->nodep()); return varp; @@ -151,8 +149,8 @@ class TraceDriver final : public DfgVisitor { // return after the call. 'visit' methods should not call 'iterate', call // this method instead, which checks for cycles. DfgVertex* trace(DfgVertex* const vtxp, const uint32_t msb, const uint32_t lsb) { - UASSERT_OBJ(!vtxp->isArray(), vtxp, "Cannot trace array type vertices"); - UASSERT_OBJ(vtxp->width() > msb, vtxp, "Traced Vertex too narrow"); + UASSERT_OBJ(vtxp->isPacked(), vtxp, "Can only trace packed type vertices"); + UASSERT_OBJ(vtxp->size() > msb, vtxp, "Traced Vertex too narrow"); // Push to stack m_stack.emplace_back(vtxp, msb, lsb); @@ -958,7 +956,7 @@ class IndependentBits final : public DfgVisitor { DfgVertex* const currp = workList.front(); workList.pop_front(); - if (VN_IS(currp->dtypep(), UnpackArrayDType)) { + if (currp->isArray()) { // For an unpacked array vertex, just enque it's sinks. // (There can be no loops through arrays directly) currp->foreachSink([&](DfgVertex& vtx) { @@ -1146,8 +1144,7 @@ class FixUpIndependentRanges final { } // Fall back on using the part of the variable (if dependent, or trace failed) if (!termp) { - AstNodeDType* const dtypep = V3Dfg::dtypePacked(width); - DfgSel* const selp = new DfgSel{m_dfg, vtx.fileline(), dtypep}; + DfgSel* const selp = new DfgSel{m_dfg, vtx.fileline(), DfgDataType::packed(width)}; // Same component as 'vtxp', as reads 'vtxp' and will replace 'vtxp' m_vtx2Scc[selp] = m_vtx2Scc.at(vtx); // Do not connect selp->fromp yet, need to do afer replacing 'vtxp' @@ -1225,8 +1222,7 @@ class FixUpIndependentRanges final { for (size_t i = 1; i < termps.size(); ++i) { DfgVertex* const termp = termps[i]; const uint32_t catWidth = replacementp->width() + termp->width(); - AstNodeDType* const dtypep = V3Dfg::dtypePacked(catWidth); - DfgConcat* const catp = new DfgConcat{m_dfg, flp, dtypep}; + DfgConcat* const catp = new DfgConcat{m_dfg, flp, DfgDataType::packed(catWidth)}; catp->rhsp(replacementp); catp->lhsp(termp); // Need to figure out which component the replacement vertex diff --git a/src/V3DfgCache.h b/src/V3DfgCache.h index 4075b42e4..10c31764d 100644 --- a/src/V3DfgCache.h +++ b/src/V3DfgCache.h @@ -54,28 +54,27 @@ inline bool vertexEqual(const DfgVertex* ap, const DfgVertex* bp) { class KeySel final { const DfgVertex* const m_fromp; const uint32_t m_lsb; - const uint32_t m_width; + const uint32_t m_size; public: - KeySel(DfgVertex* fromp, uint32_t lsb, uint32_t width) + KeySel(DfgVertex* fromp, uint32_t lsb, uint32_t size) : m_fromp{fromp} , m_lsb{lsb} - , m_width{width} {} + , m_size{size} {} struct Hash final { size_t operator()(const KeySel& key) const { // cppcheck-suppress unreadVariable // cppcheck bug V3Hash hash{vertexHash(key.m_fromp)}; hash += key.m_lsb; - hash += key.m_width; + hash += key.m_size; return hash.value(); } }; struct Equal final { bool operator()(const KeySel& a, const KeySel& b) const { - return a.m_lsb == b.m_lsb && a.m_width == b.m_width - && vertexEqual(a.m_fromp, b.m_fromp); + return a.m_lsb == b.m_lsb && a.m_size == b.m_size && vertexEqual(a.m_fromp, b.m_fromp); } }; }; @@ -166,16 +165,16 @@ using CacheBinary = Cache; using CacheTernary = Cache; // These return a reference to the mapped entry, inserting a nullptr if not yet exists -inline DfgSel*& getEntry(CacheSel& cache, AstNodeDType* dtypep, DfgVertex* src0p, uint32_t lsb) { - UASSERT_OBJ(VN_IS(dtypep, BasicDType), dtypep, "non-packed has no 'width()'"); +inline DfgSel*& getEntry(CacheSel& cache, const DfgDataType& dtype, DfgVertex* src0p, + uint32_t lsb) { return cache .emplace(std::piecewise_construct, // - std::forward_as_tuple(src0p, lsb, dtypep->width()), // + std::forward_as_tuple(src0p, lsb, dtype.size()), // std::forward_as_tuple(nullptr)) .first->second; } -inline DfgVertexUnary*& getEntry(CacheUnary& cache, AstNodeDType*, DfgVertex* src0p) { +inline DfgVertexUnary*& getEntry(CacheUnary& cache, const DfgDataType&, DfgVertex* src0p) { return cache .emplace(std::piecewise_construct, // std::forward_as_tuple(src0p), // @@ -183,7 +182,7 @@ inline DfgVertexUnary*& getEntry(CacheUnary& cache, AstNodeDType*, DfgVertex* sr .first->second; } -inline DfgVertexBinary*& getEntry(CacheBinary& cache, AstNodeDType*, DfgVertex* src0p, +inline DfgVertexBinary*& getEntry(CacheBinary& cache, const DfgDataType&, DfgVertex* src0p, DfgVertex* src1p) { return cache .emplace(std::piecewise_construct, // @@ -192,7 +191,7 @@ inline DfgVertexBinary*& getEntry(CacheBinary& cache, AstNodeDType*, DfgVertex* .first->second; } -inline DfgVertexTernary*& getEntry(CacheTernary& cache, AstNodeDType*, DfgVertex* src0p, +inline DfgVertexTernary*& getEntry(CacheTernary& cache, const DfgDataType&, DfgVertex* src0p, DfgVertex* src1p, DfgVertex* src2p) { return cache .emplace(std::piecewise_construct, // @@ -202,24 +201,20 @@ inline DfgVertexTernary*& getEntry(CacheTernary& cache, AstNodeDType*, DfgVertex } // These return a reference to the mapped entry, inserting a nullptr if not yet exists -inline CacheSel::iterator find(CacheSel& cache, AstNodeDType* dtypep, DfgVertex* src0p, - uint32_t lsb) { - UASSERT_OBJ(VN_IS(dtypep, BasicDType), dtypep, "non-packed has no 'width()'"); - const uint32_t width = dtypep->width(); - return cache.find({src0p, lsb, width}); +inline CacheSel::iterator find(CacheSel& cache, DfgVertex* src0p, uint32_t lsb, uint32_t size) { + return cache.find({src0p, lsb, size}); } -inline CacheUnary::iterator find(CacheUnary& cache, AstNodeDType*, DfgVertex* src0p) { +inline CacheUnary::iterator find(CacheUnary& cache, DfgVertex* src0p) { return cache.find({src0p}); } -inline CacheBinary::iterator find(CacheBinary& cache, AstNodeDType*, DfgVertex* src0p, - DfgVertex* src1p) { +inline CacheBinary::iterator find(CacheBinary& cache, DfgVertex* src0p, DfgVertex* src1p) { return cache.find({src0p, src1p}); } -inline CacheTernary::iterator find(CacheTernary& cache, AstNodeDType*, DfgVertex* src0p, - DfgVertex* src1p, DfgVertex* src2p) { +inline CacheTernary::iterator find(CacheTernary& cache, DfgVertex* src0p, DfgVertex* src1p, + DfgVertex* src2p) { return cache.find({src0p, src1p, src2p}); } @@ -247,11 +242,11 @@ inline void setOperands(DfgVertexTernary* vtxp, DfgVertex* src0p, DfgVertex* src // Get or create (and insert) vertex with given operands template -inline Vertex* getOrCreate(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep, T_Cache& cache, +inline Vertex* getOrCreate(DfgGraph& dfg, FileLine* flp, T_Cache& cache, const DfgDataType& dtype, Operands... operands) { - typename T_Cache::mapped_type& entrypr = getEntry(cache, dtypep, operands...); + typename T_Cache::mapped_type& entrypr = getEntry(cache, dtype, operands...); if (!entrypr) { - Vertex* const newp = new Vertex{dfg, flp, dtypep}; + Vertex* const newp = new Vertex{dfg, flp, dtype}; setOperands(newp, operands...); entrypr = newp; } @@ -260,44 +255,44 @@ inline Vertex* getOrCreate(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep, T // These add an existing vertex to the table, if an equivalent does not yet exist inline void cache(CacheSel& cache, DfgSel* vtxp) { - DfgSel*& entrypr = getEntry(cache, vtxp->dtypep(), vtxp->fromp(), vtxp->lsb()); + DfgSel*& entrypr = getEntry(cache, vtxp->dtype(), vtxp->fromp(), vtxp->lsb()); if (!entrypr) entrypr = vtxp; } inline void cache(CacheUnary& cache, DfgVertexUnary* vtxp) { - DfgVertexUnary*& entrypr = getEntry(cache, vtxp->dtypep(), vtxp->inputp(0)); + DfgVertexUnary*& entrypr = getEntry(cache, vtxp->dtype(), vtxp->inputp(0)); if (!entrypr) entrypr = vtxp; } inline void cache(CacheBinary& cache, DfgVertexBinary* vtxp) { - DfgVertexBinary*& entrypr = getEntry(cache, vtxp->dtypep(), vtxp->inputp(0), vtxp->inputp(1)); + DfgVertexBinary*& entrypr = getEntry(cache, vtxp->dtype(), vtxp->inputp(0), vtxp->inputp(1)); if (!entrypr) entrypr = vtxp; } inline void cache(CacheTernary& cache, DfgVertexTernary* vtxp) { DfgVertexTernary*& entrypr - = getEntry(cache, vtxp->dtypep(), vtxp->inputp(0), vtxp->inputp(1), vtxp->inputp(2)); + = getEntry(cache, vtxp->dtype(), vtxp->inputp(0), vtxp->inputp(1), vtxp->inputp(2)); if (!entrypr) entrypr = vtxp; } // These remove an existing vertex from the cache, if it is the cached vertex inline void invalidateByValue(CacheSel& cache, const DfgSel* vtxp) { - const auto it = find(cache, vtxp->dtypep(), vtxp->fromp(), vtxp->lsb()); + const auto it = find(cache, vtxp->fromp(), vtxp->lsb(), vtxp->size()); if (it != cache.end() && it->second == vtxp) cache.erase(it); } inline void invalidateByValue(CacheUnary& cache, const DfgVertexUnary* vtxp) { - const auto it = find(cache, vtxp->dtypep(), vtxp->inputp(0)); + const auto it = find(cache, vtxp->inputp(0)); if (it != cache.end() && it->second == vtxp) cache.erase(it); } inline void invalidateByValue(CacheBinary& cache, const DfgVertexBinary* vtxp) { - const auto it = find(cache, vtxp->dtypep(), vtxp->inputp(0), vtxp->inputp(1)); + const auto it = find(cache, vtxp->inputp(0), vtxp->inputp(1)); if (it != cache.end() && it->second == vtxp) cache.erase(it); } inline void invalidateByValue(CacheTernary& cache, const DfgVertexTernary* vtxp) { - const auto it = find(cache, vtxp->dtypep(), vtxp->inputp(0), vtxp->inputp(1), vtxp->inputp(2)); + const auto it = find(cache, vtxp->inputp(0), vtxp->inputp(1), vtxp->inputp(2)); if (it != cache.end() && it->second == vtxp) cache.erase(it); } @@ -355,7 +350,7 @@ public: // Find a vertex of type 'Vertex', with the given operands, or create a new one and add it. template - inline Vertex* getOrCreate(FileLine* flp, AstNodeDType* dtypep, Operands... operands); + inline Vertex* getOrCreate(FileLine* flp, const DfgDataType& dtype, Operands... operands); // Add an existing vertex of the table. If an equivalent already exists, then nothing happens. void cache(DfgVertex* vtxp); @@ -374,7 +369,7 @@ FOREACH_CACHED_VERTEX_TYPE(VERTEX_CACHE_DEFINE_LUT_SPECIALIZATION) // Find a vertex of type 'Vertex', with the given operands, or create a new one and add it template -Vertex* V3DfgCache::getOrCreate(FileLine* flp, AstNodeDType* dtypep, Operands... operands) { +Vertex* V3DfgCache::getOrCreate(FileLine* flp, const DfgDataType& dtype, Operands... operands) { static_assert(std::is_final::value, "Must invoke on final vertex type"); constexpr bool isSel = std::is_same::value; constexpr bool isUnary = !isSel && std::is_base_of::value; @@ -386,14 +381,14 @@ Vertex* V3DfgCache::getOrCreate(FileLine* flp, AstNodeDType* dtypep, Operands... static_assert(!isSel || sizeof...(Operands) == 2, // "Wrong number of operands to DfgSel"); static_assert(!isUnary || sizeof...(Operands) == 1, - "Wrong number of operands to unary vertex"); + "Wrong number of operands to DfgVertexUnary"); static_assert(!isBinary || sizeof...(Operands) == 2, - "Wrong number of operands to binary vertex"); + "Wrong number of operands to DfgVertexBinary"); static_assert(!isTernary || sizeof...(Operands) == 3, - "Wrong number of operands to ternary vertex"); + "Wrong number of operands to DfgVertexTernary"); return V3DfgCacheInternal::getOrCreate, Operands...>( - m_dfg, flp, dtypep, cacheForType(), operands...); + m_dfg, flp, cacheForType(), dtype, operands...); } } // namespace V3DfgCacheInternal diff --git a/src/V3DfgContext.h b/src/V3DfgContext.h index a95be5b48..42cf6e69e 100644 --- a/src/V3DfgContext.h +++ b/src/V3DfgContext.h @@ -226,6 +226,7 @@ public: VDouble0 nonRepDType; // Non representable: unsupported data type VDouble0 nonRepLValue; // Non representable: unsupported LValue form VDouble0 nonRepVarRef; // Non representable: unsupported var reference + VDouble0 nonRepOOBSel; // Non representable: out of bounds select VDouble0 nonRepNode; // Non representable: unsupported AstNode type VDouble0 nonRepUnknown; // Non representable: unhandled AstNode type } m_conv; @@ -272,6 +273,7 @@ private: addStat("conv / non-representable (dtype)", m_conv.nonRepDType); addStat("conv / non-representable (lhs)", m_conv.nonRepLValue); addStat("conv / non-representable (varref)", m_conv.nonRepVarRef); + addStat("conv / non-representable (oobsel)", m_conv.nonRepOOBSel); addStat("conv / non-representable (node)", m_conv.nonRepNode); addStat("conv / non-representable (unknown)", m_conv.nonRepUnknown); VDouble0 nConvNonRep; @@ -279,6 +281,7 @@ private: nConvNonRep += m_conv.nonRepDType; nConvNonRep += m_conv.nonRepLValue; nConvNonRep += m_conv.nonRepVarRef; + nConvNonRep += m_conv.nonRepOOBSel; nConvNonRep += m_conv.nonRepNode; nConvNonRep += m_conv.nonRepUnknown; VDouble0 nConvExpect; diff --git a/src/V3DfgCse.cpp b/src/V3DfgCse.cpp index 76c7e53b5..f1eb3d8db 100644 --- a/src/V3DfgCse.cpp +++ b/src/V3DfgCse.cpp @@ -253,7 +253,7 @@ class V3DfgCse final { if (a.type() != b.type()) return false; // If different data type, then not equal - if (a.dtypep() != b.dtypep()) return false; + if (a.dtype() != b.dtype()) return false; // If different number of inputs, then not equal if (a.nInputs() != b.nInputs()) return false; diff --git a/src/V3DfgDataType.cpp b/src/V3DfgDataType.cpp new file mode 100644 index 000000000..892faa6d3 --- /dev/null +++ b/src/V3DfgDataType.cpp @@ -0,0 +1,225 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Type system used by DFG +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2025 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 +// +//************************************************************************* + +#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT + +#include "V3Dfg.h" +#include "V3DfgPasses.h" + +VL_DEFINE_DEBUG_FUNCTIONS; + +//------------------------------------------------------------------------------ +// DfgDataType + +const DfgDataType* DfgDataType::s_nullTypep{nullptr}; +std::unordered_map DfgDataType::s_packedTypes{}; + +//------------------------------------------------------------------------------ +// Type checker - for internal validation only + +void V3DfgPasses::typeCheck(const DfgGraph& dfg) { + dfg.forEachVertex([&](const DfgVertex& vtx) { +#define CHECK(cond, msg) \ + UASSERT_OBJ(cond, &vtx, \ + "Dfg type error for vertex " << vtx.typeName() << " in " << dfg.name() << ": " \ + << msg); + switch (vtx.type()) { + case VDfgType::Const: { + CHECK(vtx.isPacked(), "Should be Packed type"); + return; + } + case VDfgType::VarArray: + case VDfgType::VarPacked: { + const DfgVertexVar& v = *vtx.as(); + CHECK(!v.defaultp() || v.defaultp()->dtype() == v.dtype(), "'defaultp' should match"); + CHECK(!v.srcp() || v.srcp()->dtype() == v.dtype(), "'srcp' should match"); + return; + } + case VDfgType::SpliceArray: + case VDfgType::SplicePacked: { + const DfgVertexSplice& v = *vtx.as(); + v.foreachDriver([&](const DfgVertex& src, uint32_t lo) { + CHECK(src.dtype() == DfgDataType::select(v.dtype(), lo, src.size()), "driver"); + return false; + }); + return; + } + case VDfgType::Logic: { + CHECK(vtx.dtype().isNull(), "Should be Null type"); + return; + } + case VDfgType::Unresolved: { + CHECK(!vtx.dtype().isNull(), "Should not be Null type"); + return; + } + case VDfgType::UnitArray: { + const DfgUnitArray& v = *vtx.as(); + CHECK(v.isArray(), "Should be Array type"); + CHECK(v.size() == 1, "Should be one element"); + CHECK(v.srcp()->dtype() == v.dtype().elemDtype(), "Input should be the element type"); + return; + } + case VDfgType::Sel: { + const DfgSel& v = *vtx.as(); + CHECK(v.isPacked(), "Should be Packed type"); + CHECK(v.dtype() == DfgDataType::select(v.srcp()->dtype(), v.lsb(), v.size()), "sel"); + return; + } + case VDfgType::Mux: { + const DfgMux& v = *vtx.as(); + CHECK(v.isPacked(), "Should be Packed type"); + CHECK(v.fromp()->isPacked(), "Source operand should be Packed type"); + CHECK(v.fromp()->size() >= v.size(), "Source operand should not be narrower"); + CHECK(v.lsbp()->isPacked(), "Index should be Packed type"); + return; + } + case VDfgType::ArraySel: { + const DfgArraySel& v = *vtx.as(); + CHECK(v.dtype() == v.fromp()->dtype().elemDtype(), "Element type should match"); + CHECK(v.bitp()->isPacked(), "Index should be Packed type"); + return; + } + + case VDfgType::Add: + case VDfgType::And: + case VDfgType::BufIf1: + case VDfgType::Div: + case VDfgType::DivS: + case VDfgType::ModDiv: + case VDfgType::ModDivS: + case VDfgType::Mul: + case VDfgType::MulS: + case VDfgType::Or: + case VDfgType::Sub: + case VDfgType::Xor: { + CHECK(vtx.isPacked(), "Should be Packed type"); + CHECK(vtx.inputp(0)->dtype() == vtx.dtype(), "LHS should be same type"); + CHECK(vtx.inputp(1)->dtype() == vtx.dtype(), "RHS should be same type"); + return; + } + + case VDfgType::Negate: + case VDfgType::Not: { + CHECK(vtx.isPacked(), "Should be Packed type"); + CHECK(vtx.inputp(0)->dtype() == vtx.dtype(), "Input should be same type"); + return; + } + + case VDfgType::ShiftL: + case VDfgType::ShiftR: + case VDfgType::ShiftRS: { + CHECK(vtx.isPacked(), "Should be Packed type"); + CHECK(vtx.inputp(0)->dtype() == vtx.dtype(), "LHS should be same type"); + CHECK(vtx.inputp(1)->isPacked(), "RHS should be Packed type"); + return; + } + + case VDfgType::Concat: { + const DfgConcat& v = *vtx.as(); + CHECK(v.isPacked(), "Should be Packed type"); + CHECK(v.lhsp()->isPacked(), "LHS should be Packed type"); + CHECK(v.rhsp()->isPacked(), "RHS should be Packed type"); + CHECK(v.size() == v.rhsp()->size() + v.lhsp()->size(), "Concat result mismatch"); + return; + } + + case VDfgType::Replicate: { + // TODO: model DfgReplicate without an explicit 'countp' which is always constant + const DfgReplicate& v = *vtx.as(); + CHECK(v.isPacked(), "Should be Packed type"); + CHECK(v.srcp()->isPacked(), "'srcp' should be same type"); + CHECK(v.countp()->isPacked(), "'countp' should be Packed type"); + CHECK(v.size() % v.srcp()->size() == 0, "Not a replicate"); + return; + } + + case VDfgType::StreamL: + case VDfgType::StreamR: { + // TODO: model these without an explicit slice size which is always constant (?) + CHECK(vtx.isPacked(), "Should be Packed type"); + CHECK(vtx.inputp(0)->dtype() == vtx.dtype(), "LHS should be same type"); + CHECK(vtx.inputp(1)->isPacked(), "Slice size should be Packed type"); + return; + } + + case VDfgType::Eq: + case VDfgType::EqCase: + case VDfgType::EqWild: + case VDfgType::Neq: + case VDfgType::NeqCase: + case VDfgType::NeqWild: + case VDfgType::Gt: + case VDfgType::GtS: + case VDfgType::Gte: + case VDfgType::GteS: + case VDfgType::Lt: + case VDfgType::LtS: + case VDfgType::Lte: + case VDfgType::LteS: { + CHECK(vtx.dtype() == DfgDataType::packed(1), "Should be 1-bit"); + CHECK(vtx.inputp(0)->dtype() == vtx.inputp(1)->dtype(), "Sides should match"); + return; + } + + case VDfgType::Extend: + case VDfgType::ExtendS: { + CHECK(vtx.isPacked(), "Should be Packed type"); + CHECK(vtx.inputp(0)->isPacked(), "Operand should be same type"); + CHECK(vtx.inputp(0)->size() < vtx.size(), "Operand should be narrower"); + return; + } + + case VDfgType::LogAnd: + case VDfgType::LogEq: + case VDfgType::LogIf: + case VDfgType::LogOr: { + CHECK(vtx.dtype() == DfgDataType::packed(1), "Should be 1-bit"); + CHECK(vtx.inputp(0)->isPacked(), "LHS should be Packed type"); + CHECK(vtx.inputp(1)->isPacked(), "RHS should be Packed type"); + return; + } + + case VDfgType::LogNot: + case VDfgType::RedAnd: + case VDfgType::RedOr: + case VDfgType::RedXor: { + CHECK(vtx.dtype() == DfgDataType::packed(1), "Should be 1-bit"); + CHECK(vtx.inputp(0)->isPacked(), "Operand should be Packed type"); + return; + } + + case VDfgType::Cond: { + const DfgCond& v = *vtx.as(); + CHECK(v.isPacked(), "Should be Packed type"); + CHECK(v.condp()->isPacked(), "Condition should be Packed type"); + CHECK(v.thenp()->dtype() == v.dtype(), "Then should be same type"); + CHECK(v.elsep()->dtype() == v.dtype(), "Else should be same type"); + return; + } + + case VDfgType::Pow: + case VDfgType::PowSS: + case VDfgType::PowSU: + case VDfgType::PowUS: { + CHECK(vtx.isPacked(), "Should be Packed type"); + CHECK(vtx.inputp(0)->dtype() == vtx.dtype(), "LHS should be same type"); + CHECK(vtx.inputp(1)->isPacked(), "RHS should be Packed type"); + return; + } + } +#undef CHECK + }); +} diff --git a/src/V3DfgDataType.h b/src/V3DfgDataType.h new file mode 100644 index 000000000..450795f3f --- /dev/null +++ b/src/V3DfgDataType.h @@ -0,0 +1,233 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Type system used by DFG +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2025 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 +// +//************************************************************************* +// +// DFG uses a restriced and simplified type system compared to Ast. Each +// DfgVertex has a type, describing the type of the value it represents. +// The DFG types are represented by an instance of DfgDataType defined below. +// +// The type can be one of +// - Null: The vertex doesn't actually represent a value directly +// - Packed: All bit-vector like types, including all packed construct +// and binary encoded numbers. Packed types are always 1-dimensional +// with no sub-type. E.g.: a packed array of N copies of M-wide elements +// is simply represented as a Packed type of size N*M. +// - Array: An unpacked array of elements with the same type. +// +// Each type has a size: +// - Null: 0, though this is largely irrelevant +// - Packed: number of bits in the packed value (minimum 1) +// - Array: number of elements in the arrray +// +// The indexing of Packed and Array are both zero based and 'descending' in +// the Systemverilog sense (index 0 is the LSB of a Packed, index 0 is at the +// lowest memory address for Array). +// +// All types are 'interned', that is, there can only be one instance of +// DfgDataType which represents that type. This means two DfgDataType are +// equal if and only if they are the same DfgDataType instance. +// +//************************************************************************* + +#ifndef VERILATOR_V3DFGDATATYPE_H_ +#define VERILATOR_V3DFGDATATYPE_H_ + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Ast.h" +#include "V3Error.h" +#include "V3Global.h" + +#include +#include + +class DfgDataType final { + enum class Kind : uint8_t { + Packed, + Array, + // Tuple - to model unpacked structs in the future + Null // No type (like 'void', but that's a C++ keyword) + }; + + // STATE + const Kind m_kind; // The type category + uint32_t m_size; // The number of elements in this type + AstNodeDType* const m_astDtypep; // Equivalent canonical AstNodeDType + const DfgDataType* const m_elemDtypep; // Type of elements - for arrays only + // Static singleton Null type + static const DfgDataType* s_nullTypep; + // Static map from 'width' -> 'interned Packed DfgDataType with that width' + static std::unordered_map s_packedTypes; + // Map from 'elements' -> 'interned Array DfgDataType with that many elements of *this* type' + mutable std::unordered_map m_arrayTypes; + + // METHODS + static AstNodeDType* canonicalPackedDType(uint32_t width) { + return v3Global.rootp()->typeTablep()->findLogicDType(width, width, VSigning::UNSIGNED); + } + static AstNodeDType* canonicalArrayDType(uint32_t size, const DfgDataType& elemType) { + AstNodeDType* const elemDTypep = elemType.m_astDtypep; + FileLine* const flp = elemDTypep->fileline(); + AstRange* const rangep = new AstRange{flp, static_cast(size - 1), 0}; + AstNodeDType* const dtypep = new AstUnpackArrayDType{flp, elemDTypep, rangep}; + v3Global.rootp()->typeTablep()->addTypesp(dtypep); + return dtypep; + } + + // CONSTRUCTOR - use 'fromAst' instead + DfgDataType() + : m_kind{Kind::Null} + , m_size{0} + , m_astDtypep{v3Global.rootp()->findVoidDType()} + , m_elemDtypep{nullptr} {} + explicit DfgDataType(uint32_t size) + : m_kind{Kind::Packed} + , m_size{size} + , m_astDtypep{canonicalPackedDType(size)} + , m_elemDtypep{nullptr} {} + DfgDataType(uint32_t size, const DfgDataType& elemType) + : m_kind{Kind::Array} + , m_size{size} + , m_astDtypep{canonicalArrayDType(size, elemType)} + , m_elemDtypep{&elemType} {} + + VL_UNCOPYABLE(DfgDataType); + VL_UNMOVABLE(DfgDataType); + ~DfgDataType() { + for (const auto& pair : m_arrayTypes) VL_DO_DANGLING(delete pair.second, pair.second); + } + +public: + //----------------------------------------------------------------------- + // Properties + + bool isNull() const { return m_kind == Kind::Null; } + bool isPacked() const { return m_kind == Kind::Packed; } + bool isArray() const { return m_kind == Kind::Array; } + // Size of type (this is 'width' for Ppacked, 'elements' for Array, 0 for Null) + uint32_t size() const { return m_size; } + AstNodeDType* astDtypep() const { return m_astDtypep; } + + // Thanks to the interning, equality is identity + bool operator==(const DfgDataType& that) const { return this == &that; } + bool operator!=(const DfgDataType& that) const { return this != &that; } + + // Type of elements, for arrays only + const DfgDataType& elemDtype() const { + UASSERT(isArray(), "Non-array has no 'elemDType'"); + return *m_elemDtypep; + } + + //----------------------------------------------------------------------- + // Static factory and management functions + + // Returns a Packed type of the given width + static const DfgDataType& packed(uint32_t width) { + // Find or create the right sized packed type + const auto pair = s_packedTypes.emplace(width, nullptr); + if (pair.second) pair.first->second = new DfgDataType{width}; + return *pair.first->second; + } + + // Returns an Array type of the given size with the given elements + static const DfgDataType& array(const DfgDataType& elemType, uint32_t size) { + UASSERT(elemType.isPacked(), "Cannot create multi-dimensional arrays yet"); + // Find or create the right sized array type with this as elements + const auto pair = elemType.m_arrayTypes.emplace(size, nullptr); + if (pair.second) pair.first->second = new DfgDataType{size, elemType}; + return *pair.first->second; + } + + // Returns the singleton Null type + static const DfgDataType& null() { + if (!s_nullTypep) s_nullTypep = new DfgDataType{}; + return *s_nullTypep; + } + + // Returns the data type of selecting the range [lo + size - 1 : lo] from this type + static const DfgDataType& select(const DfgDataType& dtype, uint32_t lo, uint32_t size) { + switch (dtype.m_kind) { + case Kind::Packed: { + UASSERT(lo + size - 1 < dtype.size(), "Out of range"); + return DfgDataType::packed(size); + } + case Kind::Array: { + UASSERT(lo + size - 1 < dtype.size(), "Out of range"); + return DfgDataType::array(dtype.elemDtype(), size); + } + case Kind::Null: { + UASSERT(false, "Type cannot be selected from"); + } + } + VL_UNREACHABLE; + } + + // Construct a DfgDataType that represents the given AstNodeDType. + // Returns nullptr if AstNodeDType is not representable by DfgDataType. + static const DfgDataType* fromAst(const AstNodeDType* dtypep) { + dtypep = dtypep->skipRefp(); + + if (const AstUnpackArrayDType* const typep = VN_CAST(dtypep, UnpackArrayDType)) { + // Convert the element type + const DfgDataType* const elemp = fromAst(typep->subDTypep()); + // If element type is not supported, we cannot handle the array either + if (!elemp) return nullptr; + // Currently restricted to 1-dimensional arrays, just assumptions in the code + if (elemp->isArray()) return nullptr; + // Unpacked array maps to Array + return &array(*elemp, typep->elementsConst()); + } + + if (const AstPackArrayDType* const typep = VN_CAST(dtypep, PackArrayDType)) { + // Packed array maps to Packed + return &packed(typep->width()); + } + + if (const AstStructDType* const typep = VN_CAST(dtypep, StructDType)) { + // Unpacked structs currently not supported + if (!typep->packed()) return nullptr; + // Packed struct maps to Packed + return &packed(typep->width()); + } + + if (const AstUnionDType* const typep = VN_CAST(dtypep, UnionDType)) { + // Unpacked unions not supported + if (!typep->packed()) return nullptr; + // Packed union maps to Packed + return &packed(typep->width()); + } + + if (const AstBasicDType* const typep = VN_CAST(dtypep, BasicDType)) { + // Anything not resembling a binary encoded number is not supported + if (!typep->keyword().isIntNumeric()) return nullptr; + // Basic numeric types map to Packed + return &packed(typep->width()); + } + + // Anything else is not representable + return nullptr; + } + + // Reset interned types + static void reset() { + for (const auto& pair : s_packedTypes) VL_DO_DANGLING(delete pair.second, pair.second); + s_packedTypes.clear(); + delete s_nullTypep; + s_nullTypep = nullptr; + } +}; + +#endif diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp index 63d1f3c14..bd76071ec 100644 --- a/src/V3DfgDfgToAst.cpp +++ b/src/V3DfgDfgToAst.cpp @@ -257,8 +257,9 @@ class DfgToAstVisitor final : DfgVisitor { DfgToAstVisitor(DfgGraph& dfg, V3DfgDfgToAstContext& ctx) : m_modp{dfg.modulep()} , m_ctx{ctx} { - // Convert the graph back to combinational assignments + if (v3Global.opt.debugCheck()) V3DfgPasses::typeCheck(dfg); + // Convert the graph back to combinational assignments // The graph must have been regularized, so we only need to render assignments for (DfgVertexVar& vtx : dfg.varVertices()) { // If there is no driver (this vertex is an input to the graph), then nothing to do. diff --git a/src/V3DfgOptimizer.cpp b/src/V3DfgOptimizer.cpp index e435775b0..c6e1f9173 100644 --- a/src/V3DfgOptimizer.cpp +++ b/src/V3DfgOptimizer.cpp @@ -366,6 +366,9 @@ class DataflowOptimize final { // Convert back to Ast V3DfgPasses::dfgToAst(*dfgp, m_ctx); } + + // Reset interned types so the corresponding Ast types can be garbage collected + DfgDataType::reset(); } public: diff --git a/src/V3DfgPasses.cpp b/src/V3DfgPasses.cpp index bbdfe6468..bb755d235 100644 --- a/src/V3DfgPasses.cpp +++ b/src/V3DfgPasses.cpp @@ -219,11 +219,9 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { FileLine* const flp = srcp->fileline(); // Required data types - AstNodeDType* const idxDTypep = srcp->dtypep(); - AstNodeDType* const bitDTypep = V3Dfg::dtypePacked(1); - AstUnpackArrayDType* const tabDTypep = new AstUnpackArrayDType{ - flp, bitDTypep, new AstRange{flp, static_cast(nBits - 1), 0}}; - v3Global.rootp()->typeTablep()->addTypesp(tabDTypep); + const DfgDataType& idxDType = srcp->dtype(); + const DfgDataType& bitDType = DfgDataType::packed(1); + const DfgDataType& tabDType = DfgDataType::array(bitDType, nBits); // The index variable AstVar* const idxVarp = [&]() { @@ -233,7 +231,7 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { varp = vp->as(); } else { const std::string name = dfg.makeUniqueName("BinToOneHot_Idx", nTables); - varp = dfg.makeNewVar(flp, name, idxDTypep, nullptr)->as(); + varp = dfg.makeNewVar(flp, name, idxDType, nullptr)->as(); varp->varp()->isInternal(true); varp->srcp(srcp); } @@ -243,7 +241,7 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { // The previous index variable - we don't need a vertex for this AstVar* const preVarp = [&]() { const std::string name = dfg.makeUniqueName("BinToOneHot_Pre", nTables); - AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, idxDTypep}; + AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, idxDType.astDtypep()}; dfg.modulep()->addStmtsp(varp); varp->isInternal(true); varp->noReset(true); @@ -254,7 +252,7 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { DfgVarArray* const tabVtxp = [&]() { const std::string name = dfg.makeUniqueName("BinToOneHot_Tab", nTables); DfgVarArray* const varp - = dfg.makeNewVar(flp, name, tabDTypep, nullptr)->as(); + = dfg.makeNewVar(flp, name, tabDType, nullptr)->as(); varp->varp()->isInternal(true); varp->varp()->noReset(true); varp->setHasModWrRefs(); @@ -310,7 +308,7 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { const std::vector& terms = pair.second; // Create the ArraySel FileLine* const aflp = terms.front().m_vtxp->fileline(); - DfgArraySel* const aselp = new DfgArraySel{dfg, aflp, bitDTypep}; + DfgArraySel* const aselp = new DfgArraySel{dfg, aflp, bitDType}; aselp->fromp(tabVtxp); aselp->bitp(new DfgConst{dfg, aflp, width, val}); // The inverted value, if needed @@ -319,7 +317,7 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) { for (const Term& term : terms) { if (term.m_inv) { if (!notp) { - notp = new DfgNot{dfg, aflp, bitDTypep}; + notp = new DfgNot{dfg, aflp, bitDType}; notp->srcp(aselp); } term.m_vtxp->replaceWith(notp); @@ -448,6 +446,7 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgContext& ctx) { = ctx.prefix() + "pass-" + cvtToStr(passNumber) + "-" + strippedName; dfg.dumpDotFilePrefixed(label); } + if (v3Global.opt.debugCheck()) V3DfgPasses::typeCheck(dfg); ++passNumber; }; diff --git a/src/V3DfgPasses.h b/src/V3DfgPasses.h index e6c211b5e..df672301d 100644 --- a/src/V3DfgPasses.h +++ b/src/V3DfgPasses.h @@ -84,6 +84,8 @@ void regularize(DfgGraph&, V3DfgRegularizeContext&) VL_MT_DISABLED; void removeUnused(DfgGraph&) VL_MT_DISABLED; // Eliminate (remove or replace) redundant variables. Also removes resulting unused logic. void eliminateVars(DfgGraph&, V3DfgEliminateVarsContext&) VL_MT_DISABLED; +// Check all types are consistent. This will not return if there is a type error. +void typeCheck(const DfgGraph&) VL_MT_DISABLED; } // namespace V3DfgPasses diff --git a/src/V3DfgPatternStats.h b/src/V3DfgPatternStats.h index 666c5bcb6..0875c9e97 100644 --- a/src/V3DfgPatternStats.h +++ b/src/V3DfgPatternStats.h @@ -132,11 +132,10 @@ class V3DfgPatternStats final { // Annotate type ss << ':'; - const AstNodeDType* const dtypep = vtx.dtypep(); - if (!VN_IS(dtypep, BasicDType)) { - dtypep->dumpSmall(ss); + if (!vtx.dtype().isPacked()) { + vtx.dtype().astDtypep()->dumpSmall(ss); } else { - const uint32_t width = dtypep->width(); + const uint32_t width = vtx.size(); if (width == 1) { ss << '1'; } else if (width <= VL_QUADSIZE) { diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp index 88883e28e..40f301116 100644 --- a/src/V3DfgPeephole.cpp +++ b/src/V3DfgPeephole.cpp @@ -131,7 +131,7 @@ class V3DfgPeephole final : public DfgVisitor { // STATE DfgGraph& m_dfg; // The DfgGraph being visited V3DfgPeepholeContext& m_ctx; // The config structure - AstNodeDType* const m_bitDType = V3Dfg::dtypePacked(1); // Common, so grab it up front + const DfgDataType& m_bitDType = DfgDataType::packed(1); // Common, so grab it up front // This is a worklist based algorithm DfgWorklist m_workList{m_dfg}; @@ -185,10 +185,6 @@ class V3DfgPeephole final : public DfgVisitor { } void replace(DfgVertex* vtxp, DfgVertex* replacementp) { - UASSERT_OBJ(vtxp != replacementp, vtxp, - "Should not try to replace with a vertex with itself"); - UASSERT_OBJ(vtxp->width() == replacementp->width(), vtxp, - "Replacement vertex has different width"); // Add sinks of replaced vertex to the work list addSinksToWorkList(vtxp); // Add replacement to the work list @@ -207,9 +203,6 @@ class V3DfgPeephole final : public DfgVisitor { deleteVertex(vtxp); } - // Shorthand - static AstNodeDType* dtypePacked(uint32_t width) { return V3Dfg::dtypePacked(width); } - // Create a 32-bit DfgConst vertex DfgConst* makeI32(FileLine* flp, uint32_t val) { return new DfgConst{m_dfg, flp, 32, val}; } @@ -220,9 +213,9 @@ class V3DfgPeephole final : public DfgVisitor { // Create a new vertex of the given type template - Vertex* make(FileLine* flp, AstNodeDType* dtypep, Operands... operands) { + Vertex* make(FileLine* flp, const DfgDataType& dtype, Operands... operands) { // Find or create an equivalent vertex - Vertex* const vtxp = m_cache.getOrCreate(flp, dtypep, operands...); + Vertex* const vtxp = m_cache.getOrCreate(flp, dtype, operands...); // Add to work list addToWorkList(vtxp); // Return new node @@ -232,7 +225,7 @@ class V3DfgPeephole final : public DfgVisitor { // Same as above, but 'flp' and 'dtypep' are taken from the given example vertex template Vertex* make(const DfgVertex* examplep, Operands... operands) { - return make(examplep->fileline(), examplep->dtypep(), operands...); + return make(examplep->fileline(), examplep->dtype(), operands...); } // Check two vertex are the same, or the same constant value @@ -369,16 +362,14 @@ class V3DfgPeephole final : public DfgVisitor { DfgVertex* const bp = alhsp->rhsp(); DfgVertex* const cp = vtxp->rhsp(); - AstNodeDType* const rootDtyptp = vtxp->dtypep(); - AstNodeDType* childDtyptp = vtxp->dtypep(); - // Concatenation dtypes need to be fixed up, other associative nodes preserve - // types - if VL_CONSTEXPR_CXX17 (std::is_same::value) { - childDtyptp = dtypePacked(bp->width() + cp->width()); - } + // Concatenation dtypes need to be fixed up, other associative nodes preserve types + const DfgDataType& childDType + = std::is_same::value + ? DfgDataType::packed(bp->width() + cp->width()) + : vtxp->dtype(); - Vertex* const childp = make(vtxp->fileline(), childDtyptp, bp, cp); - Vertex* const rootp = make(alhsp->fileline(), rootDtyptp, ap, childp); + Vertex* const childp = make(vtxp->fileline(), childDType, bp, cp); + Vertex* const rootp = make(alhsp->fileline(), vtxp->dtype(), ap, childp); replace(vtxp, rootp); changed = true; vtxp = rootp; @@ -484,31 +475,28 @@ class V3DfgPeephole final : public DfgVisitor { template VL_ATTR_WARN_UNUSED_RESULT bool tryPushBitwiseOpThroughConcat(Vertex* vtxp, DfgConst* constp, DfgConcat* concatp) { - UASSERT_OBJ(constp->dtypep() == concatp->dtypep(), vtxp, "Mismatched widths"); - FileLine* const flp = vtxp->fileline(); // If at least one of the sides of the Concat constant, or width 1 (i.e.: can be // further simplified), then push the Vertex past the Concat if (concatp->lhsp()->is() || concatp->rhsp()->is() // - || concatp->lhsp()->dtypep() == m_bitDType - || concatp->rhsp()->dtypep() == m_bitDType) { + || concatp->lhsp()->dtype() == m_bitDType || concatp->rhsp()->dtype() == m_bitDType) { APPLYING(PUSH_BITWISE_OP_THROUGH_CONCAT) { const uint32_t width = concatp->width(); - AstNodeDType* const lDtypep = concatp->lhsp()->dtypep(); - AstNodeDType* const rDtypep = concatp->rhsp()->dtypep(); - const uint32_t lWidth = lDtypep->width(); - const uint32_t rWidth = rDtypep->width(); + const DfgDataType& lDtype = concatp->lhsp()->dtype(); + const DfgDataType& rDtype = concatp->rhsp()->dtype(); + const uint32_t lWidth = lDtype.size(); + const uint32_t rWidth = rDtype.size(); // The new Lhs vertex DfgConst* const newLhsConstp = makeZero(constp->fileline(), lWidth); newLhsConstp->num().opSel(constp->num(), width - 1, rWidth); - Vertex* const newLhsp = make(flp, lDtypep, newLhsConstp, concatp->lhsp()); + Vertex* const newLhsp = make(flp, lDtype, newLhsConstp, concatp->lhsp()); // The new Rhs vertex DfgConst* const newRhsConstp = makeZero(constp->fileline(), rWidth); newRhsConstp->num().opSel(constp->num(), rWidth - 1, 0); - Vertex* const newRhsp = make(flp, rDtypep, newRhsConstp, concatp->rhsp()); + Vertex* const newRhsp = make(flp, rDtype, newRhsConstp, concatp->rhsp()); // The replacement Concat vertex DfgConcat* const newConcat = make(concatp, newLhsp, newRhsp); @@ -524,8 +512,6 @@ class V3DfgPeephole final : public DfgVisitor { template VL_ATTR_WARN_UNUSED_RESULT bool tryPushCompareOpThroughConcat(Vertex* vtxp, DfgConst* constp, DfgConcat* concatp) { - UASSERT_OBJ(constp->dtypep() == concatp->dtypep(), vtxp, "Mismatched widths"); - FileLine* const flp = vtxp->fileline(); // If at least one of the sides of the Concat is constant, then push the Vertex past @@ -573,11 +559,11 @@ class V3DfgPeephole final : public DfgVisitor { if (Reduction* const rRedp = vtxp->rhsp()->template cast()) { DfgVertex* const lSrcp = lRedp->srcp(); DfgVertex* const rSrcp = rRedp->srcp(); - if (lSrcp->dtypep() == rSrcp->dtypep() && lSrcp->width() <= 64 + if (lSrcp->dtype() == rSrcp->dtype() && lSrcp->width() <= 64 && !lSrcp->hasMultipleSinks() && !rSrcp->hasMultipleSinks()) { APPLYING(PUSH_BITWISE_THROUGH_REDUCTION) { FileLine* const flp = vtxp->fileline(); - Bitwise* const bwp = make(flp, lSrcp->dtypep(), lSrcp, rSrcp); + Bitwise* const bwp = make(flp, lSrcp->dtype(), lSrcp, rSrcp); Reduction* const redp = make(flp, m_bitDType, bwp); replace(vtxp, redp); return true; @@ -599,7 +585,7 @@ class V3DfgPeephole final : public DfgVisitor { FileLine* const flp = vtxp->fileline(); // Reduction of 1-bit value - if (srcp->dtypep() == m_bitDType) { + if (srcp->dtype() == m_bitDType) { APPLYING(REMOVE_WIDTH_ONE_REDUCTION) { replace(vtxp, srcp); return true; @@ -671,8 +657,6 @@ class V3DfgPeephole final : public DfgVisitor { //========================================================================= void visit(DfgExtend* vtxp) override { - UASSERT_OBJ(vtxp->width() > vtxp->srcp()->width(), vtxp, "Invalid zero extend"); - if (foldUnary(vtxp)) return; // Convert all Extend into Concat with zeros. This simplifies other patterns as they @@ -689,26 +673,18 @@ class V3DfgPeephole final : public DfgVisitor { } void visit(DfgExtendS* vtxp) override { - UASSERT_OBJ(vtxp->width() > vtxp->srcp()->width(), vtxp, "Invalid sign extend"); - if (foldUnary(vtxp)) return; } void visit(DfgLogNot* vtxp) override { - UASSERT_OBJ(vtxp->dtypep() == m_bitDType, vtxp, "Incorrect width"); - if (foldUnary(vtxp)) return; } void visit(DfgNegate* vtxp) override { - UASSERT_OBJ(vtxp->dtypep() == vtxp->srcp()->dtypep(), vtxp, "Mismatched width"); - if (foldUnary(vtxp)) return; } void visit(DfgNot* vtxp) override { - UASSERT_OBJ(vtxp->dtypep() == vtxp->srcp()->dtypep(), vtxp, "Mismatched width"); - if (foldUnary(vtxp)) return; // Not of Cond @@ -723,7 +699,7 @@ class V3DfgPeephole final : public DfgVisitor { DfgNot* const newElsep = make(vtxp, condp->elsep()); // The replacement Cond vertex - DfgCond* const newCondp = make(condp->fileline(), vtxp->dtypep(), + DfgCond* const newCondp = make(condp->fileline(), vtxp->dtype(), condp->condp(), newThenp, newElsep); // Replace this vertex @@ -735,7 +711,6 @@ class V3DfgPeephole final : public DfgVisitor { // Not of Not if (DfgNot* const notp = vtxp->srcp()->cast()) { - UASSERT_OBJ(vtxp->dtypep() == notp->srcp()->dtypep(), vtxp, "Width mismatch"); APPLYING(REMOVE_NOT_NOT) { replace(vtxp, notp->srcp()); return; @@ -747,7 +722,7 @@ class V3DfgPeephole final : public DfgVisitor { if (DfgEq* const eqp = vtxp->srcp()->cast()) { APPLYING(REPLACE_NOT_EQ) { DfgNeq* const replacementp - = make(eqp->fileline(), vtxp->dtypep(), eqp->lhsp(), eqp->rhsp()); + = make(eqp->fileline(), vtxp->dtype(), eqp->lhsp(), eqp->rhsp()); replace(vtxp, replacementp); return; } @@ -756,8 +731,8 @@ class V3DfgPeephole final : public DfgVisitor { // Not of Neq if (DfgNeq* const neqp = vtxp->srcp()->cast()) { APPLYING(REPLACE_NOT_NEQ) { - DfgEq* const replacementp = make(neqp->fileline(), vtxp->dtypep(), - neqp->lhsp(), neqp->rhsp()); + DfgEq* const replacementp + = make(neqp->fileline(), vtxp->dtype(), neqp->lhsp(), neqp->rhsp()); replace(vtxp, replacementp); return; } @@ -829,14 +804,16 @@ class V3DfgPeephole final : public DfgVisitor { const uint32_t lSelWidth = width - rSelWidth; // The new Lhs vertex - DfgSel* const newLhsp = make(flp, dtypePacked(lSelWidth), lhsp, 0U); + DfgSel* const newLhsp + = make(flp, DfgDataType::packed(lSelWidth), lhsp, 0U); // The new Rhs vertex - DfgSel* const newRhsp = make(flp, dtypePacked(rSelWidth), rhsp, lsb); + DfgSel* const newRhsp + = make(flp, DfgDataType::packed(rSelWidth), rhsp, lsb); // The replacement Concat vertex DfgConcat* const newConcat - = make(concatp->fileline(), vtxp->dtypep(), newLhsp, newRhsp); + = make(concatp->fileline(), vtxp->dtype(), newLhsp, newRhsp); // Replace this vertex replace(vtxp, newConcat); @@ -864,13 +841,12 @@ class V3DfgPeephole final : public DfgVisitor { if (DfgNot* const notp = fromp->cast()) { // Replace "Sel from Not" with "Not of Sel" if (!notp->hasMultipleSinks()) { - UASSERT_OBJ(notp->srcp()->dtypep() == notp->dtypep(), notp, "Mismatched widths"); APPLYING(PUSH_SEL_THROUGH_NOT) { // Make Sel select from source of Not DfgSel* const newSelp = make(vtxp, notp->srcp(), vtxp->lsb()); // Add Not after Sel DfgNot* const replacementp - = make(notp->fileline(), vtxp->dtypep(), newSelp); + = make(notp->fileline(), vtxp->dtype(), newSelp); replace(vtxp, replacementp); } } @@ -898,7 +874,7 @@ class V3DfgPeephole final : public DfgVisitor { DfgSel* const newElsep = make(vtxp, condp->elsep(), lsb); // The replacement Cond vertex - DfgCond* const newCondp = make(condp->fileline(), vtxp->dtypep(), + DfgCond* const newCondp = make(condp->fileline(), vtxp->dtype(), condp->condp(), newThenp, newElsep); // Replace this vertex @@ -916,7 +892,7 @@ class V3DfgPeephole final : public DfgVisitor { APPLYING(PUSH_SEL_THROUGH_SHIFTL) { DfgSel* const newSelp = make(vtxp, shiftLp->lhsp(), vtxp->lsb()); DfgShiftL* const replacementp = make( - shiftLp->fileline(), vtxp->dtypep(), newSelp, shiftLp->rhsp()); + shiftLp->fileline(), vtxp->dtype(), newSelp, shiftLp->rhsp()); replace(vtxp, replacementp); } } @@ -961,10 +937,7 @@ class V3DfgPeephole final : public DfgVisitor { DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); - UASSERT_OBJ(vtxp->dtypep() == lhsp->dtypep(), vtxp, "Mismatched LHS width"); - UASSERT_OBJ(vtxp->dtypep() == rhsp->dtypep(), vtxp, "Mismatched RHS width"); - - if (lhsp == rhsp) { + if (isSame(lhsp, rhsp)) { APPLYING(REMOVE_AND_WITH_SELF) { replace(vtxp, lhsp); return; @@ -1051,10 +1024,7 @@ class V3DfgPeephole final : public DfgVisitor { DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); - UASSERT_OBJ(vtxp->dtypep() == lhsp->dtypep(), vtxp, "Mismatched LHS width"); - UASSERT_OBJ(vtxp->dtypep() == rhsp->dtypep(), vtxp, "Mismatched RHS width"); - - if (lhsp == rhsp) { + if (isSame(lhsp, rhsp)) { APPLYING(REMOVE_OR_WITH_SELF) { replace(vtxp, lhsp); return; @@ -1092,7 +1062,7 @@ class V3DfgPeephole final : public DfgVisitor { if (DfgConcat* const lhsConcatp = lhsp->cast()) { if (DfgConcat* const rhsConcatp = rhsp->cast()) { - if (lhsConcatp->lhsp()->dtypep() == rhsConcatp->lhsp()->dtypep()) { + if (lhsConcatp->lhsp()->dtype() == rhsConcatp->lhsp()->dtype()) { if (isZero(lhsConcatp->lhsp()) && isZero(rhsConcatp->rhsp())) { APPLYING(REPLACE_OR_OF_CONCAT_ZERO_LHS_AND_CONCAT_RHS_ZERO) { DfgConcat* const replacementp @@ -1166,10 +1136,7 @@ class V3DfgPeephole final : public DfgVisitor { DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); - UASSERT_OBJ(vtxp->dtypep() == lhsp->dtypep(), vtxp, "Mismatched LHS width"); - UASSERT_OBJ(vtxp->dtypep() == rhsp->dtypep(), vtxp, "Mismatched RHS width"); - - if (lhsp == rhsp) { + if (isSame(lhsp, rhsp)) { APPLYING(REPLACE_XOR_WITH_SELF) { DfgConst* const replacementp = makeZero(vtxp->fileline(), vtxp->width()); replace(vtxp, replacementp); @@ -1209,9 +1176,6 @@ class V3DfgPeephole final : public DfgVisitor { //========================================================================= void visit(DfgAdd* vtxp) override { - UASSERT_OBJ(vtxp->dtypep() == vtxp->lhsp()->dtypep(), vtxp, "Mismatched LHS width"); - UASSERT_OBJ(vtxp->dtypep() == vtxp->rhsp()->dtypep(), vtxp, "Mismatched RHS width"); - if (associativeBinary(vtxp)) return; if (commutativeBinary(vtxp)) return; @@ -1258,9 +1222,6 @@ class V3DfgPeephole final : public DfgVisitor { } void visit(DfgConcat* vtxp) override { - UASSERT_OBJ(vtxp->width() == vtxp->lhsp()->width() + vtxp->rhsp()->width(), vtxp, - "Inconsistent Concat"); - if (associativeBinary(vtxp)) return; DfgVertex* const lhsp = vtxp->lhsp(); @@ -1271,8 +1232,7 @@ class V3DfgPeephole final : public DfgVisitor { if (isZero(lhsp)) { DfgConst* const lConstp = lhsp->as(); if (DfgSel* const rSelp = rhsp->cast()) { - if (vtxp->dtypep() == rSelp->fromp()->dtypep() - && rSelp->lsb() == lConstp->width()) { + if (vtxp->dtype() == rSelp->fromp()->dtype() && rSelp->lsb() == lConstp->width()) { APPLYING(REPLACE_CONCAT_ZERO_AND_SEL_TOP_WITH_SHIFTR) { DfgShiftR* const replacementp = make( vtxp, rSelp->fromp(), makeI32(flp, lConstp->width())); @@ -1286,7 +1246,7 @@ class V3DfgPeephole final : public DfgVisitor { if (isZero(rhsp)) { DfgConst* const rConstp = rhsp->as(); if (DfgSel* const lSelp = lhsp->cast()) { - if (vtxp->dtypep() == lSelp->fromp()->dtypep() && lSelp->lsb() == 0) { + if (vtxp->dtype() == lSelp->fromp()->dtype() && lSelp->lsb() == 0) { APPLYING(REPLACE_CONCAT_SEL_BOTTOM_AND_ZERO_WITH_SHIFTL) { DfgShiftL* const replacementp = make( vtxp, lSelp->fromp(), makeI32(flp, rConstp->width())); @@ -1317,7 +1277,8 @@ class V3DfgPeephole final : public DfgVisitor { if (lSelp->lsb() == rSelp->lsb() + rSelp->width()) { // Two consecutive Sels, make a single Sel. const uint32_t width = lSelp->width() + rSelp->width(); - return make(flp, dtypePacked(width), rSelp->fromp(), rSelp->lsb()); + return make(flp, DfgDataType::packed(width), rSelp->fromp(), + rSelp->lsb()); } } return nullptr; @@ -1464,18 +1425,12 @@ class V3DfgPeephole final : public DfgVisitor { } void visit(DfgMul* vtxp) override { - UASSERT_OBJ(vtxp->dtypep() == vtxp->lhsp()->dtypep(), vtxp, "Mismatched LHS width"); - UASSERT_OBJ(vtxp->dtypep() == vtxp->rhsp()->dtypep(), vtxp, "Mismatched RHS width"); - if (associativeBinary(vtxp)) return; if (commutativeBinary(vtxp)) return; } void visit(DfgMulS* vtxp) override { - UASSERT_OBJ(vtxp->dtypep() == vtxp->lhsp()->dtypep(), vtxp, "Mismatched LHS width"); - UASSERT_OBJ(vtxp->dtypep() == vtxp->rhsp()->dtypep(), vtxp, "Mismatched RHS width"); - if (associativeBinary(vtxp)) return; if (commutativeBinary(vtxp)) return; @@ -1502,7 +1457,7 @@ class V3DfgPeephole final : public DfgVisitor { } void visit(DfgReplicate* vtxp) override { - if (vtxp->dtypep() == vtxp->srcp()->dtypep()) { + if (vtxp->dtype() == vtxp->srcp()->dtype()) { APPLYING(REMOVE_REPLICATE_ONCE) { replace(vtxp, vtxp->srcp()); return; @@ -1528,9 +1483,6 @@ class V3DfgPeephole final : public DfgVisitor { } void visit(DfgSub* vtxp) override { - UASSERT_OBJ(vtxp->dtypep() == vtxp->lhsp()->dtypep(), vtxp, "Mismatched LHS width"); - UASSERT_OBJ(vtxp->dtypep() == vtxp->rhsp()->dtypep(), vtxp, "Mismatched RHS width"); - if (foldBinary(vtxp)) return; DfgVertex* const lhsp = vtxp->lhsp(); @@ -1543,7 +1495,7 @@ class V3DfgPeephole final : public DfgVisitor { return; } } - if (vtxp->dtypep() == m_bitDType && rConstp->hasValue(1)) { + if (vtxp->dtype() == m_bitDType && rConstp->hasValue(1)) { APPLYING(REPLACE_SUB_WITH_NOT) { DfgNot* const replacementp = make(vtxp->fileline(), m_bitDType, lhsp); replace(vtxp, replacementp); @@ -1558,15 +1510,12 @@ class V3DfgPeephole final : public DfgVisitor { //========================================================================= void visit(DfgCond* vtxp) override { - UASSERT_OBJ(vtxp->dtypep() == vtxp->thenp()->dtypep(), vtxp, "Width mismatch"); - UASSERT_OBJ(vtxp->dtypep() == vtxp->elsep()->dtypep(), vtxp, "Width mismatch"); - DfgVertex* const condp = vtxp->condp(); DfgVertex* const thenp = vtxp->thenp(); DfgVertex* const elsep = vtxp->elsep(); FileLine* const flp = vtxp->fileline(); - if (condp->dtypep() != m_bitDType) return; + if (condp->dtype() != m_bitDType) return; if (isOnes(condp)) { APPLYING(REMOVE_COND_WITH_TRUE_CONDITION) { @@ -1619,7 +1568,7 @@ class V3DfgPeephole final : public DfgVisitor { DfgCond* const newCondp = make( vtxp, vtxp->condp(), thenNotp->srcp(), elseNotp->srcp()); DfgNot* const replacementp - = make(thenp->fileline(), vtxp->dtypep(), newCondp); + = make(thenp->fileline(), vtxp->dtype(), newCondp); replace(vtxp, replacementp); return; } @@ -1666,8 +1615,8 @@ class V3DfgPeephole final : public DfgVisitor { DfgConcat* const extp = make( vtxp, makeZero(flp, vtxp->width() - 1), condp); FileLine* const thenFlp = thenAddp->fileline(); - DfgAdd* const addp = make(thenFlp, vtxp->dtypep(), - thenAddp->rhsp(), extp); + DfgAdd* const addp + = make(thenFlp, vtxp->dtype(), thenAddp->rhsp(), extp); replace(vtxp, addp); return; } @@ -1684,8 +1633,8 @@ class V3DfgPeephole final : public DfgVisitor { DfgConcat* const extp = make( vtxp, makeZero(flp, vtxp->width() - 1), condp); FileLine* const thenFlp = thenSubp->fileline(); - DfgSub* const subp = make(thenFlp, vtxp->dtypep(), - thenSubp->lhsp(), extp); + DfgSub* const subp + = make(thenFlp, vtxp->dtype(), thenSubp->lhsp(), extp); replace(vtxp, subp); return; } @@ -1695,7 +1644,7 @@ class V3DfgPeephole final : public DfgVisitor { } } - if (vtxp->dtypep() == m_bitDType) { + if (vtxp->dtype() == m_bitDType) { if (isZero(thenp)) { // a ? 0 : b becomes ~a & b APPLYING(REPLACE_COND_WITH_THEN_BRANCH_ZERO) { DfgNot* const notp = make(vtxp, condp); diff --git a/src/V3DfgRegularize.cpp b/src/V3DfgRegularize.cpp index 07bab6173..acf470efd 100644 --- a/src/V3DfgRegularize.cpp +++ b/src/V3DfgRegularize.cpp @@ -71,7 +71,7 @@ class DfgRegularize final { const std::string name = m_dfg.makeUniqueName("Regularize", m_nTmps); FileLine* const flp = vtx.fileline(); AstScope* const scopep = scoped ? vtx.scopep(scopeCache) : nullptr; - DfgVertexVar* const newp = m_dfg.makeNewVar(flp, name, vtx.dtypep(), scopep); + DfgVertexVar* const newp = m_dfg.makeNewVar(flp, name, vtx.dtype(), scopep); ++m_nTmps; ++m_ctx.m_temporariesIntroduced; // Replace vertex with the variable and add back driver diff --git a/src/V3DfgSynthesize.cpp b/src/V3DfgSynthesize.cpp index 89dd62654..dc030d581 100644 --- a/src/V3DfgSynthesize.cpp +++ b/src/V3DfgSynthesize.cpp @@ -38,17 +38,18 @@ namespace { // Create a DfgVertex out of a AstNodeExpr. For most AstNodeExpr subtypes, this can be done // automatically. For the few special cases, we provide specializations below template -T_Vertex* makeVertex(const T_Node* nodep, DfgGraph& dfg) { - return new T_Vertex{dfg, nodep->fileline(), V3Dfg::toDfgDType(nodep->dtypep())}; +T_Vertex* makeVertex(const T_Node* nodep, DfgGraph& dfg, const DfgDataType& dtype) { + return new T_Vertex{dfg, nodep->fileline(), dtype}; } template <> -DfgArraySel* makeVertex(const AstArraySel* nodep, DfgGraph& dfg) { +DfgArraySel* makeVertex(const AstArraySel* nodep, DfgGraph& dfg, + const DfgDataType& dtype) { // Some earlier passes create malformed ArraySels, just bail on those... // See t_bitsel_wire_array_bad if (VN_IS(nodep->fromp(), Const)) return nullptr; if (!VN_IS(nodep->fromp()->dtypep()->skipRefp(), UnpackArrayDType)) return nullptr; - return new DfgArraySel{dfg, nodep->fileline(), V3Dfg::toDfgDType(nodep->dtypep())}; + return new DfgArraySel{dfg, nodep->fileline(), dtype}; } } // namespace @@ -102,17 +103,12 @@ class AstToDfgConverter final : public VNVisitor { // Returns true if the expression cannot (or should not) be represented by DFG bool unhandled(AstNodeExpr* nodep) { // Short-circuiting if something was already unhandled - if (!m_foundUnhandled) { + if (m_foundUnhandled) { // Impure nodes cannot be represented if (!nodep->isPure()) { m_foundUnhandled = true; ++m_ctx.m_conv.nonRepImpure; } - // Check node has supported dtype - if (!V3Dfg::isSupported(nodep->dtypep())) { - m_foundUnhandled = true; - ++m_ctx.m_conv.nonRepDType; - } } return m_foundUnhandled; } @@ -170,9 +166,9 @@ class AstToDfgConverter final : public VNVisitor { // Create the Splice driver for the new temporary if (newp->is()) { - newp->srcp(make(newp->fileline(), newp->dtypep())); + newp->srcp(make(newp->fileline(), newp->dtype())); } else if (newp->is()) { - newp->srcp(make(newp->fileline(), newp->dtypep())); + newp->srcp(make(newp->fileline(), newp->dtype())); } else { nodep->v3fatalSrc("Unhandled DfgVertexVar sub-type"); // LCOV_EXCL_LINE } @@ -201,6 +197,12 @@ class AstToDfgConverter final : public VNVisitor { // Adjust index. lsb += pair.second; + // Don't optimize if statically out of bounds. TODO: Maybe later ... + if (lsb + static_cast(selp->widthConst()) > splicep->size()) { + ++m_ctx.m_conv.nonRepOOBSel; + return {nullptr, 0}; + } + // AstSel doesn't change type kind (array vs packed), so we can use // the existing splice driver with adjusted lsb return {splicep, lsb}; @@ -222,21 +224,28 @@ class AstToDfgConverter final : public VNVisitor { // Adjust index. Note pair.second is always 0, but we might handle array slices later.. index += pair.second; + // Don't optimize if statically out of bounds. TODO: Maybe later ... + if (index + 1U > splicep->size()) { + ++m_ctx.m_conv.nonRepOOBSel; + return {nullptr, 0}; + } + // Ensure the Splice driver exists for this element if (!splicep->driverAt(index)) { FileLine* const flp = nodep->fileline(); - AstNodeDType* const dtypep = V3Dfg::toDfgDType(nodep->dtypep()); - if (VN_IS(dtypep, BasicDType)) { - DfgSplicePacked* const newp = make(flp, dtypep); - AstNodeDType* const uaDtypep = V3Dfg::dtypeArray(dtypep, 1); - DfgUnitArray* const uap = make(flp, uaDtypep); + // This should never fail + const DfgDataType& dtype = *DfgDataType::fromAst(nodep->dtypep()); + if (dtype.isPacked()) { + DfgSplicePacked* const newp = make(flp, dtype); + const DfgDataType& uaDtype = DfgDataType::array(dtype, 1); + DfgUnitArray* const uap = make(flp, uaDtype); uap->srcp(newp); splicep->addDriver(uap, index, flp); - } else if (VN_IS(dtypep, UnpackArrayDType)) { - DfgSpliceArray* const newp = make(flp, dtypep); + } else if (dtype.isArray()) { + DfgSpliceArray* const newp = make(flp, dtype); splicep->addDriver(newp, index, flp); } else { - nodep->v3fatalSrc("Unhandled AstNodeDType sub-type"); // LCOV_EXCL_LINE + nodep->v3fatalSrc("Unhandled data type kind"); // LCOV_EXCL_LINE } } @@ -276,7 +285,7 @@ class AstToDfgConverter final : public VNVisitor { // to avoid multiple use of the expression if (VN_IS(lhsp, Concat) && !vtxp->is() && !vtxp->is()) { const size_t n = ++m_nUnpack; - DfgVertexVar* const tmpp = createTmp(*m_logicp, flp, vtxp->dtypep(), "Unpack", n); + DfgVertexVar* const tmpp = createTmp(*m_logicp, flp, vtxp->dtype(), "Unpack", n); tmpp->srcp(vtxp); vtxp = tmpp; } @@ -308,7 +317,8 @@ class AstToDfgConverter final : public VNVisitor { } // Otherwise select the relevant bits - DfgSel* const selp = make(subp->fileline(), V3Dfg::toDfgDType(subp->dtypep())); + const DfgDataType& dtype = *DfgDataType::fromAst(subp->dtypep()); + DfgSel* const selp = make(subp->fileline(), dtype); selp->fromp(vtxp); selp->lsb(lsb); assignments.emplace_back(pair.first, pair.second, selp); @@ -323,18 +333,15 @@ class AstToDfgConverter final : public VNVisitor { if (DfgSplicePacked* const spp = item.m_lhsp->template cast()) { spp->addDriver(item.m_rhsp, item.m_idx, flp); } else if (DfgSpliceArray* const sap = item.m_lhsp->template cast()) { - AstUnpackArrayDType* const lDtp = VN_AS(sap->dtypep(), UnpackArrayDType); - const AstNodeDType* const lEleDtp = lDtp->subDTypep(); - AstNodeDType* const rDtp = item.m_rhsp->dtypep(); - if (lEleDtp->isSame(rDtp)) { + // TODO: multi-dimensional arrays will need changes here + const DfgDataType& rDt = item.m_rhsp->dtype(); + if (rDt.isPacked()) { // RHS is assigning an element of this array. Need a DfgUnitArray adapter. - DfgUnitArray* const uap = make(flp, V3Dfg::dtypeArray(rDtp, 1)); + DfgUnitArray* const uap = make(flp, DfgDataType::array(rDt, 1)); uap->srcp(item.m_rhsp); sap->addDriver(uap, item.m_idx, flp); } else { // RHS is assigning an array (or array slice). Should be the same element type. - const AstNodeDType* const rEleDtp = VN_AS(rDtp, UnpackArrayDType)->subDTypep(); - UASSERT_OBJ(lEleDtp->isSame(rEleDtp), item.m_rhsp, "Mismatched array types"); sap->addDriver(item.m_rhsp, item.m_idx, flp); } } else { @@ -374,28 +381,49 @@ class AstToDfgConverter final : public VNVisitor { UASSERT_OBJ(m_converting, nodep, "AstToDfg visit called without m_converting"); UASSERT_OBJ(!nodep->user2p(), nodep, "Already has Dfg vertex"); if (unhandled(nodep)) return; - DfgVertex* const vtxp = make(nodep->fileline(), nodep->num()); - nodep->user2p(vtxp); + + if (nodep->width() != nodep->num().width()) { + // Sometimes the width of the AstConst is not the same as the + // V3Number it holds. Truncate it here. TODO: should this be allowed? + V3Number num{nodep, nodep->width()}; + num.opSel(nodep->num(), nodep->width() - 1, 0); + DfgVertex* const vtxp = make(nodep->fileline(), num); + nodep->user2p(vtxp); + } else { + DfgVertex* const vtxp = make(nodep->fileline(), nodep->num()); + nodep->user2p(vtxp); + } } void visit(AstSel* nodep) override { UASSERT_OBJ(m_converting, nodep, "AstToDfg visit called without m_converting"); UASSERT_OBJ(!nodep->user2p(), nodep, "Already has Dfg vertex"); if (unhandled(nodep)) return; + const DfgDataType* const dtypep = DfgDataType::fromAst(nodep->dtypep()); + if (!dtypep) { + m_foundUnhandled = true; + ++m_ctx.m_conv.nonRepDType; + return; + } + iterate(nodep->fromp()); if (m_foundUnhandled) return; FileLine* const flp = nodep->fileline(); DfgVertex* vtxp = nullptr; if (const AstConst* const constp = VN_CAST(nodep->lsbp(), Const)) { - DfgSel* const selp = make(flp, V3Dfg::toDfgDType(nodep->dtypep())); + const uint32_t lsb = constp->toUInt(); + const uint32_t msb = lsb + nodep->widthConst() - 1; + DfgSel* const selp = make(flp, *dtypep); selp->fromp(nodep->fromp()->user2u().to()); - selp->lsb(constp->toUInt()); + selp->lsb(lsb); + UASSERT_OBJ(msb < selp->fromp()->size(), nodep, + "OOB AstSel should have been fixed up by earlier passes"); vtxp = selp; } else { iterate(nodep->lsbp()); if (m_foundUnhandled) return; - DfgMux* const muxp = make(flp, V3Dfg::toDfgDType(nodep->dtypep())); + DfgMux* const muxp = make(flp, *dtypep); muxp->fromp(nodep->fromp()->user2u().to()); muxp->lsbp(nodep->lsbp()->user2u().to()); vtxp = muxp; @@ -409,10 +437,10 @@ public: // PUBLIC METHODS // Create temporay variable capable of holding the given type - DfgVertexVar* createTmp(DfgLogic& logic, FileLine* flp, AstNodeDType* dtypep, + DfgVertexVar* createTmp(DfgLogic& logic, FileLine* flp, const DfgDataType& dtype, const std::string& prefix, size_t tmpCount) { const std::string name = m_dfg.makeUniqueName(prefix, tmpCount); - DfgVertexVar* const vtxp = m_dfg.makeNewVar(flp, name, dtypep, logic.scopep()); + DfgVertexVar* const vtxp = m_dfg.makeNewVar(flp, name, dtype, logic.scopep()); logic.synth().emplace_back(vtxp); vtxp->varp()->isInternal(true); vtxp->tmpForp(vtxp->nodep()); @@ -423,13 +451,11 @@ public: DfgVertexVar* createTmp(DfgLogic& logic, Variable* varp, const std::string& prefix) { AstVar* const astVarp = T_Scoped ? reinterpret_cast(varp)->varp() : reinterpret_cast(varp); - const std::string prfx = prefix + "_" + astVarp->name(); - const std::string name = m_dfg.makeUniqueName(prfx, astVarp->user3Inc()); FileLine* const flp = astVarp->fileline(); - AstNodeDType* const dtypep = V3Dfg::toDfgDType(astVarp->dtypep()); - DfgVertexVar* const vtxp = m_dfg.makeNewVar(flp, name, dtypep, logic.scopep()); - logic.synth().emplace_back(vtxp); - vtxp->varp()->isInternal(true); + const DfgDataType& dtype = *DfgDataType::fromAst(astVarp->dtypep()); + const std::string prfx = prefix + "_" + astVarp->name(); + const size_t tmpCount = astVarp->user3Inc(); + DfgVertexVar* const vtxp = createTmp(logic, flp, dtype, prfx, tmpCount); vtxp->tmpForp(varp); return vtxp; } @@ -450,12 +476,14 @@ public: AstNodeExpr* const lhsp = nodep->lhsp(); AstNodeExpr* const rhsp = nodep->rhsp(); // Check data types are compatible. - if (!V3Dfg::isSupported(lhsp->dtypep()) || !V3Dfg::isSupported(rhsp->dtypep())) { + const DfgDataType* const lDtypep = DfgDataType::fromAst(lhsp->dtypep()); + const DfgDataType* const rDtypep = DfgDataType::fromAst(rhsp->dtypep()); + if (!lDtypep || !rDtypep) { ++m_ctx.m_conv.nonRepDType; return false; } // For now, only direct array assignment is supported (e.g. a = b, but not a = _ ? b : c) - if (VN_IS(rhsp->dtypep()->skipRefp(), UnpackArrayDType) && !VN_IS(rhsp, VarRef)) { + if (rDtypep->isArray() && !VN_IS(rhsp, VarRef)) { ++m_ctx.m_conv.nonRepDType; return false; } @@ -516,7 +544,7 @@ class AstToDfgSynthesize final { Driver(DfgVertex* vtxp, uint32_t lo, FileLine* flp) : m_vtxp{vtxp} , m_lo{lo} - , m_hi{lo + vtxp->size() - 1} + , m_hi{lo + vtxp->size() - 1U} , m_flp{flp} {} operator bool() const { return m_vtxp != nullptr; } @@ -679,7 +707,7 @@ class AstToDfgSynthesize final { if (!aSp) return {false, false}; DfgSplicePacked* const bSp = bUap->srcp()->template cast(); if (!bSp) return {false, false}; - UASSERT_OBJ(aSp->dtypep()->isSame(bSp->dtypep()), &var, "DTypes should match"); + UASSERT_OBJ(aSp->dtype() == bSp->dtype(), &var, "DTypes should match"); // Gather drivers of a std::vector aDrivers = gatherDrivers(aSp); @@ -702,9 +730,9 @@ class AstToDfgSynthesize final { // Successfully resolved. Needs a new splice and unit. FileLine* const flp = var.fileline(); - DfgSplicePacked* const splicep = make(flp, aSp->dtypep()); + DfgSplicePacked* const splicep = make(flp, aSp->dtype()); for (const Driver& d : abDrivers) splicep->addDriver(d.m_vtxp, d.m_lo, d.m_flp); - DfgUnitArray* const uap = make(flp, aUap->dtypep()); + DfgUnitArray* const uap = make(flp, aUap->dtype()); uap->srcp(splicep); a.m_vtxp = uap; return {true, false}; @@ -841,8 +869,8 @@ class AstToDfgSynthesize final { } // Coalesce Adjacent ranges, - const auto dtypep = V3Dfg::dtypePacked(iD.m_vtxp->width() + jD.m_vtxp->width()); - DfgConcat* const concatp = make(iD.m_flp, dtypep); + const DfgDataType& dt = DfgDataType::packed(iD.m_vtxp->width() + jD.m_vtxp->width()); + DfgConcat* const concatp = make(iD.m_flp, dt); concatp->rhsp(iD.m_vtxp); concatp->lhsp(jD.m_vtxp); iD.m_vtxp = concatp; @@ -862,9 +890,9 @@ class AstToDfgSynthesize final { // Create new driver DfgVertexSplice* splicep = nullptr; if (var.is()) { - splicep = make(var.fileline(), var.dtypep()); + splicep = make(var.fileline(), var.dtype()); } else if (var.is()) { - splicep = make(var.fileline(), var.dtypep()); + splicep = make(var.fileline(), var.dtype()); } else { var.v3fatalSrc("Unhandled DfgVertexVar sub-type"); // LCOV_EXCL_LINE } @@ -920,7 +948,7 @@ class AstToDfgSynthesize final { } // Can't do arrays yet - if (VN_IS(thenp->dtypep(), UnpackArrayDType)) { + if (!thenp->isPacked()) { ++m_ctx.m_synt.nonSynArray; return nullptr; } @@ -941,7 +969,7 @@ class AstToDfgSynthesize final { // Create a fresh temporary for the joined value DfgVertexVar* const joinp = m_converter.createTmp(*m_logicp, varp, "SynthJoin"); - DfgVertexSplice* const joinSplicep = make(flp, joinp->dtypep()); + DfgVertexSplice* const joinSplicep = make(flp, joinp->dtype()); joinp->srcp(joinSplicep); // If both paths are fully driven, just create a simple conditional @@ -953,7 +981,7 @@ class AstToDfgSynthesize final { && eDrivers[0].m_hi == elsep->width() - 1) { UASSERT_OBJ(!tDefaultp, varp, "Fully driven variable have default driver"); - DfgCond* const condp = make(flp, joinp->dtypep()); + DfgCond* const condp = make(flp, joinp->dtype()); condp->condp(predicatep); condp->thenp(thenp); condp->elsep(elsep); @@ -980,18 +1008,18 @@ class AstToDfgSynthesize final { return nullptr; } - AstNodeDType* const dtypep = V3Dfg::dtypePacked(tDriver.m_hi - tDriver.m_lo + 1); - DfgCond* const condp = make(flp, dtypep); + const DfgDataType& dtype = DfgDataType::packed(tDriver.m_hi - tDriver.m_lo + 1); + DfgCond* const condp = make(flp, dtype); condp->condp(predicatep); // We actally need to select the bits from the joined variables, not use the drivers - DfgSel* const thenSelp = make(flp, tDriver.m_vtxp->dtypep()); + DfgSel* const thenSelp = make(flp, tDriver.m_vtxp->dtype()); thenSelp->lsb(tDriver.m_lo); thenSelp->fromp(thenp); condp->thenp(thenSelp); // Same for the 'else' part - DfgSel* const elseSelp = make(flp, eDriver.m_vtxp->dtypep()); + DfgSel* const elseSelp = make(flp, eDriver.m_vtxp->dtype()); elseSelp->lsb(eDriver.m_lo); elseSelp->fromp(elsep); condp->elsep(elseSelp); @@ -1171,7 +1199,7 @@ class AstToDfgSynthesize final { const auto addOldDriver = [&](FileLine* const flp, uint32_t msb, uint32_t lsb) { UASSERT_OBJ(propagatedDrivers.empty() || lsb > propagatedDrivers.back().m_hi, flp, "Drivers should be in ascending order"); - DfgSel* const selp = make(flp, V3Dfg::dtypePacked(msb - lsb + 1)); + DfgSel* const selp = make(flp, DfgDataType::packed(msb - lsb + 1)); selp->lsb(lsb); selp->fromp(oldp); propagatedDrivers.emplace_back(selp, lsb, flp); @@ -1231,7 +1259,7 @@ class AstToDfgSynthesize final { UASSERT_OBJ(oldp->srcp(), varp, "Previously assigned variable has no driver"); // Can't do arrays yet - if (VN_IS(newp->dtypep(), UnpackArrayDType)) { + if (!newp->isPacked()) { ++m_ctx.m_synt.nonSynArray; return false; } @@ -1337,7 +1365,7 @@ class AstToDfgSynthesize final { // Single bit condition can be use directly, otherwise: use 'condp != 0' if (condp->width() != 1) { FileLine* const flp = condp->fileline(); - DfgNeq* const neqp = make(flp, V3Dfg::dtypePacked(1)); + DfgNeq* const neqp = make(flp, DfgDataType::packed(1)); neqp->lhsp(make(flp, condp->width(), 0U)); neqp->rhsp(condp); condp = neqp; @@ -1369,7 +1397,7 @@ class AstToDfgSynthesize final { auto it = inEdges.begin(); DfgVertex* resp = m_edgeToPredicatep[static_cast(*it)]; while (++it != inEdges.end()) { - DfgOr* const orp = make(resp->fileline(), resp->dtypep()); + DfgOr* const orp = make(resp->fileline(), resp->dtype()); orp->rhsp(resp); orp->lhsp(m_edgeToPredicatep[static_cast(*it)]); resp = orp; @@ -1378,15 +1406,11 @@ class AstToDfgSynthesize final { }(); size_t n = m_nPathPred++; // Sequence number for temporaries - AstNodeDType* const dtypep = predp->dtypep(); + const DfgDataType& dtype = predp->dtype(); const auto mkTmp = [&](FileLine* flp, const char* name, DfgVertex* srcp) { - std::string prefix; - prefix += "_BB"; - prefix += std::to_string(bb.id()); - prefix += "_"; - prefix += name; - DfgVertexVar* const tmpp = m_converter.createTmp(*m_logicp, flp, dtypep, prefix, n); + const std::string prefix = "_BB" + std::to_string(bb.id()) + "_" + name; + DfgVertexVar* const tmpp = m_converter.createTmp(*m_logicp, flp, dtype, prefix, n); tmpp->srcp(srcp); return tmpp; }; @@ -1406,7 +1430,7 @@ class AstToDfgSynthesize final { // Predicate for taken branch: 'predp & condp' { - DfgAnd* const takenPredp = make(flp, dtypep); + DfgAnd* const takenPredp = make(flp, dtype); takenPredp->lhsp(pInp); takenPredp->rhsp(condp); m_edgeToPredicatep[bb.takenEdgep()] = mkTmp(flp, "Taken", takenPredp); @@ -1414,9 +1438,9 @@ class AstToDfgSynthesize final { // Predicate for untaken branch: 'predp & ~condp' { - DfgAnd* const untknPredp = make(flp, dtypep); + DfgAnd* const untknPredp = make(flp, dtype); untknPredp->lhsp(pInp); - DfgNot* const notp = make(flp, dtypep); + DfgNot* const notp = make(flp, dtype); notp->srcp(condp); untknPredp->rhsp(notp); m_edgeToPredicatep[bb.untknEdgep()] = mkTmp(flp, "Untkn", untknPredp); @@ -1470,7 +1494,7 @@ class AstToDfgSynthesize final { // We need to add a new splice to avoid multi-use of the original splice DfgSplicePacked* const splicep - = new DfgSplicePacked{m_dfg, resp->fileline(), resp->dtypep()}; + = new DfgSplicePacked{m_dfg, resp->fileline(), resp->dtype()}; // Drivers are the same const std::vector drivers = computePropagatedDrivers({}, resp); for (const Driver& d : drivers) splicep->addDriver(d.m_vtxp, d.m_lo, d.m_flp); @@ -1557,10 +1581,10 @@ class AstToDfgSynthesize final { // Create a temporary for the branch condition as it might be used multiple times if (condp) { FileLine* const flp = condp->fileline(); - AstNodeDType* const dtypep = condp->dtypep(); + const DfgDataType& dtype = condp->dtype(); const std::string prefix = "_BB" + std::to_string(bb.id()) + "_Cond"; const size_t n = m_nBranchCond++; - DfgVertexVar* const vp = m_converter.createTmp(*m_logicp, flp, dtypep, prefix, n); + DfgVertexVar* const vp = m_converter.createTmp(*m_logicp, flp, dtype, prefix, n); vp->srcp(condp); m_bbToCondp[bb] = vp; } @@ -1848,6 +1872,7 @@ public: UASSERT_OBJ(vtx.inputp(i), &vtx, "Unconnected source operand"); } } + V3DfgPasses::typeCheck(dfg); } } }; diff --git a/src/V3DfgVertices.h b/src/V3DfgVertices.h index 0e46e0c47..590c45b05 100644 --- a/src/V3DfgVertices.h +++ b/src/V3DfgVertices.h @@ -58,7 +58,7 @@ class DfgVertexVar VL_NOT_FINAL : public DfgVertex { AstNode* m_tmpForp = nullptr; DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp, AstVarScope* vscp) - : DfgVertex{dfg, type, varp->fileline(), V3Dfg::toDfgDType(varp->dtypep())} + : DfgVertex{dfg, type, varp->fileline(), *DfgDataType::fromAst(varp->dtypep())} , m_varp{varp} , m_varScopep{vscp} { #ifdef VL_DEBUG @@ -67,7 +67,6 @@ class DfgVertexVar VL_NOT_FINAL : public DfgVertex { } else { UASSERT_OBJ(!vscp, varp, "Scoped DfgVertexVar created in un-scoped DfgGraph"); } - UASSERT_OBJ(V3Dfg::isSupported(dtypep()), varp, "Not representable by DfgVertexVar"); #endif // Increment reference count AstNode* const variablep = nodep(); @@ -162,11 +161,11 @@ class DfgVarArray final : public DfgVertexVar { public: DfgVarArray(DfgGraph& dfg, AstVar* varp) : DfgVertexVar{dfg, dfgType(), varp} { - UASSERT_OBJ(VN_IS(dtypep(), UnpackArrayDType), varp, "Non array DfgVarArray"); + UASSERT_OBJ(isArray(), varp, "Non-array DfgVarArray"); } DfgVarArray(DfgGraph& dfg, AstVarScope* vscp) : DfgVertexVar{dfg, dfgType(), vscp} { - UASSERT_OBJ(VN_IS(dtypep(), UnpackArrayDType), vscp, "Non array DfgVarArray"); + UASSERT_OBJ(isArray(), vscp, "Non-array DfgVarArray"); } ASTGEN_MEMBERS_DfgVarArray; }; @@ -178,11 +177,11 @@ class DfgVarPacked final : public DfgVertexVar { public: DfgVarPacked(DfgGraph& dfg, AstVar* varp) : DfgVertexVar{dfg, dfgType(), varp} { - UASSERT_OBJ(!VN_IS(dtypep(), UnpackArrayDType), varp, "Array DfgVarPacked"); + UASSERT_OBJ(isPacked(), varp, "Non-packed DfgVarPacked"); } DfgVarPacked(DfgGraph& dfg, AstVarScope* vscp) : DfgVertexVar{dfg, dfgType(), vscp} { - UASSERT_OBJ(!VN_IS(dtypep(), UnpackArrayDType), vscp, "Array DfgVarPacked"); + UASSERT_OBJ(isPacked(), vscp, "Non-packed DfgVarPacked"); } ASTGEN_MEMBERS_DfgVarPacked; }; @@ -192,8 +191,8 @@ public: class DfgVertexNullary VL_NOT_FINAL : public DfgVertex { protected: - DfgVertexNullary(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep) - : DfgVertex{dfg, type, flp, dtypep} {} + DfgVertexNullary(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype) + : DfgVertex{dfg, type, flp, dtype} {} public: ASTGEN_MEMBERS_DfgVertexNullary; @@ -208,10 +207,10 @@ class DfgConst final : public DfgVertexNullary { public: DfgConst(DfgGraph& dfg, FileLine* flp, const V3Number& num) - : DfgVertexNullary{dfg, dfgType(), flp, V3Dfg::dtypePacked(num.width())} + : DfgVertexNullary{dfg, dfgType(), flp, DfgDataType::packed(num.width())} , m_num{num} {} - DfgConst(DfgGraph& dfg, FileLine* flp, uint32_t width, uint32_t value) - : DfgVertexNullary{dfg, dfgType(), flp, V3Dfg::dtypePacked(width)} + DfgConst(DfgGraph& dfg, FileLine* flp, size_t width, uint32_t value) + : DfgVertexNullary{dfg, dfgType(), flp, DfgDataType::packed(width)} , m_num{flp, static_cast(width), value} {} ASTGEN_MEMBERS_DfgConst; @@ -236,8 +235,8 @@ public: class DfgVertexUnary VL_NOT_FINAL : public DfgVertex { protected: - DfgVertexUnary(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep) - : DfgVertex{dfg, type, flp, dtypep} { + DfgVertexUnary(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype) + : DfgVertex{dfg, type, flp, dtype} { newInput(); } @@ -255,8 +254,8 @@ class DfgSel final : public DfgVertexUnary { uint32_t m_lsb = 0; // The LSB index public: - DfgSel(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep) - : DfgVertexUnary{dfg, dfgType(), flp, dtypep} {} + DfgSel(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype) + : DfgVertexUnary{dfg, dfgType(), flp, dtype} {} ASTGEN_MEMBERS_DfgSel; DfgVertex* fromp() const { return srcp(); } @@ -269,10 +268,10 @@ class DfgUnitArray final : public DfgVertexUnary { // This is a type adapter for modeling arrays. It's a single element array, // with the value of the single element being the source operand. public: - DfgUnitArray(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep) - : DfgVertexUnary{dfg, dfgType(), flp, dtypep} { - UASSERT_OBJ(this->dtypep(), flp, "Non array DfgUnitArray"); - UASSERT_OBJ(this->size() == 1, flp, "DfgUnitArray must have a single element"); + DfgUnitArray(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype) + : DfgVertexUnary{dfg, dfgType(), flp, dtype} { + UASSERT_OBJ(isArray(), flp, "Non-array DfgUnitArray"); + UASSERT_OBJ(size() == 1, flp, "DfgUnitArray must have a single element"); } ASTGEN_MEMBERS_DfgUnitArray; }; @@ -282,8 +281,8 @@ public: class DfgVertexBinary VL_NOT_FINAL : public DfgVertex { protected: - DfgVertexBinary(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep) - : DfgVertex{dfg, type, flp, dtypep} { + DfgVertexBinary(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype) + : DfgVertex{dfg, type, flp, dtype} { newInput(); newInput(); } @@ -297,8 +296,8 @@ class DfgMux final : public DfgVertexBinary { // common, we special case as a DfgSel for the constant 'lsbp', and as // 'DfgMux` for the non-constant 'lsbp'. public: - DfgMux(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep) - : DfgVertexBinary{dfg, dfgType(), flp, dtypep} {} + DfgMux(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype) + : DfgVertexBinary{dfg, dfgType(), flp, dtype} {} ASTGEN_MEMBERS_DfgMux; DfgVertex* fromp() const { return inputp(0); } @@ -314,8 +313,8 @@ public: class DfgVertexTernary VL_NOT_FINAL : public DfgVertex { protected: - DfgVertexTernary(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep) - : DfgVertex{dfg, type, flp, dtypep} { + DfgVertexTernary(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype) + : DfgVertex{dfg, type, flp, dtype} { newInput(); newInput(); newInput(); @@ -330,8 +329,8 @@ public: class DfgVertexVariadic VL_NOT_FINAL : public DfgVertex { protected: - DfgVertexVariadic(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep) - : DfgVertex{dfg, type, flp, dtypep} {} + DfgVertexVariadic(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype) + : DfgVertex{dfg, type, flp, dtype} {} public: ASTGEN_MEMBERS_DfgVertexVariadic; @@ -351,8 +350,8 @@ class DfgVertexSplice VL_NOT_FINAL : public DfgVertexVariadic { std::vector m_driverData; // Additional data associated with each driver protected: - DfgVertexSplice(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep) - : DfgVertexVariadic{dfg, type, flp, dtypep} {} + DfgVertexSplice(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataType& dtype) + : DfgVertexVariadic{dfg, type, flp, dtype} {} public: ASTGEN_MEMBERS_DfgVertexSplice; @@ -442,9 +441,9 @@ class DfgSpliceArray final : public DfgVertexSplice { friend class DfgVisitor; public: - DfgSpliceArray(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep) - : DfgVertexSplice{dfg, dfgType(), flp, dtypep} { - UASSERT_OBJ(VN_IS(dtypep, UnpackArrayDType), flp, "Non array DfgSpliceArray"); + DfgSpliceArray(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype) + : DfgVertexSplice{dfg, dfgType(), flp, dtype} { + UASSERT_OBJ(isArray(), flp, "Non-array DfgSpliceArray"); } ASTGEN_MEMBERS_DfgSpliceArray; }; @@ -454,9 +453,9 @@ class DfgSplicePacked final : public DfgVertexSplice { friend class DfgVisitor; public: - DfgSplicePacked(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep) - : DfgVertexSplice{dfg, dfgType(), flp, dtypep} { - UASSERT_OBJ(!VN_IS(dtypep, UnpackArrayDType), flp, "Array DfgSplicePacked"); + DfgSplicePacked(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype) + : DfgVertexSplice{dfg, dfgType(), flp, dtype} { + UASSERT_OBJ(isPacked(), flp, "Non-packed DfgSplicePacked"); } ASTGEN_MEMBERS_DfgSplicePacked; }; @@ -474,13 +473,13 @@ class DfgLogic final : public DfgVertexVariadic { public: DfgLogic(DfgGraph& dfg, AstAssignW* nodep, AstScope* scopep) - : DfgVertexVariadic{dfg, dfgType(), nodep->fileline(), nullptr} + : DfgVertexVariadic{dfg, dfgType(), nodep->fileline(), DfgDataType::null()} , m_nodep{nodep} , m_scopep{scopep} , m_cfgp{nullptr} {} DfgLogic(DfgGraph& dfg, AstAlways* nodep, AstScope* scopep, std::unique_ptr cfgp) - : DfgVertexVariadic{dfg, dfgType(), nodep->fileline(), nullptr} + : DfgVertexVariadic{dfg, dfgType(), nodep->fileline(), DfgDataType::null()} , m_nodep{nodep} , m_scopep{scopep} , m_cfgp{std::move(cfgp)} {} @@ -511,7 +510,7 @@ class DfgUnresolved final : public DfgVertexVariadic { // Represents a collection of unresolved variable drivers before synthesis public: DfgUnresolved(DfgGraph& dfg, const DfgVertexVar* vtxp) - : DfgVertexVariadic{dfg, dfgType(), vtxp->fileline(), vtxp->dtypep()} {} + : DfgVertexVariadic{dfg, dfgType(), vtxp->fileline(), vtxp->dtype()} {} ASTGEN_MEMBERS_DfgUnresolved; std::string srcName(size_t) const override final { return ""; } diff --git a/src/astgen b/src/astgen index 9d08af903..2f1140d0f 100755 --- a/src/astgen +++ b/src/astgen @@ -1221,8 +1221,8 @@ def write_dfg_auto_classes(filename): emitBlock('''\ class Dfg{t} final : public Dfg{s} {{ public: - Dfg{t}(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep) - : Dfg{s}{{dfg, dfgType(), flp, dtypep}} {{}} + Dfg{t}(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype) + : Dfg{s}{{dfg, dfgType(), flp, dtype}} {{}} ASTGEN_MEMBERS_Dfg{t}; }}; ''', @@ -1244,7 +1244,7 @@ def write_dfg_clone_cases(filename): emitBlock('''\ case VDfgType::{t}: {{ - Dfg{t}* const cp = new Dfg{t}{{*clonep, vtx.fileline(), vtx.dtypep()}}; + Dfg{t}* const cp = new Dfg{t}{{*clonep, vtx.fileline(), vtx.dtype()}}; vtxp2clonep.emplace(&vtx, cp); break; }} @@ -1267,6 +1267,15 @@ def write_dfg_ast_to_dfg(filename): ) fh.write(' UASSERT_OBJ(!nodep->user2p(), nodep, "Already has Dfg vertex");\n\n') fh.write(" if (unhandled(nodep)) return;\n\n") + + fh.write( + " const DfgDataType* const dtypep = DfgDataType::fromAst(nodep->dtypep());\n") + fh.write(" if (!dtypep) {\n") + fh.write(" m_foundUnhandled = true;\n") + fh.write(" ++m_ctx.m_conv.nonRepDType;\n") + fh.write(" return;\n") + fh.write(" }\n\n") + for i in range(node.arity): fh.write(" iterate(nodep->op{j}p());\n".format(j=i + 1)) fh.write(" if (m_foundUnhandled) return;\n") @@ -1275,7 +1284,8 @@ def write_dfg_ast_to_dfg(filename): .format(j=i + 1)) fh.write("\n") fh.write( - " Dfg{t}* const vtxp = makeVertex(nodep, m_dfg);\n".format(t=node.name)) + " Dfg{t}* const vtxp = makeVertex(nodep, m_dfg, *dtypep);\n".format( + t=node.name)) fh.write(" if (!vtxp) {\n") fh.write(" m_foundUnhandled = true;\n") fh.write(" ++m_ctx.m_conv.nonRepNode;\n") diff --git a/test_regress/t/t_json_only_first.out b/test_regress/t/t_json_only_first.out index e913805b9..94e2aa076 100644 --- a/test_regress/t/t_json_only_first.out +++ b/test_regress/t/t_json_only_first.out @@ -85,17 +85,18 @@ ]} ],"filesp": [], "miscsp": [ - {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"UNLINKED", + {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(WB)", "typesp": [ {"type":"BASICDTYPE","name":"logic","addr":"(I)","loc":"d,34:24,34:27","dtypep":"(I)","keyword":"logic","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(G)","loc":"d,15:16,15:17","dtypep":"(G)","keyword":"logic","range":"3:0","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"logic","addr":"(LB)","loc":"d,19:18,19:19","dtypep":"(LB)","keyword":"logic","range":"31:0","generic":true,"rangep": []} + {"type":"BASICDTYPE","name":"logic","addr":"(LB)","loc":"d,19:18,19:19","dtypep":"(LB)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, + {"type":"VOIDDTYPE","name":"","addr":"(WB)","loc":"a,0:0,0:0","dtypep":"(WB)","generic":false} ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ - {"type":"MODULE","name":"@CONST-POOL@","addr":"(WB)","loc":"a,0:0,0:0","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], + {"type":"MODULE","name":"@CONST-POOL@","addr":"(XB)","loc":"a,0:0,0:0","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], "stmtsp": [ - {"type":"SCOPE","name":"@CONST-POOL@","addr":"(XB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(WB)","varsp": [],"blocksp": [],"inlinesp": []} + {"type":"SCOPE","name":"@CONST-POOL@","addr":"(YB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(XB)","varsp": [],"blocksp": [],"inlinesp": []} ]} ]} ]} diff --git a/test_regress/t/t_json_only_flat.out b/test_regress/t/t_json_only_flat.out index 7f48ce13a..36b9990fe 100644 --- a/test_regress/t/t_json_only_flat.out +++ b/test_regress/t/t_json_only_flat.out @@ -138,17 +138,18 @@ ]} ],"filesp": [], "miscsp": [ - {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"UNLINKED", + {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(BD)", "typesp": [ {"type":"BASICDTYPE","name":"logic","addr":"(J)","loc":"d,34:24,34:27","dtypep":"(J)","keyword":"logic","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(H)","loc":"d,15:16,15:17","dtypep":"(H)","keyword":"logic","range":"3:0","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"logic","addr":"(Q)","loc":"d,19:18,19:19","dtypep":"(Q)","keyword":"logic","range":"31:0","generic":true,"rangep": []} + {"type":"BASICDTYPE","name":"logic","addr":"(Q)","loc":"d,19:18,19:19","dtypep":"(Q)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, + {"type":"VOIDDTYPE","name":"","addr":"(BD)","loc":"a,0:0,0:0","dtypep":"(BD)","generic":false} ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ - {"type":"MODULE","name":"@CONST-POOL@","addr":"(BD)","loc":"a,0:0,0:0","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], + {"type":"MODULE","name":"@CONST-POOL@","addr":"(CD)","loc":"a,0:0,0:0","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], "stmtsp": [ - {"type":"SCOPE","name":"@CONST-POOL@","addr":"(CD)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(BD)","varsp": [],"blocksp": [],"inlinesp": []} + {"type":"SCOPE","name":"@CONST-POOL@","addr":"(DD)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(CD)","varsp": [],"blocksp": [],"inlinesp": []} ]} ]} ]} diff --git a/test_regress/t/t_json_only_flat_vlvbound.out b/test_regress/t/t_json_only_flat_vlvbound.out index ed297b222..40aab45b6 100644 --- a/test_regress/t/t_json_only_flat_vlvbound.out +++ b/test_regress/t/t_json_only_flat_vlvbound.out @@ -293,7 +293,7 @@ ]} ],"filesp": [], "miscsp": [ - {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"UNLINKED", + {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(OF)", "typesp": [ {"type":"BASICDTYPE","name":"logic","addr":"(RC)","loc":"d,18:18,18:19","dtypep":"(RC)","keyword":"logic","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(XC)","loc":"d,19:34,19:39","dtypep":"(XC)","keyword":"logic","range":"1:0","generic":true,"rangep": []}, @@ -303,13 +303,14 @@ {"type":"BASICDTYPE","name":"logic","addr":"(KD)","loc":"d,19:10,19:11","dtypep":"(KD)","keyword":"logic","range":"2:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(GD)","loc":"d,19:11,19:12","dtypep":"(GD)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(BD)","loc":"d,19:20,19:21","dtypep":"(BD)","keyword":"logic","range":"3:0","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"logic","addr":"(NC)","loc":"d,18:12,18:13","dtypep":"(NC)","keyword":"logic","range":"31:0","generic":true,"rangep": []} + {"type":"BASICDTYPE","name":"logic","addr":"(NC)","loc":"d,18:12,18:13","dtypep":"(NC)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, + {"type":"VOIDDTYPE","name":"","addr":"(OF)","loc":"a,0:0,0:0","dtypep":"(OF)","generic":false} ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ - {"type":"MODULE","name":"@CONST-POOL@","addr":"(OF)","loc":"a,0:0,0:0","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], + {"type":"MODULE","name":"@CONST-POOL@","addr":"(PF)","loc":"a,0:0,0:0","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], "stmtsp": [ - {"type":"SCOPE","name":"@CONST-POOL@","addr":"(PF)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(OF)","varsp": [],"blocksp": [],"inlinesp": []} + {"type":"SCOPE","name":"@CONST-POOL@","addr":"(QF)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(PF)","varsp": [],"blocksp": [],"inlinesp": []} ]} ]} ]} diff --git a/test_regress/t/t_xml_first.out b/test_regress/t/t_xml_first.out index 511de3c4b..ae71f8a51 100644 --- a/test_regress/t/t_xml_first.out +++ b/test_regress/t/t_xml_first.out @@ -80,6 +80,7 @@ + diff --git a/test_regress/t/t_xml_flat.out b/test_regress/t/t_xml_flat.out index 45d3b91cd..7a552ecd9 100644 --- a/test_regress/t/t_xml_flat.out +++ b/test_regress/t/t_xml_flat.out @@ -109,6 +109,7 @@ + diff --git a/test_regress/t/t_xml_flat_vlvbound.out b/test_regress/t/t_xml_flat_vlvbound.out index d0aaf98a7..b345b3370 100644 --- a/test_regress/t/t_xml_flat_vlvbound.out +++ b/test_regress/t/t_xml_flat_vlvbound.out @@ -210,6 +210,7 @@ +