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.
This commit is contained in:
Geza Lore 2025-09-07 20:38:50 +01:00 committed by GitHub
parent f67534069c
commit 6bc48fcdb3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 778 additions and 394 deletions

View File

@ -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

View File

@ -247,6 +247,7 @@ RAW_OBJS_PCH_ASTNOMT = \
V3DfgCache.o \
V3DfgColorSCCs.o \
V3DfgCse.o \
V3DfgDataType.o \
V3DfgDecomposition.o \
V3DfgDfgToAst.o \
V3DfgOptimizer.o \

View File

@ -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> 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<DfgSel>()->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<const DfgVertex*>& 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);
}

View File

@ -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<int>(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).

View File

@ -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)

View File

@ -123,8 +123,7 @@ class TraceDriver final : public DfgVisitor {
// Vertex is DfgConst, in which case this code is unreachable ...
using Vtx = typename std::conditional<std::is_same<DfgConst, Vertex>::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<Vertex*>(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

View File

@ -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<KeyBinary, DfgVertexBinary*>;
using CacheTernary = Cache<KeyTernary, DfgVertexTernary*>;
// 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 <typename Vertex, typename T_Cache, typename... Operands>
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 <typename Vertex, typename... Operands>
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 <typename Vertex, typename... Operands>
Vertex* V3DfgCache::getOrCreate(FileLine* flp, AstNodeDType* dtypep, Operands... operands) {
Vertex* V3DfgCache::getOrCreate(FileLine* flp, const DfgDataType& dtype, Operands... operands) {
static_assert(std::is_final<Vertex>::value, "Must invoke on final vertex type");
constexpr bool isSel = std::is_same<DfgSel, Vertex>::value;
constexpr bool isUnary = !isSel && std::is_base_of<DfgVertexUnary, Vertex>::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<Vertex, CacheType<Vertex>, Operands...>(
m_dfg, flp, dtypep, cacheForType<Vertex>(), operands...);
m_dfg, flp, cacheForType<Vertex>(), dtype, operands...);
}
} // namespace V3DfgCacheInternal

View File

@ -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;

View File

@ -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;

225
src/V3DfgDataType.cpp Normal file
View File

@ -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<uint32_t, const DfgDataType*> 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<DfgVertexVar>();
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<DfgVertexSplice>();
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<DfgUnitArray>();
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<DfgSel>();
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<DfgMux>();
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<DfgArraySel>();
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<DfgConcat>();
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<DfgReplicate>();
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<DfgCond>();
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
});
}

233
src/V3DfgDataType.h Normal file
View File

@ -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 <memory>
#include <unordered_map>
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<uint32_t, const DfgDataType*> s_packedTypes;
// Map from 'elements' -> 'interned Array DfgDataType with that many elements of *this* type'
mutable std::unordered_map<uint32_t, const DfgDataType*> 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<int>(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

View File

@ -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.

View File

@ -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:

View File

@ -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<int>(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<DfgVarPacked>();
} else {
const std::string name = dfg.makeUniqueName("BinToOneHot_Idx", nTables);
varp = dfg.makeNewVar(flp, name, idxDTypep, nullptr)->as<DfgVarPacked>();
varp = dfg.makeNewVar(flp, name, idxDType, nullptr)->as<DfgVarPacked>();
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<DfgVarArray>();
= dfg.makeNewVar(flp, name, tabDType, nullptr)->as<DfgVarArray>();
varp->varp()->isInternal(true);
varp->varp()->noReset(true);
varp->setHasModWrRefs();
@ -310,7 +308,7 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
const std::vector<Term>& 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;
};

View File

@ -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

View File

@ -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) {

View File

@ -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 <typename Vertex, typename... Operands>
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<Vertex, Operands...>(flp, dtypep, operands...);
Vertex* const vtxp = m_cache.getOrCreate<Vertex, Operands...>(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 <typename Vertex, typename... Operands>
Vertex* make(const DfgVertex* examplep, Operands... operands) {
return make<Vertex>(examplep->fileline(), examplep->dtypep(), operands...);
return make<Vertex>(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<DfgConcat, Vertex>::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<Vertex, DfgConcat>::value
? DfgDataType::packed(bp->width() + cp->width())
: vtxp->dtype();
Vertex* const childp = make<Vertex>(vtxp->fileline(), childDtyptp, bp, cp);
Vertex* const rootp = make<Vertex>(alhsp->fileline(), rootDtyptp, ap, childp);
Vertex* const childp = make<Vertex>(vtxp->fileline(), childDType, bp, cp);
Vertex* const rootp = make<Vertex>(alhsp->fileline(), vtxp->dtype(), ap, childp);
replace(vtxp, rootp);
changed = true;
vtxp = rootp;
@ -484,31 +475,28 @@ class V3DfgPeephole final : public DfgVisitor {
template <typename Vertex>
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<DfgConst>() || concatp->rhsp()->is<DfgConst>() //
|| 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<Vertex>(flp, lDtypep, newLhsConstp, concatp->lhsp());
Vertex* const newLhsp = make<Vertex>(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<Vertex>(flp, rDtypep, newRhsConstp, concatp->rhsp());
Vertex* const newRhsp = make<Vertex>(flp, rDtype, newRhsConstp, concatp->rhsp());
// The replacement Concat vertex
DfgConcat* const newConcat = make<DfgConcat>(concatp, newLhsp, newRhsp);
@ -524,8 +512,6 @@ class V3DfgPeephole final : public DfgVisitor {
template <typename Vertex>
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<Reduction>()) {
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<Bitwise>(flp, lSrcp->dtypep(), lSrcp, rSrcp);
Bitwise* const bwp = make<Bitwise>(flp, lSrcp->dtype(), lSrcp, rSrcp);
Reduction* const redp = make<Reduction>(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<DfgNot>(vtxp, condp->elsep());
// The replacement Cond vertex
DfgCond* const newCondp = make<DfgCond>(condp->fileline(), vtxp->dtypep(),
DfgCond* const newCondp = make<DfgCond>(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<DfgNot>()) {
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<DfgEq>()) {
APPLYING(REPLACE_NOT_EQ) {
DfgNeq* const replacementp
= make<DfgNeq>(eqp->fileline(), vtxp->dtypep(), eqp->lhsp(), eqp->rhsp());
= make<DfgNeq>(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<DfgNeq>()) {
APPLYING(REPLACE_NOT_NEQ) {
DfgEq* const replacementp = make<DfgEq>(neqp->fileline(), vtxp->dtypep(),
neqp->lhsp(), neqp->rhsp());
DfgEq* const replacementp
= make<DfgEq>(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<DfgSel>(flp, dtypePacked(lSelWidth), lhsp, 0U);
DfgSel* const newLhsp
= make<DfgSel>(flp, DfgDataType::packed(lSelWidth), lhsp, 0U);
// The new Rhs vertex
DfgSel* const newRhsp = make<DfgSel>(flp, dtypePacked(rSelWidth), rhsp, lsb);
DfgSel* const newRhsp
= make<DfgSel>(flp, DfgDataType::packed(rSelWidth), rhsp, lsb);
// The replacement Concat vertex
DfgConcat* const newConcat
= make<DfgConcat>(concatp->fileline(), vtxp->dtypep(), newLhsp, newRhsp);
= make<DfgConcat>(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<DfgNot>()) {
// 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<DfgSel>(vtxp, notp->srcp(), vtxp->lsb());
// Add Not after Sel
DfgNot* const replacementp
= make<DfgNot>(notp->fileline(), vtxp->dtypep(), newSelp);
= make<DfgNot>(notp->fileline(), vtxp->dtype(), newSelp);
replace(vtxp, replacementp);
}
}
@ -898,7 +874,7 @@ class V3DfgPeephole final : public DfgVisitor {
DfgSel* const newElsep = make<DfgSel>(vtxp, condp->elsep(), lsb);
// The replacement Cond vertex
DfgCond* const newCondp = make<DfgCond>(condp->fileline(), vtxp->dtypep(),
DfgCond* const newCondp = make<DfgCond>(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<DfgSel>(vtxp, shiftLp->lhsp(), vtxp->lsb());
DfgShiftL* const replacementp = make<DfgShiftL>(
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<DfgConcat>()) {
if (DfgConcat* const rhsConcatp = rhsp->cast<DfgConcat>()) {
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<DfgConst>();
if (DfgSel* const rSelp = rhsp->cast<DfgSel>()) {
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<DfgShiftR>(
vtxp, rSelp->fromp(), makeI32(flp, lConstp->width()));
@ -1286,7 +1246,7 @@ class V3DfgPeephole final : public DfgVisitor {
if (isZero(rhsp)) {
DfgConst* const rConstp = rhsp->as<DfgConst>();
if (DfgSel* const lSelp = lhsp->cast<DfgSel>()) {
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<DfgShiftL>(
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<DfgSel>(flp, dtypePacked(width), rSelp->fromp(), rSelp->lsb());
return make<DfgSel>(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<DfgNot>(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<DfgCond>(
vtxp, vtxp->condp(), thenNotp->srcp(), elseNotp->srcp());
DfgNot* const replacementp
= make<DfgNot>(thenp->fileline(), vtxp->dtypep(), newCondp);
= make<DfgNot>(thenp->fileline(), vtxp->dtype(), newCondp);
replace(vtxp, replacementp);
return;
}
@ -1666,8 +1615,8 @@ class V3DfgPeephole final : public DfgVisitor {
DfgConcat* const extp = make<DfgConcat>(
vtxp, makeZero(flp, vtxp->width() - 1), condp);
FileLine* const thenFlp = thenAddp->fileline();
DfgAdd* const addp = make<DfgAdd>(thenFlp, vtxp->dtypep(),
thenAddp->rhsp(), extp);
DfgAdd* const addp
= make<DfgAdd>(thenFlp, vtxp->dtype(), thenAddp->rhsp(), extp);
replace(vtxp, addp);
return;
}
@ -1684,8 +1633,8 @@ class V3DfgPeephole final : public DfgVisitor {
DfgConcat* const extp = make<DfgConcat>(
vtxp, makeZero(flp, vtxp->width() - 1), condp);
FileLine* const thenFlp = thenSubp->fileline();
DfgSub* const subp = make<DfgSub>(thenFlp, vtxp->dtypep(),
thenSubp->lhsp(), extp);
DfgSub* const subp
= make<DfgSub>(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<DfgNot>(vtxp, condp);

View File

@ -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

View File

@ -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 <typename T_Vertex, typename T_Node>
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<DfgArraySel, AstArraySel>(const AstArraySel* nodep, DfgGraph& dfg) {
DfgArraySel* makeVertex<DfgArraySel, AstArraySel>(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<DfgVarPacked>()) {
newp->srcp(make<DfgSplicePacked>(newp->fileline(), newp->dtypep()));
newp->srcp(make<DfgSplicePacked>(newp->fileline(), newp->dtype()));
} else if (newp->is<DfgVarArray>()) {
newp->srcp(make<DfgSpliceArray>(newp->fileline(), newp->dtypep()));
newp->srcp(make<DfgSpliceArray>(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<uint32_t>(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<DfgSplicePacked>(flp, dtypep);
AstNodeDType* const uaDtypep = V3Dfg::dtypeArray(dtypep, 1);
DfgUnitArray* const uap = make<DfgUnitArray>(flp, uaDtypep);
// This should never fail
const DfgDataType& dtype = *DfgDataType::fromAst(nodep->dtypep());
if (dtype.isPacked()) {
DfgSplicePacked* const newp = make<DfgSplicePacked>(flp, dtype);
const DfgDataType& uaDtype = DfgDataType::array(dtype, 1);
DfgUnitArray* const uap = make<DfgUnitArray>(flp, uaDtype);
uap->srcp(newp);
splicep->addDriver(uap, index, flp);
} else if (VN_IS(dtypep, UnpackArrayDType)) {
DfgSpliceArray* const newp = make<DfgSpliceArray>(flp, dtypep);
} else if (dtype.isArray()) {
DfgSpliceArray* const newp = make<DfgSpliceArray>(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<DfgVertexVar>() && !vtxp->is<DfgConst>()) {
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<DfgSel>(subp->fileline(), V3Dfg::toDfgDType(subp->dtypep()));
const DfgDataType& dtype = *DfgDataType::fromAst(subp->dtypep());
DfgSel* const selp = make<DfgSel>(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<DfgSplicePacked>()) {
spp->addDriver(item.m_rhsp, item.m_idx, flp);
} else if (DfgSpliceArray* const sap = item.m_lhsp->template cast<DfgSpliceArray>()) {
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<DfgUnitArray>(flp, V3Dfg::dtypeArray(rDtp, 1));
DfgUnitArray* const uap = make<DfgUnitArray>(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<DfgConst>(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<DfgConst>(nodep->fileline(), num);
nodep->user2p(vtxp);
} else {
DfgVertex* const vtxp = make<DfgConst>(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<DfgSel>(flp, V3Dfg::toDfgDType(nodep->dtypep()));
const uint32_t lsb = constp->toUInt();
const uint32_t msb = lsb + nodep->widthConst() - 1;
DfgSel* const selp = make<DfgSel>(flp, *dtypep);
selp->fromp(nodep->fromp()->user2u().to<DfgVertex*>());
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<DfgMux>(flp, V3Dfg::toDfgDType(nodep->dtypep()));
DfgMux* const muxp = make<DfgMux>(flp, *dtypep);
muxp->fromp(nodep->fromp()->user2u().to<DfgVertex*>());
muxp->lsbp(nodep->lsbp()->user2u().to<DfgVertex*>());
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<AstVarScope*>(varp)->varp()
: reinterpret_cast<AstVar*>(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<DfgSplicePacked>();
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<Driver> 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<DfgSplicePacked>(flp, aSp->dtypep());
DfgSplicePacked* const splicep = make<DfgSplicePacked>(flp, aSp->dtype());
for (const Driver& d : abDrivers) splicep->addDriver(d.m_vtxp, d.m_lo, d.m_flp);
DfgUnitArray* const uap = make<DfgUnitArray>(flp, aUap->dtypep());
DfgUnitArray* const uap = make<DfgUnitArray>(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<DfgConcat>(iD.m_flp, dtypep);
const DfgDataType& dt = DfgDataType::packed(iD.m_vtxp->width() + jD.m_vtxp->width());
DfgConcat* const concatp = make<DfgConcat>(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<DfgVarPacked>()) {
splicep = make<DfgSplicePacked>(var.fileline(), var.dtypep());
splicep = make<DfgSplicePacked>(var.fileline(), var.dtype());
} else if (var.is<DfgVarArray>()) {
splicep = make<DfgSpliceArray>(var.fileline(), var.dtypep());
splicep = make<DfgSpliceArray>(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<DfgSplicePacked>(flp, joinp->dtypep());
DfgVertexSplice* const joinSplicep = make<DfgSplicePacked>(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<DfgCond>(flp, joinp->dtypep());
DfgCond* const condp = make<DfgCond>(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<DfgCond>(flp, dtypep);
const DfgDataType& dtype = DfgDataType::packed(tDriver.m_hi - tDriver.m_lo + 1);
DfgCond* const condp = make<DfgCond>(flp, dtype);
condp->condp(predicatep);
// We actally need to select the bits from the joined variables, not use the drivers
DfgSel* const thenSelp = make<DfgSel>(flp, tDriver.m_vtxp->dtypep());
DfgSel* const thenSelp = make<DfgSel>(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<DfgSel>(flp, eDriver.m_vtxp->dtypep());
DfgSel* const elseSelp = make<DfgSel>(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<DfgSel>(flp, V3Dfg::dtypePacked(msb - lsb + 1));
DfgSel* const selp = make<DfgSel>(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<DfgNeq>(flp, V3Dfg::dtypePacked(1));
DfgNeq* const neqp = make<DfgNeq>(flp, DfgDataType::packed(1));
neqp->lhsp(make<DfgConst>(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<const CfgEdge&>(*it)];
while (++it != inEdges.end()) {
DfgOr* const orp = make<DfgOr>(resp->fileline(), resp->dtypep());
DfgOr* const orp = make<DfgOr>(resp->fileline(), resp->dtype());
orp->rhsp(resp);
orp->lhsp(m_edgeToPredicatep[static_cast<const CfgEdge&>(*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<DfgAnd>(flp, dtypep);
DfgAnd* const takenPredp = make<DfgAnd>(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<DfgAnd>(flp, dtypep);
DfgAnd* const untknPredp = make<DfgAnd>(flp, dtype);
untknPredp->lhsp(pInp);
DfgNot* const notp = make<DfgNot>(flp, dtypep);
DfgNot* const notp = make<DfgNot>(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<Driver> 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);
}
}
};

View File

@ -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<int>(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<DriverData> 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<CfgGraph> 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 ""; }

View File

@ -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<Dfg{t}>(nodep, m_dfg);\n".format(t=node.name))
" Dfg{t}* const vtxp = makeVertex<Dfg{t}>(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")

View File

@ -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": []}
]}
]}
]}

View File

@ -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": []}
]}
]}
]}

View File

@ -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": []}
]}
]}
]}

View File

@ -80,6 +80,7 @@
<basicdtype loc="d,34,24,34,27" id="2" name="logic"/>
<basicdtype loc="d,15,16,15,17" id="1" name="logic" left="3" right="0"/>
<basicdtype loc="d,19,18,19,19" id="3" name="logic" left="31" right="0" signed="true"/>
<voiddtype loc="a,0,0,0,0" id="4"/>
</typetable>
</netlist>
</verilator_xml>

View File

@ -109,6 +109,7 @@
<basicdtype loc="d,34,24,34,27" id="2" name="logic"/>
<basicdtype loc="d,15,16,15,17" id="1" name="logic" left="3" right="0"/>
<basicdtype loc="d,19,18,19,19" id="3" name="logic" left="31" right="0" signed="true"/>
<voiddtype loc="a,0,0,0,0" id="4"/>
</typetable>
</netlist>
</verilator_xml>

View File

@ -210,6 +210,7 @@
<basicdtype loc="d,19,11,19,12" id="8" name="logic" left="31" right="0"/>
<basicdtype loc="d,19,20,19,21" id="7" name="logic" left="3" right="0" signed="true"/>
<basicdtype loc="d,18,12,18,13" id="4" name="logic" left="31" right="0" signed="true"/>
<voiddtype loc="a,0,0,0,0" id="10"/>
</typetable>
</netlist>
</verilator_xml>