Jlm
Loading...
Searching...
No Matches
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>
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
25TEST(IpGraphToLlvmConverterTests, LoadConversion)
26{
27 using namespace jlm::llvm;
28
29 // Arrange
30 auto functionType = jlm::rvsdg::FunctionType::Create(
31 { PointerType::Create(), MemoryStateType::Create() },
32 { jlm::rvsdg::BitType::Create(64), MemoryStateType::Create() });
33
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
78TEST(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(
88 { PointerType::Create(), IOStateType::Create(), MemoryStateType::Create() },
89 { jlm::rvsdg::BitType::Create(64), IOStateType::Create(), MemoryStateType::Create() });
90
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
137TEST(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(
146 { PointerType::Create(),
147 PointerType::Create(),
149 MemoryStateType::Create() },
150 { MemoryStateType::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
196TEST(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(
206 { PointerType::Create(),
207 PointerType::Create(),
209 IOStateType::Create(),
210 MemoryStateType::Create() },
211 { IOStateType::Create(), MemoryStateType::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
260TEST(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
317TEST(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(
326 { PointerType::Create(), jlm::rvsdg::BitType::Create(64), MemoryStateType::Create() },
327 { MemoryStateType::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
372TEST(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(
382 { PointerType::Create(),
384 IOStateType::Create(),
385 MemoryStateType::Create() },
386 { IOStateType::Create(), MemoryStateType::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
434TEST(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
496TEST(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
534TEST(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();
543 auto im = InterProceduralGraphModule::create(jlm::util::FilePath(""), "", "");
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(), 2u);
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
592TEST(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
605 { PointerType::Create(), MemoryStateType::Create(), IOStateType::Create() },
606 { MemoryStateType::Create(), IOStateType::Create() });
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(), 2u);
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
650TEST(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
676TEST(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
712TEST(IpGraphToLlvmConverterTests, TestAttributeKindConversion)
713{
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
724TEST(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[]
static void print(const jlm::util::DisjointSet< int >::Set &set)
TEST(IpGraphToLlvmConverterTests, LoadConversion)
static const auto vt
Definition PullTests.cpp:16
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::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.