blob: 679a7a3c3ff8cc996251d7fde90704023cb262a2 [file] [log] [blame]
Nick Lewyckyc8a15692011-02-20 08:38:20 +00001//===- Local.cpp - Unit tests for Local -----------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Chandler Carruth130cec22012-12-04 10:23:08 +000010#include "llvm/Transforms/Utils/Local.h"
Reid Kleckner0fe506b2017-09-21 19:52:03 +000011#include "llvm/AsmParser/Parser.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000012#include "llvm/IR/BasicBlock.h"
Reid Kleckner0fe506b2017-09-21 19:52:03 +000013#include "llvm/IR/DIBuilder.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000014#include "llvm/IR/IRBuilder.h"
15#include "llvm/IR/Instructions.h"
Reid Kleckner0fe506b2017-09-21 19:52:03 +000016#include "llvm/IR/IntrinsicInst.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000017#include "llvm/IR/LLVMContext.h"
Reid Kleckner0fe506b2017-09-21 19:52:03 +000018#include "llvm/Support/SourceMgr.h"
Chandler Carruthaafe0912012-06-29 12:38:19 +000019#include "gtest/gtest.h"
20
Nick Lewyckyc8a15692011-02-20 08:38:20 +000021using namespace llvm;
22
23TEST(Local, RecursivelyDeleteDeadPHINodes) {
Mehdi Amini03b42e42016-04-14 21:59:01 +000024 LLVMContext C;
Nick Lewyckyc8a15692011-02-20 08:38:20 +000025
26 IRBuilder<> builder(C);
27
28 // Make blocks
29 BasicBlock *bb0 = BasicBlock::Create(C);
30 BasicBlock *bb1 = BasicBlock::Create(C);
31
32 builder.SetInsertPoint(bb0);
Jay Foad52131342011-03-30 11:28:46 +000033 PHINode *phi = builder.CreatePHI(Type::getInt32Ty(C), 2);
Nick Lewyckyc8a15692011-02-20 08:38:20 +000034 BranchInst *br0 = builder.CreateCondBr(builder.getTrue(), bb0, bb1);
35
36 builder.SetInsertPoint(bb1);
37 BranchInst *br1 = builder.CreateBr(bb0);
38
39 phi->addIncoming(phi, bb0);
40 phi->addIncoming(phi, bb1);
41
42 // The PHI will be removed
43 EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));
44
45 // Make sure the blocks only contain the branches
46 EXPECT_EQ(&bb0->front(), br0);
47 EXPECT_EQ(&bb1->front(), br1);
48
Nick Lewycky183c24c2011-02-20 18:05:56 +000049 builder.SetInsertPoint(bb0);
Jay Foad52131342011-03-30 11:28:46 +000050 phi = builder.CreatePHI(Type::getInt32Ty(C), 0);
Nick Lewycky183c24c2011-02-20 18:05:56 +000051
52 EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));
53
Duncan Sands6dcd49b2011-02-21 16:27:36 +000054 builder.SetInsertPoint(bb0);
Jay Foad52131342011-03-30 11:28:46 +000055 phi = builder.CreatePHI(Type::getInt32Ty(C), 0);
Duncan Sands6dcd49b2011-02-21 16:27:36 +000056 builder.CreateAdd(phi, phi);
57
58 EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));
59
Nick Lewyckyc8a15692011-02-20 08:38:20 +000060 bb0->dropAllReferences();
61 bb1->dropAllReferences();
62 delete bb0;
63 delete bb1;
64}
Benjamin Kramerf175e042015-09-02 19:52:23 +000065
66TEST(Local, RemoveDuplicatePHINodes) {
Mehdi Amini03b42e42016-04-14 21:59:01 +000067 LLVMContext C;
Benjamin Kramerf175e042015-09-02 19:52:23 +000068 IRBuilder<> B(C);
69
70 std::unique_ptr<Function> F(
71 Function::Create(FunctionType::get(B.getVoidTy(), false),
72 GlobalValue::ExternalLinkage, "F"));
73 BasicBlock *Entry(BasicBlock::Create(C, "", F.get()));
74 BasicBlock *BB(BasicBlock::Create(C, "", F.get()));
75 BranchInst::Create(BB, Entry);
76
77 B.SetInsertPoint(BB);
78
79 AssertingVH<PHINode> P1 = B.CreatePHI(Type::getInt32Ty(C), 2);
80 P1->addIncoming(B.getInt32(42), Entry);
81
82 PHINode *P2 = B.CreatePHI(Type::getInt32Ty(C), 2);
83 P2->addIncoming(B.getInt32(42), Entry);
84
85 AssertingVH<PHINode> P3 = B.CreatePHI(Type::getInt32Ty(C), 2);
86 P3->addIncoming(B.getInt32(42), Entry);
87 P3->addIncoming(B.getInt32(23), BB);
88
89 PHINode *P4 = B.CreatePHI(Type::getInt32Ty(C), 2);
90 P4->addIncoming(B.getInt32(42), Entry);
91 P4->addIncoming(B.getInt32(23), BB);
92
93 P1->addIncoming(P3, BB);
94 P2->addIncoming(P4, BB);
95 BranchInst::Create(BB, BB);
96
97 // Verify that we can eliminate PHIs that become duplicates after chaning PHIs
98 // downstream.
99 EXPECT_TRUE(EliminateDuplicatePHINodes(BB));
100 EXPECT_EQ(3U, BB->size());
101}
Reid Kleckner0fe506b2017-09-21 19:52:03 +0000102
Matt Arsenault06dfbb52018-01-31 22:54:37 +0000103static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
Reid Kleckner0fe506b2017-09-21 19:52:03 +0000104 SMDiagnostic Err;
105 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
106 if (!Mod)
107 Err.print("UtilsTests", errs());
108 return Mod;
109}
110
111TEST(Local, ReplaceDbgDeclare) {
112 LLVMContext C;
113
114 // Original C source to get debug info for a local variable:
115 // void f() { int x; }
Vedant Kumar1425e042018-03-02 21:36:33 +0000116 std::unique_ptr<Module> M = parseIR(C,
117 R"(
118 define void @f() !dbg !8 {
119 entry:
120 %x = alloca i32, align 4
121 call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata !DIExpression()), !dbg !13
122 call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata !DIExpression()), !dbg !13
123 ret void, !dbg !14
124 }
125 declare void @llvm.dbg.declare(metadata, metadata, metadata)
126 !llvm.dbg.cu = !{!0}
127 !llvm.module.flags = !{!3, !4}
128 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
129 !1 = !DIFile(filename: "t2.c", directory: "foo")
130 !2 = !{}
131 !3 = !{i32 2, !"Dwarf Version", i32 4}
132 !4 = !{i32 2, !"Debug Info Version", i32 3}
133 !8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, variables: !2)
134 !9 = !DISubroutineType(types: !10)
135 !10 = !{null}
136 !11 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !12)
137 !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
138 !13 = !DILocation(line: 2, column: 7, scope: !8)
139 !14 = !DILocation(line: 3, column: 1, scope: !8)
140 )");
Reid Kleckner0fe506b2017-09-21 19:52:03 +0000141 auto *GV = M->getNamedValue("f");
142 ASSERT_TRUE(GV);
143 auto *F = dyn_cast<Function>(GV);
144 ASSERT_TRUE(F);
145 Instruction *Inst = &F->front().front();
146 auto *AI = dyn_cast<AllocaInst>(Inst);
147 ASSERT_TRUE(AI);
148 Inst = Inst->getNextNode()->getNextNode();
149 ASSERT_TRUE(Inst);
150 auto *DII = dyn_cast<DbgDeclareInst>(Inst);
151 ASSERT_TRUE(DII);
152 Value *NewBase = Constant::getNullValue(Type::getInt32PtrTy(C));
153 DIBuilder DIB(*M);
Adrian Prantld1317012017-12-08 21:58:18 +0000154 replaceDbgDeclare(AI, NewBase, DII, DIB, DIExpression::NoDeref, 0,
155 DIExpression::NoDeref);
Reid Kleckner0fe506b2017-09-21 19:52:03 +0000156
157 // There should be exactly two dbg.declares.
158 int Declares = 0;
159 for (const Instruction &I : F->front())
160 if (isa<DbgDeclareInst>(I))
161 Declares++;
162 EXPECT_EQ(2, Declares);
163}
Balaram Makam9ee942f2017-10-26 15:04:53 +0000164
165/// Build the dominator tree for the function and run the Test.
166static void runWithDomTree(
167 Module &M, StringRef FuncName,
168 function_ref<void(Function &F, DominatorTree *DT)> Test) {
169 auto *F = M.getFunction(FuncName);
170 ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
171 // Compute the dominator tree for the function.
172 DominatorTree DT(*F);
173 Test(*F, &DT);
174}
175
176TEST(Local, MergeBasicBlockIntoOnlyPred) {
177 LLVMContext C;
178
Vedant Kumar1425e042018-03-02 21:36:33 +0000179 std::unique_ptr<Module> M = parseIR(C,
180 R"(
181 define i32 @f(i8* %str) {
182 entry:
183 br label %bb2.i
184 bb2.i: ; preds = %bb4.i, %entry
185 br i1 false, label %bb4.i, label %base2flt.exit204
186 bb4.i: ; preds = %bb2.i
187 br i1 false, label %base2flt.exit204, label %bb2.i
188 bb10.i196.bb7.i197_crit_edge: ; No predecessors!
189 br label %bb7.i197
190 bb7.i197: ; preds = %bb10.i196.bb7.i197_crit_edge
191 %.reg2mem.0 = phi i32 [ %.reg2mem.0, %bb10.i196.bb7.i197_crit_edge ]
192 br i1 undef, label %base2flt.exit204, label %base2flt.exit204
193 base2flt.exit204: ; preds = %bb7.i197, %bb7.i197, %bb2.i, %bb4.i
194 ret i32 0
195 }
196 )");
Balaram Makam9ee942f2017-10-26 15:04:53 +0000197 runWithDomTree(
198 *M, "f", [&](Function &F, DominatorTree *DT) {
199 for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
200 BasicBlock *BB = &*I++;
201 BasicBlock *SinglePred = BB->getSinglePredecessor();
202 if (!SinglePred || SinglePred == BB || BB->hasAddressTaken()) continue;
203 BranchInst *Term = dyn_cast<BranchInst>(SinglePred->getTerminator());
204 if (Term && !Term->isConditional())
205 MergeBasicBlockIntoOnlyPred(BB, DT);
206 }
207 EXPECT_TRUE(DT->verify());
208 });
209}
Matt Arsenault0cfebd92018-01-17 16:27:17 +0000210
211TEST(Local, ConstantFoldTerminator) {
212 LLVMContext C;
213
Vedant Kumar1425e042018-03-02 21:36:33 +0000214 std::unique_ptr<Module> M = parseIR(C,
215 R"(
216 define void @br_same_dest() {
217 entry:
218 br i1 false, label %bb0, label %bb0
219 bb0:
220 ret void
221 }
222
223 define void @br_different_dest() {
224 entry:
225 br i1 true, label %bb0, label %bb1
226 bb0:
227 br label %exit
228 bb1:
229 br label %exit
230 exit:
231 ret void
232 }
233
234 define void @switch_2_different_dest() {
235 entry:
236 switch i32 0, label %default [ i32 0, label %bb0 ]
237 default:
238 ret void
239 bb0:
240 ret void
241 }
242 define void @switch_2_different_dest_default() {
243 entry:
244 switch i32 1, label %default [ i32 0, label %bb0 ]
245 default:
246 ret void
247 bb0:
248 ret void
249 }
250 define void @switch_3_different_dest() {
251 entry:
252 switch i32 0, label %default [ i32 0, label %bb0
253 i32 1, label %bb1 ]
254 default:
255 ret void
256 bb0:
257 ret void
258 bb1:
259 ret void
260 }
261
262 define void @switch_variable_2_default_dest(i32 %arg) {
263 entry:
264 switch i32 %arg, label %default [ i32 0, label %default ]
265 default:
266 ret void
267 }
268
269 define void @switch_constant_2_default_dest() {
270 entry:
271 switch i32 1, label %default [ i32 0, label %default ]
272 default:
273 ret void
274 }
275
276 define void @switch_constant_3_repeated_dest() {
277 entry:
278 switch i32 0, label %default [ i32 0, label %bb0
279 i32 1, label %bb0 ]
280 bb0:
281 ret void
282 default:
283 ret void
284 }
285
286 define void @indirectbr() {
287 entry:
288 indirectbr i8* blockaddress(@indirectbr, %bb0), [label %bb0, label %bb1]
289 bb0:
290 ret void
291 bb1:
292 ret void
293 }
294
295 define void @indirectbr_repeated() {
296 entry:
297 indirectbr i8* blockaddress(@indirectbr_repeated, %bb0), [label %bb0, label %bb0]
298 bb0:
299 ret void
300 }
301
302 define void @indirectbr_unreachable() {
303 entry:
304 indirectbr i8* blockaddress(@indirectbr_unreachable, %bb0), [label %bb1]
305 bb0:
306 ret void
307 bb1:
308 ret void
309 }
310 )");
Matt Arsenault0cfebd92018-01-17 16:27:17 +0000311
312 auto CFAllTerminators = [&](Function &F, DominatorTree *DT) {
313 DeferredDominance DDT(*DT);
314 for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
315 BasicBlock *BB = &*I++;
316 ConstantFoldTerminator(BB, true, nullptr, &DDT);
317 }
318
319 EXPECT_TRUE(DDT.flush().verify());
320 };
321
322 runWithDomTree(*M, "br_same_dest", CFAllTerminators);
323 runWithDomTree(*M, "br_different_dest", CFAllTerminators);
324 runWithDomTree(*M, "switch_2_different_dest", CFAllTerminators);
325 runWithDomTree(*M, "switch_2_different_dest_default", CFAllTerminators);
326 runWithDomTree(*M, "switch_3_different_dest", CFAllTerminators);
327 runWithDomTree(*M, "switch_variable_2_default_dest", CFAllTerminators);
328 runWithDomTree(*M, "switch_constant_2_default_dest", CFAllTerminators);
329 runWithDomTree(*M, "switch_constant_3_repeated_dest", CFAllTerminators);
330 runWithDomTree(*M, "indirectbr", CFAllTerminators);
331 runWithDomTree(*M, "indirectbr_repeated", CFAllTerminators);
332 runWithDomTree(*M, "indirectbr_unreachable", CFAllTerminators);
333}
Vedant Kumar334fa572018-03-02 21:36:35 +0000334
335TEST(Local, SalvageDebugValuesInRecursiveInstDeletion) {
336 LLVMContext C;
337
338 std::unique_ptr<Module> M = parseIR(C,
339 R"(
340 define void @f() !dbg !8 {
341 entry:
342 %x = add i32 0, 1
343 %y = add i32 %x, 2
344 call void @llvm.dbg.value(metadata i32 %x, metadata !11, metadata !DIExpression()), !dbg !13
345 call void @llvm.dbg.value(metadata i32 %y, metadata !11, metadata !DIExpression()), !dbg !13
346 ret void, !dbg !14
347 }
348 declare void @llvm.dbg.value(metadata, metadata, metadata)
349 !llvm.dbg.cu = !{!0}
350 !llvm.module.flags = !{!3, !4}
351 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
352 !1 = !DIFile(filename: "t2.c", directory: "foo")
353 !2 = !{}
354 !3 = !{i32 2, !"Dwarf Version", i32 4}
355 !4 = !{i32 2, !"Debug Info Version", i32 3}
356 !8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, variables: !2)
357 !9 = !DISubroutineType(types: !10)
358 !10 = !{null}
359 !11 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !12)
360 !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
361 !13 = !DILocation(line: 2, column: 7, scope: !8)
362 !14 = !DILocation(line: 3, column: 1, scope: !8)
363 )");
364 auto *GV = M->getNamedValue("f");
365 ASSERT_TRUE(GV);
366 auto *F = dyn_cast<Function>(GV);
367 ASSERT_TRUE(F);
368 Instruction *Inst = &F->front().front();
369 Inst = Inst->getNextNode();
370 ASSERT_TRUE(Inst);
371 bool Deleted = RecursivelyDeleteTriviallyDeadInstructions(Inst);
372 ASSERT_TRUE(Deleted);
373
374 // The debug values should have been salvaged.
375 bool FoundX = false;
376 bool FoundY = false;
377 uint64_t X_expr[] = {dwarf::DW_OP_plus_uconst, 1, dwarf::DW_OP_stack_value};
378 uint64_t Y_expr[] = {dwarf::DW_OP_plus_uconst, 1, dwarf::DW_OP_plus_uconst, 2,
379 dwarf::DW_OP_stack_value};
380 for (const Instruction &I : F->front()) {
381 auto DI = dyn_cast<DbgValueInst>(&I);
382 if (!DI)
383 continue;
384 EXPECT_EQ(DI->getVariable()->getName(), "x");
385 ASSERT_TRUE(cast<ConstantInt>(DI->getValue())->isZero());
386 ArrayRef<uint64_t> ExprElts = DI->getExpression()->getElements();
387 if (ExprElts.equals(X_expr))
388 FoundX = true;
389 else if (ExprElts.equals(Y_expr))
390 FoundY = true;
391 }
392 ASSERT_TRUE(FoundX);
393 ASSERT_TRUE(FoundY);
394}