6 #include <gtest/gtest.h>
20 #include <llvm/IR/Instructions.h>
21 #include <llvm/IR/Intrinsics.h>
22 #include <llvm/IR/LLVMContext.h>
23 #include <llvm/IR/Module.h>
25 TEST(IpGraphToLlvmConverterTests, LoadConversion)
37 auto addressArgument =
39 auto memoryStateArgument =
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));
56 f->add_cfg(std::move(cfg));
58 print(ipgModule, stdout);
61 llvm::LLVMContext ctx;
63 llvmModule->print(llvm::errs(),
nullptr);
67 auto llvmFunction = llvmModule->getFunction(
"f");
68 auto & basicBlock = llvmFunction->back();
69 auto & instruction = basicBlock.front();
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);
78 TEST(IpGraphToLlvmConverterTests, LoadVolatileConversion)
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));
100 size_t alignment = 4;
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));
115 f->add_cfg(std::move(cfg));
117 print(ipgModule, stdout);
120 llvm::LLVMContext ctx;
122 llvmModule->print(llvm::errs(),
nullptr);
126 auto llvmFunction = llvmModule->getFunction(
"f");
127 auto & basicBlock = llvmFunction->back();
128 auto & instruction = basicBlock.front();
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);
137 TEST(IpGraphToLlvmConverterTests, MemCpyConversion)
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));
167 { memoryStateArgument }));
169 cfg->exit()->divert_inedges(basicBlock);
170 basicBlock->add_outedge(cfg->exit());
171 cfg->exit()->append_result(memCpyTac->result(0));
174 f->add_cfg(std::move(cfg));
176 print(ipgModule, stdout);
179 llvm::LLVMContext ctx;
181 llvmModule->print(llvm::errs(),
nullptr);
185 auto llvmFunction = llvmModule->getFunction(
"f");
186 auto & basicBlock = llvmFunction->back();
187 auto & instruction = basicBlock.front();
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());
196 TEST(IpGraphToLlvmConverterTests, MemCpyVolatileConversion)
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));
230 { &memoryStateArgument }));
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));
238 f->add_cfg(std::move(cfg));
240 print(ipgModule, stdout);
243 llvm::LLVMContext ctx;
245 llvmModule->print(llvm::errs(),
nullptr);
249 auto llvmFunction = llvmModule->getFunction(
"f");
250 auto & basicBlock = llvmFunction->back();
251 auto & instruction = basicBlock.front();
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());
260 TEST(IpGraphToLlvmConverterTests, MemSetConversion)
270 { pointerType, bit8Type, bit64Type, memoryStateType },
271 { memoryStateType });
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));
285 *destinationArgument,
288 { memoryStateArgument }));
290 cfg->exit()->divert_inedges(basicBlock);
291 basicBlock->add_outedge(cfg->exit());
292 cfg->exit()->append_result(memsetTac->result(0));
295 f->add_cfg(std::move(cfg));
297 print(ipgModule, stdout);
300 llvm::LLVMContext ctx;
302 llvmModule->print(llvm::errs(),
nullptr);
306 auto llvmFunction = llvmModule->getFunction(
"f");
307 auto & basicBlock = llvmFunction->back();
308 auto & instruction = basicBlock.front();
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());
317 TEST(IpGraphToLlvmConverterTests, StoreConversion)
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));
338 size_t alignment = 4;
345 cfg->exit()->divert_inedges(basicBlock);
346 basicBlock->add_outedge(cfg->exit());
347 cfg->exit()->append_result(storeTac->result(0));
350 f->add_cfg(std::move(cfg));
352 print(ipgModule, stdout);
355 llvm::LLVMContext ctx;
357 llvmModule->print(llvm::errs(),
nullptr);
361 auto llvmFunction = llvmModule->getFunction(
"f");
362 auto & basicBlock = llvmFunction->back();
363 auto & instruction = basicBlock.front();
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);
372 TEST(IpGraphToLlvmConverterTests, StoreVolatileConversion)
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));
398 size_t alignment = 4;
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));
412 f->add_cfg(std::move(cfg));
414 print(ipgModule, stdout);
417 llvm::LLVMContext ctx;
419 llvmModule->print(llvm::errs(),
nullptr);
423 auto llvmFunction = llvmModule->getFunction(
"f");
424 auto & basicBlock = llvmFunction->back();
425 auto & instruction = basicBlock.front();
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);
434 TEST(IpGraphToLlvmConverterTests, FMulAddConversion)
450 auto & multiplierArgument =
452 auto & multiplicandArgument =
453 *cfg->entry()->append_argument(
Argument::create(
"multiplicand", doubleType));
454 auto & summandArgument =
456 const auto ioStateArgument =
458 const auto memoryStateArgument =
459 cfg->entry()->append_argument(
Argument::create(
"memoryState", memoryStateType));
464 multiplicandArgument,
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);
474 f->add_cfg(std::move(cfg));
477 print(ipgModule, stdout);
480 llvm::LLVMContext ctx;
482 llvmModule->print(llvm::errs(),
nullptr);
486 const auto llvmFunction = llvmModule->getFunction(
"f");
487 auto & basicBlock = llvmFunction->back();
488 auto & instruction = basicBlock.front();
490 const auto fMulAddInstruction = ::llvm::dyn_cast<::llvm::CallInst>(&instruction);
491 EXPECT_NE(fMulAddInstruction,
nullptr);
492 EXPECT_EQ(fMulAddInstruction->getIntrinsicID(), ::llvm::Intrinsic::fmuladd);
496 TEST(IpGraphToLlvmConverterTests, IntegerConstant)
498 const char *
bs =
"0100000000"
517 auto c = bb->last()->result(0);
519 cfg->exit()->divert_inedges(bb);
520 bb->add_outedge(cfg->exit());
521 cfg->exit()->append_result(c);
524 f->add_cfg(std::move(cfg));
528 llvm::LLVMContext ctx;
531 llvmModule->print(llvm::errs(),
nullptr);
534 TEST(IpGraphToLlvmConverterTests, Malloc)
547 cfg->exit()->divert_inedges(bb);
548 bb->add_outedge(cfg->exit());
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));
563 { pointerType, ioStateType, memoryStateType });
565 f->add_cfg(std::move(cfg));
570 auto verify = [](
const llvm::Module & m)
572 using namespace llvm;
574 auto f = m.getFunction(
"f");
575 auto & bb = f->getEntryBlock();
577 EXPECT_EQ(bb.sizeWithoutDebug(), 2);
578 EXPECT_EQ(bb.getFirstNonPHI()->getOpcode(), llvm::Instruction::Call);
579 EXPECT_EQ(bb.getTerminator()->getOpcode(), llvm::Instruction::Ret);
585 llvm::LLVMContext ctx;
587 llvmModule->print(llvm::errs(),
nullptr);
592 TEST(IpGraphToLlvmConverterTests, Free)
611 auto arg1 = cfg->entry()->append_argument(
Argument::create(
"memstate", mt));
612 auto arg2 = cfg->entry()->append_argument(
Argument::create(
"iostate", iot));
615 cfg->exit()->divert_inedges(bb);
616 bb->add_outedge(cfg->exit());
620 cfg->exit()->append_result(bb->last()->result(0));
621 cfg->exit()->append_result(bb->last()->result(1));
623 f->add_cfg(std::move(cfg));
628 auto verify = [](
const llvm::Module & module)
630 using namespace llvm;
632 auto f = module.getFunction(
"f");
633 auto & bb = f->getEntryBlock();
635 EXPECT_EQ(bb.sizeWithoutDebug(), 2);
636 EXPECT_EQ(bb.getFirstNonPHI()->getOpcode(), Instruction::Call);
637 EXPECT_EQ(bb.getTerminator()->getOpcode(), Instruction::Ret);
640 auto ipgmod = setup();
641 print(*ipgmod, stdout);
643 llvm::LLVMContext ctx;
645 llvmModule->print(llvm::errs(),
nullptr);
650 TEST(IpGraphToLlvmConverterTests, IgnoreMemoryState)
655 auto mt = MemoryStateType::Create();
659 auto bb = BasicBlock::create(*cfg);
660 cfg->exit()->divert_inedges(bb);
661 bb->add_outedge(cfg->exit());
663 bb->append_last(UndefValueOperation::Create(mt,
"s1"));
664 auto s1 = bb->last()->result(0);
666 cfg->exit()->append_result(s1);
669 auto f = FunctionNode::create(m.
ipgraph(),
"f", ft, Linkage::externalLinkage);
670 f->add_cfg(std::move(cfg));
672 llvm::LLVMContext ctx;
673 IpGraphToLlvmConverter::CreateAndConvertModule(m, ctx);
676 TEST(IpGraphToLlvmConverterTests, SelectWithState)
681 auto pt = PointerType::Create();
682 auto mt = MemoryStateType::Create();
686 auto bb = BasicBlock::create(*cfg);
687 cfg->exit()->divert_inedges(bb);
688 bb->add_outedge(cfg->exit());
691 auto s1 = cfg->entry()->append_argument(Argument::create(
"s1", mt));
692 auto s2 = cfg->entry()->append_argument(Argument::create(
"s2", mt));
694 bb->append_last(SelectOperation::create(p, s1, s2));
695 auto s3 = bb->last()->result(0);
697 cfg->exit()->append_result(s3);
698 cfg->exit()->append_result(s3);
702 { MemoryStateType::Create(), MemoryStateType::Create() });
703 auto f = FunctionNode::create(m.
ipgraph(),
"f", ft, Linkage::externalLinkage);
704 f->add_cfg(std::move(cfg));
708 llvm::LLVMContext ctx;
709 IpGraphToLlvmConverter::CreateAndConvertModule(m, ctx);
712 TEST(IpGraphToLlvmConverterTests, TestAttributeKindConversion)
716 int begin =
static_cast<int>(ak::None);
717 int end =
static_cast<int>(ak::EndAttrKinds);
718 for (
int attributeKind = begin; attributeKind != end; attributeKind++)
724 TEST(IpGraphToLlvmConverterTests, CallingConvConversion)
737 auto ioStateType = IOStateType::Create();
738 auto memoryStateType = MemoryStateType::Create();
740 { bit64Type, ioStateType, memoryStateType },
741 { bit64Type, ioStateType, memoryStateType });
745 auto imported = FunctionNode::create(
749 Linkage::externalLinkage,
750 CallingConvention::Fast,
752 auto importedVariable = ipgModule.create_variable(imported);
754 auto callee = FunctionNode::create(
758 Linkage::externalLinkage,
759 CallingConvention::Cold,
761 auto calleeVariable = ipgModule.create_variable(callee);
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));
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);
778 callee->add_cfg(std::move(cfg));
781 auto caller = FunctionNode::create(
785 Linkage::externalLinkage,
786 CallingConvention::Tail,
788 ipgModule.create_variable(caller);
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));
798 auto basicBlock = BasicBlock::create(*cfg);
799 auto importedCall = basicBlock->append_last(CallOperation::create(
802 CallingConvention::Fast,
803 AttributeList::createEmptyList(),
804 { valueArgument, ioStateArgument, memoryStateArgument }));
805 auto calleeCall = basicBlock->append_last(CallOperation::create(
808 CallingConvention::Cold,
809 AttributeList::createEmptyList(),
810 { importedCall->result(0), importedCall->result(1), importedCall->result(2) }));
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));
818 caller->add_cfg(std::move(cfg));
821 print(ipgModule, stdout);
824 llvm::LLVMContext ctx;
825 auto llvmModule = IpGraphToLlvmConverter::CreateAndConvertModule(ipgModule, ctx);
829 auto importedFunction = llvmModule->getFunction(
"imported");
830 auto calleeFunction = llvmModule->getFunction(
"callee");
831 auto callerFunction = llvmModule->getFunction(
"caller");
833 ASSERT_NE(importedFunction,
nullptr);
834 ASSERT_NE(calleeFunction,
nullptr);
835 ASSERT_NE(callerFunction,
nullptr);
837 EXPECT_TRUE(importedFunction->empty());
838 EXPECT_FALSE(calleeFunction->empty());
839 EXPECT_FALSE(callerFunction->empty());
841 EXPECT_EQ(importedFunction->getCallingConv(), ::llvm::CallingConv::Fast);
842 EXPECT_EQ(calleeFunction->getCallingConv(), ::llvm::CallingConv::Cold);
843 EXPECT_EQ(callerFunction->getCallingConv(), ::llvm::CallingConv::Tail);
845 std::vector<const ::llvm::CallInst *> callInstructions;
846 for (
const auto & instruction : callerFunction->getEntryBlock())
848 if (
const auto callInstruction = ::llvm::dyn_cast<::llvm::CallInst>(&instruction))
849 callInstructions.push_back(callInstruction);
852 ASSERT_EQ(callInstructions.size(), 2u);
853 ASSERT_NE(callInstructions[0]->getCalledFunction(),
nullptr);
854 ASSERT_NE(callInstructions[1]->getCalledFunction(),
nullptr);
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);
TEST(IpGraphToLlvmConverterTests, LoadConversion)
static std::unique_ptr< Argument > create(const std::string &name, std::shared_ptr< const jlm::rvsdg::Type > type, const AttributeSet &attributes)
static BasicBlock * create(ControlFlowGraph &cfg)
static std::unique_ptr< ControlFlowGraph > create(InterProceduralGraphModule &im)
static std::unique_ptr< ThreeAddressCode > CreateTac(const Variable &multiplier, const Variable &multiplicand, const Variable &summand)
static std::shared_ptr< const FloatingPointType > Create(fpsize size)
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *pointer, const std::vector< const Variable * > &memoryStates, const Variable *iOState)
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)
static std::shared_ptr< const IOStateType > Create()
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)
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)
static std::unique_ptr< ThreeAddressCode > createTac(const Variable *size, const Variable *ioState)
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()
static std::shared_ptr< const PointerType > Create()
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *state, size_t alignment)
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *ioState, const Variable *memoryState, size_t alignment)
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
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()
Global memory state passed between functions.
void print(const AggregationNode &n, const AnnotationMap &dm, FILE *out)