Mercurial > hg > CbC > CbC_llvm
comparison unittests/Transforms/Utils/LocalTest.cpp @ 148:63bd29f05246
merged
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 14 Aug 2019 19:46:37 +0900 |
parents | c2174574ed3a |
children |
comparison
equal
deleted
inserted
replaced
146:3fc4d5c3e21e | 148:63bd29f05246 |
---|---|
1 //===- Local.cpp - Unit tests for Local -----------------------------------===// | |
2 // | |
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
4 // See https://llvm.org/LICENSE.txt for license information. | |
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
6 // | |
7 //===----------------------------------------------------------------------===// | |
8 | |
9 #include "llvm/Transforms/Utils/Local.h" | |
10 #include "llvm/Analysis/DomTreeUpdater.h" | |
11 #include "llvm/Analysis/PostDominators.h" | |
12 #include "llvm/AsmParser/Parser.h" | |
13 #include "llvm/IR/BasicBlock.h" | |
14 #include "llvm/IR/DIBuilder.h" | |
15 #include "llvm/IR/IRBuilder.h" | |
16 #include "llvm/IR/Instructions.h" | |
17 #include "llvm/IR/IntrinsicInst.h" | |
18 #include "llvm/IR/LLVMContext.h" | |
19 #include "llvm/IR/Verifier.h" | |
20 #include "llvm/Support/SourceMgr.h" | |
21 #include "gtest/gtest.h" | |
22 | |
23 using namespace llvm; | |
24 | |
25 TEST(Local, RecursivelyDeleteDeadPHINodes) { | |
26 LLVMContext C; | |
27 | |
28 IRBuilder<> builder(C); | |
29 | |
30 // Make blocks | |
31 BasicBlock *bb0 = BasicBlock::Create(C); | |
32 BasicBlock *bb1 = BasicBlock::Create(C); | |
33 | |
34 builder.SetInsertPoint(bb0); | |
35 PHINode *phi = builder.CreatePHI(Type::getInt32Ty(C), 2); | |
36 BranchInst *br0 = builder.CreateCondBr(builder.getTrue(), bb0, bb1); | |
37 | |
38 builder.SetInsertPoint(bb1); | |
39 BranchInst *br1 = builder.CreateBr(bb0); | |
40 | |
41 phi->addIncoming(phi, bb0); | |
42 phi->addIncoming(phi, bb1); | |
43 | |
44 // The PHI will be removed | |
45 EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi)); | |
46 | |
47 // Make sure the blocks only contain the branches | |
48 EXPECT_EQ(&bb0->front(), br0); | |
49 EXPECT_EQ(&bb1->front(), br1); | |
50 | |
51 builder.SetInsertPoint(bb0); | |
52 phi = builder.CreatePHI(Type::getInt32Ty(C), 0); | |
53 | |
54 EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi)); | |
55 | |
56 builder.SetInsertPoint(bb0); | |
57 phi = builder.CreatePHI(Type::getInt32Ty(C), 0); | |
58 builder.CreateAdd(phi, phi); | |
59 | |
60 EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi)); | |
61 | |
62 bb0->dropAllReferences(); | |
63 bb1->dropAllReferences(); | |
64 delete bb0; | |
65 delete bb1; | |
66 } | |
67 | |
68 TEST(Local, RemoveDuplicatePHINodes) { | |
69 LLVMContext C; | |
70 IRBuilder<> B(C); | |
71 | |
72 std::unique_ptr<Function> F( | |
73 Function::Create(FunctionType::get(B.getVoidTy(), false), | |
74 GlobalValue::ExternalLinkage, "F")); | |
75 BasicBlock *Entry(BasicBlock::Create(C, "", F.get())); | |
76 BasicBlock *BB(BasicBlock::Create(C, "", F.get())); | |
77 BranchInst::Create(BB, Entry); | |
78 | |
79 B.SetInsertPoint(BB); | |
80 | |
81 AssertingVH<PHINode> P1 = B.CreatePHI(Type::getInt32Ty(C), 2); | |
82 P1->addIncoming(B.getInt32(42), Entry); | |
83 | |
84 PHINode *P2 = B.CreatePHI(Type::getInt32Ty(C), 2); | |
85 P2->addIncoming(B.getInt32(42), Entry); | |
86 | |
87 AssertingVH<PHINode> P3 = B.CreatePHI(Type::getInt32Ty(C), 2); | |
88 P3->addIncoming(B.getInt32(42), Entry); | |
89 P3->addIncoming(B.getInt32(23), BB); | |
90 | |
91 PHINode *P4 = B.CreatePHI(Type::getInt32Ty(C), 2); | |
92 P4->addIncoming(B.getInt32(42), Entry); | |
93 P4->addIncoming(B.getInt32(23), BB); | |
94 | |
95 P1->addIncoming(P3, BB); | |
96 P2->addIncoming(P4, BB); | |
97 BranchInst::Create(BB, BB); | |
98 | |
99 // Verify that we can eliminate PHIs that become duplicates after chaning PHIs | |
100 // downstream. | |
101 EXPECT_TRUE(EliminateDuplicatePHINodes(BB)); | |
102 EXPECT_EQ(3U, BB->size()); | |
103 } | |
104 | |
105 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { | |
106 SMDiagnostic Err; | |
107 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); | |
108 if (!Mod) | |
109 Err.print("UtilsTests", errs()); | |
110 return Mod; | |
111 } | |
112 | |
113 TEST(Local, ReplaceDbgDeclare) { | |
114 LLVMContext C; | |
115 | |
116 // Original C source to get debug info for a local variable: | |
117 // void f() { int x; } | |
118 std::unique_ptr<Module> M = parseIR(C, | |
119 R"( | |
120 define void @f() !dbg !8 { | |
121 entry: | |
122 %x = alloca i32, align 4 | |
123 call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata !DIExpression()), !dbg !13 | |
124 call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata !DIExpression()), !dbg !13 | |
125 ret void, !dbg !14 | |
126 } | |
127 declare void @llvm.dbg.declare(metadata, metadata, metadata) | |
128 !llvm.dbg.cu = !{!0} | |
129 !llvm.module.flags = !{!3, !4} | |
130 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) | |
131 !1 = !DIFile(filename: "t2.c", directory: "foo") | |
132 !2 = !{} | |
133 !3 = !{i32 2, !"Dwarf Version", i32 4} | |
134 !4 = !{i32 2, !"Debug Info Version", i32 3} | |
135 !8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, retainedNodes: !2) | |
136 !9 = !DISubroutineType(types: !10) | |
137 !10 = !{null} | |
138 !11 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !12) | |
139 !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) | |
140 !13 = !DILocation(line: 2, column: 7, scope: !8) | |
141 !14 = !DILocation(line: 3, column: 1, scope: !8) | |
142 )"); | |
143 auto *GV = M->getNamedValue("f"); | |
144 ASSERT_TRUE(GV); | |
145 auto *F = dyn_cast<Function>(GV); | |
146 ASSERT_TRUE(F); | |
147 Instruction *Inst = &F->front().front(); | |
148 auto *AI = dyn_cast<AllocaInst>(Inst); | |
149 ASSERT_TRUE(AI); | |
150 Inst = Inst->getNextNode()->getNextNode(); | |
151 ASSERT_TRUE(Inst); | |
152 auto *DII = dyn_cast<DbgDeclareInst>(Inst); | |
153 ASSERT_TRUE(DII); | |
154 Value *NewBase = Constant::getNullValue(Type::getInt32PtrTy(C)); | |
155 DIBuilder DIB(*M); | |
156 replaceDbgDeclare(AI, NewBase, DII, DIB, DIExpression::ApplyOffset, 0); | |
157 | |
158 // There should be exactly two dbg.declares. | |
159 int Declares = 0; | |
160 for (const Instruction &I : F->front()) | |
161 if (isa<DbgDeclareInst>(I)) | |
162 Declares++; | |
163 EXPECT_EQ(2, Declares); | |
164 } | |
165 | |
166 /// Build the dominator tree for the function and run the Test. | |
167 static void runWithDomTree( | |
168 Module &M, StringRef FuncName, | |
169 function_ref<void(Function &F, DominatorTree *DT)> Test) { | |
170 auto *F = M.getFunction(FuncName); | |
171 ASSERT_NE(F, nullptr) << "Could not find " << FuncName; | |
172 // Compute the dominator tree for the function. | |
173 DominatorTree DT(*F); | |
174 Test(*F, &DT); | |
175 } | |
176 | |
177 TEST(Local, MergeBasicBlockIntoOnlyPred) { | |
178 LLVMContext C; | |
179 std::unique_ptr<Module> M; | |
180 auto resetIR = [&]() { | |
181 M = parseIR(C, | |
182 R"( | |
183 define i32 @f(i8* %str) { | |
184 entry: | |
185 br label %bb2.i | |
186 bb2.i: ; preds = %bb4.i, %entry | |
187 br i1 false, label %bb4.i, label %base2flt.exit204 | |
188 bb4.i: ; preds = %bb2.i | |
189 br i1 false, label %base2flt.exit204, label %bb2.i | |
190 bb10.i196.bb7.i197_crit_edge: ; No predecessors! | |
191 br label %bb7.i197 | |
192 bb7.i197: ; preds = %bb10.i196.bb7.i197_crit_edge | |
193 %.reg2mem.0 = phi i32 [ %.reg2mem.0, %bb10.i196.bb7.i197_crit_edge ] | |
194 br i1 undef, label %base2flt.exit204, label %base2flt.exit204 | |
195 base2flt.exit204: ; preds = %bb7.i197, %bb7.i197, %bb2.i, %bb4.i | |
196 ret i32 0 | |
197 } | |
198 )"); | |
199 }; | |
200 | |
201 auto resetIRReplaceEntry = [&]() { | |
202 M = parseIR(C, | |
203 R"( | |
204 define i32 @f() { | |
205 entry: | |
206 br label %bb2.i | |
207 bb2.i: ; preds = %entry | |
208 ret i32 0 | |
209 } | |
210 )"); | |
211 }; | |
212 | |
213 auto Test = [&](Function &F, DomTreeUpdater &DTU) { | |
214 for (Function::iterator I = F.begin(), E = F.end(); I != E;) { | |
215 BasicBlock *BB = &*I++; | |
216 BasicBlock *SinglePred = BB->getSinglePredecessor(); | |
217 if (!SinglePred || SinglePred == BB || BB->hasAddressTaken()) | |
218 continue; | |
219 BranchInst *Term = dyn_cast<BranchInst>(SinglePred->getTerminator()); | |
220 if (Term && !Term->isConditional()) | |
221 MergeBasicBlockIntoOnlyPred(BB, &DTU); | |
222 } | |
223 if (DTU.hasDomTree()) { | |
224 EXPECT_TRUE(DTU.getDomTree().verify()); | |
225 } | |
226 if (DTU.hasPostDomTree()) { | |
227 EXPECT_TRUE(DTU.getPostDomTree().verify()); | |
228 } | |
229 }; | |
230 | |
231 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with | |
232 // both DT and PDT. | |
233 resetIR(); | |
234 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
235 PostDominatorTree PDT = PostDominatorTree(F); | |
236 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager); | |
237 Test(F, DTU); | |
238 }); | |
239 | |
240 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with | |
241 // DT. | |
242 resetIR(); | |
243 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
244 DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Eager); | |
245 Test(F, DTU); | |
246 }); | |
247 | |
248 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with | |
249 // PDT. | |
250 resetIR(); | |
251 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
252 PostDominatorTree PDT = PostDominatorTree(F); | |
253 DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Eager); | |
254 Test(F, DTU); | |
255 }); | |
256 | |
257 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with | |
258 // both DT and PDT. | |
259 resetIR(); | |
260 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
261 PostDominatorTree PDT = PostDominatorTree(F); | |
262 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy); | |
263 Test(F, DTU); | |
264 }); | |
265 | |
266 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with | |
267 // PDT. | |
268 resetIR(); | |
269 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
270 PostDominatorTree PDT = PostDominatorTree(F); | |
271 DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Lazy); | |
272 Test(F, DTU); | |
273 }); | |
274 | |
275 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with DT. | |
276 resetIR(); | |
277 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
278 DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Lazy); | |
279 Test(F, DTU); | |
280 }); | |
281 | |
282 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with | |
283 // both DT and PDT. | |
284 resetIRReplaceEntry(); | |
285 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
286 PostDominatorTree PDT = PostDominatorTree(F); | |
287 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager); | |
288 Test(F, DTU); | |
289 }); | |
290 | |
291 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with | |
292 // DT. | |
293 resetIRReplaceEntry(); | |
294 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
295 DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Eager); | |
296 Test(F, DTU); | |
297 }); | |
298 | |
299 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with | |
300 // PDT. | |
301 resetIRReplaceEntry(); | |
302 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
303 PostDominatorTree PDT = PostDominatorTree(F); | |
304 DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Eager); | |
305 Test(F, DTU); | |
306 }); | |
307 | |
308 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with | |
309 // both DT and PDT. | |
310 resetIRReplaceEntry(); | |
311 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
312 PostDominatorTree PDT = PostDominatorTree(F); | |
313 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy); | |
314 Test(F, DTU); | |
315 }); | |
316 | |
317 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with | |
318 // PDT. | |
319 resetIRReplaceEntry(); | |
320 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
321 PostDominatorTree PDT = PostDominatorTree(F); | |
322 DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Lazy); | |
323 Test(F, DTU); | |
324 }); | |
325 | |
326 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with DT. | |
327 resetIRReplaceEntry(); | |
328 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) { | |
329 DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Lazy); | |
330 Test(F, DTU); | |
331 }); | |
332 } | |
333 | |
334 TEST(Local, ConstantFoldTerminator) { | |
335 LLVMContext C; | |
336 | |
337 std::unique_ptr<Module> M = parseIR(C, | |
338 R"( | |
339 define void @br_same_dest() { | |
340 entry: | |
341 br i1 false, label %bb0, label %bb0 | |
342 bb0: | |
343 ret void | |
344 } | |
345 | |
346 define void @br_different_dest() { | |
347 entry: | |
348 br i1 true, label %bb0, label %bb1 | |
349 bb0: | |
350 br label %exit | |
351 bb1: | |
352 br label %exit | |
353 exit: | |
354 ret void | |
355 } | |
356 | |
357 define void @switch_2_different_dest() { | |
358 entry: | |
359 switch i32 0, label %default [ i32 0, label %bb0 ] | |
360 default: | |
361 ret void | |
362 bb0: | |
363 ret void | |
364 } | |
365 define void @switch_2_different_dest_default() { | |
366 entry: | |
367 switch i32 1, label %default [ i32 0, label %bb0 ] | |
368 default: | |
369 ret void | |
370 bb0: | |
371 ret void | |
372 } | |
373 define void @switch_3_different_dest() { | |
374 entry: | |
375 switch i32 0, label %default [ i32 0, label %bb0 | |
376 i32 1, label %bb1 ] | |
377 default: | |
378 ret void | |
379 bb0: | |
380 ret void | |
381 bb1: | |
382 ret void | |
383 } | |
384 | |
385 define void @switch_variable_2_default_dest(i32 %arg) { | |
386 entry: | |
387 switch i32 %arg, label %default [ i32 0, label %default ] | |
388 default: | |
389 ret void | |
390 } | |
391 | |
392 define void @switch_constant_2_default_dest() { | |
393 entry: | |
394 switch i32 1, label %default [ i32 0, label %default ] | |
395 default: | |
396 ret void | |
397 } | |
398 | |
399 define void @switch_constant_3_repeated_dest() { | |
400 entry: | |
401 switch i32 0, label %default [ i32 0, label %bb0 | |
402 i32 1, label %bb0 ] | |
403 bb0: | |
404 ret void | |
405 default: | |
406 ret void | |
407 } | |
408 | |
409 define void @indirectbr() { | |
410 entry: | |
411 indirectbr i8* blockaddress(@indirectbr, %bb0), [label %bb0, label %bb1] | |
412 bb0: | |
413 ret void | |
414 bb1: | |
415 ret void | |
416 } | |
417 | |
418 define void @indirectbr_repeated() { | |
419 entry: | |
420 indirectbr i8* blockaddress(@indirectbr_repeated, %bb0), [label %bb0, label %bb0] | |
421 bb0: | |
422 ret void | |
423 } | |
424 | |
425 define void @indirectbr_unreachable() { | |
426 entry: | |
427 indirectbr i8* blockaddress(@indirectbr_unreachable, %bb0), [label %bb1] | |
428 bb0: | |
429 ret void | |
430 bb1: | |
431 ret void | |
432 } | |
433 )"); | |
434 | |
435 auto CFAllTerminatorsEager = [&](Function &F, DominatorTree *DT) { | |
436 PostDominatorTree PDT = PostDominatorTree(F); | |
437 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager); | |
438 for (Function::iterator I = F.begin(), E = F.end(); I != E;) { | |
439 BasicBlock *BB = &*I++; | |
440 ConstantFoldTerminator(BB, true, nullptr, &DTU); | |
441 } | |
442 | |
443 EXPECT_TRUE(DTU.getDomTree().verify()); | |
444 EXPECT_TRUE(DTU.getPostDomTree().verify()); | |
445 }; | |
446 | |
447 auto CFAllTerminatorsLazy = [&](Function &F, DominatorTree *DT) { | |
448 PostDominatorTree PDT = PostDominatorTree(F); | |
449 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy); | |
450 for (Function::iterator I = F.begin(), E = F.end(); I != E;) { | |
451 BasicBlock *BB = &*I++; | |
452 ConstantFoldTerminator(BB, true, nullptr, &DTU); | |
453 } | |
454 | |
455 EXPECT_TRUE(DTU.getDomTree().verify()); | |
456 EXPECT_TRUE(DTU.getPostDomTree().verify()); | |
457 }; | |
458 | |
459 // Test ConstantFoldTerminator under Eager UpdateStrategy. | |
460 runWithDomTree(*M, "br_same_dest", CFAllTerminatorsEager); | |
461 runWithDomTree(*M, "br_different_dest", CFAllTerminatorsEager); | |
462 runWithDomTree(*M, "switch_2_different_dest", CFAllTerminatorsEager); | |
463 runWithDomTree(*M, "switch_2_different_dest_default", CFAllTerminatorsEager); | |
464 runWithDomTree(*M, "switch_3_different_dest", CFAllTerminatorsEager); | |
465 runWithDomTree(*M, "switch_variable_2_default_dest", CFAllTerminatorsEager); | |
466 runWithDomTree(*M, "switch_constant_2_default_dest", CFAllTerminatorsEager); | |
467 runWithDomTree(*M, "switch_constant_3_repeated_dest", CFAllTerminatorsEager); | |
468 runWithDomTree(*M, "indirectbr", CFAllTerminatorsEager); | |
469 runWithDomTree(*M, "indirectbr_repeated", CFAllTerminatorsEager); | |
470 runWithDomTree(*M, "indirectbr_unreachable", CFAllTerminatorsEager); | |
471 | |
472 // Test ConstantFoldTerminator under Lazy UpdateStrategy. | |
473 runWithDomTree(*M, "br_same_dest", CFAllTerminatorsLazy); | |
474 runWithDomTree(*M, "br_different_dest", CFAllTerminatorsLazy); | |
475 runWithDomTree(*M, "switch_2_different_dest", CFAllTerminatorsLazy); | |
476 runWithDomTree(*M, "switch_2_different_dest_default", CFAllTerminatorsLazy); | |
477 runWithDomTree(*M, "switch_3_different_dest", CFAllTerminatorsLazy); | |
478 runWithDomTree(*M, "switch_variable_2_default_dest", CFAllTerminatorsLazy); | |
479 runWithDomTree(*M, "switch_constant_2_default_dest", CFAllTerminatorsLazy); | |
480 runWithDomTree(*M, "switch_constant_3_repeated_dest", CFAllTerminatorsLazy); | |
481 runWithDomTree(*M, "indirectbr", CFAllTerminatorsLazy); | |
482 runWithDomTree(*M, "indirectbr_repeated", CFAllTerminatorsLazy); | |
483 runWithDomTree(*M, "indirectbr_unreachable", CFAllTerminatorsLazy); | |
484 } | |
485 | |
486 struct SalvageDebugInfoTest : ::testing::Test { | |
487 LLVMContext C; | |
488 std::unique_ptr<Module> M; | |
489 Function *F = nullptr; | |
490 | |
491 void SetUp() { | |
492 M = parseIR(C, | |
493 R"( | |
494 define void @f() !dbg !8 { | |
495 entry: | |
496 %x = add i32 0, 1 | |
497 %y = add i32 %x, 2 | |
498 call void @llvm.dbg.value(metadata i32 %x, metadata !11, metadata !DIExpression()), !dbg !13 | |
499 call void @llvm.dbg.value(metadata i32 %y, metadata !11, metadata !DIExpression()), !dbg !13 | |
500 ret void, !dbg !14 | |
501 } | |
502 declare void @llvm.dbg.value(metadata, metadata, metadata) | |
503 !llvm.dbg.cu = !{!0} | |
504 !llvm.module.flags = !{!3, !4} | |
505 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) | |
506 !1 = !DIFile(filename: "t2.c", directory: "foo") | |
507 !2 = !{} | |
508 !3 = !{i32 2, !"Dwarf Version", i32 4} | |
509 !4 = !{i32 2, !"Debug Info Version", i32 3} | |
510 !8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, retainedNodes: !2) | |
511 !9 = !DISubroutineType(types: !10) | |
512 !10 = !{null} | |
513 !11 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !12) | |
514 !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) | |
515 !13 = !DILocation(line: 2, column: 7, scope: !8) | |
516 !14 = !DILocation(line: 3, column: 1, scope: !8) | |
517 )"); | |
518 | |
519 auto *GV = M->getNamedValue("f"); | |
520 ASSERT_TRUE(GV); | |
521 F = dyn_cast<Function>(GV); | |
522 ASSERT_TRUE(F); | |
523 } | |
524 | |
525 bool doesDebugValueDescribeX(const DbgValueInst &DI) { | |
526 const auto &CI = *cast<ConstantInt>(DI.getValue()); | |
527 if (CI.isZero()) | |
528 return DI.getExpression()->getElements().equals( | |
529 {dwarf::DW_OP_plus_uconst, 1, dwarf::DW_OP_stack_value}); | |
530 else if (CI.isOneValue()) | |
531 return DI.getExpression()->getElements().empty(); | |
532 return false; | |
533 } | |
534 | |
535 bool doesDebugValueDescribeY(const DbgValueInst &DI) { | |
536 const auto &CI = *cast<ConstantInt>(DI.getValue()); | |
537 if (CI.isZero()) | |
538 return DI.getExpression()->getElements().equals( | |
539 {dwarf::DW_OP_plus_uconst, 1, dwarf::DW_OP_plus_uconst, 2, | |
540 dwarf::DW_OP_stack_value}); | |
541 else if (CI.isOneValue()) | |
542 return DI.getExpression()->getElements().equals( | |
543 {dwarf::DW_OP_plus_uconst, 2, dwarf::DW_OP_stack_value}); | |
544 return false; | |
545 } | |
546 | |
547 void verifyDebugValuesAreSalvaged() { | |
548 // Check that the debug values for %x and %y are preserved. | |
549 bool FoundX = false; | |
550 bool FoundY = false; | |
551 for (const Instruction &I : F->front()) { | |
552 auto DI = dyn_cast<DbgValueInst>(&I); | |
553 if (!DI) { | |
554 // The function should only contain debug values and a terminator. | |
555 ASSERT_TRUE(I.isTerminator()); | |
556 continue; | |
557 } | |
558 EXPECT_EQ(DI->getVariable()->getName(), "x"); | |
559 FoundX |= doesDebugValueDescribeX(*DI); | |
560 FoundY |= doesDebugValueDescribeY(*DI); | |
561 } | |
562 ASSERT_TRUE(FoundX); | |
563 ASSERT_TRUE(FoundY); | |
564 } | |
565 }; | |
566 | |
567 TEST_F(SalvageDebugInfoTest, RecursiveInstDeletion) { | |
568 Instruction *Inst = &F->front().front(); | |
569 Inst = Inst->getNextNode(); // Get %y = add ... | |
570 ASSERT_TRUE(Inst); | |
571 bool Deleted = RecursivelyDeleteTriviallyDeadInstructions(Inst); | |
572 ASSERT_TRUE(Deleted); | |
573 verifyDebugValuesAreSalvaged(); | |
574 } | |
575 | |
576 TEST_F(SalvageDebugInfoTest, RecursiveBlockSimplification) { | |
577 BasicBlock *BB = &F->front(); | |
578 ASSERT_TRUE(BB); | |
579 bool Deleted = SimplifyInstructionsInBlock(BB); | |
580 ASSERT_TRUE(Deleted); | |
581 verifyDebugValuesAreSalvaged(); | |
582 } | |
583 | |
584 TEST(Local, ChangeToUnreachable) { | |
585 LLVMContext Ctx; | |
586 | |
587 std::unique_ptr<Module> M = parseIR(Ctx, | |
588 R"( | |
589 define internal void @foo() !dbg !6 { | |
590 entry: | |
591 ret void, !dbg !8 | |
592 } | |
593 | |
594 !llvm.dbg.cu = !{!0} | |
595 !llvm.debugify = !{!3, !4} | |
596 !llvm.module.flags = !{!5} | |
597 | |
598 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) | |
599 !1 = !DIFile(filename: "test.ll", directory: "/") | |
600 !2 = !{} | |
601 !3 = !{i32 1} | |
602 !4 = !{i32 0} | |
603 !5 = !{i32 2, !"Debug Info Version", i32 3} | |
604 !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, isLocal: true, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !2) | |
605 !7 = !DISubroutineType(types: !2) | |
606 !8 = !DILocation(line: 1, column: 1, scope: !6) | |
607 )"); | |
608 | |
609 bool BrokenDebugInfo = true; | |
610 verifyModule(*M, &errs(), &BrokenDebugInfo); | |
611 ASSERT_FALSE(BrokenDebugInfo); | |
612 | |
613 Function &F = *cast<Function>(M->getNamedValue("foo")); | |
614 | |
615 BasicBlock &BB = F.front(); | |
616 Instruction &A = BB.front(); | |
617 DebugLoc DLA = A.getDebugLoc(); | |
618 | |
619 ASSERT_TRUE(isa<ReturnInst>(&A)); | |
620 // One instruction should be affected. | |
621 EXPECT_EQ(changeToUnreachable(&A, /*UseLLVMTrap*/false), 1U); | |
622 | |
623 Instruction &B = BB.front(); | |
624 | |
625 // There should be an uncreachable instruction. | |
626 ASSERT_TRUE(isa<UnreachableInst>(&B)); | |
627 | |
628 DebugLoc DLB = B.getDebugLoc(); | |
629 EXPECT_EQ(DLA, DLB); | |
630 } | |
631 | |
632 TEST(Local, ReplaceAllDbgUsesWith) { | |
633 using namespace llvm::dwarf; | |
634 | |
635 LLVMContext Ctx; | |
636 | |
637 // Note: The datalayout simulates Darwin/x86_64. | |
638 std::unique_ptr<Module> M = parseIR(Ctx, | |
639 R"( | |
640 target datalayout = "e-m:o-i63:64-f80:128-n8:16:32:64-S128" | |
641 | |
642 declare i32 @escape(i32) | |
643 | |
644 define void @f() !dbg !6 { | |
645 entry: | |
646 %a = add i32 0, 1, !dbg !15 | |
647 call void @llvm.dbg.value(metadata i32 %a, metadata !9, metadata !DIExpression()), !dbg !15 | |
648 | |
649 %b = add i64 0, 1, !dbg !16 | |
650 call void @llvm.dbg.value(metadata i64 %b, metadata !11, metadata !DIExpression()), !dbg !16 | |
651 call void @llvm.dbg.value(metadata i64 %b, metadata !11, metadata !DIExpression(DW_OP_lit0, DW_OP_mul)), !dbg !16 | |
652 call void @llvm.dbg.value(metadata i64 %b, metadata !11, metadata !DIExpression(DW_OP_lit0, DW_OP_mul, DW_OP_stack_value)), !dbg !16 | |
653 call void @llvm.dbg.value(metadata i64 %b, metadata !11, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 8)), !dbg !16 | |
654 call void @llvm.dbg.value(metadata i64 %b, metadata !11, metadata !DIExpression(DW_OP_lit0, DW_OP_mul, DW_OP_LLVM_fragment, 0, 8)), !dbg !16 | |
655 call void @llvm.dbg.value(metadata i64 %b, metadata !11, metadata !DIExpression(DW_OP_lit0, DW_OP_mul, DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8)), !dbg !16 | |
656 | |
657 %c = inttoptr i64 0 to i64*, !dbg !17 | |
658 call void @llvm.dbg.declare(metadata i64* %c, metadata !13, metadata !DIExpression()), !dbg !17 | |
659 | |
660 %d = inttoptr i64 0 to i32*, !dbg !18 | |
661 call void @llvm.dbg.addr(metadata i32* %d, metadata !20, metadata !DIExpression()), !dbg !18 | |
662 | |
663 %e = add <2 x i16> zeroinitializer, zeroinitializer | |
664 call void @llvm.dbg.value(metadata <2 x i16> %e, metadata !14, metadata !DIExpression()), !dbg !18 | |
665 | |
666 %f = call i32 @escape(i32 0) | |
667 call void @llvm.dbg.value(metadata i32 %f, metadata !9, metadata !DIExpression()), !dbg !15 | |
668 | |
669 %barrier = call i32 @escape(i32 0) | |
670 | |
671 %g = call i32 @escape(i32 %f) | |
672 call void @llvm.dbg.value(metadata i32 %g, metadata !9, metadata !DIExpression()), !dbg !15 | |
673 | |
674 ret void, !dbg !19 | |
675 } | |
676 | |
677 declare void @llvm.dbg.addr(metadata, metadata, metadata) | |
678 declare void @llvm.dbg.declare(metadata, metadata, metadata) | |
679 declare void @llvm.dbg.value(metadata, metadata, metadata) | |
680 | |
681 !llvm.dbg.cu = !{!0} | |
682 !llvm.module.flags = !{!5} | |
683 | |
684 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) | |
685 !1 = !DIFile(filename: "/Users/vsk/Desktop/foo.ll", directory: "/") | |
686 !2 = !{} | |
687 !5 = !{i32 2, !"Debug Info Version", i32 3} | |
688 !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !8) | |
689 !7 = !DISubroutineType(types: !2) | |
690 !8 = !{!9, !11, !13, !14} | |
691 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) | |
692 !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_signed) | |
693 !11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !12) | |
694 !12 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_signed) | |
695 !13 = !DILocalVariable(name: "3", scope: !6, file: !1, line: 3, type: !12) | |
696 !14 = !DILocalVariable(name: "4", scope: !6, file: !1, line: 4, type: !10) | |
697 !15 = !DILocation(line: 1, column: 1, scope: !6) | |
698 !16 = !DILocation(line: 2, column: 1, scope: !6) | |
699 !17 = !DILocation(line: 3, column: 1, scope: !6) | |
700 !18 = !DILocation(line: 4, column: 1, scope: !6) | |
701 !19 = !DILocation(line: 5, column: 1, scope: !6) | |
702 !20 = !DILocalVariable(name: "5", scope: !6, file: !1, line: 5, type: !10) | |
703 )"); | |
704 | |
705 bool BrokenDebugInfo = true; | |
706 verifyModule(*M, &errs(), &BrokenDebugInfo); | |
707 ASSERT_FALSE(BrokenDebugInfo); | |
708 | |
709 Function &F = *cast<Function>(M->getNamedValue("f")); | |
710 DominatorTree DT{F}; | |
711 | |
712 BasicBlock &BB = F.front(); | |
713 Instruction &A = BB.front(); | |
714 Instruction &B = *A.getNextNonDebugInstruction(); | |
715 Instruction &C = *B.getNextNonDebugInstruction(); | |
716 Instruction &D = *C.getNextNonDebugInstruction(); | |
717 Instruction &E = *D.getNextNonDebugInstruction(); | |
718 Instruction &F_ = *E.getNextNonDebugInstruction(); | |
719 Instruction &Barrier = *F_.getNextNonDebugInstruction(); | |
720 Instruction &G = *Barrier.getNextNonDebugInstruction(); | |
721 | |
722 // Simulate i32 <-> i64* conversion. Expect no updates: the datalayout says | |
723 // pointers are 64 bits, so the conversion would be lossy. | |
724 EXPECT_FALSE(replaceAllDbgUsesWith(A, C, C, DT)); | |
725 EXPECT_FALSE(replaceAllDbgUsesWith(C, A, A, DT)); | |
726 | |
727 // Simulate i32 <-> <2 x i16> conversion. This is unsupported. | |
728 EXPECT_FALSE(replaceAllDbgUsesWith(E, A, A, DT)); | |
729 EXPECT_FALSE(replaceAllDbgUsesWith(A, E, E, DT)); | |
730 | |
731 // Simulate i32* <-> i64* conversion. | |
732 EXPECT_TRUE(replaceAllDbgUsesWith(D, C, C, DT)); | |
733 | |
734 SmallVector<DbgVariableIntrinsic *, 2> CDbgVals; | |
735 findDbgUsers(CDbgVals, &C); | |
736 EXPECT_EQ(2U, CDbgVals.size()); | |
737 EXPECT_TRUE(any_of(CDbgVals, [](DbgVariableIntrinsic *DII) { | |
738 return isa<DbgAddrIntrinsic>(DII); | |
739 })); | |
740 EXPECT_TRUE(any_of(CDbgVals, [](DbgVariableIntrinsic *DII) { | |
741 return isa<DbgDeclareInst>(DII); | |
742 })); | |
743 | |
744 EXPECT_TRUE(replaceAllDbgUsesWith(C, D, D, DT)); | |
745 | |
746 SmallVector<DbgVariableIntrinsic *, 2> DDbgVals; | |
747 findDbgUsers(DDbgVals, &D); | |
748 EXPECT_EQ(2U, DDbgVals.size()); | |
749 EXPECT_TRUE(any_of(DDbgVals, [](DbgVariableIntrinsic *DII) { | |
750 return isa<DbgAddrIntrinsic>(DII); | |
751 })); | |
752 EXPECT_TRUE(any_of(DDbgVals, [](DbgVariableIntrinsic *DII) { | |
753 return isa<DbgDeclareInst>(DII); | |
754 })); | |
755 | |
756 // Introduce a use-before-def. Check that the dbg.value for %a is salvaged. | |
757 EXPECT_TRUE(replaceAllDbgUsesWith(A, F_, F_, DT)); | |
758 | |
759 auto *ADbgVal = cast<DbgValueInst>(A.getNextNode()); | |
760 EXPECT_EQ(ConstantInt::get(A.getType(), 0), ADbgVal->getVariableLocation()); | |
761 | |
762 // Introduce a use-before-def. Check that the dbg.values for %f are deleted. | |
763 EXPECT_TRUE(replaceAllDbgUsesWith(F_, G, G, DT)); | |
764 | |
765 SmallVector<DbgValueInst *, 1> FDbgVals; | |
766 findDbgValues(FDbgVals, &F); | |
767 EXPECT_EQ(0U, FDbgVals.size()); | |
768 | |
769 // Simulate i32 -> i64 conversion to test sign-extension. Here are some | |
770 // interesting cases to handle: | |
771 // 1) debug user has empty DIExpression | |
772 // 2) debug user has non-empty, non-stack-value'd DIExpression | |
773 // 3) debug user has non-empty, stack-value'd DIExpression | |
774 // 4-6) like (1-3), but with a fragment | |
775 EXPECT_TRUE(replaceAllDbgUsesWith(B, A, A, DT)); | |
776 | |
777 SmallVector<DbgValueInst *, 8> ADbgVals; | |
778 findDbgValues(ADbgVals, &A); | |
779 EXPECT_EQ(6U, ADbgVals.size()); | |
780 | |
781 // Check that %a has a dbg.value with a DIExpression matching \p Ops. | |
782 auto hasADbgVal = [&](ArrayRef<uint64_t> Ops) { | |
783 return any_of(ADbgVals, [&](DbgValueInst *DVI) { | |
784 assert(DVI->getVariable()->getName() == "2"); | |
785 return DVI->getExpression()->getElements() == Ops; | |
786 }); | |
787 }; | |
788 | |
789 // Case 1: The original expr is empty, so no deref is needed. | |
790 EXPECT_TRUE(hasADbgVal({DW_OP_LLVM_convert, 32, DW_ATE_signed, | |
791 DW_OP_LLVM_convert, 64, DW_ATE_signed, | |
792 DW_OP_stack_value})); | |
793 | |
794 // Case 2: Perform an address calculation with the original expr, deref it, | |
795 // then sign-extend the result. | |
796 EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref, | |
797 DW_OP_LLVM_convert, 32, DW_ATE_signed, | |
798 DW_OP_LLVM_convert, 64, DW_ATE_signed, | |
799 DW_OP_stack_value})); | |
800 | |
801 // Case 3: Insert the sign-extension logic before the DW_OP_stack_value. | |
802 EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_LLVM_convert, 32, | |
803 DW_ATE_signed, DW_OP_LLVM_convert, 64, DW_ATE_signed, | |
804 DW_OP_stack_value})); | |
805 | |
806 // Cases 4-6: Just like cases 1-3, but preserve the fragment at the end. | |
807 EXPECT_TRUE(hasADbgVal({DW_OP_LLVM_convert, 32, DW_ATE_signed, | |
808 DW_OP_LLVM_convert, 64, DW_ATE_signed, | |
809 DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8})); | |
810 | |
811 EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref, | |
812 DW_OP_LLVM_convert, 32, DW_ATE_signed, | |
813 DW_OP_LLVM_convert, 64, DW_ATE_signed, | |
814 DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8})); | |
815 | |
816 EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_LLVM_convert, 32, | |
817 DW_ATE_signed, DW_OP_LLVM_convert, 64, DW_ATE_signed, | |
818 DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8})); | |
819 | |
820 verifyModule(*M, &errs(), &BrokenDebugInfo); | |
821 ASSERT_FALSE(BrokenDebugInfo); | |
822 } | |
823 | |
824 TEST(Local, RemoveUnreachableBlocks) { | |
825 LLVMContext C; | |
826 | |
827 std::unique_ptr<Module> M = parseIR(C, | |
828 R"( | |
829 define void @br_simple() { | |
830 entry: | |
831 br label %bb0 | |
832 bb0: | |
833 ret void | |
834 bb1: | |
835 ret void | |
836 } | |
837 | |
838 define void @br_self_loop() { | |
839 entry: | |
840 br label %bb0 | |
841 bb0: | |
842 br i1 true, label %bb1, label %bb0 | |
843 bb1: | |
844 br i1 true, label %bb0, label %bb2 | |
845 bb2: | |
846 br label %bb2 | |
847 } | |
848 | |
849 define void @br_constant() { | |
850 entry: | |
851 br label %bb0 | |
852 bb0: | |
853 br i1 true, label %bb1, label %bb2 | |
854 bb1: | |
855 br i1 true, label %bb0, label %bb2 | |
856 bb2: | |
857 br label %bb2 | |
858 } | |
859 | |
860 define void @br_loop() { | |
861 entry: | |
862 br label %bb0 | |
863 bb0: | |
864 br label %bb0 | |
865 bb1: | |
866 br label %bb2 | |
867 bb2: | |
868 br label %bb1 | |
869 } | |
870 )"); | |
871 | |
872 auto runEager = [&](Function &F, DominatorTree *DT) { | |
873 PostDominatorTree PDT = PostDominatorTree(F); | |
874 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager); | |
875 removeUnreachableBlocks(F, nullptr, &DTU); | |
876 EXPECT_TRUE(DTU.getDomTree().verify()); | |
877 EXPECT_TRUE(DTU.getPostDomTree().verify()); | |
878 }; | |
879 | |
880 auto runLazy = [&](Function &F, DominatorTree *DT) { | |
881 PostDominatorTree PDT = PostDominatorTree(F); | |
882 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy); | |
883 removeUnreachableBlocks(F, nullptr, &DTU); | |
884 EXPECT_TRUE(DTU.getDomTree().verify()); | |
885 EXPECT_TRUE(DTU.getPostDomTree().verify()); | |
886 }; | |
887 | |
888 // Test removeUnreachableBlocks under Eager UpdateStrategy. | |
889 runWithDomTree(*M, "br_simple", runEager); | |
890 runWithDomTree(*M, "br_self_loop", runEager); | |
891 runWithDomTree(*M, "br_constant", runEager); | |
892 runWithDomTree(*M, "br_loop", runEager); | |
893 | |
894 // Test removeUnreachableBlocks under Lazy UpdateStrategy. | |
895 runWithDomTree(*M, "br_simple", runLazy); | |
896 runWithDomTree(*M, "br_self_loop", runLazy); | |
897 runWithDomTree(*M, "br_constant", runLazy); | |
898 runWithDomTree(*M, "br_loop", runLazy); | |
899 | |
900 M = parseIR(C, | |
901 R"( | |
902 define void @f() { | |
903 entry: | |
904 ret void | |
905 bb0: | |
906 ret void | |
907 } | |
908 )"); | |
909 | |
910 auto checkRUBlocksRetVal = [&](Function &F, DominatorTree *DT) { | |
911 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy); | |
912 EXPECT_TRUE(removeUnreachableBlocks(F, nullptr, &DTU)); | |
913 EXPECT_FALSE(removeUnreachableBlocks(F, nullptr, &DTU)); | |
914 EXPECT_TRUE(DTU.getDomTree().verify()); | |
915 }; | |
916 | |
917 runWithDomTree(*M, "f", checkRUBlocksRetVal); | |
918 } |