Refactor DFG context objects (#6232)
- Move All DFG context objects to V3DfgContext.h - Add separate object for ast2dfg and dfg2ast passes - Factor out commonalities No functional change
This commit is contained in:
parent
94ef630490
commit
504884b7d5
|
@ -72,10 +72,11 @@ set(HEADERS
|
|||
V3Descope.h
|
||||
V3Dfg.h
|
||||
V3DfgCache.h
|
||||
V3DfgContext.h
|
||||
V3DfgOptimizer.h
|
||||
V3DfgPasses.h
|
||||
V3DfgPatternStats.h
|
||||
V3DfgPeephole.h
|
||||
V3DfgPeepholePatterns.h
|
||||
V3DfgVertices.h
|
||||
V3DiagSarif.h
|
||||
V3DupFinder.h
|
||||
|
|
|
@ -97,7 +97,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
// STATE
|
||||
|
||||
DfgGraph* const m_dfgp; // The graph being built
|
||||
V3DfgOptimizationContext& m_ctx; // The optimization context for stats
|
||||
V3DfgAstToDfgContext& m_ctx; // The context for stats
|
||||
bool m_foundUnhandled = false; // Found node not implemented as DFG or not implemented 'visit'
|
||||
std::vector<DfgVertex*> m_uncommittedVertices; // Vertices that we might decide to revert
|
||||
bool m_converting = false; // We are trying to convert some logic at the moment
|
||||
|
@ -886,7 +886,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
// CONSTRUCTOR
|
||||
explicit AstToDfgVisitor(RootType& root, V3DfgOptimizationContext& ctx)
|
||||
explicit AstToDfgVisitor(RootType& root, V3DfgAstToDfgContext& ctx)
|
||||
: m_dfgp{makeDfg(root)}
|
||||
, m_ctx{ctx} {
|
||||
// Build the DFG
|
||||
|
@ -922,15 +922,15 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
public:
|
||||
static DfgGraph* apply(RootType& root, V3DfgOptimizationContext& ctx) {
|
||||
static DfgGraph* apply(RootType& root, V3DfgAstToDfgContext& ctx) {
|
||||
return AstToDfgVisitor{root, ctx}.m_dfgp;
|
||||
}
|
||||
};
|
||||
|
||||
DfgGraph* V3DfgPasses::astToDfg(AstModule& module, V3DfgOptimizationContext& ctx) {
|
||||
return AstToDfgVisitor</* T_Scoped: */ false>::apply(module, ctx);
|
||||
DfgGraph* V3DfgPasses::astToDfg(AstModule& module, V3DfgContext& ctx) {
|
||||
return AstToDfgVisitor</* T_Scoped: */ false>::apply(module, ctx.m_ast2DfgContext);
|
||||
}
|
||||
|
||||
DfgGraph* V3DfgPasses::astToDfg(AstNetlist& netlist, V3DfgOptimizationContext& ctx) {
|
||||
return AstToDfgVisitor</* T_Scoped: */ true>::apply(netlist, ctx);
|
||||
DfgGraph* V3DfgPasses::astToDfg(AstNetlist& netlist, V3DfgContext& ctx) {
|
||||
return AstToDfgVisitor</* T_Scoped: */ true>::apply(netlist, ctx.m_ast2DfgContext);
|
||||
}
|
||||
|
|
|
@ -1109,8 +1109,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
std::pair<std::unique_ptr<DfgGraph>, bool>
|
||||
V3DfgPasses::breakCycles(const DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
|
||||
std::pair<std::unique_ptr<DfgGraph>, bool> //
|
||||
V3DfgPasses::breakCycles(const DfgGraph& dfg, V3DfgContext& ctx) {
|
||||
// Shorthand for dumping graph at given dump level
|
||||
const auto dump = [&](int level, const DfgGraph& dfg, const std::string& name) {
|
||||
if (dumpDfgLevel() >= level) dfg.dumpDotFilePrefixed(ctx.prefix() + "breakCycles-" + name);
|
||||
|
|
|
@ -0,0 +1,286 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Persistent context for DFG algorithms
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Various context objects hold data that need to persist across invocations
|
||||
// of a DFG algorithms.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3DFGCONTEXT_H_
|
||||
#define VERILATOR_V3DFGCONTEXT_H_
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3DfgPatternStats.h"
|
||||
#include "V3DfgPeepholePatterns.h"
|
||||
#include "V3File.h"
|
||||
#include "V3Stats.h"
|
||||
#include "V3String.h"
|
||||
|
||||
class V3DfgContext;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Base class for all context objects
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class V3DfgSubContext VL_NOT_FINAL {
|
||||
V3DfgContext& m_ctx; // The whole context
|
||||
const std::string m_label; // Label to add to stats, etc.
|
||||
const std::string m_name; // Pass/algorithm name, to be used in statistics
|
||||
|
||||
protected:
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
V3DfgSubContext(V3DfgContext& ctx, const std::string& label, const char* name)
|
||||
: m_ctx{ctx}
|
||||
, m_label{label}
|
||||
, m_name{name} {}
|
||||
|
||||
void addStat(const std::string& what, double value) {
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " " + m_name + ", " + what, value);
|
||||
}
|
||||
|
||||
public:
|
||||
inline const std::string& prefix() const;
|
||||
const std::string& label() const { return m_label; }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Contexts for various algorithms - keep sorted
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class V3DfgAstToDfgContext final : public V3DfgSubContext {
|
||||
// Only V3DfgContext can create an instance
|
||||
friend class V3DfgContext;
|
||||
|
||||
public:
|
||||
// STATE
|
||||
VDouble0 m_coalescedAssignments; // Number of partial assignments coalesced
|
||||
VDouble0 m_inputEquations; // Number of input combinational equations
|
||||
VDouble0 m_representable; // Number of combinational equations representable
|
||||
VDouble0 m_nonRepDType; // Equations non-representable due to data type
|
||||
VDouble0 m_nonRepImpure; // Equations non-representable due to impure node
|
||||
VDouble0 m_nonRepTiming; // Equations non-representable due to timing control
|
||||
VDouble0 m_nonRepLhs; // Equations non-representable due to lhs
|
||||
VDouble0 m_nonRepNode; // Equations non-representable due to node type
|
||||
VDouble0 m_nonRepUnknown; // Equations non-representable due to unknown node
|
||||
VDouble0 m_nonRepVarRef; // Equations non-representable due to variable reference
|
||||
VDouble0 m_nonRepWidth; // Equations non-representable due to width mismatch
|
||||
|
||||
private:
|
||||
V3DfgAstToDfgContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "AstToDfg"} {}
|
||||
~V3DfgAstToDfgContext() {
|
||||
addStat("coalesced assignments", m_coalescedAssignments);
|
||||
addStat("input equations", m_inputEquations);
|
||||
addStat("representable", m_representable);
|
||||
addStat("non-representable (dtype)", m_nonRepDType);
|
||||
addStat("non-representable (impure)", m_nonRepImpure);
|
||||
addStat("non-representable (timing)", m_nonRepTiming);
|
||||
addStat("non-representable (lhs)", m_nonRepLhs);
|
||||
addStat("non-representable (node)", m_nonRepNode);
|
||||
addStat("non-representable (unknown)", m_nonRepUnknown);
|
||||
addStat("non-representable (var ref)", m_nonRepVarRef);
|
||||
addStat("non-representable (width)", m_nonRepWidth);
|
||||
|
||||
// Check the stats are consistent
|
||||
UASSERT(m_representable //
|
||||
+ m_nonRepDType //
|
||||
+ m_nonRepImpure //
|
||||
+ m_nonRepTiming //
|
||||
+ m_nonRepLhs //
|
||||
+ m_nonRepNode //
|
||||
+ m_nonRepUnknown //
|
||||
+ m_nonRepVarRef //
|
||||
+ m_nonRepWidth //
|
||||
== m_inputEquations,
|
||||
"Inconsistent statistics");
|
||||
}
|
||||
};
|
||||
class V3DfgBinToOneHotContext final : public V3DfgSubContext {
|
||||
// Only V3DfgContext can create an instance
|
||||
friend class V3DfgContext;
|
||||
|
||||
public:
|
||||
// STATE
|
||||
VDouble0 m_decodersCreated; // Number of bianry to one-hot decoders created
|
||||
|
||||
private:
|
||||
V3DfgBinToOneHotContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "BinToOneHot"} {}
|
||||
~V3DfgBinToOneHotContext() { addStat("decoders created", m_decodersCreated); }
|
||||
};
|
||||
class V3DfgBreakCyclesContext final : public V3DfgSubContext {
|
||||
// Only V3DfgContext can create an instance
|
||||
friend class V3DfgContext;
|
||||
|
||||
public:
|
||||
// STATE
|
||||
VDouble0 m_nFixed; // Number of graphs that became acyclic
|
||||
VDouble0 m_nImproved; // Number of graphs that were imporoved but still cyclic
|
||||
VDouble0 m_nUnchanged; // Number of graphs that were left unchanged
|
||||
VDouble0 m_nTrivial; // Number of graphs that were not changed
|
||||
VDouble0 m_nImprovements; // Number of changes made to graphs
|
||||
|
||||
private:
|
||||
V3DfgBreakCyclesContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "BreakCycles"} {}
|
||||
~V3DfgBreakCyclesContext() {
|
||||
addStat("made acyclic", m_nFixed);
|
||||
addStat("improved", m_nImproved);
|
||||
addStat("left unchanged", m_nUnchanged);
|
||||
addStat("trivial", m_nTrivial);
|
||||
addStat("changes applied", m_nImprovements);
|
||||
}
|
||||
};
|
||||
class V3DfgCseContext final : public V3DfgSubContext {
|
||||
// Only V3DfgContext can create an instance
|
||||
friend class V3DfgContext;
|
||||
|
||||
public:
|
||||
// STATE
|
||||
VDouble0 m_eliminated; // Number of common sub-expressions eliminated
|
||||
|
||||
private:
|
||||
V3DfgCseContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "CSE"} {}
|
||||
~V3DfgCseContext() { addStat("expressions eliminated", m_eliminated); }
|
||||
};
|
||||
|
||||
class V3DfgDfgToAstContext final : public V3DfgSubContext {
|
||||
// Only V3DfgContext can create an instance
|
||||
friend class V3DfgContext;
|
||||
|
||||
public:
|
||||
// STATE
|
||||
VDouble0 m_resultEquations; // Number of result combinational equations
|
||||
|
||||
private:
|
||||
V3DfgDfgToAstContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "Dfg2Ast"} {}
|
||||
~V3DfgDfgToAstContext() { addStat("result equations", m_resultEquations); }
|
||||
};
|
||||
class V3DfgEliminateVarsContext final : public V3DfgSubContext {
|
||||
// Only V3DfgContext can create an instance
|
||||
friend class V3DfgContext;
|
||||
|
||||
public:
|
||||
// STATE
|
||||
VDouble0 m_varsReplaced; // Number of variables replaced
|
||||
VDouble0 m_varsRemoved; // Number of variables removed
|
||||
|
||||
private:
|
||||
V3DfgEliminateVarsContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "EliminateVars"} {}
|
||||
~V3DfgEliminateVarsContext() {
|
||||
addStat("variables replaced", m_varsReplaced);
|
||||
addStat("variables removed", m_varsRemoved);
|
||||
}
|
||||
};
|
||||
class V3DfgPeepholeContext final : public V3DfgSubContext {
|
||||
// Only V3DfgContext can create an instance
|
||||
friend class V3DfgContext;
|
||||
|
||||
public:
|
||||
// STATE
|
||||
// Enable flags for each optimization
|
||||
std::array<bool, VDfgPeepholePattern::_ENUM_END> m_enabled;
|
||||
// Count of applications for each optimization (for statistics)
|
||||
std::array<VDouble0, VDfgPeepholePattern::_ENUM_END> m_count;
|
||||
|
||||
private:
|
||||
V3DfgPeepholeContext(V3DfgContext& ctx, const std::string& label) VL_MT_DISABLED;
|
||||
~V3DfgPeepholeContext() VL_MT_DISABLED;
|
||||
};
|
||||
class V3DfgRegularizeContext final : public V3DfgSubContext {
|
||||
// Only V3DfgContext can create an instance
|
||||
friend class V3DfgContext;
|
||||
|
||||
public:
|
||||
// STATE
|
||||
VDouble0 m_temporariesIntroduced; // Number of temporaries introduced
|
||||
|
||||
private:
|
||||
V3DfgRegularizeContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "Regularize"} {}
|
||||
~V3DfgRegularizeContext() { addStat("temporaries introduced", m_temporariesIntroduced); }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Top level V3DfgContext
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class V3DfgContext final {
|
||||
const std::string m_label; // Label to add to stats, etc.
|
||||
const std::string m_prefix; // Prefix to add to file dumps (derived from label)
|
||||
|
||||
public:
|
||||
// STATE
|
||||
|
||||
// Global statistics
|
||||
VDouble0 m_modules; // Number of modules optimized
|
||||
|
||||
// Sub contexts - keep sorted by type
|
||||
V3DfgAstToDfgContext m_ast2DfgContext{*this, m_label};
|
||||
V3DfgBinToOneHotContext m_binToOneHotContext{*this, m_label};
|
||||
V3DfgBreakCyclesContext m_breakCyclesContext{*this, m_label};
|
||||
V3DfgCseContext m_cseContext0{*this, m_label + " 1st"};
|
||||
V3DfgCseContext m_cseContext1{*this, m_label + " 2nd"};
|
||||
V3DfgDfgToAstContext m_dfg2AstContext{*this, m_label};
|
||||
V3DfgEliminateVarsContext m_eliminateVarsContext{*this, m_label};
|
||||
V3DfgPeepholeContext m_peepholeContext{*this, m_label};
|
||||
V3DfgRegularizeContext m_regularizeContext{*this, m_label};
|
||||
|
||||
// Node pattern collector
|
||||
V3DfgPatternStats m_patternStats;
|
||||
|
||||
// CONSTRUCTOR
|
||||
explicit V3DfgContext(const std::string& label)
|
||||
: m_label{label}
|
||||
, m_prefix{VString::removeWhitespace(label) + "-"} {}
|
||||
|
||||
~V3DfgContext() {
|
||||
const string prefix = "Optimizations, DFG " + label() + " General, ";
|
||||
V3Stats::addStat(prefix + "modules", m_modules);
|
||||
|
||||
// Print the collected patterns
|
||||
if (v3Global.opt.stats()) {
|
||||
// Label to lowercase, without spaces
|
||||
std::string ident = label();
|
||||
std::transform(ident.begin(), ident.end(), ident.begin(), [](unsigned char c) { //
|
||||
return c == ' ' ? '_' : std::tolower(c);
|
||||
});
|
||||
|
||||
// File to dump to
|
||||
const std::string filename = v3Global.opt.hierTopDataDir() + "/"
|
||||
+ v3Global.opt.prefix() + "__stats_dfg_patterns__" + ident
|
||||
+ ".txt";
|
||||
// Open, write, close
|
||||
const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)};
|
||||
if (ofp->fail()) v3fatal("Can't write file: " << filename);
|
||||
m_patternStats.dump(label(), *ofp);
|
||||
}
|
||||
}
|
||||
|
||||
// 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_
|
|
@ -138,7 +138,7 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
// STATE
|
||||
|
||||
AstModule* const m_modp; // The parent/result module - This is nullptr when T_Scoped
|
||||
V3DfgOptimizationContext& m_ctx; // The optimization context for stats
|
||||
V3DfgDfgToAstContext& m_ctx; // The context for stats
|
||||
AstNodeExpr* m_resultp = nullptr; // The result node of the current traversal
|
||||
|
||||
// METHODS
|
||||
|
@ -276,7 +276,7 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
#include "V3Dfg__gen_dfg_to_ast.h"
|
||||
|
||||
// Constructor
|
||||
explicit DfgToAstVisitor(DfgGraph& dfg, V3DfgOptimizationContext& ctx)
|
||||
explicit DfgToAstVisitor(DfgGraph& dfg, V3DfgDfgToAstContext& ctx)
|
||||
: m_modp{dfg.modulep()}
|
||||
, m_ctx{ctx} {
|
||||
// Convert the graph back to combinational assignments
|
||||
|
@ -297,13 +297,13 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
}
|
||||
|
||||
public:
|
||||
static void apply(DfgGraph& dfg, V3DfgOptimizationContext& ctx) { DfgToAstVisitor{dfg, ctx}; }
|
||||
static void apply(DfgGraph& dfg, V3DfgDfgToAstContext& ctx) { DfgToAstVisitor{dfg, ctx}; }
|
||||
};
|
||||
|
||||
void V3DfgPasses::dfgToAst(DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
|
||||
void V3DfgPasses::dfgToAst(DfgGraph& dfg, V3DfgContext& ctx) {
|
||||
if (dfg.modulep()) {
|
||||
DfgToAstVisitor</* T_Scoped: */ false>::apply(dfg, ctx);
|
||||
DfgToAstVisitor</* T_Scoped: */ false>::apply(dfg, ctx.m_dfg2AstContext);
|
||||
} else {
|
||||
DfgToAstVisitor</* T_Scoped: */ true>::apply(dfg, ctx);
|
||||
DfgToAstVisitor</* T_Scoped: */ true>::apply(dfg, ctx.m_dfg2AstContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,7 +236,7 @@ void V3DfgOptimizer::extract(AstNetlist* netlistp) {
|
|||
V3Global::dumpCheckGlobalTree("dfg-extract", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
|
||||
static void process(DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
|
||||
static void process(DfgGraph& dfg, V3DfgContext& ctx) {
|
||||
// Extract the cyclic sub-graphs. We do this because a lot of the optimizations assume a
|
||||
// DAG, and large, mostly acyclic graphs could not be optimized due to the presence of
|
||||
// small cycles.
|
||||
|
@ -307,7 +307,7 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) {
|
|||
const VNUser2InUse user2InUse;
|
||||
const VNUser3InUse user3InUse;
|
||||
|
||||
V3DfgOptimizationContext ctx{label};
|
||||
V3DfgContext ctx{label};
|
||||
|
||||
if (!netlistp->topScopep()) {
|
||||
// Pre V3Scope application. Run on each module separately.
|
||||
|
|
|
@ -25,92 +25,6 @@
|
|||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
V3DfgBinToOneHotContext::~V3DfgBinToOneHotContext() {
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " BinToOneHot, decoders created",
|
||||
m_decodersCreated);
|
||||
}
|
||||
|
||||
V3DfgBreakCyclesContext::~V3DfgBreakCyclesContext() {
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " BreakCycles, made acyclic", m_nFixed);
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " BreakCycles, improved", m_nImproved);
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " BreakCycles, left unchanged",
|
||||
m_nUnchanged);
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " BreakCycles, trivial", m_nTrivial);
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " BreakCycles, changes applied",
|
||||
m_nImprovements);
|
||||
}
|
||||
|
||||
V3DfgCseContext::~V3DfgCseContext() {
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " CSE, expressions eliminated",
|
||||
m_eliminated);
|
||||
}
|
||||
|
||||
V3DfgRegularizeContext::~V3DfgRegularizeContext() {
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " Regularize, temporaries introduced",
|
||||
m_temporariesIntroduced);
|
||||
}
|
||||
|
||||
V3DfgEliminateVarsContext::~V3DfgEliminateVarsContext() {
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " EliminateVars, variables replaced",
|
||||
m_varsReplaced);
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " EliminateVars, variables removed",
|
||||
m_varsRemoved);
|
||||
}
|
||||
|
||||
static std::string getPrefix(const std::string& label) {
|
||||
if (label.empty()) return "";
|
||||
std::string str = VString::removeWhitespace(label);
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
|
||||
return c == ' ' ? '-' : std::tolower(c);
|
||||
});
|
||||
str += "-";
|
||||
return str;
|
||||
}
|
||||
|
||||
V3DfgOptimizationContext::V3DfgOptimizationContext(const std::string& label)
|
||||
: m_label{label}
|
||||
, m_prefix{getPrefix(label)} {}
|
||||
|
||||
V3DfgOptimizationContext::~V3DfgOptimizationContext() {
|
||||
const string prefix = "Optimizations, DFG " + m_label + " ";
|
||||
V3Stats::addStat(prefix + "General, modules", m_modules);
|
||||
V3Stats::addStat(prefix + "Ast2Dfg, coalesced assignments", m_coalescedAssignments);
|
||||
V3Stats::addStat(prefix + "Ast2Dfg, input equations", m_inputEquations);
|
||||
V3Stats::addStat(prefix + "Ast2Dfg, representable", m_representable);
|
||||
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (dtype)", m_nonRepDType);
|
||||
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (impure)", m_nonRepImpure);
|
||||
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (timing)", m_nonRepTiming);
|
||||
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (lhs)", m_nonRepLhs);
|
||||
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (node)", m_nonRepNode);
|
||||
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (unknown)", m_nonRepUnknown);
|
||||
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (var ref)", m_nonRepVarRef);
|
||||
V3Stats::addStat(prefix + "Ast2Dfg, non-representable (width)", m_nonRepWidth);
|
||||
V3Stats::addStat(prefix + "Dfg2Ast, result equations", m_resultEquations);
|
||||
|
||||
// Print the collected patterns
|
||||
if (v3Global.opt.stats()) {
|
||||
// Label to lowercase, without spaces
|
||||
std::string ident = m_label;
|
||||
std::transform(ident.begin(), ident.end(), ident.begin(), [](unsigned char c) { //
|
||||
return c == ' ' ? '_' : std::tolower(c);
|
||||
});
|
||||
|
||||
// File to dump to
|
||||
const std::string filename = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix()
|
||||
+ "__stats_dfg_patterns__" + ident + ".txt";
|
||||
// Open, write, close
|
||||
const std::unique_ptr<std::ofstream> ofp{V3File::new_ofstream(filename)};
|
||||
if (ofp->fail()) v3fatal("Can't write file: " << filename);
|
||||
m_patternStats.dump(m_label, *ofp);
|
||||
}
|
||||
|
||||
// Check the stats are consistent
|
||||
UASSERT(m_inputEquations
|
||||
== m_representable + m_nonRepDType + m_nonRepImpure + m_nonRepTiming + m_nonRepLhs
|
||||
+ m_nonRepNode + m_nonRepUnknown + m_nonRepVarRef + m_nonRepWidth,
|
||||
"Inconsistent statistics");
|
||||
}
|
||||
|
||||
// Common sub-expression elimination
|
||||
void V3DfgPasses::cse(DfgGraph& dfg, V3DfgCseContext& ctx) {
|
||||
// Remove common sub-expressions
|
||||
|
@ -592,7 +506,7 @@ void V3DfgPasses::eliminateVars(DfgGraph& dfg, V3DfgEliminateVarsContext& ctx) {
|
|||
for (AstNode* const nodep : replacedVariables) nodep->unlinkFrBack()->deleteTree();
|
||||
}
|
||||
|
||||
void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
|
||||
void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgContext& ctx) {
|
||||
// There is absolutely nothing useful we can do with a graph of size 2 or less
|
||||
if (dfg.size() <= 2) return;
|
||||
|
||||
|
|
|
@ -20,108 +20,11 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3DfgPatternStats.h"
|
||||
#include "V3DfgPeephole.h"
|
||||
#include "V3DfgContext.h"
|
||||
|
||||
class AstModule;
|
||||
class DfgGraph;
|
||||
|
||||
//===========================================================================
|
||||
// Various context objects hold data that need to persist across invocations
|
||||
// of a DFG pass.
|
||||
|
||||
class V3DfgBinToOneHotContext final {
|
||||
const std::string m_label; // Label to apply to stats
|
||||
|
||||
public:
|
||||
VDouble0 m_decodersCreated; // Number of bianry to one-hot decoders created
|
||||
explicit V3DfgBinToOneHotContext(const std::string& label)
|
||||
: m_label{label} {}
|
||||
~V3DfgBinToOneHotContext() VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
class V3DfgBreakCyclesContext final {
|
||||
const std::string m_label; // Label to apply to stats
|
||||
|
||||
public:
|
||||
VDouble0 m_nFixed; // Number of graphs that became acyclic
|
||||
VDouble0 m_nImproved; // Number of graphs that were imporoved but still cyclic
|
||||
VDouble0 m_nUnchanged; // Number of graphs that were left unchanged
|
||||
VDouble0 m_nTrivial; // Number of graphs that were not changed
|
||||
VDouble0 m_nImprovements; // Number of changes made to graphs
|
||||
explicit V3DfgBreakCyclesContext(const std::string& label)
|
||||
: m_label{label} {}
|
||||
~V3DfgBreakCyclesContext() VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
class V3DfgCseContext final {
|
||||
const std::string m_label; // Label to apply to stats
|
||||
|
||||
public:
|
||||
VDouble0 m_eliminated; // Number of common sub-expressions eliminated
|
||||
explicit V3DfgCseContext(const std::string& label)
|
||||
: m_label{label} {}
|
||||
~V3DfgCseContext() VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
class V3DfgRegularizeContext final {
|
||||
const std::string m_label; // Label to apply to stats
|
||||
|
||||
public:
|
||||
VDouble0 m_temporariesIntroduced; // Number of temporaries introduced
|
||||
|
||||
explicit V3DfgRegularizeContext(const std::string& label)
|
||||
: m_label{label} {}
|
||||
~V3DfgRegularizeContext() VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
class V3DfgEliminateVarsContext final {
|
||||
const std::string m_label; // Label to apply to stats
|
||||
|
||||
public:
|
||||
VDouble0 m_varsReplaced; // Number of variables replaced
|
||||
VDouble0 m_varsRemoved; // Number of variables removed
|
||||
|
||||
explicit V3DfgEliminateVarsContext(const std::string& label)
|
||||
: m_label{label} {}
|
||||
~V3DfgEliminateVarsContext() VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
class V3DfgOptimizationContext 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:
|
||||
VDouble0 m_modules; // Number of modules optimized
|
||||
VDouble0 m_coalescedAssignments; // Number of partial assignments coalesced
|
||||
VDouble0 m_inputEquations; // Number of input combinational equations
|
||||
VDouble0 m_representable; // Number of combinational equations representable
|
||||
VDouble0 m_nonRepDType; // Equations non-representable due to data type
|
||||
VDouble0 m_nonRepImpure; // Equations non-representable due to impure node
|
||||
VDouble0 m_nonRepTiming; // Equations non-representable due to timing control
|
||||
VDouble0 m_nonRepLhs; // Equations non-representable due to lhs
|
||||
VDouble0 m_nonRepNode; // Equations non-representable due to node type
|
||||
VDouble0 m_nonRepUnknown; // Equations non-representable due to unknown node
|
||||
VDouble0 m_nonRepVarRef; // Equations non-representable due to variable reference
|
||||
VDouble0 m_nonRepWidth; // Equations non-representable due to width mismatch
|
||||
VDouble0 m_resultEquations; // Number of result combinational equations
|
||||
|
||||
V3DfgBinToOneHotContext m_binToOneHotContext{m_label};
|
||||
V3DfgBreakCyclesContext m_breakCyclesContext{m_label};
|
||||
V3DfgCseContext m_cseContext0{m_label + " 1st"};
|
||||
V3DfgCseContext m_cseContext1{m_label + " 2nd"};
|
||||
V3DfgPeepholeContext m_peepholeContext{m_label};
|
||||
V3DfgRegularizeContext m_regularizeContext{m_label};
|
||||
V3DfgEliminateVarsContext m_eliminateVarsContext{m_label};
|
||||
|
||||
V3DfgPatternStats m_patternStats;
|
||||
|
||||
explicit V3DfgOptimizationContext(const std::string& label) VL_MT_DISABLED;
|
||||
~V3DfgOptimizationContext() VL_MT_DISABLED;
|
||||
|
||||
const std::string& prefix() const { return m_prefix; }
|
||||
};
|
||||
|
||||
namespace V3DfgPasses {
|
||||
//===========================================================================
|
||||
// Top level entry points
|
||||
|
@ -130,10 +33,10 @@ namespace V3DfgPasses {
|
|||
// Construct a DfGGraph representing the combinational logic in the given AstModule. The logic
|
||||
// that is represented by the graph is removed from the given AstModule. Returns the
|
||||
// constructed DfgGraph.
|
||||
DfgGraph* astToDfg(AstModule&, V3DfgOptimizationContext&) VL_MT_DISABLED;
|
||||
DfgGraph* astToDfg(AstModule&, V3DfgContext&) VL_MT_DISABLED;
|
||||
|
||||
// Same as above, but for the entire netlist, after V3Scope
|
||||
DfgGraph* astToDfg(AstNetlist&, V3DfgOptimizationContext&) VL_MT_DISABLED;
|
||||
DfgGraph* astToDfg(AstNetlist&, V3DfgContext&) VL_MT_DISABLED;
|
||||
|
||||
// Attempt to make the given cyclic graph into an acyclic, or "less cyclic"
|
||||
// equivalent. If the returned pointer is null, then no improvement was
|
||||
|
@ -142,14 +45,14 @@ DfgGraph* astToDfg(AstNetlist&, V3DfgOptimizationContext&) VL_MT_DISABLED;
|
|||
// graph is always independent of the original. If an imporoved graph is
|
||||
// returned, then the returned 'bool' flag indicated if the returned graph is
|
||||
// acyclic (flag 'true'), or still cyclic (flag 'false').
|
||||
std::pair<std::unique_ptr<DfgGraph>, bool> breakCycles(const DfgGraph&,
|
||||
V3DfgOptimizationContext&) VL_MT_DISABLED;
|
||||
std::pair<std::unique_ptr<DfgGraph>, bool> //
|
||||
breakCycles(const DfgGraph&, V3DfgContext&) VL_MT_DISABLED;
|
||||
|
||||
// Optimize the given DfgGraph
|
||||
void optimize(DfgGraph&, V3DfgOptimizationContext&) VL_MT_DISABLED;
|
||||
void optimize(DfgGraph&, V3DfgContext&) VL_MT_DISABLED;
|
||||
|
||||
// Convert DfgGraph back into Ast, and insert converted graph back into the Ast.
|
||||
void dfgToAst(DfgGraph&, V3DfgOptimizationContext&) VL_MT_DISABLED;
|
||||
void dfgToAst(DfgGraph&, V3DfgContext&) VL_MT_DISABLED;
|
||||
|
||||
//===========================================================================
|
||||
// Intermediate/internal operations
|
||||
|
|
|
@ -23,21 +23,20 @@
|
|||
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3DfgPeephole.h"
|
||||
|
||||
#include "V3Dfg.h"
|
||||
#include "V3DfgCache.h"
|
||||
#include "V3DfgPasses.h"
|
||||
#include "V3DfgPeepholePatterns.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
V3DfgPeepholeContext::V3DfgPeepholeContext(const std::string& label)
|
||||
: m_label{label} {
|
||||
V3DfgPeepholeContext::V3DfgPeepholeContext(V3DfgContext& ctx, const std::string& label)
|
||||
: V3DfgSubContext{ctx, label, "Peephole"} {
|
||||
const auto checkEnabled = [this](VDfgPeepholePattern id) {
|
||||
string str{id.ascii()};
|
||||
std::string str{id.ascii()};
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
|
||||
return c == '_' ? '-' : std::tolower(c);
|
||||
});
|
||||
|
@ -50,11 +49,11 @@ V3DfgPeepholeContext::V3DfgPeepholeContext(const std::string& label)
|
|||
|
||||
V3DfgPeepholeContext::~V3DfgPeepholeContext() {
|
||||
const auto emitStat = [this](VDfgPeepholePattern id) {
|
||||
string str{id.ascii()};
|
||||
std::string str{id.ascii()};
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
|
||||
return c == '_' ? ' ' : std::tolower(c);
|
||||
});
|
||||
V3Stats::addStat("Optimizations, DFG " + m_label + " Peephole, " + str, m_count[id]);
|
||||
addStat(str, m_count[id]);
|
||||
};
|
||||
#define OPTIMIZATION_EMIT_STATS(id, name) emitStat(VDfgPeepholePattern::id);
|
||||
FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_EMIT_STATS)
|
||||
|
|
|
@ -132,16 +132,4 @@ public:
|
|||
operator en() const { return m_e; }
|
||||
};
|
||||
|
||||
struct V3DfgPeepholeContext final {
|
||||
const std::string m_label; // Label to apply to stats
|
||||
|
||||
// Enable flags for each optimization
|
||||
std::array<bool, VDfgPeepholePattern::_ENUM_END> m_enabled;
|
||||
// Count of applications for each optimization (for statistics)
|
||||
std::array<VDouble0, VDfgPeepholePattern::_ENUM_END> m_count;
|
||||
|
||||
explicit V3DfgPeepholeContext(const std::string& label) VL_MT_DISABLED;
|
||||
~V3DfgPeepholeContext() VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -20,7 +20,7 @@ if not os.path.exists(root + "/.git"):
|
|||
# Read optimizations
|
||||
optimizations = []
|
||||
|
||||
hdrFile = "../src/V3DfgPeephole.h"
|
||||
hdrFile = "../src/V3DfgPeepholePatterns.h"
|
||||
with open(hdrFile, 'r', encoding="utf8") as hdrFh:
|
||||
prevOpt = ""
|
||||
lineno = 0
|
||||
|
|
|
@ -14,6 +14,6 @@ test.scenarios('vlt')
|
|||
test.compile(verilator_flags2=["--stats"])
|
||||
|
||||
test.file_grep(test.stats,
|
||||
r'Optimizations, DFG pre inline Ast2Dfg, non-representable \(impure\)\s+(\d+)', 1)
|
||||
r'Optimizations, DFG pre inline AstToDfg, non-representable \(impure\)\s+(\d+)', 1)
|
||||
|
||||
test.passes()
|
||||
|
|
Loading…
Reference in New Issue