Jlm
Loading...
Searching...
No Matches
UnusedStateRemoval.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 David Metz <david.c.metz@ntnu.no>
3 * See COPYING for terms of redistribution.
4 */
5
10#include <jlm/rvsdg/gamma.hpp>
11#include <jlm/rvsdg/theta.hpp>
13
14#include <algorithm>
15
16namespace jlm::hls
17{
18
19static bool
24
25static bool
27{
28 if (argument.nusers() != 1)
29 {
30 return false;
31 }
32
33 return rvsdg::is<rvsdg::RegionResult>(*argument.Users().begin());
34}
35
36static bool
38{
39 auto argument = dynamic_cast<rvsdg::RegionArgument *>(result.origin());
40 return argument != nullptr;
41}
42
43static void
45{
46 const auto & op = dynamic_cast<llvm::LlvmLambdaOperation &>(lambdaNode.GetOperation());
47 auto & oldFunctionType = op.type();
48
49 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> newArgumentTypes;
50 for (size_t i = 0; i < oldFunctionType.NumArguments(); ++i)
51 {
52 auto argument = lambdaNode.subregion()->argument(i);
54 JLM_ASSERT(*argumentType == *argument->Type());
55
56 if (!IsPassthroughArgument(*argument))
57 {
59 }
60 }
61
62 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> newResultTypes;
63 for (size_t i = 0; i < oldFunctionType.NumResults(); ++i)
64 {
65 auto result = lambdaNode.subregion()->result(i);
66 auto resultType = oldFunctionType.Results()[i];
67 JLM_ASSERT(*resultType == *result->Type());
68
69 if (!IsPassthroughResult(*result))
70 {
71 newResultTypes.push_back(resultType);
72 }
73 }
74
77 *lambdaNode.region(),
80 op.name(),
81 op.linkage(),
82 op.callingConvention(),
83 op.attributes()));
84
86 for (const auto & ctxvar : lambdaNode.GetContextVars())
87 {
88 auto oldArgument = ctxvar.inner;
89 auto origin = ctxvar.input->origin();
90
91 auto newArgument = newLambda->AddContextVar(*origin).inner;
93 }
94
95 size_t new_i = 0;
96 auto newArgs = newLambda->GetFunctionArguments();
97 for (auto argument : lambdaNode.GetFunctionArguments())
98 {
99 if (!IsPassthroughArgument(*argument))
100 {
101 substitutionMap.insert(argument, newArgs[new_i]);
102 new_i++;
103 }
104 }
105 lambdaNode.subregion()->copy(newLambda->subregion(), substitutionMap);
106
107 std::vector<jlm::rvsdg::Output *> newResults;
108 for (auto result : lambdaNode.GetFunctionResults())
109 {
110 if (!IsPassthroughResult(*result))
111 {
112 newResults.push_back(&substitutionMap.lookup(*result->origin()));
113 }
114 }
115 auto newLambdaOutput = newLambda->finalize(newResults);
116
117 // TODO handle functions at other levels?
118 JLM_ASSERT(lambdaNode.region() == &lambdaNode.region()->graph()->GetRootRegion());
120 (*lambdaNode.output()->Users().begin()).region()
121 == &lambdaNode.region()->graph()->GetRootRegion());
122
123 JLM_ASSERT(lambdaNode.output()->nusers() == 1);
124 lambdaNode.region()->RemoveResults({ (*lambdaNode.output()->Users().begin()).index() });
128}
129
130// If this output has a single user and that single user happens to be
131// the exit variable of this gamma node, then return it.
132static std::optional<rvsdg::GammaNode::ExitVar>
134{
135 if (argument.nusers() == 1)
136 {
137 rvsdg::Input * user = &*argument.Users().begin();
139 {
140 return gammaNode.MapBranchResultExitVar(*user);
141 }
142 }
143 return std::nullopt;
144}
145
146static void
148{
149 std::vector<rvsdg::GammaNode::EntryVar> deadEntryVars;
150 std::vector<rvsdg::Output *> deadGammaOutputs;
151
152 for (const auto & entryvar : gammaNode.GetEntryVars())
153 {
154 std::optional<rvsdg::GammaNode::ExitVar> exitvar0 =
155 TryGetSingleUserExitVar(gammaNode, *entryvar.branchArgument[0]);
156
158 && std::all_of(
159 entryvar.branchArgument.begin(),
160 entryvar.branchArgument.end(),
161 [&gammaNode, &exitvar0](rvsdg::Output * argument) -> bool
162 {
163 auto exitvar = TryGetSingleUserExitVar(gammaNode, *argument);
164 return exitvar && exitvar->output == exitvar0->output;
165 });
166
167 if (shouldRemove)
168 {
169 exitvar0->output->divert_users(entryvar.input->origin());
170 deadEntryVars.push_back(entryvar);
171 deadGammaOutputs.push_back(exitvar0->output);
172 }
173 }
174
177}
178
179static void
181{
182 std::vector<rvsdg::ThetaNode::LoopVar> passthroughLoopVars;
183 for (auto & loopVar : thetaNode.GetLoopVars())
184 {
186 {
187 loopVar.output->divert_users(loopVar.input->origin());
188 passthroughLoopVars.emplace_back(loopVar);
189 }
190 }
191
192 thetaNode.RemoveLoopVars(std::move(passthroughLoopVars));
193}
194
195static void
197
198static void
200{
201 // Remove unused states from innermost regions first
202 for (size_t n = 0; n < structuralNode.nsubregions(); n++)
203 {
205 }
206
207 if (auto gammaNode = dynamic_cast<rvsdg::GammaNode *>(&structuralNode))
208 {
210 }
211 else if (auto thetaNode = dynamic_cast<rvsdg::ThetaNode *>(&structuralNode))
212 {
214 }
215 else if (auto lambdaNode = dynamic_cast<rvsdg::LambdaNode *>(&structuralNode))
216 {
218 }
219}
220
221static void
223{
224 for (auto & node : rvsdg::TopDownTraverser(&region))
225 {
226 if (auto structuralNode = dynamic_cast<rvsdg::StructuralNode *>(node))
227 {
229 }
230 }
231}
232
234
238
239void
244
245}
~UnusedStateRemoval() noexcept override
void Run(rvsdg::RvsdgModule &rvsdgModule, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
rvsdg::GraphExport * GetRvsdgExport() const noexcept
static std::unique_ptr< LlvmLambdaOperation > Create(std::shared_ptr< const jlm::rvsdg::FunctionType > type, std::string name, const jlm::llvm::Linkage &linkage, jlm::llvm::CallingConvention callingConvention, jlm::llvm::AttributeSet attributes)
Definition lambda.hpp:84
static std::shared_ptr< const FunctionType > Create(std::vector< std::shared_ptr< const jlm::rvsdg::Type > > argumentTypes, std::vector< std::shared_ptr< const jlm::rvsdg::Type > > resultTypes)
const std::vector< std::shared_ptr< const jlm::rvsdg::Type > > & Arguments() const noexcept
Conditional operator / pattern matching.
Definition gamma.hpp:99
void RemoveEntryVars(const std::vector< EntryVar > &entryVars)
Removes the given entry variables.
Definition gamma.cpp:459
std::vector< EntryVar > GetEntryVars() const
Gets all entry variables for this gamma.
Definition gamma.cpp:305
void RemoveExitVars(const std::vector< Output * > &gammaOutputs)
Removes the exit variables corresponding to the given gammaOutputs.
Definition gamma.cpp:439
ExitVar MapBranchResultExitVar(const rvsdg::Input &input) const
Maps gamma region exit result to exit variable description.
Definition gamma.cpp:409
static GraphExport & Create(Output &origin, std::string name)
Definition graph.cpp:62
Output * origin() const noexcept
Definition node.hpp:58
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
Definition lambda.cpp:141
const FunctionType & type() const noexcept
Definition lambda.hpp:36
UsersRange Users()
Definition node.hpp:354
size_t nusers() const noexcept
Definition node.hpp:280
Represents the argument of a region.
Definition region.hpp:41
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
void RemoveLoopVars(std::vector< LoopVar > loopVars)
Removes loop variables.
Definition theta.cpp:63
std::vector< LoopVar > GetLoopVars() const
Returns all loop variables.
Definition theta.cpp:176
Represents an RVSDG transformation.
#define JLM_ASSERT(x)
Definition common.hpp:16
static bool IsPassthroughResult(const rvsdg::Input &result)
static void RemoveUnusedStatesInRegion(rvsdg::Region &region)
static std::optional< rvsdg::GammaNode::ExitVar > TryGetSingleUserExitVar(rvsdg::GammaNode &gammaNode, rvsdg::Output &argument)
static void RemoveUnusedStatesFromThetaNode(rvsdg::ThetaNode &thetaNode)
static bool IsPassthroughArgument(const rvsdg::Output &argument)
static void RemoveUnusedStatesFromGammaNode(rvsdg::GammaNode &gammaNode)
static bool IsPassthroughLoopVar(const rvsdg::ThetaNode::LoopVar &loopVar)
static void RemoveUnusedStatesInStructuralNode(rvsdg::StructuralNode &structuralNode)
static void RemoveUnusedStatesFromLambda(rvsdg::LambdaNode &lambdaNode)
CallSummary ComputeCallSummary(const rvsdg::LambdaNode &lambdaNode)
static bool ThetaLoopVarIsInvariant(const ThetaNode::LoopVar &loopVar) noexcept
Definition theta.hpp:227
static void remove(Node *node)
Definition region.hpp:1035
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
detail::TopDownTraverserGeneric< false > TopDownTraverser
Traverser for visiting every node in a region in a top down order.
Description of a loop-carried variable.
Definition theta.hpp:50