2025-07-26 21:37:01 +02:00
|
|
|
// -*- 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;
|
|
|
|
|
|
2025-09-07 23:18:23 +02:00
|
|
|
//######################################################################
|
2025-07-26 21:37:01 +02:00
|
|
|
// 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; }
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-07 23:18:23 +02:00
|
|
|
//######################################################################
|
2025-07-26 21:37:01 +02:00
|
|
|
// Contexts for various algorithms - keep sorted
|
|
|
|
|
|
|
|
|
|
class V3DfgAstToDfgContext final : public V3DfgSubContext {
|
|
|
|
|
// Only V3DfgContext can create an instance
|
|
|
|
|
friend class V3DfgContext;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// STATE
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
VDouble0 m_inputs; // Number of input processes (logic constructs)
|
2025-07-26 21:37:01 +02:00
|
|
|
VDouble0 m_representable; // Number of combinational equations representable
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
VDouble0 m_nonRepCfg; // Non-representable due to failing to build CFG
|
|
|
|
|
VDouble0 m_nonRepLive; // Non-representable due to failing liveness analysis
|
|
|
|
|
VDouble0 m_nonRepVar; // Non-representable due to unsupported variable properties
|
2025-07-26 21:37:01 +02:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
V3DfgAstToDfgContext(V3DfgContext& ctx, const std::string& label)
|
|
|
|
|
: V3DfgSubContext{ctx, label, "AstToDfg"} {}
|
|
|
|
|
~V3DfgAstToDfgContext() {
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
addStat("input processes", m_inputs);
|
2025-07-26 21:37:01 +02:00
|
|
|
addStat("representable", m_representable);
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
addStat("non-representable (cfg)", m_nonRepCfg);
|
|
|
|
|
addStat("non-representable (live)", m_nonRepLive);
|
|
|
|
|
addStat("non-representable (var)", m_nonRepVar);
|
2025-07-26 21:37:01 +02:00
|
|
|
// Check the stats are consistent
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
UASSERT(m_representable + m_nonRepCfg + m_nonRepLive + m_nonRepVar == m_inputs,
|
2025-07-26 21:37:01 +02:00
|
|
|
"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
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
VDouble0 m_outputVariables; // Number of output variables
|
|
|
|
|
VDouble0 m_outputVariablesWithDefault; // Number of outptu variables with a default driver
|
2025-07-26 21:37:01 +02:00
|
|
|
VDouble0 m_resultEquations; // Number of result combinational equations
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
V3DfgDfgToAstContext(V3DfgContext& ctx, const std::string& label)
|
2025-08-08 23:53:12 +02:00
|
|
|
: V3DfgSubContext{ctx, label, "DfgToAst"} {}
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
~V3DfgDfgToAstContext() {
|
|
|
|
|
addStat("output variables", m_outputVariables);
|
|
|
|
|
addStat("output variables with default driver", m_outputVariablesWithDefault);
|
|
|
|
|
addStat("result equations", m_resultEquations);
|
|
|
|
|
}
|
2025-07-26 21:37:01 +02:00
|
|
|
};
|
|
|
|
|
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
|
2025-09-10 13:38:49 +02:00
|
|
|
VDouble0 m_temporariesOmitted; // Number of temporaries omitted as cheaper to re-compute
|
2025-07-26 21:37:01 +02:00
|
|
|
VDouble0 m_temporariesIntroduced; // Number of temporaries introduced
|
|
|
|
|
|
2025-09-10 13:38:49 +02:00
|
|
|
std::vector<AstNode*> m_deleteps; // AstVar/AstVarScope that can be deleted at the end
|
|
|
|
|
VDouble0 m_usedVarsReplaced; // Number of used variables replaced with equivalent ones
|
|
|
|
|
VDouble0 m_usedVarsInlined; // Number of used variables inlined
|
|
|
|
|
VDouble0 m_unusedRemoved; // Number of unused vertices remoevd
|
|
|
|
|
|
2025-07-26 21:37:01 +02:00
|
|
|
private:
|
|
|
|
|
V3DfgRegularizeContext(V3DfgContext& ctx, const std::string& label)
|
|
|
|
|
: V3DfgSubContext{ctx, label, "Regularize"} {}
|
2025-09-10 13:38:49 +02:00
|
|
|
~V3DfgRegularizeContext() {
|
|
|
|
|
for (AstNode* const nodep : m_deleteps) {
|
|
|
|
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
|
|
|
|
}
|
|
|
|
|
addStat("used variables replaced", m_usedVarsReplaced);
|
|
|
|
|
addStat("used variables inlined", m_usedVarsInlined);
|
|
|
|
|
addStat("unused vertices removed", m_unusedRemoved);
|
|
|
|
|
|
|
|
|
|
addStat("temporaries omitted", m_temporariesOmitted);
|
|
|
|
|
addStat("temporaries introduced", m_temporariesIntroduced);
|
|
|
|
|
}
|
2025-07-26 21:37:01 +02:00
|
|
|
};
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
class V3DfgSynthesisContext final : public V3DfgSubContext {
|
|
|
|
|
// Only V3DfgContext can create an instance
|
|
|
|
|
friend class V3DfgContext;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// STATE
|
|
|
|
|
|
|
|
|
|
// Stats for conversion
|
|
|
|
|
struct {
|
|
|
|
|
// Inputs
|
|
|
|
|
VDouble0 inputAssignments; // Number of input assignments
|
|
|
|
|
VDouble0 inputExpressions; // Number of input equations
|
|
|
|
|
// Successful
|
|
|
|
|
VDouble0 representable; // Number of representable constructs
|
|
|
|
|
// Unsuccessful
|
|
|
|
|
VDouble0 nonRepImpure; // Non representable: impure
|
|
|
|
|
VDouble0 nonRepDType; // Non representable: unsupported data type
|
|
|
|
|
VDouble0 nonRepLValue; // Non representable: unsupported LValue form
|
|
|
|
|
VDouble0 nonRepVarRef; // Non representable: unsupported var reference
|
2025-09-07 21:38:50 +02:00
|
|
|
VDouble0 nonRepOOBSel; // Non representable: out of bounds select
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
VDouble0 nonRepNode; // Non representable: unsupported AstNode type
|
|
|
|
|
VDouble0 nonRepUnknown; // Non representable: unhandled AstNode type
|
|
|
|
|
} m_conv;
|
|
|
|
|
|
|
|
|
|
// Stats for synthesis
|
|
|
|
|
struct {
|
|
|
|
|
// Inputs
|
|
|
|
|
VDouble0 inputAlways; // Number of always blocks attempted
|
|
|
|
|
VDouble0 inputAssign; // Number of continuous assignments attempted
|
|
|
|
|
// Successful
|
|
|
|
|
VDouble0 synthAlways; // Number of always blocks successfully synthesized
|
|
|
|
|
VDouble0 synthAssign; // Number of continuous assignments successfully synthesized
|
|
|
|
|
// Unsuccessful
|
|
|
|
|
VDouble0 nonSynConv; // Non synthesizable: non representable (above)
|
|
|
|
|
VDouble0 nonSynExtWrite; // Non synthesizable: has externally written variable
|
|
|
|
|
VDouble0 nonSynLoop; // Non synthesizable: loop in CFG
|
|
|
|
|
VDouble0 nonSynStmt; // Non synthesizable: unsupported statement
|
|
|
|
|
VDouble0 nonSynMultidrive; // Non synthesizable: multidriven value within statement
|
|
|
|
|
VDouble0 nonSynArray; // Non synthesizable: array type unhandled
|
|
|
|
|
VDouble0 nonSynLatch; // Non synthesizable: maybe latch
|
|
|
|
|
VDouble0 nonSynJoinInput; // Non synthesizable: needing to join input variable
|
|
|
|
|
VDouble0 nonSynFalseWrite; // Non synthesizable: does not write output
|
|
|
|
|
// Reverted
|
|
|
|
|
VDouble0 revertNonSyn; // Reverted due to being driven from non-synthesizable vertex
|
|
|
|
|
VDouble0 revertMultidrive; // Reverted due to multiple drivers
|
2025-08-25 14:47:45 +02:00
|
|
|
// Additional stats
|
|
|
|
|
VDouble0 cfgTrivial; // Trivial input CFGs
|
|
|
|
|
VDouble0 cfgSp; // Series-paralel input CFGs
|
|
|
|
|
VDouble0 cfgDag; // Generic loop free input CFGs
|
|
|
|
|
VDouble0 cfgCyclic; // Cyclic input CFGs
|
|
|
|
|
VDouble0 joinUsingPathPredicate; // Num control flow joins using full path predicate
|
|
|
|
|
VDouble0 joinUsingBranchCondition; // Num Control flow joins using dominating branch cond
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
} m_synt;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
V3DfgSynthesisContext(V3DfgContext& ctx, const std::string& label)
|
|
|
|
|
: V3DfgSubContext{ctx, label, "Synthesis"} {}
|
|
|
|
|
~V3DfgSynthesisContext() {
|
|
|
|
|
// Conversion statistics
|
|
|
|
|
addStat("conv / input assignments", m_conv.inputAssignments);
|
|
|
|
|
addStat("conv / input expressions", m_conv.inputExpressions);
|
|
|
|
|
addStat("conv / representable inputs", m_conv.representable);
|
|
|
|
|
addStat("conv / non-representable (impure)", m_conv.nonRepImpure);
|
|
|
|
|
addStat("conv / non-representable (dtype)", m_conv.nonRepDType);
|
|
|
|
|
addStat("conv / non-representable (lhs)", m_conv.nonRepLValue);
|
|
|
|
|
addStat("conv / non-representable (varref)", m_conv.nonRepVarRef);
|
2025-09-07 21:38:50 +02:00
|
|
|
addStat("conv / non-representable (oobsel)", m_conv.nonRepOOBSel);
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
addStat("conv / non-representable (node)", m_conv.nonRepNode);
|
|
|
|
|
addStat("conv / non-representable (unknown)", m_conv.nonRepUnknown);
|
|
|
|
|
VDouble0 nConvNonRep;
|
|
|
|
|
nConvNonRep += m_conv.nonRepImpure;
|
|
|
|
|
nConvNonRep += m_conv.nonRepDType;
|
|
|
|
|
nConvNonRep += m_conv.nonRepLValue;
|
|
|
|
|
nConvNonRep += m_conv.nonRepVarRef;
|
2025-09-07 21:38:50 +02:00
|
|
|
nConvNonRep += m_conv.nonRepOOBSel;
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
nConvNonRep += m_conv.nonRepNode;
|
|
|
|
|
nConvNonRep += m_conv.nonRepUnknown;
|
|
|
|
|
VDouble0 nConvExpect;
|
|
|
|
|
nConvExpect += m_conv.inputAssignments;
|
|
|
|
|
nConvExpect += m_conv.inputExpressions;
|
|
|
|
|
nConvExpect -= m_conv.representable;
|
|
|
|
|
UASSERT(nConvNonRep == nConvExpect, "Inconsistent statistics / conv");
|
|
|
|
|
|
|
|
|
|
// Synthesis statistics
|
|
|
|
|
addStat("synt / always blocks considered", m_synt.inputAlways);
|
|
|
|
|
addStat("synt / always blocks synthesized", m_synt.synthAlways);
|
|
|
|
|
addStat("synt / continuous assignments considered", m_synt.inputAssign);
|
|
|
|
|
addStat("synt / continuous assignments synthesized", m_synt.synthAssign);
|
|
|
|
|
addStat("synt / non-synthesizable (conv)", m_synt.nonSynConv);
|
|
|
|
|
addStat("synt / non-synthesizable (ext write)", m_synt.nonSynExtWrite);
|
|
|
|
|
addStat("synt / non-synthesizable (loop)", m_synt.nonSynLoop);
|
|
|
|
|
addStat("synt / non-synthesizable (stmt)", m_synt.nonSynStmt);
|
|
|
|
|
addStat("synt / non-synthesizable (multidrive)", m_synt.nonSynMultidrive);
|
|
|
|
|
addStat("synt / non-synthesizable (array)", m_synt.nonSynArray);
|
|
|
|
|
addStat("synt / non-synthesizable (latch)", m_synt.nonSynLatch);
|
|
|
|
|
addStat("synt / non-synthesizable (join input)", m_synt.nonSynJoinInput);
|
|
|
|
|
addStat("synt / non-synthesizable (false write)", m_synt.nonSynFalseWrite);
|
|
|
|
|
addStat("synt / reverted (non-synthesizable)", m_synt.revertNonSyn);
|
|
|
|
|
addStat("synt / reverted (multidrive)", m_synt.revertMultidrive);
|
|
|
|
|
|
|
|
|
|
VDouble0 nSyntNonSyn;
|
|
|
|
|
nSyntNonSyn += m_synt.nonSynConv;
|
|
|
|
|
nSyntNonSyn += m_synt.nonSynExtWrite;
|
|
|
|
|
nSyntNonSyn += m_synt.nonSynLoop;
|
|
|
|
|
nSyntNonSyn += m_synt.nonSynStmt;
|
|
|
|
|
nSyntNonSyn += m_synt.nonSynMultidrive;
|
|
|
|
|
nSyntNonSyn += m_synt.nonSynArray;
|
|
|
|
|
nSyntNonSyn += m_synt.nonSynLatch;
|
|
|
|
|
nSyntNonSyn += m_synt.nonSynJoinInput;
|
|
|
|
|
nSyntNonSyn += m_synt.nonSynFalseWrite;
|
|
|
|
|
VDouble0 nSyntExpect;
|
|
|
|
|
nSyntExpect += m_synt.inputAlways;
|
|
|
|
|
nSyntExpect += m_synt.inputAssign;
|
|
|
|
|
nSyntExpect -= m_synt.synthAlways;
|
|
|
|
|
nSyntExpect -= m_synt.synthAssign;
|
|
|
|
|
UASSERT(nSyntNonSyn == nSyntExpect, "Inconsistent statistics / synt");
|
2025-08-25 14:47:45 +02:00
|
|
|
|
|
|
|
|
addStat("synt / input CFG trivial", m_synt.cfgTrivial);
|
|
|
|
|
addStat("synt / input CFG sp", m_synt.cfgSp);
|
|
|
|
|
addStat("synt / input CFG dag", m_synt.cfgDag);
|
|
|
|
|
addStat("synt / input CFG cyclic", m_synt.cfgCyclic);
|
|
|
|
|
|
|
|
|
|
addStat("synt / joins using path predicate", m_synt.joinUsingPathPredicate);
|
|
|
|
|
addStat("synt / joins using branch condition", m_synt.joinUsingBranchCondition);
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
}
|
|
|
|
|
};
|
2025-07-26 21:37:01 +02:00
|
|
|
|
2025-09-07 23:18:23 +02:00
|
|
|
//######################################################################
|
2025-07-26 21:37:01 +02:00
|
|
|
// Top level V3DfgContext
|
|
|
|
|
|
|
|
|
|
class V3DfgContext final {
|
|
|
|
|
const std::string m_label; // Label to add to stats, etc.
|
|
|
|
|
const std::string m_prefix; // Prefix to add to file dumps (derived from label)
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// STATE
|
|
|
|
|
|
|
|
|
|
// Global statistics
|
|
|
|
|
VDouble0 m_modules; // Number of modules optimized
|
|
|
|
|
|
|
|
|
|
// Sub contexts - keep sorted by type
|
|
|
|
|
V3DfgAstToDfgContext m_ast2DfgContext{*this, m_label};
|
|
|
|
|
V3DfgBinToOneHotContext m_binToOneHotContext{*this, m_label};
|
|
|
|
|
V3DfgBreakCyclesContext m_breakCyclesContext{*this, m_label};
|
|
|
|
|
V3DfgCseContext m_cseContext0{*this, m_label + " 1st"};
|
|
|
|
|
V3DfgCseContext m_cseContext1{*this, m_label + " 2nd"};
|
|
|
|
|
V3DfgDfgToAstContext m_dfg2AstContext{*this, m_label};
|
|
|
|
|
V3DfgPeepholeContext m_peepholeContext{*this, m_label};
|
|
|
|
|
V3DfgRegularizeContext m_regularizeContext{*this, m_label};
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
V3DfgSynthesisContext m_synthContext{*this, m_label};
|
2025-07-26 21:37:01 +02:00
|
|
|
|
|
|
|
|
// Node pattern collector
|
|
|
|
|
V3DfgPatternStats m_patternStats;
|
|
|
|
|
|
|
|
|
|
// CONSTRUCTOR
|
|
|
|
|
explicit V3DfgContext(const std::string& label)
|
|
|
|
|
: m_label{label}
|
|
|
|
|
, m_prefix{VString::removeWhitespace(label) + "-"} {}
|
|
|
|
|
|
|
|
|
|
~V3DfgContext() {
|
2025-08-20 19:21:24 +02:00
|
|
|
const string front = "Optimizations, DFG " + label() + " General, ";
|
|
|
|
|
V3Stats::addStat(front + "modules", m_modules);
|
2025-07-26 21:37:01 +02:00
|
|
|
|
|
|
|
|
// 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_
|