Jlm
IpGraphToLlvmConverterTests.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2024, 2025 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #include <gtest/gtest.h>
7 
18 #include <jlm/llvm/ir/print.hpp>
19 #include <jlm/rvsdg/TestType.hpp>
20 #include <llvm/IR/Instructions.h>
21 #include <llvm/IR/Intrinsics.h>
22 #include <llvm/IR/LLVMContext.h>
23 #include <llvm/IR/Module.h>
24 
25 TEST(IpGraphToLlvmConverterTests, LoadConversion)
26 {
27  using namespace jlm::llvm;
28 
29  // Arrange
30  auto functionType = jlm::rvsdg::FunctionType::Create(
33 
34  InterProceduralGraphModule ipgModule(jlm::util::FilePath(""), "", "");
35 
36  auto cfg = ControlFlowGraph::create(ipgModule);
37  auto addressArgument =
38  cfg->entry()->append_argument(Argument::create("address", PointerType::Create()));
39  auto memoryStateArgument =
40  cfg->entry()->append_argument(Argument::create("memoryState", MemoryStateType::Create()));
41 
42  auto basicBlock = BasicBlock::create(*cfg);
43  size_t alignment = 4;
44  auto loadTac = basicBlock->append_last(LoadNonVolatileOperation::Create(
45  addressArgument,
46  memoryStateArgument,
48  alignment));
49 
50  cfg->exit()->divert_inedges(basicBlock);
51  basicBlock->add_outedge(cfg->exit());
52  cfg->exit()->append_result(loadTac->result(0));
53  cfg->exit()->append_result(loadTac->result(1));
54 
55  auto f = FunctionNode::create(ipgModule.ipgraph(), "f", functionType, Linkage::externalLinkage);
56  f->add_cfg(std::move(cfg));
57 
58  print(ipgModule, stdout);
59 
60  // Act
61  llvm::LLVMContext ctx;
62  auto llvmModule = IpGraphToLlvmConverter::CreateAndConvertModule(ipgModule, ctx);
63  llvmModule->print(llvm::errs(), nullptr);
64 
65  // Assert
66  {
67  auto llvmFunction = llvmModule->getFunction("f");
68  auto & basicBlock = llvmFunction->back();
69  auto & instruction = basicBlock.front();
70 
71  auto loadInstruction = ::llvm::dyn_cast<::llvm::LoadInst>(&instruction);
72  EXPECT_NE(loadInstruction, nullptr);
73  EXPECT_FALSE(loadInstruction->isVolatile());
74  EXPECT_EQ(loadInstruction->getAlign().value(), alignment);
75  }
76 }
77 
78 TEST(IpGraphToLlvmConverterTests, LoadVolatileConversion)
79 {
80  using namespace jlm::llvm;
81 
82  // Arrange
83  auto pointerType = PointerType::Create();
84  auto ioStateType = IOStateType::Create();
85  auto memoryStateType = MemoryStateType::Create();
86  auto bit64Type = jlm::rvsdg::BitType::Create(64);
87  auto functionType = jlm::rvsdg::FunctionType::Create(
90 
91  InterProceduralGraphModule ipgModule(jlm::util::FilePath(""), "", "");
92 
93  auto cfg = ControlFlowGraph::create(ipgModule);
94  auto addressArgument = cfg->entry()->append_argument(Argument::create("address", pointerType));
95  auto ioStateArgument = cfg->entry()->append_argument(Argument::create("ioState", ioStateType));
96  auto memoryStateArgument =
97  cfg->entry()->append_argument(Argument::create("memoryState", memoryStateType));
98 
99  auto basicBlock = BasicBlock::create(*cfg);
100  size_t alignment = 4;
101  auto loadTac = basicBlock->append_last(LoadVolatileOperation::Create(
102  addressArgument,
103  ioStateArgument,
104  memoryStateArgument,
105  bit64Type,
106  alignment));
107 
108  cfg->exit()->divert_inedges(basicBlock);
109  basicBlock->add_outedge(cfg->exit());
110  cfg->exit()->append_result(loadTac->result(0));
111  cfg->exit()->append_result(loadTac->result(1));
112  cfg->exit()->append_result(loadTac->result(2));
113 
114  auto f = FunctionNode::create(ipgModule.ipgraph(), "f", functionType, Linkage::externalLinkage);
115  f->add_cfg(std::move(cfg));
116 
117  print(ipgModule, stdout);
118 
119  // Act
120  llvm::LLVMContext ctx;
121  auto llvmModule = IpGraphToLlvmConverter::CreateAndConvertModule(ipgModule, ctx);
122  llvmModule->print(llvm::errs(), nullptr);
123 
124  // Assert
125  {
126  auto llvmFunction = llvmModule->getFunction("f");
127  auto & basicBlock = llvmFunction->back();
128  auto & instruction = basicBlock.front();
129 
130  auto loadInstruction = ::llvm::dyn_cast<::llvm::LoadInst>(&instruction);
131  EXPECT_NE(loadInstruction, nullptr);
132  EXPECT_TRUE(loadInstruction->isVolatile());
133  EXPECT_EQ(loadInstruction->getAlign().value(), alignment);
134  }
135 }
136 
137 TEST(IpGraphToLlvmConverterTests, MemCpyConversion)
138 {
139  using namespace jlm::llvm;
140 
141  // Arrange
142  auto pointerType = PointerType::Create();
143  auto memoryStateType = MemoryStateType::Create();
144  auto bit64Type = jlm::rvsdg::BitType::Create(64);
145  auto functionType = jlm::rvsdg::FunctionType::Create(
151 
152  InterProceduralGraphModule ipgModule(jlm::util::FilePath(""), "", "");
153 
154  auto cfg = ControlFlowGraph::create(ipgModule);
155  auto destinationArgument =
156  cfg->entry()->append_argument(Argument::create("destination", pointerType));
157  auto sourceArgument = cfg->entry()->append_argument(Argument::create("source", pointerType));
158  auto lengthArgument = cfg->entry()->append_argument(Argument::create("length", bit64Type));
159  auto memoryStateArgument =
160  cfg->entry()->append_argument(Argument::create("memoryState", memoryStateType));
161 
162  auto basicBlock = BasicBlock::create(*cfg);
163  auto memCpyTac = basicBlock->append_last(MemCpyNonVolatileOperation::create(
164  destinationArgument,
165  sourceArgument,
166  lengthArgument,
167  { memoryStateArgument }));
168 
169  cfg->exit()->divert_inedges(basicBlock);
170  basicBlock->add_outedge(cfg->exit());
171  cfg->exit()->append_result(memCpyTac->result(0));
172 
173  auto f = FunctionNode::create(ipgModule.ipgraph(), "f", functionType, Linkage::externalLinkage);
174  f->add_cfg(std::move(cfg));
175 
176  print(ipgModule, stdout);
177 
178  // Act
179  llvm::LLVMContext ctx;
180  auto llvmModule = IpGraphToLlvmConverter::CreateAndConvertModule(ipgModule, ctx);
181  llvmModule->print(llvm::errs(), nullptr);
182 
183  // Assert
184  {
185  auto llvmFunction = llvmModule->getFunction("f");
186  auto & basicBlock = llvmFunction->back();
187  auto & instruction = basicBlock.front();
188 
189  auto memCpyInstruction = ::llvm::dyn_cast<::llvm::CallInst>(&instruction);
190  EXPECT_NE(memCpyInstruction, nullptr);
191  EXPECT_EQ(memCpyInstruction->getIntrinsicID(), ::llvm::Intrinsic::memcpy);
192  EXPECT_FALSE(memCpyInstruction->isVolatile());
193  }
194 }
195 
196 TEST(IpGraphToLlvmConverterTests, MemCpyVolatileConversion)
197 {
198  using namespace jlm::llvm;
199 
200  // Arrange
201  auto pointerType = PointerType::Create();
202  auto ioStateType = IOStateType::Create();
203  auto memoryStateType = MemoryStateType::Create();
204  auto bit64Type = jlm::rvsdg::BitType::Create(64);
205  auto functionType = jlm::rvsdg::FunctionType::Create(
212 
213  InterProceduralGraphModule ipgModule(jlm::util::FilePath(""), "", "");
214 
215  auto cfg = ControlFlowGraph::create(ipgModule);
216  auto & destinationArgument =
217  *cfg->entry()->append_argument(Argument::create("destination", pointerType));
218  auto & sourceArgument = *cfg->entry()->append_argument(Argument::create("source", pointerType));
219  auto & lengthArgument = *cfg->entry()->append_argument(Argument::create("length", bit64Type));
220  auto & ioStateArgument = *cfg->entry()->append_argument(Argument::create("ioState", ioStateType));
221  auto & memoryStateArgument =
222  *cfg->entry()->append_argument(Argument::create("memoryState", memoryStateType));
223 
224  auto basicBlock = BasicBlock::create(*cfg);
225  auto memCpyTac = basicBlock->append_last(MemCpyVolatileOperation::CreateThreeAddressCode(
226  destinationArgument,
227  sourceArgument,
228  lengthArgument,
229  ioStateArgument,
230  { &memoryStateArgument }));
231 
232  cfg->exit()->divert_inedges(basicBlock);
233  basicBlock->add_outedge(cfg->exit());
234  cfg->exit()->append_result(memCpyTac->result(0));
235  cfg->exit()->append_result(memCpyTac->result(1));
236 
237  auto f = FunctionNode::create(ipgModule.ipgraph(), "f", functionType, Linkage::externalLinkage);
238  f->add_cfg(std::move(cfg));
239 
240  print(ipgModule, stdout);
241 
242  // Act
243  llvm::LLVMContext ctx;
244  auto llvmModule = IpGraphToLlvmConverter::CreateAndConvertModule(ipgModule, ctx);
245  llvmModule->print(llvm::errs(), nullptr);
246 
247  // Assert
248  {
249  auto llvmFunction = llvmModule->getFunction("f");
250  auto & basicBlock = llvmFunction->back();
251  auto & instruction = basicBlock.front();
252 
253  auto memCpyInstruction = ::llvm::dyn_cast<::llvm::CallInst>(&instruction);
254  EXPECT_NE(memCpyInstruction, nullptr);
255  EXPECT_EQ(memCpyInstruction->getIntrinsicID(), ::llvm::Intrinsic::memcpy);
256  EXPECT_TRUE(memCpyInstruction->isVolatile());
257  }
258 }
259 
260 TEST(IpGraphToLlvmConverterTests, MemSetConversion)
261 {
262  using namespace jlm::llvm;
263 
264  // Arrange
265  auto pointerType = PointerType::Create();
266  auto memoryStateType = MemoryStateType::Create();
267  auto bit8Type = jlm::rvsdg::BitType::Create(8);
268  auto bit64Type = jlm::rvsdg::BitType::Create(64);
269  auto functionType = jlm::rvsdg::FunctionType::Create(
270  { pointerType, bit8Type, bit64Type, memoryStateType },
271  { memoryStateType });
272 
273  InterProceduralGraphModule ipgModule(jlm::util::FilePath(""), "", "");
274 
275  auto cfg = ControlFlowGraph::create(ipgModule);
276  auto destinationArgument =
277  cfg->entry()->append_argument(Argument::create("destination", pointerType));
278  auto valueArgument = cfg->entry()->append_argument(Argument::create("value", bit8Type));
279  auto lengthArgument = cfg->entry()->append_argument(Argument::create("length", bit64Type));
280  auto memoryStateArgument =
281  cfg->entry()->append_argument(Argument::create("memoryState", memoryStateType));
282 
283  auto basicBlock = BasicBlock::create(*cfg);
284  auto memsetTac = basicBlock->append_last(MemSetNonVolatileOperation::createTac(
285  *destinationArgument,
286  *valueArgument,
287  *lengthArgument,
288  { memoryStateArgument }));
289 
290  cfg->exit()->divert_inedges(basicBlock);
291  basicBlock->add_outedge(cfg->exit());
292  cfg->exit()->append_result(memsetTac->result(0));
293 
294  auto f = FunctionNode::create(ipgModule.ipgraph(), "f", functionType, Linkage::externalLinkage);
295  f->add_cfg(std::move(cfg));
296 
297  print(ipgModule, stdout);
298 
299  // Act
300  llvm::LLVMContext ctx;
301  auto llvmModule = IpGraphToLlvmConverter::CreateAndConvertModule(ipgModule, ctx);
302  llvmModule->print(llvm::errs(), nullptr);
303 
304  // Assert
305  {
306  auto llvmFunction = llvmModule->getFunction("f");
307  auto & basicBlock = llvmFunction->back();
308  auto & instruction = basicBlock.front();
309 
310  auto memsetInstruction = ::llvm::dyn_cast<::llvm::CallInst>(&instruction);
311  EXPECT_NE(memsetInstruction, nullptr);
312  EXPECT_EQ(memsetInstruction->getIntrinsicID(), ::llvm::Intrinsic::memset);
313  EXPECT_FALSE(memsetInstruction->isVolatile());
314  }
315 }
316 
317 TEST(IpGraphToLlvmConverterTests, StoreConversion)
318 {
319  using namespace jlm::llvm;
320 
321  // Arrange
322  auto pointerType = PointerType::Create();
323  auto memoryStateType = MemoryStateType::Create();
324  auto bit64Type = jlm::rvsdg::BitType::Create(64);
325  auto functionType = jlm::rvsdg::FunctionType::Create(
328 
329  InterProceduralGraphModule ipgModule(jlm::util::FilePath(""), "", "");
330 
331  auto cfg = ControlFlowGraph::create(ipgModule);
332  auto addressArgument = cfg->entry()->append_argument(Argument::create("address", pointerType));
333  auto valueArgument = cfg->entry()->append_argument(Argument::create("value", bit64Type));
334  auto memoryStateArgument =
335  cfg->entry()->append_argument(Argument::create("memoryState", memoryStateType));
336 
337  auto basicBlock = BasicBlock::create(*cfg);
338  size_t alignment = 4;
339  auto storeTac = basicBlock->append_last(StoreNonVolatileOperation::Create(
340  addressArgument,
341  valueArgument,
342  memoryStateArgument,
343  alignment));
344 
345  cfg->exit()->divert_inedges(basicBlock);
346  basicBlock->add_outedge(cfg->exit());
347  cfg->exit()->append_result(storeTac->result(0));
348 
349  auto f = FunctionNode::create(ipgModule.ipgraph(), "f", functionType, Linkage::externalLinkage);
350  f->add_cfg(std::move(cfg));
351 
352  print(ipgModule, stdout);
353 
354  // Act
355  llvm::LLVMContext ctx;
356  auto llvmModule = IpGraphToLlvmConverter::CreateAndConvertModule(ipgModule, ctx);
357  llvmModule->print(llvm::errs(), nullptr);
358 
359  // Assert
360  {
361  auto llvmFunction = llvmModule->getFunction("f");
362  auto & basicBlock = llvmFunction->back();
363  auto & instruction = basicBlock.front();
364 
365  auto storeInstruction = ::llvm::dyn_cast<::llvm::StoreInst>(&instruction);
366  EXPECT_NE(storeInstruction, nullptr);
367  EXPECT_FALSE(storeInstruction->isVolatile());
368  EXPECT_EQ(storeInstruction->getAlign().value(), alignment);
369  }
370 }
371 
372 TEST(IpGraphToLlvmConverterTests, StoreVolatileConversion)
373 {
374  using namespace jlm::llvm;
375 
376  // Arrange
377  auto pointerType = PointerType::Create();
378  auto ioStateType = IOStateType::Create();
379  auto memoryStateType = MemoryStateType::Create();
380  auto bit64Type = jlm::rvsdg::BitType::Create(64);
381  auto functionType = jlm::rvsdg::FunctionType::Create(
387 
388  InterProceduralGraphModule ipgModule(jlm::util::FilePath(""), "", "");
389 
390  auto cfg = ControlFlowGraph::create(ipgModule);
391  auto addressArgument = cfg->entry()->append_argument(Argument::create("address", pointerType));
392  auto valueArgument = cfg->entry()->append_argument(Argument::create("value", bit64Type));
393  auto ioStateArgument = cfg->entry()->append_argument(Argument::create("ioState", ioStateType));
394  auto memoryStateArgument =
395  cfg->entry()->append_argument(Argument::create("memoryState", memoryStateType));
396 
397  auto basicBlock = BasicBlock::create(*cfg);
398  size_t alignment = 4;
399  auto storeTac = basicBlock->append_last(StoreVolatileOperation::Create(
400  addressArgument,
401  valueArgument,
402  ioStateArgument,
403  memoryStateArgument,
404  alignment));
405 
406  cfg->exit()->divert_inedges(basicBlock);
407  basicBlock->add_outedge(cfg->exit());
408  cfg->exit()->append_result(storeTac->result(0));
409  cfg->exit()->append_result(storeTac->result(1));
410 
411  auto f = FunctionNode::create(ipgModule.ipgraph(), "f", functionType, Linkage::externalLinkage);
412  f->add_cfg(std::move(cfg));
413 
414  print(ipgModule, stdout);
415 
416  // Act
417  llvm::LLVMContext ctx;
418  auto llvmModule = IpGraphToLlvmConverter::CreateAndConvertModule(ipgModule, ctx);
419  llvmModule->print(llvm::errs(), nullptr);
420 
421  // Assert
422  {
423  auto llvmFunction = llvmModule->getFunction("f");
424  auto & basicBlock = llvmFunction->back();
425  auto & instruction = basicBlock.front();
426 
427  auto storeInstruction = ::llvm::dyn_cast<::llvm::StoreInst>(&instruction);
428  EXPECT_NE(storeInstruction, nullptr);
429  EXPECT_TRUE(storeInstruction->isVolatile());
430  EXPECT_EQ(storeInstruction->getAlign().value(), alignment);
431  }
432 }
433 
434 TEST(IpGraphToLlvmConverterTests, FMulAddConversion)
435 {
436  using namespace jlm::llvm;
437 
438  // Arrange
439  const auto pointerType = PointerType::Create();
440  const auto ioStateType = IOStateType::Create();
441  const auto memoryStateType = MemoryStateType::Create();
442  auto doubleType = FloatingPointType::Create(fpsize::dbl);
443  const auto functionType = jlm::rvsdg::FunctionType::Create(
444  { doubleType, doubleType, doubleType, IOStateType::Create(), MemoryStateType::Create() },
445  { doubleType, IOStateType::Create(), MemoryStateType::Create() });
446 
447  InterProceduralGraphModule ipgModule(jlm::util::FilePath(""), "", "");
448  {
449  auto cfg = ControlFlowGraph::create(ipgModule);
450  auto & multiplierArgument =
451  *cfg->entry()->append_argument(Argument::create("multiplier", doubleType));
452  auto & multiplicandArgument =
453  *cfg->entry()->append_argument(Argument::create("multiplicand", doubleType));
454  auto & summandArgument =
455  *cfg->entry()->append_argument(Argument::create("summand", doubleType));
456  const auto ioStateArgument =
457  cfg->entry()->append_argument(Argument::create("ioState", ioStateType));
458  const auto memoryStateArgument =
459  cfg->entry()->append_argument(Argument::create("memoryState", memoryStateType));
460 
461  auto basicBlock = BasicBlock::create(*cfg);
462  auto fMulAddTac = basicBlock->append_last(FMulAddIntrinsicOperation::CreateTac(
463  multiplierArgument,
464  multiplicandArgument,
465  summandArgument));
466 
467  cfg->exit()->divert_inedges(basicBlock);
468  basicBlock->add_outedge(cfg->exit());
469  cfg->exit()->append_result(fMulAddTac->result(0));
470  cfg->exit()->append_result(ioStateArgument);
471  cfg->exit()->append_result(memoryStateArgument);
472 
473  auto f = FunctionNode::create(ipgModule.ipgraph(), "f", functionType, Linkage::externalLinkage);
474  f->add_cfg(std::move(cfg));
475  }
476 
477  print(ipgModule, stdout);
478 
479  // Act
480  llvm::LLVMContext ctx;
481  const auto llvmModule = IpGraphToLlvmConverter::CreateAndConvertModule(ipgModule, ctx);
482  llvmModule->print(llvm::errs(), nullptr);
483 
484  // Assert
485  {
486  const auto llvmFunction = llvmModule->getFunction("f");
487  auto & basicBlock = llvmFunction->back();
488  auto & instruction = basicBlock.front();
489 
490  const auto fMulAddInstruction = ::llvm::dyn_cast<::llvm::CallInst>(&instruction);
491  EXPECT_NE(fMulAddInstruction, nullptr);
492  EXPECT_EQ(fMulAddInstruction->getIntrinsicID(), ::llvm::Intrinsic::fmuladd);
493  }
494 }
495 
496 TEST(IpGraphToLlvmConverterTests, IntegerConstant)
497 {
498  const char * bs = "0100000000"
499  "0000000000"
500  "0000000000"
501  "0000000000"
502  "0000000000"
503  "0000000000"
504  "00001";
505 
506  using namespace jlm::llvm;
507 
509 
511 
513 
514  auto cfg = ControlFlowGraph::create(im);
515  auto bb = BasicBlock::create(*cfg);
516  bb->append_last(ThreeAddressCode::create(std::make_unique<IntegerConstantOperation>(vr), {}));
517  auto c = bb->last()->result(0);
518 
519  cfg->exit()->divert_inedges(bb);
520  bb->add_outedge(cfg->exit());
521  cfg->exit()->append_result(c);
522 
523  auto f = FunctionNode::create(im.ipgraph(), "f", ft, Linkage::externalLinkage);
524  f->add_cfg(std::move(cfg));
525 
526  print(im, stdout);
527 
528  llvm::LLVMContext ctx;
529  auto llvmModule = IpGraphToLlvmConverter::CreateAndConvertModule(im, ctx);
530 
531  llvmModule->print(llvm::errs(), nullptr);
532 }
533 
534 TEST(IpGraphToLlvmConverterTests, Malloc)
535 {
536  auto setup = []()
537  {
538  using namespace jlm::llvm;
539 
540  auto memoryStateType = MemoryStateType::Create();
541  auto pointerType = PointerType::Create();
542  auto ioStateType = IOStateType::Create();
544 
545  auto cfg = ControlFlowGraph::create(*im);
546  auto bb = BasicBlock::create(*cfg);
547  cfg->exit()->divert_inedges(bb);
548  bb->add_outedge(cfg->exit());
549 
550  auto size =
551  cfg->entry()->append_argument(Argument::create("size", jlm::rvsdg::BitType::Create(64)));
552  auto ioState =
553  cfg->entry()->append_argument(Argument::create("ioState", IOStateType::Create()));
554 
555  bb->append_last(MallocOperation::createTac(size, ioState));
556 
557  cfg->exit()->append_result(bb->last()->result(0));
558  cfg->exit()->append_result(bb->last()->result(1));
559  cfg->exit()->append_result(bb->last()->result(2));
560 
561  auto functionType = jlm::rvsdg::FunctionType::Create(
562  { jlm::rvsdg::BitType::Create(64), ioStateType },
563  { pointerType, ioStateType, memoryStateType });
564  auto f = FunctionNode::create(im->ipgraph(), "f", functionType, Linkage::externalLinkage);
565  f->add_cfg(std::move(cfg));
566 
567  return im;
568  };
569 
570  auto verify = [](const llvm::Module & m)
571  {
572  using namespace llvm;
573 
574  auto f = m.getFunction("f");
575  auto & bb = f->getEntryBlock();
576 
577  EXPECT_EQ(bb.sizeWithoutDebug(), 2);
578  EXPECT_EQ(bb.getFirstNonPHI()->getOpcode(), llvm::Instruction::Call);
579  EXPECT_EQ(bb.getTerminator()->getOpcode(), llvm::Instruction::Ret);
580  };
581 
582  auto im = setup();
583  print(*im, stdout);
584 
585  llvm::LLVMContext ctx;
587  llvmModule->print(llvm::errs(), nullptr);
588 
589  verify(*llvmModule);
590 }
591 
592 TEST(IpGraphToLlvmConverterTests, Free)
593 {
594  auto setup = []()
595  {
596  using namespace jlm::llvm;
597 
598  auto iot = IOStateType::Create();
599  auto mt = MemoryStateType::Create();
600  auto pt = PointerType::Create();
601 
602  auto ipgmod = InterProceduralGraphModule::create(jlm::util::FilePath(""), "", "");
603 
607  auto f = FunctionNode::create(ipgmod->ipgraph(), "f", ft, Linkage::externalLinkage);
608 
609  auto cfg = ControlFlowGraph::create(*ipgmod);
610  auto arg0 = cfg->entry()->append_argument(Argument::create("pointer", pt));
611  auto arg1 = cfg->entry()->append_argument(Argument::create("memstate", mt));
612  auto arg2 = cfg->entry()->append_argument(Argument::create("iostate", iot));
613 
614  auto bb = BasicBlock::create(*cfg);
615  cfg->exit()->divert_inedges(bb);
616  bb->add_outedge(cfg->exit());
617 
618  bb->append_last(FreeOperation::Create(arg0, { arg1 }, arg2));
619 
620  cfg->exit()->append_result(bb->last()->result(0));
621  cfg->exit()->append_result(bb->last()->result(1));
622 
623  f->add_cfg(std::move(cfg));
624 
625  return ipgmod;
626  };
627 
628  auto verify = [](const llvm::Module & module)
629  {
630  using namespace llvm;
631 
632  auto f = module.getFunction("f");
633  auto & bb = f->getEntryBlock();
634 
635  EXPECT_EQ(bb.sizeWithoutDebug(), 2);
636  EXPECT_EQ(bb.getFirstNonPHI()->getOpcode(), Instruction::Call);
637  EXPECT_EQ(bb.getTerminator()->getOpcode(), Instruction::Ret);
638  };
639 
640  auto ipgmod = setup();
641  print(*ipgmod, stdout);
642 
643  llvm::LLVMContext ctx;
644  auto llvmModule = jlm::llvm::IpGraphToLlvmConverter::CreateAndConvertModule(*ipgmod, ctx);
645  llvmModule->print(llvm::errs(), nullptr);
646 
647  verify(*llvmModule);
648 }
649 
650 TEST(IpGraphToLlvmConverterTests, IgnoreMemoryState)
651 {
652  using namespace jlm::rvsdg;
653  using namespace jlm::llvm;
654 
655  auto mt = MemoryStateType::Create();
657 
658  std::unique_ptr<ControlFlowGraph> cfg(new ControlFlowGraph(m));
659  auto bb = BasicBlock::create(*cfg);
660  cfg->exit()->divert_inedges(bb);
661  bb->add_outedge(cfg->exit());
662 
663  bb->append_last(UndefValueOperation::Create(mt, "s1"));
664  auto s1 = bb->last()->result(0);
665 
666  cfg->exit()->append_result(s1);
667 
668  auto ft = FunctionType::Create({}, { mt });
669  auto f = FunctionNode::create(m.ipgraph(), "f", ft, Linkage::externalLinkage);
670  f->add_cfg(std::move(cfg));
671 
672  llvm::LLVMContext ctx;
673  IpGraphToLlvmConverter::CreateAndConvertModule(m, ctx);
674 }
675 
676 TEST(IpGraphToLlvmConverterTests, SelectWithState)
677 {
678  using namespace jlm::llvm;
679 
681  auto pt = PointerType::Create();
682  auto mt = MemoryStateType::Create();
684 
685  std::unique_ptr<ControlFlowGraph> cfg(new ControlFlowGraph(m));
686  auto bb = BasicBlock::create(*cfg);
687  cfg->exit()->divert_inedges(bb);
688  bb->add_outedge(cfg->exit());
689 
690  auto p = cfg->entry()->append_argument(Argument::create("p", jlm::rvsdg::BitType::Create(1)));
691  auto s1 = cfg->entry()->append_argument(Argument::create("s1", mt));
692  auto s2 = cfg->entry()->append_argument(Argument::create("s2", mt));
693 
694  bb->append_last(SelectOperation::create(p, s1, s2));
695  auto s3 = bb->last()->result(0);
696 
697  cfg->exit()->append_result(s3);
698  cfg->exit()->append_result(s3);
699 
701  { jlm::rvsdg::BitType::Create(1), MemoryStateType::Create(), MemoryStateType::Create() },
702  { MemoryStateType::Create(), MemoryStateType::Create() });
703  auto f = FunctionNode::create(m.ipgraph(), "f", ft, Linkage::externalLinkage);
704  f->add_cfg(std::move(cfg));
705 
706  print(m, stdout);
707 
708  llvm::LLVMContext ctx;
709  IpGraphToLlvmConverter::CreateAndConvertModule(m, ctx);
710 }
711 
712 TEST(IpGraphToLlvmConverterTests, TestAttributeKindConversion)
713 {
714  typedef jlm::llvm::Attribute::kind ak;
715 
716  int begin = static_cast<int>(ak::None);
717  int end = static_cast<int>(ak::EndAttrKinds);
718  for (int attributeKind = begin; attributeKind != end; attributeKind++)
719  {
720  jlm::llvm::IpGraphToLlvmConverter::ConvertAttributeKind(static_cast<ak>(attributeKind));
721  }
722 }
723 
724 TEST(IpGraphToLlvmConverterTests, CallingConvConversion)
725 {
733  using namespace jlm::llvm;
734 
735  // Arrange
736  auto bit64Type = jlm::rvsdg::BitType::Create(64);
737  auto ioStateType = IOStateType::Create();
738  auto memoryStateType = MemoryStateType::Create();
739  auto functionType = jlm::rvsdg::FunctionType::Create(
740  { bit64Type, ioStateType, memoryStateType },
741  { bit64Type, ioStateType, memoryStateType });
742 
743  InterProceduralGraphModule ipgModule(jlm::util::FilePath(""), "", "");
744 
745  auto imported = FunctionNode::create(
746  ipgModule.ipgraph(),
747  "imported",
748  functionType,
749  Linkage::externalLinkage,
750  CallingConvention::Fast,
751  {});
752  auto importedVariable = ipgModule.create_variable(imported);
753 
754  auto callee = FunctionNode::create(
755  ipgModule.ipgraph(),
756  "callee",
757  functionType,
758  Linkage::externalLinkage,
759  CallingConvention::Cold,
760  {});
761  auto calleeVariable = ipgModule.create_variable(callee);
762 
763  // Create the body of the callee
764  {
765  auto cfg = ControlFlowGraph::create(ipgModule);
766  auto valueArgument = cfg->entry()->append_argument(Argument::create("value", bit64Type));
767  auto ioStateArgument = cfg->entry()->append_argument(Argument::create("ioState", ioStateType));
768  auto memoryStateArgument =
769  cfg->entry()->append_argument(Argument::create("memoryState", memoryStateType));
770 
771  auto basicBlock = BasicBlock::create(*cfg);
772  cfg->exit()->divert_inedges(basicBlock);
773  basicBlock->add_outedge(cfg->exit());
774  cfg->exit()->append_result(valueArgument);
775  cfg->exit()->append_result(ioStateArgument);
776  cfg->exit()->append_result(memoryStateArgument);
777 
778  callee->add_cfg(std::move(cfg));
779  }
780 
781  auto caller = FunctionNode::create(
782  ipgModule.ipgraph(),
783  "caller",
784  functionType,
785  Linkage::externalLinkage,
786  CallingConvention::Tail,
787  {});
788  ipgModule.create_variable(caller);
789 
790  // Create the body of the caller
791  {
792  auto cfg = ControlFlowGraph::create(ipgModule);
793  auto valueArgument = cfg->entry()->append_argument(Argument::create("value", bit64Type));
794  auto ioStateArgument = cfg->entry()->append_argument(Argument::create("ioState", ioStateType));
795  auto memoryStateArgument =
796  cfg->entry()->append_argument(Argument::create("memoryState", memoryStateType));
797 
798  auto basicBlock = BasicBlock::create(*cfg);
799  auto importedCall = basicBlock->append_last(CallOperation::create(
800  importedVariable,
801  functionType,
802  CallingConvention::Fast,
803  AttributeList::createEmptyList(),
804  { valueArgument, ioStateArgument, memoryStateArgument }));
805  auto calleeCall = basicBlock->append_last(CallOperation::create(
806  calleeVariable,
807  functionType,
808  CallingConvention::Cold,
809  AttributeList::createEmptyList(),
810  { importedCall->result(0), importedCall->result(1), importedCall->result(2) }));
811 
812  cfg->exit()->divert_inedges(basicBlock);
813  basicBlock->add_outedge(cfg->exit());
814  cfg->exit()->append_result(calleeCall->result(0));
815  cfg->exit()->append_result(calleeCall->result(1));
816  cfg->exit()->append_result(calleeCall->result(2));
817 
818  caller->add_cfg(std::move(cfg));
819  }
820 
821  print(ipgModule, stdout);
822 
823  // Act
824  llvm::LLVMContext ctx;
825  auto llvmModule = IpGraphToLlvmConverter::CreateAndConvertModule(ipgModule, ctx);
826 
827  // Assert
828  {
829  auto importedFunction = llvmModule->getFunction("imported");
830  auto calleeFunction = llvmModule->getFunction("callee");
831  auto callerFunction = llvmModule->getFunction("caller");
832 
833  ASSERT_NE(importedFunction, nullptr);
834  ASSERT_NE(calleeFunction, nullptr);
835  ASSERT_NE(callerFunction, nullptr);
836 
837  EXPECT_TRUE(importedFunction->empty());
838  EXPECT_FALSE(calleeFunction->empty());
839  EXPECT_FALSE(callerFunction->empty());
840 
841  EXPECT_EQ(importedFunction->getCallingConv(), ::llvm::CallingConv::Fast);
842  EXPECT_EQ(calleeFunction->getCallingConv(), ::llvm::CallingConv::Cold);
843  EXPECT_EQ(callerFunction->getCallingConv(), ::llvm::CallingConv::Tail);
844 
845  std::vector<const ::llvm::CallInst *> callInstructions;
846  for (const auto & instruction : callerFunction->getEntryBlock())
847  {
848  if (const auto callInstruction = ::llvm::dyn_cast<::llvm::CallInst>(&instruction))
849  callInstructions.push_back(callInstruction);
850  }
851 
852  ASSERT_EQ(callInstructions.size(), 2u);
853  ASSERT_NE(callInstructions[0]->getCalledFunction(), nullptr);
854  ASSERT_NE(callInstructions[1]->getCalledFunction(), nullptr);
855 
856  EXPECT_EQ(callInstructions[0]->getCalledFunction()->getName(), "imported");
857  EXPECT_EQ(callInstructions[0]->getCallingConv(), ::llvm::CallingConv::Fast);
858  EXPECT_EQ(callInstructions[1]->getCalledFunction()->getName(), "callee");
859  EXPECT_EQ(callInstructions[1]->getCallingConv(), ::llvm::CallingConv::Cold);
860  }
861 }
static const char * bs[]
TEST(IpGraphToLlvmConverterTests, LoadConversion)
static const auto vt
Definition: PullTests.cpp:16
static std::unique_ptr< Argument > create(const std::string &name, std::shared_ptr< const jlm::rvsdg::Type > type, const AttributeSet &attributes)
Definition: cfg.hpp:59
static BasicBlock * create(ControlFlowGraph &cfg)
Definition: basic-block.cpp:37
static std::unique_ptr< ControlFlowGraph > create(InterProceduralGraphModule &im)
Definition: cfg.hpp:267
static std::unique_ptr< ThreeAddressCode > CreateTac(const Variable &multiplier, const Variable &multiplicand, const Variable &summand)
static std::shared_ptr< const FloatingPointType > Create(fpsize size)
Definition: types.cpp:117
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *pointer, const std::vector< const Variable * > &memoryStates, const Variable *iOState)
Definition: operators.hpp:2558
static FunctionNode * create(InterProceduralGraph &ipg, const std::string &name, std::shared_ptr< const rvsdg::FunctionType > type, const llvm::Linkage &linkage, const CallingConvention &callingConvention, const AttributeSet &attributes)
Definition: ipgraph.hpp:242
static std::shared_ptr< const IOStateType > Create()
Definition: types.cpp:343
static std::unique_ptr< InterProceduralGraphModule > create(const jlm::util::FilePath &sourceFilename, const std::string &targetTriple, const std::string &dataLayout)
InterProceduralGraph & ipgraph() noexcept
::llvm::Attribute::AttrKind ConvertAttributeKind(const Attribute::kind &kind)
static std::unique_ptr<::llvm::Module > CreateAndConvertModule(InterProceduralGraphModule &ipGraphModule, ::llvm::LLVMContext &ctx)
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *state, std::shared_ptr< const rvsdg::Type > loadedType, size_t alignment)
Definition: Load.hpp:444
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *iOState, const Variable *memoryState, std::shared_ptr< const rvsdg::Type > loadedType, size_t alignment)
Definition: Load.hpp:243
static std::unique_ptr< ThreeAddressCode > createTac(const Variable *size, const Variable *ioState)
Definition: operators.hpp:2485
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *destination, const Variable *source, const Variable *length, const std::vector< const Variable * > &memoryStates)
static std::unique_ptr< llvm::ThreeAddressCode > CreateThreeAddressCode(const Variable &destination, const Variable &source, const Variable &length, const Variable &ioState, const std::vector< const Variable * > &memoryStates)
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &destination, const Variable &value, const Variable &length, const std::vector< const Variable * > &memoryStates)
static std::shared_ptr< const MemoryStateType > Create()
Definition: types.cpp:379
static std::shared_ptr< const PointerType > Create()
Definition: types.cpp:45
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *state, size_t alignment)
Definition: Store.hpp:304
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *ioState, const Variable *memoryState, size_t alignment)
Definition: Store.hpp:439
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition: tac.hpp:135
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 FunctionType > Create(std::vector< std::shared_ptr< const jlm::rvsdg::Type >> argumentTypes, std::vector< std::shared_ptr< const jlm::rvsdg::Type >> resultTypes)
static std::shared_ptr< const TestType > createValueType()
Definition: TestType.cpp:67
Global memory state passed between functions.
void print(const AggregationNode &n, const AnnotationMap &dm, FILE *out)
Definition: print.cpp:120