From c0c8e7448a47692d4736e7952fbec3fd62d4349c Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Wed, 8 Apr 2020 10:27:17 -0700 Subject: [PATCH] Add pass to strip debug info from MIR Summary: Removes: * All LLVM-IR level debug info using StripDebugInfo() * All debugify metadata * 'Debug Info Version' module flag * All (valid*) DEBUG_VALUE MachineInstrs * All DebugLocs from MachineInstrs This is a more complete solution than the previous MIRPrinter option that just causes it to neglect to print debug-locations. * The qualifier 'valid' is used here because AArch64 emits an invalid one and tests depend on it Reviewers: vsk, aprantl, bogner Subscribers: mgorny, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77747 --- include/llvm/CodeGen/Passes.h | 3 + include/llvm/InitializePasses.h | 1 + lib/CodeGen/CMakeLists.txt | 1 + lib/CodeGen/CodeGen.cpp | 1 + lib/CodeGen/MachineStripDebug.cpp | 112 ++++++++++++++++++ .../CodeGen/Generic/MIRDebugify/locations.mir | 7 ++ test/CodeGen/Generic/MIRStripDebug/all.mir | 73 ++++++++++++ .../MIRStripDebug/multiple-moduleflags.mir | 75 ++++++++++++ 8 files changed, 273 insertions(+) create mode 100644 lib/CodeGen/MachineStripDebug.cpp create mode 100644 test/CodeGen/Generic/MIRStripDebug/all.mir create mode 100644 test/CodeGen/Generic/MIRStripDebug/multiple-moduleflags.mir diff --git a/include/llvm/CodeGen/Passes.h b/include/llvm/CodeGen/Passes.h index 7627baa2f05..315cbf6ad09 100644 --- a/include/llvm/CodeGen/Passes.h +++ b/include/llvm/CodeGen/Passes.h @@ -475,6 +475,9 @@ namespace llvm { /// Creates MIR Debugify pass. \see MachineDebugify.cpp ModulePass *createDebugifyMachineModulePass(); + + /// Creates MIR Strip Debug pass. \see MachineStripDebug.cpp + ModulePass *createStripDebugMachineModulePass(); } // End llvm namespace #endif diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h index a71079fdc2b..21adf2e70db 100644 --- a/include/llvm/InitializePasses.h +++ b/include/llvm/InitializePasses.h @@ -401,6 +401,7 @@ void initializeStraightLineStrengthReducePass(PassRegistry&); void initializeStripDeadDebugInfoPass(PassRegistry&); void initializeStripDeadPrototypesLegacyPassPass(PassRegistry&); void initializeStripDebugDeclarePass(PassRegistry&); +void initializeStripDebugMachineModulePass(PassRegistry &); void initializeStripGCRelocatesPass(PassRegistry&); void initializeStripNonDebugSymbolsPass(PassRegistry&); void initializeStripNonLineTableDebugInfoPass(PassRegistry&); diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 38187897fb6..ad7458fb903 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -98,6 +98,7 @@ add_llvm_component_library(LLVMCodeGen MachineSink.cpp MachineSizeOpts.cpp MachineSSAUpdater.cpp + MachineStripDebug.cpp MachineTraceMetrics.cpp MachineVerifier.cpp ModuloSchedule.cpp diff --git a/lib/CodeGen/CodeGen.cpp b/lib/CodeGen/CodeGen.cpp index f3b596a8f2b..69f6a7d6cb9 100644 --- a/lib/CodeGen/CodeGen.cpp +++ b/lib/CodeGen/CodeGen.cpp @@ -105,6 +105,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) { initializeStackMapLivenessPass(Registry); initializeStackProtectorPass(Registry); initializeStackSlotColoringPass(Registry); + initializeStripDebugMachineModulePass(Registry); initializeTailDuplicatePass(Registry); initializeTargetPassConfigPass(Registry); initializeTwoAddressInstructionPassPass(Registry); diff --git a/lib/CodeGen/MachineStripDebug.cpp b/lib/CodeGen/MachineStripDebug.cpp new file mode 100644 index 00000000000..012971874cb --- /dev/null +++ b/lib/CodeGen/MachineStripDebug.cpp @@ -0,0 +1,112 @@ +//===- MachineStripDebug.cpp - Strip debug info ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file This removes debug info from everything. It can be used to ensure +/// tests can be debugified without affecting the output MIR. +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/InitializePasses.h" + +#define DEBUG_TYPE "mir-strip-debug" + +using namespace llvm; + +namespace { + +struct StripDebugMachineModule : public ModulePass { + bool runOnModule(Module &M) override { + MachineModuleInfo &MMI = + getAnalysis().getMMI(); + + bool Changed = false; + for (Function &F : M.functions()) { + MachineFunction &MF = MMI.getOrCreateMachineFunction(F); + for (MachineBasicBlock &MBB : MF) { + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); + I != E;) { + if (I->isDebugInstr()) { + // FIXME: We should remove all of them. However, AArch64 emits an + // invalid `DBG_VALUE $lr` with only one operand instead of + // the usual three and has a test that depends on it's + // preservation. Preserve it for now. + if (I->getNumOperands() > 1) { + LLVM_DEBUG(dbgs() << "Removing debug instruction " << *I); + I = MBB.erase(I); + Changed |= true; + continue; + } + } + if (I->getDebugLoc()) { + LLVM_DEBUG(dbgs() << "Removing location " << *I); + I->setDebugLoc(DebugLoc()); + Changed |= true; + ++I; + continue; + } + LLVM_DEBUG(dbgs() << "Keeping " << *I); + ++I; + } + } + } + + Changed |= StripDebugInfo(M); + + NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify"); + if (NMD) { + NMD->eraseFromParent(); + Changed |= true; + } + + NMD = M.getModuleFlagsMetadata(); + if (NMD) { + // There must be an easier way to remove an operand from a NamedMDNode. + SmallVector Flags; + for (MDNode *Flag : NMD->operands()) + Flags.push_back(Flag); + NMD->clearOperands(); + for (MDNode *Flag : Flags) { + MDString *Key = dyn_cast_or_null(Flag->getOperand(1)); + if (Key->getString() == "Debug Info Version") { + Changed |= true; + continue; + } + NMD->addOperand(Flag); + } + // If we left it empty we might as well remove it. + if (NMD->getNumOperands() == 0) + NMD->eraseFromParent(); + } + + return Changed; + } + + StripDebugMachineModule() : ModulePass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addPreserved(); + } + + static char ID; // Pass identification. +}; +char StripDebugMachineModule::ID = 0; + +} // end anonymous namespace + +INITIALIZE_PASS_BEGIN(StripDebugMachineModule, DEBUG_TYPE, + "Machine Strip Debug Module", false, false) +INITIALIZE_PASS_END(StripDebugMachineModule, DEBUG_TYPE, + "Machine Strip Debug Module", false, false) + +ModulePass *createStripDebugMachineModulePass() { + return new StripDebugMachineModule(); +} diff --git a/test/CodeGen/Generic/MIRDebugify/locations.mir b/test/CodeGen/Generic/MIRDebugify/locations.mir index 17aab12a6fe..cd51432ad96 100644 --- a/test/CodeGen/Generic/MIRDebugify/locations.mir +++ b/test/CodeGen/Generic/MIRDebugify/locations.mir @@ -1,5 +1,6 @@ # RUN: llc -run-pass=mir-debugify -o - %s | FileCheck --check-prefixes=ALL,VALUE %s # RUN: llc -run-pass=mir-debugify -debugify-level=locations -o - %s | FileCheck --check-prefixes=ALL --implicit-check-not=dbg.value %s +# RUN: llc -run-pass=mir-debugify,mir-strip-debug,mir-debugify -o - %s | FileCheck --check-prefixes=ALL,VALUE %s --- | ; ModuleID = 'loc-only.ll' source_filename = "loc-only.ll" @@ -16,6 +17,12 @@ ret i32 %sub } + ; CHECK: !llvm.dbg.cu = !{!0} + ; CHECK: !llvm.debugify = + ; CHECK: !llvm.module.flags = !{![[VERSION:[0-9]+]]} + ; CHECK: !0 = distinct !DICompileUnit( + ; CHECK: ![[VERSION]] = !{i32 2, !"Debug Info Version", i32 3} + ... --- name: test diff --git a/test/CodeGen/Generic/MIRStripDebug/all.mir b/test/CodeGen/Generic/MIRStripDebug/all.mir new file mode 100644 index 00000000000..7eaf6095379 --- /dev/null +++ b/test/CodeGen/Generic/MIRStripDebug/all.mir @@ -0,0 +1,73 @@ +# RUN: llc -run-pass=mir-strip-debug -o - %s | FileCheck %s +# RUN: llc -run-pass=mir-strip-debug,mir-debugify,mir-strip-debug -o - %s | FileCheck %s +--- | + ; ModuleID = 'loc-only.ll' + source_filename = "loc-only.ll" + + define i32 @test(i32 %a, i32 %b) !dbg !6 { + %add = add i32 %a, 2, !dbg !12 + call void @llvm.dbg.value(metadata i32 %add, metadata !9, metadata !DIExpression()), !dbg !12 + %sub = sub i32 %add, %b, !dbg !13 + call void @llvm.dbg.value(metadata i32 %sub, metadata !11, metadata !DIExpression()), !dbg !13 + ret i32 %sub, !dbg !14 + } + ; CHECK-LABEL: define i32 @test(i32 %a, i32 %b) { + ; CHECK-NEXT: %add = add i32 %a, 2 + ; CHECK-NEXT: %sub = sub i32 %add, %b + ; CHECK-NEXT: ret i32 %sub + ; CHECK-NEXT: } + + ; Function Attrs: nounwind readnone speculatable willreturn + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #1 + + attributes #0 = { nounwind readnone speculatable willreturn } + attributes #1 = { nounwind } + + !llvm.dbg.cu = !{!0} + ; CHECK-NOT: !llvm.dbg.cu + !llvm.debugify = !{!3, !4} + ; CHECK-NOT: !llvm.debugify + !llvm.module.flags = !{!5} + ; CHECK-NOT: !llvm.module.flags + + ; CHECK-NOT: !DI + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "", directory: "/") + !2 = !{} + !3 = !{i32 3} + !4 = !{i32 2} + !5 = !{i32 2, !"Debug Info Version", i32 3} + !6 = distinct !DISubprogram(name: "test", linkageName: "test", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) + !7 = !DISubroutineType(types: !2) + !8 = !{!9, !11} + !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) + !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) + !11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !10) + !12 = !DILocation(line: 1, column: 1, scope: !6) + !13 = !DILocation(line: 2, column: 1, scope: !6) + !14 = !DILocation(line: 3, column: 1, scope: !6) + +... +--- +name: test +body: | + bb.1 (%ir-block.0): + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 0, scope: !6) + %3:_(s32) = G_ADD %0, %2, debug-location !12 + DBG_VALUE %3(s32), $noreg, !9, !DIExpression(), debug-location !12 + %4:_(s32) = G_SUB %3, %1, debug-location !13 + DBG_VALUE %4(s32), $noreg, !11, !DIExpression(), debug-location !13 + + ; CHECK-LABEL: body: + ; CHECK-NEXT: bb + ; CHECK-NEXT: %0:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %1:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %2:_(s32) = G_CONSTANT i32 2{{$}} + ; CHECK-NEXT: %3:_(s32) = G_ADD %0, %2{{$}} + ; CHECK-NEXT: %4:_(s32) = G_SUB %3, %1{{$}} +... diff --git a/test/CodeGen/Generic/MIRStripDebug/multiple-moduleflags.mir b/test/CodeGen/Generic/MIRStripDebug/multiple-moduleflags.mir new file mode 100644 index 00000000000..2a62cd4bb87 --- /dev/null +++ b/test/CodeGen/Generic/MIRStripDebug/multiple-moduleflags.mir @@ -0,0 +1,75 @@ +# RUN: llc -run-pass=mir-strip-debug -o - %s | FileCheck %s +# RUN: llc -run-pass=mir-strip-debug,mir-debugify,mir-strip-debug -o - %s | FileCheck %s +--- | + ; ModuleID = 'loc-only.ll' + source_filename = "loc-only.ll" + + define i32 @test(i32 %a, i32 %b) !dbg !6 { + %add = add i32 %a, 2, !dbg !12 + call void @llvm.dbg.value(metadata i32 %add, metadata !9, metadata !DIExpression()), !dbg !12 + %sub = sub i32 %add, %b, !dbg !13 + call void @llvm.dbg.value(metadata i32 %sub, metadata !11, metadata !DIExpression()), !dbg !13 + ret i32 %sub, !dbg !14 + } + ; CHECK-LABEL: define i32 @test(i32 %a, i32 %b) { + ; CHECK-NEXT: %add = add i32 %a, 2 + ; CHECK-NEXT: %sub = sub i32 %add, %b + ; CHECK-NEXT: ret i32 %sub + ; CHECK-NEXT: } + + ; Function Attrs: nounwind readnone speculatable willreturn + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #1 + + attributes #0 = { nounwind readnone speculatable willreturn } + attributes #1 = { nounwind } + + !llvm.dbg.cu = !{!0} + ; CHECK-NOT: !llvm.dbg.cu + !llvm.debugify = !{!3, !4} + ; CHECK-NOT: !llvm.debugify + !llvm.module.flags = !{!5, !15} + ; CHECK: !llvm.module.flags = !{!0} + ; CHECK: !0 = !{i32 2, !"Another Flag", i32 3} + + ; CHECK-NOT: !DI + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "", directory: "/") + !2 = !{} + !3 = !{i32 3} + !4 = !{i32 2} + !5 = !{i32 2, !"Debug Info Version", i32 3} + !6 = distinct !DISubprogram(name: "test", linkageName: "test", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) + !7 = !DISubroutineType(types: !2) + !8 = !{!9, !11} + !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) + !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) + !11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !10) + !12 = !DILocation(line: 1, column: 1, scope: !6) + !13 = !DILocation(line: 2, column: 1, scope: !6) + !14 = !DILocation(line: 3, column: 1, scope: !6) + !15 = !{i32 2, !"Another Flag", i32 3} + +... +--- +name: test +body: | + bb.1 (%ir-block.0): + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 0, scope: !6) + %3:_(s32) = G_ADD %0, %2, debug-location !12 + DBG_VALUE %3(s32), $noreg, !9, !DIExpression(), debug-location !12 + %4:_(s32) = G_SUB %3, %1, debug-location !13 + DBG_VALUE %4(s32), $noreg, !11, !DIExpression(), debug-location !13 + + ; CHECK-LABEL: body: + ; CHECK-NEXT: bb + ; CHECK-NEXT: %0:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %1:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %2:_(s32) = G_CONSTANT i32 2{{$}} + ; CHECK-NEXT: %3:_(s32) = G_ADD %0, %2{{$}} + ; CHECK-NEXT: %4:_(s32) = G_SUB %3, %1{{$}} +...