From 8852589f9d91978d0b59af97453932dcfd82f154 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 30 Apr 2020 13:22:22 -0700 Subject: [PATCH] [DebugInfo] Update loop metadata in stripNonLineTableDebugInfo Summary: Have stripNonLineTableDebugInfo() attach updated !llvm.loop metadata to an instruction (instead of updating and then discarding the metadata). This fixes "!dbg attachment points at wrong subprogram for function" errors seen while archiving an iOS app. It would be nice -- as a follow-up -- to catch this issue earlier, perhaps by modifying the verifier to constrain where DILocations are allowed. Any alternative suggestions appreciated. rdar://61982466 Reviewers: aprantl, dsanders Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D79200 (cherry picked from commit 9350792c6284560de5c7dff249601486bcbabe48) --- llvm/lib/IR/DebugInfo.cpp | 13 ++---- llvm/unittests/IR/DebugInfoTest.cpp | 66 +++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index 2175ffe77cfd8..2493b272f91a2 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -675,15 +675,10 @@ bool llvm::stripNonLineTableDebugInfo(Module &M) { if (I.getDebugLoc() != DebugLoc()) I.setDebugLoc(remapDebugLoc(I.getDebugLoc())); - // Remap DILocations in untyped MDNodes (e.g., llvm.loop). - SmallVector, 2> MDs; - I.getAllMetadata(MDs); - for (auto Attachment : MDs) - if (auto *T = dyn_cast_or_null(Attachment.second)) - for (unsigned N = 0; N < T->getNumOperands(); ++N) - if (auto *Loc = dyn_cast_or_null(T->getOperand(N))) - if (Loc != DebugLoc()) - T->replaceOperandWith(N, remapDebugLoc(Loc)); + // Remap DILocations in llvm.loop attachments. + updateLoopMetadataDebugLocations(I, [&](const DILocation &Loc) { + return remapDebugLoc(&Loc).get(); + }); } } } diff --git a/llvm/unittests/IR/DebugInfoTest.cpp b/llvm/unittests/IR/DebugInfoTest.cpp index 93247908d8a77..c7ec3a9333023 100644 --- a/llvm/unittests/IR/DebugInfoTest.cpp +++ b/llvm/unittests/IR/DebugInfoTest.cpp @@ -6,11 +6,25 @@ // //===----------------------------------------------------------------------===// +#include "llvm/IR/DebugInfo.h" +#include "llvm/AsmParser/Parser.h" #include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" using namespace llvm; +static std::unique_ptr parseIR(LLVMContext &C, const char *IR) { + SMDiagnostic Err; + std::unique_ptr Mod = parseAssemblyString(IR, Err, C); + if (!Mod) + Err.print("DebugInfoTest", errs()); + return Mod; +} + namespace { TEST(DINodeTest, getFlag) { @@ -79,4 +93,56 @@ TEST(DINodeTest, splitFlags) { #undef CHECK_SPLIT } +TEST(StripTest, LoopMetadata) { + LLVMContext C; + std::unique_ptr M = parseIR(C, R"( + define void @f() !dbg !5 { + ret void, !dbg !10, !llvm.loop !11 + } + + !llvm.dbg.cu = !{!0} + !llvm.debugify = !{!3, !3} + !llvm.module.flags = !{!4} + + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "loop.ll", directory: "/") + !2 = !{} + !3 = !{i32 1} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !7) + !6 = !DISubroutineType(types: !2) + !7 = !{!8} + !8 = !DILocalVariable(name: "1", scope: !5, file: !1, line: 1, type: !9) + !9 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) + !10 = !DILocation(line: 1, column: 1, scope: !5) + !11 = distinct !{!11, !10, !10} +)"); + + // Look up the debug info emission kind for the CU via the loop metadata + // attached to the terminator. If, when stripping non-line table debug info, + // we update the terminator's metadata correctly, we should be able to + // observe the change in emission kind for the CU. + auto getEmissionKind = [&]() { + Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHI(); + MDNode *LoopMD = I.getMetadata(LLVMContext::MD_loop); + return cast(LoopMD->getOperand(1)) + ->getScope() + ->getSubprogram() + ->getUnit() + ->getEmissionKind(); + }; + + EXPECT_EQ(getEmissionKind(), DICompileUnit::FullDebug); + + bool Changed = stripNonLineTableDebugInfo(*M); + EXPECT_TRUE(Changed); + + EXPECT_EQ(getEmissionKind(), DICompileUnit::LineTablesOnly); + + bool BrokenDebugInfo = false; + bool HardError = verifyModule(*M, &errs(), &BrokenDebugInfo); + EXPECT_FALSE(HardError); + EXPECT_FALSE(BrokenDebugInfo); +} + } // end namespace