Jlm
Loading...
Searching...
No Matches
IfConversionTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2025 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <gtest/gtest.h>
7
14#include <jlm/rvsdg/gamma.hpp>
15#include <jlm/rvsdg/lambda.hpp>
18#include <jlm/rvsdg/view.hpp>
20
21TEST(IfConversionTests, GammaWithoutMatch)
22{
23 using namespace jlm::llvm;
24 using namespace jlm::util;
25
26 // Arrange
28 auto functionType = jlm::rvsdg::FunctionType::Create(
29 { jlm::rvsdg::ControlType::Create(2), valueType, valueType },
30 { valueType });
31
32 LlvmRvsdgModule rvsdgModule(FilePath(""), "", "");
33
34 auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
35 rvsdgModule.Rvsdg().GetRootRegion(),
36 LlvmLambdaOperation::Create(functionType, "lambdaOutput", Linkage::externalLinkage));
37 const auto conditionValue = lambdaNode->GetFunctionArguments()[0];
38 const auto trueValue = lambdaNode->GetFunctionArguments()[1];
39 const auto falseValue = lambdaNode->GetFunctionArguments()[2];
40
41 auto gammaNode = jlm::rvsdg::GammaNode::create(conditionValue, 2);
42 auto gammaInput1 = gammaNode->AddEntryVar(trueValue);
43 auto gammaInput2 = gammaNode->AddEntryVar(falseValue);
44 auto gammaOutput =
45 gammaNode->AddExitVar({ gammaInput1.branchArgument[0], gammaInput2.branchArgument[1] });
46
47 auto lambdaOutput = lambdaNode->finalize({ gammaOutput.output });
48 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "");
49
50 jlm::rvsdg::view(rvsdgModule.Rvsdg(), stdout);
51
52 // Act
54 IfConversion ifConversion;
55 ifConversion.Run(rvsdgModule, statisticsCollector);
56
57 view(rvsdgModule.Rvsdg(), stdout);
58
59 // Assert
60
61 EXPECT_TRUE(gammaNode->IsDead());
62 const auto selectNode =
63 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*lambdaNode->subregion()->result(0)->origin());
64 EXPECT_TRUE(selectNode && is<SelectOperation>(selectNode));
65 EXPECT_EQ(selectNode->input(1)->origin(), falseValue);
66 EXPECT_EQ(selectNode->input(2)->origin(), trueValue);
67
68 const auto controlToBitsNode =
69 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*selectNode->input(0)->origin());
70 EXPECT_TRUE(controlToBitsNode && is<ControlToIntOperation>(controlToBitsNode));
71 EXPECT_EQ(controlToBitsNode->input(0)->origin(), conditionValue);
72}
73
74TEST(IfConversionTests, EmptyGammaWithTwoSubregionsAndMatch)
75{
76 using namespace jlm::llvm;
77 using namespace jlm::util;
78
79 // Arrange
81 const auto functionType = jlm::rvsdg::FunctionType::Create(
82 { jlm::rvsdg::BitType::Create(32), valueType, valueType },
83 { valueType });
84
85 LlvmRvsdgModule rvsdgModule(FilePath(""), "", "");
86
87 const auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
88 rvsdgModule.Rvsdg().GetRootRegion(),
89 LlvmLambdaOperation::Create(functionType, "lambdaOutput", Linkage::externalLinkage));
90 const auto conditionValue = lambdaNode->GetFunctionArguments()[0];
91 const auto trueValue = lambdaNode->GetFunctionArguments()[1];
92 const auto falseValue = lambdaNode->GetFunctionArguments()[2];
93
94 auto caseValue = 24;
95 auto & matchNode =
96 jlm::rvsdg::MatchOperation::CreateNode(*conditionValue, { { caseValue, 0 } }, 1, 2);
97
98 const auto gammaNode = jlm::rvsdg::GammaNode::create(matchNode.output(0), 2);
99 auto [inputTrue, branchArgumentTrue] = gammaNode->AddEntryVar(trueValue);
100 auto [inputFalse, branchArgumentFalse] = gammaNode->AddEntryVar(falseValue);
101 auto [_, gammaOutput] = gammaNode->AddExitVar({ branchArgumentTrue[0], branchArgumentFalse[1] });
102
103 const auto lambdaOutput = lambdaNode->finalize({ gammaOutput });
104 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "");
105
106 view(rvsdgModule.Rvsdg(), stdout);
107
108 // Act
110 IfConversion ifConversion;
111 ifConversion.Run(rvsdgModule, statisticsCollector);
112
113 view(rvsdgModule.Rvsdg(), stdout);
114
115 // Assert
116
117 EXPECT_TRUE(gammaNode->IsDead());
118 const auto selectNode =
119 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*lambdaNode->subregion()->result(0)->origin());
120 EXPECT_TRUE(selectNode && is<SelectOperation>(selectNode));
121 EXPECT_EQ(selectNode->input(1)->origin(), trueValue);
122 EXPECT_EQ(selectNode->input(2)->origin(), falseValue);
123
124 const auto eqNode =
125 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*selectNode->input(0)->origin());
126 EXPECT_TRUE(eqNode && is<IntegerEqOperation>(eqNode));
127
128 auto constantNode =
129 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*eqNode->input(0)->origin());
130 if (constantNode)
131 {
132 EXPECT_EQ(eqNode->input(1)->origin(), conditionValue);
133 auto constantOperation =
134 dynamic_cast<const IntegerConstantOperation *>(&constantNode->GetOperation());
135 EXPECT_NE(constantOperation, nullptr);
136 EXPECT_EQ(constantOperation->Representation(), 24u);
137 }
138 else
139 {
140 EXPECT_EQ(eqNode->input(0)->origin(), conditionValue);
141 constantNode = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*eqNode->input(1)->origin());
142 auto constantOperation =
143 dynamic_cast<const IntegerConstantOperation *>(&constantNode->GetOperation());
144 EXPECT_NE(constantOperation, nullptr);
145 EXPECT_EQ(constantOperation->Representation(), 24u);
146 }
147}
148
149TEST(IfConversionTests, EmptyGammaWithTwoSubregions)
150{
151 using namespace jlm::llvm;
152 using namespace jlm::util;
153
154 // Arrange
155 auto valueType = jlm::rvsdg::TestType::createValueType();
156 auto functionType = jlm::rvsdg::FunctionType::Create(
157 { jlm::rvsdg::BitType::Create(32), valueType, valueType },
158 { valueType });
159
160 LlvmRvsdgModule rvsdgModule(FilePath(""), "", "");
161
162 const auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
163 rvsdgModule.Rvsdg().GetRootRegion(),
164 LlvmLambdaOperation::Create(functionType, "lambdaOutput", Linkage::externalLinkage));
165 const auto trueValue = lambdaNode->GetFunctionArguments()[1];
166 const auto falseValue = lambdaNode->GetFunctionArguments()[2];
167
169 *lambdaNode->GetFunctionArguments()[0],
170 { { 0, 0 } },
171 1,
172 2);
173
174 const auto gammaNode0 = jlm::rvsdg::GammaNode::create(matchNode.output(0), 2);
176 *gammaNode0->subregion(0),
179 *gammaNode0->subregion(1),
181 auto c = gammaNode0->AddExitVar({ c0.output(0), c1.output(0) });
182
183 const auto gammaNode1 = jlm::rvsdg::GammaNode::create(c.output, 2);
184 auto [inputTrue, branchArgumentTrue] = gammaNode1->AddEntryVar(trueValue);
185 auto [inputFalse, branchArgumentFalse] = gammaNode1->AddEntryVar(falseValue);
186 auto [_, gammaOutput] = gammaNode1->AddExitVar({ branchArgumentFalse[0], branchArgumentTrue[1] });
187
188 const auto lambdaOutput = lambdaNode->finalize({ gammaOutput });
189 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "");
190
191 view(rvsdgModule.Rvsdg(), stdout);
192
193 // Act
195 IfConversion ifConversion;
196 ifConversion.Run(rvsdgModule, statisticsCollector);
197
198 view(rvsdgModule.Rvsdg(), stdout);
199
200 // Assert
201 EXPECT_TRUE(gammaNode1->IsDead());
202 const auto selectNode =
203 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*lambdaNode->subregion()->result(0)->origin());
204 EXPECT_TRUE(selectNode && is<SelectOperation>(selectNode));
205 EXPECT_EQ(selectNode->input(1)->origin(), trueValue);
206 EXPECT_EQ(selectNode->input(2)->origin(), falseValue);
207}
208
209TEST(IfConversionTests, EmptyGammaWithThreeSubregions)
210{
211 using namespace jlm::llvm;
212 using namespace jlm::util;
213
214 // Arrange
215 auto valueType = jlm::rvsdg::TestType::createValueType();
216 auto functionType = jlm::rvsdg::FunctionType::Create(
217 { jlm::rvsdg::BitType::Create(32), valueType, valueType },
218 { valueType });
219
220 LlvmRvsdgModule rvsdgModule(FilePath(""), "", "");
221
222 auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
223 rvsdgModule.Rvsdg().GetRootRegion(),
224 LlvmLambdaOperation::Create(functionType, "lambdaOutput", Linkage::externalLinkage));
225
227 *lambdaNode->GetFunctionArguments()[0],
228 { { 0, 0 }, { 1, 1 } },
229 2,
230 3);
231
232 auto gammaNode = jlm::rvsdg::GammaNode::create(matchNode.output(0), 3);
233 auto gammaInput1 = gammaNode->AddEntryVar(lambdaNode->GetFunctionArguments()[1]);
234 auto gammaInput2 = gammaNode->AddEntryVar(lambdaNode->GetFunctionArguments()[2]);
235 auto gammaOutput = gammaNode->AddExitVar({ gammaInput1.branchArgument[0],
236 gammaInput1.branchArgument[1],
237 gammaInput2.branchArgument[2] });
238
239 auto lambdaOutput = lambdaNode->finalize({ gammaOutput.output });
240 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "");
241
242 view(rvsdgModule.Rvsdg(), stdout);
243
244 // Act
246 IfConversion ifConversion;
247 ifConversion.Run(rvsdgModule, statisticsCollector);
248
249 view(rvsdgModule.Rvsdg(), stdout);
250
251 // Assert
252
253 // Only the gamma and match nodes should be in the lambda region. No select operation
254 // should have been created.
255 EXPECT_EQ(lambdaNode->subregion()->numNodes(), 2u);
256 EXPECT_FALSE(gammaNode->IsDead());
257}
258
259TEST(IfConversionTests, PartialEmptyGamma)
260{
261 using namespace jlm::llvm;
262 using namespace jlm::rvsdg;
263 using namespace jlm::util;
264
265 // Arrange
266 auto valueType = jlm::rvsdg::TestType::createValueType();
267 auto functionType = jlm::rvsdg::FunctionType::Create(
268 { jlm::rvsdg::BitType::Create(1), valueType },
269 { valueType });
270
271 jlm::llvm::LlvmRvsdgModule rvsdgModule(FilePath(""), "", "");
272
273 auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
274 rvsdgModule.Rvsdg().GetRootRegion(),
275 LlvmLambdaOperation::Create(functionType, "lambdaOutput", Linkage::externalLinkage));
276
277 auto & matchNode =
278 MatchOperation::CreateNode(*lambdaNode->GetFunctionArguments()[0], { { 0, 0 } }, 1, 2);
279 auto gammaNode = GammaNode::create(matchNode.output(0), 2);
280 auto gammaInput = gammaNode->AddEntryVar(lambdaNode->GetFunctionArguments()[1]);
281 auto output = TestOperation::createNode(
282 gammaNode->subregion(1),
283 { gammaInput.branchArgument[1] },
284 { valueType })
285 ->output(0);
286 auto gammaOutput = gammaNode->AddExitVar({ gammaInput.branchArgument[0], output });
287
288 auto lambdaOutput = lambdaNode->finalize({ gammaOutput.output });
289
290 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "");
291
292 view(rvsdgModule.Rvsdg(), stdout);
293
294 // Act
296 IfConversion ifConversion;
297 ifConversion.Run(rvsdgModule, statisticsCollector);
298
299 view(rvsdgModule.Rvsdg(), stdout);
300
301 // Assert
302
303 // Only the gamma and match nodes should be in the lambda region. No select operation
304 // should have been created.
305 EXPECT_EQ(lambdaNode->subregion()->numNodes(), 2u);
306 EXPECT_FALSE(gammaNode->IsDead());
307}
308
309TEST(IfConversionTests, GammaWithMatchAlternativeMismatch)
310{
311 using namespace jlm::llvm;
312 using namespace jlm::util;
313
314 // Arrange
315 auto valueType = jlm::rvsdg::TestType::createValueType();
316 const auto functionType = jlm::rvsdg::FunctionType::Create(
317 { jlm::rvsdg::BitType::Create(32), valueType, valueType },
318 { valueType });
319
320 LlvmRvsdgModule rvsdgModule(FilePath(""), "", "");
321
322 const auto lambdaNode = jlm::rvsdg::LambdaNode::Create(
323 rvsdgModule.Rvsdg().GetRootRegion(),
324 LlvmLambdaOperation::Create(functionType, "lambdaOutput", Linkage::externalLinkage));
325 const auto conditionValue = lambdaNode->GetFunctionArguments()[0];
326 const auto trueValue = lambdaNode->GetFunctionArguments()[1];
327 const auto falseValue = lambdaNode->GetFunctionArguments()[2];
328
330 *conditionValue,
331 { { 24, 0 }, { 3, 0 }, { 45, 0 } },
332 1,
333 2);
334
335 const auto gammaNode = jlm::rvsdg::GammaNode::create(matchNode.output(0), 2);
336 auto [inputTrue, branchArgumentTrue] = gammaNode->AddEntryVar(trueValue);
337 auto [inputFalse, branchArgumentFalse] = gammaNode->AddEntryVar(falseValue);
338 auto [_, gammaOutput] = gammaNode->AddExitVar({ branchArgumentTrue[0], branchArgumentFalse[1] });
339
340 const auto lambdaOutput = lambdaNode->finalize({ gammaOutput });
341 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "");
342
343 view(rvsdgModule.Rvsdg(), stdout);
344
345 // Act
347 IfConversion ifConversion;
348 ifConversion.Run(rvsdgModule, statisticsCollector);
349
350 view(rvsdgModule.Rvsdg(), stdout);
351
352 // Assert
353
354 // Only the gamma and match nodes should be in the lambda region. No select operation
355 // should have been created.
356 EXPECT_EQ(lambdaNode->subregion()->numNodes(), 2u);
357 EXPECT_FALSE(gammaNode->IsDead());
358}
static jlm::util::StatisticsCollector statisticsCollector
TEST(IfConversionTests, GammaWithoutMatch)
std::int64_t c1
If-Conversion Transformation.
void Run(rvsdg::RvsdgModule &module, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
Definition type.cpp:45
static std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
Definition control.cpp:50
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)
static GammaNode * create(jlm::rvsdg::Output *predicate, size_t nalternatives)
Definition gamma.hpp:161
static GraphExport & Create(Output &origin, std::string name)
Definition graph.cpp:62
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
Definition lambda.cpp:141
static Node & CreateNode(Output &predicate, const std::unordered_map< uint64_t, uint64_t > &mapping, const uint64_t defaultAlternative, const size_t numAlternatives)
Definition control.hpp:220
static std::shared_ptr< const TestType > createValueType()
Definition TestType.cpp:67
Global memory state passed between functions.
std::string view(const rvsdg::Region *region)
Definition view.cpp:142
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872