Jlm
FunctionCallTests.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #include <gtest/gtest.h>
7 
12 #include <jlm/llvm/ir/print.hpp>
13 
14 #include <llvm/IR/BasicBlock.h>
15 #include <llvm/IR/IRBuilder.h>
16 #include <llvm/IR/Module.h>
17 
18 TEST(FunctionCallTests, test_function_call)
19 {
20  auto setup = [](llvm::LLVMContext & ctx)
21  {
22  using namespace llvm;
23 
24  std::unique_ptr<Module> module(new Module("module", ctx));
25 
26  auto int64 = Type::getIntNTy(ctx, 64);
27  auto clrtype = FunctionType::get(Type::getVoidTy(ctx), {}, false);
28  auto caller = Function::Create(clrtype, GlobalValue::ExternalLinkage, "caller", module.get());
29 
30  auto bb = BasicBlock::Create(ctx, "bb", caller);
31 
32  auto c = ConstantInt::get(int64, 45);
33  auto cletype = FunctionType::get(int64, ArrayRef<Type *>(std::vector<Type *>(2, int64)), false);
34  auto callee = module->getOrInsertFunction("callee", cletype);
35 
36  IRBuilder<> builder(bb);
37  builder.CreateCall(callee, ArrayRef<Value *>(std::vector<Value *>(2, c)));
38  builder.CreateRetVoid();
39 
40  return module;
41  };
42 
43  auto verify = [](const jlm::llvm::InterProceduralGraphModule & module)
44  {
45  using namespace jlm::llvm;
46 
47  ControlFlowGraph * cfg = nullptr;
48  for (auto & node : module.ipgraph())
49  {
50  if (node.name() == "caller")
51  {
52  cfg = dynamic_cast<const FunctionNode &>(node).cfg();
53  break;
54  }
55  }
56 
57  auto bb = dynamic_cast<const BasicBlock *>(cfg->entry()->OutEdge(0)->sink());
58  EXPECT_TRUE(is<CallOperation>(*std::next(bb->rbegin(), 2)));
59  };
60 
61  llvm::LLVMContext ctx;
62  auto llvmModule = setup(ctx);
63  llvmModule->print(llvm::errs(), nullptr);
64 
65  auto ipgmod = jlm::llvm::ConvertLlvmModule(*llvmModule);
66  print(*ipgmod, stdout);
67 
68  verify(*ipgmod);
69 }
70 
71 TEST(FunctionCallTests, test_malloc_call)
72 {
73  auto setup = [](llvm::LLVMContext & ctx)
74  {
75  using namespace llvm;
76 
77  std::unique_ptr<Module> module(new Module("module", ctx));
78 
79  auto int8 = Type::getIntNTy(ctx, 8);
80  auto int64 = Type::getIntNTy(ctx, 64);
81  auto ptrint8 = PointerType::get(int8, 0);
82 
83  auto clrtype = FunctionType::get(Type::getVoidTy(ctx), {}, false);
84  auto caller = Function::Create(clrtype, GlobalValue::ExternalLinkage, "caller", module.get());
85 
86  auto bb = BasicBlock::Create(ctx, "bb", caller);
87 
88  auto c = ConstantInt::get(int64, 45);
89  auto malloctype = FunctionType::get(ptrint8, ArrayRef<Type *>(int64), false);
90  auto malloc = module->getOrInsertFunction("malloc", malloctype);
91 
92  IRBuilder<> builder(bb);
93  builder.CreateCall(malloc, ArrayRef<Value *>(c));
94  builder.CreateRetVoid();
95 
96  return module;
97  };
98 
99  auto verify = [](const jlm::llvm::InterProceduralGraphModule & module)
100  {
101  using namespace jlm::llvm;
102 
103  ControlFlowGraph * cfg = nullptr;
104  for (auto & node : module.ipgraph())
105  {
106  if (node.name() == "caller")
107  {
108  cfg = dynamic_cast<const FunctionNode &>(node).cfg();
109  break;
110  }
111  }
112 
113  auto bb = dynamic_cast<const BasicBlock *>(cfg->entry()->OutEdge(0)->sink());
114  EXPECT_TRUE(is<MemoryStateMergeOperation>(*std::next(bb->rbegin())));
115  EXPECT_TRUE(is<MallocOperation>((*std::next(bb->rbegin(), 3))));
116  };
117 
118  llvm::LLVMContext ctx;
119  auto llvmModule = setup(ctx);
120  llvmModule->print(llvm::errs(), nullptr);
121 
122  auto ipgmod = jlm::llvm::ConvertLlvmModule(*llvmModule);
123  print(*ipgmod, stdout);
124 
125  verify(*ipgmod);
126 }
127 
128 TEST(FunctionCallTests, test_free_call)
129 {
130  auto setup = [](llvm::LLVMContext & ctx)
131  {
132  using namespace llvm;
133 
134  std::unique_ptr<Module> module(new Module("module", ctx));
135 
136  auto int8 = Type::getIntNTy(ctx, 8);
137  auto ptrint8 = PointerType::get(int8, 0);
138 
139  auto clrtype = FunctionType::get(Type::getVoidTy(ctx), { ptrint8 }, false);
140  auto caller = Function::Create(clrtype, GlobalValue::ExternalLinkage, "caller", module.get());
141 
142  auto bb = BasicBlock::Create(ctx, "bb", caller);
143 
144  auto freetype = FunctionType::get(Type::getVoidTy(ctx), ArrayRef<Type *>(ptrint8), false);
145  auto free = module->getOrInsertFunction("free", freetype);
146 
147  IRBuilder<> builder(bb);
148  builder.CreateCall(free, ArrayRef<Value *>(caller->getArg(0)));
149  builder.CreateRetVoid();
150 
151  return module;
152  };
153 
154  auto verify = [](const jlm::llvm::InterProceduralGraphModule & module)
155  {
156  using namespace jlm::llvm;
157 
158  ControlFlowGraph * cfg = nullptr;
159  for (auto & node : module.ipgraph())
160  {
161  if (node.name() == "caller")
162  {
163  cfg = dynamic_cast<const FunctionNode &>(node).cfg();
164  break;
165  }
166  }
167 
168  auto bb = dynamic_cast<const BasicBlock *>(cfg->entry()->OutEdge(0)->sink());
169  EXPECT_TRUE(is<AssignmentOperation>(*bb->rbegin()));
170  EXPECT_TRUE(is<AssignmentOperation>(*std::next(bb->rbegin())));
171  EXPECT_TRUE(is<FreeOperation>(*std::next(bb->rbegin(), 2)));
172  };
173 
174  llvm::LLVMContext ctx;
175  auto llvmModule = setup(ctx);
176  llvmModule->print(llvm::errs(), nullptr);
177 
178  auto ipgmod = jlm::llvm::ConvertLlvmModule(*llvmModule);
179  print(*ipgmod, stdout);
180 
181  verify(*ipgmod);
182 }
TEST(FunctionCallTests, test_function_call)
ControlFlowGraphNode * sink() const noexcept
Definition: cfg-node.hpp:57
ControlFlowGraphEdge * OutEdge(size_t n) const
Definition: cfg-node.hpp:115
EntryNode * entry() const noexcept
Definition: cfg.hpp:206
Global memory state passed between functions.
void print(const AggregationNode &n, const AnnotationMap &dm, FILE *out)
Definition: print.cpp:120
std::unique_ptr< InterProceduralGraphModule > ConvertLlvmModule(::llvm::Module &llvmModule)