From 6bc48fcdb314ec3425b2328bd4313ee26850ea83 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 7 Sep 2025 20:38:50 +0100 Subject: [PATCH] Improve Dfg type system (#6390) Added a mini type system for Dfg using DfgDataType to replace Dfg's use of AstNodeDType. This is much more restricted and represents only the types Dfg can handle in a canonical form. This will be needed when adding more support for unpacked arrays and maybe unpacked structs one day. Also added an internal type checker for DfgGraphs which encodes all the assumptions the code makes about type relationships in the graph. Run this in a few places with --debug-check. Fix resulting fallout. --- src/CMakeLists.txt | 2 + src/Makefile_obj.in | 1 + src/V3Dfg.cpp | 60 ++--- src/V3Dfg.h | 67 ++---- src/V3DfgAstToDfg.cpp | 1 + src/V3DfgBreakCycles.cpp | 18 +- src/V3DfgCache.h | 73 +++--- src/V3DfgContext.h | 3 + src/V3DfgCse.cpp | 2 +- src/V3DfgDataType.cpp | 225 ++++++++++++++++++ src/V3DfgDataType.h | 233 +++++++++++++++++++ src/V3DfgDfgToAst.cpp | 3 +- src/V3DfgOptimizer.cpp | 3 + src/V3DfgPasses.cpp | 19 +- src/V3DfgPasses.h | 2 + src/V3DfgPatternStats.h | 7 +- src/V3DfgPeephole.cpp | 151 ++++-------- src/V3DfgRegularize.cpp | 2 +- src/V3DfgSynthesize.cpp | 177 ++++++++------ src/V3DfgVertices.h | 75 +++--- src/astgen | 18 +- test_regress/t/t_json_only_first.out | 9 +- test_regress/t/t_json_only_flat.out | 9 +- test_regress/t/t_json_only_flat_vlvbound.out | 9 +- test_regress/t/t_xml_first.out | 1 + test_regress/t/t_xml_flat.out | 1 + test_regress/t/t_xml_flat_vlvbound.out | 1 + 27 files changed, 778 insertions(+), 394 deletions(-) create mode 100644 src/V3DfgDataType.cpp create mode 100644 src/V3DfgDataType.h 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 @@ +