Jlm
PushTests.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #include <gtest/gtest.h>
7 
13 #include <jlm/llvm/opt/push.hpp>
14 #include <jlm/rvsdg/gamma.hpp>
15 #include <jlm/rvsdg/lambda.hpp>
17 #include <jlm/rvsdg/TestType.hpp>
18 #include <jlm/rvsdg/theta.hpp>
19 #include <jlm/rvsdg/view.hpp>
20 #include <jlm/util/Statistics.hpp>
21 
22 TEST(NodeHoistingTests, simpleGamma)
23 {
24  using namespace jlm::llvm;
25  using namespace jlm::rvsdg;
26 
27  // Arrange
28  const auto controlType = ControlType::Create(2);
29  const auto valueType = TestType::createValueType();
30  const auto functionType = FunctionType::Create(
31  {
32  controlType,
33  valueType,
34  },
35  { valueType });
36 
37  jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
38  auto & rvsdg = rvsdgModule.Rvsdg();
39 
40  auto lambdaNode = LambdaNode::Create(
41  rvsdg.GetRootRegion(),
43  auto controlArgument = lambdaNode->GetFunctionArguments()[0];
44  auto valueArgument = lambdaNode->GetFunctionArguments()[1];
45 
46  auto gammaNode = GammaNode::create(controlArgument, 2);
47  auto entryVar = gammaNode->AddEntryVar(valueArgument);
48 
49  // gamma subregion 0
50  auto constantNode = TestOperation::createNode(gammaNode->subregion(0), {}, { valueType });
51  auto binaryNode = TestOperation::createNode(
52  gammaNode->subregion(0),
53  { entryVar.branchArgument[0], constantNode->output(0) },
54  { valueType });
55 
56  // gamma subregion 1
57  auto unaryNode = TestOperation::createNode(
58  gammaNode->subregion(1),
59  { entryVar.branchArgument[1] },
60  { valueType });
61 
62  auto exitVar = gammaNode->AddExitVar({ binaryNode->output(0), unaryNode->output(0) });
63 
64  auto lambdaOutput = lambdaNode->finalize({ exitVar.output });
65 
66  GraphExport::Create(*lambdaOutput, "x");
67 
68  view(rvsdg, stdout);
69 
70  // Act
71  NodeHoisting nodeHoisting;
73  nodeHoisting.Run(rvsdgModule, statisticsCollector);
74 
75  view(rvsdg, stdout);
76 
77  // Assert
78  // All nodes from the gamma subregions should have been hoisted to the lambda subregion
79  EXPECT_EQ(lambdaNode->subregion()->numNodes(), 4u);
80 
81  // The original nodes in the gamma subregions should have been removed
82  EXPECT_EQ(gammaNode->subregion(0)->numNodes(), 0u);
83  EXPECT_EQ(gammaNode->subregion(1)->numNodes(), 0u);
84 }
85 
86 TEST(NodeHoistingTests, nestedGamma)
87 {
88  using namespace jlm::llvm;
89  using namespace jlm::rvsdg;
90 
91  // Arrange
92  const auto controlType = ControlType::Create(2);
93  const auto valueType = TestType::createValueType();
94  const auto functionType = FunctionType::Create(
95  {
96  controlType,
97  valueType,
98  },
99  { valueType });
100 
101  jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
102  auto & rvsdg = rvsdgModule.Rvsdg();
103 
104  auto lambdaNode = LambdaNode::Create(
105  rvsdg.GetRootRegion(),
107  auto controlArgument = lambdaNode->GetFunctionArguments()[0];
108  auto valueArgument = lambdaNode->GetFunctionArguments()[1];
109 
110  auto gammaNode1 = GammaNode::create(controlArgument, 2);
111  auto controlEntryVar = gammaNode1->AddEntryVar(controlArgument);
112  auto valueEntryVar1 = gammaNode1->AddEntryVar(valueArgument);
113 
114  // gamma1 subregion 0
115  auto constantNode1 = TestOperation::createNode(gammaNode1->subregion(0), {}, { valueType });
116 
117  auto gammaNode2 = GammaNode::create(controlEntryVar.branchArgument[0], 2);
118  auto valueEntryVar2 = gammaNode2->AddEntryVar(valueEntryVar1.branchArgument[0]);
119  auto valueEntryVar3 = gammaNode2->AddEntryVar(constantNode1->output(0));
120 
121  // gamma2 subregion 0
122  auto binaryNode = TestOperation::createNode(
123  gammaNode1->subregion(0),
124  { valueEntryVar2.branchArgument[0], valueEntryVar3.branchArgument[0] },
125  { valueType });
126 
127  // gamma2 subregion 1
128  auto unaryNode = TestOperation::createNode(
129  gammaNode1->subregion(1),
130  { valueEntryVar2.branchArgument[1] },
131  { valueType });
132 
133  auto exitVar1 = gammaNode2->AddExitVar({ binaryNode->output(0), unaryNode->output(0) });
134 
135  // gamma1 subregion 1
136  auto constantNode2 = TestOperation::createNode(gammaNode1->subregion(1), {}, { valueType });
137 
138  auto exitVar2 = gammaNode1->AddExitVar({ exitVar1.output, constantNode2->output(0) });
139 
140  auto lambdaOutput = lambdaNode->finalize({ exitVar2.output });
141 
142  GraphExport::Create(*lambdaOutput, "x");
143 
144  view(rvsdg, stdout);
145 
146  // Act
147  NodeHoisting nodeHoisting;
149  nodeHoisting.Run(rvsdgModule, statisticsCollector);
150 
151  view(rvsdg, stdout);
152 
153  // Assert
154  // All simple nodes from both gamma subregions should have been hoisted to the lambda subregion
155  EXPECT_EQ(lambdaNode->subregion()->numNodes(), 5u);
156 
157  // Only gamma node 2 should be left in gamma node 1 subregion 0
158  EXPECT_EQ(gammaNode1->subregion(0)->numNodes(), 1u);
159  EXPECT_EQ(gammaNode1->subregion(1)->numNodes(), 0u);
160 
161  // All nodes should have been hoisted out
162  EXPECT_EQ(gammaNode2->subregion(0)->numNodes(), 0u);
163  EXPECT_EQ(gammaNode2->subregion(1)->numNodes(), 0u);
164 }
165 
166 TEST(NodeHoistingTests, simpleTheta)
167 {
168  using namespace jlm::llvm;
169  using namespace jlm::rvsdg;
170 
171  // Arrange
172  auto controlType = ControlType::Create(2);
173  const auto valueType = TestType::createValueType();
174  const auto functionType = FunctionType::Create(
175  {
176  controlType,
177  valueType,
178  },
179  { valueType });
180 
181  jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
182  auto & rvsdg = rvsdgModule.Rvsdg();
183 
184  auto lambdaNode = LambdaNode::Create(
185  rvsdg.GetRootRegion(),
187  auto controlArgument = lambdaNode->GetFunctionArguments()[0];
188  auto valueArgument = lambdaNode->GetFunctionArguments()[1];
189 
190  auto thetaNode = ThetaNode::create(lambdaNode->subregion());
191 
192  auto lv1 = thetaNode->AddLoopVar(controlArgument);
193  auto lv2 = thetaNode->AddLoopVar(valueArgument);
194  auto lv3 = thetaNode->AddLoopVar(valueArgument);
195  auto lv4 = thetaNode->AddLoopVar(valueArgument);
196 
197  auto node1 = TestOperation::createNode(thetaNode->subregion(), {}, { valueType });
198  auto node2 = TestOperation::createNode(
199  thetaNode->subregion(),
200  { node1->output(0), lv3.pre },
201  { valueType });
202  auto node3 = TestOperation::createNode(
203  thetaNode->subregion(),
204  { lv2.pre, node2->output(0) },
205  { valueType });
206  auto node4 =
207  TestOperation::createNode(thetaNode->subregion(), { lv3.pre, lv4.pre }, { valueType });
208 
209  lv2.post->divert_to(node3->output(0));
210  lv4.post->divert_to(node4->output(0));
211 
212  thetaNode->set_predicate(lv1.pre);
213 
214  lambdaNode->finalize({ thetaNode->output(1) });
215 
216  view(rvsdg, stdout);
217 
218  // Act
219  NodeHoisting nodeHoisting;
221  nodeHoisting.Run(rvsdgModule, statisticsCollector);
222 
223  view(rvsdg, stdout);
224 
225  // Assert
226  // We expect node1 and node2 to be hoisted out of the theta subregion
227  EXPECT_EQ(lambdaNode->subregion()->numNodes(), 3u);
228  EXPECT_EQ(thetaNode->subregion()->numNodes(), 2u);
229 
230  EXPECT_EQ(lv2.post->origin(), node3->output(0));
231  EXPECT_EQ(lv4.post->origin(), node4->output(0));
232 }
233 
234 TEST(NodeHoistingTests, invariantMemoryOperation)
235 {
236  using namespace jlm::llvm;
237  using namespace jlm::rvsdg;
238 
239  // Arrange
240  const auto memoryStateType = MemoryStateType::Create();
241  const auto pointerType = PointerType::Create();
242  const auto controlType = ControlType::Create(2);
243  const auto valueType = TestType::createValueType();
244  const auto functionType = FunctionType::Create(
245  { controlType, pointerType, valueType, memoryStateType },
246  { memoryStateType });
247 
248  jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
249  auto & rvsdg = rvsdgModule.Rvsdg();
250 
251  auto lambdaNode = LambdaNode::Create(
252  rvsdg.GetRootRegion(),
254  auto controlArgument = lambdaNode->GetFunctionArguments()[0];
255  auto pointerArgument = lambdaNode->GetFunctionArguments()[1];
256  auto valueArgument = lambdaNode->GetFunctionArguments()[2];
257  auto memoryStateArgument = lambdaNode->GetFunctionArguments()[3];
258 
259  auto thetaNode = ThetaNode::create(lambdaNode->subregion());
260 
261  auto lvc = thetaNode->AddLoopVar(controlArgument);
262  auto lva = thetaNode->AddLoopVar(pointerArgument);
263  auto lvv = thetaNode->AddLoopVar(valueArgument);
264  auto lvs = thetaNode->AddLoopVar(memoryStateArgument);
265 
266  auto & storeNode = StoreNonVolatileOperation::CreateNode(*lva.pre, *lvv.pre, { lvs.pre }, 4);
267 
268  lvs.post->divert_to(storeNode.output(0));
269  thetaNode->set_predicate(lvc.pre);
270 
271  lambdaNode->finalize({ lvs.output });
272 
273  view(rvsdg, stdout);
274 
275  // Act
276  NodeHoisting nodeHoisting;
278  nodeHoisting.Run(rvsdgModule, statisticsCollector);
279 
280  view(rvsdg, stdout);
281 
282  // Assert
283  // We expect the store node hoisted out of the theta subregion
284  EXPECT_EQ(lambdaNode->subregion()->numNodes(), 2u);
285  EXPECT_EQ(thetaNode->subregion()->numNodes(), 0u);
286 }
287 
288 TEST(NodeHoistingTests, statefulOperations)
289 {
290  // Arrange
291  using namespace jlm::llvm;
292  using namespace jlm::rvsdg;
293 
294  auto controlType = ControlType::Create(2);
295  auto valueType = TestType::createValueType();
296  auto stateType = TestType::createStateType();
297  const auto functionType = FunctionType::Create(
298  {
299  controlType,
300  valueType,
301  stateType,
302  },
303  { valueType });
304 
305  jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
306  auto & rvsdg = rvsdgModule.Rvsdg();
307 
308  auto lambdaNode = LambdaNode::Create(
309  rvsdg.GetRootRegion(),
311  auto controlArgument = lambdaNode->GetFunctionArguments()[0];
312  auto valueArgument = lambdaNode->GetFunctionArguments()[1];
313  auto stateArgument = lambdaNode->GetFunctionArguments()[2];
314 
315  auto gammaNode1 = GammaNode::create(controlArgument, 2);
316  auto controlEntryVar = gammaNode1->AddEntryVar(controlArgument);
317  auto valueEntryVar1 = gammaNode1->AddEntryVar(valueArgument);
318  auto stateEntryVar = gammaNode1->AddEntryVar(stateArgument);
319 
320  auto stateNode = TestOperation::createNode(
321  gammaNode1->subregion(0),
322  { valueEntryVar1.branchArgument[0], stateEntryVar.branchArgument[0] },
323  { valueType });
324 
325  auto gammaNode2 = GammaNode::create(controlEntryVar.branchArgument[0], 2);
326  auto valueEntryVar2 = gammaNode2->AddEntryVar(stateNode->output(0));
327  auto valueEntryVar3 = gammaNode2->AddEntryVar(valueEntryVar1.branchArgument[0]);
328 
329  auto binaryNode = TestOperation::createNode(
330  gammaNode2->subregion(0),
331  { valueEntryVar2.branchArgument[0], valueEntryVar3.branchArgument[0] },
332  { valueType });
333 
334  auto exitVar2 =
335  gammaNode2->AddExitVar({ binaryNode->output(0), valueEntryVar2.branchArgument[1] });
336 
337  auto exitVar = gammaNode1->AddExitVar({ exitVar2.output, valueEntryVar1.branchArgument[1] });
338 
339  lambdaNode->finalize({ exitVar.output });
340 
341  view(rvsdg, stdout);
342 
343  // Act
344  NodeHoisting nodeHoisting;
346  nodeHoisting.Run(rvsdgModule, statisticsCollector);
347 
348  view(rvsdg, stdout);
349 
350  // Assert
351  // We expect that stateNode stays where it is and only the binaryNode is hoisted to the same
352  // region as stateNode
353 
354  // Gamma node and undef node
355  EXPECT_EQ(lambdaNode->subregion()->numNodes(), 1u);
356 
357  // stateNode, gammaNode2, and binaryNode
358  EXPECT_EQ(gammaNode1->subregion(0)->numNodes(), 3u);
359  EXPECT_EQ(gammaNode1->subregion(1)->numNodes(), 0u);
360 
361  EXPECT_EQ(gammaNode2->subregion(0)->numNodes(), 0u);
362  EXPECT_EQ(gammaNode2->subregion(1)->numNodes(), 0u);
363 }
static jlm::util::StatisticsCollector statisticsCollector
TEST(NodeHoistingTests, simpleGamma)
Definition: PushTests.cpp:22
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 MemoryStateType > Create()
Definition: types.cpp:379
Node Hoisting Transformation.
Definition: push.hpp:37
void Run(rvsdg::RvsdgModule &rvsdgModule, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
Definition: push.cpp:412
static std::shared_ptr< const PointerType > Create()
Definition: types.cpp:45
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &address, rvsdg::Output &value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
Definition: Store.hpp:323
Global memory state passed between functions.
std::string view(const rvsdg::Region *region)
Definition: view.cpp:142