Jlm
Loading...
Searching...
No Matches
Phi.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2012 2013 2014 2015 Nico Reißmann <nico.reissmann@gmail.com>
3 * Copyright 2012 2013 2014 2025 Helge Bahmann <hcb@chaoticmind.net>
4 * See COPYING for terms of redistribution.
5 */
6
7#include <algorithm>
8#include <functional>
9
10#include <jlm/rvsdg/Phi.hpp>
11
12namespace jlm::rvsdg
13{
14
16
17std::string
19{
20 return "Phi";
21}
22
23std::unique_ptr<Operation>
25{
26 return std::make_unique<PhiOperation>(*this);
27}
28
29PhiNode::~PhiNode() = default;
30
31[[nodiscard]] const PhiOperation &
33{
34 // Phi nodes are not parameterized, so we can return operation singleton.
35 static const PhiOperation singleton;
36 return singleton;
37}
38
41{
42 auto input = addInput(std::make_unique<StructuralInput>(this, &origin, origin.Type()), true);
43 auto & argument =
44 subregion()->addArgument(std::make_unique<RegionArgument>(subregion(), input, origin.Type()));
45
46 return ContextVar{ input, &argument };
47}
48
49[[nodiscard]] std::vector<PhiNode::ContextVar>
51{
52 std::vector<PhiNode::ContextVar> vars;
53
54 for (size_t n = 0; n < ninputs(); ++n)
55 {
56 vars.push_back(ContextVar{ input(n), subregion()->argument(n + subregion()->nresults()) });
57 }
58
59 return vars;
60}
61
62[[nodiscard]] std::vector<PhiNode::FixVar>
64{
65 std::vector<PhiNode::FixVar> vars;
66
67 for (std::size_t n = 0; n < noutputs(); ++n)
68 {
69 vars.push_back(FixVar{ subregion()->argument(n), subregion()->result(n), output(n) });
70 }
71
72 return vars;
73}
74
75[[nodiscard]] std::optional<PhiNode::FixVar>
76PhiNode::MapArgumentFixVar(const rvsdg::Output & argument) const noexcept
77{
79 if (argument.index() < subregion()->nresults())
80 {
81 size_t n = argument.index();
82 return FixVar{ subregion()->argument(n), subregion()->result(n), output(n) };
83 }
84 else
85 {
86 return std::nullopt;
87 }
88}
89
91PhiNode::MapResultFixVar(const rvsdg::Input & result) const noexcept
92{
94 return FixVar{ subregion()->argument(result.index()),
95 subregion()->result(result.index()),
96 output(result.index()) };
97}
98
100PhiNode::MapOutputFixVar(const rvsdg::Output & output) const noexcept
101{
103 return FixVar{ subregion()->argument(output.index()),
104 subregion()->result(output.index()),
105 PhiNode::output(output.index()) };
106}
107
109PhiNode::MapInputContextVar(const rvsdg::Input & input) const noexcept
110{
112 return ContextVar{ PhiNode::input(input.index()),
113 subregion()->argument(input.index() + subregion()->nresults()) };
114}
115
116[[nodiscard]] std::optional<PhiNode::ContextVar>
117PhiNode::MapArgumentContextVar(const rvsdg::Output & argument) const noexcept
118{
120 if (argument.index() >= subregion()->nresults())
121 {
122 size_t n = argument.index();
123 return ContextVar{ input(n - subregion()->nresults()), subregion()->argument(n) };
124 }
125 else
126 {
127 return std::nullopt;
128 }
129}
130
131[[nodiscard]] std::variant<PhiNode::FixVar, PhiNode::ContextVar>
132PhiNode::MapArgument(const rvsdg::Output & argument) const noexcept
133{
135 if (auto ctxvar = MapArgumentContextVar(argument))
136 {
137 return *ctxvar;
138 }
139 else if (auto fixvar = MapArgumentFixVar(argument))
140 {
141 return *fixvar;
142 }
143 else
144 {
145 JLM_UNREACHABLE("phi binder is neither context nor fixpoint variable");
146 }
147}
148
149void
150PhiNode::RemoveContextVars(std::vector<ContextVar> vars)
151{
154 for (const auto [input, argument] : vars)
155 {
156 argumentIndices.insert(argument->index());
157 inputIndices.insert(input->index());
158 }
159
162
165}
166
167void
168PhiNode::RemoveFixVars(std::vector<FixVar> vars)
169{
173 for (const auto & [argument, result, output] : vars)
174 {
175 resultIndices.insert(result->index());
176 argumentIndices.insert(argument->index());
177 outputIndices.insert(output->index());
178 }
179
182
185
188}
189
190PhiNode *
192{
194 pb.begin(region);
195
196 // add context variables
198 for (const auto & var : GetContextVars())
199 {
200 auto & origin = smap.lookup(*var.input->origin());
201 auto newcv = pb.AddContextVar(origin);
202 subregionmap.insert(var.inner, newcv.inner);
203 }
204
205 // add recursion variables
206 for (auto var : GetFixVars())
207 {
208 auto newrv = pb.AddFixVar(var.recref->Type());
209 subregionmap.insert(var.recref, newrv.recref);
210 }
211
212 // copy subregion
213 subregion()->copy(pb.subregion(), subregionmap);
214
215 // finalize phi
216 for (auto var : GetFixVars())
217 {
218 auto neworigin = &subregionmap.lookup(*var.result->origin());
219 var.result->divert_to(neworigin);
220 }
221
222 return pb.end();
223}
224
225std::vector<rvsdg::LambdaNode *>
227{
228 std::function<void(const PhiNode &, std::vector<rvsdg::LambdaNode *> &)> extractLambdaNodes =
229 [&](auto & phiNode, auto & lambdaNodes)
230 {
231 for (auto & node : phiNode.subregion()->Nodes())
232 {
233 if (auto lambdaNode = dynamic_cast<rvsdg::LambdaNode *>(&node))
234 {
235 lambdaNodes.push_back(lambdaNode);
236 }
237 else if (auto innerPhiNode = dynamic_cast<const PhiNode *>(&node))
238 {
239 extractLambdaNodes(*innerPhiNode, lambdaNodes);
240 }
241 }
242 };
243
244 std::vector<rvsdg::LambdaNode *> lambdaNodes;
245 extractLambdaNodes(phiNode, lambdaNodes);
246
247 return lambdaNodes;
248}
249
252{
253 return node_->AddContextVar(origin);
254}
255
257PhiBuilder::AddFixVar(std::shared_ptr<const jlm::rvsdg::Type> type)
258{
259 auto output = node_->addOutput(std::make_unique<StructuralOutput>(node_, type));
260 auto & argument = subregion()->insertArgument(
261 subregion()->nresults(),
262 std::make_unique<RegionArgument>(subregion(), nullptr, type));
263 auto & result =
264 subregion()->addResult(std::make_unique<RegionResult>(subregion(), &argument, output, type));
265
266 return PhiNode::FixVar{ &argument, &result, output };
267}
268
269PhiNode *
271{
272 if (!node_)
273 return nullptr;
274
275 for (auto var : node_->GetFixVars())
276 {
277 if (var.result->origin() == var.recref)
278 throw util::Error("Recursion variable not properly set.");
279 }
280
281 auto node = node_;
282 node_ = nullptr;
283
284 return node;
285}
286
287}
size_t index() const noexcept
Definition node.hpp:52
NodeInput * input(size_t index) const noexcept
Definition node.hpp:615
NodeOutput * output(size_t index) const noexcept
Definition node.hpp:650
size_t RemoveInputs(const util::HashSet< size_t > &indices)
Definition node.cpp:306
rvsdg::Region * region() const noexcept
Definition node.hpp:761
size_t ninputs() const noexcept
Definition node.hpp:609
size_t noutputs() const noexcept
Definition node.hpp:644
size_t RemoveOutputs(const util::HashSet< size_t > &indices)
Definition node.cpp:342
size_t index() const noexcept
Definition node.hpp:274
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:366
PhiNode * end()
Definition Phi.cpp:270
PhiNode::ContextVar AddContextVar(jlm::rvsdg::Output &origin)
Definition Phi.cpp:251
PhiNode::FixVar AddFixVar(std::shared_ptr< const jlm::rvsdg::Type > type)
Definition Phi.cpp:257
void begin(rvsdg::Region *parent)
Definition Phi.hpp:355
rvsdg::Region * subregion() const noexcept
Definition Phi.hpp:349
A phi node represents the fixpoint of mutually recursive definitions.
Definition Phi.hpp:46
FixVar MapResultFixVar(const rvsdg::Input &result) const noexcept
Maps region result to fixpoint variable.
Definition Phi.cpp:91
PhiNode * copy(rvsdg::Region *region, rvsdg::SubstitutionMap &smap) const override
Copy a node with substitutions.
Definition Phi.cpp:191
ContextVar MapInputContextVar(const rvsdg::Input &input) const noexcept
Maps input to context variable.
Definition Phi.cpp:109
std::optional< ContextVar > MapArgumentContextVar(const rvsdg::Output &argument) const noexcept
Attempts to map bound variable reference to context variable.
Definition Phi.cpp:117
static std::vector< rvsdg::LambdaNode * > ExtractLambdaNodes(const PhiNode &phiNode)
Definition Phi.cpp:226
std::vector< FixVar > GetFixVars() const noexcept
Gets all fixpoint variables.
Definition Phi.cpp:63
void RemoveContextVars(std::vector< ContextVar > vars)
Removes context variables from phi node.
Definition Phi.cpp:150
FixVar MapOutputFixVar(const rvsdg::Output &output) const noexcept
Maps output to fixpoint variable.
Definition Phi.cpp:100
std::vector< ContextVar > GetContextVars() const noexcept
Gets all bound context variables.
Definition Phi.cpp:50
std::optional< FixVar > MapArgumentFixVar(const rvsdg::Output &argument) const noexcept
Tries to map region argument to fixpoint variable.
Definition Phi.cpp:76
rvsdg::Region * subregion() const noexcept
Definition Phi.hpp:320
std::variant< FixVar, ContextVar > MapArgument(const rvsdg::Output &argument) const noexcept
Maps region argument to its function.
Definition Phi.cpp:132
ContextVar AddContextVar(jlm::rvsdg::Output &origin)
Adds a context variable to the phi node.
Definition Phi.cpp:40
void RemoveFixVars(std::vector< FixVar > vars)
Removes fixpoint variables from the phi node.
Definition Phi.cpp:168
const PhiOperation & GetOperation() const noexcept override
Definition Phi.cpp:32
std::string debug_string() const override
Definition Phi.cpp:18
std::unique_ptr< Operation > copy() const override
Definition Phi.cpp:24
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
size_t RemoveResults(const util::HashSet< size_t > &indices)
Definition region.cpp:281
RegionArgument * argument(size_t index) const noexcept
Definition region.hpp:466
RegionArgument & addArgument(std::unique_ptr< RegionArgument > argument)
Definition region.cpp:179
void copy(Region *target, SubstitutionMap &smap) const
Copy a region with substitutions.
Definition region.cpp:317
RegionResult & addResult(std::unique_ptr< RegionResult > result)
Definition region.cpp:265
RegionResult * result(size_t index) const noexcept
Definition region.hpp:500
size_t RemoveArguments(const util::HashSet< size_t > &indices)
Definition region.cpp:213
RegionArgument & insertArgument(size_t index, std::unique_ptr< RegionArgument > argument)
Definition region.cpp:190
StructuralInput * addInput(std::unique_ptr< StructuralInput > input, bool notifyRegion)
StructuralOutput * addOutput(std::unique_ptr< StructuralOutput > input)
StructuralOutput * output(size_t index) const noexcept
StructuralInput * input(size_t index) const noexcept
Output & lookup(const Output &original) const
bool insert(ItemType item)
Definition HashSet.hpp:210
#define JLM_ASSERT(x)
Definition common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition common.hpp:43
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
Bound context variable.
Definition Phi.hpp:73
Description of a recursively defined variable.
Definition Phi.hpp:100
rvsdg::Input * result
Definition result of a variable within the phi region.
Definition Phi.hpp:118