Jlm
Loading...
Searching...
No Matches
StoreTests.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
15#include <jlm/rvsdg/gamma.hpp>
19#include <jlm/rvsdg/view.hpp>
20
21TEST(StoreOperationTests, StoreNonVolatileOperationEquality)
22{
23 using namespace jlm::llvm;
24 using namespace jlm::rvsdg;
25
26 // Arrange
27 MemoryStateType memoryType;
29 auto pointerType = PointerType::Create();
30
31 StoreNonVolatileOperation operation1(valueType, 2, 4);
32 StoreNonVolatileOperation operation2(pointerType, 2, 4);
33 StoreNonVolatileOperation operation3(valueType, 4, 4);
34 StoreNonVolatileOperation operation4(valueType, 2, 8);
35 TestOperation operation5({ PointerType::Create() }, { PointerType::Create() });
36
37 // Act & Assert
38 EXPECT_EQ(operation1, operation1);
39 EXPECT_NE(operation1, operation2); // stored type differs
40 EXPECT_NE(operation1, operation3); // number of memory states differs
41 EXPECT_NE(operation1, operation4); // alignment differs
42 EXPECT_NE(operation1, operation5); // operation differs
43}
44
45TEST(StoreOperationTests, StoreVolatileOperationEquality)
46{
47 using namespace jlm::llvm;
48 using namespace jlm::rvsdg;
49
50 // Arrange
51 MemoryStateType memoryType;
53 auto pointerType = PointerType::Create();
54
55 StoreVolatileOperation operation1(valueType, 2, 4);
56 StoreVolatileOperation operation2(pointerType, 2, 4);
57 StoreVolatileOperation operation3(valueType, 4, 4);
58 StoreVolatileOperation operation4(valueType, 2, 8);
59 TestOperation operation5({ PointerType::Create() }, { PointerType::Create() });
60
61 // Assert
62 EXPECT_EQ(operation1, operation1);
63 EXPECT_NE(operation1, operation2); // stored type differs
64 EXPECT_NE(operation1, operation3); // number of memory states differs
65 EXPECT_NE(operation1, operation4); // alignment differs
66 EXPECT_NE(operation1, operation5); // operation differs
67}
68
69TEST(StoreOperationTests, StoreVolatileOperationCopy)
70{
71 using namespace jlm::llvm;
72
73 // Arrange
74 MemoryStateType memoryType;
76 PointerType pointerType;
77
78 StoreVolatileOperation operation(valueType, 2, 4);
79
80 // Act
81 auto copiedOperation = operation.copy();
82
83 // Assert
84 EXPECT_EQ(*copiedOperation, operation);
85}
86
87TEST(StoreOperationTests, StoreVolatileOperationAccessors)
88{
89 using namespace jlm::llvm;
90
91 // Arrange
92 MemoryStateType memoryType;
94 PointerType pointerType;
95
96 size_t alignment = 4;
97 size_t numMemoryStates = 2;
98 StoreVolatileOperation operation(valueType, numMemoryStates, alignment);
99
100 // Assert
101 EXPECT_EQ(operation.GetStoredType(), *valueType);
102 EXPECT_EQ(operation.NumMemoryStates(), numMemoryStates);
103 EXPECT_EQ(operation.GetAlignment(), alignment);
104 EXPECT_EQ(
105 operation.narguments(),
106 numMemoryStates + 3); // [address, storedValue, ioState, memoryStates]
107 EXPECT_EQ(operation.nresults(), numMemoryStates + 1); // [ioState, memoryStates]
108}
109
110TEST(StoreOperationTests, StoreVolatileNodeCopy)
111{
112 using namespace jlm::llvm;
113
114 // Arrange
115 auto pointerType = PointerType::Create();
116 auto ioStateType = IOStateType::Create();
117 auto memoryType = MemoryStateType::Create();
118 auto valueType = jlm::rvsdg::TestType::createValueType();
119
120 jlm::rvsdg::Graph graph;
121 auto & address1 = jlm::rvsdg::GraphImport::Create(graph, pointerType, "address1");
122 auto & value1 = jlm::rvsdg::GraphImport::Create(graph, valueType, "value1");
123 auto & ioState1 = jlm::rvsdg::GraphImport::Create(graph, ioStateType, "ioState1");
124 auto & memoryState1 = jlm::rvsdg::GraphImport::Create(graph, memoryType, "memoryState1");
125
126 auto & address2 = jlm::rvsdg::GraphImport::Create(graph, pointerType, "address2");
127 auto & value2 = jlm::rvsdg::GraphImport::Create(graph, valueType, "value2");
128 auto & ioState2 = jlm::rvsdg::GraphImport::Create(graph, ioStateType, "ioState2");
129 auto & memoryState2 = jlm::rvsdg::GraphImport::Create(graph, memoryType, "memoryState2");
130
131 auto & storeNode =
132 StoreVolatileOperation::CreateNode(address1, value1, ioState1, { &memoryState1 }, 4);
133
134 // Act
135 auto copiedNode =
136 storeNode.copy(&graph.GetRootRegion(), { &address2, &value2, &ioState2, &memoryState2 });
137
138 // Assert
139 EXPECT_EQ(storeNode.GetOperation(), storeNode.GetOperation());
140 EXPECT_EQ(StoreOperation::AddressInput(*copiedNode).origin(), &address2);
141 EXPECT_EQ(StoreOperation::StoredValueInput(*copiedNode).origin(), &value2);
142 EXPECT_EQ(StoreVolatileOperation::IOStateInput(*copiedNode).origin(), &ioState2);
143 EXPECT_EQ(*StoreVolatileOperation::IOStateOutput(*copiedNode).Type(), *ioStateType);
144}
145
146TEST(StoreOperationTests, TestCopy)
147{
148 using namespace jlm::llvm;
149
150 auto valueType = jlm::rvsdg::TestType::createValueType();
151 auto pointerType = PointerType::Create();
152 auto memoryStateType = MemoryStateType::Create();
153
154 jlm::rvsdg::Graph graph;
155 auto address1 = &jlm::rvsdg::GraphImport::Create(graph, pointerType, "address1");
156 auto value1 = &jlm::rvsdg::GraphImport::Create(graph, valueType, "value1");
157 auto memoryState1 = &jlm::rvsdg::GraphImport::Create(graph, memoryStateType, "state1");
158
159 auto address2 = &jlm::rvsdg::GraphImport::Create(graph, pointerType, "address2");
160 auto value2 = &jlm::rvsdg::GraphImport::Create(graph, valueType, "value2");
161 auto memoryState2 = &jlm::rvsdg::GraphImport::Create(graph, memoryStateType, "state2");
162
163 auto storeResults = StoreNonVolatileOperation::Create(address1, value1, { memoryState1 }, 4);
164
165 // Act
166 auto node = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*storeResults[0]);
167 auto copiedNode = node->copy(&graph.GetRootRegion(), { address2, value2, memoryState2 });
168
169 // Assert
170 EXPECT_EQ(
171 node->GetOperation(),
172 jlm::util::assertedCast<jlm::rvsdg::SimpleNode>(copiedNode)->GetOperation());
173}
174
175TEST(StoreOperationTests, TestStoreMuxNormalization)
176{
177 using namespace jlm::llvm;
178 using namespace jlm::rvsdg;
179
180 // Arrange
181 auto vt = TestType::createValueType();
182 auto pt = PointerType::Create();
183 auto mt = MemoryStateType::Create();
184
185 jlm::rvsdg::Graph graph;
186 auto a = &jlm::rvsdg::GraphImport::Create(graph, pt, "a");
187 auto v = &jlm::rvsdg::GraphImport::Create(graph, vt, "v");
188 auto s1 = &jlm::rvsdg::GraphImport::Create(graph, mt, "s1");
189 auto s2 = &jlm::rvsdg::GraphImport::Create(graph, mt, "s2");
190 auto s3 = &jlm::rvsdg::GraphImport::Create(graph, mt, "s3");
191
192 auto mux = MemoryStateMergeOperation::Create({ s1, s2, s3 });
193 auto & storeNode = StoreNonVolatileOperation::CreateNode(*a, *v, { mux }, 4);
194
195 auto & ex = GraphExport::Create(*storeNode.output(0), "s");
196
197 jlm::rvsdg::view(&graph.GetRootRegion(), stdout);
198
199 // Act
201 StoreNonVolatileOperation::NormalizeStoreMux,
202 storeNode);
203 graph.PruneNodes();
204
205 jlm::rvsdg::view(&graph.GetRootRegion(), stdout);
206
207 // Assert
208 EXPECT_TRUE(success);
209 auto muxNode = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*ex.origin());
210 EXPECT_TRUE(is<MemoryStateMergeOperation>(muxNode));
211 EXPECT_EQ(muxNode->ninputs(), 3u);
212 auto n0 = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*muxNode->input(0)->origin());
213 auto n1 = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*muxNode->input(1)->origin());
214 auto n2 = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*muxNode->input(2)->origin());
215 EXPECT_TRUE(jlm::rvsdg::is<StoreNonVolatileOperation>(n0->GetOperation()));
216 EXPECT_TRUE(jlm::rvsdg::is<StoreNonVolatileOperation>(n1->GetOperation()));
217 EXPECT_TRUE(jlm::rvsdg::is<StoreNonVolatileOperation>(n2->GetOperation()));
218}
219
220TEST(StoreOperationTests, TestDuplicateStateReduction)
221{
222 using namespace jlm::llvm;
223 using namespace jlm::rvsdg;
224
225 // Arrange
226 auto valueType = TestType::createValueType();
227 auto pointerType = PointerType::Create();
228 auto memoryStateType = MemoryStateType::Create();
229
230 jlm::rvsdg::Graph graph;
231 auto a = &jlm::rvsdg::GraphImport::Create(graph, pointerType, "a");
232 auto v = &jlm::rvsdg::GraphImport::Create(graph, valueType, "v");
233 auto s1 = &jlm::rvsdg::GraphImport::Create(graph, memoryStateType, "s1");
234 auto s2 = &jlm::rvsdg::GraphImport::Create(graph, memoryStateType, "s2");
235 auto s3 = &jlm::rvsdg::GraphImport::Create(graph, memoryStateType, "s3");
236
237 auto & storeNode = StoreNonVolatileOperation::CreateNode(*a, *v, { s1, s2, s1, s2, s3 }, 4);
238
239 auto & exS1 = GraphExport::Create(*storeNode.output(0), "exS1");
240 auto & exS2 = GraphExport::Create(*storeNode.output(1), "exS2");
241 auto & exS3 = GraphExport::Create(*storeNode.output(2), "exS3");
242 auto & exS4 = GraphExport::Create(*storeNode.output(3), "exS4");
243 auto & exS5 = GraphExport::Create(*storeNode.output(4), "exS5");
244
245 view(&graph.GetRootRegion(), stdout);
246
247 // Act
249 StoreNonVolatileOperation::NormalizeDuplicateStates,
250 storeNode);
251 graph.PruneNodes();
252
253 view(&graph.GetRootRegion(), stdout);
254
255 // Assert
256 EXPECT_TRUE(success);
257 auto node = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*exS1.origin());
258 EXPECT_TRUE(is<StoreNonVolatileOperation>(node));
259 EXPECT_EQ(node->ninputs(), 5u);
260 EXPECT_EQ(node->noutputs(), 3u);
261 EXPECT_EQ(exS1.origin(), node->output(0));
262 EXPECT_EQ(exS2.origin(), node->output(1));
263 EXPECT_EQ(exS3.origin(), node->output(0));
264 EXPECT_EQ(exS4.origin(), node->output(1));
265 EXPECT_EQ(exS5.origin(), node->output(2));
266}
267
268TEST(StoreOperationTests, TestStoreAllocaReduction)
269{
270 using namespace jlm::llvm;
271 using namespace jlm::rvsdg;
272
273 // Arrange
274 auto vt = TestType::createValueType();
275 auto mt = MemoryStateType::Create();
276 auto bt = jlm::rvsdg::BitType::Create(32);
277
278 jlm::rvsdg::Graph graph;
279 auto size = &jlm::rvsdg::GraphImport::Create(graph, bt, "size");
280 auto value = &jlm::rvsdg::GraphImport::Create(graph, vt, "value");
281 auto s = &jlm::rvsdg::GraphImport::Create(graph, mt, "s");
282
283 auto alloca1 = AllocaOperation::create(vt, size, 4);
284 auto alloca2 = AllocaOperation::create(vt, size, 4);
285 auto & storeNode1 =
286 StoreNonVolatileOperation::CreateNode(*alloca1[0], *value, { alloca1[1], alloca2[1], s }, 4);
287 auto & storeNode2 =
288 StoreNonVolatileOperation::CreateNode(*alloca2[0], *value, outputs(&storeNode1), 4);
289
290 GraphExport::Create(*storeNode2.output(0), "s1");
291 GraphExport::Create(*storeNode2.output(1), "s2");
292 GraphExport::Create(*storeNode2.output(2), "s3");
293
294 view(&graph.GetRootRegion(), stdout);
295
296 // Act
298 StoreNonVolatileOperation::NormalizeStoreAlloca,
299 storeNode1);
301 StoreNonVolatileOperation::NormalizeStoreAlloca,
302 storeNode2);
303 graph.PruneNodes();
304
305 view(&graph.GetRootRegion(), stdout);
306
307 // Assert
308 EXPECT_TRUE(success1 && success2);
309 bool has_add_import = false;
310 for (size_t n = 0; n < graph.GetRootRegion().nresults(); n++)
311 {
312 if (graph.GetRootRegion().result(n)->origin() == s)
313 has_add_import = true;
314 }
315 EXPECT_TRUE(has_add_import);
316}
317
318TEST(StoreOperationTests, testStoreStoreReduction)
319{
320 using namespace jlm::llvm;
321 using namespace jlm::rvsdg;
322
323 // Arrange
324 const auto i32Type = BitType::Create(32);
325 const auto i64Type = BitType::Create(64);
326 const auto pointerType = PointerType::Create();
327 const auto memoryStateType = MemoryStateType::Create();
328
329 Graph graph;
330 auto addressImport1 = &GraphImport::Create(graph, pointerType, "address1");
331 auto addressImport2 = &GraphImport::Create(graph, pointerType, "address2");
332 auto i32Import = &GraphImport::Create(graph, i32Type, "i32");
333 auto i64Import1 = &GraphImport::Create(graph, i64Type, "i64-1");
334 auto i64Import2 = &GraphImport::Create(graph, i64Type, "i64-2");
335 auto memoryStateImport1 = &GraphImport::Create(graph, memoryStateType, "memoryState1");
336 auto memoryStateImport2 = &GraphImport::Create(graph, memoryStateType, "memoryState2");
337
338 auto & storeNode1 = StoreNonVolatileOperation::CreateNode(
339 *addressImport1,
340 *i64Import1,
341 { memoryStateImport1 },
342 4);
343 auto & storeNode2 =
344 StoreNonVolatileOperation::CreateNode(*addressImport1, *i64Import2, outputs(&storeNode1), 4);
345
346 auto & storeNode3 = StoreNonVolatileOperation::CreateNode(
347 *addressImport1,
348 *i64Import1,
349 { memoryStateImport1 },
350 4);
351 auto & storeNode4 = StoreNonVolatileOperation::CreateNode(
352 *addressImport1,
353 *i64Import2,
354 { outputs(&storeNode3).front(), memoryStateImport2 },
355 4);
356
357 auto & storeNode5 = StoreNonVolatileOperation::CreateNode(
358 *addressImport1,
359 *i64Import1,
360 { memoryStateImport1 },
361 4);
362 auto & storeNode6 =
363 StoreNonVolatileOperation::CreateNode(*addressImport1, *i32Import, outputs(&storeNode5), 4);
364
365 auto & storeNode7 = StoreNonVolatileOperation::CreateNode(
366 *addressImport1,
367 *i64Import1,
368 { memoryStateImport1 },
369 4);
370 auto & storeNode8 =
371 StoreNonVolatileOperation::CreateNode(*addressImport2, *i64Import2, outputs(&storeNode7), 4);
372
373 auto & storeNode9 = StoreNonVolatileOperation::CreateNode(
374 *addressImport1,
375 *i64Import1,
376 { memoryStateImport1 },
377 4);
378 auto & storeNode10 =
379 StoreNonVolatileOperation::CreateNode(*addressImport1, *i64Import2, outputs(&storeNode9), 4);
380 GraphExport::Create(*outputs(&storeNode9).front(), "");
381
382 auto & storeNode11 = StoreNonVolatileOperation::CreateNode(
383 *addressImport1,
384 *i64Import1,
385 { memoryStateImport1, memoryStateImport2 },
386 4);
387 auto & storeNode12 = StoreNonVolatileOperation::CreateNode(
388 *addressImport1,
389 *i64Import2,
390 { storeNode11.output(0) },
391 4);
392
393 auto & ex1 = GraphExport::Create(*storeNode2.output(0), "ex1");
394 auto & ex2 = GraphExport::Create(*storeNode4.output(0), "ex2");
395 auto & ex3 = GraphExport::Create(*storeNode6.output(0), "ex3");
396 auto & ex4 = GraphExport::Create(*storeNode8.output(0), "ex4");
397 auto & ex5 = GraphExport::Create(*storeNode10.output(0), "ex5");
398 auto & ex6 = GraphExport::Create(*storeNode12.output(0), "ex6");
399
400 view(&graph.GetRootRegion(), stdout);
401
402 // Act
403 auto success1 = ReduceNode<StoreNonVolatileOperation>(
404 StoreNonVolatileOperation::normalizeStoreStore,
405 storeNode2);
406
407 auto success2 = ReduceNode<StoreNonVolatileOperation>(
408 StoreNonVolatileOperation::normalizeStoreStore,
409 storeNode4);
410
411 auto success3 = ReduceNode<StoreNonVolatileOperation>(
412 StoreNonVolatileOperation::normalizeStoreStore,
413 storeNode6);
414
415 auto success4 = ReduceNode<StoreNonVolatileOperation>(
416 StoreNonVolatileOperation::normalizeStoreStore,
417 storeNode8);
418
419 auto success5 = ReduceNode<StoreNonVolatileOperation>(
420 StoreNonVolatileOperation::normalizeStoreStore,
421 storeNode10);
422
423 auto success6 = ReduceNode<StoreNonVolatileOperation>(
424 StoreNonVolatileOperation::normalizeStoreStore,
425 storeNode12);
426
427 graph.PruneNodes();
428
429 view(&graph.GetRootRegion(), stdout);
430
431 // Assert
432 {
433 // We expect the storeNode1 - storeNode2 chain to be reduced to a single store node.
434 EXPECT_TRUE(success1);
435 auto [storeNode, storeOp] =
436 TryGetSimpleNodeAndOptionalOp<StoreNonVolatileOperation>(*ex1.origin());
437 EXPECT_NE(storeOp, nullptr);
438 EXPECT_EQ(StoreOperation::AddressInput(*storeNode).origin(), addressImport1);
439 EXPECT_EQ(StoreOperation::StoredValueInput(*storeNode).origin(), i64Import2);
440 EXPECT_EQ(storeOp->NumMemoryStates(), 1u);
441 EXPECT_EQ(
442 StoreOperation::getMemoryStateInputs(*storeNode).begin()->origin(),
443 memoryStateImport1);
444 }
445
446 {
447 // We expect the storeNode3 - storeNode4 chain NOT to be reduced as not all memory states of
448 // storeNode4 reach storeNode3
449 EXPECT_FALSE(success2);
450 auto [fstStoreNode, _] =
451 TryGetSimpleNodeAndOptionalOp<StoreNonVolatileOperation>(*ex2.origin());
452 EXPECT_EQ(fstStoreNode, &storeNode4);
453 auto [sndStoreNode, sndStoreOp] = TryGetSimpleNodeAndOptionalOp<StoreNonVolatileOperation>(
454 *StoreOperation::getMemoryStateInputs(*fstStoreNode).begin()->origin());
455 EXPECT_EQ(sndStoreNode, &storeNode3);
456 }
457
458 {
459 // We expect the storeNode5 - storeNode6 chain NOT to be reduced as the storeNode6 does not
460 // fully overwrite storeNode5
461 EXPECT_FALSE(success3);
462 auto [fstStoreNode, _] =
463 TryGetSimpleNodeAndOptionalOp<StoreNonVolatileOperation>(*ex3.origin());
464 EXPECT_EQ(fstStoreNode, &storeNode6);
465 auto [sndStoreNode, sndStoreOp] = TryGetSimpleNodeAndOptionalOp<StoreNonVolatileOperation>(
466 *StoreOperation::getMemoryStateInputs(*fstStoreNode).begin()->origin());
467 EXPECT_EQ(sndStoreNode, &storeNode5);
468 }
469
470 {
471 // We expect the storeNode7 - storeNode8 chain NOT to be reduced as the storeNode8 does not
472 // have the same address as storeNode7
473 EXPECT_FALSE(success4);
474 auto [fstStoreNode, _] =
475 TryGetSimpleNodeAndOptionalOp<StoreNonVolatileOperation>(*ex4.origin());
476 EXPECT_EQ(fstStoreNode, &storeNode8);
477 auto [sndStoreNode, sndStoreOp] = TryGetSimpleNodeAndOptionalOp<StoreNonVolatileOperation>(
478 *StoreOperation::getMemoryStateInputs(*fstStoreNode).begin()->origin());
479 EXPECT_EQ(sndStoreNode, &storeNode7);
480 }
481
482 {
483 // We expect the storeNode9 - storeNode10 chain NOT to be reduced as the storeNode9 has another
484 // user than storeNode10 for its memory state
485 EXPECT_FALSE(success5);
486 auto [fstStoreNode, _] =
487 TryGetSimpleNodeAndOptionalOp<StoreNonVolatileOperation>(*ex5.origin());
488 EXPECT_EQ(fstStoreNode, &storeNode10);
489 auto [sndStoreNode, sndStoreOp] = TryGetSimpleNodeAndOptionalOp<StoreNonVolatileOperation>(
490 *StoreOperation::getMemoryStateInputs(*fstStoreNode).begin()->origin());
491 EXPECT_EQ(sndStoreNode, &storeNode9);
492 }
493
494 {
495 // We expect the storeNode11 - storeNode12 chain to be reduced to a single store node.
496 EXPECT_TRUE(success6);
497 auto [storeNode, storeOp] =
498 TryGetSimpleNodeAndOptionalOp<StoreNonVolatileOperation>(*ex6.origin());
499 EXPECT_NE(storeOp, nullptr);
500 EXPECT_EQ(StoreOperation::AddressInput(*storeNode).origin(), addressImport1);
501 EXPECT_EQ(StoreOperation::StoredValueInput(*storeNode).origin(), i64Import2);
502 EXPECT_EQ(storeOp->NumMemoryStates(), 1u);
503 EXPECT_EQ(
504 StoreOperation::getMemoryStateInputs(*storeNode).begin()->origin(),
505 memoryStateImport1);
506 }
507}
508
509TEST(StoreOperationTests, normalizeIOBarrierAddress)
510{
511 using namespace jlm::llvm;
512 using namespace jlm::rvsdg;
513
514 // Arrange
515 const auto pointerType = PointerType::Create();
516 const auto memoryStateType = MemoryStateType::Create();
517 const auto bit32Type = jlm::rvsdg::BitType::Create(32);
518 const auto ioStateType = IOStateType::Create();
519
520 Graph graph;
521 const auto addressImport = &GraphImport::Create(graph, pointerType, "address");
522 const auto valueImport = &GraphImport::Create(graph, bit32Type, "value");
523 const auto sizeImport = &GraphImport::Create(graph, bit32Type, "value");
524 auto memoryStateImport = &GraphImport::Create(graph, memoryStateType, "memState");
525 auto ioStateImport = &GraphImport::Create(graph, ioStateType, "ioState");
526
527 auto allocaResults = AllocaOperation::create(bit32Type, sizeImport, 4);
529 { allocaResults[0], ioStateImport },
530 pointerType);
531
532 auto & storeNode1 = StoreNonVolatileOperation::CreateNode(
533 *ioBarrierNode.output(0),
534 *valueImport,
535 { allocaResults[1] },
536 4);
537
538 auto & storeNode2 =
539 StoreNonVolatileOperation::CreateNode(*addressImport, *valueImport, { memoryStateImport }, 4);
540
541 auto & ex1 = GraphExport::Create(*storeNode1.output(0), "store1");
542 auto & ex2 = GraphExport::Create(*storeNode2.output(0), "store2");
543
544 view(&graph.GetRootRegion(), stdout);
545
546 // Act
547 const auto successStoreNode1 = jlm::rvsdg::ReduceNode<StoreNonVolatileOperation>(
548 StoreNonVolatileOperation::normalizeIOBarrierAddress,
549 storeNode1);
550
551 const auto successStoreNode2 = jlm::rvsdg::ReduceNode<StoreNonVolatileOperation>(
552 StoreNonVolatileOperation::normalizeIOBarrierAddress,
553 storeNode2);
554 graph.PruneNodes();
555
556 view(&graph.GetRootRegion(), stdout);
557
558 // Assert
559 EXPECT_TRUE(successStoreNode1);
560 EXPECT_EQ(
561 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*ex1.origin())->input(0)->origin(),
562 allocaResults[0]);
563
564 // There is no IOBarrierOperation node as producer for the store address. We expect the
565 // normalization not to trigger.
566 EXPECT_FALSE(successStoreNode2);
567 EXPECT_EQ(
568 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*ex2.origin())->input(0)->origin(),
569 addressImport);
570}
571
572TEST(StoreOperationTests, normalizeIOBarrierAddress_Gamma)
573{
574 using namespace jlm::llvm;
575 using namespace jlm::rvsdg;
576
577 // Arrange
578 const auto pointerType = PointerType::Create();
579 const auto bit32Type = jlm::rvsdg::BitType::Create(32);
580 const auto ioStateType = IOStateType::Create();
581 const auto controlTye = ControlType::Create(2);
582
583 Graph graph;
584 const auto valueImport = &GraphImport::Create(graph, bit32Type, "value");
585 const auto sizeImport = &GraphImport::Create(graph, bit32Type, "value");
586 auto ioStateImport = &GraphImport::Create(graph, ioStateType, "ioState");
587 const auto controlImport = &GraphImport::Create(graph, controlTye, "control");
588
589 auto allocaResults = AllocaOperation::create(bit32Type, sizeImport, 4);
590
591 auto gammaNode = GammaNode::create(controlImport, 2);
592 auto addressEntryVar = gammaNode->AddEntryVar(allocaResults[0]);
593 auto memoryStateEntryVar = gammaNode->AddEntryVar(allocaResults[1]);
594 auto ioStateEntryVar = gammaNode->AddEntryVar(ioStateImport);
595 auto valueEntryVar = gammaNode->AddEntryVar(valueImport);
596
598 { addressEntryVar.branchArgument[0], ioStateEntryVar.branchArgument[0] },
599 pointerType);
600
601 auto & storeNode = StoreNonVolatileOperation::CreateNode(
602 *ioBarrierNode.output(0),
603 *valueEntryVar.branchArgument[0],
604 { memoryStateEntryVar.branchArgument[0] },
605 4);
606
607 auto exitVar =
608 gammaNode->AddExitVar({ storeNode.output(0), memoryStateEntryVar.branchArgument[1] });
609
610 GraphExport::Create(*exitVar.output, "store");
611
612 view(&graph.GetRootRegion(), stdout);
613
614 // Act
615 const auto successStoreNode = jlm::rvsdg::ReduceNode<StoreNonVolatileOperation>(
616 StoreNonVolatileOperation::normalizeIOBarrierAddress,
617 storeNode);
618 graph.PruneNodes();
619
620 view(&graph.GetRootRegion(), stdout);
621
622 // Assert
623 EXPECT_TRUE(successStoreNode);
624 // There should only be the store node left.
625 // The IOBarrier node should have been pruned.
626 EXPECT_EQ(gammaNode->subregion(0)->numNodes(), 1u);
627 EXPECT_EQ(
628 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*exitVar.branchResult[0]->origin())
629 ->input(0)
630 ->origin(),
631 addressEntryVar.branchArgument[0]);
632}
633
634TEST(StoreOperationTests, normalizeIOBarrierAddress_GEP)
635{
636 using namespace jlm::llvm;
637 using namespace jlm::rvsdg;
638
639 // Arrange
640 const auto pointerType = PointerType::Create();
641 const auto memoryStateType = MemoryStateType::Create();
642 const auto bit32Type = jlm::rvsdg::BitType::Create(32);
643 const auto ioStateType = IOStateType::Create();
644 const auto arrayType = ArrayType::Create(bit32Type, 10);
645
646 Graph graph;
647 const auto valueImport = &GraphImport::Create(graph, bit32Type, "value");
648 const auto sizeImport = &GraphImport::Create(graph, bit32Type, "value");
649 auto ioStateImport = &GraphImport::Create(graph, ioStateType, "ioState");
650
651 auto & zeroNode = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 0);
652 auto & twoNode = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 2);
653 auto & tenNode = IntegerConstantOperation::Create(graph.GetRootRegion(), 32, 10);
654
655 auto allocaResults = AllocaOperation::create(arrayType, sizeImport, 4);
656
657 auto & gepNode1 = GetElementPtrOperation::createNode(
658 *allocaResults[0],
659 { zeroNode.output(0), twoNode.output(0) },
660 arrayType);
661 auto & ioBarrierNode1 = jlm::rvsdg::CreateOpNode<IOBarrierOperation>(
662 { gepNode1.output(0), ioStateImport },
663 pointerType);
664 auto & storeNode1 = StoreNonVolatileOperation::CreateNode(
665 *ioBarrierNode1.output(0),
666 *valueImport,
667 { allocaResults[1] },
668 4);
669
670 auto & gepNode2 = GetElementPtrOperation::createNode(
671 *allocaResults[0],
672 { zeroNode.output(0), tenNode.output(0) },
673 arrayType);
674 auto & ioBarrierNode2 = jlm::rvsdg::CreateOpNode<IOBarrierOperation>(
675 { gepNode2.output(0), ioStateImport },
676 pointerType);
677 auto & storeNode2 = StoreNonVolatileOperation::CreateNode(
678 *ioBarrierNode2.output(0),
679 *valueImport,
680 { allocaResults[1] },
681 4);
682
683 auto & ex1 = GraphExport::Create(*storeNode1.output(0), "store1");
684 auto & ex2 = GraphExport::Create(*storeNode2.output(0), "store2");
685
686 view(&graph.GetRootRegion(), stdout);
687
688 // Act
689 const auto successStoreNode1 = jlm::rvsdg::ReduceNode<StoreNonVolatileOperation>(
690 StoreNonVolatileOperation::normalizeIOBarrierAddress,
691 storeNode1);
692
693 const auto successStoreNode2 = jlm::rvsdg::ReduceNode<StoreNonVolatileOperation>(
694 StoreNonVolatileOperation::normalizeIOBarrierAddress,
695 storeNode2);
696 graph.PruneNodes();
697
698 view(&graph.GetRootRegion(), stdout);
699
700 // Assert
701 {
702 EXPECT_TRUE(successStoreNode1);
703 EXPECT_EQ(
704 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*ex1.origin())->input(0)->origin(),
705 gepNode1.output(0));
706 }
707
708 {
709 // The offset computed by the GEP + the stored size exceeds the array, we expect the IOBarrier
710 // to not be removed.
711 EXPECT_FALSE(successStoreNode2);
712 EXPECT_EQ(
713 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*ex2.origin())->input(0)->origin(),
714 ioBarrierNode2.output(0));
715 }
716}
717
718TEST(StoreOperationTests, storeAllocaSingleUser)
719{
720 using namespace jlm::llvm;
721 using namespace jlm::rvsdg;
722
723 // Arrange
724 const auto valueType = TestType::createValueType();
725 const auto bit32Type = BitType::Create(32);
726
727 Graph graph;
728 const auto valueImport = &jlm::rvsdg::GraphImport::Create(graph, valueType, "value");
729 const auto sizeImport = &jlm::rvsdg::GraphImport::Create(graph, bit32Type, "value");
730
731 auto allocaResults = AllocaOperation::create(valueType, sizeImport, 4);
732
733 auto & storeNode = StoreNonVolatileOperation::CreateNode(
734 *allocaResults[0],
735 *valueImport,
736 { allocaResults[1] },
737 4);
738
739 auto & x1 = GraphExport::Create(*storeNode.output(0), "store");
740
741 view(&graph.GetRootRegion(), stdout);
742
743 // Act
745 StoreNonVolatileOperation::normalizeStoreAllocaSingleUser,
746 storeNode);
747
748 graph.PruneNodes();
749
750 view(&graph.GetRootRegion(), stdout);
751
752 // Assert
753 EXPECT_TRUE(success);
754 EXPECT_EQ(x1.origin(), allocaResults[1]);
755}
756
757TEST(StoreOperationTests, storeAllocaSingleUser_MultipleUsers)
758{
759 using namespace jlm::llvm;
760 using namespace jlm::rvsdg;
761
762 // Arrange
763 const auto valueType = TestType::createValueType();
764 const auto bit32Type = BitType::Create(32);
765
766 Graph graph;
767 const auto valueImport = &jlm::rvsdg::GraphImport::Create(graph, valueType, "value");
768 const auto sizeImport = &jlm::rvsdg::GraphImport::Create(graph, bit32Type, "value");
769
770 auto allocaResults = AllocaOperation::create(valueType, sizeImport, 4);
771
772 auto & storeNode1 = StoreNonVolatileOperation::CreateNode(
773 *allocaResults[0],
774 *valueImport,
775 { allocaResults[1] },
776 4);
777
778 auto & storeNode2 = StoreNonVolatileOperation::CreateNode(
779 *allocaResults[0],
780 *valueImport,
781 { storeNode1.output(0) },
782 4);
783
784 auto & x1 = GraphExport::Create(*storeNode1.output(0), "store1");
785 auto & x2 = GraphExport::Create(*storeNode2.output(0), "store2");
786
787 view(&graph.GetRootRegion(), stdout);
788
789 // Act
790 const auto successStoreNode1 = jlm::rvsdg::ReduceNode<StoreNonVolatileOperation>(
791 StoreNonVolatileOperation::normalizeStoreAllocaSingleUser,
792 storeNode1);
793 const auto successStoreNode2 = jlm::rvsdg::ReduceNode<StoreNonVolatileOperation>(
794 StoreNonVolatileOperation::normalizeStoreAllocaSingleUser,
795 storeNode2);
796
797 graph.PruneNodes();
798
799 view(&graph.GetRootRegion(), stdout);
800
801 // Assert
802 EXPECT_FALSE(successStoreNode1);
803 EXPECT_FALSE(successStoreNode2);
804 EXPECT_EQ(x1.origin(), storeNode1.output(0));
805 EXPECT_EQ(x2.origin(), storeNode2.output(0));
806}
static const auto vt
Definition PullTests.cpp:16
Memory state type class.
Definition types.hpp:477
PointerType class.
Definition types.hpp:25
size_t GetAlignment() const noexcept
Definition Store.hpp:57
const rvsdg::Type & GetStoredType() const noexcept
Definition Store.hpp:63
size_t NumMemoryStates() const noexcept
Definition Store.hpp:69
std::unique_ptr< Operation > copy() const override
Definition Store.cpp:360
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
Definition type.cpp:45
static GraphImport & Create(Graph &graph, std::shared_ptr< const rvsdg::Type > type, std::string name)
Definition graph.cpp:36
Region & GetRootRegion() const noexcept
Definition graph.hpp:99
void PruneNodes()
Definition graph.hpp:116
Output * origin() const noexcept
Definition node.hpp:58
RegionResult * result(size_t index) const noexcept
Definition region.hpp:500
size_t nresults() const noexcept
Definition operation.cpp:30
size_t narguments() const noexcept
Definition operation.cpp:17
static std::shared_ptr< const TestType > createValueType()
Definition TestType.cpp:67
TEST(StoreTests, StoreConversion)
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