1305 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Transforms/Utils/Local.h"10#include "llvm/ADT/ScopeExit.h"11#include "llvm/Analysis/DomTreeUpdater.h"12#include "llvm/Analysis/InstructionSimplify.h"13#include "llvm/Analysis/PostDominators.h"14#include "llvm/Analysis/TargetTransformInfo.h"15#include "llvm/AsmParser/Parser.h"16#include "llvm/IR/BasicBlock.h"17#include "llvm/IR/DIBuilder.h"18#include "llvm/IR/DebugInfo.h"19#include "llvm/IR/DebugProgramInstruction.h"20#include "llvm/IR/IRBuilder.h"21#include "llvm/IR/Instructions.h"22#include "llvm/IR/IntrinsicInst.h"23#include "llvm/IR/LLVMContext.h"24#include "llvm/IR/Module.h"25#include "llvm/IR/Verifier.h"26#include "llvm/Support/SourceMgr.h"27#include "gtest/gtest.h"28 29using namespace llvm;30 31TEST(Local, RecursivelyDeleteDeadPHINodes) {32 LLVMContext C;33 34 IRBuilder<> builder(C);35 36 // Make blocks37 BasicBlock *bb0 = BasicBlock::Create(C);38 BasicBlock *bb1 = BasicBlock::Create(C);39 40 builder.SetInsertPoint(bb0);41 PHINode *phi = builder.CreatePHI(Type::getInt32Ty(C), 2);42 BranchInst *br0 = builder.CreateCondBr(builder.getTrue(), bb0, bb1);43 44 builder.SetInsertPoint(bb1);45 BranchInst *br1 = builder.CreateBr(bb0);46 47 phi->addIncoming(phi, bb0);48 phi->addIncoming(phi, bb1);49 50 // The PHI will be removed51 EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));52 53 // Make sure the blocks only contain the branches54 EXPECT_EQ(&bb0->front(), br0);55 EXPECT_EQ(&bb1->front(), br1);56 57 builder.SetInsertPoint(bb0);58 phi = builder.CreatePHI(Type::getInt32Ty(C), 0);59 60 EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));61 62 builder.SetInsertPoint(bb0);63 phi = builder.CreatePHI(Type::getInt32Ty(C), 0);64 builder.CreateAdd(phi, phi);65 66 EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));67 68 bb0->dropAllReferences();69 bb1->dropAllReferences();70 delete bb0;71 delete bb1;72}73 74TEST(Local, RemoveDuplicatePHINodes) {75 LLVMContext C;76 IRBuilder<> B(C);77 78 std::unique_ptr<Function> F(79 Function::Create(FunctionType::get(B.getVoidTy(), false),80 GlobalValue::ExternalLinkage, "F"));81 BasicBlock *Entry(BasicBlock::Create(C, "", F.get()));82 BasicBlock *BB(BasicBlock::Create(C, "", F.get()));83 BranchInst::Create(BB, Entry);84 85 B.SetInsertPoint(BB);86 87 AssertingVH<PHINode> P1 = B.CreatePHI(Type::getInt32Ty(C), 2);88 P1->addIncoming(B.getInt32(42), Entry);89 90 PHINode *P2 = B.CreatePHI(Type::getInt32Ty(C), 2);91 P2->addIncoming(B.getInt32(42), Entry);92 93 AssertingVH<PHINode> P3 = B.CreatePHI(Type::getInt32Ty(C), 2);94 P3->addIncoming(B.getInt32(42), Entry);95 P3->addIncoming(B.getInt32(23), BB);96 97 PHINode *P4 = B.CreatePHI(Type::getInt32Ty(C), 2);98 P4->addIncoming(B.getInt32(42), Entry);99 P4->addIncoming(B.getInt32(23), BB);100 101 P1->addIncoming(P3, BB);102 P2->addIncoming(P4, BB);103 BranchInst::Create(BB, BB);104 105 // Verify that we can eliminate PHIs that become duplicates after chaning PHIs106 // downstream.107 EXPECT_TRUE(EliminateDuplicatePHINodes(BB));108 EXPECT_EQ(3U, BB->size());109}110 111static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {112 SMDiagnostic Err;113 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);114 if (!Mod)115 Err.print("UtilsTests", errs());116 return Mod;117}118 119TEST(Local, ReplaceDbgDeclare) {120 LLVMContext C;121 // Original C source to get debug info for a local variable:122 // void f() { int x; }123 std::unique_ptr<Module> M = parseIR(C,124 R"(125 define void @f() !dbg !8 {126 entry:127 %x = alloca i32, align 4128 #dbg_declare(ptr %x, !11, !DIExpression(), !13)129 #dbg_declare(ptr %x, !11, !DIExpression(), !13)130 ret void, !dbg !14131 }132 133 !llvm.dbg.cu = !{!0}134 !llvm.module.flags = !{!3, !4}135 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)136 !1 = !DIFile(filename: "t2.c", directory: "foo")137 !2 = !{}138 !3 = !{i32 2, !"Dwarf Version", i32 4}139 !4 = !{i32 2, !"Debug Info Version", i32 3}140 !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)141 !9 = !DISubroutineType(types: !10)142 !10 = !{null}143 !11 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !12)144 !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)145 !13 = !DILocation(line: 2, column: 7, scope: !8)146 !14 = !DILocation(line: 3, column: 1, scope: !8)147 )");148 auto *GV = M->getNamedValue("f");149 ASSERT_TRUE(GV);150 auto *F = dyn_cast<Function>(GV);151 ASSERT_TRUE(F);152 Instruction *Inst = &F->front().front();153 auto *AI = dyn_cast<AllocaInst>(Inst);154 ASSERT_TRUE(AI);155 156 Value *NewBase = Constant::getNullValue(PointerType::getUnqual(C));157 DIBuilder DIB(*M);158 replaceDbgDeclare(AI, NewBase, DIB, DIExpression::ApplyOffset, 0);159 160 // There should be exactly two dbg.declares, attached to the terminator.161 Inst = F->front().getTerminator();162 ASSERT_TRUE(Inst);163 EXPECT_TRUE(Inst->hasDbgRecords());164 EXPECT_EQ(range_size(Inst->getDbgRecordRange()), 2u);165 for (DbgVariableRecord &DVR : filterDbgVars(Inst->getDbgRecordRange()))166 EXPECT_EQ(DVR.getAddress(), NewBase);167}168 169/// Build the dominator tree for the function and run the Test.170static void runWithDomTree(171 Module &M, StringRef FuncName,172 function_ref<void(Function &F, DominatorTree *DT)> Test) {173 auto *F = M.getFunction(FuncName);174 ASSERT_NE(F, nullptr) << "Could not find " << FuncName;175 // Compute the dominator tree for the function.176 DominatorTree DT(*F);177 Test(*F, &DT);178}179 180TEST(Local, MergeBasicBlockIntoOnlyPred) {181 LLVMContext C;182 std::unique_ptr<Module> M;183 auto resetIR = [&]() {184 M = parseIR(C,185 R"(186 define i32 @f(ptr %str) {187 entry:188 br label %bb2.i189 bb2.i: ; preds = %bb4.i, %entry190 br i1 false, label %bb4.i, label %base2flt.exit204191 bb4.i: ; preds = %bb2.i192 br i1 false, label %base2flt.exit204, label %bb2.i193 bb10.i196.bb7.i197_crit_edge: ; No predecessors!194 br label %bb7.i197195 bb7.i197: ; preds = %bb10.i196.bb7.i197_crit_edge196 %.reg2mem.0 = phi i32 [ %.reg2mem.0, %bb10.i196.bb7.i197_crit_edge ]197 br i1 undef, label %base2flt.exit204, label %base2flt.exit204198 base2flt.exit204: ; preds = %bb7.i197, %bb7.i197, %bb2.i, %bb4.i199 ret i32 0200 }201 )");202 };203 204 auto resetIRReplaceEntry = [&]() {205 M = parseIR(C,206 R"(207 define i32 @f() {208 entry:209 br label %bb2.i210 bb2.i: ; preds = %entry211 ret i32 0212 }213 )");214 };215 216 auto Test = [&](Function &F, DomTreeUpdater &DTU) {217 for (Function::iterator I = F.begin(), E = F.end(); I != E;) {218 BasicBlock *BB = &*I++;219 BasicBlock *SinglePred = BB->getSinglePredecessor();220 if (!SinglePred || SinglePred == BB || BB->hasAddressTaken())221 continue;222 BranchInst *Term = dyn_cast<BranchInst>(SinglePred->getTerminator());223 if (Term && !Term->isConditional())224 MergeBasicBlockIntoOnlyPred(BB, &DTU);225 }226 if (DTU.hasDomTree()) {227 EXPECT_TRUE(DTU.getDomTree().verify());228 }229 if (DTU.hasPostDomTree()) {230 EXPECT_TRUE(DTU.getPostDomTree().verify());231 }232 };233 234 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with235 // both DT and PDT.236 resetIR();237 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {238 PostDominatorTree PDT = PostDominatorTree(F);239 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager);240 Test(F, DTU);241 });242 243 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with244 // DT.245 resetIR();246 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {247 DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Eager);248 Test(F, DTU);249 });250 251 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with252 // PDT.253 resetIR();254 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {255 PostDominatorTree PDT = PostDominatorTree(F);256 DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Eager);257 Test(F, DTU);258 });259 260 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with261 // both DT and PDT.262 resetIR();263 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {264 PostDominatorTree PDT = PostDominatorTree(F);265 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);266 Test(F, DTU);267 });268 269 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with270 // PDT.271 resetIR();272 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {273 PostDominatorTree PDT = PostDominatorTree(F);274 DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Lazy);275 Test(F, DTU);276 });277 278 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with DT.279 resetIR();280 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {281 DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Lazy);282 Test(F, DTU);283 });284 285 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with286 // both DT and PDT.287 resetIRReplaceEntry();288 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {289 PostDominatorTree PDT = PostDominatorTree(F);290 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager);291 Test(F, DTU);292 });293 294 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with295 // DT.296 resetIRReplaceEntry();297 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {298 DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Eager);299 Test(F, DTU);300 });301 302 // Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with303 // PDT.304 resetIRReplaceEntry();305 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {306 PostDominatorTree PDT = PostDominatorTree(F);307 DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Eager);308 Test(F, DTU);309 });310 311 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with312 // both DT and PDT.313 resetIRReplaceEntry();314 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {315 PostDominatorTree PDT = PostDominatorTree(F);316 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);317 Test(F, DTU);318 });319 320 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with321 // PDT.322 resetIRReplaceEntry();323 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {324 PostDominatorTree PDT = PostDominatorTree(F);325 DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Lazy);326 Test(F, DTU);327 });328 329 // Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with DT.330 resetIRReplaceEntry();331 runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {332 DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Lazy);333 Test(F, DTU);334 });335}336 337TEST(Local, ConstantFoldTerminator) {338 LLVMContext C;339 340 std::unique_ptr<Module> M = parseIR(C,341 R"(342 define void @br_same_dest() {343 entry:344 br i1 false, label %bb0, label %bb0345 bb0:346 ret void347 }348 349 define void @br_different_dest() {350 entry:351 br i1 true, label %bb0, label %bb1352 bb0:353 br label %exit354 bb1:355 br label %exit356 exit:357 ret void358 }359 360 define void @switch_2_different_dest() {361 entry:362 switch i32 0, label %default [ i32 0, label %bb0 ]363 default:364 ret void365 bb0:366 ret void367 }368 define void @switch_2_different_dest_default() {369 entry:370 switch i32 1, label %default [ i32 0, label %bb0 ]371 default:372 ret void373 bb0:374 ret void375 }376 define void @switch_3_different_dest() {377 entry:378 switch i32 0, label %default [ i32 0, label %bb0379 i32 1, label %bb1 ]380 default:381 ret void382 bb0:383 ret void384 bb1:385 ret void386 }387 388 define void @switch_variable_2_default_dest(i32 %arg) {389 entry:390 switch i32 %arg, label %default [ i32 0, label %default ]391 default:392 ret void393 }394 395 define void @switch_constant_2_default_dest() {396 entry:397 switch i32 1, label %default [ i32 0, label %default ]398 default:399 ret void400 }401 402 define void @switch_constant_3_repeated_dest() {403 entry:404 switch i32 0, label %default [ i32 0, label %bb0405 i32 1, label %bb0 ]406 bb0:407 ret void408 default:409 ret void410 }411 412 define void @indirectbr() {413 entry:414 indirectbr ptr blockaddress(@indirectbr, %bb0), [label %bb0, label %bb1]415 bb0:416 ret void417 bb1:418 ret void419 }420 421 define void @indirectbr_repeated() {422 entry:423 indirectbr ptr blockaddress(@indirectbr_repeated, %bb0), [label %bb0, label %bb0]424 bb0:425 ret void426 }427 428 define void @indirectbr_unreachable() {429 entry:430 indirectbr ptr blockaddress(@indirectbr_unreachable, %bb0), [label %bb1]431 bb0:432 ret void433 bb1:434 ret void435 }436 )");437 438 auto CFAllTerminatorsEager = [&](Function &F, DominatorTree *DT) {439 PostDominatorTree PDT = PostDominatorTree(F);440 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager);441 for (Function::iterator I = F.begin(), E = F.end(); I != E;) {442 BasicBlock *BB = &*I++;443 ConstantFoldTerminator(BB, true, nullptr, &DTU);444 }445 446 EXPECT_TRUE(DTU.getDomTree().verify());447 EXPECT_TRUE(DTU.getPostDomTree().verify());448 };449 450 auto CFAllTerminatorsLazy = [&](Function &F, DominatorTree *DT) {451 PostDominatorTree PDT = PostDominatorTree(F);452 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);453 for (Function::iterator I = F.begin(), E = F.end(); I != E;) {454 BasicBlock *BB = &*I++;455 ConstantFoldTerminator(BB, true, nullptr, &DTU);456 }457 458 EXPECT_TRUE(DTU.getDomTree().verify());459 EXPECT_TRUE(DTU.getPostDomTree().verify());460 };461 462 // Test ConstantFoldTerminator under Eager UpdateStrategy.463 runWithDomTree(*M, "br_same_dest", CFAllTerminatorsEager);464 runWithDomTree(*M, "br_different_dest", CFAllTerminatorsEager);465 runWithDomTree(*M, "switch_2_different_dest", CFAllTerminatorsEager);466 runWithDomTree(*M, "switch_2_different_dest_default", CFAllTerminatorsEager);467 runWithDomTree(*M, "switch_3_different_dest", CFAllTerminatorsEager);468 runWithDomTree(*M, "switch_variable_2_default_dest", CFAllTerminatorsEager);469 runWithDomTree(*M, "switch_constant_2_default_dest", CFAllTerminatorsEager);470 runWithDomTree(*M, "switch_constant_3_repeated_dest", CFAllTerminatorsEager);471 runWithDomTree(*M, "indirectbr", CFAllTerminatorsEager);472 runWithDomTree(*M, "indirectbr_repeated", CFAllTerminatorsEager);473 runWithDomTree(*M, "indirectbr_unreachable", CFAllTerminatorsEager);474 475 // Test ConstantFoldTerminator under Lazy UpdateStrategy.476 runWithDomTree(*M, "br_same_dest", CFAllTerminatorsLazy);477 runWithDomTree(*M, "br_different_dest", CFAllTerminatorsLazy);478 runWithDomTree(*M, "switch_2_different_dest", CFAllTerminatorsLazy);479 runWithDomTree(*M, "switch_2_different_dest_default", CFAllTerminatorsLazy);480 runWithDomTree(*M, "switch_3_different_dest", CFAllTerminatorsLazy);481 runWithDomTree(*M, "switch_variable_2_default_dest", CFAllTerminatorsLazy);482 runWithDomTree(*M, "switch_constant_2_default_dest", CFAllTerminatorsLazy);483 runWithDomTree(*M, "switch_constant_3_repeated_dest", CFAllTerminatorsLazy);484 runWithDomTree(*M, "indirectbr", CFAllTerminatorsLazy);485 runWithDomTree(*M, "indirectbr_repeated", CFAllTerminatorsLazy);486 runWithDomTree(*M, "indirectbr_unreachable", CFAllTerminatorsLazy);487}488 489struct SalvageDebugInfoTest : ::testing::Test {490 LLVMContext C;491 std::unique_ptr<Module> M;492 Function *F = nullptr;493 494 void SetUp() override {495 M = parseIR(C,496 R"(497 define void @f() !dbg !8 {498 entry:499 %x = add i32 0, 1500 %y = add i32 %x, 2501 #dbg_value(i32 %x, !11, !DIExpression(), !13)502 #dbg_value(i32 %y, !11, !DIExpression(), !13)503 ret void, !dbg !14504 }505 !llvm.dbg.cu = !{!0}506 !llvm.module.flags = !{!3, !4}507 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)508 !1 = !DIFile(filename: "t2.c", directory: "foo")509 !2 = !{}510 !3 = !{i32 2, !"Dwarf Version", i32 4}511 !4 = !{i32 2, !"Debug Info Version", i32 3}512 !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)513 !9 = !DISubroutineType(types: !10)514 !10 = !{null}515 !11 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !12)516 !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)517 !13 = !DILocation(line: 2, column: 7, scope: !8)518 !14 = !DILocation(line: 3, column: 1, scope: !8)519 )");520 521 auto *GV = M->getNamedValue("f");522 ASSERT_TRUE(GV);523 F = dyn_cast<Function>(GV);524 ASSERT_TRUE(F);525 }526 527 bool doesDebugValueDescribeX(const DbgVariableRecord &DVR) {528 if (DVR.getNumVariableLocationOps() != 1u)529 return false;530 const auto &CI = *cast<ConstantInt>(DVR.getValue(0));531 if (CI.isZero())532 return DVR.getExpression()->getElements().equals(533 {dwarf::DW_OP_plus_uconst, 1, dwarf::DW_OP_stack_value});534 else if (CI.isOneValue())535 return DVR.getExpression()->getElements().empty();536 return false;537 }538 539 bool doesDebugValueDescribeY(const DbgVariableRecord &DVR) {540 if (DVR.getNumVariableLocationOps() != 1u)541 return false;542 const auto &CI = *cast<ConstantInt>(DVR.getVariableLocationOp(0));543 if (CI.isZero())544 return DVR.getExpression()->getElements().equals(545 {dwarf::DW_OP_plus_uconst, 3, dwarf::DW_OP_stack_value});546 else if (CI.isOneValue())547 return DVR.getExpression()->getElements().equals(548 {dwarf::DW_OP_plus_uconst, 2, dwarf::DW_OP_stack_value});549 return false;550 }551 552 void verifyDebugValuesAreSalvaged() {553 // The function should only contain debug values and a terminator.554 EXPECT_EQ(F->size(), 1u);555 EXPECT_TRUE(F->begin()->begin()->isTerminator());556 557 // Check that the debug values for %x and %y are preserved.558 bool FoundX = false;559 bool FoundY = false;560 for (DbgVariableRecord &DVR :561 filterDbgVars(F->begin()->begin()->getDbgRecordRange())) {562 EXPECT_EQ(DVR.getVariable()->getName(), "x");563 FoundX |= doesDebugValueDescribeX(DVR);564 FoundY |= doesDebugValueDescribeY(DVR);565 }566 EXPECT_TRUE(FoundX);567 EXPECT_TRUE(FoundY);568 }569};570 571TEST_F(SalvageDebugInfoTest, RecursiveInstDeletion) {572 Instruction *Inst = &F->front().front();573 Inst = Inst->getNextNode(); // Get %y = add ...574 ASSERT_TRUE(Inst);575 bool Deleted = RecursivelyDeleteTriviallyDeadInstructions(Inst);576 ASSERT_TRUE(Deleted);577 verifyDebugValuesAreSalvaged();578}579 580TEST_F(SalvageDebugInfoTest, RecursiveBlockSimplification) {581 BasicBlock *BB = &F->front();582 ASSERT_TRUE(BB);583 bool Deleted = SimplifyInstructionsInBlock(BB);584 ASSERT_TRUE(Deleted);585 verifyDebugValuesAreSalvaged();586}587 588TEST(Local, ChangeToUnreachable) {589 LLVMContext Ctx;590 591 std::unique_ptr<Module> M = parseIR(Ctx,592 R"(593 define internal void @foo() !dbg !6 {594 entry:595 ret void, !dbg !8596 }597 598 !llvm.dbg.cu = !{!0}599 !llvm.debugify = !{!3, !4}600 !llvm.module.flags = !{!5}601 602 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)603 !1 = !DIFile(filename: "test.ll", directory: "/")604 !2 = !{}605 !3 = !{i32 1}606 !4 = !{i32 0}607 !5 = !{i32 2, !"Debug Info Version", i32 3}608 !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)609 !7 = !DISubroutineType(types: !2)610 !8 = !DILocation(line: 1, column: 1, scope: !6)611 )");612 613 bool BrokenDebugInfo = true;614 verifyModule(*M, &errs(), &BrokenDebugInfo);615 ASSERT_FALSE(BrokenDebugInfo);616 617 Function &F = *cast<Function>(M->getNamedValue("foo"));618 619 BasicBlock &BB = F.front();620 Instruction &A = BB.front();621 DebugLoc DLA = A.getDebugLoc();622 623 ASSERT_TRUE(isa<ReturnInst>(&A));624 // One instruction should be affected.625 EXPECT_EQ(changeToUnreachable(&A), 1U);626 627 Instruction &B = BB.front();628 629 // There should be an uncreachable instruction.630 ASSERT_TRUE(isa<UnreachableInst>(&B));631 632 DebugLoc DLB = B.getDebugLoc();633 EXPECT_EQ(DLA, DLB);634}635 636TEST(Local, FindDbgRecords) {637 // DbgRecord copy of the FindDbgUsers test above.638 LLVMContext Ctx;639 std::unique_ptr<Module> M = parseIR(Ctx,640 R"(641 define dso_local void @fun(ptr %a) #0 !dbg !11 {642 entry:643 #dbg_assign(ptr %a, !16, !DIExpression(), !15, ptr %a, !DIExpression(), !19)644 ret void645 }646 647 !llvm.dbg.cu = !{!0}648 !llvm.module.flags = !{!2, !3, !9}649 !llvm.ident = !{!10}650 651 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 17.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)652 !1 = !DIFile(filename: "test.cpp", directory: "/")653 !2 = !{i32 7, !"Dwarf Version", i32 5}654 !3 = !{i32 2, !"Debug Info Version", i32 3}655 !4 = !{i32 1, !"wchar_size", i32 4}656 !9 = !{i32 7, !"debug-info-assignment-tracking", i1 true}657 !10 = !{!"clang version 17.0.0"}658 !11 = distinct !DISubprogram(name: "fun", linkageName: "fun", scope: !1, file: !1, line: 1, type: !12, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)659 !12 = !DISubroutineType(types: !13)660 !13 = !{null}661 !14 = !{}662 !15 = distinct !DIAssignID()663 !16 = !DILocalVariable(name: "x", scope: !11, file: !1, line: 2, type: !17)664 !17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64)665 !18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)666 !19 = !DILocation(line: 0, scope: !11)667 )");668 669 bool BrokenDebugInfo = true;670 verifyModule(*M, &errs(), &BrokenDebugInfo);671 ASSERT_FALSE(BrokenDebugInfo);672 673 Function &Fun = *cast<Function>(M->getNamedValue("fun"));674 Value *Arg = Fun.getArg(0);675 676 SmallVector<DbgVariableRecord *> Records;677 // Arg (%a) is used twice by a single dbg_assign. Check findDbgUsers returns678 // only 1 pointer to it rather than 2.679 findDbgUsers(Arg, Records);680 EXPECT_EQ(Records.size(), 1u);681 682 Records.clear();683 // Arg (%a) is used twice by a single dbg_assign. Check findDbgValues returns684 // only 1 pointer to it rather than 2.685 findDbgValues(Arg, Records);686 EXPECT_EQ(Records.size(), 1u);687}688 689TEST(Local, ReplaceAllDbgUsesWith) {690 using namespace llvm::dwarf;691 LLVMContext Ctx;692 693 // Note: The datalayout simulates Darwin/x86_64.694 std::unique_ptr<Module> M = parseIR(Ctx,695 R"(696 target datalayout = "e-m:o-i63:64-f80:128-n8:16:32:64-S128"697 698 declare i32 @escape(i32)699 700 define void @f() !dbg !6 {701 entry:702 %a = add i32 0, 1, !dbg !15703 704 #dbg_value(i32 %a, !9, !DIExpression(), !15)705 %b = add i64 0, 1, !dbg !16706 707 #dbg_value(i64 %b, !11, !DIExpression(), !16)708 #dbg_value(i64 %b, !11, !DIExpression(DW_OP_lit0, DW_OP_mul), !16)709 #dbg_value(i64 %b, !11, !DIExpression(DW_OP_lit0, DW_OP_mul, DW_OP_stack_value), !16)710 #dbg_value(i64 %b, !11, !DIExpression(DW_OP_LLVM_fragment, 0, 8), !16)711 #dbg_value(i64 %b, !11, !DIExpression(DW_OP_lit0, DW_OP_mul, DW_OP_LLVM_fragment, 0, 8), !16)712 #dbg_value(i64 %b, !11, !DIExpression(DW_OP_lit0, DW_OP_mul, DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8), !16)713 %c = inttoptr i64 0 to ptr, !dbg !17714 715 #dbg_declare(ptr %c, !13, !DIExpression(), !17)716 %d = inttoptr i64 0 to ptr, !dbg !18717 718 #dbg_declare(ptr %d, !20, !DIExpression(), !18)719 %e = add <2 x i16> zeroinitializer, zeroinitializer720 721 #dbg_value(<2 x i16> %e, !14, !DIExpression(), !18)722 %f = call i32 @escape(i32 0)723 724 #dbg_value(i32 %f, !9, !DIExpression(), !15)725 %barrier = call i32 @escape(i32 0)726 727 %g = call i32 @escape(i32 %f)728 729 #dbg_value(i32 %g, !9, !DIExpression(), !15)730 ret void, !dbg !19731 }732 733 !llvm.dbg.cu = !{!0}734 !llvm.module.flags = !{!5}735 736 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)737 !1 = !DIFile(filename: "/Users/vsk/Desktop/foo.ll", directory: "/")738 !2 = !{}739 !5 = !{i32 2, !"Debug Info Version", i32 3}740 !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)741 !7 = !DISubroutineType(types: !2)742 !8 = !{!9, !11, !13, !14}743 !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)744 !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_signed)745 !11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !12)746 !12 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_signed)747 !13 = !DILocalVariable(name: "3", scope: !6, file: !1, line: 3, type: !12)748 !14 = !DILocalVariable(name: "4", scope: !6, file: !1, line: 4, type: !10)749 !15 = !DILocation(line: 1, column: 1, scope: !6)750 !16 = !DILocation(line: 2, column: 1, scope: !6)751 !17 = !DILocation(line: 3, column: 1, scope: !6)752 !18 = !DILocation(line: 4, column: 1, scope: !6)753 !19 = !DILocation(line: 5, column: 1, scope: !6)754 !20 = !DILocalVariable(name: "5", scope: !6, file: !1, line: 5, type: !10)755 )");756 757 bool BrokenDebugInfo = true;758 verifyModule(*M, &errs(), &BrokenDebugInfo);759 ASSERT_FALSE(BrokenDebugInfo);760 761 Function &F = *cast<Function>(M->getNamedValue("f"));762 DominatorTree DT{F};763 764 BasicBlock &BB = F.front();765 Instruction &A = BB.front();766 Instruction &B = *A.getNextNode();767 Instruction &C = *B.getNextNode();768 Instruction &D = *C.getNextNode();769 Instruction &E = *D.getNextNode();770 Instruction &F_ = *E.getNextNode();771 Instruction &Barrier = *F_.getNextNode();772 Instruction &G = *Barrier.getNextNode();773 774 // Simulate i32 <-> i64* conversion. Expect no updates: the datalayout says775 // pointers are 64 bits, so the conversion would be lossy.776 EXPECT_FALSE(replaceAllDbgUsesWith(A, C, C, DT));777 EXPECT_FALSE(replaceAllDbgUsesWith(C, A, A, DT));778 779 // Simulate i32 <-> <2 x i16> conversion. This is unsupported.780 EXPECT_FALSE(replaceAllDbgUsesWith(E, A, A, DT));781 EXPECT_FALSE(replaceAllDbgUsesWith(A, E, E, DT));782 783 // Simulate i32* <-> i64* conversion.784 EXPECT_TRUE(replaceAllDbgUsesWith(D, C, C, DT));785 786 SmallVector<DbgVariableRecord *, 2> CDbgRecords;787 findDbgUsers(&C, CDbgRecords);788 EXPECT_EQ(2U, CDbgRecords.size());789 EXPECT_TRUE(all_of(790 CDbgRecords, [](DbgVariableRecord *DVR) { return DVR->isDbgDeclare(); }));791 792 EXPECT_TRUE(replaceAllDbgUsesWith(C, D, D, DT));793 794 SmallVector<DbgVariableRecord *, 2> DDbgRecords;795 findDbgUsers(&D, DDbgRecords);796 EXPECT_EQ(2U, DDbgRecords.size());797 EXPECT_TRUE(all_of(798 DDbgRecords, [](DbgVariableRecord *DVR) { return DVR->isDbgDeclare(); }));799 800 // Introduce a use-before-def. Check that the dbg.value for %a is salvaged.801 EXPECT_TRUE(replaceAllDbgUsesWith(A, F_, F_, DT));802 803 EXPECT_FALSE(A.hasDbgRecords());804 EXPECT_TRUE(B.hasDbgRecords());805 DbgVariableRecord *BDbgVal =806 cast<DbgVariableRecord>(&*B.getDbgRecordRange().begin());807 EXPECT_EQ(BDbgVal->getNumVariableLocationOps(), 1u);808 EXPECT_EQ(ConstantInt::get(A.getType(), 0),809 BDbgVal->getVariableLocationOp(0));810 811 // Introduce a use-before-def. Check that the dbg.values for %f become undef.812 EXPECT_TRUE(replaceAllDbgUsesWith(F_, G, G, DT));813 814 DbgVariableRecord *BarrierDbgVal =815 cast<DbgVariableRecord>(&*Barrier.getDbgRecordRange().begin());816 EXPECT_EQ(BarrierDbgVal->getNumVariableLocationOps(), 1u);817 EXPECT_TRUE(BarrierDbgVal->isKillLocation());818 819 SmallVector<DbgVariableRecord *, 8> BarrierDbgRecs;820 findDbgValues(&F_, BarrierDbgRecs);821 EXPECT_EQ(0U, BarrierDbgRecs.size());822 823 // Simulate i32 -> i64 conversion to test sign-extension. Here are some824 // interesting cases to handle:825 // 1) debug user has empty DIExpression826 // 2) debug user has non-empty, non-stack-value'd DIExpression827 // 3) debug user has non-empty, stack-value'd DIExpression828 // 4-6) like (1-3), but with a fragment829 EXPECT_TRUE(replaceAllDbgUsesWith(B, A, A, DT));830 831 SmallVector<DbgVariableRecord *, 8> BDbgRecs;832 findDbgValues(&A, BDbgRecs);833 EXPECT_EQ(6U, BDbgRecs.size());834 835 // Check that %a has a dbg.value with a DIExpression matching \p Ops.836 auto hasADbgVal = [&](ArrayRef<uint64_t> Ops) {837 return any_of(BDbgRecs, [&](DbgVariableRecord *DVI) {838 assert(DVI->getVariable()->getName() == "2");839 return DVI->getExpression()->getElements() == Ops;840 });841 };842 843 // Case 1: The original expr is empty, so no deref is needed.844 EXPECT_TRUE(hasADbgVal({DW_OP_LLVM_convert, 32, DW_ATE_signed,845 DW_OP_LLVM_convert, 64, DW_ATE_signed,846 DW_OP_stack_value}));847 848 // Case 2: Perform an address calculation with the original expr, deref it,849 // then sign-extend the result.850 EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref,851 DW_OP_LLVM_convert, 32, DW_ATE_signed,852 DW_OP_LLVM_convert, 64, DW_ATE_signed,853 DW_OP_stack_value}));854 855 // Case 3: Insert the sign-extension logic before the DW_OP_stack_value.856 EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_LLVM_convert, 32,857 DW_ATE_signed, DW_OP_LLVM_convert, 64, DW_ATE_signed,858 DW_OP_stack_value}));859 860 // Cases 4-6: Just like cases 1-3, but preserve the fragment at the end.861 EXPECT_TRUE(hasADbgVal({DW_OP_LLVM_convert, 32, DW_ATE_signed,862 DW_OP_LLVM_convert, 64, DW_ATE_signed,863 DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8}));864 865 EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_deref,866 DW_OP_LLVM_convert, 32, DW_ATE_signed,867 DW_OP_LLVM_convert, 64, DW_ATE_signed,868 DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8}));869 870 EXPECT_TRUE(hasADbgVal({DW_OP_lit0, DW_OP_mul, DW_OP_LLVM_convert, 32,871 DW_ATE_signed, DW_OP_LLVM_convert, 64, DW_ATE_signed,872 DW_OP_stack_value, DW_OP_LLVM_fragment, 0, 8}));873 874 verifyModule(*M, &errs(), &BrokenDebugInfo);875 ASSERT_FALSE(BrokenDebugInfo);876}877 878TEST(Local, RemoveUnreachableBlocks) {879 LLVMContext C;880 881 std::unique_ptr<Module> M = parseIR(C,882 R"(883 define void @br_simple() {884 entry:885 br label %bb0886 bb0:887 ret void888 bb1:889 ret void890 }891 892 define void @br_self_loop() {893 entry:894 br label %bb0895 bb0:896 br i1 true, label %bb1, label %bb0897 bb1:898 br i1 true, label %bb0, label %bb2899 bb2:900 br label %bb2901 }902 903 define void @br_constant() {904 entry:905 br label %bb0906 bb0:907 br i1 true, label %bb1, label %bb2908 bb1:909 br i1 true, label %bb0, label %bb2910 bb2:911 br label %bb2912 }913 914 define void @br_loop() {915 entry:916 br label %bb0917 bb0:918 br label %bb0919 bb1:920 br label %bb2921 bb2:922 br label %bb1923 }924 925 declare i32 @__gxx_personality_v0(...)926 927 define void @invoke_terminator() personality ptr @__gxx_personality_v0 {928 entry:929 br i1 undef, label %invoke.block, label %exit930 931 invoke.block:932 %cond = invoke zeroext i1 @invokable()933 to label %continue.block unwind label %lpad.block934 935 continue.block:936 br i1 %cond, label %if.then, label %if.end937 938 if.then:939 unreachable940 941 if.end:942 unreachable943 944 lpad.block:945 %lp = landingpad { ptr, i32 }946 catch ptr null947 br label %exit948 949 exit:950 ret void951 }952 953 declare i1 @invokable()954 )");955 956 auto runEager = [&](Function &F, DominatorTree *DT) {957 PostDominatorTree PDT = PostDominatorTree(F);958 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager);959 removeUnreachableBlocks(F, &DTU);960 EXPECT_TRUE(DTU.getDomTree().verify());961 EXPECT_TRUE(DTU.getPostDomTree().verify());962 };963 964 auto runLazy = [&](Function &F, DominatorTree *DT) {965 PostDominatorTree PDT = PostDominatorTree(F);966 DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);967 removeUnreachableBlocks(F, &DTU);968 EXPECT_TRUE(DTU.getDomTree().verify());969 EXPECT_TRUE(DTU.getPostDomTree().verify());970 };971 972 // Test removeUnreachableBlocks under Eager UpdateStrategy.973 runWithDomTree(*M, "br_simple", runEager);974 runWithDomTree(*M, "br_self_loop", runEager);975 runWithDomTree(*M, "br_constant", runEager);976 runWithDomTree(*M, "br_loop", runEager);977 runWithDomTree(*M, "invoke_terminator", runEager);978 979 // Test removeUnreachableBlocks under Lazy UpdateStrategy.980 runWithDomTree(*M, "br_simple", runLazy);981 runWithDomTree(*M, "br_self_loop", runLazy);982 runWithDomTree(*M, "br_constant", runLazy);983 runWithDomTree(*M, "br_loop", runLazy);984 runWithDomTree(*M, "invoke_terminator", runLazy);985 986 M = parseIR(C,987 R"(988 define void @f() {989 entry:990 ret void991 bb0:992 ret void993 }994 )");995 996 auto checkRUBlocksRetVal = [&](Function &F, DominatorTree *DT) {997 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);998 EXPECT_TRUE(removeUnreachableBlocks(F, &DTU));999 EXPECT_FALSE(removeUnreachableBlocks(F, &DTU));1000 EXPECT_TRUE(DTU.getDomTree().verify());1001 };1002 1003 runWithDomTree(*M, "f", checkRUBlocksRetVal);1004}1005 1006TEST(Local, SimplifyCFGWithNullAC) {1007 LLVMContext Ctx;1008 1009 std::unique_ptr<Module> M = parseIR(Ctx, R"(1010 declare void @true_path()1011 declare void @false_path()1012 declare void @llvm.assume(i1 %cond);1013 1014 define i32 @foo(i1, i32) {1015 entry:1016 %cmp = icmp sgt i32 %1, 01017 br i1 %cmp, label %if.bb1, label %then.bb11018 if.bb1:1019 call void @true_path()1020 br label %test.bb1021 then.bb1:1022 call void @false_path()1023 br label %test.bb1024 test.bb:1025 %phi = phi i1 [1, %if.bb1], [%0, %then.bb1]1026 call void @llvm.assume(i1 %0)1027 br i1 %phi, label %if.bb2, label %then.bb21028 if.bb2:1029 ret i32 %11030 then.bb2:1031 ret i32 01032 }1033 )");1034 1035 Function &F = *cast<Function>(M->getNamedValue("foo"));1036 TargetTransformInfo TTI(M->getDataLayout());1037 1038 SimplifyCFGOptions Options{};1039 Options.setAssumptionCache(nullptr);1040 1041 // Obtain BasicBlock of interest to this test, %test.bb.1042 BasicBlock *TestBB = nullptr;1043 for (BasicBlock &BB : F) {1044 if (BB.getName() == "test.bb") {1045 TestBB = &BB;1046 break;1047 }1048 }1049 ASSERT_TRUE(TestBB);1050 1051 DominatorTree DT(F);1052 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);1053 1054 // %test.bb is expected to be simplified by FoldCondBranchOnPHI.1055 EXPECT_TRUE(simplifyCFG(TestBB, TTI,1056 RequireAndPreserveDomTree ? &DTU : nullptr, Options));1057}1058 1059TEST(LocalTest, TargetTypeInfoHasNoReplacementProperty) {1060 LLVMContext Ctx;1061 SmallVector<unsigned, 3> Ints = {};1062 auto *TT = llvm::TargetExtType::get(Ctx, "dx.RawBuffer", {}, Ints);1063 1064 EXPECT_TRUE(TT->hasProperty(TargetExtType::Property::IsTokenLike));1065}1066 1067TEST(Local, CanReplaceOperandWithVariable) {1068 LLVMContext Ctx;1069 Module M("test_module", Ctx);1070 IRBuilder<> B(Ctx);1071 1072 FunctionType *FnType =1073 FunctionType::get(Type::getVoidTy(Ctx), {}, false);1074 1075 FunctionType *VarArgFnType =1076 FunctionType::get(Type::getVoidTy(Ctx), {B.getInt32Ty()}, true);1077 1078 Function *TestBody = Function::Create(FnType, GlobalValue::ExternalLinkage,1079 0, "", &M);1080 1081 BasicBlock *BB0 = BasicBlock::Create(Ctx, "", TestBody);1082 B.SetInsertPoint(BB0);1083 1084 FunctionCallee Intrin = M.getOrInsertFunction("llvm.foo", FnType);1085 FunctionCallee Func = M.getOrInsertFunction("foo", FnType);1086 FunctionCallee VarArgFunc1087 = M.getOrInsertFunction("foo.vararg", VarArgFnType);1088 FunctionCallee VarArgIntrin1089 = M.getOrInsertFunction("llvm.foo.vararg", VarArgFnType);1090 1091 auto *CallToIntrin = B.CreateCall(Intrin);1092 auto *CallToFunc = B.CreateCall(Func);1093 1094 // Test if it's valid to replace the callee operand.1095 EXPECT_FALSE(canReplaceOperandWithVariable(CallToIntrin, 0));1096 EXPECT_TRUE(canReplaceOperandWithVariable(CallToFunc, 0));1097 1098 // That it's invalid to replace an argument in the variadic argument list for1099 // an intrinsic, but OK for a normal function.1100 auto *CallToVarArgFunc = B.CreateCall(1101 VarArgFunc, {B.getInt32(0), B.getInt32(1), B.getInt32(2)});1102 EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 0));1103 EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 1));1104 EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 2));1105 EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 3));1106 1107 auto *CallToVarArgIntrin = B.CreateCall(1108 VarArgIntrin, {B.getInt32(0), B.getInt32(1), B.getInt32(2)});1109 EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgIntrin, 0));1110 EXPECT_FALSE(canReplaceOperandWithVariable(CallToVarArgIntrin, 1));1111 EXPECT_FALSE(canReplaceOperandWithVariable(CallToVarArgIntrin, 2));1112 EXPECT_FALSE(canReplaceOperandWithVariable(CallToVarArgIntrin, 3));1113 1114 // Test that it's invalid to replace gcroot operands, even though it can't use1115 // immarg.1116 Type *PtrPtr = B.getPtrTy(0);1117 Value *Alloca = B.CreateAlloca(PtrPtr, (unsigned)0);1118 CallInst *GCRoot = B.CreateIntrinsic(1119 Intrinsic::gcroot, {Alloca, Constant::getNullValue(PtrPtr)});1120 EXPECT_TRUE(canReplaceOperandWithVariable(GCRoot, 0)); // Alloca1121 EXPECT_FALSE(canReplaceOperandWithVariable(GCRoot, 1));1122 EXPECT_FALSE(canReplaceOperandWithVariable(GCRoot, 2));1123 1124 BB0->dropAllReferences();1125}1126 1127TEST(Local, ExpressionForConstant) {1128 LLVMContext Context;1129 Module M("test_module", Context);1130 DIBuilder DIB(M);1131 DIExpression *Expr = nullptr;1132 1133 auto createExpression = [&](Constant *C, Type *Ty) -> DIExpression * {1134 EXPECT_NE(C, nullptr);1135 EXPECT_NE(Ty, nullptr);1136 EXPECT_EQ(C->getType(), Ty);1137 std::unique_ptr<GlobalVariable> GV = std::make_unique<GlobalVariable>(1138 Ty, false, GlobalValue::ExternalLinkage, C, "GV");1139 EXPECT_NE(GV, nullptr);1140 1141 DIExpression *Expr = getExpressionForConstant(DIB, *GV->getInitializer(),1142 *GV->getValueType());1143 if (Expr) {1144 EXPECT_EQ(Expr->getNumElements(), 3u);1145 EXPECT_EQ(Expr->getElement(0), dwarf::DW_OP_constu);1146 EXPECT_EQ(Expr->getElement(2), dwarf::DW_OP_stack_value);1147 }1148 return Expr;1149 };1150 1151 // Integer.1152 IntegerType *Int1Ty = Type::getInt1Ty(Context);1153 Expr = createExpression(ConstantInt::getTrue(Context), Int1Ty);1154 EXPECT_NE(Expr, nullptr);1155 EXPECT_EQ(Expr->getElement(1), 1U);1156 1157 Expr = createExpression(ConstantInt::getFalse(Context), Int1Ty);1158 EXPECT_NE(Expr, nullptr);1159 EXPECT_EQ(Expr->getElement(1), 0U);1160 1161 IntegerType *Int8Ty = Type::getInt8Ty(Context);1162 Expr = createExpression(ConstantInt::get(Int8Ty, 100), Int8Ty);1163 EXPECT_NE(Expr, nullptr);1164 EXPECT_EQ(Expr->getElement(1), 100U);1165 1166 IntegerType *Int16Ty = Type::getInt16Ty(Context);1167 Expr = createExpression(ConstantInt::getSigned(Int16Ty, -50), Int16Ty);1168 EXPECT_NE(Expr, nullptr);1169 EXPECT_EQ(Expr->getElement(1), -50ULL);1170 1171 IntegerType *Int32Ty = Type::getInt32Ty(Context);1172 Expr = createExpression(ConstantInt::get(Int32Ty, 0x7FFFFFFF), Int32Ty);1173 EXPECT_NE(Expr, nullptr);1174 EXPECT_EQ(Expr->getElement(1), 0x7FFFFFFFU);1175 1176 IntegerType *Int64Ty = Type::getInt64Ty(Context);1177 Expr =1178 createExpression(ConstantInt::get(Int64Ty, 0x7FFFFFFFFFFFFFFF), Int64Ty);1179 EXPECT_NE(Expr, nullptr);1180 EXPECT_EQ(Expr->getElement(1), 0x7FFFFFFFFFFFFFFFU);1181 1182 IntegerType *Int128Ty = Type::getInt128Ty(Context);1183 Expr = createExpression(ConstantInt::get(Int128Ty, 0x7FFFFFFFFFFFFFFF),1184 Int128Ty);1185 EXPECT_NE(Expr, nullptr);1186 EXPECT_EQ(Expr->getElement(1), 0x7FFFFFFFFFFFFFFFU);1187 1188 GlobalVariable *String =1189 IRBuilder<>(Context).CreateGlobalString("hello", "hello", 0, &M);1190 Expr = createExpression(ConstantExpr::getPtrToInt(String, Int32Ty), Int32Ty);1191 EXPECT_EQ(Expr, nullptr);1192 1193 // Float.1194 Type *FloatTy = Type::getFloatTy(Context);1195 Expr = createExpression(ConstantFP::get(FloatTy, 5.55), FloatTy);1196 EXPECT_NE(Expr, nullptr);1197 EXPECT_EQ(Expr->getElement(1), 1085381018U);1198 1199 // Double.1200 Type *DoubleTy = Type::getDoubleTy(Context);1201 Expr = createExpression(ConstantFP::get(DoubleTy, -5.55), DoubleTy);1202 EXPECT_NE(Expr, nullptr);1203 EXPECT_EQ(Expr->getElement(1), 13841306799765140275U);1204 1205 // Half.1206 Type *HalfTy = Type::getHalfTy(Context);1207 Expr = createExpression(ConstantFP::get(HalfTy, 5.55), HalfTy);1208 EXPECT_NE(Expr, nullptr);1209 EXPECT_EQ(Expr->getElement(1), 17805U);1210 1211 // BFloat.1212 Type *BFloatTy = Type::getBFloatTy(Context);1213 Expr = createExpression(ConstantFP::get(BFloatTy, -5.55), BFloatTy);1214 EXPECT_NE(Expr, nullptr);1215 EXPECT_EQ(Expr->getElement(1), 49330U);1216 1217 // Pointer.1218 PointerType *PtrTy = PointerType::get(Context, 0);1219 Expr = createExpression(ConstantPointerNull::get(PtrTy), PtrTy);1220 EXPECT_NE(Expr, nullptr);1221 EXPECT_EQ(Expr->getElement(1), 0U);1222 1223 ConstantInt *K1 = ConstantInt::get(Type::getInt32Ty(Context), 1234);1224 Expr = createExpression(ConstantExpr::getIntToPtr(K1, PtrTy), PtrTy);1225 EXPECT_NE(Expr, nullptr);1226 EXPECT_EQ(Expr->getElement(1), 1234U);1227 1228 ConstantInt *K2 = ConstantInt::get(Type::getInt64Ty(Context), 5678);1229 Expr = createExpression(ConstantExpr::getIntToPtr(K2, PtrTy), PtrTy);1230 EXPECT_NE(Expr, nullptr);1231 EXPECT_EQ(Expr->getElement(1), 5678U);1232 1233 Type *FP128Ty = Type::getFP128Ty(Context);1234 Expr = createExpression(ConstantFP::get(FP128Ty, 32), FP128Ty);1235 EXPECT_EQ(Expr, nullptr);1236 1237 Type *X86_FP80Ty = Type::getX86_FP80Ty(Context);1238 Expr = createExpression(ConstantFP::get(X86_FP80Ty, 32), X86_FP80Ty);1239 EXPECT_EQ(Expr, nullptr);1240 1241 Type *PPC_FP128Ty = Type::getPPC_FP128Ty(Context);1242 Expr = createExpression(ConstantFP::get(PPC_FP128Ty, 32), PPC_FP128Ty);1243 EXPECT_EQ(Expr, nullptr);1244}1245 1246TEST(Local, ReplaceDbgVariableRecord) {1247 LLVMContext C;1248 1249 // Test that RAUW also replaces the operands of DbgVariableRecord objects,1250 // i.e. non-instruction stored debugging information.1251 std::unique_ptr<Module> M = parseIR(C,1252 R"(1253 declare void @llvm.dbg.value(metadata, metadata, metadata)1254 define void @f(i32 %a) !dbg !8 {1255 entry:1256 %foo = add i32 %a, 1, !dbg !131257 %bar = add i32 %foo, 0, !dbg !131258 #dbg_value(i32 %bar, !11, !DIExpression(), !13)1259 ret void, !dbg !141260 }1261 !llvm.dbg.cu = !{!0}1262 !llvm.module.flags = !{!3, !4}1263 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)1264 !1 = !DIFile(filename: "t2.c", directory: "foo")1265 !2 = !{}1266 !3 = !{i32 2, !"Dwarf Version", i32 4}1267 !4 = !{i32 2, !"Debug Info Version", i32 3}1268 !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)1269 !9 = !DISubroutineType(types: !10)1270 !10 = !{null}1271 !11 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !12)1272 !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)1273 !13 = !DILocation(line: 2, column: 7, scope: !8)1274 !14 = !DILocation(line: 3, column: 1, scope: !8)1275 )");1276 auto *GV = M->getNamedValue("f");1277 ASSERT_TRUE(GV);1278 auto *F = dyn_cast<Function>(GV);1279 ASSERT_TRUE(F);1280 BasicBlock::iterator It = F->front().begin();1281 Instruction *FooInst = &*It;1282 It = std::next(It);1283 Instruction *BarInst = &*It;1284 It = std::next(It);1285 Instruction *RetInst = &*It;1286 1287 // There should be a DbgVariableRecord on the return.1288 auto Range = RetInst->getDbgRecordRange();1289 ASSERT_FALSE(Range.empty());1290 DbgVariableRecord *DVR = dyn_cast<DbgVariableRecord>(&*Range.begin());1291 ASSERT_NE(DVR, nullptr);1292 1293 // DVR should originally refer to %bar,1294 EXPECT_EQ(DVR->getVariableLocationOp(0), BarInst);1295 1296 // Now try to replace the computation of %bar with %foo -- this should cause1297 // the DbgVariableRecord's to have it's operand updated beneath it.1298 BarInst->replaceAllUsesWith(FooInst);1299 // Check DVR now points at %foo.1300 EXPECT_EQ(DVR->getVariableLocationOp(0), FooInst);1301 1302 // Teardown.1303 RetInst->DebugMarker->eraseFromParent();1304}1305