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:
parent
f67534069c
commit
6bc48fcdb3
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -247,6 +247,7 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||
V3DfgCache.o \
|
||||
V3DfgColorSCCs.o \
|
||||
V3DfgCse.o \
|
||||
V3DfgDataType.o \
|
||||
V3DfgDecomposition.o \
|
||||
V3DfgDfgToAst.o \
|
||||
V3DfgOptimizer.o \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
67
src/V3Dfg.h
67
src/V3Dfg.h
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Cfg.h"
|
||||
#include "V3DfgDataType.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Hash.h"
|
||||
|
|
@ -71,16 +72,13 @@ namespace V3Dfg {
|
|||
//-----------------------------------------------------------------------
|
||||
// Functions for compatibility tests
|
||||
|
||||
// Returns true if the given data type can be represented in the graph
|
||||
bool isSupported(const AstNodeDType* dtypep) VL_MT_DISABLED;
|
||||
|
||||
// Returns true if variable can be represented in the graph
|
||||
inline bool isSupported(const AstVar* varp) {
|
||||
if (varp->isIfaceRef()) return false; // Cannot handle interface references
|
||||
if (varp->delayp()) return false; // Cannot handle delayed variables
|
||||
if (varp->isSc()) return false; // SystemC variables are special and rare, we can ignore
|
||||
if (varp->dfgMultidriven()) return false; // Discovered as multidriven on earlier DFG run
|
||||
return isSupported(varp->dtypep());
|
||||
return DfgDataType::fromAst(varp->dtypep());
|
||||
}
|
||||
|
||||
// Returns true if variable can be represented in the graph
|
||||
|
|
@ -99,38 +97,6 @@ inline bool isSupported(const AstVarScope* vscp) {
|
|||
return isSupported(vscp->varp());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Functions for data types
|
||||
|
||||
// Some data types are interned, in order to facilitate type comparison
|
||||
// via pointer compariosn. These are functoins to construct the canonical
|
||||
// DFG data types
|
||||
|
||||
// Returns data type used to represent any packed value of the given 'width'.
|
||||
inline AstNodeDType* dtypePacked(uint32_t width) {
|
||||
return v3Global.rootp()->typeTablep()->findLogicDType(width, width, VSigning::UNSIGNED);
|
||||
}
|
||||
|
||||
// Returns data type used to represent any array with the given type and number of elements.
|
||||
inline AstNodeDType* dtypeArray(AstNodeDType* subDtypep, uint32_t size) {
|
||||
UASSERT_OBJ(isSupported(subDtypep), subDtypep, "Unsupported element type");
|
||||
FileLine* const flp = subDtypep->fileline();
|
||||
AstRange* const rangep = new AstRange{flp, static_cast<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).
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 ""; }
|
||||
|
|
|
|||
18
src/astgen
18
src/astgen
|
|
@ -1221,8 +1221,8 @@ def write_dfg_auto_classes(filename):
|
|||
emitBlock('''\
|
||||
class Dfg{t} final : public Dfg{s} {{
|
||||
public:
|
||||
Dfg{t}(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep)
|
||||
: Dfg{s}{{dfg, dfgType(), flp, dtypep}} {{}}
|
||||
Dfg{t}(DfgGraph& dfg, FileLine* flp, const DfgDataType& dtype)
|
||||
: Dfg{s}{{dfg, dfgType(), flp, dtype}} {{}}
|
||||
ASTGEN_MEMBERS_Dfg{t};
|
||||
}};
|
||||
''',
|
||||
|
|
@ -1244,7 +1244,7 @@ def write_dfg_clone_cases(filename):
|
|||
|
||||
emitBlock('''\
|
||||
case VDfgType::{t}: {{
|
||||
Dfg{t}* const cp = new Dfg{t}{{*clonep, vtx.fileline(), vtx.dtypep()}};
|
||||
Dfg{t}* const cp = new Dfg{t}{{*clonep, vtx.fileline(), vtx.dtype()}};
|
||||
vtxp2clonep.emplace(&vtx, cp);
|
||||
break;
|
||||
}}
|
||||
|
|
@ -1267,6 +1267,15 @@ def write_dfg_ast_to_dfg(filename):
|
|||
)
|
||||
fh.write(' UASSERT_OBJ(!nodep->user2p(), nodep, "Already has Dfg vertex");\n\n')
|
||||
fh.write(" if (unhandled(nodep)) return;\n\n")
|
||||
|
||||
fh.write(
|
||||
" const DfgDataType* const dtypep = DfgDataType::fromAst(nodep->dtypep());\n")
|
||||
fh.write(" if (!dtypep) {\n")
|
||||
fh.write(" m_foundUnhandled = true;\n")
|
||||
fh.write(" ++m_ctx.m_conv.nonRepDType;\n")
|
||||
fh.write(" return;\n")
|
||||
fh.write(" }\n\n")
|
||||
|
||||
for i in range(node.arity):
|
||||
fh.write(" iterate(nodep->op{j}p());\n".format(j=i + 1))
|
||||
fh.write(" if (m_foundUnhandled) return;\n")
|
||||
|
|
@ -1275,7 +1284,8 @@ def write_dfg_ast_to_dfg(filename):
|
|||
.format(j=i + 1))
|
||||
fh.write("\n")
|
||||
fh.write(
|
||||
" Dfg{t}* const vtxp = makeVertex<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")
|
||||
|
|
|
|||
|
|
@ -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": []}
|
||||
]}
|
||||
]}
|
||||
]}
|
||||
|
|
|
|||
|
|
@ -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": []}
|
||||
]}
|
||||
]}
|
||||
]}
|
||||
|
|
|
|||
|
|
@ -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": []}
|
||||
]}
|
||||
]}
|
||||
]}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue