Optimize Dfg only once, after V3Scope (#7362)
This commit is contained in:
parent
e63c4f563e
commit
9f9532ff78
|
|
@ -649,9 +649,12 @@ Summary:
|
||||||
|
|
||||||
.. option:: -fno-dfg
|
.. option:: -fno-dfg
|
||||||
|
|
||||||
Rarely needed. Disable all use of the DFG-based combinational logic
|
Rarely needed. Disable the DFG-based combinational logic optimizer.
|
||||||
optimizer. Alias for :vlopt:`-fno-dfg-pre-inline`,
|
|
||||||
:vlopt:`-fno-dfg-post-inline` and :vlopt:`-fno-dfg-scoped`.
|
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
|
.. option:: -fno-dfg-break-cycles
|
||||||
|
|
||||||
|
|
@ -667,11 +670,15 @@ Summary:
|
||||||
|
|
||||||
.. option:: -fno-dfg-post-inline
|
.. 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
|
.. 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
|
.. option:: -fno-dfg-push-down-sels
|
||||||
|
|
||||||
|
|
@ -679,7 +686,10 @@ Summary:
|
||||||
|
|
||||||
.. option:: -fno-dfg-scoped
|
.. 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
|
.. 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_ignorePostRead : 1; // Ignore reads in 'Post' blocks during ordering
|
||||||
bool m_ignorePostWrite : 1; // Ignore writes 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_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_dfgTriLowered : 1; // Signal/temporary introduced by tristate lowering
|
||||||
bool m_dfgAllowMultidriveTri : 1; // Allow DFG MULTIDRIVEN warning for intentional tri nets
|
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
|
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_ignorePostRead = false;
|
||||||
m_ignorePostWrite = false;
|
m_ignorePostWrite = false;
|
||||||
m_ignoreSchedWrite = false;
|
m_ignoreSchedWrite = false;
|
||||||
m_dfgMultidriven = false;
|
|
||||||
m_dfgTriLowered = false;
|
m_dfgTriLowered = false;
|
||||||
m_dfgAllowMultidriveTri = false;
|
m_dfgAllowMultidriveTri = false;
|
||||||
m_globalConstrained = false;
|
m_globalConstrained = false;
|
||||||
|
|
@ -2206,8 +2204,6 @@ public:
|
||||||
void setIgnorePostWrite() { m_ignorePostWrite = true; }
|
void setIgnorePostWrite() { m_ignorePostWrite = true; }
|
||||||
bool ignoreSchedWrite() const { return m_ignoreSchedWrite; }
|
bool ignoreSchedWrite() const { return m_ignoreSchedWrite; }
|
||||||
void setIgnoreSchedWrite() { m_ignoreSchedWrite = true; }
|
void setIgnoreSchedWrite() { m_ignoreSchedWrite = true; }
|
||||||
bool dfgMultidriven() const { return m_dfgMultidriven; }
|
|
||||||
void setDfgMultidriven() { m_dfgMultidriven = true; }
|
|
||||||
bool dfgTriLowered() const { return m_dfgTriLowered; }
|
bool dfgTriLowered() const { return m_dfgTriLowered; }
|
||||||
void setDfgTriLowered() { m_dfgTriLowered = true; }
|
void setDfgTriLowered() { m_dfgTriLowered = true; }
|
||||||
bool dfgAllowMultidriveTri() const { return m_dfgAllowMultidriveTri; }
|
bool dfgAllowMultidriveTri() const { return m_dfgAllowMultidriveTri; }
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include "V3Dfg.h"
|
#include "V3Dfg.h"
|
||||||
|
|
||||||
|
#include "V3Ast.h"
|
||||||
#include "V3EmitV.h"
|
#include "V3EmitV.h"
|
||||||
#include "V3File.h"
|
#include "V3File.h"
|
||||||
|
|
||||||
|
|
@ -26,18 +27,16 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// DfgGraph
|
// DfgGraph
|
||||||
|
|
||||||
DfgGraph::DfgGraph(AstModule* modulep, const string& name)
|
DfgGraph::DfgGraph(const string& name)
|
||||||
: m_modulep{modulep}
|
: m_name{name} {}
|
||||||
, m_name{name} {}
|
|
||||||
|
|
||||||
DfgGraph::~DfgGraph() {
|
DfgGraph::~DfgGraph() {
|
||||||
forEachVertex([&](DfgVertex& vtx) { vtx.unlinkDelete(*this); });
|
forEachVertex([&](DfgVertex& vtx) { vtx.unlinkDelete(*this); });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
||||||
const bool scoped = !modulep();
|
// Create the new graph
|
||||||
|
DfgGraph* const clonep = new DfgGraph{name()};
|
||||||
DfgGraph* const clonep = new DfgGraph{modulep(), name()};
|
|
||||||
|
|
||||||
// Map from original vertex to clone
|
// Map from original vertex to clone
|
||||||
std::unordered_map<const DfgVertex*, DfgVertex*> vtxp2clonep(size() * 2);
|
std::unordered_map<const DfgVertex*, DfgVertex*> vtxp2clonep(size() * 2);
|
||||||
|
|
@ -54,20 +53,12 @@ std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
||||||
|
|
||||||
switch (vtx.type()) {
|
switch (vtx.type()) {
|
||||||
case VDfgType::VarArray: {
|
case VDfgType::VarArray: {
|
||||||
if (scoped) {
|
cp = new DfgVarArray{*clonep, vp->vscp()};
|
||||||
cp = new DfgVarArray{*clonep, vp->varScopep()};
|
|
||||||
} else {
|
|
||||||
cp = new DfgVarArray{*clonep, vp->varp()};
|
|
||||||
}
|
|
||||||
vtxp2clonep.emplace(&vtx, cp);
|
vtxp2clonep.emplace(&vtx, cp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VDfgType::VarPacked: {
|
case VDfgType::VarPacked: {
|
||||||
if (scoped) {
|
cp = new DfgVarPacked{*clonep, vp->vscp()};
|
||||||
cp = new DfgVarPacked{*clonep, vp->varScopep()};
|
|
||||||
} else {
|
|
||||||
cp = new DfgVarPacked{*clonep, vp->varp()};
|
|
||||||
}
|
|
||||||
vtxp2clonep.emplace(&vtx, cp);
|
vtxp2clonep.emplace(&vtx, cp);
|
||||||
break;
|
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
|
// Clone ast reference vertices
|
||||||
for (const DfgVertexAst& vtx : m_astVertices) { // LCOV_EXCL_START
|
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;
|
if (otherps.empty()) return;
|
||||||
|
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// AstVar/AstVarScope::user2p() -> corresponding DfgVertexVar* in 'this' graph
|
// AstVarScope::user2p() -> corresponding DfgVertexVar* in 'this' graph
|
||||||
const VNUser2InUse user2InUse;
|
const VNUser2InUse user2InUse;
|
||||||
|
|
||||||
// Set up Ast Variable -> DfgVertexVar map for 'this' graph
|
// 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
|
// Merge in each of the other graphs
|
||||||
for (const std::unique_ptr<DfgGraph>& otherp : otherps) {
|
for (const std::unique_ptr<DfgGraph>& otherp : otherps) {
|
||||||
// Process variables
|
// Process variables
|
||||||
for (DfgVertexVar* const vtxp : otherp->m_varVertices.unlinkable()) {
|
for (DfgVertexVar* const vtxp : otherp->m_varVertices.unlinkable()) {
|
||||||
// Variabels that are present in 'this', make them use the DfgVertexVar in 'this'.
|
// 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 srcp = vtxp->srcp();
|
||||||
DfgVertex* const defaultp = vtxp->defaultp();
|
DfgVertex* const defaultp = vtxp->defaultp();
|
||||||
UASSERT_OBJ(!(srcp || defaultp) || (!altp->srcp() && !altp->defaultp()), vtxp,
|
UASSERT_OBJ(!(srcp || defaultp) || (!altp->srcp() && !altp->defaultp()), vtxp,
|
||||||
|
|
@ -226,7 +217,7 @@ void DfgGraph::mergeGraphs(std::vector<std::unique_ptr<DfgGraph>>&& otherps) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Otherwise they will be moved
|
// Otherwise they will be moved
|
||||||
vtxp->nodep()->user2p(vtxp);
|
vtxp->vscp()->user2p(vtxp);
|
||||||
vtxp->m_userGeneration = 0;
|
vtxp->m_userGeneration = 0;
|
||||||
#ifdef VL_DEBUG
|
#ifdef VL_DEBUG
|
||||||
vtxp->m_dfgp = this;
|
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,
|
DfgVertexVar* DfgGraph::makeNewVar(FileLine* flp, const std::string& name,
|
||||||
const DfgDataType& dtype, AstScope* scopep) {
|
const DfgDataType& dtype, AstScope* scopep) {
|
||||||
UASSERT_OBJ(!!scopep != !!modulep(), flp,
|
|
||||||
"makeNewVar scopep should only be provided for a scoped DfgGraph");
|
|
||||||
|
|
||||||
// Create AstVar
|
// Create AstVar
|
||||||
AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, dtype.astDtypep()};
|
AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, dtype.astDtypep()};
|
||||||
|
// Add AstVar to the scope's module
|
||||||
if (scopep) {
|
scopep->modp()->addStmtsp(varp);
|
||||||
// Add AstVar to the scope's module
|
// Create AstVarScope
|
||||||
scopep->modp()->addStmtsp(varp);
|
AstVarScope* const vscp = new AstVarScope{flp, scopep, varp};
|
||||||
// Create AstVarScope
|
// Add to scope
|
||||||
AstVarScope* const vscp = new AstVarScope{flp, scopep, varp};
|
scopep->addVarsp(vscp);
|
||||||
// Add to scope
|
// Create and return the corresponding variable vertex
|
||||||
scopep->addVarsp(vscp);
|
if (dtype.isArray()) return new DfgVarArray{*this, vscp};
|
||||||
// Create and return the corresponding variable vertex
|
return new DfgVarPacked{*this, vscp};
|
||||||
if (dtype.isArray()) return new DfgVarArray{*this, vscp};
|
|
||||||
return new DfgVarPacked{*this, vscp};
|
|
||||||
} else {
|
|
||||||
// Add AstVar to containing module
|
|
||||||
modulep()->addStmtsp(varp);
|
|
||||||
// Create and return the corresponding variable vertex
|
|
||||||
if (dtype.isArray()) return new DfgVarArray{*this, varp};
|
|
||||||
return new DfgVarPacked{*this, varp};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::string toDotId(const DfgVertex& vtx) { return '"' + cvtToHex(&vtx) + '"'; }
|
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
|
// Dump one DfgVertex in Graphviz format
|
||||||
static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) {
|
static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) {
|
||||||
if (const DfgVertexVar* const varVtxp = vtx.cast<DfgVertexVar>()) {
|
if (const DfgVertexVar* const varVtxp = vtx.cast<DfgVertexVar>()) {
|
||||||
const AstNode* const nodep = varVtxp->nodep();
|
const AstVarScope* const vscp = varVtxp->vscp();
|
||||||
os << toDotId(vtx);
|
os << toDotId(vtx);
|
||||||
// Begin attributes
|
// Begin attributes
|
||||||
os << " [";
|
os << " [";
|
||||||
// Begin 'label'
|
// Begin 'label'
|
||||||
os << "label=\"";
|
os << "label=\"";
|
||||||
// Name
|
// Name
|
||||||
os << nodep->prettyName();
|
os << vscp->prettyName();
|
||||||
// Address
|
// Address
|
||||||
os << '\n' << cvtToHex(varVtxp);
|
os << '\n' << cvtToHex(varVtxp);
|
||||||
// Original variable, if any
|
// Original variable, if any
|
||||||
if (const AstNode* const tmpForp = varVtxp->tmpForp()) {
|
if (const AstVarScope* const tmpForp = varVtxp->tmpForp()) {
|
||||||
if (tmpForp != nodep) os << "\ntemporary for: " << tmpForp->prettyName();
|
if (tmpForp != vscp) os << "\ntemporary for: " << tmpForp->prettyName();
|
||||||
}
|
}
|
||||||
// Type and fanout
|
// Type and fanout
|
||||||
os << '\n';
|
os << '\n';
|
||||||
|
|
@ -879,10 +858,8 @@ DfgVertexVar* DfgVertex::getResultVar() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefer real variables over temporaries
|
// Prefer real variables over temporaries
|
||||||
const bool resIsTemp
|
const bool resIsTemp = resp->vscp()->varp()->isTemp();
|
||||||
= resp->varp() ? resp->varp()->isTemp() : resp->varScopep()->varp()->isTemp();
|
const bool varIsTemp = varp->vscp()->varp()->isTemp();
|
||||||
const bool varIsTemp
|
|
||||||
= varp->varp() ? varp->varp()->isTemp() : varp->varScopep()->varp()->isTemp();
|
|
||||||
if (resIsTemp != varIsTemp) {
|
if (resIsTemp != varIsTemp) {
|
||||||
if (resIsTemp) resp = varp;
|
if (resIsTemp) resp = varp;
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -900,7 +877,7 @@ DfgVertexVar* DfgVertex::getResultVar() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Prefer the one with the lexically smaller name
|
// 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;
|
if (cmp > 0) resp = varp;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -913,13 +890,13 @@ DfgVertexVar* DfgVertex::getResultVar() {
|
||||||
AstScope* DfgVertex::scopep(ScopeCache& cache, bool tryResultVar) VL_MT_DISABLED {
|
AstScope* DfgVertex::scopep(ScopeCache& cache, bool tryResultVar) VL_MT_DISABLED {
|
||||||
// If this is a variable, we are done
|
// If this is a variable, we are done
|
||||||
if (const DfgVertexVar* const varp = this->cast<DfgVertexVar>()) {
|
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)
|
// Try the result var first if instructed (usully only in the recursive case)
|
||||||
if (tryResultVar) {
|
if (tryResultVar) {
|
||||||
if (const DfgVertexVar* const varp = this->getResultVar()) {
|
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<DfgConst> m_constVertices; // The constant vertices in the graph
|
||||||
DfgVertex::List<DfgVertex> m_opVertices; // The operation 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
|
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
|
const std::string m_name; // Name of graph - need not be unique
|
||||||
std::string m_tmpNameStub{""}; // Name stub for temporary variables - computed lazy
|
std::string m_tmpNameStub{""}; // Name stub for temporary variables - computed lazy
|
||||||
|
|
||||||
|
|
@ -399,15 +396,13 @@ class DfgGraph final {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTOR
|
// CONSTRUCTOR
|
||||||
explicit DfgGraph(AstModule* modulep, const string& name = "") VL_MT_DISABLED;
|
explicit DfgGraph(const string& name = "") VL_MT_DISABLED;
|
||||||
~DfgGraph() VL_MT_DISABLED;
|
~DfgGraph() VL_MT_DISABLED;
|
||||||
VL_UNCOPYABLE(DfgGraph);
|
VL_UNCOPYABLE(DfgGraph);
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
// Number of vertices in this graph
|
// Number of vertices in this graph
|
||||||
size_t size() const { return m_size; }
|
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
|
// Name of this graph
|
||||||
const string& name() const { return m_name; }
|
const string& name() const { return m_name; }
|
||||||
|
|
||||||
|
|
@ -558,16 +553,6 @@ namespace V3Dfg {
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
// Functions for compatibility tests
|
// 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
|
// Returns true if variable can be represented in the graph
|
||||||
inline bool isSupported(const AstVarScope* vscp) {
|
inline bool isSupported(const AstVarScope* vscp) {
|
||||||
const AstNodeModule* const modp = vscp->scopep()->modp();
|
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
|
if (DfgVertexVar::hasRWRefs(vscp)) return false; // Referenced via READWRITE references
|
||||||
// Check the AstVar
|
// 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
|
} //namespace V3Dfg
|
||||||
|
|
|
||||||
|
|
@ -30,28 +30,14 @@
|
||||||
|
|
||||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
|
|
||||||
template <bool T_Scoped>
|
|
||||||
class AstToDfgAddAstRefs final : public VNVisitorConst {
|
class AstToDfgAddAstRefs final : public VNVisitorConst {
|
||||||
// TYPES
|
|
||||||
using Variable = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
DfgGraph& m_dfg; // The graph being processed
|
DfgGraph& m_dfg; // The graph being processed
|
||||||
// Function to get the DfgVertexVar for a Variable
|
// Function to get the DfgVertexVar for a AstVarScope
|
||||||
const std::function<DfgVertexVar*(Variable*)> m_getVarVertex;
|
const std::function<DfgVertexVar*(AstVarScope*)> m_getVarVertex;
|
||||||
bool m_inSenItem = false; // Inside an AstSenItem
|
bool m_inSenItem = false; // Inside an AstSenItem
|
||||||
bool m_inLoop = false; // Inside an AstLoop
|
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
|
// VISITORS
|
||||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||||
|
|
||||||
|
|
@ -71,12 +57,12 @@ class AstToDfgAddAstRefs final : public VNVisitorConst {
|
||||||
// Disguised hierarchical reference handled as external reference, ignore
|
// Disguised hierarchical reference handled as external reference, ignore
|
||||||
if (nodep->classOrPackagep()) return;
|
if (nodep->classOrPackagep()) return;
|
||||||
// If target is not supported, ignore
|
// If target is not supported, ignore
|
||||||
Variable* const tgtp = getTarget(nodep);
|
AstVarScope* const vscp = nodep->varScopep();
|
||||||
if (!V3Dfg::isSupported(tgtp)) return;
|
if (!V3Dfg::isSupported(vscp)) return;
|
||||||
// V3Dfg::isSupported should reject vars with READWRITE references
|
// 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
|
// Get target variable vergtex, ignore if not given one
|
||||||
DfgVertexVar* const varp = m_getVarVertex(tgtp);
|
DfgVertexVar* const varp = m_getVarVertex(vscp);
|
||||||
if (!varp) return;
|
if (!varp) return;
|
||||||
// Create Ast reference vertices
|
// Create Ast reference vertices
|
||||||
if (nodep->access().isReadOnly()) {
|
if (nodep->access().isReadOnly()) {
|
||||||
|
|
@ -85,11 +71,11 @@ class AstToDfgAddAstRefs final : public VNVisitorConst {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Mark as written from non-DFG logic
|
// Mark as written from non-DFG logic
|
||||||
DfgVertexVar::setHasModWrRefs(tgtp);
|
DfgVertexVar::setHasModWrRefs(vscp);
|
||||||
}
|
}
|
||||||
|
|
||||||
AstToDfgAddAstRefs(DfgGraph& dfg, AstNode* nodep,
|
AstToDfgAddAstRefs(DfgGraph& dfg, AstNode* nodep,
|
||||||
std::function<DfgVertexVar*(Variable*)> getVarVertex)
|
std::function<DfgVertexVar*(AstVarScope*)> getVarVertex)
|
||||||
: m_dfg{dfg}
|
: m_dfg{dfg}
|
||||||
, m_getVarVertex{getVarVertex} {
|
, m_getVarVertex{getVarVertex} {
|
||||||
iterateConst(nodep);
|
iterateConst(nodep);
|
||||||
|
|
@ -97,67 +83,37 @@ class AstToDfgAddAstRefs final : public VNVisitorConst {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void apply(DfgGraph& dfg, AstNode* nodep,
|
static void apply(DfgGraph& dfg, AstNode* nodep,
|
||||||
std::function<DfgVertexVar*(Variable*)> getVarVertex) {
|
std::function<DfgVertexVar*(AstVarScope*)> getVarVertex) {
|
||||||
AstToDfgAddAstRefs{dfg, nodep, getVarVertex};
|
AstToDfgAddAstRefs{dfg, nodep, getVarVertex};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void V3DfgPasses::addAstRefs(DfgGraph& dfg, AstNode* nodep,
|
void V3DfgPasses::addAstRefs(DfgGraph& dfg, AstNode* nodep,
|
||||||
std::function<DfgVertexVar*(AstNode*)> getVarVertex) {
|
std::function<DfgVertexVar*(AstVarScope*)> getVarVertex) {
|
||||||
if (dfg.modulep()) {
|
AstToDfgAddAstRefs::apply(dfg, nodep, getVarVertex);
|
||||||
AstToDfgAddAstRefs</* T_Scoped: */ false>::apply(dfg, nodep, getVarVertex);
|
|
||||||
} else {
|
|
||||||
AstToDfgAddAstRefs</* T_Scoped: */ true>::apply(dfg, nodep, getVarVertex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool T_Scoped>
|
|
||||||
class AstToDfgVisitor final : public VNVisitor {
|
class AstToDfgVisitor final : public VNVisitor {
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// AstVar/AstVarScope::user2() -> DfgVertexVar* : the corresponding variable vertex
|
// AstVarScope::user2() -> DfgVertexVar* : the corresponding variable vertex
|
||||||
// AstVar/AstVarScope::user3() -> bool : Already gathered - used fine grained below
|
// AstVarScope::user3() -> bool : Already gathered - used fine grained below
|
||||||
const VNUser2InUse m_user2InUse;
|
const VNUser2InUse m_user2InUse;
|
||||||
|
|
||||||
// TYPES
|
|
||||||
using RootType = std::conditional_t<T_Scoped, AstNetlist, AstModule>;
|
|
||||||
using Variable = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
DfgGraph& m_dfg; // The graph being built
|
DfgGraph& m_dfg; // The graph being built
|
||||||
V3DfgAstToDfgContext& m_ctx; // The context for stats
|
V3DfgAstToDfgContext& m_ctx; // The context for stats
|
||||||
AstScope* m_scopep = nullptr; // The current scope, iff T_Scoped
|
AstScope* m_scopep = nullptr; // The current scope, iff T_Scoped
|
||||||
|
|
||||||
// METHODS
|
// 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
|
// Mark variables referenced under node
|
||||||
void markReferenced(AstNode* nodep) {
|
void markReferenced(AstNode* nodep) {
|
||||||
V3DfgPasses::addAstRefs(m_dfg, nodep, [this](AstNode* varp) { //
|
V3DfgPasses::addAstRefs(m_dfg, nodep, [this](AstVarScope* vscp) { //
|
||||||
return getVarVertex(static_cast<Variable*>(varp));
|
return getVarVertex(vscp);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
DfgVertexVar* getVarVertex(Variable* varp) {
|
DfgVertexVar* getVarVertex(AstVarScope* varp) {
|
||||||
if (!varp->user2p()) {
|
if (!varp->user2p()) {
|
||||||
// TODO: fix this up when removing the different flavours of DfgVar
|
// TODO: fix this up when removing the different flavours of DfgVar
|
||||||
const AstNodeDType* const dtypep = varp->dtypep()->skipRefp();
|
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) {
|
std::unique_ptr<std::vector<DfgVertexVar*>> gatherWritten(const AstNode* nodep) {
|
||||||
const VNUser3InUse user3InUse;
|
const VNUser3InUse user3InUse;
|
||||||
std::unique_ptr<std::vector<DfgVertexVar*>> resp{new std::vector<DfgVertexVar*>{}};
|
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
|
const bool abort = nodep->exists([&](const AstVarRef* refp) -> bool {
|
||||||
// synthesize it into regular vertices, which will fail on a VarXRef at that point.
|
if (refp->access().isReadOnly()) return false;
|
||||||
const bool abort = nodep->exists([&](const AstNodeVarRef* vrefp) -> bool {
|
AstVarScope* const vscp = refp->varScopep();
|
||||||
if (VN_IS(vrefp, VarXRef)) return true;
|
if (!V3Dfg::isSupported(vscp)) return true;
|
||||||
if (vrefp->access().isReadOnly()) return false;
|
if (!vscp->user3SetOnce()) resp->emplace_back(getVarVertex(vscp));
|
||||||
Variable* const varp = getTarget(VN_AS(vrefp, VarRef));
|
|
||||||
if (!V3Dfg::isSupported(varp)) return true;
|
|
||||||
if (!varp->user3SetOnce()) resp->emplace_back(getVarVertex(varp));
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
if (abort) {
|
if (abort) {
|
||||||
|
|
@ -197,14 +150,11 @@ class AstToDfgVisitor final : public VNVisitor {
|
||||||
std::unique_ptr<std::vector<DfgVertexVar*>> gatherRead(const AstNode* nodep) {
|
std::unique_ptr<std::vector<DfgVertexVar*>> gatherRead(const AstNode* nodep) {
|
||||||
const VNUser3InUse user3InUse;
|
const VNUser3InUse user3InUse;
|
||||||
std::unique_ptr<std::vector<DfgVertexVar*>> resp{new std::vector<DfgVertexVar*>{}};
|
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
|
const bool abort = nodep->exists([&](const AstVarRef* refp) -> bool {
|
||||||
// synthesize it into regular vertices, which will fail on a VarXRef at that point.
|
if (refp->access().isWriteOnly()) return false;
|
||||||
const bool abort = nodep->exists([&](const AstNodeVarRef* vrefp) -> bool {
|
AstVarScope* const vscp = refp->varScopep();
|
||||||
if (VN_IS(vrefp, VarXRef)) return true;
|
if (!V3Dfg::isSupported(vscp)) return true;
|
||||||
if (vrefp->access().isWriteOnly()) return false;
|
if (!vscp->user3SetOnce()) resp->emplace_back(getVarVertex(vscp));
|
||||||
Variable* const varp = getTarget(VN_AS(vrefp, VarRef));
|
|
||||||
if (!V3Dfg::isSupported(varp)) return true;
|
|
||||||
if (!varp->user3SetOnce()) resp->emplace_back(getVarVertex(varp));
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
if (abort) {
|
if (abort) {
|
||||||
|
|
@ -218,7 +168,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
||||||
// Return nullptr if any are not supported.
|
// Return nullptr if any are not supported.
|
||||||
std::unique_ptr<std::vector<DfgVertexVar*>> gatherLive(const CfgGraph& cfg) {
|
std::unique_ptr<std::vector<DfgVertexVar*>> gatherLive(const CfgGraph& cfg) {
|
||||||
// Run analysis
|
// Run analysis
|
||||||
std::unique_ptr<std::vector<Variable*>> varps = getLiveVariables(cfg);
|
std::unique_ptr<std::vector<AstVarScope*>> varps = V3Cfg::liveVarScopes(cfg);
|
||||||
if (!varps) {
|
if (!varps) {
|
||||||
++m_ctx.m_nonRepLive;
|
++m_ctx.m_nonRepLive;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -228,7 +178,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
||||||
const VNUser3InUse user3InUse;
|
const VNUser3InUse user3InUse;
|
||||||
std::unique_ptr<std::vector<DfgVertexVar*>> resp{new std::vector<DfgVertexVar*>{}};
|
std::unique_ptr<std::vector<DfgVertexVar*>> resp{new std::vector<DfgVertexVar*>{}};
|
||||||
resp->reserve(varps->size());
|
resp->reserve(varps->size());
|
||||||
for (Variable* const varp : *varps) {
|
for (AstVarScope* const varp : *varps) {
|
||||||
if (!V3Dfg::isSupported(varp)) {
|
if (!V3Dfg::isSupported(varp)) {
|
||||||
++m_ctx.m_nonRepVar;
|
++m_ctx.m_nonRepVar;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -347,7 +297,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CONSTRUCTOR
|
// CONSTRUCTOR
|
||||||
AstToDfgVisitor(DfgGraph& dfg, RootType& root, V3DfgAstToDfgContext& ctx)
|
AstToDfgVisitor(DfgGraph& dfg, AstNetlist& root, V3DfgAstToDfgContext& ctx)
|
||||||
: m_dfg{dfg}
|
: m_dfg{dfg}
|
||||||
, m_ctx{ctx} {
|
, m_ctx{ctx} {
|
||||||
iterate(&root);
|
iterate(&root);
|
||||||
|
|
@ -356,7 +306,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
||||||
VL_UNMOVABLE(AstToDfgVisitor);
|
VL_UNMOVABLE(AstToDfgVisitor);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void apply(DfgGraph& dfg, RootType& root, V3DfgAstToDfgContext& ctx) {
|
static void apply(DfgGraph& dfg, AstNetlist& root, V3DfgAstToDfgContext& ctx) {
|
||||||
// Convert all logic under 'root'
|
// Convert all logic under 'root'
|
||||||
AstToDfgVisitor{dfg, root, ctx};
|
AstToDfgVisitor{dfg, root, ctx};
|
||||||
// Remove unread and undriven variables (created when something failed to convert)
|
// 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) {
|
std::unique_ptr<DfgGraph> V3DfgPasses::astToDfg(AstNetlist& netlist, V3DfgContext& ctx) {
|
||||||
DfgGraph* const dfgp = new DfgGraph{nullptr, "netlist"};
|
DfgGraph* const dfgp = new DfgGraph{"netlist"};
|
||||||
AstToDfgVisitor</* T_Scoped: */ true>::apply(*dfgp, netlist, ctx.m_ast2DfgContext);
|
AstToDfgVisitor::apply(*dfgp, netlist, ctx.m_ast2DfgContext);
|
||||||
return std::unique_ptr<DfgGraph>{dfgp};
|
return std::unique_ptr<DfgGraph>{dfgp};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,15 +115,14 @@ class TraceDriver final : public DfgVisitor {
|
||||||
|
|
||||||
// Create temporary capable of holding the result of 'vtxp'
|
// Create temporary capable of holding the result of 'vtxp'
|
||||||
DfgVertexVar* createTmp(const char* prefix, DfgVertex* vtxp) {
|
DfgVertexVar* createTmp(const char* prefix, DfgVertex* vtxp) {
|
||||||
AstNode* nodep = m_dfg.modulep();
|
AstNode* nodep = v3Global.rootp();
|
||||||
if (!nodep) nodep = v3Global.rootp();
|
|
||||||
const std::string name = m_dfg.makeUniqueName(prefix, nodep->user2Inc());
|
const std::string name = m_dfg.makeUniqueName(prefix, nodep->user2Inc());
|
||||||
FileLine* const flp = vtxp->fileline();
|
FileLine* const flp = vtxp->fileline();
|
||||||
DfgVertex::ScopeCache scopeCache;
|
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);
|
DfgVertexVar* const varp = m_dfg.makeNewVar(flp, name, vtxp->dtype(), scopep);
|
||||||
varp->varp()->isInternal(true);
|
varp->vscp()->varp()->isInternal(true);
|
||||||
varp->tmpForp(varp->nodep());
|
varp->tmpForp(varp->vscp());
|
||||||
m_vtx2Scc[varp] = 0;
|
m_vtx2Scc[varp] = 0;
|
||||||
return varp;
|
return varp;
|
||||||
}
|
}
|
||||||
|
|
@ -1015,7 +1014,7 @@ class FixUp final {
|
||||||
return debugStr(*aselp->fromp()) + "[" + std::to_string(i) + "]";
|
return debugStr(*aselp->fromp()) + "[" + std::to_string(i) + "]";
|
||||||
}
|
}
|
||||||
if (const DfgVertexVar* const varp = vtx.cast<DfgVertexVar>()) {
|
if (const DfgVertexVar* const varp = vtx.cast<DfgVertexVar>()) {
|
||||||
return varp->nodep()->name();
|
return varp->vscp()->name();
|
||||||
}
|
}
|
||||||
vtx.v3fatalSrc("Unhandled node type");
|
vtx.v3fatalSrc("Unhandled node type");
|
||||||
} // LCOV_EXCL_STOP
|
} // LCOV_EXCL_STOP
|
||||||
|
|
@ -1128,7 +1127,7 @@ class FixUp final {
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(DfgVertexVar& var) {
|
void main(DfgVertexVar& var) {
|
||||||
UINFO(9, "FixUp of " << var.nodep()->name());
|
UINFO(9, "FixUp of " << var.vscp()->name());
|
||||||
|
|
||||||
if (var.is<DfgVarPacked>()) {
|
if (var.is<DfgVarPacked>()) {
|
||||||
// For Packed variables, fix up as whole
|
// For Packed variables, fix up as whole
|
||||||
|
|
@ -1179,7 +1178,7 @@ std::pair<std::unique_ptr<DfgGraph>, bool> //
|
||||||
breakCycles(const DfgGraph& dfg, V3DfgContext& ctx) {
|
breakCycles(const DfgGraph& dfg, V3DfgContext& ctx) {
|
||||||
// Shorthand for dumping graph at given dump level
|
// Shorthand for dumping graph at given dump level
|
||||||
const auto dump = [&](int level, const DfgGraph& dfg, const std::string& name) {
|
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
|
// 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) {
|
if (dumpDfgLevel() >= 9) {
|
||||||
Vtx2Scc vtx2Scc = res.makeUserMap<uint64_t>();
|
Vtx2Scc vtx2Scc = res.makeUserMap<uint64_t>();
|
||||||
V3DfgPasses::colorStronglyConnectedComponents(res, vtx2Scc);
|
V3DfgPasses::colorStronglyConnectedComponents(res, vtx2Scc);
|
||||||
res.dumpDotFilePrefixed(ctx.prefix() + "breakCycles-remaining", [&](const DfgVertex& vtx) {
|
res.dumpDotFilePrefixed("breakCycles-remaining", [&](const DfgVertex& vtx) {
|
||||||
return vtx2Scc[vtx]; //
|
return vtx2Scc[vtx]; //
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,25 +37,17 @@ class V3DfgContext;
|
||||||
// Base class for all context objects
|
// Base class for all context objects
|
||||||
|
|
||||||
class V3DfgSubContext VL_NOT_FINAL {
|
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
|
const std::string m_name; // Pass/algorithm name, to be used in statistics
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
|
|
||||||
V3DfgSubContext(V3DfgContext& ctx, const std::string& label, const char* name)
|
V3DfgSubContext(const std::string& name)
|
||||||
: m_ctx{ctx}
|
: m_name{name} {}
|
||||||
, m_label{label}
|
|
||||||
, m_name{name} {}
|
|
||||||
|
|
||||||
void addStat(const std::string& what, double value) {
|
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
|
VDouble0 m_nonRepVar; // Non-representable due to unsupported variable properties
|
||||||
|
|
||||||
private:
|
private:
|
||||||
V3DfgAstToDfgContext(V3DfgContext& ctx, const std::string& label)
|
V3DfgAstToDfgContext()
|
||||||
: V3DfgSubContext{ctx, label, "AstToDfg"} {}
|
: V3DfgSubContext{"AstToDfg"} {}
|
||||||
~V3DfgAstToDfgContext() {
|
~V3DfgAstToDfgContext() {
|
||||||
addStat("input processes", m_inputs);
|
addStat("input processes", m_inputs);
|
||||||
addStat("representable", m_representable);
|
addStat("representable", m_representable);
|
||||||
|
|
@ -96,8 +88,8 @@ public:
|
||||||
VDouble0 m_decodersCreated; // Number of bianry to one-hot decoders created
|
VDouble0 m_decodersCreated; // Number of bianry to one-hot decoders created
|
||||||
|
|
||||||
private:
|
private:
|
||||||
V3DfgBinToOneHotContext(V3DfgContext& ctx, const std::string& label)
|
V3DfgBinToOneHotContext()
|
||||||
: V3DfgSubContext{ctx, label, "BinToOneHot"} {}
|
: V3DfgSubContext{"BinToOneHot"} {}
|
||||||
~V3DfgBinToOneHotContext() { addStat("decoders created", m_decodersCreated); }
|
~V3DfgBinToOneHotContext() { addStat("decoders created", m_decodersCreated); }
|
||||||
};
|
};
|
||||||
class V3DfgBreakCyclesContext final : public V3DfgSubContext {
|
class V3DfgBreakCyclesContext final : public V3DfgSubContext {
|
||||||
|
|
@ -113,8 +105,8 @@ public:
|
||||||
VDouble0 m_nImprovements; // Number of changes made to graphs
|
VDouble0 m_nImprovements; // Number of changes made to graphs
|
||||||
|
|
||||||
private:
|
private:
|
||||||
V3DfgBreakCyclesContext(V3DfgContext& ctx, const std::string& label)
|
V3DfgBreakCyclesContext()
|
||||||
: V3DfgSubContext{ctx, label, "BreakCycles"} {}
|
: V3DfgSubContext{"BreakCycles"} {}
|
||||||
~V3DfgBreakCyclesContext() {
|
~V3DfgBreakCyclesContext() {
|
||||||
addStat("made acyclic", m_nFixed);
|
addStat("made acyclic", m_nFixed);
|
||||||
addStat("improved", m_nImproved);
|
addStat("improved", m_nImproved);
|
||||||
|
|
@ -132,8 +124,8 @@ public:
|
||||||
VDouble0 m_eliminated; // Number of common sub-expressions eliminated
|
VDouble0 m_eliminated; // Number of common sub-expressions eliminated
|
||||||
|
|
||||||
private:
|
private:
|
||||||
V3DfgCseContext(V3DfgContext& ctx, const std::string& label)
|
explicit V3DfgCseContext(const std::string& label)
|
||||||
: V3DfgSubContext{ctx, label, "CSE"} {}
|
: V3DfgSubContext{"CSE " + label} {}
|
||||||
~V3DfgCseContext() { addStat("expressions eliminated", m_eliminated); }
|
~V3DfgCseContext() { addStat("expressions eliminated", m_eliminated); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -150,8 +142,8 @@ public:
|
||||||
VDouble0 m_varRefsSubstituted; // Number of variable references substituted in the Ast
|
VDouble0 m_varRefsSubstituted; // Number of variable references substituted in the Ast
|
||||||
|
|
||||||
private:
|
private:
|
||||||
V3DfgDfgToAstContext(V3DfgContext& ctx, const std::string& label)
|
V3DfgDfgToAstContext()
|
||||||
: V3DfgSubContext{ctx, label, "DfgToAst"} {}
|
: V3DfgSubContext{"DfgToAst"} {}
|
||||||
~V3DfgDfgToAstContext() {
|
~V3DfgDfgToAstContext() {
|
||||||
addStat("output variables", m_outputVariables);
|
addStat("output variables", m_outputVariables);
|
||||||
addStat("output variables with default driver", m_outputVariablesWithDefault);
|
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
|
std::vector<AstNode*> m_deleteps; // AstVar/AstVarScope that can be deleted at the end
|
||||||
|
|
||||||
private:
|
private:
|
||||||
V3DfgPeepholeContext(V3DfgContext& ctx, const std::string& label) VL_MT_DISABLED;
|
V3DfgPeepholeContext()
|
||||||
~V3DfgPeepholeContext() VL_MT_DISABLED;
|
: 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 {
|
class V3DfgPushDownSelsContext final : public V3DfgSubContext {
|
||||||
// Only V3DfgContext can create an instance
|
// 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_pushedDown = 0; // Number of selects pushed down through concatenations
|
||||||
size_t m_wouldBeCyclic = 0; // Number of selects not pushed due to cycle
|
size_t m_wouldBeCyclic = 0; // Number of selects not pushed due to cycle
|
||||||
private:
|
private:
|
||||||
V3DfgPushDownSelsContext(V3DfgContext& ctx, const std::string& label)
|
V3DfgPushDownSelsContext()
|
||||||
: V3DfgSubContext{ctx, label, "PushDownSels"} {}
|
: V3DfgSubContext{"PushDownSels"} {}
|
||||||
~V3DfgPushDownSelsContext() {
|
~V3DfgPushDownSelsContext() {
|
||||||
addStat("sels pushed down", m_pushedDown);
|
addStat("sels pushed down", m_pushedDown);
|
||||||
addStat("would be cyclic", m_wouldBeCyclic);
|
addStat("would be cyclic", m_wouldBeCyclic);
|
||||||
|
|
@ -204,8 +222,8 @@ public:
|
||||||
VDouble0 m_temporariesIntroduced; // Number of temporaries introduced for reuse
|
VDouble0 m_temporariesIntroduced; // Number of temporaries introduced for reuse
|
||||||
|
|
||||||
private:
|
private:
|
||||||
V3DfgRegularizeContext(V3DfgContext& ctx, const std::string& label)
|
V3DfgRegularizeContext()
|
||||||
: V3DfgSubContext{ctx, label, "Regularize"} {}
|
: V3DfgSubContext{"Regularize"} {}
|
||||||
~V3DfgRegularizeContext() {
|
~V3DfgRegularizeContext() {
|
||||||
for (AstNode* const nodep : m_deleteps) {
|
for (AstNode* const nodep : m_deleteps) {
|
||||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
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
|
VDouble0 m_logicDeleted; // Number of logic blocks removed from the Dfg and the Ast
|
||||||
|
|
||||||
private:
|
private:
|
||||||
V3DfgRemoveUnobservableContext(V3DfgContext& ctx, const std::string& label)
|
V3DfgRemoveUnobservableContext()
|
||||||
: V3DfgSubContext{ctx, label, "RemoveUnobservable"} {}
|
: V3DfgSubContext{"RemoveUnobservable"} {}
|
||||||
~V3DfgRemoveUnobservableContext() {
|
~V3DfgRemoveUnobservableContext() {
|
||||||
addStat("variables removed", m_varsRemoved);
|
addStat("variables removed", m_varsRemoved);
|
||||||
addStat("variables deleted", m_varsDeleted);
|
addStat("variables deleted", m_varsDeleted);
|
||||||
|
|
@ -291,8 +309,8 @@ public:
|
||||||
} m_synt;
|
} m_synt;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
V3DfgSynthesisContext(V3DfgContext& ctx, const std::string& label)
|
V3DfgSynthesisContext()
|
||||||
: V3DfgSubContext{ctx, label, "Synthesis"} {}
|
: V3DfgSubContext{"Synthesis"} {}
|
||||||
~V3DfgSynthesisContext() {
|
~V3DfgSynthesisContext() {
|
||||||
// Conversion statistics
|
// Conversion statistics
|
||||||
addStat("conv / input assignments", m_conv.inputAssignments);
|
addStat("conv / input assignments", m_conv.inputAssignments);
|
||||||
|
|
@ -367,64 +385,40 @@ private:
|
||||||
// Top level V3DfgContext
|
// Top level V3DfgContext
|
||||||
|
|
||||||
class V3DfgContext final {
|
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:
|
public:
|
||||||
// STATE
|
// STATE
|
||||||
|
|
||||||
// Global statistics
|
|
||||||
VDouble0 m_modules; // Number of modules optimized
|
|
||||||
|
|
||||||
// Sub contexts - keep sorted by type
|
// Sub contexts - keep sorted by type
|
||||||
V3DfgAstToDfgContext m_ast2DfgContext{*this, m_label};
|
V3DfgAstToDfgContext m_ast2DfgContext;
|
||||||
V3DfgBinToOneHotContext m_binToOneHotContext{*this, m_label};
|
V3DfgBinToOneHotContext m_binToOneHotContext;
|
||||||
V3DfgBreakCyclesContext m_breakCyclesContext{*this, m_label};
|
V3DfgBreakCyclesContext m_breakCyclesContext;
|
||||||
V3DfgCseContext m_cseContext0{*this, m_label + " 1st"};
|
V3DfgCseContext m_cseContext0{"1st"};
|
||||||
V3DfgCseContext m_cseContext1{*this, m_label + " 2nd"};
|
V3DfgCseContext m_cseContext1{"2nd"};
|
||||||
V3DfgDfgToAstContext m_dfg2AstContext{*this, m_label};
|
V3DfgDfgToAstContext m_dfg2AstContext;
|
||||||
V3DfgPeepholeContext m_peepholeContext{*this, m_label};
|
V3DfgPeepholeContext m_peepholeContext;
|
||||||
V3DfgPushDownSelsContext m_pushDownSelsContext{*this, m_label};
|
V3DfgPushDownSelsContext m_pushDownSelsContext;
|
||||||
V3DfgRegularizeContext m_regularizeContext{*this, m_label};
|
V3DfgRegularizeContext m_regularizeContext;
|
||||||
V3DfgRemoveUnobservableContext m_removeUnobservableContext{*this, m_label};
|
V3DfgRemoveUnobservableContext m_removeUnobservableContext;
|
||||||
V3DfgSynthesisContext m_synthContext{*this, m_label};
|
V3DfgSynthesisContext m_synthContext;
|
||||||
|
|
||||||
// Node pattern collector
|
// Node pattern collector
|
||||||
V3DfgPatternStats m_patternStats;
|
V3DfgPatternStats m_patternStats;
|
||||||
|
|
||||||
// CONSTRUCTOR
|
// CONSTRUCTOR
|
||||||
explicit V3DfgContext(const std::string& label)
|
V3DfgContext() = default;
|
||||||
: m_label{label}
|
|
||||||
, m_prefix{VString::removeWhitespace(label) + "-"} {}
|
|
||||||
|
|
||||||
~V3DfgContext() {
|
~V3DfgContext() {
|
||||||
const string front = "Optimizations, DFG " + label() + " General, ";
|
|
||||||
V3Stats::addStat(front + "modules", m_modules);
|
|
||||||
|
|
||||||
// Print the collected patterns
|
// Print the collected patterns
|
||||||
if (v3Global.opt.stats()) {
|
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
|
// File to dump to
|
||||||
const std::string filename = v3Global.opt.hierTopDataDir() + "/"
|
const std::string filename = v3Global.opt.hierTopDataDir() + "/"
|
||||||
+ v3Global.opt.prefix() + "__stats_dfg_patterns__" + ident
|
+ v3Global.opt.prefix() + "__stats_dfg_patterns.txt";
|
||||||
+ ".txt";
|
|
||||||
// Open, write, close
|
// Open, write, close
|
||||||
const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)};
|
const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)};
|
||||||
if (ofp->fail()) v3fatal("Can't write file: " << 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_
|
#endif //VERILATOR_V3DFGCONTEXT_H_
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,7 @@
|
||||||
|
|
||||||
#include "V3Dfg.h"
|
#include "V3Dfg.h"
|
||||||
#include "V3DfgPasses.h"
|
#include "V3DfgPasses.h"
|
||||||
#include "V3File.h"
|
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -103,7 +101,7 @@ class SplitIntoComponents final {
|
||||||
// Allocate the component graphs
|
// Allocate the component graphs
|
||||||
m_components.resize(m_componentCounter - 1);
|
m_components.resize(m_componentCounter - 1);
|
||||||
for (size_t i = 1; i < m_componentCounter; ++i) {
|
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
|
// Move the vertices to the component graphs
|
||||||
moveVertices(m_dfg.varVertices());
|
moveVertices(m_dfg.varVertices());
|
||||||
|
|
@ -222,17 +220,9 @@ class ExtractCyclicComponents final {
|
||||||
DfgVertexVar*& clonep = m_clones[&vtx][component];
|
DfgVertexVar*& clonep = m_clones[&vtx][component];
|
||||||
if (!clonep) {
|
if (!clonep) {
|
||||||
if (DfgVarPacked* const pVtxp = vtx.cast<DfgVarPacked>()) {
|
if (DfgVarPacked* const pVtxp = vtx.cast<DfgVarPacked>()) {
|
||||||
if (AstVarScope* const vscp = pVtxp->varScopep()) {
|
clonep = new DfgVarPacked{m_dfg, pVtxp->vscp()};
|
||||||
clonep = new DfgVarPacked{m_dfg, vscp};
|
|
||||||
} else {
|
|
||||||
clonep = new DfgVarPacked{m_dfg, pVtxp->varp()};
|
|
||||||
}
|
|
||||||
} else if (DfgVarArray* const aVtxp = vtx.cast<DfgVarArray>()) {
|
} else if (DfgVarArray* const aVtxp = vtx.cast<DfgVarArray>()) {
|
||||||
if (AstVarScope* const vscp = aVtxp->varScopep()) {
|
clonep = new DfgVarArray{m_dfg, aVtxp->vscp()};
|
||||||
clonep = new DfgVarArray{m_dfg, vscp};
|
|
||||||
} else {
|
|
||||||
clonep = new DfgVarArray{m_dfg, aVtxp->varp()};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
UASSERT_OBJ(clonep, &vtx, "Unhandled 'DfgVertexVar' sub-type");
|
UASSERT_OBJ(clonep, &vtx, "Unhandled 'DfgVertexVar' sub-type");
|
||||||
m_component[clonep] = component;
|
m_component[clonep] = component;
|
||||||
|
|
@ -326,7 +316,7 @@ class ExtractCyclicComponents final {
|
||||||
// Allocate result graphs
|
// Allocate result graphs
|
||||||
m_components.resize(nComponents);
|
m_components.resize(nComponents);
|
||||||
for (uint32_t i = 0; i < nComponents; ++i) {
|
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
|
// Fix up edges crossing components (we can only do this at variable boundaries, and the
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,6 @@
|
||||||
#include "V3DfgPasses.h"
|
#include "V3DfgPasses.h"
|
||||||
#include "V3UniqueNames.h"
|
#include "V3UniqueNames.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
@ -92,34 +90,19 @@ AstShiftRS* makeNode<AstShiftRS, DfgShiftRS, AstNodeExpr*, AstNodeExpr*>( //
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
template <bool T_Scoped>
|
|
||||||
class DfgToAstVisitor final : DfgVisitor {
|
class DfgToAstVisitor final : DfgVisitor {
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
|
|
||||||
// AstScope::user2p // The combinational AstActive under this scope
|
// AstScope::user2p // The combinational AstActive under this scope
|
||||||
const VNUser2InUse m_user2InUse;
|
const VNUser2InUse m_user2InUse;
|
||||||
|
|
||||||
// TYPES
|
|
||||||
using Variable = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
|
||||||
using Container = std::conditional_t<T_Scoped, AstActive, AstNodeModule>;
|
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
AstModule* const m_modp; // The parent/result module - This is nullptr when T_Scoped
|
|
||||||
V3DfgDfgToAstContext& m_ctx; // The context for stats
|
V3DfgDfgToAstContext& m_ctx; // The context for stats
|
||||||
AstNodeExpr* m_resultp = nullptr; // The result node of the current traversal
|
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
|
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
|
// 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) {
|
static AstActive* getCombActive(AstScope* scopep) {
|
||||||
if (!scopep->user2p()) {
|
if (!scopep->user2p()) {
|
||||||
// Try to find the existing combinational AstActive
|
// Try to find the existing combinational AstActive
|
||||||
|
|
@ -173,7 +156,7 @@ class DfgToAstVisitor final : DfgVisitor {
|
||||||
|
|
||||||
// Otherwise create an AssignW
|
// Otherwise create an AssignW
|
||||||
AstAssignW* const ap = new AstAssignW{flp, lhsp, rhsp};
|
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) {
|
void convertDriver(FileLine* flp, AstNodeExpr* lhsp, DfgVertex* driverp) {
|
||||||
|
|
@ -234,11 +217,11 @@ class DfgToAstVisitor final : DfgVisitor {
|
||||||
} // LCOV_EXCL_STOP
|
} // LCOV_EXCL_STOP
|
||||||
|
|
||||||
void visit(DfgVarPacked* vtxp) override {
|
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 {
|
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 { //
|
void visit(DfgConst* vtxp) override { //
|
||||||
|
|
@ -264,8 +247,7 @@ class DfgToAstVisitor final : DfgVisitor {
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
DfgToAstVisitor(DfgGraph& dfg, V3DfgDfgToAstContext& ctx)
|
DfgToAstVisitor(DfgGraph& dfg, V3DfgDfgToAstContext& ctx)
|
||||||
: m_modp{dfg.modulep()}
|
: m_ctx{ctx} {
|
||||||
, m_ctx{ctx} {
|
|
||||||
if (v3Global.opt.debugCheck()) V3DfgPasses::typeCheck(dfg);
|
if (v3Global.opt.debugCheck()) V3DfgPasses::typeCheck(dfg);
|
||||||
|
|
||||||
// Convert the graph back to combinational assignments. The graph must have been
|
// Convert the graph back to combinational assignments. The graph must have been
|
||||||
|
|
@ -283,24 +265,18 @@ class DfgToAstVisitor final : DfgVisitor {
|
||||||
|
|
||||||
// Render variable assignments
|
// Render variable assignments
|
||||||
FileLine* const flp = vtx.driverFileLine() ? vtx.driverFileLine() : vtx.fileline();
|
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);
|
// Add it to the scope holding the target variable
|
||||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
VL_RESTORER(m_activep);
|
||||||
// Add it to the scope holding the target variable
|
m_activep = getCombActive(vtx.vscp()->scopep());
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is a default value, render all drivers under an AstAlways
|
// If there is a default value, render all drivers under an AstAlways
|
||||||
VL_RESTORER(m_alwaysp);
|
VL_RESTORER(m_alwaysp);
|
||||||
if (DfgVertex* const defaultp = vtx.defaultp()) {
|
if (DfgVertex* const defaultp = vtx.defaultp()) {
|
||||||
++m_ctx.m_outputVariablesWithDefault;
|
++m_ctx.m_outputVariablesWithDefault;
|
||||||
m_alwaysp = new AstAlways{vtx.fileline(), VAlwaysKwd::ALWAYS_COMB, nullptr};
|
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
|
// The default assignment needs to go first
|
||||||
createAssignment(vtx.fileline(), lhsp->cloneTreePure(false), defaultp);
|
createAssignment(vtx.fileline(), lhsp->cloneTreePure(false), defaultp);
|
||||||
}
|
}
|
||||||
|
|
@ -326,8 +302,6 @@ class DfgToAstVisitor final : DfgVisitor {
|
||||||
if (VN_IS(exprp, VarRef)) {
|
if (VN_IS(exprp, VarRef)) {
|
||||||
++m_ctx.m_varRefsSubstituted;
|
++m_ctx.m_varRefsSubstituted;
|
||||||
} else {
|
} else {
|
||||||
UASSERT_OBJ(!dfg.modulep(), &vtx,
|
|
||||||
"Expressions should only be inlined on final scoped run");
|
|
||||||
++m_ctx.m_expressionsInlined;
|
++m_ctx.m_expressionsInlined;
|
||||||
}
|
}
|
||||||
rVtxp->exprp()->replaceWith(exprp);
|
rVtxp->exprp()->replaceWith(exprp);
|
||||||
|
|
@ -342,9 +316,5 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
void V3DfgPasses::dfgToAst(DfgGraph& dfg, V3DfgContext& ctx) {
|
void V3DfgPasses::dfgToAst(DfgGraph& dfg, V3DfgContext& ctx) {
|
||||||
if (dfg.modulep()) {
|
DfgToAstVisitor::apply(dfg, ctx.m_dfg2AstContext);
|
||||||
DfgToAstVisitor</* T_Scoped: */ false>::apply(dfg, ctx.m_dfg2AstContext);
|
|
||||||
} else {
|
|
||||||
DfgToAstVisitor</* T_Scoped: */ true>::apply(dfg, ctx.m_dfg2AstContext);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "V3Const.h"
|
#include "V3Const.h"
|
||||||
#include "V3Dfg.h"
|
#include "V3Dfg.h"
|
||||||
#include "V3DfgPasses.h"
|
#include "V3DfgPasses.h"
|
||||||
|
#include "V3Error.h"
|
||||||
#include "V3Graph.h"
|
#include "V3Graph.h"
|
||||||
#include "V3UniqueNames.h"
|
#include "V3UniqueNames.h"
|
||||||
|
|
||||||
|
|
@ -255,84 +256,39 @@ class DataflowOptimize final {
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
V3DfgContext m_ctx; // The context holding values that need to persist across multiple graphs
|
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) {
|
void endOfStage(const std::string& name, const DfgGraph* dfgp = nullptr) {
|
||||||
// Dump the graph for debugging if given one
|
// Dump the graph for debugging if given one
|
||||||
if (VL_UNLIKELY(dumpDfgLevel() >= 8 && dfgp)) {
|
if (VL_UNLIKELY(dumpDfgLevel() >= 8 && dfgp)) dfgp->dumpDotFilePrefixed(name);
|
||||||
dfgp->dumpDotFilePrefixed(m_ctx.prefix() + name);
|
|
||||||
}
|
|
||||||
// Dump stage stats only in scoped mode when running on the whole netlist
|
// Dump stage stats only in scoped mode when running on the whole netlist
|
||||||
if (VL_UNLIKELY(v3Global.opt.stats() && m_scoped)) {
|
if (VL_UNLIKELY(v3Global.opt.stats())) V3Stats::statsStage("dfg-optimize-" + name);
|
||||||
V3Stats::statsStage("dfg-optimize-" + name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark variables with external references
|
// Mark variables with external references
|
||||||
void markExternallyReferencedVariables(AstNetlist* netlistp) {
|
void markExternallyReferencedVariables(AstNetlist* netlistp) {
|
||||||
netlistp->foreach([this](AstNode* nodep) {
|
netlistp->foreach([](AstNode* nodep) {
|
||||||
// Check variable flags
|
// Check variable flags
|
||||||
if (m_scoped) {
|
if (AstVarScope* const vscp = VN_CAST(nodep, VarScope)) {
|
||||||
if (AstVarScope* const vscp = VN_CAST(nodep, VarScope)) {
|
const AstVar* const varp = vscp->varp();
|
||||||
const AstVar* const varp = vscp->varp();
|
// Force and trace have already been processed
|
||||||
// Force and trace have already been processed
|
const bool hasExtRd = varp->isPrimaryIO() || varp->isSigUserRdPublic();
|
||||||
const bool hasExtRd = varp->isPrimaryIO() || varp->isSigUserRdPublic();
|
const bool hasExtWr
|
||||||
const bool hasExtWr = varp->isPrimaryIO() || varp->isSigUserRWPublic();
|
= (varp->isPrimaryIO() && varp->isNonOutput()) || varp->isSigUserRWPublic();
|
||||||
if (hasExtRd) DfgVertexVar::setHasExtRdRefs(vscp);
|
if (hasExtRd) DfgVertexVar::setHasExtRdRefs(vscp);
|
||||||
if (hasExtWr) DfgVertexVar::setHasExtWrRefs(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);
|
|
||||||
return;
|
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
|
// Check cell ports
|
||||||
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
|
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
|
||||||
for (const AstPin *pinp = cellp->pinsp(), *nextp; pinp; pinp = nextp) {
|
// Why does this not hold?
|
||||||
nextp = VN_AS(pinp->nextp(), Pin);
|
UASSERT_OBJ(true || !cellp->pinsp(), cellp, "Pins should have been lowered");
|
||||||
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);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -415,9 +371,7 @@ class DataflowOptimize final {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DataflowOptimize(AstNetlist* netlistp, const string& label)
|
DataflowOptimize(AstNetlist* netlistp) {
|
||||||
: m_ctx{label}
|
|
||||||
, m_scoped{!!netlistp->topScopep()} {
|
|
||||||
|
|
||||||
// Mark interfaces that might be referenced by a virtual interface
|
// Mark interfaces that might be referenced by a virtual interface
|
||||||
if (v3Global.hasVirtIfaces()) {
|
if (v3Global.hasVirtIfaces()) {
|
||||||
|
|
@ -430,51 +384,29 @@ class DataflowOptimize final {
|
||||||
// Mark variables with external references
|
// Mark variables with external references
|
||||||
markExternallyReferencedVariables(netlistp);
|
markExternallyReferencedVariables(netlistp);
|
||||||
|
|
||||||
if (!m_scoped) {
|
// Post V3Scope application. Run on whole netlist.
|
||||||
// Pre V3Scope application. Run on each module separately.
|
UINFO(4, "Applying DFG optimization to entire netlist");
|
||||||
for (AstNode* nodep = netlistp->modulesp(); nodep; nodep = nodep->nextp()) {
|
// Build the DFG of the entire netlist
|
||||||
// Only optimize proper modules
|
const std::unique_ptr<DfgGraph> dfgp = V3DfgPasses::astToDfg(*netlistp, m_ctx);
|
||||||
AstModule* const modp = VN_CAST(nodep, Module);
|
endOfStage("ast-to-dfg", dfgp.get());
|
||||||
if (!modp) continue;
|
// Actually process the graph
|
||||||
// Pre V3Scope application. Run on module.
|
optimize(*dfgp);
|
||||||
UINFO(4, "Applying DFG optimization to module '" << modp->name() << "'");
|
// Convert back to Ast
|
||||||
++m_ctx.m_modules;
|
V3DfgPasses::dfgToAst(*dfgp, m_ctx);
|
||||||
// Build the DFG of this module or netlist
|
endOfStage("dfg-to-ast", dfgp.get());
|
||||||
const std::unique_ptr<DfgGraph> dfgp = V3DfgPasses::astToDfg(*modp, m_ctx);
|
// Some sentrees might have become constant, remove them
|
||||||
endOfStage("ast-to-dfg", dfgp.get());
|
removeNeverActives(netlistp);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset interned types so the corresponding Ast types can be garbage collected
|
// Reset interned types so the corresponding Ast types can be garbage collected
|
||||||
DfgDataType::reset();
|
DfgDataType::reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void apply(AstNetlist* netlistp, const string& label) {
|
static void apply(AstNetlist* netlistp) { DataflowOptimize{netlistp}; }
|
||||||
DataflowOptimize{netlistp, label};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
|
void V3DfgOptimizer::optimize(AstNetlist* netlistp) {
|
||||||
UINFO(2, __FUNCTION__ << ":");
|
UINFO(2, __FUNCTION__ << ":");
|
||||||
DataflowOptimize::apply(netlistp, label);
|
DataflowOptimize::apply(netlistp);
|
||||||
V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeEitherLevel() >= 3);
|
V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeEitherLevel() >= 3);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ namespace V3DfgOptimizer {
|
||||||
void extract(AstNetlist*) VL_MT_DISABLED;
|
void extract(AstNetlist*) VL_MT_DISABLED;
|
||||||
|
|
||||||
// Optimize the design
|
// Optimize the design
|
||||||
void optimize(AstNetlist*, const string& label) VL_MT_DISABLED;
|
void optimize(AstNetlist*) VL_MT_DISABLED;
|
||||||
} // namespace V3DfgOptimizer
|
} // namespace V3DfgOptimizer
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include "V3DfgPasses.h"
|
#include "V3DfgPasses.h"
|
||||||
|
|
||||||
|
#include "V3Ast.h"
|
||||||
#include "V3Dfg.h"
|
#include "V3Dfg.h"
|
||||||
#include "V3File.h"
|
#include "V3File.h"
|
||||||
#include "V3Global.h"
|
#include "V3Global.h"
|
||||||
|
|
@ -71,7 +72,7 @@ void V3DfgPasses::removeUnobservable(DfgGraph& dfg, V3DfgContext& dfgCtx) {
|
||||||
if (vVtxp->hasSinks()) continue;
|
if (vVtxp->hasSinks()) continue;
|
||||||
if (vVtxp->isObserved()) continue;
|
if (vVtxp->isObserved()) continue;
|
||||||
DfgVertex* const srcp = vVtxp->srcp(); // Must be a DfgUnresolved or nullptr
|
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
|
// Can delete the Ast variable too if it has no other references
|
||||||
const bool delAst = (!srcp || !srcp->nInputs()) //
|
const bool delAst = (!srcp || !srcp->nInputs()) //
|
||||||
&& !vVtxp->hasExtWrRefs() //
|
&& !vVtxp->hasExtWrRefs() //
|
||||||
|
|
@ -79,7 +80,7 @@ void V3DfgPasses::removeUnobservable(DfgGraph& dfg, V3DfgContext& dfgCtx) {
|
||||||
VL_DO_DANGLING(vVtxp->unlinkDelete(dfg), vVtxp);
|
VL_DO_DANGLING(vVtxp->unlinkDelete(dfg), vVtxp);
|
||||||
if (srcp) VL_DO_DANGLING(srcp->unlinkDelete(dfg), srcp);
|
if (srcp) VL_DO_DANGLING(srcp->unlinkDelete(dfg), srcp);
|
||||||
if (delAst) {
|
if (delAst) {
|
||||||
VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp);
|
VL_DO_DANGLING(vscp->unlinkFrBack()->deleteTree(), vscp);
|
||||||
++ctx.m_varsDeleted;
|
++ctx.m_varsDeleted;
|
||||||
} else {
|
} else {
|
||||||
++ctx.m_varsRemoved;
|
++ctx.m_varsRemoved;
|
||||||
|
|
@ -96,7 +97,7 @@ void V3DfgPasses::removeUnobservable(DfgGraph& dfg, V3DfgContext& dfgCtx) {
|
||||||
// AstVar/AstVarScope::user2p() -> corresponding DfgVertexVar* in the graph
|
// AstVar/AstVarScope::user2p() -> corresponding DfgVertexVar* in the graph
|
||||||
const VNUser2InUse m_user2InUse;
|
const VNUser2InUse m_user2InUse;
|
||||||
logicp->foreachSource([](DfgVertex& src) {
|
logicp->foreachSource([](DfgVertex& src) {
|
||||||
src.as<DfgVertexVar>()->nodep()->user2p(&src);
|
src.as<DfgVertexVar>()->vscp()->user2p(&src);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
V3DfgPasses::addAstRefs(dfg, logicp->nodep(), [](AstNode* varp) { //
|
V3DfgPasses::addAstRefs(dfg, logicp->nodep(), [](AstNode* varp) { //
|
||||||
|
|
@ -181,8 +182,6 @@ void V3DfgPasses::removeUnused(DfgGraph& dfg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
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
|
// Structure to keep track of comparison details
|
||||||
struct Term final {
|
struct Term final {
|
||||||
DfgVertex* m_vtxp = nullptr; // Vertex to replace
|
DfgVertex* m_vtxp = nullptr; // Vertex to replace
|
||||||
|
|
@ -291,6 +290,8 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
||||||
// Sequence numbers for name generation
|
// Sequence numbers for name generation
|
||||||
size_t nTables = 0;
|
size_t nTables = 0;
|
||||||
|
|
||||||
|
DfgVertex::ScopeCache scopeCache;
|
||||||
|
|
||||||
// Create decoders for each srcp
|
// Create decoders for each srcp
|
||||||
for (DfgVertex* const srcp : srcps) {
|
for (DfgVertex* const srcp : srcps) {
|
||||||
const Val2Terms& val2Terms = vtx2Val2Terms[srcp];
|
const Val2Terms& val2Terms = vtx2Val2Terms[srcp];
|
||||||
|
|
@ -318,6 +319,38 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
||||||
// - and replace the comparisons with 'tab[const]'
|
// - and replace the comparisons with 'tab[const]'
|
||||||
|
|
||||||
FileLine* const flp = srcp->fileline();
|
FileLine* const flp = srcp->fileline();
|
||||||
|
AstScope* const scopep = srcp->scopep(scopeCache, true);
|
||||||
|
|
||||||
|
AstActive* const staticActivep = [scopep]() {
|
||||||
|
// Try to find the existing static 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
|
// Required data types
|
||||||
const DfgDataType& idxDType = srcp->dtype();
|
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>();
|
if (DfgVertexVar* const vp = srcp->getResultVar()) return vp->as<DfgVarPacked>();
|
||||||
// Otherwise create a new variable
|
// Otherwise create a new variable
|
||||||
const std::string name = dfg.makeUniqueName("BinToOneHot_Idx", nTables);
|
const std::string name = dfg.makeUniqueName("BinToOneHot_Idx", nTables);
|
||||||
DfgVertexVar* const vtxp = dfg.makeNewVar(flp, name, idxDType, nullptr);
|
DfgVertexVar* const vtxp = dfg.makeNewVar(flp, name, idxDType, scopep);
|
||||||
vtxp->varp()->isInternal(true);
|
vtxp->vscp()->varp()->isInternal(true);
|
||||||
vtxp->srcp(srcp);
|
vtxp->srcp(srcp);
|
||||||
return vtxp->as<DfgVarPacked>();
|
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
|
// 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);
|
const std::string name = dfg.makeUniqueName("BinToOneHot_Pre", nTables);
|
||||||
AstVar* const varp = new AstVar{flp, VVarType::MODULETEMP, name, idxDType.astDtypep()};
|
DfgVertexVar* const vtxp = dfg.makeNewVar(flp, name, idxDType, scopep);
|
||||||
dfg.modulep()->addStmtsp(varp);
|
AstVarScope* const vscp = vtxp->vscp();
|
||||||
varp->isInternal(true);
|
VL_DO_DANGLING(vtxp->unlinkDelete(dfg), vtxp);
|
||||||
varp->noReset(true);
|
vscp->varp()->isInternal(true);
|
||||||
varp->setIgnoreSchedWrite();
|
vscp->varp()->noReset(true);
|
||||||
return varp;
|
vscp->varp()->setIgnoreSchedWrite();
|
||||||
|
return vscp;
|
||||||
}();
|
}();
|
||||||
// The table variable
|
// The table variable
|
||||||
DfgVarArray* const tabVtxp = [&]() {
|
DfgVarArray* const tabVtxp = [&]() {
|
||||||
const std::string name = dfg.makeUniqueName("BinToOneHot_Tab", nTables);
|
const std::string name = dfg.makeUniqueName("BinToOneHot_Tab", nTables);
|
||||||
DfgVarArray* const varp
|
DfgVertexVar* const varp = dfg.makeNewVar(flp, name, tabDType, scopep);
|
||||||
= dfg.makeNewVar(flp, name, tabDType, nullptr)->as<DfgVarArray>();
|
varp->vscp()->varp()->isInternal(true);
|
||||||
varp->varp()->isInternal(true);
|
varp->vscp()->varp()->noReset(true);
|
||||||
varp->varp()->noReset(true);
|
|
||||||
varp->setHasModWrRefs();
|
varp->setHasModWrRefs();
|
||||||
return varp;
|
return varp->as<DfgVarArray>();
|
||||||
}();
|
}();
|
||||||
|
|
||||||
++nTables;
|
++nTables;
|
||||||
|
|
@ -362,16 +395,16 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
||||||
|
|
||||||
// Initialize 'tab' and 'pre' variables statically
|
// Initialize 'tab' and 'pre' variables statically
|
||||||
AstInitialStatic* const initp = new AstInitialStatic{flp, nullptr};
|
AstInitialStatic* const initp = new AstInitialStatic{flp, nullptr};
|
||||||
dfg.modulep()->addStmtsp(initp);
|
staticActivep->addStmtsp(initp);
|
||||||
{ // pre = 0
|
{ // pre = 0
|
||||||
initp->addStmtsp(new AstAssign{
|
initp->addStmtsp(new AstAssign{
|
||||||
flp, //
|
flp, //
|
||||||
new AstVarRef{flp, preVarp, VAccess::WRITE}, //
|
new AstVarRef{flp, preVscp, VAccess::WRITE}, //
|
||||||
new AstConst{flp, AstConst::WidthedValue{}, static_cast<int>(width), 0}});
|
new AstConst{flp, AstConst::WidthedValue{}, static_cast<int>(width), 0}});
|
||||||
}
|
}
|
||||||
{ // tab.fill(0)
|
{ // tab.fill(0)
|
||||||
AstCMethodHard* const callp = new AstCMethodHard{
|
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->addPinsp(new AstConst{flp, AstConst::BitFalse{}});
|
||||||
callp->dtypeSetVoid();
|
callp->dtypeSetVoid();
|
||||||
initp->addStmtsp(callp->makeStmt());
|
initp->addStmtsp(callp->makeStmt());
|
||||||
|
|
@ -379,28 +412,28 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
||||||
|
|
||||||
// Build the decoder logic
|
// Build the decoder logic
|
||||||
AstAlways* const logicp = new AstAlways{flp, VAlwaysKwd::ALWAYS_COMB, nullptr, nullptr};
|
AstAlways* const logicp = new AstAlways{flp, VAlwaysKwd::ALWAYS_COMB, nullptr, nullptr};
|
||||||
dfg.modulep()->addStmtsp(logicp);
|
combActivep->addStmtsp(logicp);
|
||||||
{ // tab[pre] = 0;
|
{ // tab[pre] = 0;
|
||||||
logicp->addStmtsp(new AstAssign{
|
logicp->addStmtsp(new AstAssign{
|
||||||
flp, //
|
flp, //
|
||||||
new AstArraySel{flp, new AstVarRef{flp, tabVtxp->varp(), VAccess::WRITE},
|
new AstArraySel{flp, new AstVarRef{flp, tabVtxp->vscp(), VAccess::WRITE},
|
||||||
new AstVarRef{flp, preVarp, VAccess::READ}}, //
|
new AstVarRef{flp, preVscp, VAccess::READ}}, //
|
||||||
new AstConst{flp, AstConst::BitFalse{}}});
|
new AstConst{flp, AstConst::BitFalse{}}});
|
||||||
}
|
}
|
||||||
{ // tab[idx] = 1
|
{ // 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{
|
logicp->addStmtsp(new AstAssign{
|
||||||
flp, //
|
flp, //
|
||||||
new AstArraySel{flp, new AstVarRef{flp, tabVtxp->varp(), VAccess::WRITE},
|
new AstArraySel{flp, new AstVarRef{flp, tabVtxp->vscp(), VAccess::WRITE},
|
||||||
idxRefp}, //
|
idxRefp}, //
|
||||||
new AstConst{flp, AstConst::BitTrue{}}});
|
new AstConst{flp, AstConst::BitTrue{}}});
|
||||||
DfgAstRd* const astRdp = new DfgAstRd{dfg, idxRefp, false, false};
|
DfgAstRd* const astRdp = new DfgAstRd{dfg, idxRefp, false, false};
|
||||||
astRdp->srcp(idxVtxp);
|
astRdp->srcp(idxVtxp);
|
||||||
}
|
}
|
||||||
{ // pre = idx
|
{ // 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, //
|
logicp->addStmtsp(new AstAssign{flp, //
|
||||||
new AstVarRef{flp, preVarp, VAccess::WRITE}, //
|
new AstVarRef{flp, preVscp, VAccess::WRITE}, //
|
||||||
idxRefp});
|
idxRefp});
|
||||||
DfgAstRd* const astRdp = new DfgAstRd{dfg, idxRefp, false, false};
|
DfgAstRd* const astRdp = new DfgAstRd{dfg, idxRefp, false, false};
|
||||||
astRdp->srcp(idxVtxp);
|
astRdp->srcp(idxVtxp);
|
||||||
|
|
@ -442,7 +475,7 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgContext& ctx) {
|
||||||
// Apply the pass
|
// Apply the pass
|
||||||
pass();
|
pass();
|
||||||
// Debug dump
|
// Debug dump
|
||||||
if (dump) dfg.dumpDotFilePrefixed(ctx.prefix() + "opt-" + VString::removeWhitespace(name));
|
if (dump) dfg.dumpDotFilePrefixed("opt-" + VString::removeWhitespace(name));
|
||||||
// Internal type check
|
// Internal type check
|
||||||
if (v3Global.opt.debugCheck()) V3DfgPasses::typeCheck(dfg);
|
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("cse0 ", dumpLvl >= 4, [&]() { cse(dfg, ctx.m_cseContext0); });
|
||||||
run("binToOneHot ", dumpLvl >= 4, [&]() { binToOneHot(dfg, ctx.m_binToOneHotContext); });
|
run("binToOneHot ", dumpLvl >= 4, [&]() { binToOneHot(dfg, ctx.m_binToOneHotContext); });
|
||||||
run("peephole ", dumpLvl >= 4, [&]() { peephole(dfg, ctx.m_peepholeContext); });
|
run("peephole ", dumpLvl >= 4, [&]() { peephole(dfg, ctx.m_peepholeContext); });
|
||||||
// Run only on final scoped DfgGraphs, as otherwise later DfgPeephole wold just undo this work
|
run("pushDownSels", dumpLvl >= 4, [&]() { pushDownSels(dfg, ctx.m_pushDownSelsContext); });
|
||||||
if (!dfg.modulep()) {
|
|
||||||
run("pushDownSels", dumpLvl >= 4, [&]() { pushDownSels(dfg, ctx.m_pushDownSelsContext); });
|
|
||||||
}
|
|
||||||
run("cse1 ", dumpLvl >= 4, [&]() { cse(dfg, ctx.m_cseContext1); });
|
run("cse1 ", dumpLvl >= 4, [&]() { cse(dfg, ctx.m_cseContext1); });
|
||||||
run("output ", dumpLvl >= 3, [&]() { /* debug dump only */ });
|
run("output ", dumpLvl >= 3, [&]() { /* debug dump only */ });
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,19 +30,16 @@ namespace V3DfgPasses {
|
||||||
// Top level entry points
|
// Top level entry points
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
// Construct a DfGGraph representing the combinational logic in the given AstModule. The logic
|
// Construct a DfGGraph representing the combinational logic in the netlist.
|
||||||
// that is represented by the graph is removed from the given AstModule. Returns the
|
// The logic that is represented by the graph is removed from the netlist.
|
||||||
// constructed DfgGraph.
|
// Returns the constructed DfgGraph.
|
||||||
std::unique_ptr<DfgGraph> astToDfg(AstModule&, V3DfgContext&) VL_MT_DISABLED;
|
|
||||||
|
|
||||||
// Same as above, but for the entire netlist, after V3Scope
|
|
||||||
std::unique_ptr<DfgGraph> astToDfg(AstNetlist&, V3DfgContext&) VL_MT_DISABLED;
|
std::unique_ptr<DfgGraph> astToDfg(AstNetlist&, V3DfgContext&) VL_MT_DISABLED;
|
||||||
|
|
||||||
// Add DfgVertexAst to the given DfgGraph for all references in the given AstNode.
|
// 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.
|
// If it returns nullptr, the reference will be ignored.
|
||||||
void addAstRefs(DfgGraph& dfg, AstNode* nodep,
|
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
|
// Remove unobservable variabels and logic that drives only such variables
|
||||||
void removeUnobservable(DfgGraph&, V3DfgContext&) VL_MT_DISABLED;
|
void removeUnobservable(DfgGraph&, V3DfgContext&) VL_MT_DISABLED;
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class V3DfgPatternStats final {
|
||||||
static constexpr uint32_t MAX_PATTERN_DEPTH = 4;
|
static constexpr uint32_t MAX_PATTERN_DEPTH = 4;
|
||||||
|
|
||||||
std::map<std::string, std::string> m_internedConsts; // Interned constants
|
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_internedSelLsbs; // Interned lsb value for selects
|
||||||
std::map<uint32_t, std::string> m_internedWordWidths; // Interned widths
|
std::map<uint32_t, std::string> m_internedWordWidths; // Interned widths
|
||||||
std::map<uint32_t, std::string> m_internedWideWidths; // 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 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);
|
if (pair.second) pair.first->second += toLetters(m_internedVars.size() - 1);
|
||||||
return pair.first->second;
|
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>;
|
using Line = std::pair<std::string, size_t>;
|
||||||
for (uint32_t i = MIN_PATTERN_DEPTH; i <= MAX_PATTERN_DEPTH; ++i) {
|
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
|
// Pick up pattern accumulators with given depth
|
||||||
const auto& patternCounts = m_patterCounts[i];
|
const auto& patternCounts = m_patterCounts[i];
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,11 @@
|
||||||
|
|
||||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||||
|
|
||||||
|
#include "V3Ast.h"
|
||||||
#include "V3Dfg.h"
|
#include "V3Dfg.h"
|
||||||
#include "V3DfgCache.h"
|
#include "V3DfgCache.h"
|
||||||
#include "V3DfgPasses.h"
|
#include "V3DfgPasses.h"
|
||||||
#include "V3DfgPeepholePatterns.h"
|
#include "V3DfgPeepholePatterns.h"
|
||||||
#include "V3Stats.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
|
@ -50,36 +50,6 @@
|
||||||
|
|
||||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
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
|
// clang-format off
|
||||||
template <typename T_Reduction>
|
template <typename T_Reduction>
|
||||||
struct ReductionToBitwiseImpl {};
|
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.
|
// to the variable and no references in other graph then delete the Ast var too.
|
||||||
const DfgVertexVar* const varp = vtxp->cast<DfgVertexVar>();
|
const DfgVertexVar* const varp = vtxp->cast<DfgVertexVar>();
|
||||||
if (varp && !varp->isVolatile() && !varp->hasDfgRefs()) {
|
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);
|
VL_DO_DANGLING(vtxp->unlinkDelete(m_dfg), vtxp);
|
||||||
m_ctx.m_deleteps.push_back(nodep);
|
|
||||||
} else {
|
} else {
|
||||||
VL_DO_DANGLING(vtxp->unlinkDelete(m_dfg), vtxp);
|
VL_DO_DANGLING(vtxp->unlinkDelete(m_dfg), vtxp);
|
||||||
}
|
}
|
||||||
|
|
@ -1617,8 +1586,8 @@ class V3DfgPeephole final : public DfgVisitor {
|
||||||
if (!idxp) return;
|
if (!idxp) return;
|
||||||
DfgVarArray* const varp = vtxp->fromp()->cast<DfgVarArray>();
|
DfgVarArray* const varp = vtxp->fromp()->cast<DfgVarArray>();
|
||||||
if (!varp) return;
|
if (!varp) return;
|
||||||
if (varp->varp()->isForced()) return;
|
if (varp->vscp()->varp()->isForced()) return;
|
||||||
if (varp->varp()->isSigUserRWPublic()) return;
|
if (varp->vscp()->varp()->isSigUserRWPublic()) return;
|
||||||
DfgVertex* const srcp = varp->srcp();
|
DfgVertex* const srcp = varp->srcp();
|
||||||
if (!srcp) return;
|
if (!srcp) return;
|
||||||
|
|
||||||
|
|
@ -1862,16 +1831,13 @@ class V3DfgPeephole final : public DfgVisitor {
|
||||||
DfgSplicePacked* const sp = new DfgSplicePacked{m_dfg, flp, vtxp->dtype()};
|
DfgSplicePacked* const sp = new DfgSplicePacked{m_dfg, flp, vtxp->dtype()};
|
||||||
m_vInfo[sp].m_id = ++m_lastId;
|
m_vInfo[sp].m_id = ++m_lastId;
|
||||||
sp->addDriver(catp, lsb, flp);
|
sp->addDriver(catp, lsb, flp);
|
||||||
AstScope* const scopep = [&]() -> AstScope* {
|
DfgVertex::ScopeCache scopeCache;
|
||||||
if (m_dfg.modulep()) return nullptr;
|
AstScope* const scopep = vtxp->scopep(scopeCache, true);
|
||||||
DfgVertex::ScopeCache scopeCache;
|
|
||||||
return vtxp->scopep(scopeCache, true);
|
|
||||||
}();
|
|
||||||
const std::string name = m_dfg.makeUniqueName("PeepholeNarrow", m_nTemps++);
|
const std::string name = m_dfg.makeUniqueName("PeepholeNarrow", m_nTemps++);
|
||||||
DfgVertexVar* const varp = m_dfg.makeNewVar(flp, name, vtxp->dtype(), scopep);
|
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;
|
m_vInfo[varp].m_id = ++m_lastId;
|
||||||
varp->varp()->isInternal(true);
|
varp->vscp()->varp()->isInternal(true);
|
||||||
varp->srcp(sp);
|
varp->srcp(sp);
|
||||||
replace(varp);
|
replace(varp);
|
||||||
return;
|
return;
|
||||||
|
|
@ -2591,8 +2557,6 @@ class V3DfgPeephole final : public DfgVisitor {
|
||||||
if (const DfgVertexVar* const varp = sink.cast<DfgVertexVar>()) {
|
if (const DfgVertexVar* const varp = sink.cast<DfgVertexVar>()) {
|
||||||
if (!varp->hasSinks() && !varp->isObserved()) return false;
|
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
|
// Keep if found more than one sink
|
||||||
if (foundOne) return true;
|
if (foundOne) return true;
|
||||||
// Mark first sink found
|
// Mark first sink found
|
||||||
|
|
|
||||||
|
|
@ -54,26 +54,6 @@ class DfgRegularize final {
|
||||||
vtx.replaceWith(varp);
|
vtx.replaceWith(varp);
|
||||||
varp->srcp(&vtx);
|
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() {
|
std::unordered_set<const DfgVertexVar*> gatherCyclicVariables() {
|
||||||
|
|
@ -108,9 +88,6 @@ class DfgRegularize final {
|
||||||
UASSERT_OBJ(!aVtx.is<DfgVertexVar>(), &aVtx, "Should be an operation vertex");
|
UASSERT_OBJ(!aVtx.is<DfgVertexVar>(), &aVtx, "Should be an operation vertex");
|
||||||
|
|
||||||
if (bVtx.hasMultipleSinks()) {
|
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
|
// Add a temporary if it's cheaper to store and load from memory than recompute
|
||||||
if (!aVtx.isCheaperThanLoad()) return true;
|
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
|
// No need to add a temporary if the single sink is a variable already
|
||||||
if (sink.is<DfgVertexVar>()) return false;
|
if (sink.is<DfgVertexVar>()) return false;
|
||||||
|
|
||||||
// Do not inline expressions prior to the final scoped run, or if they are in a loop
|
// Do not inline expressions into a loop body
|
||||||
if (const DfgAstRd* const astRdp = sink.cast<DfgAstRd>()) {
|
if (const DfgAstRd* const astRdp = sink.cast<DfgAstRd>()) { return astRdp->inLoop(); }
|
||||||
return m_dfg.modulep() || astRdp->inLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure roots of wide concatenation trees are written to variables,
|
// Make sure roots of wide concatenation trees are written to variables,
|
||||||
// this enables V3FuncOpt to split them which can be a big speed gain
|
// 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
|
// Delete corresponsing Ast variable at the end
|
||||||
if (const DfgVertexVar* const varp = vtx.cast<DfgVertexVar>()) {
|
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
|
// Remove the unused vertex
|
||||||
vtx.unlinkDelete(m_dfg);
|
vtx.unlinkDelete(m_dfg);
|
||||||
|
|
@ -218,7 +193,6 @@ class DfgRegularize final {
|
||||||
// Insert a temporary variable for all vertices that have multiple non-variable sinks
|
// Insert a temporary variable for all vertices that have multiple non-variable sinks
|
||||||
|
|
||||||
// Scope cache for below
|
// Scope cache for below
|
||||||
const bool scoped = !m_dfg.modulep();
|
|
||||||
DfgVertex::ScopeCache scopeCache;
|
DfgVertex::ScopeCache scopeCache;
|
||||||
|
|
||||||
// Ensure intermediate values used multiple times are written to variables
|
// Ensure intermediate values used multiple times are written to variables
|
||||||
|
|
@ -233,7 +207,7 @@ class DfgRegularize final {
|
||||||
++m_ctx.m_temporariesIntroduced;
|
++m_ctx.m_temporariesIntroduced;
|
||||||
const std::string name = m_dfg.makeUniqueName("Regularize", m_nTmps);
|
const std::string name = m_dfg.makeUniqueName("Regularize", m_nTmps);
|
||||||
FileLine* const flp = vtx.fileline();
|
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);
|
DfgVertexVar* const newp = m_dfg.makeNewVar(flp, name, vtx.dtype(), scopep);
|
||||||
++m_nTmps;
|
++m_nTmps;
|
||||||
// Replace vertex with the variable, make it drive the variable
|
// Replace vertex with the variable, make it drive the variable
|
||||||
|
|
@ -248,13 +222,13 @@ class DfgRegularize final {
|
||||||
, m_ctx{ctx} {
|
, m_ctx{ctx} {
|
||||||
|
|
||||||
uninlineVariables();
|
uninlineVariables();
|
||||||
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed(ctx.prefix() + "regularize-uninlined");
|
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed("regularize-uninlined");
|
||||||
|
|
||||||
eliminateVars();
|
eliminateVars();
|
||||||
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed(ctx.prefix() + "regularize-eliminate");
|
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed("regularize-eliminate");
|
||||||
|
|
||||||
insertTemporaries();
|
insertTemporaries();
|
||||||
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed(ctx.prefix() + "regularize-inserttmp");
|
if (dumpDfgLevel() >= 9) dfg.dumpDotFilePrefixed("regularize-inserttmp");
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,12 @@
|
||||||
|
|
||||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||||
|
|
||||||
|
#include "V3Ast.h"
|
||||||
#include "V3Cfg.h"
|
#include "V3Cfg.h"
|
||||||
#include "V3Const.h"
|
#include "V3Const.h"
|
||||||
#include "V3Dfg.h"
|
#include "V3Dfg.h"
|
||||||
#include "V3DfgPasses.h"
|
#include "V3DfgPasses.h"
|
||||||
#include "V3EmitV.h"
|
#include "V3EmitV.h"
|
||||||
#include "V3Os.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
@ -55,16 +55,12 @@ DfgArraySel* makeVertex<DfgArraySel, AstArraySel>(const AstArraySel* nodep, DfgG
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Visitor that can convert Ast statements and expressions in Dfg vertices
|
// Visitor that can convert Ast statements and expressions in Dfg vertices
|
||||||
template <bool T_Scoped>
|
|
||||||
class AstToDfgConverter final : public VNVisitor {
|
class AstToDfgConverter final : public VNVisitor {
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// AstNodeExpr/AstVar/AstVarScope::user2p -> DfgVertex* for this Node
|
// AstNodeExpr/AstVar/AstVarScope::user2p -> DfgVertex* for this Node
|
||||||
// AstVar::user3() -> int temporary counter for variable
|
// AstVar::user3() -> int temporary counter for variable
|
||||||
const VNUser3InUse m_user3InUse;
|
const VNUser3InUse m_user3InUse;
|
||||||
|
|
||||||
// TYPES
|
|
||||||
using Variable = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
DfgGraph& m_dfg; // The graph being built
|
DfgGraph& m_dfg; // The graph being built
|
||||||
V3DfgSynthesisContext& m_ctx; // The context for stats
|
V3DfgSynthesisContext& m_ctx; // The context for stats
|
||||||
|
|
@ -73,7 +69,7 @@ class AstToDfgConverter final : public VNVisitor {
|
||||||
DfgLogic* m_logicp = nullptr;
|
DfgLogic* m_logicp = nullptr;
|
||||||
// Variable updates produced by currently converted statement. This almost
|
// Variable updates produced by currently converted statement. This almost
|
||||||
// always have a single element, so a vector is ok
|
// 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_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
|
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
|
size_t m_nUnpack = 0; // Sequence numbers for temporaries
|
||||||
|
|
||||||
// METHODS
|
// 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
|
// Allocate a new non-variable vertex, add it to the currently synthesized logic
|
||||||
template <typename Vertex, typename... Args>
|
template <typename Vertex, typename... Args>
|
||||||
|
|
@ -117,7 +105,7 @@ class AstToDfgConverter final : public VNVisitor {
|
||||||
// Cannot represent cross module references
|
// Cannot represent cross module references
|
||||||
if (nodep->classOrPackagep()) return false;
|
if (nodep->classOrPackagep()) return false;
|
||||||
// Check target
|
// 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.
|
// 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
|
// Get (or create a new) temporary for this variable
|
||||||
const DfgVertexVar* const vtxp = [&]() -> DfgVertexVar* {
|
const DfgVertexVar* const vtxp = [&]() -> DfgVertexVar* {
|
||||||
// The variable being assigned
|
// The variable being assigned
|
||||||
Variable* const tgtp = getTarget(vrefp);
|
AstVarScope* const vscp = vrefp->varScopep();
|
||||||
|
|
||||||
// Find existing one, if any
|
// Find existing one, if any
|
||||||
for (const auto& pair : *m_updatesp) {
|
for (const auto& pair : *m_updatesp) {
|
||||||
if (pair.first == tgtp) return pair.second;
|
if (pair.first == vscp) return pair.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new one
|
// Create new one
|
||||||
DfgVertexVar* const newp = createTmp(*m_logicp, tgtp, "SynthAssign");
|
DfgVertexVar* const newp = createTmp(*m_logicp, vscp, "SynthAssign");
|
||||||
m_updatesp->emplace_back(tgtp, newp);
|
m_updatesp->emplace_back(vscp, newp);
|
||||||
|
|
||||||
// Create the Splice driver for the new temporary
|
// Create the Splice driver for the new temporary
|
||||||
if (newp->is<DfgVarPacked>()) {
|
if (newp->is<DfgVarPacked>()) {
|
||||||
|
|
@ -375,7 +363,7 @@ class AstToDfgConverter final : public VNVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variable should have been bound before starting conversion
|
// 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");
|
UASSERT_OBJ(vtxp, nodep, "Referenced variable has no associated DfgVertexVar");
|
||||||
nodep->user2p(vtxp);
|
nodep->user2p(vtxp);
|
||||||
}
|
}
|
||||||
|
|
@ -450,27 +438,26 @@ public:
|
||||||
const std::string name = m_dfg.makeUniqueName(prefix, tmpCount);
|
const std::string name = m_dfg.makeUniqueName(prefix, tmpCount);
|
||||||
DfgVertexVar* const vtxp = m_dfg.makeNewVar(flp, name, dtype, logic.scopep());
|
DfgVertexVar* const vtxp = m_dfg.makeNewVar(flp, name, dtype, logic.scopep());
|
||||||
logic.synth().emplace_back(vtxp);
|
logic.synth().emplace_back(vtxp);
|
||||||
vtxp->varp()->isInternal(true);
|
vtxp->vscp()->varp()->isInternal(true);
|
||||||
vtxp->tmpForp(vtxp->nodep());
|
vtxp->tmpForp(vtxp->vscp());
|
||||||
return vtxp;
|
return vtxp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new temporary variable capable of holding 'varp'
|
// Create a new temporary variable capable of holding 'varp'
|
||||||
DfgVertexVar* createTmp(DfgLogic& logic, Variable* varp, const std::string& prefix) {
|
DfgVertexVar* createTmp(DfgLogic& logic, AstVarScope* vscp, const std::string& prefix) {
|
||||||
AstVar* const astVarp = T_Scoped ? reinterpret_cast<AstVarScope*>(varp)->varp()
|
AstVar* const astVarp = vscp->varp();
|
||||||
: reinterpret_cast<AstVar*>(varp);
|
|
||||||
FileLine* const flp = astVarp->fileline();
|
FileLine* const flp = astVarp->fileline();
|
||||||
const DfgDataType& dtype = *DfgDataType::fromAst(astVarp->dtypep());
|
const DfgDataType& dtype = *DfgDataType::fromAst(astVarp->dtypep());
|
||||||
const std::string prfx = prefix + "_" + astVarp->name();
|
const std::string prfx = prefix + "_" + astVarp->name();
|
||||||
const size_t tmpCount = astVarp->user3Inc();
|
const size_t tmpCount = astVarp->user3Inc();
|
||||||
DfgVertexVar* const vtxp = createTmp(logic, flp, dtype, prfx, tmpCount);
|
DfgVertexVar* const vtxp = createTmp(logic, flp, dtype, prfx, tmpCount);
|
||||||
vtxp->tmpForp(varp);
|
vtxp->tmpForp(vscp);
|
||||||
return vtxp;
|
return vtxp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert AstAssign to Dfg, return true if successful.
|
// Convert AstAssign to Dfg, return true if successful.
|
||||||
// Fills 'updates' with bindings for assigned variables.
|
// 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) {
|
AstNodeAssign* nodep) {
|
||||||
UASSERT_OBJ(VN_IS(nodep, Assign) || VN_IS(nodep, AssignW), nodep, "Bad NodeAssign");
|
UASSERT_OBJ(VN_IS(nodep, Assign) || VN_IS(nodep, AssignW), nodep, "Bad NodeAssign");
|
||||||
UASSERT_OBJ(updates.empty(), nodep, "'updates' should be empty");
|
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
|
// Debug aid - outisde 'AstToDfgSynthesize' as it is a template, but want one instance
|
||||||
V3DebugBisect s_dfgSynthDebugBisect{"DfgSynthesize"};
|
V3DebugBisect s_dfgSynthDebugBisect{"DfgSynthesize"};
|
||||||
|
|
||||||
template <bool T_Scoped>
|
|
||||||
class AstToDfgSynthesize final {
|
class AstToDfgSynthesize final {
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// AstNodeExpr/AstVar/AstVarScope::user2p -> DfgVertex* for this Node
|
// AstNodeExpr/AstVar/AstVarScope::user2p -> DfgVertex* for this Node
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
using Variable = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
|
||||||
|
|
||||||
// SymTab must be ordered in order to yield stable results
|
// SymTab must be ordered in order to yield stable results
|
||||||
struct VariableComparator final {
|
struct AstVarScopeComparator final {
|
||||||
bool operator()(const Variable* lhs, const Variable* rhs) const {
|
bool operator()(const AstVarScope* lhs, const AstVarScope* rhs) const {
|
||||||
return lhs->name() < rhs->name();
|
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
|
// Represents a [potentially partial] driver of a variable
|
||||||
struct Driver final {
|
struct Driver final {
|
||||||
|
|
@ -573,7 +558,7 @@ class AstToDfgSynthesize final {
|
||||||
// STATE - Persistent
|
// STATE - Persistent
|
||||||
DfgGraph& m_dfg; // The graph being built
|
DfgGraph& m_dfg; // The graph being built
|
||||||
V3DfgSynthesisContext& m_ctx; // The context for stats
|
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_nBranchCond = 0; // Sequence numbers for temporaries
|
||||||
size_t m_nPathPred = 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
|
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)) {
|
if (VL_UNLIKELY(dumpDfgLevel() >= 9 || m_debugOSrcConep)) {
|
||||||
const auto label = m_ctx.prefix() + name;
|
m_dfg.dumpDotFilePrefixed(name);
|
||||||
m_dfg.dumpDotFilePrefixed(label);
|
|
||||||
if (m_debugOSrcConep) {
|
if (m_debugOSrcConep) {
|
||||||
// Dump only the subgraph involving the inputs and outputs of the bad vertex
|
// 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);
|
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
|
// Allocate a new non-variable vertex, add it to the currently synthesized logic
|
||||||
template <typename Vertex, typename... Args>
|
template <typename Vertex, typename... Args>
|
||||||
Vertex* make(Args&&... args) {
|
Vertex* make(Args&&... args) {
|
||||||
|
|
@ -674,14 +649,7 @@ class AstToDfgSynthesize final {
|
||||||
if (std::find(visited.begin(), visited.end(), vtxp) != visited.end()) continue;
|
if (std::find(visited.begin(), visited.end(), vtxp) != visited.end()) continue;
|
||||||
visited.emplace_back(vtxp);
|
visited.emplace_back(vtxp);
|
||||||
if (const DfgVertexVar* const varp = vtxp->cast<DfgVertexVar>()) {
|
if (const DfgVertexVar* const varp = vtxp->cast<DfgVertexVar>()) {
|
||||||
AstVar* const astVarp = [&]() -> AstVar* {
|
if (varp->vscp()->varp()->dfgTriLowered()) return true;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
vtxp->foreachSource([&](const DfgVertex& src) {
|
vtxp->foreachSource([&](const DfgVertex& src) {
|
||||||
stack.emplace_back(&src);
|
stack.emplace_back(&src);
|
||||||
|
|
@ -849,15 +817,14 @@ class AstToDfgSynthesize final {
|
||||||
if (warned) continue;
|
if (warned) continue;
|
||||||
|
|
||||||
// The variable to warn on
|
// The variable to warn on
|
||||||
AstNode* const nodep = var.tmpForp() ? var.tmpForp() : var.nodep();
|
AstVarScope* const vscp = var.tmpForp() ? var.tmpForp() : var.vscp();
|
||||||
Variable* const varp = reinterpret_cast<Variable*>(nodep);
|
|
||||||
|
|
||||||
// Loop index often abused, so suppress
|
// Loop index often abused, so suppress
|
||||||
if (getAstVar(varp)->isUsedLoopIdx()) continue;
|
if (vscp->varp()->isUsedLoopIdx()) continue;
|
||||||
// Tristate lowering can intentionally create overlapping contributors.
|
// Tristate lowering can intentionally create overlapping contributors.
|
||||||
// Keep the signal marked multidriven for DFG fallback, but suppress
|
// Keep the signal marked multidriven for DFG fallback, but suppress
|
||||||
// warning only when both overlapping driver cones look tri-lowered.
|
// 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 iTri = containsTriLoweredVar(iD.m_vtxp);
|
||||||
const bool jTri = containsTriLoweredVar(jD.m_vtxp);
|
const bool jTri = containsTriLoweredVar(jD.m_vtxp);
|
||||||
const bool triPair = iTri && jTri;
|
const bool triPair = iTri && jTri;
|
||||||
|
|
@ -872,9 +839,9 @@ class AstToDfgSynthesize final {
|
||||||
const std::string kind = isPacked ? "Bit" : "Element";
|
const std::string kind = isPacked ? "Bit" : "Element";
|
||||||
const std::string part = hi == lo ? (" [" + lo + "]") : ("s [" + hi + ":" + lo + "]");
|
const std::string part = hi == lo ? (" [" + lo + "]") : ("s [" + hi + ":" + lo + "]");
|
||||||
|
|
||||||
varp->v3warn( //
|
vscp->v3warn( //
|
||||||
MULTIDRIVEN, //
|
MULTIDRIVEN, //
|
||||||
kind << part << " of signal '" << varp->prettyName() << sub << "'"
|
kind << part << " of signal '" << vscp->prettyName() << sub << "'"
|
||||||
<< " have multiple combinational drivers."
|
<< " have multiple combinational drivers."
|
||||||
<< " This can cause performance degradation.\n"
|
<< " This can cause performance degradation.\n"
|
||||||
<< iD.m_flp->warnOther() << "... Location of offending driver\n"
|
<< iD.m_flp->warnOther() << "... Location of offending driver\n"
|
||||||
|
|
@ -961,29 +928,28 @@ class AstToDfgSynthesize final {
|
||||||
void initializeEntrySymbolTable(SymTab& iSymTab) {
|
void initializeEntrySymbolTable(SymTab& iSymTab) {
|
||||||
m_logicp->foreachSource([&](DfgVertex& src) {
|
m_logicp->foreachSource([&](DfgVertex& src) {
|
||||||
DfgVertexVar* const vvp = src.as<DfgVertexVar>();
|
DfgVertexVar* const vvp = src.as<DfgVertexVar>();
|
||||||
Variable* const varp = reinterpret_cast<Variable*>(vvp->nodep());
|
iSymTab[vvp->vscp()] = vvp;
|
||||||
iSymTab[varp] = vvp;
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join variable drivers across a control flow confluence (insert muxes ...)
|
// 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) {
|
DfgVertexVar* thenp, DfgVertexVar* elsep) {
|
||||||
AstNode* const thenVarp = thenp->tmpForp() ? thenp->tmpForp() : thenp->nodep();
|
AstVarScope* const thenVscp = thenp->tmpForp() ? thenp->tmpForp() : thenp->vscp();
|
||||||
AstNode* const elseVarp = elsep->tmpForp() ? elsep->tmpForp() : elsep->nodep();
|
AstVarScope* const elseVscp = elsep->tmpForp() ? elsep->tmpForp() : elsep->vscp();
|
||||||
UASSERT_OBJ(thenVarp == elseVarp, varp, "Attempting to join unrelated variables");
|
UASSERT_OBJ(thenVscp == elseVscp, vscp, "Attempting to join unrelated variables");
|
||||||
|
|
||||||
// If both bindings are the the same (variable not updated through either path),
|
// If both bindings are the the same (variable not updated through either path),
|
||||||
// then there is nothing to do, can use the same binding
|
// then there is nothing to do, can use the same binding
|
||||||
if (thenp == elsep) return thenp;
|
if (thenp == elsep) return thenp;
|
||||||
|
|
||||||
// We can't join the input variable just yet, so bail
|
// We can't join the input variable just yet, so bail
|
||||||
if (thenp->nodep() == varp) {
|
if (thenp->vscp() == vscp) {
|
||||||
++m_ctx.m_synt.nonSynJoinInput;
|
++m_ctx.m_synt.nonSynJoinInput;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (elsep->nodep() == varp) {
|
if (elsep->vscp() == vscp) {
|
||||||
++m_ctx.m_synt.nonSynJoinInput;
|
++m_ctx.m_synt.nonSynJoinInput;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -1003,13 +969,13 @@ class AstToDfgSynthesize final {
|
||||||
std::vector<Driver> eDrivers = gatherDrivers(elsep->srcp()->as<DfgVertexSplice>());
|
std::vector<Driver> eDrivers = gatherDrivers(elsep->srcp()->as<DfgVertexSplice>());
|
||||||
|
|
||||||
// Default drivers should be the same or not present on either
|
// 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
|
// Location to use for the join vertices
|
||||||
FileLine* const flp = predicatep->fileline();
|
FileLine* const flp = predicatep->fileline();
|
||||||
|
|
||||||
// Create a fresh temporary for the joined value
|
// 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());
|
DfgVertexSplice* const joinSplicep = make<DfgSplicePacked>(flp, joinp->dtype());
|
||||||
joinp->srcp(joinSplicep);
|
joinp->srcp(joinSplicep);
|
||||||
|
|
||||||
|
|
@ -1020,7 +986,7 @@ class AstToDfgSynthesize final {
|
||||||
&& eDrivers.size() == 1 //
|
&& eDrivers.size() == 1 //
|
||||||
&& eDrivers[0].m_lo == 0 //
|
&& eDrivers[0].m_lo == 0 //
|
||||||
&& eDrivers[0].m_hi == elsep->width() - 1) {
|
&& 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());
|
DfgCond* const condp = make<DfgCond>(flp, joinp->dtype());
|
||||||
condp->condp(predicatep);
|
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
|
// 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
|
// temporaries, loop vars, etc used only in one branch. Conversion will fail if the
|
||||||
// variable is actually referenced later.
|
// variable is actually referenced later.
|
||||||
std::vector<Variable*> toRemove;
|
std::vector<AstVarScope*> toRemove;
|
||||||
|
|
||||||
// Join each symbol
|
// Join each symbol
|
||||||
for (std::pair<Variable* const, DfgVertexVar*>& pair : elseSymTab) {
|
for (std::pair<AstVarScope* const, DfgVertexVar*>& pair : elseSymTab) {
|
||||||
Variable* const varp = pair.first;
|
AstVarScope* const varp = pair.first;
|
||||||
// Find same variable on the else path
|
// Find same variable on the else path
|
||||||
const auto it = thenSymTab.find(varp);
|
const auto it = thenSymTab.find(varp);
|
||||||
// Record for removal if not assigned on both paths
|
// Record for removal if not assigned on both paths
|
||||||
|
|
@ -1102,7 +1068,7 @@ class AstToDfgSynthesize final {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove variables not assigned on both paths
|
// Remove variables not assigned on both paths
|
||||||
for (Variable* const varp : toRemove) elseSymTab.erase(varp);
|
for (AstVarScope* const varp : toRemove) elseSymTab.erase(varp);
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1285,8 +1251,8 @@ class AstToDfgSynthesize final {
|
||||||
// Given the drivers of a variable after converting a single statement
|
// Given the drivers of a variable after converting a single statement
|
||||||
// 'newp', add drivers from 'oldp' that were not reassigned be drivers
|
// 'newp', add drivers from 'oldp' that were not reassigned be drivers
|
||||||
// in newp. This computes the total result of all previous assignments.
|
// in newp. This computes the total result of all previous assignments.
|
||||||
bool incorporatePreviousValue(Variable* varp, DfgVertexVar* newp, DfgVertexVar* oldp) {
|
bool incorporatePreviousValue(AstVarScope* vscp, DfgVertexVar* newp, DfgVertexVar* oldp) {
|
||||||
UASSERT_OBJ(newp->srcp(), varp, "Assigned variable has no driver");
|
UASSERT_OBJ(newp->srcp(), vscp, "Assigned variable has no driver");
|
||||||
|
|
||||||
// Easy if there is no old value...
|
// Easy if there is no old value...
|
||||||
if (!oldp) return true;
|
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,
|
// 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.
|
// 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);
|
if (!nSplicep->wholep()) newp->defaultp(oldp);
|
||||||
return true;
|
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
|
// Can't do arrays yet
|
||||||
if (!newp->isPacked()) {
|
if (!newp->isPacked()) {
|
||||||
|
|
@ -1347,16 +1313,16 @@ class AstToDfgSynthesize final {
|
||||||
// Use fresh set of vertices in m_converter
|
// Use fresh set of vertices in m_converter
|
||||||
const VNUser2InUse user2InUse;
|
const VNUser2InUse user2InUse;
|
||||||
|
|
||||||
// Initialize Variable -> Vertex bindings available in this block
|
// Initialize AstVarScope -> Vertex bindings available in this block
|
||||||
for (const auto& pair : iSymTab) {
|
for (const auto& pair : iSymTab) {
|
||||||
Variable* const varp = pair.first;
|
AstVarScope* const varp = pair.first;
|
||||||
DfgVertexVar* const vtxp = pair.second;
|
DfgVertexVar* const vtxp = pair.second;
|
||||||
varp->user2p(vtxp);
|
varp->user2p(vtxp);
|
||||||
oSymTab[varp] = vtxp;
|
oSymTab[varp] = vtxp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synthesize each statement one after the other
|
// 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) {
|
for (AstNodeStmt* const stmtp : stmtps) {
|
||||||
// Regular statements
|
// Regular statements
|
||||||
AstNodeAssign* const ap = VN_CAST(stmtp, NodeAssign);
|
AstNodeAssign* const ap = VN_CAST(stmtp, NodeAssign);
|
||||||
|
|
@ -1369,7 +1335,7 @@ class AstToDfgSynthesize final {
|
||||||
// Apply variable updates from this statement
|
// Apply variable updates from this statement
|
||||||
for (const auto& pair : updates) {
|
for (const auto& pair : updates) {
|
||||||
// The target variable that was assigned to
|
// The target variable that was assigned to
|
||||||
Variable* const varp = pair.first;
|
AstVarScope* const vscp = pair.first;
|
||||||
// The new, potentially partially assigned value
|
// The new, potentially partially assigned value
|
||||||
DfgVertexVar* const newp = pair.second;
|
DfgVertexVar* const newp = pair.second;
|
||||||
// Normalize drivers within this statement, bail if multidriven
|
// Normalize drivers within this statement, bail if multidriven
|
||||||
|
|
@ -1377,7 +1343,6 @@ class AstToDfgSynthesize final {
|
||||||
std::vector<Driver> drivers = gatherDrivers(srcp);
|
std::vector<Driver> drivers = gatherDrivers(srcp);
|
||||||
const bool single = drivers.size() == 1;
|
const bool single = drivers.size() == 1;
|
||||||
if (!normalizeDrivers(*newp, drivers)) {
|
if (!normalizeDrivers(*newp, drivers)) {
|
||||||
getAstVar(varp)->setDfgMultidriven();
|
|
||||||
++m_ctx.m_synt.nonSynMultidrive;
|
++m_ctx.m_synt.nonSynMultidrive;
|
||||||
return false;
|
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);
|
for (const Driver& d : drivers) srcp->addDriver(d.m_vtxp, d.m_lo, d.m_flp);
|
||||||
}
|
}
|
||||||
// The old value, if any
|
// 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
|
// 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
|
// Update binding of target variable
|
||||||
varp->user2p(newp);
|
vscp->user2p(newp);
|
||||||
// Update output symbol table of this block
|
// Update output symbol table of this block
|
||||||
oSymTab[varp] = newp;
|
oSymTab[vscp] = newp;
|
||||||
}
|
}
|
||||||
updates.clear();
|
updates.clear();
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1518,10 +1483,8 @@ class AstToDfgSynthesize final {
|
||||||
// braces and check here too. We can't touch any output variables if so.
|
// braces and check here too. We can't touch any output variables if so.
|
||||||
const bool missing = m_logicp->foreachSink([&](const DfgVertex& sink) {
|
const bool missing = m_logicp->foreachSink([&](const DfgVertex& sink) {
|
||||||
const DfgUnresolved* const unresolvedp = sink.as<DfgUnresolved>();
|
const DfgUnresolved* const unresolvedp = sink.as<DfgUnresolved>();
|
||||||
AstNode* const tgtp = unresolvedp->singleSink()->as<DfgVertexVar>()->nodep();
|
AstVarScope* const vscp = unresolvedp->singleSink()->as<DfgVertexVar>()->vscp();
|
||||||
// cppcheck-suppress constVariablePointer
|
return !oSymTab.count(vscp);
|
||||||
Variable* const varp = reinterpret_cast<Variable*>(tgtp);
|
|
||||||
return !oSymTab.count(varp);
|
|
||||||
});
|
});
|
||||||
if (missing) {
|
if (missing) {
|
||||||
++m_ctx.m_synt.nonSynFalseWrite;
|
++m_ctx.m_synt.nonSynFalseWrite;
|
||||||
|
|
@ -1532,7 +1495,7 @@ class AstToDfgSynthesize final {
|
||||||
return !m_logicp->foreachSink([&](DfgVertex& sink) {
|
return !m_logicp->foreachSink([&](DfgVertex& sink) {
|
||||||
DfgUnresolved* const unresolvedp = sink.as<DfgUnresolved>();
|
DfgUnresolved* const unresolvedp = sink.as<DfgUnresolved>();
|
||||||
const DfgVertexVar* const varp = unresolvedp->singleSink()->as<DfgVertexVar>();
|
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");
|
UASSERT_OBJ(resp->srcp(), resp, "Undriven result");
|
||||||
|
|
||||||
// If the output is not used further in the synthesized logic itself,
|
// 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
|
// There should be no sinks left for unselected DfgLogic, delete them here
|
||||||
UASSERT_OBJ(!logicp->hasSinks(), vtxp, "Unselected 'DfgLogic' with sinks remaining");
|
UASSERT_OBJ(!logicp->hasSinks(), vtxp, "Unselected 'DfgLogic' with sinks remaining");
|
||||||
// Input variables will be read in Ast code, add Ast reference vertices
|
// 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;
|
const VNUser4InUse m_user4InUse;
|
||||||
logicp->foreachSource([](DfgVertex& src) {
|
logicp->foreachSource([](DfgVertex& src) {
|
||||||
src.as<DfgVertexVar>()->nodep()->user4p(&src);
|
src.as<DfgVertexVar>()->vscp()->user4p(&src);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
V3DfgPasses::addAstRefs(m_dfg, logicp->nodep(), [](AstNode* varp) { //
|
V3DfgPasses::addAstRefs(m_dfg, logicp->nodep(), [](AstNode* varp) { //
|
||||||
|
|
@ -1831,8 +1794,6 @@ class AstToDfgSynthesize final {
|
||||||
const bool newEntry = resolvedDrivers.emplace(&var, resolvedp).second;
|
const bool newEntry = resolvedDrivers.emplace(&var, resolvedp).second;
|
||||||
UASSERT_OBJ(newEntry, &var, "Dupliacte driver");
|
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 and remove drivers of multi-driven variables
|
||||||
revert(m_ctx.m_synt.revertMultidrive);
|
revert(m_ctx.m_synt.revertMultidrive);
|
||||||
// Replace all DfgUnresolved with the resolved drivers
|
// Replace all DfgUnresolved with the resolved drivers
|
||||||
|
|
@ -1866,10 +1827,10 @@ class AstToDfgSynthesize final {
|
||||||
} else {
|
} else {
|
||||||
// Not synthesized. Logic stays in Ast. Add Ast reference vertices.
|
// Not synthesized. Logic stays in Ast. Add Ast reference vertices.
|
||||||
// Outputs already marked by revertTransivelyAndRemove.
|
// Outputs already marked by revertTransivelyAndRemove.
|
||||||
// AstVar/AstVarScope::user4p() -> corresponding DfgVertexVar* in the graph
|
// AstVarScope::user4p() -> corresponding DfgVertexVar* in the graph
|
||||||
const VNUser4InUse m_user4InUse;
|
const VNUser4InUse m_user4InUse;
|
||||||
logicp->foreachSource([](DfgVertex& src) {
|
logicp->foreachSource([](DfgVertex& src) {
|
||||||
src.as<DfgVertexVar>()->nodep()->user4p(&src);
|
src.as<DfgVertexVar>()->vscp()->user4p(&src);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
V3DfgPasses::addAstRefs(m_dfg, logicp->nodep(), [](AstNode* varp) { //
|
V3DfgPasses::addAstRefs(m_dfg, logicp->nodep(), [](AstNode* varp) { //
|
||||||
|
|
@ -1926,7 +1887,7 @@ public:
|
||||||
// Final step outside, as both AstToDfgSynthesize and removeUnused used DfgUserMap
|
// Final step outside, as both AstToDfgSynthesize and removeUnused used DfgUserMap
|
||||||
UINFO(5, "Step 6: Remove all unused vertices");
|
UINFO(5, "Step 6: Remove all unused vertices");
|
||||||
V3DfgPasses::removeUnused(dfg);
|
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
|
// No operation vertex should have multiple sinks. Cyclic decomoposition
|
||||||
// depends on this and it can easily be ensured by using temporaries.
|
// 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
|
// Select which DfgLogic to attempt to synthesize
|
||||||
dfgSelectLogicForSynthesis(dfg);
|
dfgSelectLogicForSynthesis(dfg);
|
||||||
// Synthesize them - also removes un-synthesized DfgLogic, so must run even if nothing selected
|
// Synthesize them - also removes un-synthesized DfgLogic, so must run even if nothing selected
|
||||||
if (dfg.modulep()) {
|
AstToDfgSynthesize::apply(dfg, ctx.m_synthContext);
|
||||||
AstToDfgSynthesize</* T_Scoped: */ false>::apply(dfg, ctx.m_synthContext);
|
|
||||||
} else {
|
|
||||||
AstToDfgSynthesize</* T_Scoped: */ true>::apply(dfg, ctx.m_synthContext);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,47 +48,32 @@
|
||||||
class DfgVertexVar VL_NOT_FINAL : public DfgVertex {
|
class DfgVertexVar VL_NOT_FINAL : public DfgVertex {
|
||||||
// Represents a variable. It has 2 optional inputs, 'srcp' and 'defaultp'.
|
// 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_vscp; // The AstVarScope associated with this vertex (not owned)
|
||||||
AstVarScope* const m_varScopep; // The AstVarScope associated with this vertex (not owned)
|
|
||||||
// Location of driver of this variable. Only used for converting back to Ast. Might be nullptr.
|
// Location of driver of this variable. Only used for converting back to Ast. Might be nullptr.
|
||||||
FileLine* m_driverFileLine = nullptr;
|
FileLine* m_driverFileLine = nullptr;
|
||||||
// If this DfgVertexVar is a synthesized temporary, this is the original Var/VarScope it stands
|
// If this DfgVertexVar is a synthesized temporary, this is the original AstVarScope it stands
|
||||||
// for. It might point to m_varp/m_varScopep itself to indicate it's a temporary without an
|
// for. It might point to m_vscp itself to indicate it's a temporary without an associated
|
||||||
// associated input Var/VarScope.
|
// input AstVarScope.
|
||||||
AstNode* m_tmpForp = nullptr;
|
AstVarScope* m_tmpForp = nullptr;
|
||||||
|
|
||||||
DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp, AstVarScope* vscp)
|
protected:
|
||||||
: DfgVertex{dfg, type, varp->fileline(), *DfgDataType::fromAst(varp->dtypep())}
|
DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVarScope* vscp)
|
||||||
, m_varp{varp}
|
: DfgVertex{dfg, type, vscp->varp()->fileline(),
|
||||||
, m_varScopep{vscp} {
|
*DfgDataType::fromAst(vscp->varp()->dtypep())}
|
||||||
#ifdef VL_DEBUG
|
, m_vscp{vscp} {
|
||||||
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
|
|
||||||
// Increment reference count
|
// Increment reference count
|
||||||
AstNode* const variablep = nodep();
|
m_vscp->user1(m_vscp->user1() + 0x20);
|
||||||
variablep->user1(variablep->user1() + 0x20);
|
UASSERT_OBJ((m_vscp->user1() >> 5) > 0, m_vscp, "Reference count overflow");
|
||||||
UASSERT_OBJ((variablep->user1() >> 5) > 0, variablep, "Reference count overflow");
|
|
||||||
// Allocate sources
|
// Allocate sources
|
||||||
newInput();
|
newInput();
|
||||||
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:
|
public:
|
||||||
~DfgVertexVar() {
|
~DfgVertexVar() {
|
||||||
// Decrement reference count
|
// Decrement reference count
|
||||||
AstNode* const variablep = nodep();
|
m_vscp->user1(m_vscp->user1() - 0x20);
|
||||||
variablep->user1(variablep->user1() - 0x20);
|
UASSERT_OBJ((m_vscp->user1() >> 5) >= 0, m_vscp, "Reference count underflow");
|
||||||
UASSERT_OBJ((variablep->user1() >> 5) >= 0, variablep, "Reference count underflow");
|
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_DfgVertexVar;
|
ASTGEN_MEMBERS_DfgVertexVar;
|
||||||
|
|
||||||
|
|
@ -102,42 +87,39 @@ public:
|
||||||
std::string srcName(size_t idx) const override final { return idx ? "defaultp" : "srcp"; }
|
std::string srcName(size_t idx) const override final { return idx ? "defaultp" : "srcp"; }
|
||||||
|
|
||||||
// The Ast variable this vertex representess
|
// The Ast variable this vertex representess
|
||||||
AstVar* varp() const { return m_varp; }
|
// AstVar* varp() const { return m_varp; }
|
||||||
AstVarScope* varScopep() const { return m_varScopep; }
|
AstVarScope* vscp() const { return m_vscp; }
|
||||||
AstNode* nodep() const {
|
|
||||||
return m_varScopep ? static_cast<AstNode*>(m_varScopep) : static_cast<AstNode*>(m_varp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is a temporary, the Ast variable it stands for, or same as
|
// 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.
|
// 'nodep()' if it's a temporary with no associated original Ast variable.
|
||||||
AstNode* tmpForp() const { return m_tmpForp; }
|
AstVarScope* tmpForp() const { return m_tmpForp; }
|
||||||
void tmpForp(AstNode* nodep) { m_tmpForp = nodep; }
|
void tmpForp(AstVarScope* nodep) { m_tmpForp = nodep; }
|
||||||
|
|
||||||
// Location of driver of variable (only used if 'srcp' is not a splice)
|
// Location of driver of variable (only used if 'srcp' is not a splice)
|
||||||
FileLine* driverFileLine() const { return m_driverFileLine; }
|
FileLine* driverFileLine() const { return m_driverFileLine; }
|
||||||
void driverFileLine(FileLine* flp) { m_driverFileLine = flp; }
|
void driverFileLine(FileLine* flp) { m_driverFileLine = flp; }
|
||||||
|
|
||||||
// Variable referenced from other DFG in the same module/netlist
|
// 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
|
// Variable referenced from Ast code in the same module/netlist
|
||||||
static bool hasModWrRefs(const AstNode* nodep) { return nodep->user1() & 0x08; }
|
static bool hasModWrRefs(const AstVarScope* nodep) { return nodep->user1() & 0x08; }
|
||||||
static void setHasModWrRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x08); }
|
static void setHasModWrRefs(AstVarScope* nodep) { nodep->user1(nodep->user1() | 0x08); }
|
||||||
bool hasModWrRefs() const { return hasModWrRefs(nodep()); }
|
bool hasModWrRefs() const { return hasModWrRefs(m_vscp); }
|
||||||
void setHasModWrRefs() const { setHasModWrRefs(nodep()); }
|
void setHasModWrRefs() const { setHasModWrRefs(m_vscp); }
|
||||||
|
|
||||||
// Variable referenced outside the containing module/netlist.
|
// Variable referenced outside the containing module/netlist.
|
||||||
static bool hasExtRdRefs(const AstNode* nodep) { return nodep->user1() & 0x01; }
|
static bool hasExtRdRefs(const AstVarScope* nodep) { return nodep->user1() & 0x01; }
|
||||||
static bool hasExtWrRefs(const AstNode* nodep) { return nodep->user1() & 0x02; }
|
static bool hasExtWrRefs(const AstVarScope* nodep) { return nodep->user1() & 0x02; }
|
||||||
static void setHasExtRdRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x01); }
|
static void setHasExtRdRefs(AstVarScope* nodep) { nodep->user1(nodep->user1() | 0x01); }
|
||||||
static void setHasExtWrRefs(AstNode* nodep) { nodep->user1(nodep->user1() | 0x02); }
|
static void setHasExtWrRefs(AstVarScope* nodep) { nodep->user1(nodep->user1() | 0x02); }
|
||||||
bool hasExtRdRefs() const { return hasExtRdRefs(nodep()); }
|
bool hasExtRdRefs() const { return hasExtRdRefs(m_vscp); }
|
||||||
bool hasExtWrRefs() const { return hasExtWrRefs(nodep()); }
|
bool hasExtWrRefs() const { return hasExtWrRefs(m_vscp); }
|
||||||
bool hasExtRefs() const { return hasExtRdRefs() || hasExtWrRefs(); }
|
bool hasExtRefs() const { return hasExtRdRefs() || hasExtWrRefs(); }
|
||||||
|
|
||||||
// Variable referenced via READWRITE references
|
// Variable referenced via READWRITE references
|
||||||
static bool hasRWRefs(const AstNode* nodep) { return nodep->user1() & 0x10; }
|
static bool hasRWRefs(const AstVarScope* nodep) { return nodep->user1() & 0x10; }
|
||||||
static void setHasRWRefs(AstNode* nodep) { nodep->user1(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
|
// True iff the value of this variable is read outside this DfgGraph
|
||||||
bool isObserved() const {
|
bool isObserved() const {
|
||||||
|
|
@ -150,10 +132,10 @@ public:
|
||||||
// The value of this vertex might differ from what is defined by its drivers
|
// 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,
|
// 'srcp' and 'defaultp'. That is, it might be assigned, possibly partially,
|
||||||
// or abruptly outside the graph, hence it is not equivalent to its 'srcp'.
|
// 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);
|
return hasModWrRefs(nodep) || hasExtWrRefs(nodep);
|
||||||
}
|
}
|
||||||
bool isVolatile() const { return isVolatile(nodep()); }
|
bool isVolatile() const { return isVolatile(m_vscp); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class DfgVarArray final : public DfgVertexVar {
|
class DfgVarArray final : public DfgVertexVar {
|
||||||
|
|
@ -161,10 +143,6 @@ class DfgVarArray final : public DfgVertexVar {
|
||||||
friend class DfgVisitor;
|
friend class DfgVisitor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DfgVarArray(DfgGraph& dfg, AstVar* varp)
|
|
||||||
: DfgVertexVar{dfg, dfgType(), varp} {
|
|
||||||
UASSERT_OBJ(isArray(), varp, "Non-array DfgVarArray");
|
|
||||||
}
|
|
||||||
DfgVarArray(DfgGraph& dfg, AstVarScope* vscp)
|
DfgVarArray(DfgGraph& dfg, AstVarScope* vscp)
|
||||||
: DfgVertexVar{dfg, dfgType(), vscp} {
|
: DfgVertexVar{dfg, dfgType(), vscp} {
|
||||||
UASSERT_OBJ(isArray(), vscp, "Non-array DfgVarArray");
|
UASSERT_OBJ(isArray(), vscp, "Non-array DfgVarArray");
|
||||||
|
|
@ -177,10 +155,6 @@ class DfgVarPacked final : public DfgVertexVar {
|
||||||
friend class DfgVisitor;
|
friend class DfgVisitor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DfgVarPacked(DfgGraph& dfg, AstVar* varp)
|
|
||||||
: DfgVertexVar{dfg, dfgType(), varp} {
|
|
||||||
UASSERT_OBJ(isPacked(), varp, "Non-packed DfgVarPacked");
|
|
||||||
}
|
|
||||||
DfgVarPacked(DfgGraph& dfg, AstVarScope* vscp)
|
DfgVarPacked(DfgGraph& dfg, AstVarScope* vscp)
|
||||||
: DfgVertexVar{dfg, dfgType(), vscp} {
|
: DfgVertexVar{dfg, dfgType(), vscp} {
|
||||||
UASSERT_OBJ(isPacked(), vscp, "Non-packed DfgVarPacked");
|
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-assigns", FOnOff, &m_fDeadAssigns);
|
||||||
DECL_OPTION("-fdead-cells", FOnOff, &m_fDeadCells);
|
DECL_OPTION("-fdead-cells", FOnOff, &m_fDeadCells);
|
||||||
DECL_OPTION("-fdedup", FOnOff, &m_fDedupe);
|
DECL_OPTION("-fdedup", FOnOff, &m_fDedupe);
|
||||||
DECL_OPTION("-fdfg", CbFOnOff, [this](bool flag) {
|
DECL_OPTION("-fdfg", CbFOnOff, [this](bool flag) { m_fDfg = flag; });
|
||||||
m_fDfgPreInline = flag;
|
|
||||||
m_fDfgPostInline = flag;
|
|
||||||
m_fDfgScoped = flag;
|
|
||||||
});
|
|
||||||
DECL_OPTION("-fdfg-break-cycles", FOnOff, &m_fDfgBreakCycles);
|
DECL_OPTION("-fdfg-break-cycles", FOnOff, &m_fDfgBreakCycles);
|
||||||
DECL_OPTION("-fdfg-peephole", FOnOff, &m_fDfgPeephole);
|
DECL_OPTION("-fdfg-peephole", FOnOff, &m_fDfgPeephole);
|
||||||
DECL_OPTION("-fdfg-peephole-", CbPartialMatch, [this](const char* optp) { //
|
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) { //
|
DECL_OPTION("-fno-dfg-peephole-", CbPartialMatch, [this](const char* optp) { //
|
||||||
m_fDfgPeepholeDisabled.emplace(optp);
|
m_fDfgPeepholeDisabled.emplace(optp);
|
||||||
});
|
});
|
||||||
DECL_OPTION("-fdfg-pre-inline", FOnOff, &m_fDfgPreInline);
|
DECL_OPTION("-fdfg-pre-inline", CbFOnOff, [fl](bool) {
|
||||||
DECL_OPTION("-fdfg-post-inline", FOnOff, &m_fDfgPostInline);
|
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-push-down-sels", FOnOff, &m_fDfgPushDownSels);
|
||||||
DECL_OPTION("-fdfg-scoped", FOnOff, &m_fDfgScoped);
|
|
||||||
DECL_OPTION("-fdfg-synthesize-all", FOnOff, &m_fDfgSynthesizeAll);
|
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("-fexpand", FOnOff, &m_fExpand);
|
||||||
DECL_OPTION("-ffunc-opt", CbFOnOff, [this](bool flag) { //
|
DECL_OPTION("-ffunc-opt", CbFOnOff, [this](bool flag) { //
|
||||||
m_fFuncSplitCat = flag;
|
m_fFuncSplitCat = flag;
|
||||||
|
|
@ -2351,9 +2354,7 @@ void V3Options::optimize(int level) {
|
||||||
m_fConst = flag;
|
m_fConst = flag;
|
||||||
m_fConstBitOpTree = flag;
|
m_fConstBitOpTree = flag;
|
||||||
m_fDedupe = flag;
|
m_fDedupe = flag;
|
||||||
m_fDfgPreInline = flag;
|
m_fDfg = flag;
|
||||||
m_fDfgPostInline = flag;
|
|
||||||
m_fDfgScoped = flag;
|
|
||||||
m_fDeadAssigns = flag;
|
m_fDeadAssigns = flag;
|
||||||
m_fDeadCells = flag;
|
m_fDeadCells = flag;
|
||||||
m_fExpand = flag;
|
m_fExpand = flag;
|
||||||
|
|
|
||||||
|
|
@ -399,10 +399,8 @@ private:
|
||||||
bool m_fDedupe; // main switch: -fno-dedupe: logic deduplication
|
bool m_fDedupe; // main switch: -fno-dedupe: logic deduplication
|
||||||
bool m_fDfgBreakCycles = true; // main switch: -fno-dfg-break-cycles
|
bool m_fDfgBreakCycles = true; // main switch: -fno-dfg-break-cycles
|
||||||
bool m_fDfgPeephole = true; // main switch: -fno-dfg-peephole
|
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_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_fDfgSynthesizeAll = false; // main switch: -fdfg-synthesize-all
|
||||||
bool m_fDeadAssigns; // main switch: -fno-dead-assigns: remove dead assigns
|
bool m_fDeadAssigns; // main switch: -fno-dead-assigns: remove dead assigns
|
||||||
bool m_fDeadCells; // main switch: -fno-dead-cells: remove dead cells
|
bool m_fDeadCells; // main switch: -fno-dead-cells: remove dead cells
|
||||||
|
|
@ -718,12 +716,10 @@ public:
|
||||||
bool fConstBitOpTree() const { return m_fConstBitOpTree; }
|
bool fConstBitOpTree() const { return m_fConstBitOpTree; }
|
||||||
bool fConstEager() const { return m_fConstEager; }
|
bool fConstEager() const { return m_fConstEager; }
|
||||||
bool fDedupe() const { return m_fDedupe; }
|
bool fDedupe() const { return m_fDedupe; }
|
||||||
|
bool fDfg() const { return m_fDfg; }
|
||||||
bool fDfgBreakCycles() const { return m_fDfgBreakCycles; }
|
bool fDfgBreakCycles() const { return m_fDfgBreakCycles; }
|
||||||
bool fDfgPeephole() const { return m_fDfgPeephole; }
|
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 fDfgPushDownSels() const { return m_fDfgPushDownSels; }
|
||||||
bool fDfgScoped() const { return m_fDfgScoped; }
|
|
||||||
bool fDfgSynthesizeAll() const { return m_fDfgSynthesizeAll; }
|
bool fDfgSynthesizeAll() const { return m_fDfgSynthesizeAll; }
|
||||||
bool fDfgPeepholeEnabled(const std::string& name) const {
|
bool fDfgPeepholeEnabled(const std::string& name) const {
|
||||||
return !m_fDfgPeepholeDisabled.count(name);
|
return !m_fDfgPeepholeDisabled.count(name);
|
||||||
|
|
|
||||||
|
|
@ -307,15 +307,8 @@ static void process() {
|
||||||
v3Global.constRemoveXs(true);
|
v3Global.constRemoveXs(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v3Global.opt.fDfgPreInline() || v3Global.opt.fDfgPostInline()) {
|
// If doing DFG optimization, extract some additional candidates
|
||||||
// If doing DFG optimization, extract some additional candidates
|
if (v3Global.opt.fDfg()) V3DfgOptimizer::extract(v3Global.rootp());
|
||||||
V3DfgOptimizer::extract(v3Global.rootp());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v3Global.opt.fDfgPreInline()) {
|
|
||||||
// Pre inline DFG optimization
|
|
||||||
V3DfgOptimizer::optimize(v3Global.rootp(), "pre inline");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) {
|
if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) {
|
||||||
// Module inlining
|
// Module inlining
|
||||||
|
|
@ -329,15 +322,10 @@ static void process() {
|
||||||
|
|
||||||
if (v3Global.opt.trace()) V3Interface::interfaceAll(v3Global.rootp());
|
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------------------
|
// --PRE-FLAT OPTIMIZATIONS------------------
|
||||||
|
|
||||||
// Initial const/dead to reduce work for ordering code
|
// Initial const/dead to reduce work for ordering code
|
||||||
V3Const::constifyAll(v3Global.rootp());
|
if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp());
|
||||||
v3Global.checkTree();
|
v3Global.checkTree();
|
||||||
|
|
||||||
V3Dead::deadifyDTypes(v3Global.rootp());
|
V3Dead::deadifyDTypes(v3Global.rootp());
|
||||||
|
|
@ -355,7 +343,7 @@ static void process() {
|
||||||
V3Inst::instAll(v3Global.rootp());
|
V3Inst::instAll(v3Global.rootp());
|
||||||
|
|
||||||
// Inst may have made lots of concats; fix them
|
// 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
|
// Flatten hierarchy, creating a SCOPE for each module's usage as a cell
|
||||||
// No more AstAlias after linkDotScope
|
// No more AstAlias after linkDotScope
|
||||||
|
|
@ -370,7 +358,7 @@ static void process() {
|
||||||
|
|
||||||
if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) {
|
if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) {
|
||||||
// Cleanup
|
// Cleanup
|
||||||
V3Const::constifyAll(v3Global.rootp());
|
if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp());
|
||||||
V3Dead::deadifyDTypesScoped(v3Global.rootp());
|
V3Dead::deadifyDTypesScoped(v3Global.rootp());
|
||||||
v3Global.checkTree();
|
v3Global.checkTree();
|
||||||
}
|
}
|
||||||
|
|
@ -398,7 +386,7 @@ static void process() {
|
||||||
V3Slice::sliceAll(v3Global.rootp());
|
V3Slice::sliceAll(v3Global.rootp());
|
||||||
|
|
||||||
// Push constants across variables and remove redundant assignments
|
// 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());
|
if (v3Global.opt.fLife()) V3Life::lifeAll(v3Global.rootp());
|
||||||
|
|
||||||
|
|
@ -409,7 +397,7 @@ static void process() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
V3Const::constifyAll(v3Global.rootp());
|
if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAll(v3Global.rootp());
|
||||||
V3Dead::deadifyDTypesScoped(v3Global.rootp());
|
V3Dead::deadifyDTypesScoped(v3Global.rootp());
|
||||||
v3Global.checkTree();
|
v3Global.checkTree();
|
||||||
|
|
||||||
|
|
@ -429,10 +417,8 @@ static void process() {
|
||||||
// forcing.
|
// forcing.
|
||||||
V3Force::forceAll(v3Global.rootp());
|
V3Force::forceAll(v3Global.rootp());
|
||||||
|
|
||||||
if (v3Global.opt.fDfgScoped()) {
|
// DFG optimization
|
||||||
// Scoped DFG optimization
|
if (v3Global.opt.fDfg()) V3DfgOptimizer::optimize(v3Global.rootp());
|
||||||
V3DfgOptimizer::optimize(v3Global.rootp(), "scoped");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gate-based logic elimination; eliminate signals and push constant across cell
|
// Gate-based logic elimination; eliminate signals and push constant across cell
|
||||||
// boundaries Instant propagation makes lots-o-constant reduction possibilities.
|
// boundaries Instant propagation makes lots-o-constant reduction possibilities.
|
||||||
|
|
|
||||||
|
|
@ -465,9 +465,9 @@
|
||||||
+000010 point: type=line comment=block hier=top.t.cond1
|
+000010 point: type=line comment=block hier=top.t.cond1
|
||||||
endfunction
|
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
|
-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;
|
~000028 assign b = (cyc == 1) ? clk : 0;
|
||||||
-000003 point: type=branch comment=cond_then hier=top.t.cond1
|
-000003 point: type=branch comment=cond_then hier=top.t.cond1
|
||||||
+000028 point: type=branch comment=cond_else 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:328,10
|
||||||
DA:329,10
|
DA:329,10
|
||||||
DA:330,10
|
DA:330,10
|
||||||
DA:333,11
|
DA:333,31
|
||||||
BRDA:333,0,0,0
|
BRDA:333,0,0,0
|
||||||
BRDA:333,0,1,11
|
BRDA:333,0,1,31
|
||||||
DA:334,28
|
DA:334,28
|
||||||
BRDA:334,0,0,3
|
BRDA:334,0,0,3
|
||||||
BRDA:334,0,1,28
|
BRDA:334,0,1,28
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,10 @@ import vltest_bootstrap
|
||||||
|
|
||||||
test.scenarios('vlt')
|
test.scenarios('vlt')
|
||||||
|
|
||||||
test.compile(verilator_flags2=["--stats"])
|
test.compile(verilator_flags2=["--stats", "-fno-table", "-fno-inline"])
|
||||||
|
|
||||||
test.execute()
|
test.execute()
|
||||||
|
|
||||||
test.file_grep(test.stats, r'Optimizations, DFG pre inline BinToOneHot, decoders created\s+(\d+)',
|
test.file_grep(test.stats, r'Optimizations, DFG, BinToOneHot, decoders created\s+(\d+)', 5)
|
||||||
4)
|
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ module t (
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sub u_sub(clk, cyc, cntB, cntC);
|
||||||
|
|
||||||
// Should create decoder
|
// Should create decoder
|
||||||
wire [127:0] cntAOneHot = {
|
wire [127:0] cntAOneHot = {
|
||||||
cntA == 7'd127,
|
cntA == 7'd127,
|
||||||
|
|
@ -296,120 +298,6 @@ module t (
|
||||||
~cntA == 7'd0
|
~cntA == 7'd0
|
||||||
};
|
};
|
||||||
|
|
||||||
// Should create decoder
|
|
||||||
wire stupidWayToWriteConstOne = 1'b0
|
|
||||||
+ (cntB == 7'd127)
|
|
||||||
+ (cntB == 7'd126)
|
|
||||||
+ (cntB == 7'd125)
|
|
||||||
+ (cntB == 7'd124)
|
|
||||||
+ (cntB == 7'd123)
|
|
||||||
+ (cntB == 7'd122)
|
|
||||||
+ (cntB == 7'd121)
|
|
||||||
+ (cntB == 7'd120)
|
|
||||||
+ (cntB == 7'd119)
|
|
||||||
+ (cntB == 7'd118)
|
|
||||||
+ (cntB == 7'd117)
|
|
||||||
+ (cntB == 7'd116)
|
|
||||||
+ (cntB == 7'd115)
|
|
||||||
+ (cntB == 7'd114)
|
|
||||||
+ (cntB == 7'd113)
|
|
||||||
+ (cntB == 7'd112)
|
|
||||||
+ (cntB == 7'd111)
|
|
||||||
+ (cntB == 7'd110)
|
|
||||||
+ (cntB == 7'd109)
|
|
||||||
+ (cntB == 7'd108)
|
|
||||||
+ (cntB == 7'd107)
|
|
||||||
+ (cntB == 7'd106)
|
|
||||||
+ (cntB == 7'd105)
|
|
||||||
+ (cntB == 7'd104)
|
|
||||||
+ (cntB == 7'd103)
|
|
||||||
+ (cntB == 7'd102)
|
|
||||||
+ (cntB == 7'd101)
|
|
||||||
+ (cntB == 7'd100)
|
|
||||||
+ (cntB == 7'd99)
|
|
||||||
+ (cntB == 7'd98)
|
|
||||||
+ (cntB == 7'd97)
|
|
||||||
+ (cntB == 7'd96)
|
|
||||||
+ (cntB == 7'd95)
|
|
||||||
+ (cntB == 7'd94)
|
|
||||||
+ (cntB == 7'd93)
|
|
||||||
+ (cntB == 7'd92)
|
|
||||||
+ (cntB == 7'd91)
|
|
||||||
+ (cntB == 7'd90)
|
|
||||||
+ (cntB == 7'd89)
|
|
||||||
+ (cntB == 7'd88)
|
|
||||||
+ (cntB == 7'd87)
|
|
||||||
+ (cntB == 7'd86)
|
|
||||||
+ (cntB == 7'd85)
|
|
||||||
+ (cntB == 7'd84)
|
|
||||||
+ (cntB == 7'd83)
|
|
||||||
+ (cntB == 7'd82)
|
|
||||||
+ (cntB == 7'd81)
|
|
||||||
+ (cntB == 7'd80)
|
|
||||||
+ (cntB == 7'd79)
|
|
||||||
+ (cntB == 7'd78)
|
|
||||||
+ (cntB == 7'd77)
|
|
||||||
+ (cntB == 7'd76)
|
|
||||||
+ (cntB == 7'd75)
|
|
||||||
+ (cntB == 7'd74)
|
|
||||||
+ (cntB == 7'd73)
|
|
||||||
+ (cntB == 7'd72)
|
|
||||||
+ (cntB == 7'd71)
|
|
||||||
+ (cntB == 7'd70)
|
|
||||||
+ (cntB == 7'd69)
|
|
||||||
+ (cntB == 7'd68)
|
|
||||||
+ (cntB == 7'd67)
|
|
||||||
+ (cntB == 7'd66)
|
|
||||||
+ (cntB == 7'd65)
|
|
||||||
+ (cntB == 7'd64)
|
|
||||||
+ (cntB == 7'd63)
|
|
||||||
+ (cntB == 7'd62)
|
|
||||||
+ (cntB == 7'd61)
|
|
||||||
+ (cntB == 7'd60)
|
|
||||||
+ (cntB == 7'd59)
|
|
||||||
+ (cntB == 7'd58)
|
|
||||||
+ (cntB == 7'd57)
|
|
||||||
+ (cntB == 7'd56)
|
|
||||||
+ (cntB == 7'd55)
|
|
||||||
+ (cntB == 7'd54)
|
|
||||||
+ (cntB == 7'd53)
|
|
||||||
+ (cntB == 7'd52)
|
|
||||||
+ (cntB == 7'd51)
|
|
||||||
+ (cntB == 7'd50)
|
|
||||||
+ (cntB == 7'd49)
|
|
||||||
+ (cntB == 7'd48)
|
|
||||||
+ (cntB == 7'd47)
|
|
||||||
+ (cntB == 7'd46)
|
|
||||||
+ (cntB == 7'd45)
|
|
||||||
+ (cntB == 7'd44)
|
|
||||||
+ (cntB == 7'd43)
|
|
||||||
+ (cntB == 7'd42)
|
|
||||||
+ (cntB == 7'd41)
|
|
||||||
+ (cntB == 7'd40)
|
|
||||||
+ (cntB == 7'd39)
|
|
||||||
+ (cntB == 7'd38)
|
|
||||||
+ (cntB == 7'd37)
|
|
||||||
+ (cntB == 7'd36)
|
|
||||||
+ (cntB == 7'd35)
|
|
||||||
+ (cntB == 7'd34)
|
|
||||||
+ (cntB == 7'd33)
|
|
||||||
+ (cntB == 7'd32)
|
|
||||||
+ (cntB == 7'd31)
|
|
||||||
+ (cntB == 7'd30)
|
|
||||||
+ (cntB == 7'd29)
|
|
||||||
+ (cntB == 7'd28)
|
|
||||||
+ (cntB == 7'd27)
|
|
||||||
+ (cntB == 7'd26)
|
|
||||||
+ (cntB == 7'd25)
|
|
||||||
+ (cntB == 7'd24)
|
|
||||||
+ (cntB == 7'd23)
|
|
||||||
+ (cntB == 7'd22)
|
|
||||||
+ (cntB == 7'd21)
|
|
||||||
+ (cntB == 7'd20)
|
|
||||||
+ (cntB == 7'd19)
|
|
||||||
+ (cntB == 7'd18)
|
|
||||||
+ (cntB <= 7'd17);
|
|
||||||
|
|
||||||
// Should not create decoder
|
// Should not create decoder
|
||||||
wire [6:0] twiceCntC =
|
wire [6:0] twiceCntC =
|
||||||
cntC == 7'd127 ? (7'd127 * 7'd2) :
|
cntC == 7'd127 ? (7'd127 * 7'd2) :
|
||||||
|
|
@ -540,7 +428,6 @@ module t (
|
||||||
cntC == 7'd2 ? (7'd2 * 7'd2) :
|
cntC == 7'd2 ? (7'd2 * 7'd2) :
|
||||||
cntC == 7'd1 ? (7'd1 * 7'd2) : 7'd0;
|
cntC == 7'd1 ? (7'd1 * 7'd2) : 7'd0;
|
||||||
|
|
||||||
|
|
||||||
// Should create decoder
|
// Should create decoder
|
||||||
wire [127:0] cntD_OH = 128'h1 << cntD;
|
wire [127:0] cntD_OH = 128'h1 << cntD;
|
||||||
wire [6:0] cntD_sel =
|
wire [6:0] cntD_sel =
|
||||||
|
|
@ -686,11 +573,262 @@ module t (
|
||||||
`check(notCntAOneHot[i], 1'b0);
|
`check(notCntAOneHot[i], 1'b0);
|
||||||
end
|
end
|
||||||
|
|
||||||
`check(stupidWayToWriteConstOne, 1'b1);
|
|
||||||
|
|
||||||
`check(twiceCntC, cntC * 7'd2);
|
`check(twiceCntC, cntC * 7'd2);
|
||||||
|
|
||||||
`check(cntD_sel, cntD);
|
`check(cntD_sel, cntD);
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module alt;
|
||||||
|
reg [6:0] cntC_q;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module sub (
|
||||||
|
input wire clk,
|
||||||
|
input wire [31:0] cyc,
|
||||||
|
input wire [6:0] cntB,
|
||||||
|
input wire [6:0] cntC
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [6:0] cntB_q;
|
||||||
|
always @(posedge clk) cntB_q <= cntB;
|
||||||
|
|
||||||
|
alt u_alt();
|
||||||
|
always @(posedge clk) u_alt.cntC_q <= cntC;
|
||||||
|
|
||||||
|
// Should create decoder
|
||||||
|
wire stupidWayToWriteConstOne_B = 1'b0
|
||||||
|
+ (cntB_q == 7'd127)
|
||||||
|
+ (cntB_q == 7'd126)
|
||||||
|
+ (cntB_q == 7'd125)
|
||||||
|
+ (cntB_q == 7'd124)
|
||||||
|
+ (cntB_q == 7'd123)
|
||||||
|
+ (cntB_q == 7'd122)
|
||||||
|
+ (cntB_q == 7'd121)
|
||||||
|
+ (cntB_q == 7'd120)
|
||||||
|
+ (cntB_q == 7'd119)
|
||||||
|
+ (cntB_q == 7'd118)
|
||||||
|
+ (cntB_q == 7'd117)
|
||||||
|
+ (cntB_q == 7'd116)
|
||||||
|
+ (cntB_q == 7'd115)
|
||||||
|
+ (cntB_q == 7'd114)
|
||||||
|
+ (cntB_q == 7'd113)
|
||||||
|
+ (cntB_q == 7'd112)
|
||||||
|
+ (cntB_q == 7'd111)
|
||||||
|
+ (cntB_q == 7'd110)
|
||||||
|
+ (cntB_q == 7'd109)
|
||||||
|
+ (cntB_q == 7'd108)
|
||||||
|
+ (cntB_q == 7'd107)
|
||||||
|
+ (cntB_q == 7'd106)
|
||||||
|
+ (cntB_q == 7'd105)
|
||||||
|
+ (cntB_q == 7'd104)
|
||||||
|
+ (cntB_q == 7'd103)
|
||||||
|
+ (cntB_q == 7'd102)
|
||||||
|
+ (cntB_q == 7'd101)
|
||||||
|
+ (cntB_q == 7'd100)
|
||||||
|
+ (cntB_q == 7'd99)
|
||||||
|
+ (cntB_q == 7'd98)
|
||||||
|
+ (cntB_q == 7'd97)
|
||||||
|
+ (cntB_q == 7'd96)
|
||||||
|
+ (cntB_q == 7'd95)
|
||||||
|
+ (cntB_q == 7'd94)
|
||||||
|
+ (cntB_q == 7'd93)
|
||||||
|
+ (cntB_q == 7'd92)
|
||||||
|
+ (cntB_q == 7'd91)
|
||||||
|
+ (cntB_q == 7'd90)
|
||||||
|
+ (cntB_q == 7'd89)
|
||||||
|
+ (cntB_q == 7'd88)
|
||||||
|
+ (cntB_q == 7'd87)
|
||||||
|
+ (cntB_q == 7'd86)
|
||||||
|
+ (cntB_q == 7'd85)
|
||||||
|
+ (cntB_q == 7'd84)
|
||||||
|
+ (cntB_q == 7'd83)
|
||||||
|
+ (cntB_q == 7'd82)
|
||||||
|
+ (cntB_q == 7'd81)
|
||||||
|
+ (cntB_q == 7'd80)
|
||||||
|
+ (cntB_q == 7'd79)
|
||||||
|
+ (cntB_q == 7'd78)
|
||||||
|
+ (cntB_q == 7'd77)
|
||||||
|
+ (cntB_q == 7'd76)
|
||||||
|
+ (cntB_q == 7'd75)
|
||||||
|
+ (cntB_q == 7'd74)
|
||||||
|
+ (cntB_q == 7'd73)
|
||||||
|
+ (cntB_q == 7'd72)
|
||||||
|
+ (cntB_q == 7'd71)
|
||||||
|
+ (cntB_q == 7'd70)
|
||||||
|
+ (cntB_q == 7'd69)
|
||||||
|
+ (cntB_q == 7'd68)
|
||||||
|
+ (cntB_q == 7'd67)
|
||||||
|
+ (cntB_q == 7'd66)
|
||||||
|
+ (cntB_q == 7'd65)
|
||||||
|
+ (cntB_q == 7'd64)
|
||||||
|
+ (cntB_q == 7'd63)
|
||||||
|
+ (cntB_q == 7'd62)
|
||||||
|
+ (cntB_q == 7'd61)
|
||||||
|
+ (cntB_q == 7'd60)
|
||||||
|
+ (cntB_q == 7'd59)
|
||||||
|
+ (cntB_q == 7'd58)
|
||||||
|
+ (cntB_q == 7'd57)
|
||||||
|
+ (cntB_q == 7'd56)
|
||||||
|
+ (cntB_q == 7'd55)
|
||||||
|
+ (cntB_q == 7'd54)
|
||||||
|
+ (cntB_q == 7'd53)
|
||||||
|
+ (cntB_q == 7'd52)
|
||||||
|
+ (cntB_q == 7'd51)
|
||||||
|
+ (cntB_q == 7'd50)
|
||||||
|
+ (cntB_q == 7'd49)
|
||||||
|
+ (cntB_q == 7'd48)
|
||||||
|
+ (cntB_q == 7'd47)
|
||||||
|
+ (cntB_q == 7'd46)
|
||||||
|
+ (cntB_q == 7'd45)
|
||||||
|
+ (cntB_q == 7'd44)
|
||||||
|
+ (cntB_q == 7'd43)
|
||||||
|
+ (cntB_q == 7'd42)
|
||||||
|
+ (cntB_q == 7'd41)
|
||||||
|
+ (cntB_q == 7'd40)
|
||||||
|
+ (cntB_q == 7'd39)
|
||||||
|
+ (cntB_q == 7'd38)
|
||||||
|
+ (cntB_q == 7'd37)
|
||||||
|
+ (cntB_q == 7'd36)
|
||||||
|
+ (cntB_q == 7'd35)
|
||||||
|
+ (cntB_q == 7'd34)
|
||||||
|
+ (cntB_q == 7'd33)
|
||||||
|
+ (cntB_q == 7'd32)
|
||||||
|
+ (cntB_q == 7'd31)
|
||||||
|
+ (cntB_q == 7'd30)
|
||||||
|
+ (cntB_q == 7'd29)
|
||||||
|
+ (cntB_q == 7'd28)
|
||||||
|
+ (cntB_q == 7'd27)
|
||||||
|
+ (cntB_q == 7'd26)
|
||||||
|
+ (cntB_q == 7'd25)
|
||||||
|
+ (cntB_q == 7'd24)
|
||||||
|
+ (cntB_q == 7'd23)
|
||||||
|
+ (cntB_q == 7'd22)
|
||||||
|
+ (cntB_q == 7'd21)
|
||||||
|
+ (cntB_q == 7'd20)
|
||||||
|
+ (cntB_q == 7'd19)
|
||||||
|
+ (cntB_q == 7'd18)
|
||||||
|
+ (cntB_q <= 7'd17);
|
||||||
|
|
||||||
|
// Should create decoder
|
||||||
|
wire stupidWayToWriteConstOne_C = 1'b0
|
||||||
|
+ (u_alt.cntC_q == 7'd127)
|
||||||
|
+ (u_alt.cntC_q == 7'd126)
|
||||||
|
+ (u_alt.cntC_q == 7'd125)
|
||||||
|
+ (u_alt.cntC_q == 7'd124)
|
||||||
|
+ (u_alt.cntC_q == 7'd123)
|
||||||
|
+ (u_alt.cntC_q == 7'd122)
|
||||||
|
+ (u_alt.cntC_q == 7'd121)
|
||||||
|
+ (u_alt.cntC_q == 7'd120)
|
||||||
|
+ (u_alt.cntC_q == 7'd119)
|
||||||
|
+ (u_alt.cntC_q == 7'd118)
|
||||||
|
+ (u_alt.cntC_q == 7'd117)
|
||||||
|
+ (u_alt.cntC_q == 7'd116)
|
||||||
|
+ (u_alt.cntC_q == 7'd115)
|
||||||
|
+ (u_alt.cntC_q == 7'd114)
|
||||||
|
+ (u_alt.cntC_q == 7'd113)
|
||||||
|
+ (u_alt.cntC_q == 7'd112)
|
||||||
|
+ (u_alt.cntC_q == 7'd111)
|
||||||
|
+ (u_alt.cntC_q == 7'd110)
|
||||||
|
+ (u_alt.cntC_q == 7'd109)
|
||||||
|
+ (u_alt.cntC_q == 7'd108)
|
||||||
|
+ (u_alt.cntC_q == 7'd107)
|
||||||
|
+ (u_alt.cntC_q == 7'd106)
|
||||||
|
+ (u_alt.cntC_q == 7'd105)
|
||||||
|
+ (u_alt.cntC_q == 7'd104)
|
||||||
|
+ (u_alt.cntC_q == 7'd103)
|
||||||
|
+ (u_alt.cntC_q == 7'd102)
|
||||||
|
+ (u_alt.cntC_q == 7'd101)
|
||||||
|
+ (u_alt.cntC_q == 7'd100)
|
||||||
|
+ (u_alt.cntC_q == 7'd99)
|
||||||
|
+ (u_alt.cntC_q == 7'd98)
|
||||||
|
+ (u_alt.cntC_q == 7'd97)
|
||||||
|
+ (u_alt.cntC_q == 7'd96)
|
||||||
|
+ (u_alt.cntC_q == 7'd95)
|
||||||
|
+ (u_alt.cntC_q == 7'd94)
|
||||||
|
+ (u_alt.cntC_q == 7'd93)
|
||||||
|
+ (u_alt.cntC_q == 7'd92)
|
||||||
|
+ (u_alt.cntC_q == 7'd91)
|
||||||
|
+ (u_alt.cntC_q == 7'd90)
|
||||||
|
+ (u_alt.cntC_q == 7'd89)
|
||||||
|
+ (u_alt.cntC_q == 7'd88)
|
||||||
|
+ (u_alt.cntC_q == 7'd87)
|
||||||
|
+ (u_alt.cntC_q == 7'd86)
|
||||||
|
+ (u_alt.cntC_q == 7'd85)
|
||||||
|
+ (u_alt.cntC_q == 7'd84)
|
||||||
|
+ (u_alt.cntC_q == 7'd83)
|
||||||
|
+ (u_alt.cntC_q == 7'd82)
|
||||||
|
+ (u_alt.cntC_q == 7'd81)
|
||||||
|
+ (u_alt.cntC_q == 7'd80)
|
||||||
|
+ (u_alt.cntC_q == 7'd79)
|
||||||
|
+ (u_alt.cntC_q == 7'd78)
|
||||||
|
+ (u_alt.cntC_q == 7'd77)
|
||||||
|
+ (u_alt.cntC_q == 7'd76)
|
||||||
|
+ (u_alt.cntC_q == 7'd75)
|
||||||
|
+ (u_alt.cntC_q == 7'd74)
|
||||||
|
+ (u_alt.cntC_q == 7'd73)
|
||||||
|
+ (u_alt.cntC_q == 7'd72)
|
||||||
|
+ (u_alt.cntC_q == 7'd71)
|
||||||
|
+ (u_alt.cntC_q == 7'd70)
|
||||||
|
+ (u_alt.cntC_q == 7'd69)
|
||||||
|
+ (u_alt.cntC_q == 7'd68)
|
||||||
|
+ (u_alt.cntC_q == 7'd67)
|
||||||
|
+ (u_alt.cntC_q == 7'd66)
|
||||||
|
+ (u_alt.cntC_q == 7'd65)
|
||||||
|
+ (u_alt.cntC_q == 7'd64)
|
||||||
|
+ (u_alt.cntC_q == 7'd63)
|
||||||
|
+ (u_alt.cntC_q == 7'd62)
|
||||||
|
+ (u_alt.cntC_q == 7'd61)
|
||||||
|
+ (u_alt.cntC_q == 7'd60)
|
||||||
|
+ (u_alt.cntC_q == 7'd59)
|
||||||
|
+ (u_alt.cntC_q == 7'd58)
|
||||||
|
+ (u_alt.cntC_q == 7'd57)
|
||||||
|
+ (u_alt.cntC_q == 7'd56)
|
||||||
|
+ (u_alt.cntC_q == 7'd55)
|
||||||
|
+ (u_alt.cntC_q == 7'd54)
|
||||||
|
+ (u_alt.cntC_q == 7'd53)
|
||||||
|
+ (u_alt.cntC_q == 7'd52)
|
||||||
|
+ (u_alt.cntC_q == 7'd51)
|
||||||
|
+ (u_alt.cntC_q == 7'd50)
|
||||||
|
+ (u_alt.cntC_q == 7'd49)
|
||||||
|
+ (u_alt.cntC_q == 7'd48)
|
||||||
|
+ (u_alt.cntC_q == 7'd47)
|
||||||
|
+ (u_alt.cntC_q == 7'd46)
|
||||||
|
+ (u_alt.cntC_q == 7'd45)
|
||||||
|
+ (u_alt.cntC_q == 7'd44)
|
||||||
|
+ (u_alt.cntC_q == 7'd43)
|
||||||
|
+ (u_alt.cntC_q == 7'd42)
|
||||||
|
+ (u_alt.cntC_q == 7'd41)
|
||||||
|
+ (u_alt.cntC_q == 7'd40)
|
||||||
|
+ (u_alt.cntC_q == 7'd39)
|
||||||
|
+ (u_alt.cntC_q == 7'd38)
|
||||||
|
+ (u_alt.cntC_q == 7'd37)
|
||||||
|
+ (u_alt.cntC_q == 7'd36)
|
||||||
|
+ (u_alt.cntC_q == 7'd35)
|
||||||
|
+ (u_alt.cntC_q == 7'd34)
|
||||||
|
+ (u_alt.cntC_q == 7'd33)
|
||||||
|
+ (u_alt.cntC_q == 7'd32)
|
||||||
|
+ (u_alt.cntC_q == 7'd31)
|
||||||
|
+ (u_alt.cntC_q == 7'd30)
|
||||||
|
+ (u_alt.cntC_q == 7'd29)
|
||||||
|
+ (u_alt.cntC_q == 7'd28)
|
||||||
|
+ (u_alt.cntC_q == 7'd27)
|
||||||
|
+ (u_alt.cntC_q == 7'd26)
|
||||||
|
+ (u_alt.cntC_q == 7'd25)
|
||||||
|
+ (u_alt.cntC_q == 7'd24)
|
||||||
|
+ (u_alt.cntC_q == 7'd23)
|
||||||
|
+ (u_alt.cntC_q == 7'd22)
|
||||||
|
+ (u_alt.cntC_q == 7'd21)
|
||||||
|
+ (u_alt.cntC_q == 7'd20)
|
||||||
|
+ (u_alt.cntC_q == 7'd19)
|
||||||
|
+ (u_alt.cntC_q == 7'd18)
|
||||||
|
+ (u_alt.cntC_q <= 7'd17);
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
`check(stupidWayToWriteConstOne_B, 1'b1);
|
||||||
|
|
||||||
|
`check(stupidWayToWriteConstOne_C, 1'b1);
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,6 @@ test.file_grep(test.obj_dir + "/obj_ref/Vref__stats.txt",
|
||||||
test.compile(verilator_flags2=[
|
test.compile(verilator_flags2=[
|
||||||
"--stats",
|
"--stats",
|
||||||
"--build",
|
"--build",
|
||||||
"-fno-dfg-post-inline",
|
|
||||||
"-fno-dfg-scoped",
|
|
||||||
"--exe",
|
"--exe",
|
||||||
"+incdir+" + test.obj_dir,
|
"+incdir+" + test.obj_dir,
|
||||||
"-Mdir", test.obj_dir + "/obj_opt",
|
"-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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:48:22: ... Location of offending driver
|
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;
|
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
|
... 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.
|
... 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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:17:17: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:17:17: ... Location of offending driver
|
||||||
17 | assign a[3:0] = i[3:0];
|
17 | assign a[3:0] = i[3:0];
|
||||||
| ^
|
| ^
|
||||||
t/t_dfg_multidriver_dfg_bad.v:18:17: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:18:17: ... Location of offending driver
|
||||||
18 | assign a[4:1] = ~i[4:1];
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:17:17: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:17:17: ... Location of offending driver
|
||||||
17 | assign a[3:0] = i[3:0];
|
17 | assign a[3:0] = i[3:0];
|
||||||
| ^
|
| ^
|
||||||
t/t_dfg_multidriver_dfg_bad.v:19:15: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:19:15: ... Location of offending driver
|
||||||
19 | assign a[3] = ~i[3];
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:20:17: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:20:17: ... Location of offending driver
|
||||||
20 | assign a[8:5] = i[8:5];
|
20 | assign a[8:5] = i[8:5];
|
||||||
| ^
|
| ^
|
||||||
t/t_dfg_multidriver_dfg_bad.v:21:17: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:21:17: ... Location of offending driver
|
||||||
21 | assign a[7:6] = ~i[7:6];
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:22:15: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:22:15: ... Location of offending driver
|
||||||
22 | assign a[9] = i[9];
|
22 | assign a[9] = i[9];
|
||||||
| ^
|
| ^
|
||||||
t/t_dfg_multidriver_dfg_bad.v:23:15: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:23:15: ... Location of offending driver
|
||||||
23 | assign a[9] = ~i[9];
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:27:12: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:27:12: ... Location of offending driver
|
||||||
27 | assign u = j;
|
27 | assign u = j;
|
||||||
| ^
|
| ^
|
||||||
t/t_dfg_multidriver_dfg_bad.v:28:12: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:28:12: ... Location of offending driver
|
||||||
28 | assign u = k;
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:31:12: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:31:12: ... Location of offending driver
|
||||||
31 | assign v = j;
|
31 | assign v = j;
|
||||||
| ^
|
| ^
|
||||||
t/t_dfg_multidriver_dfg_bad.v:32:11: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:32:11: ... Location of offending driver
|
||||||
32 | assign v[1] = i;
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:35:11: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:35:11: ... Location of offending driver
|
||||||
35 | assign w[0] = i;
|
35 | assign w[0] = i;
|
||||||
| ^
|
| ^
|
||||||
t/t_dfg_multidriver_dfg_bad.v:36:12: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:36:12: ... Location of offending driver
|
||||||
36 | assign w = j;
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:39:15: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:39:15: ... Location of offending driver
|
||||||
39 | assign x[3] = i;
|
39 | assign x[3] = i;
|
||||||
| ^
|
| ^
|
||||||
t/t_dfg_multidriver_dfg_bad.v:40:20: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:40:20: ... Location of offending driver
|
||||||
40 | assign x[3][3:2] = ~i[1:0];
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:53:12: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:53:12: ... Location of offending driver
|
||||||
53 | z[2:0] = i[2:0];
|
53 | z[2:0] = i[2:0];
|
||||||
| ^
|
| ^
|
||||||
t/t_dfg_multidriver_dfg_bad.v:58:15: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:58:15: ... Location of offending driver
|
||||||
58 | z[3:1] = i[3:1];
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:57:12: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:57:12: ... Location of offending driver
|
||||||
57 | z[6:4] = i[6:4];
|
57 | z[6:4] = i[6:4];
|
||||||
| ^
|
| ^
|
||||||
t/t_dfg_multidriver_dfg_bad.v:54:12: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:54:12: ... Location of offending driver
|
||||||
54 | z[7:5] = i[7:5];
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_dfg_multidriver_dfg_bad.v:54:12: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:54:12: ... Location of offending driver
|
||||||
54 | z[7:5] = i[7:5];
|
54 | z[7:5] = i[7:5];
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -117,4 +105,7 @@
|
||||||
t/t_dfg_multidriver_dfg_bad.v:66:24: ... Location of offending driver
|
t/t_dfg_multidriver_dfg_bad.v:66:24: ... Location of offending driver
|
||||||
66 | assign sub_2.a[10:5] = i[10:5];
|
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.compile(verilator_flags2=["--stats"])
|
||||||
|
|
||||||
test.file_grep(
|
test.file_grep(test.stats,
|
||||||
test.stats,
|
r'Optimizations, DFG, Synthesis, conv / non-representable \(oobsel\)\s+(\d+)', 1)
|
||||||
r'Optimizations, DFG scoped Synthesis, conv / non-representable \(oobsel\)\s+(\d+)', 1)
|
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ test.compile(verilator_flags2=[
|
||||||
def check(name, enabled):
|
def check(name, enabled):
|
||||||
name = name.lower()
|
name = name.lower()
|
||||||
name = re.sub(r'_', ' ', name)
|
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:
|
if enabled:
|
||||||
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt", pattern)
|
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt", pattern)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,12 @@ import vltest_bootstrap
|
||||||
|
|
||||||
test.scenarios('simulator_st')
|
test.scenarios('simulator_st')
|
||||||
|
|
||||||
test.compile(verilator_flags2=[
|
test.compile(verilator_flags2=["--binary", "--stats", "-fno-dfg-peephole"])
|
||||||
"--binary", "--stats", "-fno-dfg-pre-inline", "-fno-dfg-post-inline", "-fno-dfg-peephole"
|
|
||||||
])
|
|
||||||
|
|
||||||
test.execute()
|
test.execute()
|
||||||
|
|
||||||
if test.vlt:
|
if test.vlt:
|
||||||
test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, sels pushed down\s+(\d+)',
|
test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, sels pushed down\s+(\d+)', 49)
|
||||||
49)
|
test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, would be cyclic\s+(\d+)', 1)
|
||||||
test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, would be cyclic\s+(\d+)',
|
|
||||||
1)
|
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,13 @@ test.scenarios('simulator_st')
|
||||||
|
|
||||||
test.top_filename = "t/t_dfg_push_sel.v"
|
test.top_filename = "t/t_dfg_push_sel.v"
|
||||||
|
|
||||||
test.compile(verilator_flags2=[
|
test.compile(
|
||||||
"--binary", "--stats", "-fno-dfg-pre-inline", "-fno-dfg-post-inline", "-fno-dfg-peephole",
|
verilator_flags2=["--binary", "--stats", "-fno-dfg-peephole", "-fno-dfg-push-down-sels"])
|
||||||
"-fno-dfg-push-down-sels"
|
|
||||||
])
|
|
||||||
|
|
||||||
test.execute()
|
test.execute()
|
||||||
|
|
||||||
if test.vlt:
|
if test.vlt:
|
||||||
test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, sels pushed down\s+(\d+)',
|
test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, sels pushed down\s+(\d+)', 0)
|
||||||
0)
|
test.file_grep(test.stats, r'Optimizations, DFG, PushDownSels, would be cyclic\s+(\d+)', 0)
|
||||||
test.file_grep(test.stats, r'Optimizations, DFG scoped PushDownSels, would be cyclic\s+(\d+)',
|
|
||||||
0)
|
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
DFG 'scoped' patterns with depth 1
|
DFG patterns with depth 1
|
||||||
9 (CONCAT _A:1 _B:a):b
|
9 (CONCAT _A:1 _B:a):b
|
||||||
8 (REDXOR _A:a):1
|
8 (REDXOR _A:a):1
|
||||||
3 (NOT vA:a)*:a
|
3 (NOT vA:a)*:a
|
||||||
|
|
@ -16,7 +16,7 @@ DFG 'scoped' patterns with depth 1
|
||||||
1 (SEL@0 _A:a):b
|
1 (SEL@0 _A:a):b
|
||||||
1 (SEL@A _A:a):1
|
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
|
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 (AND (NOT vA:a)*:a (NOT vB:a)*:a):a
|
||||||
2 (REDXOR (AND _A:a _B:a):a):1
|
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@0 (REPLICATE _A:a cA:a)*:b):c
|
||||||
1 (SEL@A (AND _A:a _B:a)*:a):1
|
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
|
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 (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@0 (REPLICATE (NOT _A:a):a cA:a)*:b):c
|
||||||
1 (SEL@A (AND (NOT vA:a)*:a (NOT vB:a)*:a)*:a):1
|
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 (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 (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 (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.scenarios('vlt')
|
||||||
test.top_filename = "t/t_dfg_stats_patterns.v"
|
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(test.obj_dir + "/" + test.vm_prefix + "__stats_dfg_patterns.txt",
|
||||||
test.files_identical(fn, test.golden_filename)
|
test.golden_filename)
|
||||||
|
|
||||||
test.passes()
|
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",
|
"--stats",
|
||||||
"--build",
|
"--build",
|
||||||
"--fdfg-synthesize-all",
|
"--fdfg-synthesize-all",
|
||||||
"-fno-dfg-pre-inline",
|
|
||||||
"-fno-dfg-post-inline",
|
|
||||||
"--exe",
|
"--exe",
|
||||||
"+incdir+" + test.obj_dir,
|
"+incdir+" + test.obj_dir,
|
||||||
"-Mdir", test.obj_dir + "/obj_opt",
|
"-Mdir", test.obj_dir + "/obj_opt",
|
||||||
"--prefix", "Vopt",
|
"--prefix", "Vopt",
|
||||||
"-fno-const-before-dfg", # Otherwise V3Const makes testing painful
|
|
||||||
"-fno-split", # Dfg will take care of it
|
"-fno-split", # Dfg will take care of it
|
||||||
"--debug", "--debugi", "0", "--dumpi-tree", "0",
|
"--debug", "--debugi", "0", "--dumpi-tree", "0",
|
||||||
"-CFLAGS \"-I .. -I ../obj_ref\"",
|
"-CFLAGS \"-I .. -I ../obj_ref\"",
|
||||||
|
|
@ -85,13 +82,13 @@ test.compile(verilator_flags2=[
|
||||||
]) # yapf:disable
|
]) # yapf:disable
|
||||||
|
|
||||||
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt",
|
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)
|
nAlwaysSynthesized + nAlwaysReverted + nAlwaysNotSynthesized)
|
||||||
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt",
|
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)
|
nAlwaysSynthesized + nAlwaysReverted)
|
||||||
test.file_grep(test.obj_dir + "/obj_opt/Vopt__stats.txt",
|
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
|
# Execute test to check equivalence
|
||||||
test.execute(executable=test.obj_dir + "/obj_opt/Vopt")
|
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
|
... 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.
|
... 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: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
|
t/t_dfg_true_cycle_bad.v:10:23: Example path: o
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,7 @@
|
||||||
%Warning-DEPRECATED: Option order-clock-delay is deprecated and has no effect.
|
%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 '--clk' is deprecated and has no effect.
|
||||||
%Warning-DEPRECATED: Option '--no-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
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@ import vltest_bootstrap
|
||||||
|
|
||||||
test.scenarios('vlt')
|
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,
|
fails=True,
|
||||||
expect_filename=test.golden_filename)
|
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"
|
out_filename = test.obj_dir + "/V" + test.name + ".tree.json"
|
||||||
|
|
||||||
test.compile(v_flags2=[
|
test.compile(
|
||||||
"--no-json-edit-nums", "-fno-dfg-post-inline", "-fno-dfg-scoped", test.t_dir +
|
v_flags2=["--no-json-edit-nums", "-fno-dfg", test.t_dir + "/t_inst_tree_inl1_pub0.vlt"])
|
||||||
"/t_inst_tree_inl1_pub0.vlt"
|
|
||||||
])
|
|
||||||
|
|
||||||
if test.vlt_all:
|
if test.vlt_all:
|
||||||
test.file_grep(
|
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"
|
out_filename = test.obj_dir + "/V" + test.name + ".tree.json"
|
||||||
|
|
||||||
test.compile(v_flags2=[
|
test.compile(v_flags2=[
|
||||||
"--no-json-edit-nums", "-fno-dfg-post-inline", "t/" + test.name +
|
"--no-json-edit-nums", "t/" + test.name + ".vlt", test.wno_unopthreads_for_few_cores
|
||||||
".vlt", test.wno_unopthreads_for_few_cores
|
|
||||||
])
|
])
|
||||||
|
|
||||||
if test.vlt_all:
|
if test.vlt_all:
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,10 @@
|
||||||
"stmtsp": [
|
"stmtsp": [
|
||||||
{"type":"ASSIGNW","name":"","addr":"(IB)","loc":"d,56:12,56:13","dtypep":"(G)",
|
{"type":"ASSIGNW","name":"","addr":"(IB)","loc":"d,56:12,56:13","dtypep":"(G)",
|
||||||
"rhsp": [
|
"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": [
|
"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": []}
|
],"timingControlp": [],"strengthSpecp": []}
|
||||||
]}
|
]}
|
||||||
]},
|
]},
|
||||||
|
|
@ -88,19 +88,18 @@
|
||||||
]}
|
]}
|
||||||
],"filesp": [],
|
],"filesp": [],
|
||||||
"miscsp": [
|
"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": [
|
"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":"(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":"(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":"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":"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":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
{"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
||||||
"modulep": [
|
"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": [
|
"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": [
|
"stmtsp": [
|
||||||
{"type":"ASSIGNW","name":"","addr":"(JD)","loc":"d,56:12,56:13","dtypep":"(H)",
|
{"type":"ASSIGNW","name":"","addr":"(JD)","loc":"d,56:12,56:13","dtypep":"(H)",
|
||||||
"rhsp": [
|
"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": [
|
"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": []}
|
],"timingControlp": [],"strengthSpecp": []}
|
||||||
]}
|
]}
|
||||||
],"inlinesp": []}
|
],"inlinesp": []}
|
||||||
|
|
@ -168,19 +168,18 @@
|
||||||
]}
|
]}
|
||||||
],"filesp": [],
|
],"filesp": [],
|
||||||
"miscsp": [
|
"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": [
|
"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":"(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":"(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":"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":"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":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
{"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
||||||
"modulep": [
|
"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": [
|
"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": [],
|
],"filesp": [],
|
||||||
"miscsp": [
|
"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": [
|
"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":"(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": []},
|
{"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":"(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":"(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":"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":"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":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
{"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
||||||
"modulep": [
|
"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": [
|
"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": [
|
"stmtsp": [
|
||||||
{"type":"ASSIGNW","name":"","addr":"(X)","loc":"d,26:16,26:17","dtypep":"(G)",
|
{"type":"ASSIGNW","name":"","addr":"(X)","loc":"d,26:16,26:17","dtypep":"(G)",
|
||||||
"rhsp": [
|
"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": [
|
"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": []}
|
],"timingControlp": [],"strengthSpecp": []}
|
||||||
]}
|
]}
|
||||||
]},
|
]},
|
||||||
|
|
@ -44,29 +44,28 @@
|
||||||
"rhsp": [
|
"rhsp": [
|
||||||
{"type":"AND","name":"","addr":"(CB)","loc":"d,34:19,34:20","dtypep":"(G)",
|
{"type":"AND","name":"","addr":"(CB)","loc":"d,34:19,34:20","dtypep":"(G)",
|
||||||
"lhsp": [
|
"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": [
|
"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": [
|
"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": []}
|
],"timingControlp": [],"strengthSpecp": []}
|
||||||
]}
|
]}
|
||||||
]}
|
]}
|
||||||
],"filesp": [],
|
],"filesp": [],
|
||||||
"miscsp": [
|
"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": [
|
"typesp": [
|
||||||
{"type":"BASICDTYPE","name":"logic","addr":"(G)","loc":"d,30:16,30:18","dtypep":"(G)","keyword":"logic","generic":true,"rangep": []},
|
{"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":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
{"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0",
|
||||||
"modulep": [
|
"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": [
|
"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;
|
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.
|
%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
|
t/t_lint_always_comb_multidriven_bad.v:28:15: ... Location of offending driver
|
||||||
28 | assign out2 = d;
|
28 | assign out2 = d;
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -57,7 +56,6 @@
|
||||||
29 | always_comb out2 = 1'b0;
|
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.
|
%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
|
t/t_lint_always_comb_multidriven_bad.v:34:20: ... Location of offending driver
|
||||||
34 | always_comb out4 = 1'b0;
|
34 | always_comb out4 = 1'b0;
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -65,7 +63,6 @@
|
||||||
35 | assign out4 = d;
|
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.
|
%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
|
t/t_lint_always_comb_multidriven_bad.v:37:20: ... Location of offending driver
|
||||||
37 | always_comb out5 = 1'b0;
|
37 | always_comb out5 = 1'b0;
|
||||||
| ^
|
| ^
|
||||||
|
|
@ -73,7 +70,6 @@
|
||||||
38 | always_comb out5 = d;
|
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.
|
%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
|
t/t_lint_always_comb_multidriven_bad.v:40:20: ... Location of offending driver
|
||||||
40 | always_comb out6 = d;
|
40 | always_comb out6 = d;
|
||||||
| ^
|
| ^
|
||||||
|
|
|
||||||
|
|
@ -48,32 +48,28 @@
|
||||||
t/t_lint_always_comb_multidriven_bad.v:40:15: ... Location of other write
|
t/t_lint_always_comb_multidriven_bad.v:40:15: ... Location of other write
|
||||||
40 | always_comb out6 = d;
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_lint_always_comb_multidriven_bad.v:28:15: ... Location of offending driver
|
t/t_lint_always_comb_multidriven_bad.v:28:15: ... Location of offending driver
|
||||||
28 | assign out2 = d;
|
28 | assign out2 = d;
|
||||||
| ^
|
| ^
|
||||||
t/t_lint_always_comb_multidriven_bad.v:29:20: ... Location of offending driver
|
t/t_lint_always_comb_multidriven_bad.v:29:20: ... Location of offending driver
|
||||||
29 | always_comb out2 = 1'b0;
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_lint_always_comb_multidriven_bad.v:34:20: ... Location of offending driver
|
t/t_lint_always_comb_multidriven_bad.v:34:20: ... Location of offending driver
|
||||||
34 | always_comb out4 = 1'b0;
|
34 | always_comb out4 = 1'b0;
|
||||||
| ^
|
| ^
|
||||||
t/t_lint_always_comb_multidriven_bad.v:35:15: ... Location of offending driver
|
t/t_lint_always_comb_multidriven_bad.v:35:15: ... Location of offending driver
|
||||||
35 | assign out4 = d;
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_lint_always_comb_multidriven_bad.v:37:20: ... Location of offending driver
|
t/t_lint_always_comb_multidriven_bad.v:37:20: ... Location of offending driver
|
||||||
37 | always_comb out5 = 1'b0;
|
37 | always_comb out5 = 1'b0;
|
||||||
| ^
|
| ^
|
||||||
t/t_lint_always_comb_multidriven_bad.v:38:20: ... Location of offending driver
|
t/t_lint_always_comb_multidriven_bad.v:38:20: ... Location of offending driver
|
||||||
38 | always_comb out5 = d;
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_lint_always_comb_multidriven_bad.v:40:20: ... Location of offending driver
|
t/t_lint_always_comb_multidriven_bad.v:40:20: ... Location of offending driver
|
||||||
40 | always_comb out6 = d;
|
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.
|
%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.
|
||||||
: ... note: In instance 't'
|
|
||||||
t/t_lint_multidriven_coverage_bad.v:15:15: ... Location of offending driver
|
t/t_lint_multidriven_coverage_bad.v:15:15: ... Location of offending driver
|
||||||
15 | assign w[0] = a;
|
15 | assign w[0] = a;
|
||||||
| ^
|
| ^
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "--stats", test.pli_filename
|
||||||
test.execute()
|
test.execute()
|
||||||
|
|
||||||
if test.vlt:
|
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.file_grep(test.stats, r'SplitVar, packed variables split automatically\s+(\d+)', 1)
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue