6 #include <gtest/gtest.h>
15 #include <llvm/IR/BasicBlock.h>
16 #include <llvm/IR/IRBuilder.h>
17 #include <llvm/IRReader/IRReader.h>
49 TEST(LlvmPhiConversionTests, TestPhiConversion)
52 llvm::LLVMContext ctx;
53 llvm::Module module(
"popcount.c", ctx);
57 llvm::IRBuilder builder(ctx);
59 auto i64 = builder.getInt64Ty();
60 auto prototype = llvm::FunctionType::get(i64, { i64 },
false);
61 llvm::Function *
function =
62 llvm::Function::Create(prototype, llvm::Function::ExternalLinkage,
"popcount", module);
64 auto bb1 = llvm::BasicBlock::Create(ctx,
"bb1",
function);
65 auto bb2 = llvm::BasicBlock::Create(ctx,
"bb2",
function);
66 auto bb3 = llvm::BasicBlock::Create(ctx,
"bb3",
function);
67 auto bb4 = llvm::BasicBlock::Create(ctx,
"bb4",
function);
68 auto bb5 = llvm::BasicBlock::Create(ctx,
"bb5",
function);
69 auto bb6 = llvm::BasicBlock::Create(ctx,
"bb6",
function);
71 builder.SetInsertPoint(bb1);
72 builder.CreateBr(bb2);
74 builder.SetInsertPoint(bb2);
75 auto phiX = builder.CreatePHI(i64, 3);
76 auto phiPopcount = builder.CreatePHI(i64, 3);
78 auto xIs0 = builder.CreateICmpEQ(phiX, llvm::ConstantInt::get(i64, 0,
false));
79 builder.CreateCondBr(xIs0, bb6, bb3);
81 builder.SetInsertPoint(bb3);
82 auto rem = builder.CreateURem(phiX, llvm::ConstantInt::get(i64, 2,
false));
83 auto remEq1 = builder.CreateICmpEQ(rem, llvm::ConstantInt::get(i64, 1,
false));
84 auto halfX = builder.CreateLShr(phiX, llvm::ConstantInt::get(i64, 1,
false));
85 builder.CreateCondBr(remEq1, bb4, bb5);
87 builder.SetInsertPoint(bb4);
88 auto popcountPlus1 = builder.CreateAdd(phiPopcount, llvm::ConstantInt::get(i64, 1,
false));
89 builder.CreateBr(bb2);
91 builder.SetInsertPoint(bb5);
92 builder.CreateBr(bb2);
94 builder.SetInsertPoint(bb6);
95 builder.CreateRet(phiPopcount);
98 phiX->addIncoming(function->getArg(0), bb1);
99 phiX->addIncoming(halfX, bb4);
100 phiX->addIncoming(halfX, bb5);
102 phiPopcount->addIncoming(llvm::ConstantInt::get(i64, 0,
false), bb1);
103 phiPopcount->addIncoming(popcountPlus1, bb4);
104 phiPopcount->addIncoming(phiPopcount, bb5);
117 jlm::util::assertedCast<const jlm::llvm::FunctionNode>(ipgmod->ipgraph().find(
"popcount"));
118 auto entry_node = popcount->cfg()->entry();
119 EXPECT_TRUE(entry_node->single_successor());
120 auto bb1_node = entry_node->OutEdge(0)->sink();
121 EXPECT_TRUE(bb1_node->single_successor());
122 auto bb2_node = bb1_node->OutEdge(0)->sink();
123 auto bb2 = jlm::util::assertedCast<jlm::llvm::BasicBlock>(bb2_node);
126 auto tacs = bb2->begin();
128 auto & phiPopcnt = *std::next(tacs);
131 auto phiXOp = *jlm::util::assertedCast<const jlm::llvm::SsaPhiOperation>(&phiX->operation());
133 *jlm::util::assertedCast<const jlm::llvm::SsaPhiOperation>(&phiPopcnt->operation());
136 EXPECT_EQ(phiX->noperands(), 3u);
138 EXPECT_EQ(phiX->operand(0), popcount->cfg()->entry()->argument(0));
140 EXPECT_EQ(phiX->operand(1), phiX->operand(2));
142 EXPECT_EQ(phiPopcnt->noperands(), 3u);
144 auto constant0variable =
145 jlm::util::assertedCast<const jlm::llvm::ThreeAddressCodeVariable>(phiPopcnt->operand(0));
146 auto constant0op = jlm::util::assertedCast<const jlm::llvm::IntegerConstantOperation>(
147 &constant0variable->tac()->operation());
148 EXPECT_EQ(constant0op->Representation(), 0);
150 EXPECT_EQ(phiPopcnt->operand(2), phiPopcnt->result(0));
158 TEST(LlvmPhiConversionTests, TestPhiOperandElision)
161 llvm::LLVMContext ctx;
162 llvm::Module module(
"phi-elide.c", ctx);
166 llvm::IRBuilder builder(ctx);
168 auto i64 = builder.getInt64Ty();
169 auto prototype = llvm::FunctionType::get(i64, { i64 },
false);
170 llvm::Function *
function =
171 llvm::Function::Create(prototype, llvm::Function::ExternalLinkage,
"phi_elide", module);
173 auto bb1 = llvm::BasicBlock::Create(ctx,
"bb1",
function);
174 auto bb2 = llvm::BasicBlock::Create(ctx,
"bb2",
function);
175 auto bb3 = llvm::BasicBlock::Create(ctx,
"bb3",
function);
176 auto bb4 = llvm::BasicBlock::Create(ctx,
"bb4",
function);
177 auto bb5 = llvm::BasicBlock::Create(ctx,
"bb5",
function);
179 builder.SetInsertPoint(bb1);
180 auto xIs0 = builder.CreateICmpEQ(function->getArg(0), llvm::ConstantInt::get(i64, 0));
181 builder.CreateCondBr(xIs0, bb4, bb5);
183 builder.SetInsertPoint(bb2);
184 auto xPlus1 = builder.CreateAdd(function->getArg(0), llvm::ConstantInt::get(i64, 1));
185 auto xIs1 = builder.CreateICmpEQ(function->getArg(0), llvm::ConstantInt::get(i64, 1));
186 builder.CreateCondBr(xIs1, bb3, bb5);
188 builder.SetInsertPoint(bb3);
189 builder.CreateBr(bb5);
191 builder.SetInsertPoint(bb4);
192 auto xPlus2 = builder.CreateAdd(function->getArg(0), llvm::ConstantInt::get(i64, 2));
193 builder.CreateBr(bb5);
195 builder.SetInsertPoint(bb5);
196 auto bb5phi = builder.CreatePHI(i64, 4);
197 builder.CreateRet(bb5phi);
199 bb5phi->addIncoming(llvm::ConstantInt::get(i64, 0), bb1);
200 bb5phi->addIncoming(xPlus1, bb2);
201 bb5phi->addIncoming(function->getArg(0), bb3);
202 bb5phi->addIncoming(xPlus2, bb4);
205 module.print(llvm::errs(),
nullptr);
210 print(*ipgmod, stdout);
215 jlm::util::assertedCast<const jlm::llvm::FunctionNode>(ipgmod->ipgraph().find(
"phi_elide"));
218 size_t numBasicBlocks = 0;
219 std::vector<jlm::llvm::ThreeAddressCode *> phiTacs;
220 for (
auto & bb : *phi_elide->cfg())
225 if (jlm::rvsdg::is<jlm::llvm::SsaPhiOperation>(tac->operation()))
226 phiTacs.push_back(tac);
231 EXPECT_EQ(numBasicBlocks, 3u);
233 EXPECT_EQ(phiTacs.size(), 1u);
234 auto phiTac = phiTacs[0];
236 EXPECT_EQ(phiTac->noperands(), 2u);
238 auto constant0variable =
239 jlm::util::assertedCast<const jlm::llvm::ThreeAddressCodeVariable>(phiTac->operand(0));
240 auto constant0op = jlm::util::assertedCast<const jlm::llvm::IntegerConstantOperation>(
241 &constant0variable->tac()->operation());
242 EXPECT_EQ(constant0op->Representation(), 0);
TEST(LlvmPhiConversionTests, TestPhiConversion)
void print(const AggregationNode &n, const AnnotationMap &dm, FILE *out)
std::unique_ptr< InterProceduralGraphModule > ConvertLlvmModule(::llvm::Module &llvmModule)