Merge b998721513 into 2736262b98
This commit is contained in:
commit
9b323b7786
|
|
@ -649,9 +649,12 @@ Summary:
|
|||
|
||||
.. option:: -fno-dfg
|
||||
|
||||
Rarely needed. Disable all use of the DFG-based combinational logic
|
||||
optimizer. Alias for :vlopt:`-fno-dfg-pre-inline`,
|
||||
:vlopt:`-fno-dfg-post-inline` and :vlopt:`-fno-dfg-scoped`.
|
||||
Rarely needed. Disable the DFG-based combinational logic optimizer.
|
||||
|
||||
In versions before 5.048:
|
||||
|
||||
Alias for :vlopt:`-fno-dfg-pre-inline`, :vlopt:`-fno-dfg-post-inline` and
|
||||
:vlopt:`-fno-dfg-scoped`.
|
||||
|
||||
.. option:: -fno-dfg-break-cycles
|
||||
|
||||
|
|
@ -667,11 +670,15 @@ Summary:
|
|||
|
||||
.. option:: -fno-dfg-post-inline
|
||||
|
||||
Rarely needed. Do not apply the DFG optimizer after inlining.
|
||||
Deprecated and has no effect (ignored).
|
||||
|
||||
In versions before 5.048: Do not apply the DFG optimizer after inlining.
|
||||
|
||||
.. option:: -fno-dfg-pre-inline
|
||||
|
||||
Rarely needed. Do not apply the DFG optimizer before inlining.
|
||||
Deprecated and has no effect (ignored).
|
||||
|
||||
In versions before 5.048: Do not apply the DFG optimizer before inlining.
|
||||
|
||||
.. option:: -fno-dfg-push-down-sels
|
||||
|
||||
|
|
@ -679,7 +686,10 @@ Summary:
|
|||
|
||||
.. option:: -fno-dfg-scoped
|
||||
|
||||
Rarely needed. Do not apply the DFG optimizer across module scopes.
|
||||
Deprecated; use :vlopt:`-fno-dfg` instead.
|
||||
|
||||
In versions before 5.048: Do not apply the DFG optimizer across module
|
||||
scopes.
|
||||
|
||||
.. option:: -fno-expand
|
||||
|
||||
|
|
|
|||
|
|
@ -1964,7 +1964,6 @@ class AstVar final : public AstNode {
|
|||
bool m_ignorePostRead : 1; // Ignore reads in 'Post' blocks during ordering
|
||||
bool m_ignorePostWrite : 1; // Ignore writes in 'Post' blocks during ordering
|
||||
bool m_ignoreSchedWrite : 1; // Ignore writes in scheduling (for special optimizations)
|
||||
bool m_dfgMultidriven : 1; // Singal is multidriven, used by DFG to avoid repeat processing
|
||||
bool m_dfgTriLowered : 1; // Signal/temporary introduced by tristate lowering
|
||||
bool m_dfgAllowMultidriveTri : 1; // Allow DFG MULTIDRIVEN warning for intentional tri nets
|
||||
bool m_globalConstrained : 1; // Global constraint per IEEE 1800-2023 18.5.8
|
||||
|
|
@ -2024,7 +2023,6 @@ class AstVar final : public AstNode {
|
|||
m_ignorePostRead = false;
|
||||
m_ignorePostWrite = false;
|
||||
m_ignoreSchedWrite = false;
|
||||
m_dfgMultidriven = false;
|
||||
m_dfgTriLowered = false;
|
||||
m_dfgAllowMultidriveTri = false;
|
||||
m_globalConstrained = false;
|
||||
|
|
@ -2206,8 +2204,6 @@ public:
|
|||
void setIgnorePostWrite() { m_ignorePostWrite = true; }
|
||||
bool ignoreSchedWrite() const { return m_ignoreSchedWrite; }
|
||||
void setIgnoreSchedWrite() { m_ignoreSchedWrite = true; }
|
||||
bool dfgMultidriven() const { return m_dfgMultidriven; }
|
||||
void setDfgMultidriven() { m_dfgMultidriven = true; }
|
||||
bool dfgTriLowered() const { return m_dfgTriLowered; }
|
||||
void setDfgTriLowered() { m_dfgTriLowered = true; }
|
||||
bool dfgAllowMultidriveTri() const { return m_dfgAllowMultidriveTri; }
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "V3Dfg.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3EmitV.h"
|
||||
#include "V3File.h"
|
||||
|
||||
|
|
@ -26,18 +27,16 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
//------------------------------------------------------------------------------
|
||||
// DfgGraph
|
||||
|
||||
DfgGraph::DfgGraph(AstModule* modulep, const string& name)
|
||||
: m_modulep{modulep}
|
||||
, m_name{name} {}
|
||||
DfgGraph::DfgGraph(const string& name)
|
||||
: m_name{name} {}
|
||||
|
||||
DfgGraph::~DfgGraph() {
|
||||
forEachVertex([&](DfgVertex& vtx) { vtx.unlinkDelete(*this); });
|
||||
}
|
||||
|
||||
std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
||||
const bool scoped = !modulep();
|
||||
|
||||
DfgGraph* const clonep = new DfgGraph{modulep(), name()};
|
||||
// Create the new graph
|
||||
DfgGraph* const clonep = new DfgGraph{name()};
|
||||
|
||||
// Map from original vertex to clone
|
||||
std::unordered_map<const DfgVertex*, DfgVertex*> vtxp2clonep(size() * 2);
|
||||
|
|
@ -54,20 +53,12 @@ std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
|||
|
||||
switch (vtx.type()) {
|
||||
case VDfgType::VarArray: {
|
||||
if (scoped) {
|
||||
cp = new DfgVarArray{*clonep, vp->varScopep()};
|
||||
} else {
|
||||
cp = new DfgVarArray{*clonep, vp->varp()};
|
||||
}
|
||||
cp = new DfgVarArray{*clonep, vp->vscp()};
|
||||
vtxp2clonep.emplace(&vtx, cp);
|
||||
break;
|
||||
}
|
||||
case VDfgType::VarPacked: {
|
||||
if (scoped) {
|
||||
cp = new DfgVarPacked{*clonep, vp->varScopep()};
|
||||
} else {
|
||||
cp = new DfgVarPacked{*clonep, vp->varp()};
|
||||
}
|
||||
cp = new DfgVarPacked{*clonep, vp->vscp()};
|
||||
vtxp2clonep.emplace(&vtx, cp);
|
||||
break;
|
||||
}
|
||||
|
|
@ -78,7 +69,7 @@ std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
|||
}
|
||||
}
|
||||
|
||||
if (AstNode* const tmpForp = vp->tmpForp()) cp->tmpForp(tmpForp);
|
||||
if (AstVarScope* const tmpForp = vp->tmpForp()) cp->tmpForp(tmpForp);
|
||||
}
|
||||
// Clone ast reference vertices
|
||||
for (const DfgVertexAst& vtx : m_astVertices) { // LCOV_EXCL_START
|
||||
|
|
@ -203,18 +194,18 @@ void DfgGraph::mergeGraphs(std::vector<std::unique_ptr<DfgGraph>>&& otherps) {
|
|||
if (otherps.empty()) return;
|
||||
|
||||
// NODE STATE
|
||||
// AstVar/AstVarScope::user2p() -> corresponding DfgVertexVar* in 'this' graph
|
||||
// AstVarScope::user2p() -> corresponding DfgVertexVar* in 'this' graph
|
||||
const VNUser2InUse user2InUse;
|
||||
|
||||
// Set up Ast Variable -> DfgVertexVar map for 'this' graph
|
||||
for (DfgVertexVar& vtx : m_varVertices) vtx.nodep()->user2p(&vtx);
|
||||
for (DfgVertexVar& vtx : m_varVertices) vtx.vscp()->user2p(&vtx);
|
||||
|
||||
// Merge in each of the other graphs
|
||||
for (const std::unique_ptr<DfgGraph>& otherp : otherps) {
|
||||
// Process variables
|
||||
for (DfgVertexVar* const vtxp : otherp->m_varVertices.unlinkable()) {
|
||||
// Variabels that are present in 'this', make them use the DfgVertexVar in 'this'.
|
||||
if (DfgVertexVar* const altp = vtxp->nodep()->user2u().to<DfgVertexVar*>()) {
|
||||
if (DfgVertexVar* const altp = vtxp->vscp()->user2u().to<DfgVertexVar*>()) {
|
||||
DfgVertex* const srcp = vtxp->srcp();
|
||||
DfgVertex* const defaultp = vtxp->defaultp();
|
||||
UASSERT_OBJ(!(srcp || defaultp) || (!altp->srcp() && !altp->defaultp()), vtxp,
|
||||
|
|
@ -226,7 +217,7 @@ void DfgGraph::mergeGraphs(std::vector<std::unique_ptr<DfgGraph>>&& otherps) {
|
|||
continue;
|
||||
}
|
||||
// Otherwise they will be moved
|
||||
vtxp->nodep()->user2p(vtxp);
|
||||
vtxp->vscp()->user2p(vtxp);
|
||||
vtxp->m_userGeneration = 0;
|
||||
#ifdef VL_DEBUG
|
||||
vtxp->m_dfgp = this;
|
||||
|
|
@ -279,29 +270,17 @@ std::string DfgGraph::makeUniqueName(const std::string& prefix, size_t n) {
|
|||
|
||||
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, dtype.astDtypep()};
|
||||
|
||||
if (scopep) {
|
||||
// Add AstVar to the scope's module
|
||||
scopep->modp()->addStmtsp(varp);
|
||||
// Create AstVarScope
|
||||
AstVarScope* const vscp = new AstVarScope{flp, scopep, varp};
|
||||
// Add to scope
|
||||
scopep->addVarsp(vscp);
|
||||
// Create and return the corresponding variable vertex
|
||||
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 (dtype.isArray()) return new DfgVarArray{*this, varp};
|
||||
return new DfgVarPacked{*this, varp};
|
||||
}
|
||||
// Add AstVar to the scope's module
|
||||
scopep->modp()->addStmtsp(varp);
|
||||
// Create AstVarScope
|
||||
AstVarScope* const vscp = new AstVarScope{flp, scopep, varp};
|
||||
// Add to scope
|
||||
scopep->addVarsp(vscp);
|
||||
// Create and return the corresponding variable vertex
|
||||
if (dtype.isArray()) return new DfgVarArray{*this, vscp};
|
||||
return new DfgVarPacked{*this, vscp};
|
||||
}
|
||||
|
||||
static const std::string toDotId(const DfgVertex& vtx) { return '"' + cvtToHex(&vtx) + '"'; }
|
||||
|
|
@ -309,19 +288,19 @@ static const std::string toDotId(const DfgVertex& vtx) { return '"' + cvtToHex(&
|
|||
// Dump one DfgVertex in Graphviz format
|
||||
static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) {
|
||||
if (const DfgVertexVar* const varVtxp = vtx.cast<DfgVertexVar>()) {
|
||||
const AstNode* const nodep = varVtxp->nodep();
|
||||
const AstVarScope* const vscp = varVtxp->vscp();
|
||||
os << toDotId(vtx);
|
||||
// Begin attributes
|
||||
os << " [";
|
||||
// Begin 'label'
|
||||
os << "label=\"";
|
||||
// Name
|
||||
os << nodep->prettyName();
|
||||
os << vscp->prettyName();
|
||||
// Address
|
||||
os << '\n' << cvtToHex(varVtxp);
|
||||
// Original variable, if any
|
||||
if (const AstNode* const tmpForp = varVtxp->tmpForp()) {
|
||||
if (tmpForp != nodep) os << "\ntemporary for: " << tmpForp->prettyName();
|
||||
if (const AstVarScope* const tmpForp = varVtxp->tmpForp()) {
|
||||
if (tmpForp != vscp) os << "\ntemporary for: " << tmpForp->prettyName();
|
||||
}
|
||||
// Type and fanout
|
||||
os << '\n';
|
||||
|
|
@ -877,10 +856,8 @@ DfgVertexVar* DfgVertex::getResultVar() {
|
|||
}
|
||||
|
||||
// Prefer real variables over temporaries
|
||||
const bool resIsTemp
|
||||
= resp->varp() ? resp->varp()->isTemp() : resp->varScopep()->varp()->isTemp();
|
||||
const bool varIsTemp
|
||||
= varp->varp() ? varp->varp()->isTemp() : varp->varScopep()->varp()->isTemp();
|
||||
const bool resIsTemp = resp->vscp()->varp()->isTemp();
|
||||
const bool varIsTemp = varp->vscp()->varp()->isTemp();
|
||||
if (resIsTemp != varIsTemp) {
|
||||
if (resIsTemp) resp = varp;
|
||||
return false;
|
||||
|
|
@ -898,7 +875,7 @@ DfgVertexVar* DfgVertex::getResultVar() {
|
|||
return false;
|
||||
}
|
||||
// Prefer the one with the lexically smaller name
|
||||
if (const int cmp = resp->nodep()->name().compare(varp->nodep()->name())) {
|
||||
if (const int cmp = resp->vscp()->name().compare(varp->vscp()->name())) {
|
||||
if (cmp > 0) resp = varp;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -911,13 +888,13 @@ DfgVertexVar* DfgVertex::getResultVar() {
|
|||
AstScope* DfgVertex::scopep(ScopeCache& cache, bool tryResultVar) VL_MT_DISABLED {
|
||||
// If this is a variable, we are done
|
||||
if (const DfgVertexVar* const varp = this->cast<DfgVertexVar>()) {
|
||||
return varp->varScopep()->scopep();
|
||||
return varp->vscp()->scopep();
|
||||
}
|
||||
|
||||
// Try the result var first if instructed (usully only in the recursive case)
|
||||
if (tryResultVar) {
|
||||
if (const DfgVertexVar* const varp = this->getResultVar()) {
|
||||
return varp->varScopep()->scopep();
|
||||
return varp->vscp()->scopep();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
23
src/V3Dfg.h
23
src/V3Dfg.h
|
|
@ -386,9 +386,6 @@ class DfgGraph final {
|
|||
DfgVertex::List<DfgConst> m_constVertices; // The constant vertices in the graph
|
||||
DfgVertex::List<DfgVertex> m_opVertices; // The operation vertices in the graph
|
||||
size_t m_size = 0; // Number of vertices in the graph
|
||||
// Parent of the graph (i.e.: the module containing the logic represented by this graph),
|
||||
// or nullptr when run after V3Scope
|
||||
AstModule* const m_modulep;
|
||||
const std::string m_name; // Name of graph - need not be unique
|
||||
std::string m_tmpNameStub{""}; // Name stub for temporary variables - computed lazy
|
||||
|
||||
|
|
@ -399,15 +396,13 @@ class DfgGraph final {
|
|||
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
explicit DfgGraph(AstModule* modulep, const string& name = "") VL_MT_DISABLED;
|
||||
explicit DfgGraph(const string& name = "") VL_MT_DISABLED;
|
||||
~DfgGraph() VL_MT_DISABLED;
|
||||
VL_UNCOPYABLE(DfgGraph);
|
||||
|
||||
// METHODS
|
||||
// Number of vertices in this graph
|
||||
size_t size() const { return m_size; }
|
||||
// Parent module - or nullptr when run after V3Scope
|
||||
AstModule* modulep() const { return m_modulep; }
|
||||
// Name of this graph
|
||||
const string& name() const { return m_name; }
|
||||
|
||||
|
|
@ -558,16 +553,6 @@ namespace V3Dfg {
|
|||
//-----------------------------------------------------------------------
|
||||
// Functions for compatibility tests
|
||||
|
||||
// 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
|
||||
if (DfgVertexVar::hasRWRefs(varp)) return false; // Referenced via READWRITE references
|
||||
return DfgDataType::fromAst(varp->dtypep());
|
||||
}
|
||||
|
||||
// Returns true if variable can be represented in the graph
|
||||
inline bool isSupported(const AstVarScope* vscp) {
|
||||
const AstNodeModule* const modp = vscp->scopep()->modp();
|
||||
|
|
@ -582,7 +567,11 @@ inline bool isSupported(const AstVarScope* vscp) {
|
|||
}
|
||||
if (DfgVertexVar::hasRWRefs(vscp)) return false; // Referenced via READWRITE references
|
||||
// Check the AstVar
|
||||
return isSupported(vscp->varp());
|
||||
AstVar* const varp = vscp->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
|
||||
return DfgDataType::fromAst(varp->dtypep());
|
||||
}
|
||||
|
||||
} //namespace V3Dfg
|
||||
|
|
|
|||
|
|
@ -30,28 +30,14 @@
|
|||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
template <bool T_Scoped>
|
||||
class AstToDfgAddAstRefs final : public VNVisitorConst {
|
||||
// TYPES
|
||||
using Variable = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
||||
|
||||
// STATE
|
||||
DfgGraph& m_dfg; // The graph being processed
|
||||
// Function to get the DfgVertexVar for a Variable
|
||||
const std::function<DfgVertexVar*(Variable*)> m_getVarVertex;
|
||||
// Function to get the DfgVertexVar for a AstVarScope
|
||||
const std::function<DfgVertexVar*(AstVarScope*)> m_getVarVertex;
|
||||
bool m_inSenItem = false; // Inside an AstSenItem
|
||||
bool m_inLoop = false; // Inside an AstLoop
|
||||
|
||||
// METHODS
|
||||
static Variable* getTarget(const AstVarRef* refp) {
|
||||
// TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
return reinterpret_cast<Variable*>(refp->varScopep());
|
||||
} else {
|
||||
return reinterpret_cast<Variable*>(refp->varp());
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
|
|
@ -71,12 +57,12 @@ class AstToDfgAddAstRefs final : public VNVisitorConst {
|
|||
// Disguised hierarchical reference handled as external reference, ignore
|
||||
if (nodep->classOrPackagep()) return;
|
||||
// If target is not supported, ignore
|
||||
Variable* const tgtp = getTarget(nodep);
|
||||
if (!V3Dfg::isSupported(tgtp)) return;
|
||||
AstVarScope* const vscp = nodep->varScopep();
|
||||
if (!V3Dfg::isSupported(vscp)) return;
|
||||
// V3Dfg::isSupported should reject vars with READWRITE references
|
||||
UASSERT_OBJ(!nodep->access().isRW(), nodep, "Variable with READWRITE ref not rejected");
|
||||
UASSERT_OBJ(!nodep->access().isRW(), nodep, "AstVarScope with READWRITE ref not rejected");
|
||||
// Get target variable vergtex, ignore if not given one
|
||||
DfgVertexVar* const varp = m_getVarVertex(tgtp);
|
||||
DfgVertexVar* const varp = m_getVarVertex(vscp);
|
||||
if (!varp) return;
|
||||
// Create Ast reference vertices
|
||||
if (nodep->access().isReadOnly()) {
|
||||
|
|
@ -85,11 +71,11 @@ class AstToDfgAddAstRefs final : public VNVisitorConst {
|
|||
return;
|
||||
}
|
||||
// Mark as written from non-DFG logic
|
||||
DfgVertexVar::setHasModWrRefs(tgtp);
|
||||
DfgVertexVar::setHasModWrRefs(vscp);
|
||||
}
|
||||
|
||||
AstToDfgAddAstRefs(DfgGraph& dfg, AstNode* nodep,
|
||||
std::function<DfgVertexVar*(Variable*)> getVarVertex)
|
||||
std::function<DfgVertexVar*(AstVarScope*)> getVarVertex)
|
||||
: m_dfg{dfg}
|
||||
, m_getVarVertex{getVarVertex} {
|
||||
iterateConst(nodep);
|
||||
|
|
@ -97,67 +83,37 @@ class AstToDfgAddAstRefs final : public VNVisitorConst {
|
|||
|
||||
public:
|
||||
static void apply(DfgGraph& dfg, AstNode* nodep,
|
||||
std::function<DfgVertexVar*(Variable*)> getVarVertex) {
|
||||
std::function<DfgVertexVar*(AstVarScope*)> getVarVertex) {
|
||||
AstToDfgAddAstRefs{dfg, nodep, getVarVertex};
|
||||
}
|
||||
};
|
||||
|
||||
void V3DfgPasses::addAstRefs(DfgGraph& dfg, AstNode* nodep,
|
||||
std::function<DfgVertexVar*(AstNode*)> getVarVertex) {
|
||||
if (dfg.modulep()) {
|
||||
AstToDfgAddAstRefs</* T_Scoped: */ false>::apply(dfg, nodep, getVarVertex);
|
||||
} else {
|
||||
AstToDfgAddAstRefs</* T_Scoped: */ true>::apply(dfg, nodep, getVarVertex);
|
||||
}
|
||||
std::function<DfgVertexVar*(AstVarScope*)> getVarVertex) {
|
||||
AstToDfgAddAstRefs::apply(dfg, nodep, getVarVertex);
|
||||
}
|
||||
|
||||
template <bool T_Scoped>
|
||||
class AstToDfgVisitor final : public VNVisitor {
|
||||
// NODE STATE
|
||||
// AstVar/AstVarScope::user2() -> DfgVertexVar* : the corresponding variable vertex
|
||||
// AstVar/AstVarScope::user3() -> bool : Already gathered - used fine grained below
|
||||
// AstVarScope::user2() -> DfgVertexVar* : the corresponding variable vertex
|
||||
// AstVarScope::user3() -> bool : Already gathered - used fine grained below
|
||||
const VNUser2InUse m_user2InUse;
|
||||
|
||||
// TYPES
|
||||
using RootType = std::conditional_t<T_Scoped, AstNetlist, AstModule>;
|
||||
using Variable = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
||||
|
||||
// STATE
|
||||
DfgGraph& m_dfg; // The graph being built
|
||||
V3DfgAstToDfgContext& m_ctx; // The context for stats
|
||||
AstScope* m_scopep = nullptr; // The current scope, iff T_Scoped
|
||||
|
||||
// METHODS
|
||||
static Variable* getTarget(const AstVarRef* refp) {
|
||||
// TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
return reinterpret_cast<Variable*>(refp->varScopep());
|
||||
} else {
|
||||
return reinterpret_cast<Variable*>(refp->varp());
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<Variable*>> getLiveVariables(const CfgGraph& cfg) {
|
||||
// TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
std::unique_ptr<std::vector<AstVarScope*>> result = V3Cfg::liveVarScopes(cfg);
|
||||
const auto resultp = reinterpret_cast<std::vector<Variable*>*>(result.release());
|
||||
return std::unique_ptr<std::vector<Variable*>>{resultp};
|
||||
} else {
|
||||
std::unique_ptr<std::vector<AstVar*>> result = V3Cfg::liveVars(cfg);
|
||||
const auto resultp = reinterpret_cast<std::vector<Variable*>*>(result.release());
|
||||
return std::unique_ptr<std::vector<Variable*>>{resultp};
|
||||
}
|
||||
}
|
||||
|
||||
// Mark variables referenced under node
|
||||
void markReferenced(AstNode* nodep) {
|
||||
V3DfgPasses::addAstRefs(m_dfg, nodep, [this](AstNode* varp) { //
|
||||
return getVarVertex(static_cast<Variable*>(varp));
|
||||
V3DfgPasses::addAstRefs(m_dfg, nodep, [this](AstVarScope* vscp) { //
|
||||
return getVarVertex(vscp);
|
||||
});
|
||||
}
|
||||
|
||||
DfgVertexVar* getVarVertex(Variable* varp) {
|
||||
DfgVertexVar* getVarVertex(AstVarScope* varp) {
|
||||
if (!varp->user2p()) {
|
||||
// TODO: fix this up when removing the different flavours of DfgVar
|
||||
const AstNodeDType* const dtypep = varp->dtypep()->skipRefp();
|
||||
|
|
@ -175,14 +131,11 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
std::unique_ptr<std::vector<DfgVertexVar*>> gatherWritten(const AstNode* nodep) {
|
||||
const VNUser3InUse user3InUse;
|
||||
std::unique_ptr<std::vector<DfgVertexVar*>> resp{new std::vector<DfgVertexVar*>{}};
|
||||
// We can ignore AstVarXRef here. The only thing we can do with DfgLogic is
|
||||
// synthesize it into regular vertices, which will fail on a VarXRef at that point.
|
||||
const bool abort = nodep->exists([&](const AstNodeVarRef* vrefp) -> bool {
|
||||
if (VN_IS(vrefp, VarXRef)) return true;
|
||||
if (vrefp->access().isReadOnly()) return false;
|
||||
Variable* const varp = getTarget(VN_AS(vrefp, VarRef));
|
||||
if (!V3Dfg::isSupported(varp)) return true;
|
||||
if (!varp->user3SetOnce()) resp->emplace_back(getVarVertex(varp));
|
||||
const bool abort = nodep->exists([&](const AstVarRef* refp) -> bool {
|
||||
if (refp->access().isReadOnly()) return false;
|
||||
AstVarScope* const vscp = refp->varScopep();
|
||||
if (!V3Dfg::isSupported(vscp)) return true;
|
||||
if (!vscp->user3SetOnce()) resp->emplace_back(getVarVertex(vscp));
|
||||
return false;
|
||||
});
|
||||
if (abort) {
|
||||
|
|
@ -197,14 +150,11 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
std::unique_ptr<std::vector<DfgVertexVar*>> gatherRead(const AstNode* nodep) {
|
||||
const VNUser3InUse user3InUse;
|
||||
std::unique_ptr<std::vector<DfgVertexVar*>> resp{new std::vector<DfgVertexVar*>{}};
|
||||
// We can ignore AstVarXRef here. The only thing we can do with DfgLogic is
|
||||
// synthesize it into regular vertices, which will fail on a VarXRef at that point.
|
||||
const bool abort = nodep->exists([&](const AstNodeVarRef* vrefp) -> bool {
|
||||
if (VN_IS(vrefp, VarXRef)) return true;
|
||||
if (vrefp->access().isWriteOnly()) return false;
|
||||
Variable* const varp = getTarget(VN_AS(vrefp, VarRef));
|
||||
if (!V3Dfg::isSupported(varp)) return true;
|
||||
if (!varp->user3SetOnce()) resp->emplace_back(getVarVertex(varp));
|
||||
const bool abort = nodep->exists([&](const AstVarRef* refp) -> bool {
|
||||
if (refp->access().isWriteOnly()) return false;
|
||||
AstVarScope* const vscp = refp->varScopep();
|
||||
if (!V3Dfg::isSupported(vscp)) return true;
|
||||
if (!vscp->user3SetOnce()) resp->emplace_back(getVarVertex(vscp));
|
||||
return false;
|
||||
});
|
||||
if (abort) {
|
||||
|
|
@ -218,7 +168,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
// Return nullptr if any are not supported.
|
||||
std::unique_ptr<std::vector<DfgVertexVar*>> gatherLive(const CfgGraph& cfg) {
|
||||
// Run analysis
|
||||
std::unique_ptr<std::vector<Variable*>> varps = getLiveVariables(cfg);
|
||||
std::unique_ptr<std::vector<AstVarScope*>> varps = V3Cfg::liveVarScopes(cfg);
|
||||
if (!varps) {
|
||||
++m_ctx.m_nonRepLive;
|
||||
return nullptr;
|
||||
|
|
@ -228,7 +178,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
const VNUser3InUse user3InUse;
|
||||
std::unique_ptr<std::vector<DfgVertexVar*>> resp{new std::vector<DfgVertexVar*>{}};
|
||||
resp->reserve(varps->size());
|
||||
for (Variable* const varp : *varps) {
|
||||
for (AstVarScope* const varp : *varps) {
|
||||
if (!V3Dfg::isSupported(varp)) {
|
||||
++m_ctx.m_nonRepVar;
|
||||
return nullptr;
|
||||
|
|
@ -347,7 +297,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
// CONSTRUCTOR
|
||||
AstToDfgVisitor(DfgGraph& dfg, RootType& root, V3DfgAstToDfgContext& ctx)
|
||||
AstToDfgVisitor(DfgGraph& dfg, AstNetlist& root, V3DfgAstToDfgContext& ctx)
|
||||
: m_dfg{dfg}
|
||||
, m_ctx{ctx} {
|
||||
iterate(&root);
|
||||
|
|
@ -356,7 +306,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
VL_UNMOVABLE(AstToDfgVisitor);
|
||||
|
||||
public:
|
||||
static void apply(DfgGraph& dfg, RootType& root, V3DfgAstToDfgContext& ctx) {
|
||||
static void apply(DfgGraph& dfg, AstNetlist& root, V3DfgAstToDfgContext& ctx) {
|
||||
// Convert all logic under 'root'
|
||||
AstToDfgVisitor{dfg, root, ctx};
|
||||
// Remove unread and undriven variables (created when something failed to convert)
|
||||
|
|
@ -371,14 +321,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<DfgGraph> V3DfgPasses::astToDfg(AstModule& module, V3DfgContext& ctx) {
|
||||
DfgGraph* const dfgp = new DfgGraph{&module, module.name()};
|
||||
AstToDfgVisitor</* T_Scoped: */ false>::apply(*dfgp, module, ctx.m_ast2DfgContext);
|
||||
return std::unique_ptr<DfgGraph>{dfgp};
|
||||
}
|
||||
|
||||
std::unique_ptr<DfgGraph> V3DfgPasses::astToDfg(AstNetlist& netlist, V3DfgContext& ctx) {
|
||||
DfgGraph* const dfgp = new DfgGraph{nullptr, "netlist"};
|
||||
AstToDfgVisitor</* T_Scoped: */ true>::apply(*dfgp, netlist, ctx.m_ast2DfgContext);
|
||||
DfgGraph* const dfgp = new DfgGraph{"netlist"};
|
||||
AstToDfgVisitor::apply(*dfgp, netlist, ctx.m_ast2DfgContext);
|
||||
return std::unique_ptr<DfgGraph>{dfgp};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,15 +115,14 @@ class TraceDriver final : public DfgVisitor {
|
|||
|
||||
// Create temporary capable of holding the result of 'vtxp'
|
||||
DfgVertexVar* createTmp(const char* prefix, DfgVertex* vtxp) {
|
||||
AstNode* nodep = m_dfg.modulep();
|
||||
if (!nodep) nodep = v3Global.rootp();
|
||||
AstNode* nodep = v3Global.rootp();
|
||||
const std::string name = m_dfg.makeUniqueName(prefix, nodep->user2Inc());
|
||||
FileLine* const flp = vtxp->fileline();
|
||||
DfgVertex::ScopeCache scopeCache;
|
||||
AstScope* const scopep = m_dfg.modulep() ? nullptr : vtxp->scopep(scopeCache);
|
||||
AstScope* const scopep = vtxp->scopep(scopeCache);
|
||||
DfgVertexVar* const varp = m_dfg.makeNewVar(flp, name, vtxp->dtype(), scopep);
|
||||
varp->varp()->isInternal(true);
|
||||
varp->tmpForp(varp->nodep());
|
||||
varp->vscp()->varp()->isInternal(true);
|
||||
varp->tmpForp(varp->vscp());
|
||||
m_vtx2Scc[varp] = 0;
|
||||
return varp;
|
||||
}
|
||||
|
|
@ -1015,7 +1014,7 @@ class FixUp final {
|
|||
return debugStr(*aselp->fromp()) + "[" + std::to_string(i) + "]";
|
||||
}
|
||||
if (const DfgVertexVar* const varp = vtx.cast<DfgVertexVar>()) {
|
||||
return varp->nodep()->name();
|
||||
return varp->vscp()->name();
|
||||
}
|
||||
vtx.v3fatalSrc("Unhandled node type");
|
||||
} // LCOV_EXCL_STOP
|
||||
|
|
@ -1128,7 +1127,7 @@ class FixUp final {
|
|||
}
|
||||
|
||||
void main(DfgVertexVar& var) {
|
||||
UINFO(9, "FixUp of " << var.nodep()->name());
|
||||
UINFO(9, "FixUp of " << var.vscp()->name());
|
||||
|
||||
if (var.is<DfgVarPacked>()) {
|
||||
// For Packed variables, fix up as whole
|
||||
|
|
@ -1179,7 +1178,7 @@ std::pair<std::unique_ptr<DfgGraph>, bool> //
|
|||
breakCycles(const DfgGraph& dfg, V3DfgContext& ctx) {
|
||||
// Shorthand for dumping graph at given dump level
|
||||
const auto dump = [&](int level, const DfgGraph& dfg, const std::string& name) {
|
||||
if (dumpDfgLevel() >= level) dfg.dumpDotFilePrefixed(ctx.prefix() + "breakCycles-" + name);
|
||||
if (dumpDfgLevel() >= level) dfg.dumpDotFilePrefixed("breakCycles-" + name);
|
||||
};
|
||||
|
||||
// Can't do much with trivial things ('a = a' or 'a[1] = a[0]'), so bail
|
||||
|
|
@ -1237,7 +1236,7 @@ breakCycles(const DfgGraph& dfg, V3DfgContext& ctx) {
|
|||
if (dumpDfgLevel() >= 9) {
|
||||
Vtx2Scc vtx2Scc = res.makeUserMap<uint64_t>();
|
||||
V3DfgPasses::colorStronglyConnectedComponents(res, vtx2Scc);
|
||||
res.dumpDotFilePrefixed(ctx.prefix() + "breakCycles-remaining", [&](const DfgVertex& vtx) {
|
||||
res.dumpDotFilePrefixed("breakCycles-remaining", [&](const DfgVertex& vtx) {
|
||||
return vtx2Scc[vtx]; //
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,25 +37,17 @@ class V3DfgContext;
|
|||
// Base class for all context objects
|
||||
|
||||
class V3DfgSubContext VL_NOT_FINAL {
|
||||
V3DfgContext& m_ctx; // The whole context
|
||||
const std::string m_label; // Label to add to stats, etc.
|
||||
const std::string m_name; // Pass/algorithm name, to be used in statistics
|
||||
|
||||
protected:
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
V3DfgSubContext(V3DfgContext& ctx, const std::string& label, const char* name)
|
||||
: m_ctx{ctx}
|
||||
, m_label{label}
|
||||
, m_name{name} {}
|
||||
V3DfgSubContext(const std::string& name)
|
||||
: m_name{name} {}
|
||||
|
||||
void addStat(const std::string& what, double value) {
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " " + m_name + ", " + what, value);
|
||||
V3Stats::addStat("Optimizations, DFG, " + m_name + ", " + what, value);
|
||||
}
|
||||
|
||||
public:
|
||||
inline const std::string& prefix() const;
|
||||
const std::string& label() const { return m_label; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
@ -74,8 +66,8 @@ public:
|
|||
VDouble0 m_nonRepVar; // Non-representable due to unsupported variable properties
|
||||
|
||||
private:
|
||||
V3DfgAstToDfgContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "AstToDfg"} {}
|
||||
V3DfgAstToDfgContext()
|
||||
: V3DfgSubContext{"AstToDfg"} {}
|
||||
~V3DfgAstToDfgContext() {
|
||||
addStat("input processes", m_inputs);
|
||||
addStat("representable", m_representable);
|
||||
|
|
@ -96,8 +88,8 @@ public:
|
|||
VDouble0 m_decodersCreated; // Number of bianry to one-hot decoders created
|
||||
|
||||
private:
|
||||
V3DfgBinToOneHotContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "BinToOneHot"} {}
|
||||
V3DfgBinToOneHotContext()
|
||||
: V3DfgSubContext{"BinToOneHot"} {}
|
||||
~V3DfgBinToOneHotContext() { addStat("decoders created", m_decodersCreated); }
|
||||
};
|
||||
class V3DfgBreakCyclesContext final : public V3DfgSubContext {
|
||||
|
|
@ -113,8 +105,8 @@ public:
|
|||
VDouble0 m_nImprovements; // Number of changes made to graphs
|
||||
|
||||
private:
|
||||
V3DfgBreakCyclesContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "BreakCycles"} {}
|
||||
V3DfgBreakCyclesContext()
|
||||
: V3DfgSubContext{"BreakCycles"} {}
|
||||
~V3DfgBreakCyclesContext() {
|
||||
addStat("made acyclic", m_nFixed);
|
||||
addStat("improved", m_nImproved);
|
||||
|
|
@ -132,8 +124,8 @@ public:
|
|||
VDouble0 m_eliminated; // Number of common sub-expressions eliminated
|
||||
|
||||
private:
|
||||
V3DfgCseContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "CSE"} {}
|
||||
explicit V3DfgCseContext(const std::string& label)
|
||||
: V3DfgSubContext{"CSE " + label} {}
|
||||
~V3DfgCseContext() { addStat("expressions eliminated", m_eliminated); }
|
||||
};
|
||||
|
||||
|
|
@ -150,8 +142,8 @@ public:
|
|||
VDouble0 m_varRefsSubstituted; // Number of variable references substituted in the Ast
|
||||
|
||||
private:
|
||||
V3DfgDfgToAstContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "DfgToAst"} {}
|
||||
V3DfgDfgToAstContext()
|
||||
: V3DfgSubContext{"DfgToAst"} {}
|
||||
~V3DfgDfgToAstContext() {
|
||||
addStat("output variables", m_outputVariables);
|
||||
addStat("output variables with default driver", m_outputVariablesWithDefault);
|
||||
|
|
@ -173,8 +165,34 @@ public:
|
|||
std::vector<AstNode*> m_deleteps; // AstVar/AstVarScope that can be deleted at the end
|
||||
|
||||
private:
|
||||
V3DfgPeepholeContext(V3DfgContext& ctx, const std::string& label) VL_MT_DISABLED;
|
||||
~V3DfgPeepholeContext() VL_MT_DISABLED;
|
||||
V3DfgPeepholeContext()
|
||||
: V3DfgSubContext{"Peephole"} {
|
||||
const auto checkEnabled = [this](VDfgPeepholePattern id) {
|
||||
std::string str{id.ascii()};
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
|
||||
return c == '_' ? '-' : std::tolower(c);
|
||||
});
|
||||
m_enabled[id] = v3Global.opt.fDfgPeepholeEnabled(str);
|
||||
};
|
||||
#define OPTIMIZATION_CHECK_ENABLED(id, name) checkEnabled(VDfgPeepholePattern::id);
|
||||
FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_CHECK_ENABLED)
|
||||
#undef OPTIMIZATION_CHECK_ENABLED
|
||||
}
|
||||
~V3DfgPeepholeContext() {
|
||||
for (AstNode* const nodep : m_deleteps) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
const auto emitStat = [this](VDfgPeepholePattern id) {
|
||||
std::string str{id.ascii()};
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
|
||||
return c == '_' ? ' ' : std::tolower(c);
|
||||
});
|
||||
addStat(str, m_count[id]);
|
||||
};
|
||||
#define OPTIMIZATION_EMIT_STATS(id, name) emitStat(VDfgPeepholePattern::id);
|
||||
FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_EMIT_STATS)
|
||||
#undef OPTIMIZATION_EMIT_STATS
|
||||
}
|
||||
};
|
||||
class V3DfgPushDownSelsContext final : public V3DfgSubContext {
|
||||
// Only V3DfgContext can create an instance
|
||||
|
|
@ -185,8 +203,8 @@ public:
|
|||
size_t m_pushedDown = 0; // Number of selects pushed down through concatenations
|
||||
size_t m_wouldBeCyclic = 0; // Number of selects not pushed due to cycle
|
||||
private:
|
||||
V3DfgPushDownSelsContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "PushDownSels"} {}
|
||||
V3DfgPushDownSelsContext()
|
||||
: V3DfgSubContext{"PushDownSels"} {}
|
||||
~V3DfgPushDownSelsContext() {
|
||||
addStat("sels pushed down", m_pushedDown);
|
||||
addStat("would be cyclic", m_wouldBeCyclic);
|
||||
|
|
@ -204,8 +222,8 @@ public:
|
|||
VDouble0 m_temporariesIntroduced; // Number of temporaries introduced for reuse
|
||||
|
||||
private:
|
||||
V3DfgRegularizeContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "Regularize"} {}
|
||||
V3DfgRegularizeContext()
|
||||
: V3DfgSubContext{"Regularize"} {}
|
||||
~V3DfgRegularizeContext() {
|
||||
for (AstNode* const nodep : m_deleteps) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
|
|
@ -227,8 +245,8 @@ public:
|
|||
VDouble0 m_logicDeleted; // Number of logic blocks removed from the Dfg and the Ast
|
||||
|
||||
private:
|
||||
V3DfgRemoveUnobservableContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "RemoveUnobservable"} {}
|
||||
V3DfgRemoveUnobservableContext()
|
||||
: V3DfgSubContext{"RemoveUnobservable"} {}
|
||||
~V3DfgRemoveUnobservableContext() {
|
||||
addStat("variables removed", m_varsRemoved);
|
||||
addStat("variables deleted", m_varsDeleted);
|
||||
|
|
@ -291,8 +309,8 @@ public:
|
|||
} m_synt;
|
||||
|
||||
private:
|
||||
V3DfgSynthesisContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "Synthesis"} {}
|
||||
V3DfgSynthesisContext()
|
||||
: V3DfgSubContext{"Synthesis"} {}
|
||||
~V3DfgSynthesisContext() {
|
||||
// Conversion statistics
|
||||
addStat("conv / input assignments", m_conv.inputAssignments);
|
||||
|
|
@ -367,64 +385,40 @@ private:
|
|||
// Top level V3DfgContext
|
||||
|
||||
class V3DfgContext final {
|
||||
const std::string m_label; // Label to add to stats, etc.
|
||||
const std::string m_prefix; // Prefix to add to file dumps (derived from label)
|
||||
|
||||
public:
|
||||
// STATE
|
||||
|
||||
// Global statistics
|
||||
VDouble0 m_modules; // Number of modules optimized
|
||||
|
||||
// Sub contexts - keep sorted by type
|
||||
V3DfgAstToDfgContext m_ast2DfgContext{*this, m_label};
|
||||
V3DfgBinToOneHotContext m_binToOneHotContext{*this, m_label};
|
||||
V3DfgBreakCyclesContext m_breakCyclesContext{*this, m_label};
|
||||
V3DfgCseContext m_cseContext0{*this, m_label + " 1st"};
|
||||
V3DfgCseContext m_cseContext1{*this, m_label + " 2nd"};
|
||||
V3DfgDfgToAstContext m_dfg2AstContext{*this, m_label};
|
||||
V3DfgPeepholeContext m_peepholeContext{*this, m_label};
|
||||
V3DfgPushDownSelsContext m_pushDownSelsContext{*this, m_label};
|
||||
V3DfgRegularizeContext m_regularizeContext{*this, m_label};
|
||||
V3DfgRemoveUnobservableContext m_removeUnobservableContext{*this, m_label};
|
||||
V3DfgSynthesisContext m_synthContext{*this, m_label};
|
||||
V3DfgAstToDfgContext m_ast2DfgContext;
|
||||
V3DfgBinToOneHotContext m_binToOneHotContext;
|
||||
V3DfgBreakCyclesContext m_breakCyclesContext;
|
||||
V3DfgCseContext m_cseContext0{"1st"};
|
||||
V3DfgCseContext m_cseContext1{"2nd"};
|
||||
V3DfgDfgToAstContext m_dfg2AstContext;
|
||||
V3DfgPeepholeContext m_peepholeContext;
|
||||
V3DfgPushDownSelsContext m_pushDownSelsContext;
|
||||
V3DfgRegularizeContext m_regularizeContext;
|
||||
V3DfgRemoveUnobservableContext m_removeUnobservableContext;
|
||||
V3DfgSynthesisContext m_synthContext;
|
||||
|
||||
// Node pattern collector
|
||||
V3DfgPatternStats m_patternStats;
|
||||
|
||||
// CONSTRUCTOR
|
||||
explicit V3DfgContext(const std::string& label)
|
||||
: m_label{label}
|
||||
, m_prefix{VString::removeWhitespace(label) + "-"} {}
|
||||
V3DfgContext() = default;
|
||||
|
||||
~V3DfgContext() {
|
||||
const string front = "Optimizations, DFG " + label() + " General, ";
|
||||
V3Stats::addStat(front + "modules", m_modules);
|
||||
|
||||
// Print the collected patterns
|
||||
if (v3Global.opt.stats()) {
|
||||
// Label to lowercase, without spaces
|
||||
std::string ident = label();
|
||||
std::transform(ident.begin(), ident.end(), ident.begin(), [](unsigned char c) { //
|
||||
return c == ' ' ? '_' : std::tolower(c);
|
||||
});
|
||||
|
||||
// File to dump to
|
||||
const std::string filename = v3Global.opt.hierTopDataDir() + "/"
|
||||
+ v3Global.opt.prefix() + "__stats_dfg_patterns__" + ident
|
||||
+ ".txt";
|
||||
+ v3Global.opt.prefix() + "__stats_dfg_patterns.txt";
|
||||
// Open, write, close
|
||||
const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)};
|
||||
if (ofp->fail()) v3fatal("Can't write file: " << filename);
|
||||
m_patternStats.dump(label(), *ofp);
|
||||
m_patternStats.dump(*ofp);
|
||||
}
|
||||
}
|
||||
|
||||
// ACCESSORS
|
||||
const std::string& label() const { return m_label; }
|
||||
const std::string& prefix() const { return m_prefix; }
|
||||
};
|
||||
|
||||
const std::string& V3DfgSubContext::prefix() const { return m_ctx.prefix(); }
|
||||
|
||||
#endif //VERILATOR_V3DFGCONTEXT_H_
|
||||
|
|
|
|||
|
|
@ -22,9 +22,7 @@
|
|||
|
||||
#include "V3Dfg.h"
|
||||
#include "V3DfgPasses.h"
|
||||
#include "V3File.h"
|
||||
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -103,7 +101,7 @@ class SplitIntoComponents final {
|
|||
// Allocate the component graphs
|
||||
m_components.resize(m_componentCounter - 1);
|
||||
for (size_t i = 1; i < m_componentCounter; ++i) {
|
||||
m_components[i - 1].reset(new DfgGraph{m_dfg.modulep(), m_prefix + cvtToStr(i - 1)});
|
||||
m_components[i - 1].reset(new DfgGraph{m_prefix + cvtToStr(i - 1)});
|
||||
}
|
||||
// Move the vertices to the component graphs
|
||||
moveVertices(m_dfg.varVertices());
|
||||
|
|
@ -222,17 +220,9 @@ class ExtractCyclicComponents final {
|
|||
DfgVertexVar*& clonep = m_clones[&vtx][component];
|
||||
if (!clonep) {
|
||||
if (DfgVarPacked* const pVtxp = vtx.cast<DfgVarPacked>()) {
|
||||
if (AstVarScope* const vscp = pVtxp->varScopep()) {
|
||||
clonep = new DfgVarPacked{m_dfg, vscp};
|
||||
} else {
|
||||
clonep = new DfgVarPacked{m_dfg, pVtxp->varp()};
|
||||
}
|
||||
clonep = new DfgVarPacked{m_dfg, pVtxp->vscp()};
|
||||
} else if (DfgVarArray* const aVtxp = vtx.cast<DfgVarArray>()) {
|
||||
if (AstVarScope* const vscp = aVtxp->varScopep()) {
|
||||
clonep = new DfgVarArray{m_dfg, vscp};
|
||||
} else {
|
||||
clonep = new DfgVarArray{m_dfg, aVtxp->varp()};
|
||||
}
|
||||
clonep = new DfgVarArray{m_dfg, aVtxp->vscp()};
|
||||
}
|
||||
UASSERT_OBJ(clonep, &vtx, "Unhandled 'DfgVertexVar' sub-type");
|
||||
m_component[clonep] = component;
|
||||
|
|
@ -326,7 +316,7 @@ class ExtractCyclicComponents final {
|
|||
// Allocate result graphs
|
||||
m_components.resize(nComponents);
|
||||
for (uint32_t i = 0; i < nComponents; ++i) {
|
||||
m_components[i].reset(new DfgGraph{m_dfg.modulep(), m_prefix + cvtToStr(i)});
|
||||
m_components[i].reset(new DfgGraph{m_prefix + cvtToStr(i)});
|
||||
}
|
||||
|
||||
// Fix up edges crossing components (we can only do this at variable boundaries, and the
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@
|
|||
#include "V3DfgPasses.h"
|
||||
#include "V3UniqueNames.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
namespace {
|
||||
|
|
@ -92,34 +90,19 @@ AstShiftRS* makeNode<AstShiftRS, DfgShiftRS, AstNodeExpr*, AstNodeExpr*>( //
|
|||
|
||||
} // namespace
|
||||
|
||||
template <bool T_Scoped>
|
||||
class DfgToAstVisitor final : DfgVisitor {
|
||||
// NODE STATE
|
||||
|
||||
// AstScope::user2p // The combinational AstActive under this scope
|
||||
const VNUser2InUse m_user2InUse;
|
||||
|
||||
// TYPES
|
||||
using Variable = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
||||
using Container = std::conditional_t<T_Scoped, AstActive, AstNodeModule>;
|
||||
|
||||
// STATE
|
||||
AstModule* const m_modp; // The parent/result module - This is nullptr when T_Scoped
|
||||
V3DfgDfgToAstContext& m_ctx; // The context for stats
|
||||
AstNodeExpr* m_resultp = nullptr; // The result node of the current traversal
|
||||
AstAlways* m_alwaysp = nullptr; // Process to add assignments to, if have a default driver
|
||||
Container* m_containerp = nullptr; // The AstNodeModule or AstActive to insert assigns into
|
||||
AstActive* m_activep = nullptr; // The AstNodeModule or AstActive to insert assigns into
|
||||
|
||||
// METHODS
|
||||
|
||||
static Variable* getNode(const DfgVertexVar* vtxp) {
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
return reinterpret_cast<Variable*>(vtxp->varScopep());
|
||||
} else {
|
||||
return reinterpret_cast<Variable*>(vtxp->varp());
|
||||
}
|
||||
}
|
||||
|
||||
static AstActive* getCombActive(AstScope* scopep) {
|
||||
if (!scopep->user2p()) {
|
||||
// Try to find the existing combinational AstActive
|
||||
|
|
@ -173,7 +156,7 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
|
||||
// Otherwise create an AssignW
|
||||
AstAssignW* const ap = new AstAssignW{flp, lhsp, rhsp};
|
||||
m_containerp->addStmtsp(new AstAlways{ap});
|
||||
m_activep->addStmtsp(new AstAlways{ap});
|
||||
}
|
||||
|
||||
void convertDriver(FileLine* flp, AstNodeExpr* lhsp, DfgVertex* driverp) {
|
||||
|
|
@ -234,11 +217,11 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
} // LCOV_EXCL_STOP
|
||||
|
||||
void visit(DfgVarPacked* vtxp) override {
|
||||
m_resultp = new AstVarRef{vtxp->fileline(), getNode(vtxp), VAccess::READ};
|
||||
m_resultp = new AstVarRef{vtxp->fileline(), vtxp->vscp(), VAccess::READ};
|
||||
}
|
||||
|
||||
void visit(DfgVarArray* vtxp) override {
|
||||
m_resultp = new AstVarRef{vtxp->fileline(), getNode(vtxp), VAccess::READ};
|
||||
m_resultp = new AstVarRef{vtxp->fileline(), vtxp->vscp(), VAccess::READ};
|
||||
}
|
||||
|
||||
void visit(DfgConst* vtxp) override { //
|
||||
|
|
@ -264,8 +247,7 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
|
||||
// Constructor
|
||||
DfgToAstVisitor(DfgGraph& dfg, V3DfgDfgToAstContext& ctx)
|
||||
: m_modp{dfg.modulep()}
|
||||
, m_ctx{ctx} {
|
||||
: m_ctx{ctx} {
|
||||
if (v3Global.opt.debugCheck()) V3DfgPasses::typeCheck(dfg);
|
||||
|
||||
// Convert the graph back to combinational assignments. The graph must have been
|
||||
|
|
@ -283,24 +265,18 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
|
||||
// Render variable assignments
|
||||
FileLine* const flp = vtx.driverFileLine() ? vtx.driverFileLine() : vtx.fileline();
|
||||
AstVarRef* const lhsp = new AstVarRef{flp, getNode(&vtx), VAccess::WRITE};
|
||||
AstVarRef* const lhsp = new AstVarRef{flp, vtx.vscp(), VAccess::WRITE};
|
||||
|
||||
VL_RESTORER(m_containerp);
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
// Add it to the scope holding the target variable
|
||||
AstActive* const activep = getCombActive(vtx.varScopep()->scopep());
|
||||
m_containerp = reinterpret_cast<Container*>(activep);
|
||||
} else {
|
||||
// Add it to the parent module of the DfgGraph
|
||||
m_containerp = reinterpret_cast<Container*>(m_modp);
|
||||
}
|
||||
// Add it to the scope holding the target variable
|
||||
VL_RESTORER(m_activep);
|
||||
m_activep = getCombActive(vtx.vscp()->scopep());
|
||||
|
||||
// If there is a default value, render all drivers under an AstAlways
|
||||
VL_RESTORER(m_alwaysp);
|
||||
if (DfgVertex* const defaultp = vtx.defaultp()) {
|
||||
++m_ctx.m_outputVariablesWithDefault;
|
||||
m_alwaysp = new AstAlways{vtx.fileline(), VAlwaysKwd::ALWAYS_COMB, nullptr};
|
||||
m_containerp->addStmtsp(m_alwaysp);
|
||||
m_activep->addStmtsp(m_alwaysp);
|
||||
// The default assignment needs to go first
|
||||
createAssignment(vtx.fileline(), lhsp->cloneTreePure(false), defaultp);
|
||||
}
|
||||
|
|
@ -326,8 +302,6 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
if (VN_IS(exprp, VarRef)) {
|
||||
++m_ctx.m_varRefsSubstituted;
|
||||
} else {
|
||||
UASSERT_OBJ(!dfg.modulep(), &vtx,
|
||||
"Expressions should only be inlined on final scoped run");
|
||||
++m_ctx.m_expressionsInlined;
|
||||
}
|
||||
rVtxp->exprp()->replaceWith(exprp);
|
||||
|
|
@ -342,9 +316,5 @@ public:
|
|||
};
|
||||
|
||||
void V3DfgPasses::dfgToAst(DfgGraph& dfg, V3DfgContext& ctx) {
|
||||
if (dfg.modulep()) {
|
||||
DfgToAstVisitor</* T_Scoped: */ false>::apply(dfg, ctx.m_dfg2AstContext);
|
||||
} else {
|
||||
DfgToAstVisitor</* T_Scoped: */ true>::apply(dfg, ctx.m_dfg2AstContext);
|
||||
}
|
||||
DfgToAstVisitor::apply(dfg, ctx.m_dfg2AstContext);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "V3Const.h"
|
||||
#include "V3Dfg.h"
|
||||
#include "V3DfgPasses.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Graph.h"
|
||||
#include "V3UniqueNames.h"
|
||||
|
||||
|
|
@ -255,84 +256,39 @@ class DataflowOptimize final {
|
|||
|
||||
// STATE
|
||||
V3DfgContext m_ctx; // The context holding values that need to persist across multiple graphs
|
||||
const bool m_scoped; // Running after V3Scope
|
||||
|
||||
void endOfStage(const std::string& name, const DfgGraph* dfgp = nullptr) {
|
||||
// Dump the graph for debugging if given one
|
||||
if (VL_UNLIKELY(dumpDfgLevel() >= 8 && dfgp)) {
|
||||
dfgp->dumpDotFilePrefixed(m_ctx.prefix() + name);
|
||||
}
|
||||
if (VL_UNLIKELY(dumpDfgLevel() >= 8 && dfgp)) dfgp->dumpDotFilePrefixed(name);
|
||||
// Dump stage stats only in scoped mode when running on the whole netlist
|
||||
if (VL_UNLIKELY(v3Global.opt.stats() && m_scoped)) {
|
||||
V3Stats::statsStage("dfg-optimize-" + name);
|
||||
}
|
||||
if (VL_UNLIKELY(v3Global.opt.stats())) V3Stats::statsStage("dfg-optimize-" + name);
|
||||
}
|
||||
|
||||
// Mark variables with external references
|
||||
void markExternallyReferencedVariables(AstNetlist* netlistp) {
|
||||
netlistp->foreach([this](AstNode* nodep) {
|
||||
netlistp->foreach([](AstNode* nodep) {
|
||||
// Check variable flags
|
||||
if (m_scoped) {
|
||||
if (AstVarScope* const vscp = VN_CAST(nodep, VarScope)) {
|
||||
const AstVar* const varp = vscp->varp();
|
||||
// Force and trace have already been processed
|
||||
const bool hasExtRd = varp->isPrimaryIO() || varp->isSigUserRdPublic();
|
||||
const bool hasExtWr = varp->isPrimaryIO() || varp->isSigUserRWPublic();
|
||||
if (hasExtRd) DfgVertexVar::setHasExtRdRefs(vscp);
|
||||
if (hasExtWr) DfgVertexVar::setHasExtWrRefs(vscp);
|
||||
return;
|
||||
}
|
||||
// Check direct references
|
||||
if (const AstVarRef* const refp = VN_CAST(nodep, VarRef)) {
|
||||
if (refp->access().isRW()) DfgVertexVar::setHasRWRefs(refp->varScopep());
|
||||
UASSERT_OBJ(!refp->classOrPackagep(), refp, "V3Scope should have removed");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (AstVar* const varp = VN_CAST(nodep, Var)) {
|
||||
const bool hasExtRd = varp->isPrimaryIO() || varp->isSigUserRdPublic() //
|
||||
|| varp->isForced() || varp->isTrace();
|
||||
const bool hasExtWr = varp->isPrimaryIO() || varp->isSigUserRWPublic() //
|
||||
|| varp->isForced();
|
||||
if (hasExtRd) DfgVertexVar::setHasExtRdRefs(varp);
|
||||
if (hasExtWr) DfgVertexVar::setHasExtWrRefs(varp);
|
||||
return;
|
||||
}
|
||||
// Check direct references
|
||||
if (const AstVarRef* const refp = VN_CAST(nodep, VarRef)) {
|
||||
AstVar* const varp = refp->varp();
|
||||
if (refp->access().isRW()) DfgVertexVar::setHasRWRefs(varp);
|
||||
// With classOrPackagep set this is a disguised hierarchical reference, mark
|
||||
if (refp->classOrPackagep()) {
|
||||
if (refp->access().isReadOrRW()) DfgVertexVar::setHasExtRdRefs(varp);
|
||||
if (refp->access().isWriteOrRW()) DfgVertexVar::setHasExtWrRefs(varp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check hierarchical references
|
||||
if (const AstVarXRef* const xrefp = VN_CAST(nodep, VarXRef)) {
|
||||
AstVar* const tgtp = xrefp->varp();
|
||||
if (!tgtp) return;
|
||||
if (xrefp->access().isReadOrRW()) DfgVertexVar::setHasExtRdRefs(tgtp);
|
||||
if (xrefp->access().isWriteOrRW()) DfgVertexVar::setHasExtWrRefs(tgtp);
|
||||
if (xrefp->access().isRW()) DfgVertexVar::setHasRWRefs(tgtp);
|
||||
if (AstVarScope* const vscp = VN_CAST(nodep, VarScope)) {
|
||||
const AstVar* const varp = vscp->varp();
|
||||
// Force and trace have already been processed
|
||||
const bool hasExtRd = varp->isPrimaryIO() || varp->isSigUserRdPublic();
|
||||
const bool hasExtWr
|
||||
= (varp->isPrimaryIO() && varp->isNonOutput()) || varp->isSigUserRWPublic();
|
||||
if (hasExtRd) DfgVertexVar::setHasExtRdRefs(vscp);
|
||||
if (hasExtWr) DfgVertexVar::setHasExtWrRefs(vscp);
|
||||
return;
|
||||
}
|
||||
// Check references
|
||||
if (const AstVarRef* const refp = VN_CAST(nodep, VarRef)) {
|
||||
if (refp->access().isRW()) DfgVertexVar::setHasRWRefs(refp->varScopep());
|
||||
UASSERT_OBJ(!refp->classOrPackagep(), refp, "V3Scope should have removed");
|
||||
return;
|
||||
}
|
||||
UASSERT_OBJ(!VN_IS(nodep, VarXRef), nodep, "V3Scope should have removed");
|
||||
// Check cell ports
|
||||
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
|
||||
for (const AstPin *pinp = cellp->pinsp(), *nextp; pinp; pinp = nextp) {
|
||||
nextp = VN_AS(pinp->nextp(), Pin);
|
||||
AstVar* const tgtp = pinp->modVarp();
|
||||
if (!tgtp) return;
|
||||
const VDirection dir = tgtp->direction();
|
||||
// hasExtRd/hasExtWr from perspective of Pin
|
||||
const bool hasExtRd = dir == VDirection::OUTPUT || dir.isInoutOrRef();
|
||||
const bool hasExtWr = dir == VDirection::INPUT || dir.isInoutOrRef();
|
||||
if (hasExtRd) DfgVertexVar::setHasExtRdRefs(tgtp);
|
||||
if (hasExtWr) DfgVertexVar::setHasExtWrRefs(tgtp);
|
||||
}
|
||||
// Why does this not hold?
|
||||
UASSERT_OBJ(true || !cellp->pinsp(), cellp, "Pins should have been lowered");
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
|
@ -415,9 +371,7 @@ class DataflowOptimize final {
|
|||
}
|
||||
}
|
||||
|
||||
DataflowOptimize(AstNetlist* netlistp, const string& label)
|
||||
: m_ctx{label}
|
||||
, m_scoped{!!netlistp->topScopep()} {
|
||||
DataflowOptimize(AstNetlist* netlistp) {
|
||||
|
||||
// Mark interfaces that might be referenced by a virtual interface
|
||||
if (v3Global.hasVirtIfaces()) {
|
||||
|
|
@ -430,51 +384,29 @@ class DataflowOptimize final {
|
|||
// Mark variables with external references
|
||||
markExternallyReferencedVariables(netlistp);
|
||||
|
||||
if (!m_scoped) {
|
||||
// Pre V3Scope application. Run on each module separately.
|
||||
for (AstNode* nodep = netlistp->modulesp(); nodep; nodep = nodep->nextp()) {
|
||||
// Only optimize proper modules
|
||||
AstModule* const modp = VN_CAST(nodep, Module);
|
||||
if (!modp) continue;
|
||||
// Pre V3Scope application. Run on module.
|
||||
UINFO(4, "Applying DFG optimization to module '" << modp->name() << "'");
|
||||
++m_ctx.m_modules;
|
||||
// Build the DFG of this module or netlist
|
||||
const std::unique_ptr<DfgGraph> dfgp = V3DfgPasses::astToDfg(*modp, m_ctx);
|
||||
endOfStage("ast-to-dfg", dfgp.get());
|
||||
// Actually process the graph
|
||||
optimize(*dfgp);
|
||||
// Convert back to Ast
|
||||
V3DfgPasses::dfgToAst(*dfgp, m_ctx);
|
||||
endOfStage("dfg-to-ast", dfgp.get());
|
||||
}
|
||||
} else {
|
||||
// Post V3Scope application. Run on whole netlist.
|
||||
UINFO(4, "Applying DFG optimization to entire netlist");
|
||||
// Build the DFG of the entire netlist
|
||||
const std::unique_ptr<DfgGraph> dfgp = V3DfgPasses::astToDfg(*netlistp, m_ctx);
|
||||
endOfStage("ast-to-dfg", dfgp.get());
|
||||
// Actually process the graph
|
||||
optimize(*dfgp);
|
||||
// Convert back to Ast
|
||||
V3DfgPasses::dfgToAst(*dfgp, m_ctx);
|
||||
endOfStage("dfg-to-ast", dfgp.get());
|
||||
// Some sentrees might have become constant, remove them
|
||||
removeNeverActives(netlistp);
|
||||
}
|
||||
// Post V3Scope application. Run on whole netlist.
|
||||
UINFO(4, "Applying DFG optimization to entire netlist");
|
||||
// Build the DFG of the entire netlist
|
||||
const std::unique_ptr<DfgGraph> dfgp = V3DfgPasses::astToDfg(*netlistp, m_ctx);
|
||||
endOfStage("ast-to-dfg", dfgp.get());
|
||||
// Actually process the graph
|
||||
optimize(*dfgp);
|
||||
// Convert back to Ast
|
||||
V3DfgPasses::dfgToAst(*dfgp, m_ctx);
|
||||
endOfStage("dfg-to-ast", dfgp.get());
|
||||
// Some sentrees might have become constant, remove them
|
||||
removeNeverActives(netlistp);
|
||||
|
||||
// Reset interned types so the corresponding Ast types can be garbage collected
|
||||
DfgDataType::reset();
|
||||
}
|
||||
|
||||
public:
|
||||
static void apply(AstNetlist* netlistp, const string& label) {
|
||||
DataflowOptimize{netlistp, label};
|
||||
}
|
||||
static void apply(AstNetlist* netlistp) { DataflowOptimize{netlistp}; }
|
||||
};
|
||||
|
||||
void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
|
||||
void V3DfgOptimizer::optimize(AstNetlist* netlistp) {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
DataflowOptimize::apply(netlistp, label);
|
||||
DataflowOptimize::apply(netlistp);
|
||||
V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace V3DfgOptimizer {
|
|||
void extract(AstNetlist*) VL_MT_DISABLED;
|
||||
|
||||
// Optimize the design
|
||||
void optimize(AstNetlist*, const string& label) VL_MT_DISABLED;
|
||||
void optimize(AstNetlist*) VL_MT_DISABLED;
|
||||
} // namespace V3DfgOptimizer
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "V3DfgPasses.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Dfg.h"
|
||||
#include "V3File.h"
|
||||
#include "V3Global.h"
|
||||
|
|
@ -71,7 +72,7 @@ void V3DfgPasses::removeUnobservable(DfgGraph& dfg, V3DfgContext& dfgCtx) {
|
|||
if (vVtxp->hasSinks()) continue;
|
||||
if (vVtxp->isObserved()) continue;
|
||||
DfgVertex* const srcp = vVtxp->srcp(); // Must be a DfgUnresolved or nullptr
|
||||
AstNode* const varp = vVtxp->nodep();
|
||||
AstVarScope* const vscp = vVtxp->vscp();
|
||||
// Can delete the Ast variable too if it has no other references
|
||||
const bool delAst = (!srcp || !srcp->nInputs()) //
|
||||
&& !vVtxp->hasExtWrRefs() //
|
||||
|
|
@ -79,7 +80,7 @@ void V3DfgPasses::removeUnobservable(DfgGraph& dfg, V3DfgContext& dfgCtx) {
|
|||
VL_DO_DANGLING(vVtxp->unlinkDelete(dfg), vVtxp);
|
||||
if (srcp) VL_DO_DANGLING(srcp->unlinkDelete(dfg), srcp);
|
||||
if (delAst) {
|
||||
VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp);
|
||||
VL_DO_DANGLING(vscp->unlinkFrBack()->deleteTree(), vscp);
|
||||
++ctx.m_varsDeleted;
|
||||
} else {
|
||||
++ctx.m_varsRemoved;
|
||||
|
|
@ -96,7 +97,7 @@ void V3DfgPasses::removeUnobservable(DfgGraph& dfg, V3DfgContext& dfgCtx) {
|
|||
// AstVar/AstVarScope::user2p() -> corresponding DfgVertexVar* in the graph
|
||||
const VNUser2InUse m_user2InUse;
|
||||
logicp->foreachSource([](DfgVertex& src) {
|
||||
src.as<DfgVertexVar>()->nodep()->user2p(&src);
|
||||
src.as<DfgVertexVar>()->vscp()->user2p(&src);
|
||||
return false;
|
||||
});
|
||||
V3DfgPasses::addAstRefs(dfg, logicp->nodep(), [](AstNode* varp) { //
|
||||
|
|
@ -181,8 +182,6 @@ void V3DfgPasses::removeUnused(DfgGraph& dfg) {
|
|||
}
|
||||
|
||||
void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
||||
if (!dfg.modulep()) return; // binToOneHot only works with unscoped DfgGraphs for now
|
||||
|
||||
// Structure to keep track of comparison details
|
||||
struct Term final {
|
||||
DfgVertex* m_vtxp = nullptr; // Vertex to replace
|
||||
|
|
@ -291,6 +290,8 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
|||
// Sequence numbers for name generation
|
||||
size_t nTables = 0;
|
||||
|
||||
DfgVertex::ScopeCache scopeCache;
|
||||
|
||||
// Create decoders for each srcp
|
||||
for (DfgVertex* const srcp : srcps) {
|
||||
const Val2Terms& val2Terms = vtx2Val2Terms[srcp];
|
||||
|
|
@ -318,6 +319,38 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
|||
// - and replace the comparisons with 'tab[const]'
|
||||
|
||||
FileLine* const flp = srcp->fileline();
|
||||
AstScope* const scopep = srcp->scopep(scopeCache, true);
|
||||
|
||||
AstActive* const staticActivep = [scopep]() {
|
||||
// Try to find the existing combinational AstActive
|
||||
for (AstNode* nodep = scopep->blocksp(); nodep; nodep = nodep->nextp()) {
|
||||
AstActive* const activep = VN_CAST(nodep, Active);
|
||||
if (!activep) continue;
|
||||
if (activep->sentreep()->hasStatic()) return activep;
|
||||
}
|
||||
// If there isn't one, create a new one
|
||||
FileLine* const flp = scopep->fileline();
|
||||
AstSenTree* const stp = new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Static{}}};
|
||||
AstActive* const activep = new AstActive{flp, "", stp};
|
||||
activep->senTreeStorep(stp);
|
||||
scopep->addBlocksp(activep);
|
||||
return activep;
|
||||
}();
|
||||
AstActive* const combActivep = [scopep]() {
|
||||
// Try to find the existing combinational AstActive
|
||||
for (AstNode* nodep = scopep->blocksp(); nodep; nodep = nodep->nextp()) {
|
||||
AstActive* const activep = VN_CAST(nodep, Active);
|
||||
if (!activep) continue;
|
||||
if (activep->sentreep()->hasCombo()) return activep;
|
||||
}
|
||||
// If there isn't one, create a new one
|
||||
FileLine* const flp = scopep->fileline();
|
||||
AstSenTree* const stp = new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Combo{}}};
|
||||
AstActive* const activep = new AstActive{flp, "", stp};
|
||||
activep->senTreeStorep(stp);
|
||||
scopep->addBlocksp(activep);
|
||||
return activep;
|
||||
}();
|
||||
|
||||
// Required data types
|
||||
const DfgDataType& idxDType = srcp->dtype();
|
||||
|
|
@ -330,31 +363,31 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
|||
if (DfgVertexVar* const vp = srcp->getResultVar()) return vp->as<DfgVarPacked>();
|
||||
// Otherwise create a new variable
|
||||
const std::string name = dfg.makeUniqueName("BinToOneHot_Idx", nTables);
|
||||
DfgVertexVar* const vtxp = dfg.makeNewVar(flp, name, idxDType, nullptr);
|
||||
vtxp->varp()->isInternal(true);
|
||||
DfgVertexVar* const vtxp = dfg.makeNewVar(flp, name, idxDType, scopep);
|
||||
vtxp->vscp()->varp()->isInternal(true);
|
||||
vtxp->srcp(srcp);
|
||||
return vtxp->as<DfgVarPacked>();
|
||||
}();
|
||||
AstVar* const idxVarp = idxVtxp->varp();
|
||||
AstVarScope* const idxVscp = idxVtxp->vscp();
|
||||
// The previous index variable - we don't need a vertex for this
|
||||
AstVar* const preVarp = [&]() {
|
||||
AstVarScope* const preVscp = [&]() {
|
||||
const std::string name = dfg.makeUniqueName("BinToOneHot_Pre", nTables);
|
||||
AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, idxDType.astDtypep()};
|
||||
dfg.modulep()->addStmtsp(varp);
|
||||
varp->isInternal(true);
|
||||
varp->noReset(true);
|
||||
varp->setIgnoreSchedWrite();
|
||||
return varp;
|
||||
DfgVertexVar* const vtxp = dfg.makeNewVar(flp, name, idxDType, scopep);
|
||||
AstVarScope* const vscp = vtxp->vscp();
|
||||
VL_DO_DANGLING(vtxp->unlinkDelete(dfg), vtxp);
|
||||
vscp->varp()->isInternal(true);
|
||||
vscp->varp()->noReset(true);
|
||||
vscp->varp()->setIgnoreSchedWrite();
|
||||
return vscp;
|
||||
}();
|
||||
// The table variable
|
||||
DfgVarArray* const tabVtxp = [&]() {
|
||||
const std::string name = dfg.makeUniqueName("BinToOneHot_Tab", nTables);
|
||||
DfgVarArray* const varp
|
||||
= dfg.makeNewVar(flp, name, tabDType, nullptr)->as<DfgVarArray>();
|
||||
varp->varp()->isInternal(true);
|
||||
varp->varp()->noReset(true);
|
||||
DfgVertexVar* const varp = dfg.makeNewVar(flp, name, tabDType, scopep);
|
||||
varp->vscp()->varp()->isInternal(true);
|
||||
varp->vscp()->varp()->noReset(true);
|
||||
varp->setHasModWrRefs();
|
||||
return varp;
|
||||
return varp->as<DfgVarArray>();
|
||||
}();
|
||||
|
||||
++nTables;
|
||||
|
|
@ -362,16 +395,16 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
|||
|
||||
// Initialize 'tab' and 'pre' variables statically
|
||||
AstInitialStatic* const initp = new AstInitialStatic{flp, nullptr};
|
||||
dfg.modulep()->addStmtsp(initp);
|
||||
staticActivep->addStmtsp(initp);
|
||||
{ // pre = 0
|
||||
initp->addStmtsp(new AstAssign{
|
||||
flp, //
|
||||
new AstVarRef{flp, preVarp, VAccess::WRITE}, //
|
||||
new AstVarRef{flp, preVscp, VAccess::WRITE}, //
|
||||
new AstConst{flp, AstConst::WidthedValue{}, static_cast<int>(width), 0}});
|
||||
}
|
||||
{ // tab.fill(0)
|
||||
AstCMethodHard* const callp = new AstCMethodHard{
|
||||
flp, new AstVarRef{flp, tabVtxp->varp(), VAccess::WRITE}, VCMethod::UNPACKED_FILL};
|
||||
flp, new AstVarRef{flp, tabVtxp->vscp(), VAccess::WRITE}, VCMethod::UNPACKED_FILL};
|
||||
callp->addPinsp(new AstConst{flp, AstConst::BitFalse{}});
|
||||
callp->dtypeSetVoid();
|
||||
initp->addStmtsp(callp->makeStmt());
|
||||
|
|
@ -379,28 +412,28 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
|||
|
||||
// Build the decoder logic
|
||||
AstAlways* const logicp = new AstAlways{flp, VAlwaysKwd::ALWAYS_COMB, nullptr, nullptr};
|
||||
dfg.modulep()->addStmtsp(logicp);
|
||||
combActivep->addStmtsp(logicp);
|
||||
{ // tab[pre] = 0;
|
||||
logicp->addStmtsp(new AstAssign{
|
||||
flp, //
|
||||
new AstArraySel{flp, new AstVarRef{flp, tabVtxp->varp(), VAccess::WRITE},
|
||||
new AstVarRef{flp, preVarp, VAccess::READ}}, //
|
||||
new AstArraySel{flp, new AstVarRef{flp, tabVtxp->vscp(), VAccess::WRITE},
|
||||
new AstVarRef{flp, preVscp, VAccess::READ}}, //
|
||||
new AstConst{flp, AstConst::BitFalse{}}});
|
||||
}
|
||||
{ // tab[idx] = 1
|
||||
AstVarRef* const idxRefp = new AstVarRef{flp, idxVarp, VAccess::READ};
|
||||
AstVarRef* const idxRefp = new AstVarRef{flp, idxVscp, VAccess::READ};
|
||||
logicp->addStmtsp(new AstAssign{
|
||||
flp, //
|
||||
new AstArraySel{flp, new AstVarRef{flp, tabVtxp->varp(), VAccess::WRITE},
|
||||
new AstArraySel{flp, new AstVarRef{flp, tabVtxp->vscp(), VAccess::WRITE},
|
||||
idxRefp}, //
|
||||
new AstConst{flp, AstConst::BitTrue{}}});
|
||||
DfgAstRd* const astRdp = new DfgAstRd{dfg, idxRefp, false, false};
|
||||
astRdp->srcp(idxVtxp);
|
||||
}
|
||||
{ // pre = idx
|
||||
AstVarRef* const idxRefp = new AstVarRef{flp, idxVarp, VAccess::READ};
|
||||
AstVarRef* const idxRefp = new AstVarRef{flp, idxVscp, VAccess::READ};
|
||||
logicp->addStmtsp(new AstAssign{flp, //
|
||||
new AstVarRef{flp, preVarp, VAccess::WRITE}, //
|
||||
new AstVarRef{flp, preVscp, VAccess::WRITE}, //
|
||||
idxRefp});
|
||||
DfgAstRd* const astRdp = new DfgAstRd{dfg, idxRefp, false, false};
|
||||
astRdp->srcp(idxVtxp);
|
||||
|
|
@ -442,7 +475,7 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgContext& ctx) {
|
|||
// Apply the pass
|
||||
pass();
|
||||
// Debug dump
|
||||
if (dump) dfg.dumpDotFilePrefixed(ctx.prefix() + "opt-" + VString::removeWhitespace(name));
|
||||
if (dump) dfg.dumpDotFilePrefixed("opt-" + VString::removeWhitespace(name));
|
||||
// Internal type check
|
||||
if (v3Global.opt.debugCheck()) V3DfgPasses::typeCheck(dfg);
|
||||
};
|
||||
|
|
@ -456,10 +489,7 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgContext& ctx) {
|
|||
run("cse0 ", dumpLvl >= 4, [&]() { cse(dfg, ctx.m_cseContext0); });
|
||||
run("binToOneHot ", dumpLvl >= 4, [&]() { binToOneHot(dfg, ctx.m_binToOneHotContext); });
|
||||
run("peephole ", dumpLvl >= 4, [&]() { peephole(dfg, ctx.m_peepholeContext); });
|
||||
// Run only on final scoped DfgGraphs, as otherwise later DfgPeephole wold just undo this work
|
||||
if (!dfg.modulep()) {
|
||||
run("pushDownSels", dumpLvl >= 4, [&]() { pushDownSels(dfg, ctx.m_pushDownSelsContext); });
|
||||
}
|
||||
run("pushDownSels", dumpLvl >= 4, [&]() { pushDownSels(dfg, ctx.m_pushDownSelsContext); });
|
||||
run("cse1 ", dumpLvl >= 4, [&]() { cse(dfg, ctx.m_cseContext1); });
|
||||
run("output ", dumpLvl >= 3, [&]() { /* debug dump only */ });
|
||||
|
||||
|
|
|
|||
|
|
@ -30,19 +30,16 @@ namespace V3DfgPasses {
|
|||
// Top level entry points
|
||||
//===========================================================================
|
||||
|
||||
// Construct a DfGGraph representing the combinational logic in the given AstModule. The logic
|
||||
// that is represented by the graph is removed from the given AstModule. Returns the
|
||||
// constructed DfgGraph.
|
||||
std::unique_ptr<DfgGraph> astToDfg(AstModule&, V3DfgContext&) VL_MT_DISABLED;
|
||||
|
||||
// Same as above, but for the entire netlist, after V3Scope
|
||||
// Construct a DfGGraph representing the combinational logic in the netlist.
|
||||
// The logic that is represented by the graph is removed from the netlist.
|
||||
// Returns the constructed DfgGraph.
|
||||
std::unique_ptr<DfgGraph> astToDfg(AstNetlist&, V3DfgContext&) VL_MT_DISABLED;
|
||||
|
||||
// Add DfgVertexAst to the given DfgGraph for all references in the given AstNode.
|
||||
// The function 'getVarVertex' is used to get the DfgVertexVar for an AstVar/AstVarScope.
|
||||
// The function 'getVarVertex' is used to get the DfgVertexVar for an AstVarScope.
|
||||
// If it returns nullptr, the reference will be ignored.
|
||||
void addAstRefs(DfgGraph& dfg, AstNode* nodep,
|
||||
std::function<DfgVertexVar*(AstNode*)> getVarVertex) VL_MT_DISABLED;
|
||||
std::function<DfgVertexVar*(AstVarScope*)> getVarVertex) VL_MT_DISABLED;
|
||||
|
||||
// Remove unobservable variabels and logic that drives only such variables
|
||||
void removeUnobservable(DfgGraph&, V3DfgContext&) VL_MT_DISABLED;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class V3DfgPatternStats final {
|
|||
static constexpr uint32_t MAX_PATTERN_DEPTH = 4;
|
||||
|
||||
std::map<std::string, std::string> m_internedConsts; // Interned constants
|
||||
std::map<const AstNode*, std::string> m_internedVars; // Interned variables
|
||||
std::map<const AstVarScope*, std::string> m_internedVars; // Interned variables
|
||||
std::map<uint32_t, std::string> m_internedSelLsbs; // Interned lsb value for selects
|
||||
std::map<uint32_t, std::string> m_internedWordWidths; // Interned widths
|
||||
std::map<uint32_t, std::string> m_internedWideWidths; // Interned widths
|
||||
|
|
@ -51,7 +51,7 @@ class V3DfgPatternStats final {
|
|||
}
|
||||
|
||||
const std::string& internVar(const DfgVertexVar& vtx) {
|
||||
const auto pair = m_internedVars.emplace(vtx.nodep(), "v");
|
||||
const auto pair = m_internedVars.emplace(vtx.vscp(), "v");
|
||||
if (pair.second) pair.first->second += toLetters(m_internedVars.size() - 1);
|
||||
return pair.first->second;
|
||||
}
|
||||
|
|
@ -167,10 +167,10 @@ public:
|
|||
});
|
||||
}
|
||||
|
||||
void dump(const std::string& stage, std::ostream& os) {
|
||||
void dump(std::ostream& os) {
|
||||
using Line = std::pair<std::string, size_t>;
|
||||
for (uint32_t i = MIN_PATTERN_DEPTH; i <= MAX_PATTERN_DEPTH; ++i) {
|
||||
os << "DFG '" << stage << "' patterns with depth " << i << '\n';
|
||||
os << "DFG patterns with depth " << i << '\n';
|
||||
|
||||
// Pick up pattern accumulators with given depth
|
||||
const auto& patternCounts = m_patterCounts[i];
|
||||
|
|
|
|||
|
|
@ -38,11 +38,11 @@
|
|||
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Dfg.h"
|
||||
#include "V3DfgCache.h"
|
||||
#include "V3DfgPasses.h"
|
||||
#include "V3DfgPeepholePatterns.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
|
@ -50,36 +50,6 @@
|
|||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
V3DfgPeepholeContext::V3DfgPeepholeContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "Peephole"} {
|
||||
const auto checkEnabled = [this](VDfgPeepholePattern id) {
|
||||
std::string str{id.ascii()};
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
|
||||
return c == '_' ? '-' : std::tolower(c);
|
||||
});
|
||||
m_enabled[id] = v3Global.opt.fDfgPeepholeEnabled(str);
|
||||
};
|
||||
#define OPTIMIZATION_CHECK_ENABLED(id, name) checkEnabled(VDfgPeepholePattern::id);
|
||||
FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_CHECK_ENABLED)
|
||||
#undef OPTIMIZATION_CHECK_ENABLED
|
||||
}
|
||||
|
||||
V3DfgPeepholeContext::~V3DfgPeepholeContext() {
|
||||
for (AstNode* const nodep : m_deleteps) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
const auto emitStat = [this](VDfgPeepholePattern id) {
|
||||
std::string str{id.ascii()};
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
|
||||
return c == '_' ? ' ' : std::tolower(c);
|
||||
});
|
||||
addStat(str, m_count[id]);
|
||||
};
|
||||
#define OPTIMIZATION_EMIT_STATS(id, name) emitStat(VDfgPeepholePattern::id);
|
||||
FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_EMIT_STATS)
|
||||
#undef OPTIMIZATION_EMIT_STATS
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <typename T_Reduction>
|
||||
struct ReductionToBitwiseImpl {};
|
||||
|
|
@ -250,9 +220,8 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
// to the variable and no references in other graph then delete the Ast var too.
|
||||
const DfgVertexVar* const varp = vtxp->cast<DfgVertexVar>();
|
||||
if (varp && !varp->isVolatile() && !varp->hasDfgRefs()) {
|
||||
AstNode* const nodep = varp->nodep();
|
||||
m_ctx.m_deleteps.push_back(varp->vscp());
|
||||
VL_DO_DANGLING(vtxp->unlinkDelete(m_dfg), vtxp);
|
||||
m_ctx.m_deleteps.push_back(nodep);
|
||||
} else {
|
||||
VL_DO_DANGLING(vtxp->unlinkDelete(m_dfg), vtxp);
|
||||
}
|
||||
|
|
@ -1617,8 +1586,8 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
if (!idxp) return;
|
||||
DfgVarArray* const varp = vtxp->fromp()->cast<DfgVarArray>();
|
||||
if (!varp) return;
|
||||
if (varp->varp()->isForced()) return;
|
||||
if (varp->varp()->isSigUserRWPublic()) return;
|
||||
if (varp->vscp()->varp()->isForced()) return;
|
||||
if (varp->vscp()->varp()->isSigUserRWPublic()) return;
|
||||
DfgVertex* const srcp = varp->srcp();
|
||||
if (!srcp) return;
|
||||
|
||||
|
|
@ -1862,16 +1831,13 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
DfgSplicePacked* const sp = new DfgSplicePacked{m_dfg, flp, vtxp->dtype()};
|
||||
m_vInfo[sp].m_id = ++m_lastId;
|
||||
sp->addDriver(catp, lsb, flp);
|
||||
AstScope* const scopep = [&]() -> AstScope* {
|
||||
if (m_dfg.modulep()) return nullptr;
|
||||
DfgVertex::ScopeCache scopeCache;
|
||||
return vtxp->scopep(scopeCache, true);
|
||||
}();
|
||||
DfgVertex::ScopeCache scopeCache;
|
||||
AstScope* const scopep = vtxp->scopep(scopeCache, true);
|
||||
const std::string name = m_dfg.makeUniqueName("PeepholeNarrow", m_nTemps++);
|
||||
DfgVertexVar* const varp = m_dfg.makeNewVar(flp, name, vtxp->dtype(), scopep);
|
||||
varp->tmpForp(varp->nodep());
|
||||
varp->tmpForp(varp->vscp());
|
||||
m_vInfo[varp].m_id = ++m_lastId;
|
||||
varp->varp()->isInternal(true);
|
||||
varp->vscp()->varp()->isInternal(true);
|
||||
varp->srcp(sp);
|
||||
replace(varp);
|
||||
return;
|
||||
|
|
@ -2591,8 +2557,6 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
if (const DfgVertexVar* const varp = sink.cast<DfgVertexVar>()) {
|
||||
if (!varp->hasSinks() && !varp->isObserved()) return false;
|
||||
}
|
||||
// Keep before final scoped run if feeds an Ast reference
|
||||
if (sink.is<DfgVertexAst>() && m_dfg.modulep()) return true;
|
||||
// Keep if found more than one sink
|
||||
if (foundOne) return true;
|
||||
// Mark first sink found
|
||||
|
|
|
|||
|
|
@ -54,26 +54,6 @@ class DfgRegularize final {
|
|||
vtx.replaceWith(varp);
|
||||
varp->srcp(&vtx);
|
||||
}
|
||||
|
||||
// Const vertices driving an Ast reference can only be inlined in scoped
|
||||
// mode as some algorithms assume VarRefs in certain places.
|
||||
if (m_dfg.modulep()) {
|
||||
for (DfgConst& vtx : m_dfg.constVertices()) {
|
||||
const bool drivesAstRef = vtx.foreachSink([](const DfgVertex& dst) { //
|
||||
return dst.is<DfgAstRd>();
|
||||
});
|
||||
if (!drivesAstRef) continue;
|
||||
|
||||
// The prefered result variable is the canonical one if exists
|
||||
DfgVertexVar* const varp = vtx.getResultVar();
|
||||
if (!varp) continue;
|
||||
|
||||
// Relink all other sinks reading this vertex to read 'varp'
|
||||
varp->srcp(nullptr);
|
||||
vtx.replaceWith(varp);
|
||||
varp->srcp(&vtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<const DfgVertexVar*> gatherCyclicVariables() {
|
||||
|
|
@ -108,9 +88,6 @@ class DfgRegularize final {
|
|||
UASSERT_OBJ(!aVtx.is<DfgVertexVar>(), &aVtx, "Should be an operation vertex");
|
||||
|
||||
if (bVtx.hasMultipleSinks()) {
|
||||
// We are not inlining expressions prior to the final scoped run
|
||||
if (m_dfg.modulep()) return true;
|
||||
|
||||
// Add a temporary if it's cheaper to store and load from memory than recompute
|
||||
if (!aVtx.isCheaperThanLoad()) return true;
|
||||
|
||||
|
|
@ -123,10 +100,8 @@ class DfgRegularize final {
|
|||
// No need to add a temporary if the single sink is a variable already
|
||||
if (sink.is<DfgVertexVar>()) return false;
|
||||
|
||||
// Do not inline expressions prior to the final scoped run, or if they are in a loop
|
||||
if (const DfgAstRd* const astRdp = sink.cast<DfgAstRd>()) {
|
||||
return m_dfg.modulep() || astRdp->inLoop();
|
||||
}
|
||||
// Do not inline expressions into a loop body
|
||||
if (const DfgAstRd* const astRdp = sink.cast<DfgAstRd>()) { return astRdp->inLoop(); }
|
||||
|
||||
// Make sure roots of wide concatenation trees are written to variables,
|
||||
// this enables V3FuncOpt to split them which can be a big speed gain
|
||||
|
|
@ -163,7 +138,7 @@ class DfgRegularize final {
|
|||
});
|
||||
// Delete corresponsing Ast variable at the end
|
||||
if (const DfgVertexVar* const varp = vtx.cast<DfgVertexVar>()) {
|
||||
m_ctx.m_deleteps.push_back(varp->nodep());
|
||||
m_ctx.m_deleteps.push_back(varp->vscp());
|
||||
}
|
||||
// Remove the unused vertex
|
||||
vtx.unlinkDelete(m_dfg);
|
||||
|
|
@ -218,7 +193,6 @@ class DfgRegularize final {
|
|||
// Insert a temporary variable for all vertices that have multiple non-variable sinks
|
||||
|
||||
// Scope cache for below
|
||||
const bool scoped = !m_dfg.modulep();
|
||||
DfgVertex::ScopeCache scopeCache;
|
||||
|
||||
// Ensure intermediate values used multiple times are written to variables
|
||||
|
|
@ -233,7 +207,7 @@ class DfgRegularize final {
|
|||
++m_ctx.m_temporariesIntroduced;
|
||||
const std::string name = m_dfg.makeUniqueName("Regularize", m_nTmps);
|
||||
FileLine* const flp = vtx.fileline();
|
||||
AstScope* const scopep = scoped ? vtx.scopep(scopeCache) : nullptr;
|
||||
AstScope* const scopep = vtx.scopep(scopeCache);
|
||||
DfgVertexVar* const newp = m_dfg.makeNewVar(flp, name, vtx.dtype(), scopep);
|
||||
++m_nTmps;
|
||||
// Replace vertex with the variable, make it drive the variable
|
||||
|
|
@ -248,13 +222,13 @@ class DfgRegularize final {
|
|||
, m_ctx{ctx} {
|
||||
|
||||
uninlineVariables();
|
||||
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed(ctx.prefix() + "regularize-uninlined");
|
||||
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed("regularize-uninlined");
|
||||
|
||||
eliminateVars();
|
||||
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed(ctx.prefix() + "regularize-eliminate");
|
||||
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed("regularize-eliminate");
|
||||
|
||||
insertTemporaries();
|
||||
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed(ctx.prefix() + "regularize-inserttmp");
|
||||
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed("regularize-inserttmp");
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@
|
|||
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Cfg.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Dfg.h"
|
||||
#include "V3DfgPasses.h"
|
||||
#include "V3EmitV.h"
|
||||
#include "V3Os.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
|
@ -55,16 +55,12 @@ DfgArraySel* makeVertex<DfgArraySel, AstArraySel>(const AstArraySel* nodep, DfgG
|
|||
} // namespace
|
||||
|
||||
// Visitor that can convert Ast statements and expressions in Dfg vertices
|
||||
template <bool T_Scoped>
|
||||
class AstToDfgConverter final : public VNVisitor {
|
||||
// NODE STATE
|
||||
// AstNodeExpr/AstVar/AstVarScope::user2p -> DfgVertex* for this Node
|
||||
// AstVar::user3() -> int temporary counter for variable
|
||||
const VNUser3InUse m_user3InUse;
|
||||
|
||||
// TYPES
|
||||
using Variable = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
||||
|
||||
// STATE
|
||||
DfgGraph& m_dfg; // The graph being built
|
||||
V3DfgSynthesisContext& m_ctx; // The context for stats
|
||||
|
|
@ -73,7 +69,7 @@ class AstToDfgConverter final : public VNVisitor {
|
|||
DfgLogic* m_logicp = nullptr;
|
||||
// Variable updates produced by currently converted statement. This almost
|
||||
// always have a single element, so a vector is ok
|
||||
std::vector<std::pair<Variable*, DfgVertexVar*>>* m_updatesp = nullptr;
|
||||
std::vector<std::pair<AstVarScope*, DfgVertexVar*>>* m_updatesp = nullptr;
|
||||
|
||||
bool m_foundUnhandled = false; // Found node not implemented as DFG or not implemented 'visit'
|
||||
bool m_converting = false; // We are trying to convert some logic at the moment
|
||||
|
|
@ -81,14 +77,6 @@ class AstToDfgConverter final : public VNVisitor {
|
|||
size_t m_nUnpack = 0; // Sequence numbers for temporaries
|
||||
|
||||
// METHODS
|
||||
static Variable* getTarget(const AstVarRef* refp) {
|
||||
// TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
return reinterpret_cast<Variable*>(refp->varScopep());
|
||||
} else {
|
||||
return reinterpret_cast<Variable*>(refp->varp());
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate a new non-variable vertex, add it to the currently synthesized logic
|
||||
template <typename Vertex, typename... Args>
|
||||
|
|
@ -117,7 +105,7 @@ class AstToDfgConverter final : public VNVisitor {
|
|||
// Cannot represent cross module references
|
||||
if (nodep->classOrPackagep()) return false;
|
||||
// Check target
|
||||
return V3Dfg::isSupported(getTarget(nodep));
|
||||
return V3Dfg::isSupported(nodep->varScopep());
|
||||
}
|
||||
|
||||
// Given an RValue expression, return the equivalent Vertex, or nullptr if not representable.
|
||||
|
|
@ -154,16 +142,16 @@ class AstToDfgConverter final : public VNVisitor {
|
|||
// Get (or create a new) temporary for this variable
|
||||
const DfgVertexVar* const vtxp = [&]() -> DfgVertexVar* {
|
||||
// The variable being assigned
|
||||
Variable* const tgtp = getTarget(vrefp);
|
||||
AstVarScope* const vscp = vrefp->varScopep();
|
||||
|
||||
// Find existing one, if any
|
||||
for (const auto& pair : *m_updatesp) {
|
||||
if (pair.first == tgtp) return pair.second;
|
||||
if (pair.first == vscp) return pair.second;
|
||||
}
|
||||
|
||||
// Create new one
|
||||
DfgVertexVar* const newp = createTmp(*m_logicp, tgtp, "SynthAssign");
|
||||
m_updatesp->emplace_back(tgtp, newp);
|
||||
DfgVertexVar* const newp = createTmp(*m_logicp, vscp, "SynthAssign");
|
||||
m_updatesp->emplace_back(vscp, newp);
|
||||
|
||||
// Create the Splice driver for the new temporary
|
||||
if (newp->is<DfgVarPacked>()) {
|
||||
|
|
@ -375,7 +363,7 @@ class AstToDfgConverter final : public VNVisitor {
|
|||
}
|
||||
|
||||
// Variable should have been bound before starting conversion
|
||||
DfgVertex* const vtxp = getTarget(nodep)->user2u().template to<DfgVertexVar*>();
|
||||
DfgVertex* const vtxp = nodep->varScopep()->user2u().template to<DfgVertexVar*>();
|
||||
UASSERT_OBJ(vtxp, nodep, "Referenced variable has no associated DfgVertexVar");
|
||||
nodep->user2p(vtxp);
|
||||
}
|
||||
|
|
@ -450,27 +438,26 @@ public:
|
|||
const std::string name = m_dfg.makeUniqueName(prefix, tmpCount);
|
||||
DfgVertexVar* const vtxp = m_dfg.makeNewVar(flp, name, dtype, logic.scopep());
|
||||
logic.synth().emplace_back(vtxp);
|
||||
vtxp->varp()->isInternal(true);
|
||||
vtxp->tmpForp(vtxp->nodep());
|
||||
vtxp->vscp()->varp()->isInternal(true);
|
||||
vtxp->tmpForp(vtxp->vscp());
|
||||
return vtxp;
|
||||
}
|
||||
|
||||
// Create a new temporary variable capable of holding 'varp'
|
||||
DfgVertexVar* createTmp(DfgLogic& logic, Variable* varp, const std::string& prefix) {
|
||||
AstVar* const astVarp = T_Scoped ? reinterpret_cast<AstVarScope*>(varp)->varp()
|
||||
: reinterpret_cast<AstVar*>(varp);
|
||||
DfgVertexVar* createTmp(DfgLogic& logic, AstVarScope* vscp, const std::string& prefix) {
|
||||
AstVar* const astVarp = vscp->varp();
|
||||
FileLine* const flp = astVarp->fileline();
|
||||
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);
|
||||
vtxp->tmpForp(vscp);
|
||||
return vtxp;
|
||||
}
|
||||
|
||||
// Convert AstAssign to Dfg, return true if successful.
|
||||
// Fills 'updates' with bindings for assigned variables.
|
||||
bool convert(std::vector<std::pair<Variable*, DfgVertexVar*>>& updates, DfgLogic& vtx,
|
||||
bool convert(std::vector<std::pair<AstVarScope*, DfgVertexVar*>>& updates, DfgLogic& vtx,
|
||||
AstNodeAssign* nodep) {
|
||||
UASSERT_OBJ(VN_IS(nodep, Assign) || VN_IS(nodep, AssignW), nodep, "Bad NodeAssign");
|
||||
UASSERT_OBJ(updates.empty(), nodep, "'updates' should be empty");
|
||||
|
|
@ -530,21 +517,19 @@ public:
|
|||
// Debug aid - outisde 'AstToDfgSynthesize' as it is a template, but want one instance
|
||||
V3DebugBisect s_dfgSynthDebugBisect{"DfgSynthesize"};
|
||||
|
||||
template <bool T_Scoped>
|
||||
class AstToDfgSynthesize final {
|
||||
// NODE STATE
|
||||
// AstNodeExpr/AstVar/AstVarScope::user2p -> DfgVertex* for this Node
|
||||
|
||||
// TYPES
|
||||
using Variable = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
||||
|
||||
// SymTab must be ordered in order to yield stable results
|
||||
struct VariableComparator final {
|
||||
bool operator()(const Variable* lhs, const Variable* rhs) const {
|
||||
struct AstVarScopeComparator final {
|
||||
bool operator()(const AstVarScope* lhs, const AstVarScope* rhs) const {
|
||||
return lhs->name() < rhs->name();
|
||||
}
|
||||
};
|
||||
using SymTab = std::map<Variable*, DfgVertexVar*, VariableComparator>;
|
||||
using SymTab = std::map<AstVarScope*, DfgVertexVar*, AstVarScopeComparator>;
|
||||
|
||||
// Represents a [potentially partial] driver of a variable
|
||||
struct Driver final {
|
||||
|
|
@ -573,7 +558,7 @@ class AstToDfgSynthesize final {
|
|||
// STATE - Persistent
|
||||
DfgGraph& m_dfg; // The graph being built
|
||||
V3DfgSynthesisContext& m_ctx; // The context for stats
|
||||
AstToDfgConverter<T_Scoped> m_converter; // The convert instance to use for each construct
|
||||
AstToDfgConverter m_converter; // The convert instance to use for each construct
|
||||
size_t m_nBranchCond = 0; // Sequence numbers for temporaries
|
||||
size_t m_nPathPred = 0; // Sequence numbers for temporaries
|
||||
DfgWorklist m_toRevert{m_dfg}; // We need a worklist for reverting synthesis
|
||||
|
|
@ -609,26 +594,16 @@ class AstToDfgSynthesize final {
|
|||
}
|
||||
|
||||
if (VL_UNLIKELY(dumpDfgLevel() >= 9 || m_debugOSrcConep)) {
|
||||
const auto label = m_ctx.prefix() + name;
|
||||
m_dfg.dumpDotFilePrefixed(label);
|
||||
m_dfg.dumpDotFilePrefixed(name);
|
||||
if (m_debugOSrcConep) {
|
||||
// Dump only the subgraph involving the inputs and outputs of the bad vertex
|
||||
m_dfg.dumpDotFilePrefixed(label + "-min", [&](const DfgVertex& v) -> bool {
|
||||
m_dfg.dumpDotFilePrefixed(name + "-min"s, [&](const DfgVertex& v) -> bool {
|
||||
return m_debugOSrcConep->count(&v);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static AstVar* getAstVar(Variable* vp) {
|
||||
// TODO: remove the useless reinterpret_casts when C++17 'if constexpr' actually works
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
return reinterpret_cast<AstVarScope*>(vp)->varp();
|
||||
} else {
|
||||
return reinterpret_cast<AstVar*>(vp);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate a new non-variable vertex, add it to the currently synthesized logic
|
||||
template <typename Vertex, typename... Args>
|
||||
Vertex* make(Args&&... args) {
|
||||
|
|
@ -674,14 +649,7 @@ class AstToDfgSynthesize final {
|
|||
if (std::find(visited.begin(), visited.end(), vtxp) != visited.end()) continue;
|
||||
visited.emplace_back(vtxp);
|
||||
if (const DfgVertexVar* const varp = vtxp->cast<DfgVertexVar>()) {
|
||||
AstVar* const astVarp = [&]() -> AstVar* {
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
return reinterpret_cast<AstVarScope*>(varp->nodep())->varp();
|
||||
} else {
|
||||
return reinterpret_cast<AstVar*>(varp->nodep());
|
||||
}
|
||||
}();
|
||||
if (astVarp->dfgTriLowered()) return true;
|
||||
if (varp->vscp()->varp()->dfgTriLowered()) return true;
|
||||
}
|
||||
vtxp->foreachSource([&](const DfgVertex& src) {
|
||||
stack.emplace_back(&src);
|
||||
|
|
@ -849,15 +817,14 @@ class AstToDfgSynthesize final {
|
|||
if (warned) continue;
|
||||
|
||||
// The variable to warn on
|
||||
AstNode* const nodep = var.tmpForp() ? var.tmpForp() : var.nodep();
|
||||
Variable* const varp = reinterpret_cast<Variable*>(nodep);
|
||||
AstVarScope* const vscp = var.tmpForp() ? var.tmpForp() : var.vscp();
|
||||
|
||||
// Loop index often abused, so suppress
|
||||
if (getAstVar(varp)->isUsedLoopIdx()) continue;
|
||||
if (vscp->varp()->isUsedLoopIdx()) continue;
|
||||
// Tristate lowering can intentionally create overlapping contributors.
|
||||
// Keep the signal marked multidriven for DFG fallback, but suppress
|
||||
// warning only when both overlapping driver cones look tri-lowered.
|
||||
if (getAstVar(varp)->dfgAllowMultidriveTri()) {
|
||||
if (vscp->varp()->dfgAllowMultidriveTri()) {
|
||||
const bool iTri = containsTriLoweredVar(iD.m_vtxp);
|
||||
const bool jTri = containsTriLoweredVar(jD.m_vtxp);
|
||||
const bool triPair = iTri && jTri;
|
||||
|
|
@ -872,9 +839,9 @@ class AstToDfgSynthesize final {
|
|||
const std::string kind = isPacked ? "Bit" : "Element";
|
||||
const std::string part = hi == lo ? (" [" + lo + "]") : ("s [" + hi + ":" + lo + "]");
|
||||
|
||||
varp->v3warn( //
|
||||
vscp->v3warn( //
|
||||
MULTIDRIVEN, //
|
||||
kind << part << " of signal '" << varp->prettyName() << sub << "'"
|
||||
kind << part << " of signal '" << vscp->prettyName() << sub << "'"
|
||||
<< " have multiple combinational drivers."
|
||||
<< " This can cause performance degradation.\n"
|
||||
<< iD.m_flp->warnOther() << "... Location of offending driver\n"
|
||||
|
|
@ -961,29 +928,28 @@ class AstToDfgSynthesize final {
|
|||
void initializeEntrySymbolTable(SymTab& iSymTab) {
|
||||
m_logicp->foreachSource([&](DfgVertex& src) {
|
||||
DfgVertexVar* const vvp = src.as<DfgVertexVar>();
|
||||
Variable* const varp = reinterpret_cast<Variable*>(vvp->nodep());
|
||||
iSymTab[varp] = vvp;
|
||||
iSymTab[vvp->vscp()] = vvp;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Join variable drivers across a control flow confluence (insert muxes ...)
|
||||
DfgVertexVar* joinDrivers(Variable* varp, DfgVertexVar* predicatep, //
|
||||
DfgVertexVar* joinDrivers(AstVarScope* vscp, DfgVertexVar* predicatep, //
|
||||
DfgVertexVar* thenp, DfgVertexVar* elsep) {
|
||||
AstNode* const thenVarp = thenp->tmpForp() ? thenp->tmpForp() : thenp->nodep();
|
||||
AstNode* const elseVarp = elsep->tmpForp() ? elsep->tmpForp() : elsep->nodep();
|
||||
UASSERT_OBJ(thenVarp == elseVarp, varp, "Attempting to join unrelated variables");
|
||||
AstVarScope* const thenVscp = thenp->tmpForp() ? thenp->tmpForp() : thenp->vscp();
|
||||
AstVarScope* const elseVscp = elsep->tmpForp() ? elsep->tmpForp() : elsep->vscp();
|
||||
UASSERT_OBJ(thenVscp == elseVscp, vscp, "Attempting to join unrelated variables");
|
||||
|
||||
// If both bindings are the the same (variable not updated through either path),
|
||||
// then there is nothing to do, can use the same binding
|
||||
if (thenp == elsep) return thenp;
|
||||
|
||||
// We can't join the input variable just yet, so bail
|
||||
if (thenp->nodep() == varp) {
|
||||
if (thenp->vscp() == vscp) {
|
||||
++m_ctx.m_synt.nonSynJoinInput;
|
||||
return nullptr;
|
||||
}
|
||||
if (elsep->nodep() == varp) {
|
||||
if (elsep->vscp() == vscp) {
|
||||
++m_ctx.m_synt.nonSynJoinInput;
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -1003,13 +969,13 @@ class AstToDfgSynthesize final {
|
|||
std::vector<Driver> eDrivers = gatherDrivers(elsep->srcp()->as<DfgVertexSplice>());
|
||||
|
||||
// Default drivers should be the same or not present on either
|
||||
UASSERT_OBJ(tDefaultp == eDefaultp, varp, "Different default drivers");
|
||||
UASSERT_OBJ(tDefaultp == eDefaultp, vscp, "Different default drivers");
|
||||
|
||||
// Location to use for the join vertices
|
||||
FileLine* const flp = predicatep->fileline();
|
||||
|
||||
// Create a fresh temporary for the joined value
|
||||
DfgVertexVar* const joinp = m_converter.createTmp(*m_logicp, varp, "SynthJoin");
|
||||
DfgVertexVar* const joinp = m_converter.createTmp(*m_logicp, vscp, "SynthJoin");
|
||||
DfgVertexSplice* const joinSplicep = make<DfgSplicePacked>(flp, joinp->dtype());
|
||||
joinp->srcp(joinSplicep);
|
||||
|
||||
|
|
@ -1020,7 +986,7 @@ class AstToDfgSynthesize final {
|
|||
&& eDrivers.size() == 1 //
|
||||
&& eDrivers[0].m_lo == 0 //
|
||||
&& eDrivers[0].m_hi == elsep->width() - 1) {
|
||||
UASSERT_OBJ(!tDefaultp, varp, "Fully driven variable have default driver");
|
||||
UASSERT_OBJ(!tDefaultp, vscp, "Fully driven variable have default driver");
|
||||
|
||||
DfgCond* const condp = make<DfgCond>(flp, joinp->dtype());
|
||||
condp->condp(predicatep);
|
||||
|
|
@ -1081,11 +1047,11 @@ class AstToDfgSynthesize final {
|
|||
// Any variable that does not have a binding on both paths will be removed. These might be
|
||||
// temporaries, loop vars, etc used only in one branch. Conversion will fail if the
|
||||
// variable is actually referenced later.
|
||||
std::vector<Variable*> toRemove;
|
||||
std::vector<AstVarScope*> toRemove;
|
||||
|
||||
// Join each symbol
|
||||
for (std::pair<Variable* const, DfgVertexVar*>& pair : elseSymTab) {
|
||||
Variable* const varp = pair.first;
|
||||
for (std::pair<AstVarScope* const, DfgVertexVar*>& pair : elseSymTab) {
|
||||
AstVarScope* const varp = pair.first;
|
||||
// Find same variable on the else path
|
||||
const auto it = thenSymTab.find(varp);
|
||||
// Record for removal if not assigned on both paths
|
||||
|
|
@ -1102,7 +1068,7 @@ class AstToDfgSynthesize final {
|
|||
}
|
||||
|
||||
// Remove variables not assigned on both paths
|
||||
for (Variable* const varp : toRemove) elseSymTab.erase(varp);
|
||||
for (AstVarScope* const varp : toRemove) elseSymTab.erase(varp);
|
||||
|
||||
// Done
|
||||
return true;
|
||||
|
|
@ -1285,8 +1251,8 @@ class AstToDfgSynthesize final {
|
|||
// Given the drivers of a variable after converting a single statement
|
||||
// 'newp', add drivers from 'oldp' that were not reassigned be drivers
|
||||
// in newp. This computes the total result of all previous assignments.
|
||||
bool incorporatePreviousValue(Variable* varp, DfgVertexVar* newp, DfgVertexVar* oldp) {
|
||||
UASSERT_OBJ(newp->srcp(), varp, "Assigned variable has no driver");
|
||||
bool incorporatePreviousValue(AstVarScope* vscp, DfgVertexVar* newp, DfgVertexVar* oldp) {
|
||||
UASSERT_OBJ(newp->srcp(), vscp, "Assigned variable has no driver");
|
||||
|
||||
// Easy if there is no old value...
|
||||
if (!oldp) return true;
|
||||
|
|
@ -1296,12 +1262,12 @@ class AstToDfgSynthesize final {
|
|||
|
||||
// If the old value is the real variable we just computed the new value for,
|
||||
// then it is the circular feedback into the synthesized block, add it as default driver.
|
||||
if (oldp->nodep() == varp) {
|
||||
if (oldp->vscp() == vscp) {
|
||||
if (!nSplicep->wholep()) newp->defaultp(oldp);
|
||||
return true;
|
||||
}
|
||||
|
||||
UASSERT_OBJ(oldp->srcp(), varp, "Previously assigned variable has no driver");
|
||||
UASSERT_OBJ(oldp->srcp(), vscp, "Previously assigned variable has no driver");
|
||||
|
||||
// Can't do arrays yet
|
||||
if (!newp->isPacked()) {
|
||||
|
|
@ -1347,16 +1313,16 @@ class AstToDfgSynthesize final {
|
|||
// Use fresh set of vertices in m_converter
|
||||
const VNUser2InUse user2InUse;
|
||||
|
||||
// Initialize Variable -> Vertex bindings available in this block
|
||||
// Initialize AstVarScope -> Vertex bindings available in this block
|
||||
for (const auto& pair : iSymTab) {
|
||||
Variable* const varp = pair.first;
|
||||
AstVarScope* const varp = pair.first;
|
||||
DfgVertexVar* const vtxp = pair.second;
|
||||
varp->user2p(vtxp);
|
||||
oSymTab[varp] = vtxp;
|
||||
}
|
||||
|
||||
// Synthesize each statement one after the other
|
||||
std::vector<std::pair<Variable*, DfgVertexVar*>> updates;
|
||||
std::vector<std::pair<AstVarScope*, DfgVertexVar*>> updates;
|
||||
for (AstNodeStmt* const stmtp : stmtps) {
|
||||
// Regular statements
|
||||
AstNodeAssign* const ap = VN_CAST(stmtp, NodeAssign);
|
||||
|
|
@ -1369,7 +1335,7 @@ class AstToDfgSynthesize final {
|
|||
// Apply variable updates from this statement
|
||||
for (const auto& pair : updates) {
|
||||
// The target variable that was assigned to
|
||||
Variable* const varp = pair.first;
|
||||
AstVarScope* const vscp = pair.first;
|
||||
// The new, potentially partially assigned value
|
||||
DfgVertexVar* const newp = pair.second;
|
||||
// Normalize drivers within this statement, bail if multidriven
|
||||
|
|
@ -1377,7 +1343,6 @@ class AstToDfgSynthesize final {
|
|||
std::vector<Driver> drivers = gatherDrivers(srcp);
|
||||
const bool single = drivers.size() == 1;
|
||||
if (!normalizeDrivers(*newp, drivers)) {
|
||||
getAstVar(varp)->setDfgMultidriven();
|
||||
++m_ctx.m_synt.nonSynMultidrive;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1387,13 +1352,13 @@ class AstToDfgSynthesize final {
|
|||
for (const Driver& d : drivers) srcp->addDriver(d.m_vtxp, d.m_lo, d.m_flp);
|
||||
}
|
||||
// The old value, if any
|
||||
DfgVertexVar* const oldp = varp->user2u().template to<DfgVertexVar*>();
|
||||
DfgVertexVar* const oldp = vscp->user2u().template to<DfgVertexVar*>();
|
||||
// Inncorporate old value into the new value
|
||||
if (!incorporatePreviousValue(varp, newp, oldp)) return false;
|
||||
if (!incorporatePreviousValue(vscp, newp, oldp)) return false;
|
||||
// Update binding of target variable
|
||||
varp->user2p(newp);
|
||||
vscp->user2p(newp);
|
||||
// Update output symbol table of this block
|
||||
oSymTab[varp] = newp;
|
||||
oSymTab[vscp] = newp;
|
||||
}
|
||||
updates.clear();
|
||||
continue;
|
||||
|
|
@ -1518,10 +1483,8 @@ class AstToDfgSynthesize final {
|
|||
// braces and check here too. We can't touch any output variables if so.
|
||||
const bool missing = m_logicp->foreachSink([&](const DfgVertex& sink) {
|
||||
const DfgUnresolved* const unresolvedp = sink.as<DfgUnresolved>();
|
||||
AstNode* const tgtp = unresolvedp->singleSink()->as<DfgVertexVar>()->nodep();
|
||||
// cppcheck-suppress constVariablePointer
|
||||
Variable* const varp = reinterpret_cast<Variable*>(tgtp);
|
||||
return !oSymTab.count(varp);
|
||||
AstVarScope* const vscp = unresolvedp->singleSink()->as<DfgVertexVar>()->vscp();
|
||||
return !oSymTab.count(vscp);
|
||||
});
|
||||
if (missing) {
|
||||
++m_ctx.m_synt.nonSynFalseWrite;
|
||||
|
|
@ -1532,7 +1495,7 @@ class AstToDfgSynthesize final {
|
|||
return !m_logicp->foreachSink([&](DfgVertex& sink) {
|
||||
DfgUnresolved* const unresolvedp = sink.as<DfgUnresolved>();
|
||||
const DfgVertexVar* const varp = unresolvedp->singleSink()->as<DfgVertexVar>();
|
||||
DfgVertexVar* const resp = oSymTab.at(reinterpret_cast<Variable*>(varp->nodep()));
|
||||
DfgVertexVar* const resp = oSymTab.at(varp->vscp());
|
||||
UASSERT_OBJ(resp->srcp(), resp, "Undriven result");
|
||||
|
||||
// If the output is not used further in the synthesized logic itself,
|
||||
|
|
@ -1750,10 +1713,10 @@ class AstToDfgSynthesize final {
|
|||
// There should be no sinks left for unselected DfgLogic, delete them here
|
||||
UASSERT_OBJ(!logicp->hasSinks(), vtxp, "Unselected 'DfgLogic' with sinks remaining");
|
||||
// Input variables will be read in Ast code, add Ast reference vertices
|
||||
// AstVar/AstVarScope::user4p() -> corresponding DfgVertexVar* in the graph
|
||||
// AstVarScope::user4p() -> corresponding DfgVertexVar* in the graph
|
||||
const VNUser4InUse m_user4InUse;
|
||||
logicp->foreachSource([](DfgVertex& src) {
|
||||
src.as<DfgVertexVar>()->nodep()->user4p(&src);
|
||||
src.as<DfgVertexVar>()->vscp()->user4p(&src);
|
||||
return false;
|
||||
});
|
||||
V3DfgPasses::addAstRefs(m_dfg, logicp->nodep(), [](AstNode* varp) { //
|
||||
|
|
@ -1831,8 +1794,6 @@ class AstToDfgSynthesize final {
|
|||
const bool newEntry = resolvedDrivers.emplace(&var, resolvedp).second;
|
||||
UASSERT_OBJ(newEntry, &var, "Dupliacte driver");
|
||||
}
|
||||
// Mark as multidriven for future DFG runs - here, so we get all warnings above
|
||||
for (const DfgVertexVar* const vtxp : multidrivenps) vtxp->varp()->setDfgMultidriven();
|
||||
// Revert and remove drivers of multi-driven variables
|
||||
revert(m_ctx.m_synt.revertMultidrive);
|
||||
// Replace all DfgUnresolved with the resolved drivers
|
||||
|
|
@ -1866,10 +1827,10 @@ class AstToDfgSynthesize final {
|
|||
} else {
|
||||
// Not synthesized. Logic stays in Ast. Add Ast reference vertices.
|
||||
// Outputs already marked by revertTransivelyAndRemove.
|
||||
// AstVar/AstVarScope::user4p() -> corresponding DfgVertexVar* in the graph
|
||||
// AstVarScope::user4p() -> corresponding DfgVertexVar* in the graph
|
||||
const VNUser4InUse m_user4InUse;
|
||||
logicp->foreachSource([](DfgVertex& src) {
|
||||
src.as<DfgVertexVar>()->nodep()->user4p(&src);
|
||||
src.as<DfgVertexVar>()->vscp()->user4p(&src);
|
||||
return false;
|
||||
});
|
||||
V3DfgPasses::addAstRefs(m_dfg, logicp->nodep(), [](AstNode* varp) { //
|
||||
|
|
@ -1926,7 +1887,7 @@ public:
|
|||
// Final step outside, as both AstToDfgSynthesize and removeUnused used DfgUserMap
|
||||
UINFO(5, "Step 6: Remove all unused vertices");
|
||||
V3DfgPasses::removeUnused(dfg);
|
||||
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed(ctx.prefix() + "synth-rmunused");
|
||||
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed("synth-rmunused");
|
||||
|
||||
// No operation vertex should have multiple sinks. Cyclic decomoposition
|
||||
// depends on this and it can easily be ensured by using temporaries.
|
||||
|
|
@ -2021,9 +1982,5 @@ void V3DfgPasses::synthesize(DfgGraph& dfg, V3DfgContext& ctx) {
|
|||
// Select which DfgLogic to attempt to synthesize
|
||||
dfgSelectLogicForSynthesis(dfg);
|
||||
// Synthesize them - also removes un-synthesized DfgLogic, so must run even if nothing selected
|
||||
if (dfg.modulep()) {
|
||||
AstToDfgSynthesize</* T_Scoped: */ false>::apply(dfg, ctx.m_synthContext);
|
||||
} else {
|
||||
AstToDfgSynthesize</* T_Scoped: */ true>::apply(dfg, ctx.m_synthContext);
|
||||
}
|
||||
AstToDfgSynthesize::apply(dfg, ctx.m_synthContext);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,47 +48,32 @@
|
|||
class DfgVertexVar VL_NOT_FINAL : public DfgVertex {
|
||||
// Represents a variable. It has 2 optional inputs, 'srcp' and 'defaultp'.
|
||||
|
||||
AstVar* const m_varp; // The AstVar associated with this vertex (not owned by this vertex)
|
||||
AstVarScope* const m_varScopep; // The AstVarScope associated with this vertex (not owned)
|
||||
AstVarScope* const m_vscp; // The AstVarScope associated with this vertex (not owned)
|
||||
// Location of driver of this variable. Only used for converting back to Ast. Might be nullptr.
|
||||
FileLine* m_driverFileLine = nullptr;
|
||||
// If this DfgVertexVar is a synthesized temporary, this is the original Var/VarScope it stands
|
||||
// for. It might point to m_varp/m_varScopep itself to indicate it's a temporary without an
|
||||
// associated input Var/VarScope.
|
||||
AstNode* m_tmpForp = nullptr;
|
||||
// If this DfgVertexVar is a synthesized temporary, this is the original AstVarScope it stands
|
||||
// for. It might point to m_vscp itself to indicate it's a temporary without an associated
|
||||
// input AstVarScope.
|
||||
AstVarScope* m_tmpForp = nullptr;
|
||||
|
||||
DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp, AstVarScope* vscp)
|
||||
: DfgVertex{dfg, type, varp->fileline(), *DfgDataType::fromAst(varp->dtypep())}
|
||||
, m_varp{varp}
|
||||
, m_varScopep{vscp} {
|
||||
#ifdef VL_DEBUG
|
||||
if (v3Global.rootp()->topScopep()) {
|
||||
UASSERT_OBJ(vscp, varp, "Un-scoped DfgVertexVar created in scoped DfgGraph");
|
||||
} else {
|
||||
UASSERT_OBJ(!vscp, varp, "Scoped DfgVertexVar created in un-scoped DfgGraph");
|
||||
}
|
||||
#endif
|
||||
protected:
|
||||
DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVarScope* vscp)
|
||||
: DfgVertex{dfg, type, vscp->varp()->fileline(),
|
||||
*DfgDataType::fromAst(vscp->varp()->dtypep())}
|
||||
, m_vscp{vscp} {
|
||||
// Increment reference count
|
||||
AstNode* const variablep = nodep();
|
||||
variablep->user1(variablep->user1() + 0x20);
|
||||
UASSERT_OBJ((variablep->user1() >> 5) > 0, variablep, "Reference count overflow");
|
||||
m_vscp->user1(m_vscp->user1() + 0x20);
|
||||
UASSERT_OBJ((m_vscp->user1() >> 5) > 0, m_vscp, "Reference count overflow");
|
||||
// Allocate sources
|
||||
newInput();
|
||||
newInput();
|
||||
}
|
||||
|
||||
protected:
|
||||
DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp)
|
||||
: DfgVertexVar{dfg, type, varp, nullptr} {}
|
||||
DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVarScope* vscp)
|
||||
: DfgVertexVar{dfg, type, vscp->varp(), vscp} {}
|
||||
|
||||
public:
|
||||
~DfgVertexVar() {
|
||||
// Decrement reference count
|
||||
AstNode* const variablep = nodep();
|
||||
variablep->user1(variablep->user1() - 0x20);
|
||||
UASSERT_OBJ((variablep->user1() >> 5) >= 0, variablep, "Reference count underflow");
|
||||
m_vscp->user1(m_vscp->user1() - 0x20);
|
||||
UASSERT_OBJ((m_vscp->user1() >> 5) >= 0, m_vscp, "Reference count underflow");
|
||||
}
|
||||
ASTGEN_MEMBERS_DfgVertexVar;
|
||||
|
||||
|
|
@ -102,42 +87,39 @@ public:
|
|||
std::string srcName(size_t idx) const override final { return idx ? "defaultp" : "srcp"; }
|
||||
|
||||
// The Ast variable this vertex representess
|
||||
AstVar* varp() const { return m_varp; }
|
||||
AstVarScope* varScopep() const { return m_varScopep; }
|
||||
AstNode* nodep() const {
|
||||
return m_varScopep ? static_cast<AstNode*>(m_varScopep) : static_cast<AstNode*>(m_varp);
|
||||
}
|
||||
// AstVar* varp() const { return m_varp; }
|
||||
AstVarScope* vscp() const { return m_vscp; }
|
||||
|
||||
// If this is a temporary, the Ast variable it stands for, or same as
|
||||
// 'nodep()' if it's a temporary with no associated original Ast variable.
|
||||
AstNode* tmpForp() const { return m_tmpForp; }
|
||||
void tmpForp(AstNode* nodep) { m_tmpForp = nodep; }
|
||||
AstVarScope* tmpForp() const { return m_tmpForp; }
|
||||
void tmpForp(AstVarScope* nodep) { m_tmpForp = nodep; }
|
||||
|
||||
// Location of driver of variable (only used if 'srcp' is not a splice)
|
||||
FileLine* driverFileLine() const { return m_driverFileLine; }
|
||||
void driverFileLine(FileLine* flp) { m_driverFileLine = flp; }
|
||||
|
||||
// Variable referenced from other DFG in the same module/netlist
|
||||
bool hasDfgRefs() const { return nodep()->user1() >> 6; } // I.e.: (nodep()->user1() >> 5) > 1
|
||||
bool hasDfgRefs() const { return m_vscp->user1() >> 6; } // I.e.: (nodep()->user1() >> 5) > 1
|
||||
|
||||
// Variable referenced from Ast code in the same module/netlist
|
||||
static bool hasModWrRefs(const AstNode* nodep) { return nodep->user1() & 0x08; }
|
||||
static void setHasModWrRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x08); }
|
||||
bool hasModWrRefs() const { return hasModWrRefs(nodep()); }
|
||||
void setHasModWrRefs() const { setHasModWrRefs(nodep()); }
|
||||
static bool hasModWrRefs(const AstVarScope* nodep) { return nodep->user1() & 0x08; }
|
||||
static void setHasModWrRefs(AstVarScope* nodep) { nodep->user1(nodep->user1() | 0x08); }
|
||||
bool hasModWrRefs() const { return hasModWrRefs(m_vscp); }
|
||||
void setHasModWrRefs() const { setHasModWrRefs(m_vscp); }
|
||||
|
||||
// Variable referenced outside the containing module/netlist.
|
||||
static bool hasExtRdRefs(const AstNode* nodep) { return nodep->user1() & 0x01; }
|
||||
static bool hasExtWrRefs(const AstNode* nodep) { return nodep->user1() & 0x02; }
|
||||
static void setHasExtRdRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x01); }
|
||||
static void setHasExtWrRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x02); }
|
||||
bool hasExtRdRefs() const { return hasExtRdRefs(nodep()); }
|
||||
bool hasExtWrRefs() const { return hasExtWrRefs(nodep()); }
|
||||
static bool hasExtRdRefs(const AstVarScope* nodep) { return nodep->user1() & 0x01; }
|
||||
static bool hasExtWrRefs(const AstVarScope* nodep) { return nodep->user1() & 0x02; }
|
||||
static void setHasExtRdRefs(AstVarScope* nodep) { nodep->user1(nodep->user1() | 0x01); }
|
||||
static void setHasExtWrRefs(AstVarScope* nodep) { nodep->user1(nodep->user1() | 0x02); }
|
||||
bool hasExtRdRefs() const { return hasExtRdRefs(m_vscp); }
|
||||
bool hasExtWrRefs() const { return hasExtWrRefs(m_vscp); }
|
||||
bool hasExtRefs() const { return hasExtRdRefs() || hasExtWrRefs(); }
|
||||
|
||||
// Variable referenced via READWRITE references
|
||||
static bool hasRWRefs(const AstNode* nodep) { return nodep->user1() & 0x10; }
|
||||
static void setHasRWRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x10); }
|
||||
static bool hasRWRefs(const AstVarScope* nodep) { return nodep->user1() & 0x10; }
|
||||
static void setHasRWRefs(AstVarScope* nodep) { nodep->user1(nodep->user1() | 0x10); }
|
||||
|
||||
// True iff the value of this variable is read outside this DfgGraph
|
||||
bool isObserved() const {
|
||||
|
|
@ -150,10 +132,10 @@ public:
|
|||
// The value of this vertex might differ from what is defined by its drivers
|
||||
// 'srcp' and 'defaultp'. That is, it might be assigned, possibly partially,
|
||||
// or abruptly outside the graph, hence it is not equivalent to its 'srcp'.
|
||||
static bool isVolatile(const AstNode* nodep) {
|
||||
static bool isVolatile(const AstVarScope* nodep) {
|
||||
return hasModWrRefs(nodep) || hasExtWrRefs(nodep);
|
||||
}
|
||||
bool isVolatile() const { return isVolatile(nodep()); }
|
||||
bool isVolatile() const { return isVolatile(m_vscp); }
|
||||
};
|
||||
|
||||
class DfgVarArray final : public DfgVertexVar {
|
||||
|
|
@ -161,10 +143,6 @@ class DfgVarArray final : public DfgVertexVar {
|
|||
friend class DfgVisitor;
|
||||
|
||||
public:
|
||||
DfgVarArray(DfgGraph& dfg, AstVar* varp)
|
||||
: DfgVertexVar{dfg, dfgType(), varp} {
|
||||
UASSERT_OBJ(isArray(), varp, "Non-array DfgVarArray");
|
||||
}
|
||||
DfgVarArray(DfgGraph& dfg, AstVarScope* vscp)
|
||||
: DfgVertexVar{dfg, dfgType(), vscp} {
|
||||
UASSERT_OBJ(isArray(), vscp, "Non-array DfgVarArray");
|
||||
|
|
@ -177,10 +155,6 @@ class DfgVarPacked final : public DfgVertexVar {
|
|||
friend class DfgVisitor;
|
||||
|
||||
public:
|
||||
DfgVarPacked(DfgGraph& dfg, AstVar* varp)
|
||||
: DfgVertexVar{dfg, dfgType(), varp} {
|
||||
UASSERT_OBJ(isPacked(), varp, "Non-packed DfgVarPacked");
|
||||
}
|
||||
DfgVarPacked(DfgGraph& dfg, AstVarScope* vscp)
|
||||
: DfgVertexVar{dfg, dfgType(), vscp} {
|
||||
UASSERT_OBJ(isPacked(), vscp, "Non-packed DfgVarPacked");
|
||||
|
|
|
|||
|
|
@ -1455,11 +1455,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
DECL_OPTION("-fdead-assigns", FOnOff, &m_fDeadAssigns);
|
||||
DECL_OPTION("-fdead-cells", FOnOff, &m_fDeadCells);
|
||||
DECL_OPTION("-fdedup", FOnOff, &m_fDedupe);
|
||||
DECL_OPTION("-fdfg", CbFOnOff, [this](bool flag) {
|
||||
m_fDfgPreInline = flag;
|
||||
m_fDfgPostInline = flag;
|
||||
m_fDfgScoped = flag;
|
||||
});
|
||||
DECL_OPTION("-fdfg", CbFOnOff, [this](bool flag) { m_fDfg = flag; });
|
||||
DECL_OPTION("-fdfg-break-cycles", FOnOff, &m_fDfgBreakCycles);
|
||||
DECL_OPTION("-fdfg-peephole", FOnOff, &m_fDfgPeephole);
|
||||
DECL_OPTION("-fdfg-peephole-", CbPartialMatch, [this](const char* optp) { //
|
||||
|
|
@ -1468,11 +1464,18 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
DECL_OPTION("-fno-dfg-peephole-", CbPartialMatch, [this](const char* optp) { //
|
||||
m_fDfgPeepholeDisabled.emplace(optp);
|
||||
});
|
||||
DECL_OPTION("-fdfg-pre-inline", FOnOff, &m_fDfgPreInline);
|
||||
DECL_OPTION("-fdfg-post-inline", FOnOff, &m_fDfgPostInline);
|
||||
DECL_OPTION("-fdfg-pre-inline", CbFOnOff, [fl](bool) {
|
||||
fl->v3warn(DEPRECATED, "Option '-fno-dfg-pre-inline' is deprecated and has no effect");
|
||||
});
|
||||
DECL_OPTION("-fdfg-post-inline", CbFOnOff, [fl](bool) {
|
||||
fl->v3warn(DEPRECATED, "Option '-fno-dfg-post-inline' is deprecated and has no effect");
|
||||
});
|
||||
DECL_OPTION("-fdfg-push-down-sels", FOnOff, &m_fDfgPushDownSels);
|
||||
DECL_OPTION("-fdfg-scoped", FOnOff, &m_fDfgScoped);
|
||||
DECL_OPTION("-fdfg-synthesize-all", FOnOff, &m_fDfgSynthesizeAll);
|
||||
DECL_OPTION("-fdfg-scoped", CbFOnOff, [this, fl](bool flag) {
|
||||
fl->v3warn(DEPRECATED, "Option '-fno-dfg-scoped' is deprecated, use '-fno-dfg' instead.");
|
||||
m_fDfg = flag;
|
||||
});
|
||||
DECL_OPTION("-fexpand", FOnOff, &m_fExpand);
|
||||
DECL_OPTION("-ffunc-opt", CbFOnOff, [this](bool flag) { //
|
||||
m_fFuncSplitCat = flag;
|
||||
|
|
@ -2351,9 +2354,7 @@ void V3Options::optimize(int level) {
|
|||
m_fConst = flag;
|
||||
m_fConstBitOpTree = flag;
|
||||
m_fDedupe = flag;
|
||||
m_fDfgPreInline = flag;
|
||||
m_fDfgPostInline = flag;
|
||||
m_fDfgScoped = flag;
|
||||
m_fDfg = flag;
|
||||
m_fDeadAssigns = flag;
|
||||
m_fDeadCells = flag;
|
||||
m_fExpand = flag;
|
||||
|
|
|
|||
|
|
@ -399,10 +399,8 @@ private:
|
|||
bool m_fDedupe; // main switch: -fno-dedupe: logic deduplication
|
||||
bool m_fDfgBreakCycles = true; // main switch: -fno-dfg-break-cycles
|
||||
bool m_fDfgPeephole = true; // main switch: -fno-dfg-peephole
|
||||
bool m_fDfgPreInline; // main switch: -fno-dfg-pre-inline and -fno-dfg
|
||||
bool m_fDfgPostInline; // main switch: -fno-dfg-post-inline and -fno-dfg
|
||||
bool m_fDfgPushDownSels = true; // main switch: -fno-dfg-push-down-sels
|
||||
bool m_fDfgScoped; // main switch: -fno-dfg-scoped and -fno-dfg
|
||||
bool m_fDfg; // main switch: -fno-dfg
|
||||
bool m_fDfgSynthesizeAll = false; // main switch: -fdfg-synthesize-all
|
||||
bool m_fDeadAssigns; // main switch: -fno-dead-assigns: remove dead assigns
|
||||
bool m_fDeadCells; // main switch: -fno-dead-cells: remove dead cells
|
||||
|
|
@ -718,12 +716,10 @@ public:
|
|||
bool fConstBitOpTree() const { return m_fConstBitOpTree; }
|
||||
bool fConstEager() const { return m_fConstEager; }
|
||||
bool fDedupe() const { return m_fDedupe; }
|
||||
bool fDfg() const { return m_fDfg; }
|
||||
bool fDfgBreakCycles() const { return m_fDfgBreakCycles; }
|
||||
bool fDfgPeephole() const { return m_fDfgPeephole; }
|
||||
bool fDfgPreInline() const { return m_fDfgPreInline; }
|
||||
bool fDfgPostInline() const { return m_fDfgPostInline; }
|
||||
bool fDfgPushDownSels() const { return m_fDfgPushDownSels; }
|
||||
bool fDfgScoped() const { return m_fDfgScoped; }
|
||||
bool fDfgSynthesizeAll() const { return m_fDfgSynthesizeAll; }
|
||||
bool fDfgPeepholeEnabled(const std::string& name) const {
|
||||
return !m_fDfgPeepholeDisabled.count(name);
|
||||
|
|
|
|||
|
|
@ -307,15 +307,8 @@ static void process() {
|
|||
v3Global.constRemoveXs(true);
|
||||
}
|
||||
|
||||
if (v3Global.opt.fDfgPreInline() || v3Global.opt.fDfgPostInline()) {
|
||||
// If doing DFG optimization, extract some additional candidates
|
||||
V3DfgOptimizer::extract(v3Global.rootp());
|
||||
}
|
||||
|
||||
if (v3Global.opt.fDfgPreInline()) {
|
||||
// Pre inline DFG optimization
|
||||
V3DfgOptimizer::optimize(v3Global.rootp(), "pre inline");
|
||||
}
|
||||
// If doing DFG optimization, extract some additional candidates
|
||||
if (v3Global.opt.fDfg()) V3DfgOptimizer::extract(v3Global.rootp());
|
||||
|
||||
if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) {
|
||||
// Module inlining
|
||||
|
|
@ -329,15 +322,10 @@ static void process() {
|
|||
|
||||
if (v3Global.opt.trace()) V3Interface::interfaceAll(v3Global.rootp());
|
||||
|
||||
if (v3Global.opt.fDfgPostInline()) {
|
||||
// Post inline DFG optimization
|
||||
V3DfgOptimizer::optimize(v3Global.rootp(), "post inline");
|
||||
}
|
||||
|
||||
// --PRE-FLAT OPTIMIZATIONS------------------
|
||||
|
||||
// Initial const/dead to reduce work for ordering code
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp());
|
||||
v3Global.checkTree();
|
||||
|
||||
V3Dead::deadifyDTypes(v3Global.rootp());
|
||||
|
|
@ -355,7 +343,7 @@ static void process() {
|
|||
V3Inst::instAll(v3Global.rootp());
|
||||
|
||||
// Inst may have made lots of concats; fix them
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp());
|
||||
|
||||
// Flatten hierarchy, creating a SCOPE for each module's usage as a cell
|
||||
// No more AstAlias after linkDotScope
|
||||
|
|
@ -370,7 +358,7 @@ static void process() {
|
|||
|
||||
if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) {
|
||||
// Cleanup
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp());
|
||||
V3Dead::deadifyDTypesScoped(v3Global.rootp());
|
||||
v3Global.checkTree();
|
||||
}
|
||||
|
|
@ -398,7 +386,7 @@ static void process() {
|
|||
V3Slice::sliceAll(v3Global.rootp());
|
||||
|
||||
// Push constants across variables and remove redundant assignments
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp());
|
||||
|
||||
if (v3Global.opt.fLife()) V3Life::lifeAll(v3Global.rootp());
|
||||
|
||||
|
|
@ -409,7 +397,7 @@ static void process() {
|
|||
}
|
||||
|
||||
// Cleanup
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp());
|
||||
V3Dead::deadifyDTypesScoped(v3Global.rootp());
|
||||
v3Global.checkTree();
|
||||
|
||||
|
|
@ -429,10 +417,8 @@ static void process() {
|
|||
// forcing.
|
||||
V3Force::forceAll(v3Global.rootp());
|
||||
|
||||
if (v3Global.opt.fDfgScoped()) {
|
||||
// Scoped DFG optimization
|
||||
V3DfgOptimizer::optimize(v3Global.rootp(), "scoped");
|
||||
}
|
||||
// DFG optimization
|
||||
if (v3Global.opt.fDfg()) V3DfgOptimizer::optimize(v3Global.rootp());
|
||||
|
||||
// Gate-based logic elimination; eliminate signals and push constant across cell
|
||||
// boundaries Instant propagation makes lots-o-constant reduction possibilities.
|
||||
|
|
|
|||
|
|
@ -465,9 +465,9 @@
|
|||
+000010 point: type=line comment=block hier=top.t.cond1
|
||||
endfunction
|
||||
|
||||
~000011 assign a = (cyc == 0) ? clk : 1'bz;
|
||||
~000031 assign a = (cyc == 0) ? clk : 1'bz;
|
||||
-000000 point: type=branch comment=cond_then hier=top.t.cond1
|
||||
+000011 point: type=branch comment=cond_else hier=top.t.cond1
|
||||
+000031 point: type=branch comment=cond_else hier=top.t.cond1
|
||||
~000028 assign b = (cyc == 1) ? clk : 0;
|
||||
-000003 point: type=branch comment=cond_then hier=top.t.cond1
|
||||
+000028 point: type=branch comment=cond_else hier=top.t.cond1
|
||||
|
|
|
|||
|
|
@ -156,9 +156,9 @@ DA:325,1
|
|||
DA:328,10
|
||||
DA:329,10
|
||||
DA:330,10
|
||||
DA:333,11
|
||||
DA:333,31
|
||||
BRDA:333,0,0,0
|
||||
BRDA:333,0,1,11
|
||||
BRDA:333,0,1,31
|
||||
DA:334,28
|
||||
BRDA:334,0,0,3
|
||||
BRDA:334,0,1,28
|
||||
|
|
|
|||
|
|
@ -11,11 +11,10 @@ import vltest_bootstrap
|
|||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile(verilator_flags2=["--stats"])
|
||||
test.compile(verilator_flags2=["--stats", "-fno-table"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.file_grep(test.stats, r'Optimizations, DFG pre inline BinToOneHot, decoders created\s+(\d+)',
|
||||
4)
|
||||
test.file_grep(test.stats, r'Optimizations, DFG, BinToOneHot, decoders created\s+(\d+)', 4)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -80,8 +80,6 @@ test.file_grep(test.obj_dir + "/obj_ref/Vref__stats.txt",
|
|||
test.compile(verilator_flags2=[
|
||||
"--stats",
|
||||
"--build",
|
||||
"-fno-dfg-post-inline",
|
||||
"-fno-dfg-scoped",
|
||||
"--exe",
|
||||
"+incdir+" + test.obj_dir,
|
||||
"-Mdir", test.obj_dir + "/obj_opt",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:45:16: Bit [1] of signal 'y' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:45:16: Bit [1] of signal 't.y' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:48:22: ... Location of offending driver
|
||||
48 | {y[1:0], y[2:1]} = i[3:0] + 4'd5;
|
||||
| ^
|
||||
|
|
@ -8,88 +7,77 @@
|
|||
| ^
|
||||
... For warning description see https://verilator.org/warn/MULTIDRIVEN?v=latest
|
||||
... Use "/* verilator lint_off MULTIDRIVEN */" and lint_on around source to disable this message.
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bits [3:1] of signal 'a' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bits [3:1] of signal 't.a' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:17:17: ... Location of offending driver
|
||||
17 | assign a[3:0] = i[3:0];
|
||||
| ^
|
||||
t/t_dfg_multidriver_dfg_bad.v:18:17: ... Location of offending driver
|
||||
18 | assign a[4:1] = ~i[4:1];
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bit [3] of signal 'a' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bit [3] of signal 't.a' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:17:17: ... Location of offending driver
|
||||
17 | assign a[3:0] = i[3:0];
|
||||
| ^
|
||||
t/t_dfg_multidriver_dfg_bad.v:19:15: ... Location of offending driver
|
||||
19 | assign a[3] = ~i[3];
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bits [7:6] of signal 'a' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bits [7:6] of signal 't.a' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:20:17: ... Location of offending driver
|
||||
20 | assign a[8:5] = i[8:5];
|
||||
| ^
|
||||
t/t_dfg_multidriver_dfg_bad.v:21:17: ... Location of offending driver
|
||||
21 | assign a[7:6] = ~i[7:6];
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bit [9] of signal 'a' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:16:16: Bit [9] of signal 't.a' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:22:15: ... Location of offending driver
|
||||
22 | assign a[9] = i[9];
|
||||
| ^
|
||||
t/t_dfg_multidriver_dfg_bad.v:23:15: ... Location of offending driver
|
||||
23 | assign a[9] = ~i[9];
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:26:16: Elements [3:0] of signal 'u' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:26:16: Elements [3:0] of signal 't.u' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:27:12: ... Location of offending driver
|
||||
27 | assign u = j;
|
||||
| ^
|
||||
t/t_dfg_multidriver_dfg_bad.v:28:12: ... Location of offending driver
|
||||
28 | assign u = k;
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:30:16: Element [1] of signal 'v' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:30:16: Element [1] of signal 't.v' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:31:12: ... Location of offending driver
|
||||
31 | assign v = j;
|
||||
| ^
|
||||
t/t_dfg_multidriver_dfg_bad.v:32:11: ... Location of offending driver
|
||||
32 | assign v[1] = i;
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:34:16: Element [0] of signal 'w' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:34:16: Element [0] of signal 't.w' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:35:11: ... Location of offending driver
|
||||
35 | assign w[0] = i;
|
||||
| ^
|
||||
t/t_dfg_multidriver_dfg_bad.v:36:12: ... Location of offending driver
|
||||
36 | assign w = j;
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:38:16: Bits [3:2] of signal 'x[3]' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:38:16: Bits [3:2] of signal 't.x[3]' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:39:15: ... Location of offending driver
|
||||
39 | assign x[3] = i;
|
||||
| ^
|
||||
t/t_dfg_multidriver_dfg_bad.v:40:20: ... Location of offending driver
|
||||
40 | assign x[3][3:2] = ~i[1:0];
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bits [2:1] of signal 'z' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bits [2:1] of signal 't.z' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:53:12: ... Location of offending driver
|
||||
53 | z[2:0] = i[2:0];
|
||||
| ^
|
||||
t/t_dfg_multidriver_dfg_bad.v:58:15: ... Location of offending driver
|
||||
58 | z[3:1] = i[3:1];
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bits [6:5] of signal 'z' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bits [6:5] of signal 't.z' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:57:12: ... Location of offending driver
|
||||
57 | z[6:4] = i[6:4];
|
||||
| ^
|
||||
t/t_dfg_multidriver_dfg_bad.v:54:12: ... Location of offending driver
|
||||
54 | z[7:5] = i[7:5];
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bit [7] of signal 'z' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_dfg_multidriver_dfg_bad.v:51:16: Bit [7] of signal 't.z' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_dfg_multidriver_dfg_bad.v:54:12: ... Location of offending driver
|
||||
54 | z[7:5] = i[7:5];
|
||||
| ^
|
||||
|
|
@ -117,4 +105,7 @@
|
|||
t/t_dfg_multidriver_dfg_bad.v:66:24: ... Location of offending driver
|
||||
66 | assign sub_2.a[10:5] = i[10:5];
|
||||
| ^
|
||||
%Error: Exiting due to
|
||||
%Error: Internal Error: t/t_dfg_multidriver_dfg_bad.v:48:12: ../V3Gate.cpp:#: Concat on LHS of assignment; V3Const should have deleted it
|
||||
48 | {y[1:0], y[2:1]} = i[3:0] + 4'd5;
|
||||
| ^
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ test.scenarios('vlt')
|
|||
|
||||
test.compile(verilator_flags2=["--stats"])
|
||||
|
||||
test.file_grep(
|
||||
test.stats,
|
||||
r'Optimizations, DFG scoped Synthesis, conv / non-representable \(oobsel\)\s+(\d+)', 1)
|
||||
test.file_grep(test.stats,
|
||||
r'Optimizations, DFG, Synthesis, conv / non-representable \(oobsel\)\s+(\d+)', 1)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ test.compile(verilator_flags2=[
|
|||
def check(name, enabled):
|
||||
name = name.lower()
|
||||
name = re.sub(r'_', ' ', name)
|
||||
pattern = r'DFG\s+(pre inline|post inline|scoped) Peephole, ' + name + r'\s+([1-9]\d*)\s*$'
|
||||
pattern = r'DFG, Peephole, ' + name + r'\s+([1-9]\d*)\s*$'
|
||||
if enabled:
|
||||
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt", pattern)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -11,16 +11,12 @@ import vltest_bootstrap
|
|||
|
||||
test.scenarios('simulator_st')
|
||||
|
||||
test.compile(verilator_flags2=[
|
||||
"--binary", "--stats", "-fno-dfg-pre-inline", "-fno-dfg-post-inline", "-fno-dfg-peephole"
|
||||
])
|
||||
test.compile(verilator_flags2=["--binary", "--stats", "-fno-dfg-peephole"])
|
||||
|
||||
test.execute()
|
||||
|
||||
if test.vlt:
|
||||
test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, sels pushed down\s+(\d+)',
|
||||
49)
|
||||
test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, would be cyclic\s+(\d+)',
|
||||
1)
|
||||
test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, sels pushed down\s+(\d+)', 49)
|
||||
test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, would be cyclic\s+(\d+)', 1)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -13,17 +13,13 @@ test.scenarios('simulator_st')
|
|||
|
||||
test.top_filename = "t/t_dfg_push_sel.v"
|
||||
|
||||
test.compile(verilator_flags2=[
|
||||
"--binary", "--stats", "-fno-dfg-pre-inline", "-fno-dfg-post-inline", "-fno-dfg-peephole",
|
||||
"-fno-dfg-push-down-sels"
|
||||
])
|
||||
test.compile(
|
||||
verilator_flags2=["--binary", "--stats", "-fno-dfg-peephole", "-fno-dfg-push-down-sels"])
|
||||
|
||||
test.execute()
|
||||
|
||||
if test.vlt:
|
||||
test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, sels pushed down\s+(\d+)',
|
||||
0)
|
||||
test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, would be cyclic\s+(\d+)',
|
||||
0)
|
||||
test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, sels pushed down\s+(\d+)', 0)
|
||||
test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, would be cyclic\s+(\d+)', 0)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
DFG 'scoped' patterns with depth 1
|
||||
DFG patterns with depth 1
|
||||
9 (CONCAT _A:1 _B:a):b
|
||||
8 (REDXOR _A:a):1
|
||||
3 (NOT vA:a)*:a
|
||||
|
|
@ -16,7 +16,7 @@ DFG 'scoped' patterns with depth 1
|
|||
1 (SEL@0 _A:a):b
|
||||
1 (SEL@A _A:a):1
|
||||
|
||||
DFG 'scoped' patterns with depth 2
|
||||
DFG patterns with depth 2
|
||||
6 (CONCAT (REDXOR _A:a):1 (CONCAT _B:1 _C:b):c):d
|
||||
2 (AND (NOT vA:a)*:a (NOT vB:a)*:a):a
|
||||
2 (REDXOR (AND _A:a _B:a):a):1
|
||||
|
|
@ -42,7 +42,7 @@ DFG 'scoped' patterns with depth 2
|
|||
1 (SEL@0 (REPLICATE _A:a cA:a)*:b):c
|
||||
1 (SEL@A (AND _A:a _B:a)*:a):1
|
||||
|
||||
DFG 'scoped' patterns with depth 3
|
||||
DFG patterns with depth 3
|
||||
2 (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1
|
||||
1 (CONCAT (REDXOR (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e
|
||||
1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e
|
||||
|
|
@ -71,7 +71,7 @@ DFG 'scoped' patterns with depth 3
|
|||
1 (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c
|
||||
1 (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
||||
|
||||
DFG 'scoped' patterns with depth 4
|
||||
DFG patterns with depth 4
|
||||
1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f
|
||||
1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (SEL@0 _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f
|
||||
1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (SEL@0 (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:c):d):e):b):f
|
||||
|
|
@ -12,9 +12,9 @@ import vltest_bootstrap
|
|||
test.scenarios('vlt')
|
||||
test.top_filename = "t/t_dfg_stats_patterns.v"
|
||||
|
||||
test.compile(verilator_flags2=["--stats --no-skip-identical -fno-dfg-pre-inline -fno-dfg-scoped"])
|
||||
test.compile(verilator_flags2=["--stats --no-skip-identical"])
|
||||
|
||||
fn = test.glob_one(test.obj_dir + "/" + test.vm_prefix + "__stats_dfg_patterns*")
|
||||
test.files_identical(fn, test.golden_filename)
|
||||
test.files_identical(test.obj_dir + "/" + test.vm_prefix + "__stats_dfg_patterns.txt",
|
||||
test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
DFG 'post inline' patterns with depth 1
|
||||
9 (CONCAT _A:1 _B:a):b
|
||||
8 (REDXOR _A:a):1
|
||||
4 (ASTRD vA:a):a
|
||||
3 (NOT vA:a)*:a
|
||||
2 (AND _A:a _B:a):a
|
||||
1 (AND _A:a _B:a)*:a
|
||||
1 (CONCAT _A:1 _B:1):a
|
||||
1 (NOT _A:a):a
|
||||
1 (REDXOR _A:a)*:1
|
||||
1 (REPLICATE _A:1 cA:a)*:b
|
||||
1 (REPLICATE _A:a cA:a)*:b
|
||||
1 (REPLICATE _A:a cA:a):b
|
||||
1 (REPLICATE _A:a cA:b)*:b
|
||||
1 (REPLICATE _A:a cA:b)*:c
|
||||
1 (SEL@0 _A:a):1
|
||||
1 (SEL@0 _A:a):b
|
||||
1 (SEL@A _A:a):1
|
||||
|
||||
DFG 'post inline' patterns with depth 2
|
||||
6 (CONCAT (REDXOR _A:a):1 (CONCAT _B:1 _C:b):c):d
|
||||
2 (AND (NOT vA:a)*:a (NOT vB:a)*:a):a
|
||||
2 (REDXOR (AND _A:a _B:a):a):1
|
||||
1 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a
|
||||
1 (CONCAT (REDXOR _A:a)*:1 (CONCAT _B:1 _C:b):c):d
|
||||
1 (CONCAT (REDXOR _A:a):1 (CONCAT _B:1 _C:1):b):c
|
||||
1 (CONCAT (REDXOR _A:a):1 (REDXOR _B:b)*:1):c
|
||||
1 (CONCAT (SEL@0 _A:a):1 (CONCAT _B:1 _C:b):c):d
|
||||
1 (NOT (REPLICATE _A:a cA:b)*:b):b
|
||||
1 (REDXOR (AND _A:a _B:a)*:a):1
|
||||
1 (REDXOR (REPLICATE _A:1 cA:a)*:b):1
|
||||
1 (REDXOR (REPLICATE _A:a cA:a)*:b):1
|
||||
1 (REDXOR (REPLICATE _A:a cA:a):b)*:1
|
||||
1 (REDXOR (REPLICATE _A:a cA:b)*:b):1
|
||||
1 (REDXOR (REPLICATE _A:a cA:b)*:c):1
|
||||
1 (REDXOR (SEL@0 _A:a):b):1
|
||||
1 (REPLICATE (NOT _A:a):a cA:a)*:b
|
||||
1 (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c
|
||||
1 (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c
|
||||
1 (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b
|
||||
1 (REPLICATE (SEL@A _A:a):1 cA:b)*:c
|
||||
1 (SEL@0 (AND _A:a _B:a)*:a):1
|
||||
1 (SEL@0 (REPLICATE _A:a cA:a)*:b):c
|
||||
1 (SEL@A (AND _A:a _B:a)*:a):1
|
||||
|
||||
DFG 'post inline' patterns with depth 3
|
||||
2 (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1
|
||||
1 (CONCAT (REDXOR (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e
|
||||
1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e
|
||||
1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (SEL@0 _C:a):1 (CONCAT _D:1 _E:b):c):d):e
|
||||
1 (CONCAT (REDXOR (REPLICATE _A:1 cA:a)*:b):1 (CONCAT (REDXOR _B:c):1 (CONCAT _C:1 _D:d):e):f):g
|
||||
1 (CONCAT (REDXOR (REPLICATE _A:a cA:a)*:b):1 (CONCAT (REDXOR _B:c):1 (REDXOR _C:b)*:1):d):e
|
||||
1 (CONCAT (REDXOR (REPLICATE _A:a cA:a):b)*:1 (CONCAT (REDXOR _B:b):1 (CONCAT _C:1 _D:1):c):d):e
|
||||
1 (CONCAT (REDXOR (REPLICATE _A:a cA:b)*:b):1 (CONCAT (REDXOR _B:c)*:1 (CONCAT _C:1 _D:d):e):f):g
|
||||
1 (CONCAT (REDXOR (REPLICATE _A:a cA:b)*:c):1 (CONCAT (REDXOR _B:b):1 (CONCAT _C:1 _D:d):e):f):g
|
||||
1 (CONCAT (REDXOR (SEL@0 _A:a):b):1 (REDXOR (REPLICATE _B:c cA:c):a)*:1):d
|
||||
1 (CONCAT (SEL@0 (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:c):d):e):b
|
||||
1 (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b
|
||||
1 (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
||||
1 (REDXOR (REPLICATE (NOT _A:a):a cA:a)*:b):1
|
||||
1 (REDXOR (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c):1
|
||||
1 (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c)*:1
|
||||
1 (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):1
|
||||
1 (REDXOR (REPLICATE (SEL@A _A:a):1 cA:b)*:c):1
|
||||
1 (REDXOR (SEL@0 (REPLICATE _A:a cA:a)*:b):c):1
|
||||
1 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c
|
||||
1 (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a
|
||||
1 (REPLICATE (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b cA:b):d
|
||||
1 (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d
|
||||
1 (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c
|
||||
1 (SEL@0 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
||||
1 (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c
|
||||
1 (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
||||
|
||||
DFG 'post inline' patterns with depth 4
|
||||
1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f
|
||||
1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (SEL@0 _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f
|
||||
1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (SEL@0 (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:c):d):e):b):f
|
||||
1 (CONCAT (REDXOR (REPLICATE (NOT _A:a):a cA:a)*:b):1 (CONCAT (REDXOR (SEL@0 _B:b):c):1 (REDXOR (REPLICATE _A:a cA:a):b)*:1):d):e
|
||||
1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c):1 (CONCAT (REDXOR (REPLICATE _B:c cB:a)*:a):1 (CONCAT (REDXOR _C:d)*:1 (CONCAT _D:1 _E:e):f):g):h):i
|
||||
1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c)*:1 (CONCAT (REDXOR (REPLICATE _B:b cA:b)*:c):1 (CONCAT (REDXOR _C:d):1 (REDXOR _D:c)*:1):e):f):g
|
||||
1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):1 (CONCAT (REDXOR (REPLICATE _B:b cA:b):d)*:1 (CONCAT (REDXOR _C:d):1 (CONCAT _D:1 _E:1):e):f):g):h
|
||||
1 (CONCAT (REDXOR (REPLICATE (SEL@A _A:a):1 cA:b)*:c):1 (CONCAT (REDXOR (REPLICATE _B:c cB:b)*:d):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:e):a):f):g):h
|
||||
1 (CONCAT (REDXOR (SEL@0 (REPLICATE _A:a cA:a)*:b):c):1 (REDXOR (REPLICATE (REPLICATE _B:d cA:a)*:a cA:a):b)*:1):e
|
||||
1 (CONCAT (SEL@0 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 (CONCAT (REDXOR (REPLICATE _A:1 cA:b)*:c):1 (CONCAT (REDXOR _B:d):1 (CONCAT _C:1 _D:a):e):f):g):c
|
||||
1 (NOT (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a):a
|
||||
1 (REDXOR (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c):1
|
||||
1 (REDXOR (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a):1
|
||||
1 (REDXOR (REPLICATE (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b cA:b):d)*:1
|
||||
1 (REDXOR (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d):1
|
||||
1 (REDXOR (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c):1
|
||||
1 (REDXOR (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c):1
|
||||
1 (REPLICATE (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b cA:b)*:d
|
||||
1 (REPLICATE (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a cB:a):d
|
||||
1 (REPLICATE (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d cB:b)*:b
|
||||
1 (REPLICATE (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c cB:b)*:d
|
||||
1 (REPLICATE (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 cA:b)*:c
|
||||
1 (SEL@0 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c):d
|
||||
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
DFG 'pre inline' patterns with depth 1
|
||||
9 (CONCAT _A:1 _B:a):b
|
||||
8 (REDXOR _A:a):1
|
||||
3 (NOT vA:a)*:a
|
||||
2 (AND _A:a _B:a):a
|
||||
1 (AND _A:a _B:a)*:a
|
||||
1 (CONCAT _A:1 _B:1):a
|
||||
1 (NOT _A:a):a
|
||||
1 (REDXOR _A:a)*:1
|
||||
1 (REPLICATE _A:1 cA:a)*:b
|
||||
1 (REPLICATE _A:a cA:a)*:b
|
||||
1 (REPLICATE _A:a cA:a):b
|
||||
1 (REPLICATE _A:a cA:b)*:b
|
||||
1 (REPLICATE _A:a cA:b)*:c
|
||||
1 (SEL@0 _A:a):1
|
||||
1 (SEL@0 _A:a):b
|
||||
1 (SEL@A _A:a):1
|
||||
|
||||
DFG 'pre inline' patterns with depth 2
|
||||
6 (CONCAT (REDXOR _A:a):1 (CONCAT _B:1 _C:b):c):d
|
||||
2 (AND (NOT vA:a)*:a (NOT vB:a)*:a):a
|
||||
2 (REDXOR (AND _A:a _B:a):a):1
|
||||
1 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a
|
||||
1 (CONCAT (REDXOR _A:a)*:1 (CONCAT _B:1 _C:b):c):d
|
||||
1 (CONCAT (REDXOR _A:a):1 (CONCAT _B:1 _C:1):b):c
|
||||
1 (CONCAT (REDXOR _A:a):1 (REDXOR _B:b)*:1):c
|
||||
1 (CONCAT (SEL@0 _A:a):1 (CONCAT _B:1 _C:b):c):d
|
||||
1 (NOT (REPLICATE _A:a cA:b)*:b):b
|
||||
1 (REDXOR (AND _A:a _B:a)*:a):1
|
||||
1 (REDXOR (REPLICATE _A:1 cA:a)*:b):1
|
||||
1 (REDXOR (REPLICATE _A:a cA:a)*:b):1
|
||||
1 (REDXOR (REPLICATE _A:a cA:a):b)*:1
|
||||
1 (REDXOR (REPLICATE _A:a cA:b)*:b):1
|
||||
1 (REDXOR (REPLICATE _A:a cA:b)*:c):1
|
||||
1 (REDXOR (SEL@0 _A:a):b):1
|
||||
1 (REPLICATE (NOT _A:a):a cA:a)*:b
|
||||
1 (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c
|
||||
1 (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c
|
||||
1 (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b
|
||||
1 (REPLICATE (SEL@A _A:a):1 cA:b)*:c
|
||||
1 (SEL@0 (AND _A:a _B:a)*:a):1
|
||||
1 (SEL@0 (REPLICATE _A:a cA:a)*:b):c
|
||||
1 (SEL@A (AND _A:a _B:a)*:a):1
|
||||
|
||||
DFG 'pre inline' patterns with depth 3
|
||||
2 (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1
|
||||
1 (CONCAT (REDXOR (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e
|
||||
1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e
|
||||
1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (SEL@0 _C:a):1 (CONCAT _D:1 _E:b):c):d):e
|
||||
1 (CONCAT (REDXOR (REPLICATE _A:1 cA:a)*:b):1 (CONCAT (REDXOR _B:c):1 (CONCAT _C:1 _D:d):e):f):g
|
||||
1 (CONCAT (REDXOR (REPLICATE _A:a cA:a)*:b):1 (CONCAT (REDXOR _B:c):1 (REDXOR _C:b)*:1):d):e
|
||||
1 (CONCAT (REDXOR (REPLICATE _A:a cA:a):b)*:1 (CONCAT (REDXOR _B:b):1 (CONCAT _C:1 _D:1):c):d):e
|
||||
1 (CONCAT (REDXOR (REPLICATE _A:a cA:b)*:b):1 (CONCAT (REDXOR _B:c)*:1 (CONCAT _C:1 _D:d):e):f):g
|
||||
1 (CONCAT (REDXOR (REPLICATE _A:a cA:b)*:c):1 (CONCAT (REDXOR _B:b):1 (CONCAT _C:1 _D:d):e):f):g
|
||||
1 (CONCAT (REDXOR (SEL@0 _A:a):b):1 (REDXOR (REPLICATE _B:c cA:c):a)*:1):d
|
||||
1 (CONCAT (SEL@0 (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:c):d):e):b
|
||||
1 (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b
|
||||
1 (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
||||
1 (REDXOR (REPLICATE (NOT _A:a):a cA:a)*:b):1
|
||||
1 (REDXOR (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c):1
|
||||
1 (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c)*:1
|
||||
1 (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):1
|
||||
1 (REDXOR (REPLICATE (SEL@A _A:a):1 cA:b)*:c):1
|
||||
1 (REDXOR (SEL@0 (REPLICATE _A:a cA:a)*:b):c):1
|
||||
1 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c
|
||||
1 (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a
|
||||
1 (REPLICATE (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b cA:b):d
|
||||
1 (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d
|
||||
1 (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c
|
||||
1 (SEL@0 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
||||
1 (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c
|
||||
1 (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
||||
|
||||
DFG 'pre inline' patterns with depth 4
|
||||
1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (REDXOR _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f
|
||||
1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (REDXOR (AND _A:a _B:a):a):1 (CONCAT (SEL@0 _C:a):1 (CONCAT _D:1 _E:b):c):d):e):f
|
||||
1 (CONCAT (REDXOR (AND (NOT vA:a)*:a (NOT vB:a)*:a):a):1 (CONCAT (SEL@0 (AND _A:a _B:a)*:a):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:c):d):e):b):f
|
||||
1 (CONCAT (REDXOR (REPLICATE (NOT _A:a):a cA:a)*:b):1 (CONCAT (REDXOR (SEL@0 _B:b):c):1 (REDXOR (REPLICATE _A:a cA:a):b)*:1):d):e
|
||||
1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c):1 (CONCAT (REDXOR (REPLICATE _B:c cB:a)*:a):1 (CONCAT (REDXOR _C:d)*:1 (CONCAT _D:1 _E:e):f):g):h):i
|
||||
1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:b cA:b):c)*:1 (CONCAT (REDXOR (REPLICATE _B:b cA:b)*:c):1 (CONCAT (REDXOR _C:d):1 (REDXOR _D:c)*:1):e):f):g
|
||||
1 (CONCAT (REDXOR (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):1 (CONCAT (REDXOR (REPLICATE _B:b cA:b):d)*:1 (CONCAT (REDXOR _C:d):1 (CONCAT _D:1 _E:1):e):f):g):h
|
||||
1 (CONCAT (REDXOR (REPLICATE (SEL@A _A:a):1 cA:b)*:c):1 (CONCAT (REDXOR (REPLICATE _B:c cB:b)*:d):1 (CONCAT (REDXOR _C:b):1 (CONCAT _D:1 _E:e):a):f):g):h
|
||||
1 (CONCAT (REDXOR (SEL@0 (REPLICATE _A:a cA:a)*:b):c):1 (REDXOR (REPLICATE (REPLICATE _B:d cA:a)*:a cA:a):b)*:1):e
|
||||
1 (CONCAT (SEL@0 (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 (CONCAT (REDXOR (REPLICATE _A:1 cA:b)*:c):1 (CONCAT (REDXOR _B:d):1 (CONCAT _C:1 _D:a):e):f):g):c
|
||||
1 (NOT (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a):a
|
||||
1 (REDXOR (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c):1
|
||||
1 (REDXOR (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a):1
|
||||
1 (REDXOR (REPLICATE (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b cA:b):d)*:1
|
||||
1 (REDXOR (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d):1
|
||||
1 (REDXOR (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c):1
|
||||
1 (REDXOR (SEL@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c):1
|
||||
1 (REPLICATE (NOT (REPLICATE (REPLICATE _A:a cA:b)*:c cA:b)*:b):b cA:b)*:d
|
||||
1 (REPLICATE (REPLICATE (REPLICATE (REPLICATE _A:1 cA:a)*:b cB:a)*:c cB:a)*:a cB:a):d
|
||||
1 (REPLICATE (REPLICATE (REPLICATE (SEL@A _A:a):1 cA:b)*:c cB:b)*:d cB:b)*:b
|
||||
1 (REPLICATE (REPLICATE (SEL@A (AND _A:a _B:a)*:a):1 cA:b)*:c cB:b)*:d
|
||||
1 (REPLICATE (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1 cA:b)*:c
|
||||
1 (SEL@0 (REPLICATE (NOT (REPLICATE _A:a cA:b)*:b):b cA:b)*:c):d
|
||||
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
test.top_filename = "t/t_dfg_stats_patterns.v"
|
||||
|
||||
test.compile(verilator_flags2=["--stats --no-skip-identical -fno-dfg-post-inline -fno-dfg-scoped"])
|
||||
|
||||
fn = test.glob_one(test.obj_dir + "/" + test.vm_prefix + "__stats_dfg_patterns*")
|
||||
test.files_identical(fn, test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
test.top_filename = "t/t_dfg_stats_patterns.v"
|
||||
|
||||
test.compile(
|
||||
verilator_flags2=["--stats --no-skip-identical -fno-dfg-pre-inline -fno-dfg-post-inline"])
|
||||
|
||||
fn = test.glob_one(test.obj_dir + "/" + test.vm_prefix + "__stats_dfg_patterns*")
|
||||
test.files_identical(fn, test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -70,13 +70,10 @@ test.compile(verilator_flags2=[
|
|||
"--stats",
|
||||
"--build",
|
||||
"--fdfg-synthesize-all",
|
||||
"-fno-dfg-pre-inline",
|
||||
"-fno-dfg-post-inline",
|
||||
"--exe",
|
||||
"+incdir+" + test.obj_dir,
|
||||
"-Mdir", test.obj_dir + "/obj_opt",
|
||||
"--prefix", "Vopt",
|
||||
"-fno-const-before-dfg", # Otherwise V3Const makes testing painful
|
||||
"-fno-split", # Dfg will take care of it
|
||||
"--debug", "--debugi", "0", "--dumpi-tree", "0",
|
||||
"-CFLAGS \"-I .. -I ../obj_ref\"",
|
||||
|
|
@ -85,13 +82,13 @@ test.compile(verilator_flags2=[
|
|||
]) # yapf:disable
|
||||
|
||||
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt",
|
||||
r'DFG scoped Synthesis, synt / always blocks considered\s+(\d+)$',
|
||||
r'DFG, Synthesis, synt / always blocks considered\s+(\d+)$',
|
||||
nAlwaysSynthesized + nAlwaysReverted + nAlwaysNotSynthesized)
|
||||
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt",
|
||||
r'DFG scoped Synthesis, synt / always blocks synthesized\s+(\d+)$',
|
||||
r'DFG, Synthesis, synt / always blocks synthesized\s+(\d+)$',
|
||||
nAlwaysSynthesized + nAlwaysReverted)
|
||||
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt",
|
||||
r'DFG scoped Synthesis, synt / reverted \(multidrive\)\s+(\d)$', nAlwaysReverted)
|
||||
r'DFG, Synthesis, synt / reverted \(multidrive\)\s+(\d)$', nAlwaysReverted)
|
||||
|
||||
# Execute test to check equivalence
|
||||
test.execute(executable=test.obj_dir + "/obj_opt/Vopt")
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
//
|
||||
// DESCRIPTION: Verilator: DFG optimizer equivalence testing
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2022 Geza Lore
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
|
||||
#include <verilated.h>
|
||||
#include <verilated_cov.h>
|
||||
|
||||
#include <Vopt.h>
|
||||
#include <Vref.h>
|
||||
#include <iostream>
|
||||
|
||||
void rngUpdate(uint64_t& x) {
|
||||
x ^= x << 13;
|
||||
x ^= x >> 7;
|
||||
x ^= x << 17;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
// Create contexts
|
||||
VerilatedContext ctx;
|
||||
|
||||
// Create models
|
||||
Vref ref{&ctx};
|
||||
Vopt opt{&ctx};
|
||||
|
||||
uint64_t rand_a = 0x5aef0c8dd70a4497;
|
||||
uint64_t rand_b = 0xf0c0a8dd75ae4497;
|
||||
uint64_t srand_a = 0x00fa8dcc7ae4957;
|
||||
uint64_t srand_b = 0x0fa8dc7ae3c9574;
|
||||
|
||||
for (size_t n = 0; n < 200000; ++n) {
|
||||
// Update rngs
|
||||
rngUpdate(rand_a);
|
||||
rngUpdate(rand_b);
|
||||
rngUpdate(srand_a);
|
||||
rngUpdate(srand_b);
|
||||
|
||||
// Assign inputs
|
||||
ref.rand_a = opt.rand_a = rand_a;
|
||||
ref.rand_b = opt.rand_b = rand_b;
|
||||
ref.srand_a = opt.srand_a = srand_a;
|
||||
ref.srand_b = opt.srand_b = srand_b;
|
||||
|
||||
// Evaluate both models
|
||||
ref.eval();
|
||||
opt.eval();
|
||||
|
||||
// Check equivalence
|
||||
#include "checks.h"
|
||||
|
||||
// increment time
|
||||
ctx.timeInc(1);
|
||||
}
|
||||
|
||||
std::cout << "*-* All Finished *-*\n";
|
||||
}
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2025 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.sim_time = 2000000
|
||||
|
||||
if not os.path.exists(test.root + "/.git"):
|
||||
test.skip("Not in a git repository")
|
||||
|
||||
# Generate the equivalence checks and declaration boilerplate
|
||||
rdFile = test.top_filename
|
||||
plistFile = test.obj_dir + "/portlist.vh"
|
||||
pdeclFile = test.obj_dir + "/portdecl.vh"
|
||||
checkFile = test.obj_dir + "/checks.h"
|
||||
nAlwaysSynthesized = 0
|
||||
nAlwaysNotSynthesized = 0
|
||||
nAlwaysReverted = 0
|
||||
with open(rdFile, 'r', encoding="utf8") as rdFh, \
|
||||
open(plistFile, 'w', encoding="utf8") as plistFh, \
|
||||
open(pdeclFile, 'w', encoding="utf8") as pdeclFh, \
|
||||
open(checkFile, 'w', encoding="utf8") as checkFh:
|
||||
for line in rdFh:
|
||||
if re.search(r'^\s*always.*//\s*nosynth$', line):
|
||||
nAlwaysNotSynthesized += 1
|
||||
elif re.search(r'^\s*always.*//\s*revert$', line):
|
||||
nAlwaysReverted += 1
|
||||
elif re.search(r'^\s*always', line):
|
||||
nAlwaysSynthesized += 1
|
||||
line = line.split("//")[0]
|
||||
m = re.search(r'`signal\((\w+),', line)
|
||||
if not m:
|
||||
continue
|
||||
sig = m.group(1)
|
||||
plistFh.write(sig + ",\n")
|
||||
pdeclFh.write("output " + sig + ";\n")
|
||||
checkFh.write("if (ref." + sig + " != opt." + sig + ") {\n")
|
||||
checkFh.write(" std::cout << \"Mismatched " + sig + "\" << std::endl;\n")
|
||||
checkFh.write(" std::cout << \"Ref: 0x\" << std::hex << (ref." + sig +
|
||||
" + 0) << std::endl;\n")
|
||||
checkFh.write(" std::cout << \"Opt: 0x\" << std::hex << (opt." + sig +
|
||||
" + 0) << std::endl;\n")
|
||||
checkFh.write(" std::exit(1);\n")
|
||||
checkFh.write("}\n")
|
||||
|
||||
# Compile un-optimized
|
||||
test.compile(verilator_flags2=[
|
||||
"--stats",
|
||||
"--build",
|
||||
"-fno-dfg",
|
||||
"+incdir+" + test.obj_dir,
|
||||
"-Mdir", test.obj_dir + "/obj_ref",
|
||||
"--prefix", "Vref",
|
||||
"-Wno-UNOPTFLAT"
|
||||
]) # yapf:disable
|
||||
|
||||
test.file_grep_not(test.obj_dir + "/obj_ref/Vref__stats.txt", r'DFG.*Synthesis')
|
||||
|
||||
# Compile optimized - also builds executable
|
||||
test.compile(verilator_flags2=[
|
||||
"--stats",
|
||||
"--build",
|
||||
"--fdfg-synthesize-all",
|
||||
"-fno-dfg-post-inline",
|
||||
"-fno-dfg-scoped",
|
||||
"--exe",
|
||||
"+incdir+" + test.obj_dir,
|
||||
"-Mdir", test.obj_dir + "/obj_opt",
|
||||
"--prefix", "Vopt",
|
||||
"-fno-const-before-dfg", # Otherwise V3Const makes testing painful
|
||||
"-fno-split", # Dfg will take care of it
|
||||
"--debug", "--debugi", "0", "--dumpi-tree", "0",
|
||||
"-CFLAGS \"-I .. -I ../obj_ref\"",
|
||||
"../obj_ref/Vref__ALL.a",
|
||||
"../../t/" + test.name + ".cpp"
|
||||
]) # yapf:disable
|
||||
|
||||
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt",
|
||||
r'DFG pre inline Synthesis, synt / always blocks considered\s+(\d+)$',
|
||||
nAlwaysSynthesized + nAlwaysReverted + nAlwaysNotSynthesized)
|
||||
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt",
|
||||
r'DFG pre inline Synthesis, synt / always blocks synthesized\s+(\d+)$',
|
||||
nAlwaysSynthesized + nAlwaysReverted)
|
||||
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt",
|
||||
r'DFG pre inline Synthesis, synt / reverted \(multidrive\)\s+(\d)$',
|
||||
nAlwaysReverted)
|
||||
|
||||
# Execute test to check equivalence
|
||||
test.execute(executable=test.obj_dir + "/obj_opt/Vopt")
|
||||
|
||||
test.passes()
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2025 Geza Lore
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define signal(name, expr) wire [$bits(expr)-1:0] ``name = expr
|
||||
|
||||
module t (
|
||||
`include "portlist.vh" // Boilerplate generated by t_dfg_break_cycles.py
|
||||
rand_a, rand_b, srand_a, srand_b
|
||||
);
|
||||
|
||||
`include "portdecl.vh" // Boilerplate generated by t_dfg_break_cycles.py
|
||||
|
||||
input rand_a;
|
||||
input rand_b;
|
||||
input srand_a;
|
||||
input srand_b;
|
||||
wire logic [63:0] rand_a;
|
||||
wire logic [63:0] rand_b;
|
||||
wire logic signed [63:0] srand_a;
|
||||
wire logic signed [63:0] srand_b;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
logic concat_lhs_a;
|
||||
logic concat_lhs_b;
|
||||
always_comb begin
|
||||
{concat_lhs_a, concat_lhs_b} = rand_a[1:0] + rand_b[1:0];
|
||||
end
|
||||
`signal(CONCAT_LHS, {concat_lhs_a, concat_lhs_b});
|
||||
|
||||
endmodule
|
||||
|
|
@ -4,6 +4,6 @@
|
|||
... For warning description see https://verilator.org/warn/UNOPTFLAT?v=latest
|
||||
... Use "/* verilator lint_off UNOPTFLAT */" and lint_on around source to disable this message.
|
||||
t/t_dfg_true_cycle_bad.v:10:23: Example path: o
|
||||
t/t_dfg_true_cycle_bad.v:12:20: Example path: ASSIGNW
|
||||
t/t_dfg_true_cycle_bad.v:12:17: Example path: ASSIGNW
|
||||
t/t_dfg_true_cycle_bad.v:10:23: Example path: o
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -4,4 +4,7 @@
|
|||
%Warning-DEPRECATED: Option order-clock-delay is deprecated and has no effect.
|
||||
%Warning-DEPRECATED: Option '--clk' is deprecated and has no effect.
|
||||
%Warning-DEPRECATED: Option '--no-clk' is deprecated and has no effect.
|
||||
%Warning-DEPRECATED: Option '-fno-dfg-pre-inline' is deprecated and has no effect
|
||||
%Warning-DEPRECATED: Option '-fno-dfg-post-inline' is deprecated and has no effect
|
||||
%Warning-DEPRECATED: Option '-fno-dfg-scoped' is deprecated, use '-fno-dfg' instead.
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ import vltest_bootstrap
|
|||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.lint(verilator_flags2=["--trace-fst-thread --order-clock-delay --clk foo --no-clk bar"],
|
||||
test.lint(verilator_flags2=[
|
||||
"--trace-fst-thread --order-clock-delay --clk foo --no-clk bar -fno-dfg-pre-inline -fno-dfg-post-inline -fno-dfg-scoped"
|
||||
],
|
||||
fails=True,
|
||||
expect_filename=test.golden_filename)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,8 @@ test.top_filename = "t/t_inst_tree.v"
|
|||
|
||||
out_filename = test.obj_dir + "/V" + test.name + ".tree.json"
|
||||
|
||||
test.compile(v_flags2=[
|
||||
"--no-json-edit-nums", "-fno-dfg-post-inline", "-fno-dfg-scoped", test.t_dir +
|
||||
"/t_inst_tree_inl1_pub0.vlt"
|
||||
])
|
||||
test.compile(
|
||||
v_flags2=["--no-json-edit-nums", "-fno-dfg", test.t_dir + "/t_inst_tree_inl1_pub0.vlt"])
|
||||
|
||||
if test.vlt_all:
|
||||
test.file_grep(
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ test.top_filename = "t/t_inst_tree.v"
|
|||
out_filename = test.obj_dir + "/V" + test.name + ".tree.json"
|
||||
|
||||
test.compile(v_flags2=[
|
||||
"--no-json-edit-nums", "-fno-dfg-post-inline", "t/" + test.name +
|
||||
".vlt", test.wno_unopthreads_for_few_cores
|
||||
"--no-json-edit-nums", "t/" + test.name + ".vlt", test.wno_unopthreads_for_few_cores
|
||||
])
|
||||
|
||||
if test.vlt_all:
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@
|
|||
"stmtsp": [
|
||||
{"type":"ASSIGNW","name":"","addr":"(IB)","loc":"d,56:12,56:13","dtypep":"(G)",
|
||||
"rhsp": [
|
||||
{"type":"VARREF","name":"d","addr":"(JB)","loc":"d,52:17,52:18","dtypep":"(G)","access":"RD","varp":"(Z)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
{"type":"VARREF","name":"d","addr":"(JB)","loc":"d,56:14,56:15","dtypep":"(G)","access":"RD","varp":"(Z)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
],
|
||||
"lhsp": [
|
||||
{"type":"VARREF","name":"q","addr":"(KB)","loc":"d,56:12,56:13","dtypep":"(G)","access":"WR","varp":"(CB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
{"type":"VARREF","name":"q","addr":"(KB)","loc":"d,56:10,56:11","dtypep":"(G)","access":"WR","varp":"(CB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
],"timingControlp": [],"strengthSpecp": []}
|
||||
]}
|
||||
]},
|
||||
|
|
@ -88,19 +88,18 @@
|
|||
]}
|
||||
],"filesp": [],
|
||||
"miscsp": [
|
||||
{"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(YB)",
|
||||
{"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"UNLINKED",
|
||||
"typesp": [
|
||||
{"type":"BASICDTYPE","name":"logic","addr":"(MB)","loc":"d,37:15,37:20","dtypep":"(MB)","keyword":"logic","range":"31:0","generic":true,"signed":true,"rangep": []},
|
||||
{"type":"BASICDTYPE","name":"logic","addr":"(I)","loc":"d,39:11,39:14","dtypep":"(I)","keyword":"logic","generic":true,"rangep": []},
|
||||
{"type":"BASICDTYPE","name":"logic","addr":"(G)","loc":"d,16:15,16:16","dtypep":"(G)","keyword":"logic","range":"3:0","generic":true,"rangep": []},
|
||||
{"type":"BASICDTYPE","name":"bit","addr":"(OB)","loc":"d,21:14,21:15","dtypep":"(OB)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []},
|
||||
{"type":"VOIDDTYPE","name":"","addr":"(YB)","loc":"a,0:0,0:0","dtypep":"(YB)"}
|
||||
{"type":"BASICDTYPE","name":"bit","addr":"(OB)","loc":"d,21:14,21:15","dtypep":"(OB)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []}
|
||||
]},
|
||||
{"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
||||
"modulep": [
|
||||
{"type":"MODULE","name":"@CONST-POOL@","addr":"(ZB)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [],
|
||||
{"type":"MODULE","name":"@CONST-POOL@","addr":"(YB)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [],
|
||||
"stmtsp": [
|
||||
{"type":"SCOPE","name":"@CONST-POOL@","addr":"(AC)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(ZB)","varsp": [],"blocksp": [],"inlinesp": []}
|
||||
{"type":"SCOPE","name":"@CONST-POOL@","addr":"(ZB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(YB)","varsp": [],"blocksp": [],"inlinesp": []}
|
||||
]}
|
||||
]}
|
||||
]}
|
||||
|
|
|
|||
|
|
@ -157,10 +157,10 @@
|
|||
"stmtsp": [
|
||||
{"type":"ASSIGNW","name":"","addr":"(JD)","loc":"d,56:12,56:13","dtypep":"(H)",
|
||||
"rhsp": [
|
||||
{"type":"VARREF","name":"t.between","addr":"(KD)","loc":"d,18:15,18:22","dtypep":"(H)","access":"RD","varp":"(O)","varScopep":"(UB)","classOrPackagep":"UNLINKED"}
|
||||
{"type":"VARREF","name":"t.between","addr":"(KD)","loc":"d,56:14,56:15","dtypep":"(H)","access":"RD","varp":"(O)","varScopep":"(UB)","classOrPackagep":"UNLINKED"}
|
||||
],
|
||||
"lhsp": [
|
||||
{"type":"VARREF","name":"q","addr":"(LD)","loc":"d,56:12,56:13","dtypep":"(H)","access":"WR","varp":"(G)","varScopep":"(CB)","classOrPackagep":"UNLINKED"}
|
||||
{"type":"VARREF","name":"q","addr":"(LD)","loc":"d,56:10,56:11","dtypep":"(H)","access":"WR","varp":"(G)","varScopep":"(CB)","classOrPackagep":"UNLINKED"}
|
||||
],"timingControlp": [],"strengthSpecp": []}
|
||||
]}
|
||||
],"inlinesp": []}
|
||||
|
|
@ -168,19 +168,18 @@
|
|||
]}
|
||||
],"filesp": [],
|
||||
"miscsp": [
|
||||
{"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(MD)",
|
||||
{"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"UNLINKED",
|
||||
"typesp": [
|
||||
{"type":"BASICDTYPE","name":"logic","addr":"(Q)","loc":"d,37:15,37:20","dtypep":"(Q)","keyword":"logic","range":"31:0","generic":true,"signed":true,"rangep": []},
|
||||
{"type":"BASICDTYPE","name":"logic","addr":"(J)","loc":"d,39:11,39:14","dtypep":"(J)","keyword":"logic","generic":true,"rangep": []},
|
||||
{"type":"BASICDTYPE","name":"logic","addr":"(H)","loc":"d,16:15,16:16","dtypep":"(H)","keyword":"logic","range":"3:0","generic":true,"rangep": []},
|
||||
{"type":"BASICDTYPE","name":"bit","addr":"(S)","loc":"d,21:14,21:15","dtypep":"(S)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []},
|
||||
{"type":"VOIDDTYPE","name":"","addr":"(MD)","loc":"a,0:0,0:0","dtypep":"(MD)"}
|
||||
{"type":"BASICDTYPE","name":"bit","addr":"(S)","loc":"d,21:14,21:15","dtypep":"(S)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []}
|
||||
]},
|
||||
{"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
||||
"modulep": [
|
||||
{"type":"MODULE","name":"@CONST-POOL@","addr":"(ND)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [],
|
||||
{"type":"MODULE","name":"@CONST-POOL@","addr":"(MD)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [],
|
||||
"stmtsp": [
|
||||
{"type":"SCOPE","name":"@CONST-POOL@","addr":"(OD)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(ND)","varsp": [],"blocksp": [],"inlinesp": []}
|
||||
{"type":"SCOPE","name":"@CONST-POOL@","addr":"(ND)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(MD)","varsp": [],"blocksp": [],"inlinesp": []}
|
||||
]}
|
||||
]}
|
||||
]}
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@
|
|||
]}
|
||||
],"filesp": [],
|
||||
"miscsp": [
|
||||
{"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(IG)",
|
||||
{"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"UNLINKED",
|
||||
"typesp": [
|
||||
{"type":"BASICDTYPE","name":"bit","addr":"(BD)","loc":"d,18:18,18:19","dtypep":"(BD)","keyword":"bit","generic":true,"rangep": []},
|
||||
{"type":"BASICDTYPE","name":"bit","addr":"(ID)","loc":"d,19:34,19:39","dtypep":"(ID)","keyword":"bit","range":"1:0","generic":true,"rangep": []},
|
||||
|
|
@ -343,14 +343,13 @@
|
|||
{"type":"BASICDTYPE","name":"logic","addr":"(KD)","loc":"d,19:20,19:21","dtypep":"(KD)","keyword":"logic","range":"1:0","generic":true,"rangep": []},
|
||||
{"type":"BASICDTYPE","name":"logic","addr":"(ND)","loc":"d,19:20,19:21","dtypep":"(ND)","keyword":"logic","range":"3:0","generic":true,"signed":true,"rangep": []},
|
||||
{"type":"BASICDTYPE","name":"logic","addr":"(CE)","loc":"d,18:24,18:26","dtypep":"(CE)","keyword":"logic","range":"31:0","generic":true,"rangep": []},
|
||||
{"type":"BASICDTYPE","name":"bit","addr":"(WC)","loc":"d,18:12,18:13","dtypep":"(WC)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []},
|
||||
{"type":"VOIDDTYPE","name":"","addr":"(IG)","loc":"a,0:0,0:0","dtypep":"(IG)"}
|
||||
{"type":"BASICDTYPE","name":"bit","addr":"(WC)","loc":"d,18:12,18:13","dtypep":"(WC)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []}
|
||||
]},
|
||||
{"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
||||
"modulep": [
|
||||
{"type":"MODULE","name":"@CONST-POOL@","addr":"(JG)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [],
|
||||
{"type":"MODULE","name":"@CONST-POOL@","addr":"(IG)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [],
|
||||
"stmtsp": [
|
||||
{"type":"SCOPE","name":"@CONST-POOL@","addr":"(KG)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(JG)","varsp": [],"blocksp": [],"inlinesp": []}
|
||||
{"type":"SCOPE","name":"@CONST-POOL@","addr":"(JG)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(IG)","varsp": [],"blocksp": [],"inlinesp": []}
|
||||
]}
|
||||
]}
|
||||
]}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@
|
|||
"stmtsp": [
|
||||
{"type":"ASSIGNW","name":"","addr":"(X)","loc":"d,26:16,26:17","dtypep":"(G)",
|
||||
"rhsp": [
|
||||
{"type":"VARREF","name":"ready_reg","addr":"(Y)","loc":"d,18:8,18:17","dtypep":"(G)","access":"RD","varp":"(K)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
{"type":"VARREF","name":"ready_reg","addr":"(Y)","loc":"d,26:18,26:27","dtypep":"(G)","access":"RD","varp":"(K)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
],
|
||||
"lhsp": [
|
||||
{"type":"VARREF","name":"ready","addr":"(Z)","loc":"d,26:16,26:17","dtypep":"(G)","access":"WR","varp":"(J)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
{"type":"VARREF","name":"ready","addr":"(Z)","loc":"d,26:10,26:15","dtypep":"(G)","access":"WR","varp":"(J)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
],"timingControlp": [],"strengthSpecp": []}
|
||||
]}
|
||||
]},
|
||||
|
|
@ -44,29 +44,28 @@
|
|||
"rhsp": [
|
||||
{"type":"AND","name":"","addr":"(CB)","loc":"d,34:19,34:20","dtypep":"(G)",
|
||||
"lhsp": [
|
||||
{"type":"VARREF","name":"a1","addr":"(DB)","loc":"d,30:16,30:18","dtypep":"(G)","access":"RD","varp":"(O)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
{"type":"VARREF","name":"a1","addr":"(DB)","loc":"d,34:16,34:18","dtypep":"(G)","access":"RD","varp":"(O)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
],
|
||||
"rhsp": [
|
||||
{"type":"VARREF","name":"a2","addr":"(EB)","loc":"d,31:16,31:18","dtypep":"(G)","access":"RD","varp":"(R)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
{"type":"VARREF","name":"a2","addr":"(EB)","loc":"d,34:21,34:23","dtypep":"(G)","access":"RD","varp":"(R)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
]}
|
||||
],
|
||||
"lhsp": [
|
||||
{"type":"VARREF","name":"zn","addr":"(FB)","loc":"d,34:13,34:14","dtypep":"(G)","access":"WR","varp":"(U)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
{"type":"VARREF","name":"zn","addr":"(FB)","loc":"d,34:10,34:12","dtypep":"(G)","access":"WR","varp":"(U)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
],"timingControlp": [],"strengthSpecp": []}
|
||||
]}
|
||||
]}
|
||||
],"filesp": [],
|
||||
"miscsp": [
|
||||
{"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(GB)",
|
||||
{"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"UNLINKED",
|
||||
"typesp": [
|
||||
{"type":"BASICDTYPE","name":"logic","addr":"(G)","loc":"d,30:16,30:18","dtypep":"(G)","keyword":"logic","generic":true,"rangep": []},
|
||||
{"type":"VOIDDTYPE","name":"","addr":"(GB)","loc":"a,0:0,0:0","dtypep":"(GB)"}
|
||||
{"type":"BASICDTYPE","name":"logic","addr":"(G)","loc":"d,30:16,30:18","dtypep":"(G)","keyword":"logic","generic":true,"rangep": []}
|
||||
]},
|
||||
{"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
||||
"modulep": [
|
||||
{"type":"MODULE","name":"@CONST-POOL@","addr":"(HB)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [],
|
||||
{"type":"MODULE","name":"@CONST-POOL@","addr":"(GB)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","verilogName":"@CONST-POOL@","level":0,"timeunit":"NONE","inlinesp": [],
|
||||
"stmtsp": [
|
||||
{"type":"SCOPE","name":"@CONST-POOL@","addr":"(IB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(HB)","varsp": [],"blocksp": [],"inlinesp": []}
|
||||
{"type":"SCOPE","name":"@CONST-POOL@","addr":"(HB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(GB)","varsp": [],"blocksp": [],"inlinesp": []}
|
||||
]}
|
||||
]}
|
||||
]}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@
|
|||
40 | always_comb out6 = d;
|
||||
| ^~~~
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:17:14: Bit [0] of signal 'out2' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
t/t_lint_always_comb_multidriven_bad.v:28:15: ... Location of offending driver
|
||||
28 | assign out2 = d;
|
||||
| ^
|
||||
|
|
@ -57,7 +56,6 @@
|
|||
29 | always_comb out2 = 1'b0;
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:19:14: Bit [0] of signal 'out4' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
t/t_lint_always_comb_multidriven_bad.v:34:20: ... Location of offending driver
|
||||
34 | always_comb out4 = 1'b0;
|
||||
| ^
|
||||
|
|
@ -65,7 +63,6 @@
|
|||
35 | assign out4 = d;
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:20:14: Bit [0] of signal 'out5' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
t/t_lint_always_comb_multidriven_bad.v:37:20: ... Location of offending driver
|
||||
37 | always_comb out5 = 1'b0;
|
||||
| ^
|
||||
|
|
@ -73,7 +70,6 @@
|
|||
38 | always_comb out5 = d;
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:21:14: Bit [0] of signal 'out6' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
t/t_lint_always_comb_multidriven_bad.v:40:20: ... Location of offending driver
|
||||
40 | always_comb out6 = d;
|
||||
| ^
|
||||
|
|
|
|||
|
|
@ -48,32 +48,28 @@
|
|||
t/t_lint_always_comb_multidriven_bad.v:40:15: ... Location of other write
|
||||
40 | always_comb out6 = d;
|
||||
| ^~~~
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:17:14: Bit [0] of signal 'out2' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:17:14: Bit [0] of signal 't.out2' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_lint_always_comb_multidriven_bad.v:28:15: ... Location of offending driver
|
||||
28 | assign out2 = d;
|
||||
| ^
|
||||
t/t_lint_always_comb_multidriven_bad.v:29:20: ... Location of offending driver
|
||||
29 | always_comb out2 = 1'b0;
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:19:14: Bit [0] of signal 'out4' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:19:14: Bit [0] of signal 't.out4' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_lint_always_comb_multidriven_bad.v:34:20: ... Location of offending driver
|
||||
34 | always_comb out4 = 1'b0;
|
||||
| ^
|
||||
t/t_lint_always_comb_multidriven_bad.v:35:15: ... Location of offending driver
|
||||
35 | assign out4 = d;
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:20:14: Bit [0] of signal 'out5' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:20:14: Bit [0] of signal 't.out5' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_lint_always_comb_multidriven_bad.v:37:20: ... Location of offending driver
|
||||
37 | always_comb out5 = 1'b0;
|
||||
| ^
|
||||
t/t_lint_always_comb_multidriven_bad.v:38:20: ... Location of offending driver
|
||||
38 | always_comb out5 = d;
|
||||
| ^
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:21:14: Bit [0] of signal 'out6' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven_bad.v:21:14: Bit [0] of signal 't.out6' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_lint_always_comb_multidriven_bad.v:40:20: ... Location of offending driver
|
||||
40 | always_comb out6 = d;
|
||||
| ^
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
%Warning-MULTIDRIVEN: t/t_lint_multidriven_coverage_bad.v:13:15: Bit [0] of signal 'w' have multiple combinational drivers. This can cause performance degradation.
|
||||
: ... note: In instance 't'
|
||||
%Warning-MULTIDRIVEN: t/t_lint_multidriven_coverage_bad.v:13:15: Bit [0] of signal 't.w' have multiple combinational drivers. This can cause performance degradation.
|
||||
t/t_lint_multidriven_coverage_bad.v:15:15: ... Location of offending driver
|
||||
15 | assign w[0] = a;
|
||||
| ^
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "--stats", test.pli_filename
|
|||
test.execute()
|
||||
|
||||
if test.vlt:
|
||||
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 42)
|
||||
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 43)
|
||||
test.file_grep(test.stats, r'SplitVar, packed variables split automatically\s+(\d+)', 1)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
Loading…
Reference in New Issue