Index: llvm/include/llvm/IR/Instruction.h =================================================================== --- llvm/include/llvm/IR/Instruction.h +++ llvm/include/llvm/IR/Instruction.h @@ -352,7 +352,13 @@ bool extractProfTotalWeight(uint64_t &TotalVal) const; /// Set the debug location information for this instruction. - void setDebugLoc(DebugLoc Loc) { DbgLoc = std::move(Loc); } + void setDebugLoc(DebugLoc Loc) { + if (!Loc || (Loc.getLine() == 0 && Loc.getCol() == 0)) + droppedLocation = true; + else + droppedLocation = false; + DbgLoc = std::move(Loc); + } /// Return the debug location for this node as a DebugLoc. const DebugLoc &getDebugLoc() const { return DbgLoc; } @@ -540,7 +546,9 @@ /// are not modified. void mergeDIAssignID(ArrayRef SourceInstructions); + bool isLocationDropped() const { return droppedLocation; } private: + bool droppedLocation = false; // These are all implemented in Metadata.cpp. MDNode *getMetadataImpl(unsigned KindID) const; MDNode *getMetadataImpl(StringRef Kind) const; Index: llvm/lib/IR/DebugInfo.cpp =================================================================== --- llvm/lib/IR/DebugInfo.cpp +++ llvm/lib/IR/DebugInfo.cpp @@ -917,6 +917,8 @@ void Instruction::updateLocationAfterHoist() { dropLocation(); } void Instruction::dropLocation() { + // Mark this Instructions location as intentionally dropped. + droppedLocation = true; const DebugLoc &DL = getDebugLoc(); if (!DL) return; Index: llvm/lib/Transforms/Utils/Debugify.cpp =================================================================== --- llvm/lib/Transforms/Utils/Debugify.cpp +++ llvm/lib/Transforms/Utils/Debugify.cpp @@ -433,6 +433,10 @@ if (WeakInstrPtr != InstToDelete.end() && !WeakInstrPtr->second) continue; + // Skip instruction if its DebugLoc is intentionally dropped. + if (Instr->isLocationDropped()) + continue; + auto FnName = Instr->getFunction()->getName(); auto BB = Instr->getParent(); auto BBName = BB->hasName() ? BB->getName() : "no-name"; @@ -746,6 +750,10 @@ continue; } + // Skip instruction if its DebugLoc is intentionally dropped. + if (!DL && I.isLocationDropped()) + continue; + if (!isa(&I) && !DL) { dbg() << "WARNING: Instruction with empty DebugLoc in function "; dbg() << F.getName() << " --"; Index: llvm/test/DebugInfo/Generic/licm-hoist-debug-loc.ll =================================================================== --- llvm/test/DebugInfo/Generic/licm-hoist-debug-loc.ll +++ llvm/test/DebugInfo/Generic/licm-hoist-debug-loc.ll @@ -21,6 +21,9 @@ ; CHECK: getelementptr{{.*}}%p.addr, i64 4{{$}} ; CHECK: for.body: ; +; RUN: opt < %s -S -verify-debuginfo-preserve -passes=licm 2>&1 | FileCheck %s --check-prefix=DEBUGIFY +; DEBUGIFY: CheckModuleDebugify (original debuginfo): PASS +; ; ModuleID = 't.ll' source_filename = "test.c" Index: llvm/test/DebugInfo/debugify.ll =================================================================== --- llvm/test/DebugInfo/debugify.ll +++ llvm/test/DebugInfo/debugify.ll @@ -88,15 +88,20 @@ ; CHECK-REPEAT: ModuleDebugify: Skipping module with debug info ; --- Failure case -; CHECK-WARN: WARNING: Instruction with empty DebugLoc in function foo -- ret void -; CHECK-WARN: WARNING: Instruction with empty DebugLoc in function bar -- call void @foo() -; CHECK-WARN: WARNING: Instruction with empty DebugLoc in function bar -- {{.*}} add i32 0, 1 -; CHECK-WARN: WARNING: Instruction with empty DebugLoc in function bar -- ret i32 0 +;; Strip (debug info) is explicit removal of debug-loc, therefore, not a debug-loc drop. +; CHECK-WARN-NOT: WARNING: Instruction with empty DebugLoc in function foo -- ret void +; CHECK-WARN-NOT: WARNING: Instruction with empty DebugLoc in function bar -- call void @foo() +; CHECK-WARN-NOT: WARNING: Instruction with empty DebugLoc in function bar -- {{.*}} add i32 0, 1 +; CHECK-WARN-NOT: WARNING: Instruction with empty DebugLoc in function bar -- ret i32 0 ; CHECK-WARN: WARNING: Missing line 1 ; CHECK-WARN: WARNING: Missing line 2 ; CHECK-WARN: WARNING: Missing line 3 ; CHECK-WARN: WARNING: Missing line 4 +; CHECK-WARN: WARNING: Missing line 5 +; CHECK-WARN: WARNING: Missing line 6 ; CHECK-WARN: WARNING: Missing variable 1 +; CHECK-WARN: WARNING: Missing variable 2 +; CHECK-WARN: WARNING: Missing variable 3 ; CHECK-WARN: CheckModuleDebugify: PASS ; PASS: CheckModuleDebugify: PASS Index: llvm/unittests/IR/InstructionsTest.cpp =================================================================== --- llvm/unittests/IR/InstructionsTest.cpp +++ llvm/unittests/IR/InstructionsTest.cpp @@ -752,7 +752,7 @@ AttrBuilder AB(C); AB.addAttribute(Attribute::Cold); Call->setAttributes(AttributeList::get(C, AttributeList::FunctionIndex, AB)); - Call->setDebugLoc(DebugLoc(MDNode::get(C, std::nullopt))); + Call->setDebugLoc(DebugLoc()); OperandBundleDef NewBundle("after", ConstantInt::get(Int32Ty, 7)); std::unique_ptr Clone(CallInst::Create(Call.get(), NewBundle)); @@ -782,7 +782,7 @@ AB.addAttribute(Attribute::Cold); Invoke->setAttributes( AttributeList::get(C, AttributeList::FunctionIndex, AB)); - Invoke->setDebugLoc(DebugLoc(MDNode::get(C, std::nullopt))); + Invoke->setDebugLoc(DebugLoc()); OperandBundleDef NewBundle("after", ConstantInt::get(Int32Ty, 7)); std::unique_ptr Clone( Index: llvm/unittests/Transforms/Utils/DebugifyTest.cpp =================================================================== --- llvm/unittests/Transforms/Utils/DebugifyTest.cpp +++ llvm/unittests/Transforms/Utils/DebugifyTest.cpp @@ -13,6 +13,8 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Transforms/Utils/Debugify.h" +#include "llvm/IR/IRBuilder.h" + #include "gtest/gtest.h" using namespace llvm; @@ -27,6 +29,7 @@ namespace llvm { void initializeDebugInfoDropPass(PassRegistry &); +void initializeDebugLocDropPass(PassRegistry &); void initializeDebugInfoDummyAnalysisPass(PassRegistry &); namespace { @@ -51,6 +54,27 @@ DebugInfoDrop() : FunctionPass(ID) {} }; +struct DebugLocDrop : public FunctionPass { + static char ID; + bool runOnFunction(Function &F) override { + BasicBlock *BB = &*F.begin(); + Instruction* Instr = BB->getFirstNonPHIOrDbg(); + Instr->setDebugLoc(DebugLoc()); + Instruction *I = Instr->clone(); + I->insertInto(BB, BB->begin()); + Instr->replaceAllUsesWith(I); + Instr->eraseFromParent(); + + return false; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + } + + DebugLocDrop() : FunctionPass(ID) {} +}; + struct DebugValueDrop : public FunctionPass { static char ID; bool runOnFunction(Function &F) override { @@ -91,6 +115,7 @@ } char DebugInfoDrop::ID = 0; +char DebugLocDrop::ID = 0; char DebugValueDrop::ID = 0; char DebugInfoDummyAnalysis::ID = 0; @@ -141,6 +166,56 @@ std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL"; EXPECT_TRUE(StdOut.find(ErrorForSP) != std::string::npos); + // explicit removal is not a drop + EXPECT_TRUE(StdOut.find(WarningForLoc) == std::string::npos); + EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos); +} + +TEST(DebugLocDrop, DropOriginalDebugLoc) { + LLVMContext C; + std::unique_ptr M = parseIR(C, R"( + define i16 @f(i16 %a) !dbg !6 { + %b = add i16 %a, 1, !dbg !11 + ret i16 0, !dbg !11 + } + declare void @llvm.dbg.value(metadata, metadata, metadata) + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!5} + + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "t.ll", directory: "/") + !2 = !{} + !5 = !{i32 2, !"Debug Info Version", i32 3} + !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) + !7 = !DISubroutineType(types: !2) + !8 = !{!9} + !9 = !DILocalVariable(name: "b", scope: !6, file: !1, line: 1, type: !10) + !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) + !11 = !DILocation(line: 1, column: 1, scope: !6) + )"); + + DebugLocDrop *P = new DebugLocDrop(); + + + DebugInfoPerPass DIBeforePass; + DebugifyCustomPassManager Passes; + Passes.setDebugInfoBeforePass(DIBeforePass); + Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "", + &(Passes.getDebugInfoPerPass()))); + Passes.add(P); + Passes.add(createCheckDebugifyModulePass(false, "", nullptr, + DebugifyMode::OriginalDebugInfo, + &(Passes.getDebugInfoPerPass()))); + + testing::internal::CaptureStderr(); + Passes.run(*M); + + std::string StdOut = testing::internal::GetCapturedStderr(); + + std::string WarningForLoc = "WARNING: did not generate DILocation"; + std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL"; + EXPECT_TRUE(StdOut.find(WarningForLoc) != std::string::npos); EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos); } @@ -258,6 +333,11 @@ INITIALIZE_PASS_END(DebugInfoDrop, "debuginfodroppass", "debuginfodroppass", false, false) +INITIALIZE_PASS_BEGIN(DebugLocDrop, "debuglocdroppass", "debuglocdroppass", + false, false) +INITIALIZE_PASS_END(DebugLocDrop, "debuglocdroppass", "debuglocdroppass", false, + false) + INITIALIZE_PASS_BEGIN(DebugInfoDummyAnalysis, "debuginfodummyanalysispass", "debuginfodummyanalysispass", false, false) INITIALIZE_PASS_END(DebugInfoDummyAnalysis, "debuginfodummyanalysispass",