2024-03-02 20:49:29 +01:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Convert DfgGraph to AstModule
|
|
|
|
|
//
|
|
|
|
|
// Code available from: https://verilator.org
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2025-01-01 14:30:25 +01:00
|
|
|
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
|
2024-03-02 20:49:29 +01:00
|
|
|
// 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
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// - Ensures intermediate values (other than simple memory references or
|
|
|
|
|
// constants) with multiple uses are assigned to variables
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
|
|
|
|
|
|
|
|
|
#include "V3Dfg.h"
|
|
|
|
|
#include "V3DfgPasses.h"
|
|
|
|
|
|
|
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
|
|
|
|
class DfgRegularize final {
|
|
|
|
|
DfgGraph& m_dfg; // The graph being processed
|
|
|
|
|
V3DfgRegularizeContext& m_ctx; // The optimization context for stats
|
|
|
|
|
|
2024-03-05 20:16:34 +01:00
|
|
|
// Prefix of temporary variable names
|
|
|
|
|
size_t m_nTmps = 0; // Number of temporaries added to this graph - for variable names only
|
2024-03-02 20:49:29 +01:00
|
|
|
|
|
|
|
|
// Insert intermediate variables for vertices with multiple sinks (or use an existing one)
|
|
|
|
|
DfgRegularize(DfgGraph& dfg, V3DfgRegularizeContext& ctx)
|
|
|
|
|
: m_dfg{dfg}
|
|
|
|
|
, m_ctx{ctx} {
|
|
|
|
|
|
2025-07-01 23:55:08 +02:00
|
|
|
// Scope cache for below
|
|
|
|
|
const bool scoped = !dfg.modulep();
|
|
|
|
|
DfgVertex::ScopeCache scopeCache;
|
|
|
|
|
|
2024-03-02 20:49:29 +01:00
|
|
|
// Ensure intermediate values used multiple times are written to variables
|
2024-03-26 00:06:25 +01:00
|
|
|
for (DfgVertex& vtx : m_dfg.opVertices()) {
|
2024-04-27 14:41:10 +02:00
|
|
|
const bool needsIntermediateVariable = [&]() {
|
|
|
|
|
// Anything that drives an SC variable needs an intermediate,
|
|
|
|
|
// as we can only assign simple variables to SC variables at runtime.
|
|
|
|
|
const bool hasScSink = vtx.findSink<DfgVertexVar>([](const DfgVertexVar& var) { //
|
|
|
|
|
return var.varp()->isSc();
|
|
|
|
|
});
|
|
|
|
|
if (hasScSink) return true;
|
|
|
|
|
// Operations without multiple sinks need no variables
|
|
|
|
|
if (!vtx.hasMultipleSinks()) return false;
|
|
|
|
|
// Array selects need no variables, they are just memory references
|
|
|
|
|
if (vtx.is<DfgArraySel>()) return false;
|
|
|
|
|
// Otherwise needs an intermediate variable
|
|
|
|
|
return true;
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
if (!needsIntermediateVariable) continue;
|
2024-03-02 20:49:29 +01:00
|
|
|
|
2025-06-16 13:25:44 +02:00
|
|
|
// This is an op that requires a result variable. Ensure it is
|
|
|
|
|
// assigned to one, and redirect other sinks read that variable.
|
|
|
|
|
if (DfgVarPacked* const varp = vtx.getResultVar()) {
|
|
|
|
|
// A variable already exists
|
|
|
|
|
UASSERT_OBJ(varp->arity() == 1, varp, "Result variable with multiple drivers");
|
2024-03-02 20:49:29 +01:00
|
|
|
FileLine* const flp = varp->driverFileLine(0);
|
|
|
|
|
varp->sourceEdge(0)->unlinkSource();
|
|
|
|
|
varp->resetSources();
|
2024-03-26 00:06:25 +01:00
|
|
|
vtx.replaceWith(varp);
|
|
|
|
|
varp->addDriver(flp, 0, &vtx);
|
2024-03-02 20:49:29 +01:00
|
|
|
} else {
|
2025-06-16 13:25:44 +02:00
|
|
|
// Need to create an intermediate variable
|
|
|
|
|
const std::string name = m_dfg.makeUniqueName("Regularize", m_nTmps);
|
|
|
|
|
FileLine* const flp = vtx.fileline();
|
2025-07-01 23:55:08 +02:00
|
|
|
AstScope* const scopep = scoped ? vtx.scopep(scopeCache) : nullptr;
|
2025-06-16 13:25:44 +02:00
|
|
|
DfgVarPacked* const newp
|
2025-07-01 23:55:08 +02:00
|
|
|
= m_dfg.makeNewVar(flp, name, vtx.dtypep(), scopep)->as<DfgVarPacked>();
|
2025-06-16 13:25:44 +02:00
|
|
|
++m_nTmps;
|
|
|
|
|
++m_ctx.m_temporariesIntroduced;
|
|
|
|
|
// Replace vertex with the variable and add back driver
|
|
|
|
|
vtx.replaceWith(newp);
|
|
|
|
|
newp->addDriver(vtx.fileline(), 0, &vtx);
|
2024-03-02 20:49:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
static void apply(DfgGraph& dfg, V3DfgRegularizeContext& ctx) { DfgRegularize{dfg, ctx}; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void V3DfgPasses::regularize(DfgGraph& dfg, V3DfgRegularizeContext& ctx) {
|
|
|
|
|
DfgRegularize::apply(dfg, ctx);
|
|
|
|
|
}
|