From 7323c4ef30da6dfc71b0e9c6dbf2ab8f69f48ef8 Mon Sep 17 00:00:00 2001 From: Shubham Sandeep Rastogi Date: Fri, 20 Dec 2024 10:08:54 -0800 Subject: [PATCH] Add a pass to collect dropped var stats for MIR (#120780) This patch uses the DroppedVariableStats class to add dropped variable statistics for MIR passes. Reland 1c082c9cd12efaa67a32c5da89a328c458ed51c5 (cherry picked from commit 3bf91ad2a9c75dd045961e45fdd830fd7b7a5455) --- .../llvm/CodeGen/DroppedVariableStatsMIR.h | 70 ++ .../llvm/CodeGen/MachineFunctionPass.h | 2 + llvm/lib/CodeGen/CMakeLists.txt | 1 + llvm/lib/CodeGen/DroppedVariableStatsMIR.cpp | 77 ++ llvm/lib/CodeGen/MachineFunctionPass.cpp | 15 +- llvm/unittests/CodeGen/CMakeLists.txt | 1 + .../CodeGen/DroppedVariableStatsMIRTest.cpp | 1052 +++++++++++++++++ 7 files changed, 1217 insertions(+), 1 deletion(-) create mode 100644 llvm/include/llvm/CodeGen/DroppedVariableStatsMIR.h create mode 100644 llvm/lib/CodeGen/DroppedVariableStatsMIR.cpp create mode 100644 llvm/unittests/CodeGen/DroppedVariableStatsMIRTest.cpp diff --git a/llvm/include/llvm/CodeGen/DroppedVariableStatsMIR.h b/llvm/include/llvm/CodeGen/DroppedVariableStatsMIR.h new file mode 100644 index 0000000000000..462bbb8b404bc --- /dev/null +++ b/llvm/include/llvm/CodeGen/DroppedVariableStatsMIR.h @@ -0,0 +1,70 @@ +///===- DroppedVariableStatsMIR.h - Opt Diagnostics -*- C++ -*-------------===// +/// +/// 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 +/// Dropped Variable Statistics for Debug Information. Reports any number +/// of DBG_VALUEs that get dropped due to an optimization pass. +/// +///===---------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_DROPPEDVARIABLESTATSMIR_H +#define LLVM_CODEGEN_DROPPEDVARIABLESTATSMIR_H + +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/Passes/DroppedVariableStats.h" + +namespace llvm { + +/// A class to collect and print dropped debug information due to MIR +/// optimization passes. After every MIR pass is run, it will print how many +/// #DBG_VALUEs were dropped due to that pass. +class DroppedVariableStatsMIR : public DroppedVariableStats { +public: + DroppedVariableStatsMIR() : llvm::DroppedVariableStats(false) {} + + void runBeforePass(StringRef PassID, MachineFunction *MF) { + if (PassID == "Debug Variable Analysis") + return; + setup(); + return runOnMachineFunction(MF, true); + } + + void runAfterPass(StringRef PassID, MachineFunction *MF) { + if (PassID == "Debug Variable Analysis") + return; + runOnMachineFunction(MF, false); + calculateDroppedVarStatsOnMachineFunction(MF, PassID, MF->getName().str()); + cleanup(); + } + +private: + const MachineFunction *MFunc; + /// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or + /// after a pass has run to facilitate dropped variable calculation for an + /// llvm::MachineFunction. + void runOnMachineFunction(const MachineFunction *MF, bool Before); + /// Iterate over all Instructions in a MachineFunction and report any dropped + /// debug information. + void calculateDroppedVarStatsOnMachineFunction(const MachineFunction *MF, + StringRef PassID, + StringRef FuncOrModName); + /// Override base class method to run on an llvm::MachineFunction + /// specifically. + virtual void + visitEveryInstruction(unsigned &DroppedCount, + DenseMap &InlinedAtsMap, + VarID Var) override; + /// Override base class method to run on DBG_VALUEs specifically. + virtual void visitEveryDebugRecord( + DenseSet &VarIDSet, + DenseMap> &InlinedAtsMap, + StringRef FuncName, bool Before) override; +}; + +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/CodeGen/MachineFunctionPass.h b/llvm/include/llvm/CodeGen/MachineFunctionPass.h index caaf22c2139e3..8d7e4192003d2 100644 --- a/llvm/include/llvm/CodeGen/MachineFunctionPass.h +++ b/llvm/include/llvm/CodeGen/MachineFunctionPass.h @@ -18,6 +18,7 @@ #ifndef LLVM_CODEGEN_MACHINEFUNCTIONPASS_H #define LLVM_CODEGEN_MACHINEFUNCTIONPASS_H +#include "llvm/CodeGen/DroppedVariableStatsMIR.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/Pass.h" @@ -67,6 +68,7 @@ class MachineFunctionPass : public FunctionPass { MachineFunctionProperties RequiredProperties; MachineFunctionProperties SetProperties; MachineFunctionProperties ClearedProperties; + DroppedVariableStatsMIR DroppedVarStatsMF; /// createPrinterPass - Get a machine function printer pass. Pass *createPrinterPass(raw_ostream &O, diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt index 213407efaf7a3..2ea213b57f15c 100644 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -50,6 +50,7 @@ add_llvm_component_library(LLVMCodeGen DeadMachineInstructionElim.cpp DetectDeadLanes.cpp DFAPacketizer.cpp + DroppedVariableStatsMIR.cpp DwarfEHPrepare.cpp EarlyIfConversion.cpp EdgeBundles.cpp diff --git a/llvm/lib/CodeGen/DroppedVariableStatsMIR.cpp b/llvm/lib/CodeGen/DroppedVariableStatsMIR.cpp new file mode 100644 index 0000000000000..4379db8b16679 --- /dev/null +++ b/llvm/lib/CodeGen/DroppedVariableStatsMIR.cpp @@ -0,0 +1,77 @@ +///===- DroppedVariableStatsMIR.cpp ---------------------------------------===// +/// +/// 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 +/// Dropped Variable Statistics for Debug Information. Reports any number +/// of DBG_VALUEs that get dropped due to an optimization pass. +/// +///===---------------------------------------------------------------------===// + +#include "llvm/CodeGen/DroppedVariableStatsMIR.h" + +using namespace llvm; + +void DroppedVariableStatsMIR::runOnMachineFunction(const MachineFunction *MF, + bool Before) { + auto &DebugVariables = DebugVariablesStack.back()[&MF->getFunction()]; + auto FuncName = MF->getName(); + MFunc = MF; + run(DebugVariables, FuncName, Before); +} + +void DroppedVariableStatsMIR::calculateDroppedVarStatsOnMachineFunction( + const MachineFunction *MF, StringRef PassID, StringRef FuncOrModName) { + MFunc = MF; + StringRef FuncName = MF->getName(); + const Function *Func = &MF->getFunction(); + DebugVariables &DbgVariables = DebugVariablesStack.back()[Func]; + calculateDroppedStatsAndPrint(DbgVariables, FuncName, PassID, FuncOrModName, + "MachineFunction", Func); +} + +void DroppedVariableStatsMIR::visitEveryInstruction( + unsigned &DroppedCount, DenseMap &InlinedAtsMap, + VarID Var) { + unsigned PrevDroppedCount = DroppedCount; + const DIScope *DbgValScope = std::get<0>(Var); + for (const auto &MBB : *MFunc) { + for (const auto &MI : MBB) { + if (!MI.isDebugInstr()) { + auto *DbgLoc = MI.getDebugLoc().get(); + if (!DbgLoc) + continue; + + auto *Scope = DbgLoc->getScope(); + if (updateDroppedCount(DbgLoc, Scope, DbgValScope, InlinedAtsMap, Var, + DroppedCount)) + break; + } + } + if (PrevDroppedCount != DroppedCount) { + PrevDroppedCount = DroppedCount; + break; + } + } +} + +void DroppedVariableStatsMIR::visitEveryDebugRecord( + DenseSet &VarIDSet, + DenseMap> &InlinedAtsMap, + StringRef FuncName, bool Before) { + for (const auto &MBB : *MFunc) { + for (const auto &MI : MBB) { + if (MI.isDebugValueLike()) { + auto *DbgVar = MI.getDebugVariable(); + if (!DbgVar) + continue; + auto DbgLoc = MI.getDebugLoc(); + populateVarIDSetAndInlinedMap(DbgVar, DbgLoc, VarIDSet, InlinedAtsMap, + FuncName, Before); + } + } + } +} \ No newline at end of file diff --git a/llvm/lib/CodeGen/MachineFunctionPass.cpp b/llvm/lib/CodeGen/MachineFunctionPass.cpp index 62ac3e32d24d9..e803811643f87 100644 --- a/llvm/lib/CodeGen/MachineFunctionPass.cpp +++ b/llvm/lib/CodeGen/MachineFunctionPass.cpp @@ -32,6 +32,11 @@ using namespace llvm; using namespace ore; +static cl::opt DroppedVarStatsMIR( + "dropped-variable-stats-mir", cl::Hidden, + cl::desc("Dump dropped debug variables stats for MIR passes"), + cl::init(false)); + Pass *MachineFunctionPass::createPrinterPass(raw_ostream &O, const std::string &Banner) const { return createMachineFunctionPrinterPass(O, Banner); @@ -91,7 +96,15 @@ bool MachineFunctionPass::runOnFunction(Function &F) { MFProps.reset(ClearedProperties); - bool RV = runOnMachineFunction(MF); + bool RV; + if (DroppedVarStatsMIR) { + auto PassName = getPassName(); + DroppedVarStatsMF.runBeforePass(PassName, &MF); + RV = runOnMachineFunction(MF); + DroppedVarStatsMF.runAfterPass(PassName, &MF); + } else { + RV = runOnMachineFunction(MF); + } if (ShouldEmitSizeRemarks) { // We wanted size remarks. Check if there was a change to the number of diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt index 963cdcc0275e1..4f580e7539f4d 100644 --- a/llvm/unittests/CodeGen/CMakeLists.txt +++ b/llvm/unittests/CodeGen/CMakeLists.txt @@ -27,6 +27,7 @@ add_llvm_unittest(CodeGenTests CCStateTest.cpp DIEHashTest.cpp DIETest.cpp + DroppedVariableStatsMIRTest.cpp DwarfStringPoolEntryRefTest.cpp InstrRefLDVTest.cpp LowLevelTypeTest.cpp diff --git a/llvm/unittests/CodeGen/DroppedVariableStatsMIRTest.cpp b/llvm/unittests/CodeGen/DroppedVariableStatsMIRTest.cpp new file mode 100644 index 0000000000000..7fdd30390a444 --- /dev/null +++ b/llvm/unittests/CodeGen/DroppedVariableStatsMIRTest.cpp @@ -0,0 +1,1052 @@ +//===- unittests/CodeGen/DroppedVariableStatsMIRTest.cpp ------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/DroppedVariableStatsMIR.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/CodeGen/MIRParser/MIRParser.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Pass.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "gtest/gtest.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +namespace { + +std::unique_ptr +createTargetMachine(std::string TT, StringRef CPU, StringRef FS) { + std::string Error; + const Target *T = TargetRegistry::lookupTarget(TT, Error); + if (!T) + return nullptr; + TargetOptions Options; + return std::unique_ptr( + static_cast(T->createTargetMachine( + TT, CPU, FS, Options, std::nullopt, std::nullopt))); +} + +std::unique_ptr parseMIR(const LLVMTargetMachine &TM, StringRef MIRCode, + MachineModuleInfo &MMI, LLVMContext *Context) { + SMDiagnostic Diagnostic; + std::unique_ptr M; + std::unique_ptr MBuffer = MemoryBuffer::getMemBuffer(MIRCode); + auto MIR = createMIRParser(std::move(MBuffer), *Context); + if (!MIR) + return nullptr; + + std::unique_ptr Mod = MIR->parseIRModule(); + if (!Mod) + return nullptr; + + Mod->setDataLayout(TM.createDataLayout()); + + if (MIR->parseMachineFunctions(*Mod, MMI)) { + M.reset(); + return nullptr; + } + return Mod; +} +// This test ensures that if a DBG_VALUE and an instruction that exists in the +// same scope as that DBG_VALUE are both deleted as a result of an optimization +// pass, debug information is considered not dropped. +TEST(DroppedVariableStatsMIR, BothDeleted) { + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + PassInstrumentationCallbacks PIC; + PassInstrumentation PI(&PIC); + + LLVMContext C; + + const char *MIR = + R"( +--- | + ; ModuleID = '/tmp/test.ll' + source_filename = "/tmp/test.ll" + target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + + define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr !dbg !4 { + entry: + #dbg_value(i32 %x, !10, !DIExpression(), !11) + %add = add nsw i32 %x, 1, !dbg !12 + ret i32 0 + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2} + !llvm.ident = !{!3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/") + !1 = !DIFile(filename: "/tmp/code.cpp", directory: "/") + !2 = !{i32 2, !"Debug Info Version", i32 3} + !3 = !{!"clang"} + !4 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !5, file: !5, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !9) + !5 = !DIFile(filename: "/tmp/code.cpp", directory: "") + !6 = !DISubroutineType(types: !7) + !7 = !{!8, !8} + !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !9 = !{!10} + !10 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !5, line: 1, type: !8) + !11 = !DILocation(line: 0, scope: !4) + !12 = !DILocation(line: 2, column: 11, scope: !4) + +... +--- +name: _Z3fooi +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +callsEHReturn: false +callsUnwindInit: false +hasEHCatchret: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: + - { id: 0, class: _, preferred-register: ''} + - { id: 1, class: _, preferred-register: ''} + - { id: 2, class: _, preferred-register: ''} + - { id: 3, class: _, preferred-register: ''} +liveins: + - { reg: '$w0', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + isCalleeSavedInfoValid: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $w0 + + %0:_(s32) = COPY $w0 + %1:_(s32) = G_CONSTANT i32 1 + %3:_(s32) = G_CONSTANT i32 0 + DBG_VALUE %0(s32), $noreg, !10, !DIExpression(), debug-location !11 + %2:_(s32) = nsw G_ADD %0, %1, debug-location !12 + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + )"; + auto TM = createTargetMachine(Triple::normalize("aarch64--"), "", ""); + if (!TM) + return; + MachineModuleInfo MMI(TM.get()); + std::unique_ptr M = parseMIR(*TM, MIR, MMI, &C); + ASSERT_TRUE(M); + + DroppedVariableStatsMIR Stats; + auto *MF = MMI.getMachineFunction(*M->getFunction("_Z3fooi")); + Stats.runBeforePass("Test", MF); + + // This loop simulates an IR pass that drops debug information. + for (auto &MBB : *MF) { + for (auto &MI : MBB) { + if (MI.isDebugValueLike()) { + MI.eraseFromParent(); + break; + } + } + for (auto &MI : MBB) { + auto *DbgLoc = MI.getDebugLoc().get(); + if (DbgLoc) { + MI.eraseFromParent(); + break; + } + } + break; + } + + Stats.runAfterPass("Test", MF); + ASSERT_EQ(Stats.getPassDroppedVariables(), false); +} + +// This test ensures that if a DBG_VALUE is dropped after an optimization pass, +// but an instruction that shares the same scope as the DBG_VALUE still exists, +// debug information is conisdered dropped. +TEST(DroppedVariableStatsMIR, DbgValLost) { + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + PassInstrumentationCallbacks PIC; + PassInstrumentation PI(&PIC); + + LLVMContext C; + + const char *MIR = + R"( +--- | + ; ModuleID = '/tmp/test.ll' + source_filename = "/tmp/test.ll" + target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + + define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr !dbg !4 { + entry: + #dbg_value(i32 %x, !10, !DIExpression(), !11) + %add = add nsw i32 %x, 1, !dbg !12 + ret i32 0 + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2} + !llvm.ident = !{!3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/") + !1 = !DIFile(filename: "/tmp/code.cpp", directory: "/") + !2 = !{i32 2, !"Debug Info Version", i32 3} + !3 = !{!"clang"} + !4 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !5, file: !5, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !9) + !5 = !DIFile(filename: "/tmp/code.cpp", directory: "") + !6 = !DISubroutineType(types: !7) + !7 = !{!8, !8} + !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !9 = !{!10} + !10 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !5, line: 1, type: !8) + !11 = !DILocation(line: 0, scope: !4) + !12 = !DILocation(line: 2, column: 11, scope: !4) + +... +--- +name: _Z3fooi +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +callsEHReturn: false +callsUnwindInit: false +hasEHCatchret: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: + - { id: 0, class: _, preferred-register: ''} + - { id: 1, class: _, preferred-register: ''} + - { id: 2, class: _, preferred-register: ''} + - { id: 3, class: _, preferred-register: ''} +liveins: + - { reg: '$w0', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + isCalleeSavedInfoValid: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $w0 + + %0:_(s32) = COPY $w0 + %1:_(s32) = G_CONSTANT i32 1 + %3:_(s32) = G_CONSTANT i32 0 + DBG_VALUE %0(s32), $noreg, !10, !DIExpression(), debug-location !11 + %2:_(s32) = nsw G_ADD %0, %1, debug-location !12 + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + )"; + auto TM = createTargetMachine(Triple::normalize("aarch64--"), "", ""); + if (!TM) + return; + MachineModuleInfo MMI(TM.get()); + std::unique_ptr M = parseMIR(*TM, MIR, MMI, &C); + ASSERT_TRUE(M); + + DroppedVariableStatsMIR Stats; + auto *MF = MMI.getMachineFunction(*M->getFunction("_Z3fooi")); + Stats.runBeforePass("Test", MF); + + // This loop simulates an IR pass that drops debug information. + for (auto &MBB : *MF) { + for (auto &MI : MBB) { + if (MI.isDebugValueLike()) { + MI.eraseFromParent(); + break; + } + } + break; + } + + Stats.runAfterPass("Test", MF); + ASSERT_EQ(Stats.getPassDroppedVariables(), true); +} + +// This test ensures that if a #dbg_value is dropped after an optimization pass, +// but an instruction that has an unrelated scope as the #dbg_value still +// exists, debug information is conisdered not dropped. +TEST(DroppedVariableStatsMIR, UnrelatedScopes) { + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + PassInstrumentationCallbacks PIC; + PassInstrumentation PI(&PIC); + + LLVMContext C; + + const char *MIR = + R"( +--- | + ; ModuleID = '/tmp/test.ll' + source_filename = "/tmp/test.ll" + target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + + define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr !dbg !4 { + entry: + #dbg_value(i32 %x, !10, !DIExpression(), !11) + %add = add nsw i32 %x, 1, !dbg !12 + ret i32 0 + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2} + !llvm.ident = !{!3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/") + !1 = !DIFile(filename: "/tmp/code.cpp", directory: "/") + !2 = !{i32 2, !"Debug Info Version", i32 3} + !3 = !{!"clang"} + !4 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !5, file: !5, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !9) + !5 = !DIFile(filename: "/tmp/code.cpp", directory: "") + !6 = !DISubroutineType(types: !7) + !7 = !{!8, !8} + !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !9 = !{!10} + !10 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !5, line: 1, type: !8) + !11 = !DILocation(line: 0, scope: !4) + !12 = !DILocation(line: 2, column: 11, scope: !13) + !13 = distinct !DISubprogram(name: "bar", linkageName: "_Z3bari", scope: !5, file: !5, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !9) + +... +--- +name: _Z3fooi +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +callsEHReturn: false +callsUnwindInit: false +hasEHCatchret: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: + - { id: 0, class: _, preferred-register: ''} + - { id: 1, class: _, preferred-register: ''} + - { id: 2, class: _, preferred-register: ''} + - { id: 3, class: _, preferred-register: ''} +liveins: + - { reg: '$w0', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + isCalleeSavedInfoValid: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $w0 + + %0:_(s32) = COPY $w0 + %1:_(s32) = G_CONSTANT i32 1 + %3:_(s32) = G_CONSTANT i32 0 + DBG_VALUE %0(s32), $noreg, !10, !DIExpression(), debug-location !11 + %2:_(s32) = nsw G_ADD %0, %1, debug-location !12 + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + )"; + auto TM = createTargetMachine(Triple::normalize("aarch64--"), "", ""); + if (!TM) + return; + MachineModuleInfo MMI(TM.get()); + std::unique_ptr M = parseMIR(*TM, MIR, MMI, &C); + ASSERT_TRUE(M); + + DroppedVariableStatsMIR Stats; + auto *MF = MMI.getMachineFunction(*M->getFunction("_Z3fooi")); + Stats.runBeforePass("Test", MF); + + // This loop simulates an IR pass that drops debug information. + for (auto &MBB : *MF) { + for (auto &MI : MBB) { + if (MI.isDebugValueLike()) { + MI.eraseFromParent(); + break; + } + } + break; + } + + Stats.runAfterPass("Test", MF); + ASSERT_EQ(Stats.getPassDroppedVariables(), false); +} + +// This test ensures that if a #dbg_value is dropped after an optimization pass, +// but an instruction that has a scope which is a child of the #dbg_value scope +// still exists, debug information is conisdered dropped. +TEST(DroppedVariableStatsMIR, ChildScopes) { + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + PassInstrumentationCallbacks PIC; + PassInstrumentation PI(&PIC); + + LLVMContext C; + + const char *MIR = + R"( +--- | + ; ModuleID = '/tmp/test.ll' + source_filename = "/tmp/test.ll" + target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + + define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr !dbg !4 { + entry: + #dbg_value(i32 %x, !10, !DIExpression(), !11) + %add = add nsw i32 %x, 1, !dbg !12 + ret i32 0 + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2} + !llvm.ident = !{!3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/") + !1 = !DIFile(filename: "/tmp/code.cpp", directory: "/") + !2 = !{i32 2, !"Debug Info Version", i32 3} + !3 = !{!"clang"} + !4 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !5, file: !5, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !9) + !5 = !DIFile(filename: "/tmp/code.cpp", directory: "") + !6 = !DISubroutineType(types: !7) + !7 = !{!8, !8} + !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !9 = !{!10} + !10 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !5, line: 1, type: !8) + !11 = !DILocation(line: 0, scope: !4) + !12 = !DILocation(line: 2, column: 11, scope: !13) + !13 = distinct !DILexicalBlock(scope: !4, file: !5, line: 10, column: 28) + +... +--- +name: _Z3fooi +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +callsEHReturn: false +callsUnwindInit: false +hasEHCatchret: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: + - { id: 0, class: _, preferred-register: ''} + - { id: 1, class: _, preferred-register: ''} + - { id: 2, class: _, preferred-register: ''} + - { id: 3, class: _, preferred-register: ''} +liveins: + - { reg: '$w0', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + isCalleeSavedInfoValid: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $w0 + + %0:_(s32) = COPY $w0 + %1:_(s32) = G_CONSTANT i32 1 + %3:_(s32) = G_CONSTANT i32 0 + DBG_VALUE %0(s32), $noreg, !10, !DIExpression(), debug-location !11 + %2:_(s32) = nsw G_ADD %0, %1, debug-location !12 + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + )"; + auto TM = createTargetMachine(Triple::normalize("aarch64--"), "", ""); + if (!TM) + return; + MachineModuleInfo MMI(TM.get()); + std::unique_ptr M = parseMIR(*TM, MIR, MMI, &C); + ASSERT_TRUE(M); + + DroppedVariableStatsMIR Stats; + auto *MF = MMI.getMachineFunction(*M->getFunction("_Z3fooi")); + Stats.runBeforePass("Test", MF); + + // This loop simulates an IR pass that drops debug information. + for (auto &MBB : *MF) { + for (auto &MI : MBB) { + if (MI.isDebugValueLike()) { + MI.eraseFromParent(); + break; + } + } + break; + } + + Stats.runAfterPass("Test", MF); + ASSERT_EQ(Stats.getPassDroppedVariables(), true); +} + +// This test ensures that if a DBG_VALUE is dropped after an optimization pass, +// but an instruction that has a scope which is a child of the DBG_VALUE scope +// still exists, and the DBG_VALUE is inlined at another location, debug +// information is conisdered not dropped. +TEST(DroppedVariableStatsMIR, InlinedAt) { + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + PassInstrumentationCallbacks PIC; + PassInstrumentation PI(&PIC); + + LLVMContext C; + + const char *MIR = + R"( +--- | + ; ModuleID = '/tmp/test.ll' + source_filename = "/tmp/test.ll" + target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + + define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr !dbg !4 { + entry: + #dbg_value(i32 %x, !10, !DIExpression(), !11) + %add = add nsw i32 %x, 1, !dbg !12 + ret i32 0 + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2} + !llvm.ident = !{!3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/") + !1 = !DIFile(filename: "/tmp/code.cpp", directory: "/") + !2 = !{i32 2, !"Debug Info Version", i32 3} + !3 = !{!"clang"} + !4 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !5, file: !5, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !9) + !5 = !DIFile(filename: "/tmp/code.cpp", directory: "") + !6 = !DISubroutineType(types: !7) + !7 = !{!8, !8} + !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !9 = !{!10} + !10 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !5, line: 1, type: !8) + !11 = !DILocation(line: 0, scope: !4, inlinedAt: !14) + !12 = !DILocation(line: 2, column: 11, scope: !13) + !13 = distinct !DILexicalBlock(scope: !4, file: !5, line: 10, column: 28) + !14 = !DILocation(line: 3, column: 2, scope: !4) + +... +--- +name: _Z3fooi +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +callsEHReturn: false +callsUnwindInit: false +hasEHCatchret: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: + - { id: 0, class: _, preferred-register: ''} + - { id: 1, class: _, preferred-register: ''} + - { id: 2, class: _, preferred-register: ''} + - { id: 3, class: _, preferred-register: ''} +liveins: + - { reg: '$w0', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + isCalleeSavedInfoValid: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $w0 + + %0:_(s32) = COPY $w0 + %1:_(s32) = G_CONSTANT i32 1 + %3:_(s32) = G_CONSTANT i32 0 + DBG_VALUE %0(s32), $noreg, !10, !DIExpression(), debug-location !11 + %2:_(s32) = nsw G_ADD %0, %1, debug-location !12 + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + )"; + auto TM = createTargetMachine(Triple::normalize("aarch64--"), "", ""); + if (!TM) + return; + MachineModuleInfo MMI(TM.get()); + std::unique_ptr M = parseMIR(*TM, MIR, MMI, &C); + ASSERT_TRUE(M); + + DroppedVariableStatsMIR Stats; + auto *MF = MMI.getMachineFunction(*M->getFunction("_Z3fooi")); + Stats.runBeforePass("Test", MF); + + // This loop simulates an IR pass that drops debug information. + for (auto &MBB : *MF) { + for (auto &MI : MBB) { + if (MI.isDebugValueLike()) { + MI.eraseFromParent(); + break; + } + } + break; + } + + Stats.runAfterPass("Test", MF); + ASSERT_EQ(Stats.getPassDroppedVariables(), false); +} + +// This test ensures that if a DBG_VALUE is dropped after an optimization pass, +// but an instruction that has a scope which is a child of the DBG_VALUE scope +// still exists, and the DBG_VALUE and the instruction are inlined at another +// location, debug information is conisdered dropped. +TEST(DroppedVariableStatsMIR, InlinedAtShared) { + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + PassInstrumentationCallbacks PIC; + PassInstrumentation PI(&PIC); + + LLVMContext C; + + const char *MIR = + R"( +--- | + ; ModuleID = '/tmp/test.ll' + source_filename = "/tmp/test.ll" + target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + + define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr !dbg !4 { + entry: + #dbg_value(i32 %x, !10, !DIExpression(), !11) + %add = add nsw i32 %x, 1, !dbg !12 + ret i32 0 + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2} + !llvm.ident = !{!3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/") + !1 = !DIFile(filename: "/tmp/code.cpp", directory: "/") + !2 = !{i32 2, !"Debug Info Version", i32 3} + !3 = !{!"clang"} + !4 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !5, file: !5, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !9) + !5 = !DIFile(filename: "/tmp/code.cpp", directory: "") + !6 = !DISubroutineType(types: !7) + !7 = !{!8, !8} + !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !9 = !{!10} + !10 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !5, line: 1, type: !8) + !11 = !DILocation(line: 0, scope: !4, inlinedAt: !14) + !12 = !DILocation(line: 2, column: 11, scope: !13, inlinedAt: !14) + !13 = distinct !DILexicalBlock(scope: !4, file: !5, line: 10, column: 28) + !14 = !DILocation(line: 3, column: 2, scope: !4) + +... +--- +name: _Z3fooi +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +callsEHReturn: false +callsUnwindInit: false +hasEHCatchret: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: + - { id: 0, class: _, preferred-register: ''} + - { id: 1, class: _, preferred-register: ''} + - { id: 2, class: _, preferred-register: ''} + - { id: 3, class: _, preferred-register: ''} +liveins: + - { reg: '$w0', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + isCalleeSavedInfoValid: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $w0 + + %0:_(s32) = COPY $w0 + %1:_(s32) = G_CONSTANT i32 1 + %3:_(s32) = G_CONSTANT i32 0 + DBG_VALUE %0(s32), $noreg, !10, !DIExpression(), debug-location !11 + %2:_(s32) = nsw G_ADD %0, %1, debug-location !12 + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + )"; + auto TM = createTargetMachine(Triple::normalize("aarch64--"), "", ""); + if (!TM) + return; + MachineModuleInfo MMI(TM.get()); + std::unique_ptr M = parseMIR(*TM, MIR, MMI, &C); + ASSERT_TRUE(M); + + DroppedVariableStatsMIR Stats; + auto *MF = MMI.getMachineFunction(*M->getFunction("_Z3fooi")); + Stats.runBeforePass("Test", MF); + + // This loop simulates an IR pass that drops debug information. + for (auto &MBB : *MF) { + for (auto &MI : MBB) { + if (MI.isDebugValueLike()) { + MI.eraseFromParent(); + break; + } + } + break; + } + + Stats.runAfterPass("Test", MF); + ASSERT_EQ(Stats.getPassDroppedVariables(), true); +} + +// This test ensures that if a DBG_VALUE is dropped after an optimization pass, +// but an instruction that has a scope which is a child of the DBG_VALUE scope +// still exists, and the instruction is inlined at a location that is the +// DBG_VALUE's inlined at location, debug information is conisdered dropped. +TEST(DroppedVariableStatsMIR, InlinedAtChild) { + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + PassInstrumentationCallbacks PIC; + PassInstrumentation PI(&PIC); + + LLVMContext C; + + const char *MIR = + R"( +--- | + ; ModuleID = '/tmp/test.ll' + source_filename = "/tmp/test.ll" + target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" + + define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr !dbg !4 { + entry: + #dbg_value(i32 %x, !10, !DIExpression(), !11) + %add = add nsw i32 %x, 1, !dbg !12 + ret i32 0 + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2} + !llvm.ident = !{!3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/") + !1 = !DIFile(filename: "/tmp/code.cpp", directory: "/") + !2 = !{i32 2, !"Debug Info Version", i32 3} + !3 = !{!"clang"} + !4 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !5, file: !5, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !9) + !5 = !DIFile(filename: "/tmp/code.cpp", directory: "") + !6 = !DISubroutineType(types: !7) + !7 = !{!8, !8} + !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !9 = !{!10} + !10 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !5, line: 1, type: !8) + !11 = !DILocation(line: 0, scope: !4, inlinedAt: !14) + !12 = !DILocation(line: 2, column: 11, scope: !13, inlinedAt: !15) + !13 = distinct !DILexicalBlock(scope: !4, file: !5, line: 10, column: 28) + !14 = !DILocation(line: 3, column: 2, scope: !4) + !15 = !DILocation(line: 4, column: 5, scope: !13, inlinedAt: !14) + +... +--- +name: _Z3fooi +alignment: 4 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +callsEHReturn: false +callsUnwindInit: false +hasEHCatchret: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: + - { id: 0, class: _, preferred-register: ''} + - { id: 1, class: _, preferred-register: ''} + - { id: 2, class: _, preferred-register: ''} + - { id: 3, class: _, preferred-register: ''} +liveins: + - { reg: '$w0', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + isCalleeSavedInfoValid: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $w0 + + %0:_(s32) = COPY $w0 + %1:_(s32) = G_CONSTANT i32 1 + %3:_(s32) = G_CONSTANT i32 0 + DBG_VALUE %0(s32), $noreg, !10, !DIExpression(), debug-location !11 + %2:_(s32) = nsw G_ADD %0, %1, debug-location !12 + $w0 = COPY %3(s32) + RET_ReallyLR implicit $w0 + )"; + auto TM = createTargetMachine(Triple::normalize("aarch64--"), "", ""); + if (!TM) + return; + MachineModuleInfo MMI(TM.get()); + std::unique_ptr M = parseMIR(*TM, MIR, MMI, &C); + ASSERT_TRUE(M); + + DroppedVariableStatsMIR Stats; + auto *MF = MMI.getMachineFunction(*M->getFunction("_Z3fooi")); + Stats.runBeforePass("Test", MF); + + // This loop simulates an IR pass that drops debug information. + for (auto &MBB : *MF) { + for (auto &MI : MBB) { + if (MI.isDebugValueLike()) { + MI.eraseFromParent(); + break; + } + } + break; + } + + Stats.runAfterPass("Test", MF); + ASSERT_EQ(Stats.getPassDroppedVariables(), true); +} + +} // end anonymous namespace \ No newline at end of file