verilator/src/V3DfgContext.h

411 lines
17 KiB
C
Raw Normal View History

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Persistent context for DFG algorithms
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// 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: 2003-2026 Wilson Snyder
// 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"
2026-04-09 14:32:16 +02:00
#include "V3Ast.h"
#include "V3DfgPeepholePatterns.h"
2026-04-09 14:32:16 +02:00
#include "V3Error.h"
#include "V3File.h"
2026-04-09 14:32:16 +02:00
#include "V3Global.h"
#include "V3Stats.h"
class V3DfgContext;
2025-09-07 23:18:23 +02:00
//######################################################################
// Base class for all context objects
class V3DfgSubContext VL_NOT_FINAL {
const std::string m_name; // Pass/algorithm name, to be used in statistics
protected:
VL_DEFINE_DEBUG_FUNCTIONS;
V3DfgSubContext(const std::string& name)
: m_name{name} {}
void addStat(const std::string& what, double value) {
V3Stats::addStat("Optimizations, DFG, " + m_name + ", " + what, value);
}
};
2025-09-07 23:18:23 +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)
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
private:
V3DfgAstToDfgContext()
: V3DfgSubContext{"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);
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);
// 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,
"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()
: V3DfgSubContext{"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()
: V3DfgSubContext{"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:
explicit V3DfgCseContext(const std::string& label)
: V3DfgSubContext{"CSE " + label} {}
~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
VDouble0 m_resultEquations; // Number of result combinational equations
VDouble0 m_expressionsInlined; // Number of expressions inlined directly into the Ast
VDouble0 m_varRefsSubstituted; // Number of variable references substituted in the Ast
private:
V3DfgDfgToAstContext()
: V3DfgSubContext{"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);
addStat("expressions inlined", m_expressionsInlined);
addStat("var refs substituted", m_varRefsSubstituted);
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 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;
std::vector<AstNode*> m_deleteps; // AstVar/AstVarScope that can be deleted at the end
private:
V3DfgPeepholeContext()
: V3DfgSubContext{"Peephole"} {
const auto checkEnabled = [this](VDfgPeepholePattern id) {
std::string str{id.ascii()};
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
return c == '_' ? '-' : std::tolower(c);
});
m_enabled[id] = v3Global.opt.fDfgPeepholeEnabled(str);
};
#define OPTIMIZATION_CHECK_ENABLED(id, name) checkEnabled(VDfgPeepholePattern::id);
FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_CHECK_ENABLED)
#undef OPTIMIZATION_CHECK_ENABLED
}
~V3DfgPeepholeContext() {
for (AstNode* const nodep : m_deleteps) {
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
const auto emitStat = [this](VDfgPeepholePattern id) {
std::string str{id.ascii()};
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { //
return c == '_' ? ' ' : std::tolower(c);
});
addStat(str, m_count[id]);
};
#define OPTIMIZATION_EMIT_STATS(id, name) emitStat(VDfgPeepholePattern::id);
FOR_EACH_DFG_PEEPHOLE_OPTIMIZATION(OPTIMIZATION_EMIT_STATS)
#undef OPTIMIZATION_EMIT_STATS
}
};
class V3DfgPushDownSelsContext final : public V3DfgSubContext {
// Only V3DfgContext can create an instance
friend class V3DfgContext;
public:
// STATE
size_t m_pushedDown = 0; // Number of selects pushed down through concatenations
size_t m_wouldBeCyclic = 0; // Number of selects not pushed due to cycle
private:
V3DfgPushDownSelsContext()
: V3DfgSubContext{"PushDownSels"} {}
~V3DfgPushDownSelsContext() {
addStat("sels pushed down", m_pushedDown);
addStat("would be cyclic", m_wouldBeCyclic);
}
};
class V3DfgRegularizeContext final : public V3DfgSubContext {
// Only V3DfgContext can create an instance
friend class V3DfgContext;
public:
// STATE
std::vector<AstNode*> m_deleteps; // AstVar/AstVarScope that can be deleted at the end
VDouble0 m_usedVarsInlined; // Number of used variables inlined
VDouble0 m_unusedRemoved; // Number of unused vertices remoevd
VDouble0 m_temporariesIntroduced; // Number of temporaries introduced for reuse
private:
V3DfgRegularizeContext()
: V3DfgSubContext{"Regularize"} {}
~V3DfgRegularizeContext() {
for (AstNode* const nodep : m_deleteps) {
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
addStat("used variables inlined", m_usedVarsInlined);
addStat("unused vertices removed", m_unusedRemoved);
addStat("temporaries introduced", m_temporariesIntroduced);
}
};
class V3DfgRemoveUnobservableContext final : public V3DfgSubContext {
// Only V3DfgContext can create an instance
friend class V3DfgContext;
public:
// STATE
VDouble0 m_varsRemoved; // Number of variables removed from the Dfg
VDouble0 m_varsDeleted; // Number of variables removed from the Dfg and the Ast
VDouble0 m_logicRemoved; // Number of logic blocks removed from the Dfg
VDouble0 m_logicDeleted; // Number of logic blocks removed from the Dfg and the Ast
private:
V3DfgRemoveUnobservableContext()
: V3DfgSubContext{"RemoveUnobservable"} {}
~V3DfgRemoveUnobservableContext() {
addStat("variables removed", m_varsRemoved);
addStat("variables deleted", m_varsDeleted);
addStat("logic removed", m_logicRemoved);
addStat("logic deleted", m_logicDeleted);
}
};
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
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
2026-03-12 00:53:23 +01:00
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
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
// Reverted
VDouble0 revertNonSyn; // Reverted due to being driven from non-synthesizable vertex
VDouble0 revertMultidrive; // Reverted due to multiple drivers
// 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()
: V3DfgSubContext{"Synthesis"} {}
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() {
// 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);
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;
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");
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-09-07 23:18:23 +02:00
//######################################################################
// Top level V3DfgContext
class V3DfgContext final {
public:
// STATE
// Sub contexts - keep sorted by type
V3DfgAstToDfgContext m_ast2DfgContext;
V3DfgBinToOneHotContext m_binToOneHotContext;
V3DfgBreakCyclesContext m_breakCyclesContext;
V3DfgCseContext m_cseContext0{"1st"};
V3DfgCseContext m_cseContext1{"2nd"};
V3DfgDfgToAstContext m_dfg2AstContext;
V3DfgPeepholeContext m_peepholeContext;
V3DfgPushDownSelsContext m_pushDownSelsContext;
V3DfgRegularizeContext m_regularizeContext;
V3DfgRemoveUnobservableContext m_removeUnobservableContext;
V3DfgSynthesisContext m_synthContext;
// CONSTRUCTOR
V3DfgContext() = default;
~V3DfgContext() = default;
};
#endif //VERILATOR_V3DFGCONTEXT_H_