[llvm] Reland "[NFC] Move DroppedVariableStats to its own file and redesign it to be extensible (#118546)" (PR #119048)
Shubham Sandeep Rastogi via llvm-commits
llvm-commits at lists.llvm.org
Fri Dec 6 17:15:17 PST 2024
https://github.com/rastogishubham created https://github.com/llvm/llvm-project/pull/119048
Move the virtual destructor definition to the cpp file and see if that gets rid of the undefined vtable error.
>From 97f52d16e0eeec61d9b3b55bd13a83f4058a2348 Mon Sep 17 00:00:00 2001
From: Shubham Sandeep Rastogi <srastogi22 at apple.com>
Date: Wed, 4 Dec 2024 12:50:57 -0800
Subject: [PATCH] Reland "[NFC] Move DroppedVariableStats to its own file and
redesign it to be extensible (#118546)"
Move the virtual destructor definition to the cpp file and see if that
gets rid of the undefined vtable error.
---
...s-to-collect-dropped-var-stats-for-M.patch | 1301 +++++++++++++++++
...DroppedVariableStats-to-its-own-file.patch | 1045 +++++++++++++
.../llvm/CodeGen/DroppedVariableStats.h | 224 +++
.../llvm/Passes/StandardInstrumentations.h | 80 +-
llvm/lib/CodeGen/CMakeLists.txt | 1 +
llvm/lib/CodeGen/DroppedVariableStats.cpp | 196 +++
llvm/lib/Passes/StandardInstrumentations.cpp | 178 +--
llvm/unittests/CodeGen/CMakeLists.txt | 1 +
.../DroppedVariableStatsIRTest.cpp} | 74 +-
llvm/unittests/IR/CMakeLists.txt | 1 -
10 files changed, 2802 insertions(+), 299 deletions(-)
create mode 100644 0001-Reland-Add-a-pass-to-collect-dropped-var-stats-for-M.patch
create mode 100644 0001-Reland-NFC-Move-DroppedVariableStats-to-its-own-file.patch
create mode 100644 llvm/include/llvm/CodeGen/DroppedVariableStats.h
create mode 100644 llvm/lib/CodeGen/DroppedVariableStats.cpp
rename llvm/unittests/{IR/DroppedVariableStatsTest.cpp => CodeGen/DroppedVariableStatsIRTest.cpp} (91%)
diff --git a/0001-Reland-Add-a-pass-to-collect-dropped-var-stats-for-M.patch b/0001-Reland-Add-a-pass-to-collect-dropped-var-stats-for-M.patch
new file mode 100644
index 00000000000000..95c0a0b54f7e24
--- /dev/null
+++ b/0001-Reland-Add-a-pass-to-collect-dropped-var-stats-for-M.patch
@@ -0,0 +1,1301 @@
+From 8f00eaaa595c1b908d43b1de288e3c03f1f998bf Mon Sep 17 00:00:00 2001
+From: Shubham Sandeep Rastogi <srastogi22 at apple.com>
+Date: Mon, 18 Nov 2024 16:06:59 -0800
+Subject: [PATCH] Reland "Add a pass to collect dropped var stats for MIR"
+
+Moved the MIR Test to the unittests/CodeGen folder
+---
+ .../llvm/CodeGen/DroppedVariableStats.h | 48 +-
+ .../llvm/CodeGen/MachineFunctionPass.h | 2 +
+ llvm/lib/CodeGen/DroppedVariableStats.cpp | 63 +-
+ llvm/lib/CodeGen/MachineFunctionPass.cpp | 15 +-
+ llvm/unittests/CodeGen/CMakeLists.txt | 1 +
+ .../CodeGen/DroppedVariableStatsMIRTest.cpp | 1067 +++++++++++++++++
+ 6 files changed, 1193 insertions(+), 3 deletions(-)
+ create mode 100644 llvm/unittests/CodeGen/DroppedVariableStatsMIRTest.cpp
+
+diff --git a/llvm/include/llvm/CodeGen/DroppedVariableStats.h b/llvm/include/llvm/CodeGen/DroppedVariableStats.h
+index 371d775b02e8..f6050c68c91a 100644
+--- a/llvm/include/llvm/CodeGen/DroppedVariableStats.h
++++ b/llvm/include/llvm/CodeGen/DroppedVariableStats.h
+@@ -7,7 +7,7 @@
+ ///===---------------------------------------------------------------------===//
+ /// \file
+ /// Dropped Variable Statistics for Debug Information. Reports any number
+-/// of #dbg_value that get dropped due to an optimization pass.
++/// of #dbg_values or DBG_VALUEs that get dropped due to an optimization pass.
+ ///
+ ///===---------------------------------------------------------------------===//
+
+@@ -221,6 +221,52 @@ private:
+ }
+ };
+
++/// 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<VarID, DILocation *> &InlinedAtsMap,
++ VarID Var) override;
++ /// Override base class method to run on DBG_VALUEs specifically.
++ virtual void visitEveryDebugRecord(
++ DenseSet<VarID> &VarIDSet,
++ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &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 caaf22c2139e..d82b593497ff 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/DroppedVariableStats.h"
+ #include "llvm/CodeGen/MachineFunction.h"
+ #include "llvm/Pass.h"
+
+@@ -67,6 +68,7 @@ private:
+ 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/DroppedVariableStats.cpp b/llvm/lib/CodeGen/DroppedVariableStats.cpp
+index 122fcad1293f..71f91292160f 100644
+--- a/llvm/lib/CodeGen/DroppedVariableStats.cpp
++++ b/llvm/lib/CodeGen/DroppedVariableStats.cpp
+@@ -7,7 +7,7 @@
+ ///===---------------------------------------------------------------------===//
+ /// \file
+ /// Dropped Variable Statistics for Debug Information. Reports any number
+-/// of #dbg_value that get dropped due to an optimization pass.
++/// of #dbg_values or DBG_VALUEs that get dropped due to an optimization pass.
+ ///
+ ///===---------------------------------------------------------------------===//
+
+@@ -192,3 +192,64 @@ void DroppedVariableStatsIR::visitEveryDebugRecord(
+ }
+ }
+ }
++
++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<VarID, DILocation *> &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<VarID> &VarIDSet,
++ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &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);
++ }
++ }
++ }
++}
+diff --git a/llvm/lib/CodeGen/MachineFunctionPass.cpp b/llvm/lib/CodeGen/MachineFunctionPass.cpp
+index 62ac3e32d24d..e803811643f8 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<bool> 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 807fd1a9b7b5..50ef1bb5b7af 100644
+--- a/llvm/unittests/CodeGen/CMakeLists.txt
++++ b/llvm/unittests/CodeGen/CMakeLists.txt
+@@ -28,6 +28,7 @@ add_llvm_unittest(CodeGenTests
+ DIEHashTest.cpp
+ DIETest.cpp
+ DroppedVariableStatsIRTest.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 000000000000..b26a89c7adcb
+--- /dev/null
++++ b/llvm/unittests/CodeGen/DroppedVariableStatsMIRTest.cpp
+@@ -0,0 +1,1067 @@
++//===- unittests/IR/DroppedVariableStatsTest.cpp - TimePassesHandler tests
++//----------===//
++//
++// 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/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/Passes/StandardInstrumentations.h"
++#include "llvm/Support/TargetSelect.h"
++#include "llvm/Target/TargetMachine.h"
++#include "gtest/gtest.h"
++#include <gtest/gtest.h>
++#include <llvm/ADT/SmallString.h>
++#include <llvm/IR/LLVMContext.h>
++#include <llvm/IR/Module.h>
++#include <llvm/IR/PassInstrumentation.h>
++#include <llvm/IR/PassManager.h>
++#include <llvm/IR/PassTimingInfo.h>
++#include <llvm/Support/raw_ostream.h>
++
++using namespace llvm;
++
++namespace {
++
++std::unique_ptr<TargetMachine>
++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<TargetMachine>(
++ static_cast<TargetMachine *>(T->createTargetMachine(
++ TT, CPU, FS, Options, std::nullopt, std::nullopt)));
++}
++
++std::unique_ptr<Module> parseMIR(const TargetMachine &TM, StringRef MIRCode,
++ MachineModuleInfo &MMI, LLVMContext *Context) {
++ SMDiagnostic Diagnostic;
++ std::unique_ptr<Module> M;
++ std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
++ auto MIR = createMIRParser(std::move(MBuffer), *Context);
++ if (!MIR)
++ return nullptr;
++
++ std::unique_ptr<Module> 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
++noPhis: false
++isSSA: true
++noVRegs: false
++hasFakeUses: 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: '', flags: [ ] }
++ - { id: 1, class: _, preferred-register: '', flags: [ ] }
++ - { id: 2, class: _, preferred-register: '', flags: [ ] }
++ - { id: 3, class: _, preferred-register: '', flags: [ ] }
++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--"), "", "");
++ MachineModuleInfo MMI(TM.get());
++ std::unique_ptr<Module> 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
++noPhis: false
++isSSA: true
++noVRegs: false
++hasFakeUses: 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: '', flags: [ ] }
++ - { id: 1, class: _, preferred-register: '', flags: [ ] }
++ - { id: 2, class: _, preferred-register: '', flags: [ ] }
++ - { id: 3, class: _, preferred-register: '', flags: [ ] }
++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--"), "", "");
++ MachineModuleInfo MMI(TM.get());
++ std::unique_ptr<Module> 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
++noPhis: false
++isSSA: true
++noVRegs: false
++hasFakeUses: 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: '', flags: [ ] }
++ - { id: 1, class: _, preferred-register: '', flags: [ ] }
++ - { id: 2, class: _, preferred-register: '', flags: [ ] }
++ - { id: 3, class: _, preferred-register: '', flags: [ ] }
++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--"), "", "");
++ MachineModuleInfo MMI(TM.get());
++ std::unique_ptr<Module> 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
++noPhis: false
++isSSA: true
++noVRegs: false
++hasFakeUses: 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: '', flags: [ ] }
++ - { id: 1, class: _, preferred-register: '', flags: [ ] }
++ - { id: 2, class: _, preferred-register: '', flags: [ ] }
++ - { id: 3, class: _, preferred-register: '', flags: [ ] }
++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--"), "", "");
++ MachineModuleInfo MMI(TM.get());
++ std::unique_ptr<Module> 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
++noPhis: false
++isSSA: true
++noVRegs: false
++hasFakeUses: 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: '', flags: [ ] }
++ - { id: 1, class: _, preferred-register: '', flags: [ ] }
++ - { id: 2, class: _, preferred-register: '', flags: [ ] }
++ - { id: 3, class: _, preferred-register: '', flags: [ ] }
++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--"), "", "");
++ MachineModuleInfo MMI(TM.get());
++ std::unique_ptr<Module> 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
++noPhis: false
++isSSA: true
++noVRegs: false
++hasFakeUses: 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: '', flags: [ ] }
++ - { id: 1, class: _, preferred-register: '', flags: [ ] }
++ - { id: 2, class: _, preferred-register: '', flags: [ ] }
++ - { id: 3, class: _, preferred-register: '', flags: [ ] }
++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--"), "", "");
++ MachineModuleInfo MMI(TM.get());
++ std::unique_ptr<Module> 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
++noPhis: false
++isSSA: true
++noVRegs: false
++hasFakeUses: 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: '', flags: [ ] }
++ - { id: 1, class: _, preferred-register: '', flags: [ ] }
++ - { id: 2, class: _, preferred-register: '', flags: [ ] }
++ - { id: 3, class: _, preferred-register: '', flags: [ ] }
++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--"), "", "");
++ MachineModuleInfo MMI(TM.get());
++ std::unique_ptr<Module> 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
+--
+2.46.2
+
diff --git a/0001-Reland-NFC-Move-DroppedVariableStats-to-its-own-file.patch b/0001-Reland-NFC-Move-DroppedVariableStats-to-its-own-file.patch
new file mode 100644
index 00000000000000..e68aa98b82b092
--- /dev/null
+++ b/0001-Reland-NFC-Move-DroppedVariableStats-to-its-own-file.patch
@@ -0,0 +1,1045 @@
+From 1f4f368b9c3b92787018a6ee410c5ab4e79b072d Mon Sep 17 00:00:00 2001
+From: Shubham Sandeep Rastogi <srastogi22 at apple.com>
+Date: Mon, 18 Nov 2024 16:06:26 -0800
+Subject: [PATCH] Reland [NFC] Move DroppedVariableStats to its own file and
+ redesign it to be extensible.
+
+Moved the IR unit test to the CodeGen folder to resolve linker errors:
+
+error: undefined reference to 'vtable for llvm::DroppedVariableStatsIR'
+---
+ .../llvm/CodeGen/DroppedVariableStats.h | 226 ++++++++++++++++++
+ .../llvm/Passes/StandardInstrumentations.h | 80 +------
+ llvm/lib/CodeGen/CMakeLists.txt | 1 +
+ llvm/lib/CodeGen/DroppedVariableStats.cpp | 194 +++++++++++++++
+ llvm/lib/Passes/StandardInstrumentations.cpp | 178 +-------------
+ llvm/unittests/CodeGen/CMakeLists.txt | 1 +
+ .../DroppedVariableStatsIRTest.cpp} | 74 +++---
+ llvm/unittests/IR/CMakeLists.txt | 1 -
+ 8 files changed, 456 insertions(+), 299 deletions(-)
+ create mode 100644 llvm/include/llvm/CodeGen/DroppedVariableStats.h
+ create mode 100644 llvm/lib/CodeGen/DroppedVariableStats.cpp
+ rename llvm/unittests/{IR/DroppedVariableStatsTest.cpp => CodeGen/DroppedVariableStatsIRTest.cpp} (91%)
+
+diff --git a/llvm/include/llvm/CodeGen/DroppedVariableStats.h b/llvm/include/llvm/CodeGen/DroppedVariableStats.h
+new file mode 100644
+index 000000000000..371d775b02e8
+--- /dev/null
++++ b/llvm/include/llvm/CodeGen/DroppedVariableStats.h
+@@ -0,0 +1,226 @@
++///===- DroppedVariableStats.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_value that get dropped due to an optimization pass.
++///
++///===---------------------------------------------------------------------===//
++
++#ifndef LLVM_CODEGEN_DROPPEDVARIABLESTATS_H
++#define LLVM_CODEGEN_DROPPEDVARIABLESTATS_H
++
++#include "llvm/CodeGen/MachinePassManager.h"
++#include "llvm/IR/DebugInfoMetadata.h"
++#include "llvm/IR/DiagnosticInfo.h"
++#include "llvm/IR/Function.h"
++#include "llvm/IR/Module.h"
++#include "llvm/IR/PassInstrumentation.h"
++
++namespace llvm {
++
++/// A unique key that represents a debug variable.
++/// First const DIScope *: Represents the scope of the debug variable.
++/// Second const DIScope *: Represents the InlinedAt scope of the debug
++/// variable. const DILocalVariable *: It is a pointer to the debug variable
++/// itself.
++using VarID =
++ std::tuple<const DIScope *, const DIScope *, const DILocalVariable *>;
++
++/// A base class to collect and print dropped debug information variable
++/// statistics.
++class DroppedVariableStats {
++public:
++ DroppedVariableStats(bool DroppedVarStatsEnabled)
++ : DroppedVariableStatsEnabled(DroppedVarStatsEnabled) {
++ if (DroppedVarStatsEnabled)
++ llvm::outs()
++ << "Pass Level, Pass Name, Num of Dropped Variables, Func or "
++ "Module Name\n";
++ };
++
++ virtual ~DroppedVariableStats() = default;
++
++ // We intend this to be unique per-compilation, thus no copies.
++ DroppedVariableStats(const DroppedVariableStats &) = delete;
++ void operator=(const DroppedVariableStats &) = delete;
++
++ bool getPassDroppedVariables() { return PassDroppedVariables; }
++
++protected:
++ void setup() {
++ DebugVariablesStack.push_back(
++ {DenseMap<const Function *, DebugVariables>()});
++ InlinedAts.push_back(
++ {DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
++ }
++
++ void cleanup() {
++ assert(!DebugVariablesStack.empty() &&
++ "DebugVariablesStack shouldn't be empty!");
++ assert(!InlinedAts.empty() && "InlinedAts shouldn't be empty!");
++ DebugVariablesStack.pop_back();
++ InlinedAts.pop_back();
++ }
++
++ bool DroppedVariableStatsEnabled = false;
++ struct DebugVariables {
++ /// DenseSet of VarIDs before an optimization pass has run.
++ DenseSet<VarID> DebugVariablesBefore;
++ /// DenseSet of VarIDs after an optimization pass has run.
++ DenseSet<VarID> DebugVariablesAfter;
++ };
++
++protected:
++ /// A stack of a DenseMap, that maps DebugVariables for every pass to an
++ /// llvm::Function. A stack is used because an optimization pass can call
++ /// other passes.
++ SmallVector<DenseMap<const Function *, DebugVariables>> DebugVariablesStack;
++
++ /// A DenseSet tracking whether a scope was visited before.
++ DenseSet<const DIScope *> VisitedScope;
++ /// A stack of DenseMaps, which map the name of an llvm::Function to a
++ /// DenseMap of VarIDs and their inlinedAt locations before an optimization
++ /// pass has run.
++ SmallVector<DenseMap<StringRef, DenseMap<VarID, DILocation *>>> InlinedAts;
++ /// Calculate the number of dropped variables in an llvm::Function or
++ /// llvm::MachineFunction and print the relevant information to stdout.
++ void calculateDroppedStatsAndPrint(DebugVariables &DbgVariables,
++ StringRef FuncName, StringRef PassID,
++ StringRef FuncOrModName,
++ StringRef PassLevel, const Function *Func);
++
++ /// Check if a \p Var has been dropped or is a false positive. Also update the
++ /// \p DroppedCount if a debug variable is dropped.
++ bool updateDroppedCount(DILocation *DbgLoc, const DIScope *Scope,
++ const DIScope *DbgValScope,
++ DenseMap<VarID, DILocation *> &InlinedAtsMap,
++ VarID Var, unsigned &DroppedCount);
++ /// Run code to populate relevant data structures over an llvm::Function or
++ /// llvm::MachineFunction.
++ void run(DebugVariables &DbgVariables, StringRef FuncName, bool Before);
++ /// Populate the VarIDSet and InlinedAtMap with the relevant information
++ /// needed for before and after pass analysis to determine dropped variable
++ /// status.
++ void populateVarIDSetAndInlinedMap(
++ const DILocalVariable *DbgVar, DebugLoc DbgLoc, DenseSet<VarID> &VarIDSet,
++ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
++ StringRef FuncName, bool Before);
++ /// Visit every llvm::Instruction or llvm::MachineInstruction and check if the
++ /// debug variable denoted by its ID \p Var may have been dropped by an
++ /// optimization pass.
++ virtual void
++ visitEveryInstruction(unsigned &DroppedCount,
++ DenseMap<VarID, DILocation *> &InlinedAtsMap,
++ VarID Var) = 0;
++ /// Visit every debug record in an llvm::Function or llvm::MachineFunction
++ /// and call populateVarIDSetAndInlinedMap on it.
++ virtual void visitEveryDebugRecord(
++ DenseSet<VarID> &VarIDSet,
++ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
++ StringRef FuncName, bool Before) = 0;
++
++private:
++ /// Remove a dropped debug variable's VarID from all Sets in the
++ /// DroppedVariablesBefore stack.
++ void removeVarFromAllSets(VarID Var, const Function *F) {
++ // Do not remove Var from the last element, it will be popped from the
++ // stack.
++ for (auto &DebugVariablesMap : llvm::drop_end(DebugVariablesStack))
++ DebugVariablesMap[F].DebugVariablesBefore.erase(Var);
++ }
++ /// Return true if \p Scope is the same as \p DbgValScope or a child scope of
++ /// \p DbgValScope, return false otherwise.
++ bool isScopeChildOfOrEqualTo(const DIScope *Scope,
++ const DIScope *DbgValScope);
++ /// Return true if \p InlinedAt is the same as \p DbgValInlinedAt or part of
++ /// the InlinedAt chain, return false otherwise.
++ bool isInlinedAtChildOfOrEqualTo(const DILocation *InlinedAt,
++ const DILocation *DbgValInlinedAt);
++ bool PassDroppedVariables = false;
++};
++
++/// A class to collect and print dropped debug information due to LLVM IR
++/// optimization passes. After every LLVM IR pass is run, it will print how many
++/// #dbg_values were dropped due to that pass.
++class DroppedVariableStatsIR : public DroppedVariableStats {
++public:
++ DroppedVariableStatsIR(bool DroppedVarStatsEnabled)
++ : llvm::DroppedVariableStats(DroppedVarStatsEnabled) {}
++
++ virtual ~DroppedVariableStatsIR() = default;
++
++ void runBeforePass(Any IR) {
++ setup();
++ if (const auto *M = unwrapIR<Module>(IR))
++ return this->runOnModule(M, true);
++ if (const auto *F = unwrapIR<Function>(IR))
++ return this->runOnFunction(F, true);
++ }
++
++ void runAfterPass(StringRef P, Any IR) {
++ if (const auto *M = unwrapIR<Module>(IR))
++ runAfterPassModule(P, M);
++ else if (const auto *F = unwrapIR<Function>(IR))
++ runAfterPassFunction(P, F);
++ cleanup();
++ }
++
++ void registerCallbacks(PassInstrumentationCallbacks &PIC);
++
++private:
++ const Function *Func;
++
++ void runAfterPassFunction(StringRef PassID, const Function *F) {
++ runOnFunction(F, false);
++ calculateDroppedVarStatsOnFunction(F, PassID, F->getName().str(),
++ "Function");
++ }
++
++ void runAfterPassModule(StringRef PassID, const Module *M) {
++ runOnModule(M, false);
++ calculateDroppedVarStatsOnModule(M, PassID, M->getName().str(), "Module");
++ }
++ /// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
++ /// after a pass has run to facilitate dropped variable calculation for an
++ /// llvm::Function.
++ void runOnFunction(const Function *F, bool Before);
++ /// Iterate over all Instructions in a Function and report any dropped debug
++ /// information.
++ void calculateDroppedVarStatsOnFunction(const Function *F, StringRef PassID,
++ StringRef FuncOrModName,
++ StringRef PassLevel);
++ /// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
++ /// after a pass has run to facilitate dropped variable calculation for an
++ /// llvm::Module. Calls runOnFunction on every Function in the Module.
++ void runOnModule(const Module *M, bool Before);
++ /// Iterate over all Functions in a Module and report any dropped debug
++ /// information. Will call calculateDroppedVarStatsOnFunction on every
++ /// Function.
++ void calculateDroppedVarStatsOnModule(const Module *M, StringRef PassID,
++ StringRef FuncOrModName,
++ StringRef PassLevel);
++ /// Override base class method to run on an llvm::Function specifically.
++ virtual void
++ visitEveryInstruction(unsigned &DroppedCount,
++ DenseMap<VarID, DILocation *> &InlinedAtsMap,
++ VarID Var) override;
++ /// Override base class method to run on #dbg_values specifically.
++ virtual void visitEveryDebugRecord(
++ DenseSet<VarID> &VarIDSet,
++ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
++ StringRef FuncName, bool Before) override;
++
++ template <typename IRUnitT> static const IRUnitT *unwrapIR(Any IR) {
++ const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR);
++ return IRPtr ? *IRPtr : nullptr;
++ }
++};
++
++} // namespace llvm
++
++#endif
+diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h
+index 9301a12c740e..12a34c099eaf 100644
+--- a/llvm/include/llvm/Passes/StandardInstrumentations.h
++++ b/llvm/include/llvm/Passes/StandardInstrumentations.h
+@@ -19,6 +19,7 @@
+ #include "llvm/ADT/SmallVector.h"
+ #include "llvm/ADT/StringRef.h"
+ #include "llvm/ADT/StringSet.h"
++#include "llvm/CodeGen/DroppedVariableStats.h"
+ #include "llvm/CodeGen/MachineBasicBlock.h"
+ #include "llvm/IR/BasicBlock.h"
+ #include "llvm/IR/DebugInfoMetadata.h"
+@@ -579,83 +580,6 @@ private:
+ static void SignalHandler(void *);
+ };
+
+-/// A class to collect and print dropped debug information variable statistics.
+-/// After every LLVM IR pass is run, it will print how many #dbg_values were
+-/// dropped due to that pass.
+-class DroppedVariableStats {
+-public:
+- DroppedVariableStats(bool DroppedVarStatsEnabled) {
+- if (DroppedVarStatsEnabled)
+- llvm::outs()
+- << "Pass Level, Pass Name, Num of Dropped Variables, Func or "
+- "Module Name\n";
+- };
+- // We intend this to be unique per-compilation, thus no copies.
+- DroppedVariableStats(const DroppedVariableStats &) = delete;
+- void operator=(const DroppedVariableStats &) = delete;
+-
+- void registerCallbacks(PassInstrumentationCallbacks &PIC);
+- void runBeforePass(StringRef PassID, Any IR);
+- void runAfterPass(StringRef PassID, Any IR, const PreservedAnalyses &PA);
+- void runAfterPassInvalidated(StringRef PassID, const PreservedAnalyses &PA);
+- bool getPassDroppedVariables() { return PassDroppedVariables; }
+-
+-private:
+- bool PassDroppedVariables = false;
+- /// A unique key that represents a #dbg_value.
+- using VarID =
+- std::tuple<const DIScope *, const DIScope *, const DILocalVariable *>;
+-
+- struct DebugVariables {
+- /// DenseSet of VarIDs before an optimization pass has run.
+- DenseSet<VarID> DebugVariablesBefore;
+- /// DenseSet of VarIDs after an optimization pass has run.
+- DenseSet<VarID> DebugVariablesAfter;
+- };
+-
+- /// A stack of a DenseMap, that maps DebugVariables for every pass to an
+- /// llvm::Function. A stack is used because an optimization pass can call
+- /// other passes.
+- SmallVector<DenseMap<const Function *, DebugVariables>> DebugVariablesStack;
+-
+- /// A DenseSet tracking whether a scope was visited before.
+- DenseSet<const DIScope *> VisitedScope;
+- /// A stack of DenseMaps, which map the name of an llvm::Function to a
+- /// DenseMap of VarIDs and their inlinedAt locations before an optimization
+- /// pass has run.
+- SmallVector<DenseMap<StringRef, DenseMap<VarID, DILocation *>>> InlinedAts;
+-
+- /// Iterate over all Functions in a Module and report any dropped debug
+- /// information. Will call calculateDroppedVarStatsOnFunction on every
+- /// Function.
+- void calculateDroppedVarStatsOnModule(const Module *M, StringRef PassID,
+- std::string FuncOrModName,
+- std::string PassLevel);
+- /// Iterate over all Instructions in a Function and report any dropped debug
+- /// information.
+- void calculateDroppedVarStatsOnFunction(const Function *F, StringRef PassID,
+- std::string FuncOrModName,
+- std::string PassLevel);
+- /// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
+- /// after a pass has run to facilitate dropped variable calculation for an
+- /// llvm::Function.
+- void runOnFunction(const Function *F, bool Before);
+- /// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
+- /// after a pass has run to facilitate dropped variable calculation for an
+- /// llvm::Module. Calls runOnFunction on every Function in the Module.
+- void runOnModule(const Module *M, bool Before);
+- /// Remove a dropped #dbg_value VarID from all Sets in the
+- /// DroppedVariablesBefore stack.
+- void removeVarFromAllSets(VarID Var, const Function *F);
+- /// Return true if \p Scope is the same as \p DbgValScope or a child scope of
+- /// \p DbgValScope, return false otherwise.
+- bool isScopeChildOfOrEqualTo(DIScope *Scope, const DIScope *DbgValScope);
+- /// Return true if \p InlinedAt is the same as \p DbgValInlinedAt or part of
+- /// the InlinedAt chain, return false otherwise.
+- bool isInlinedAtChildOfOrEqualTo(const DILocation *InlinedAt,
+- const DILocation *DbgValInlinedAt);
+-};
+-
+ /// This class provides an interface to register all the standard pass
+ /// instrumentations and manages their state (if any).
+ class StandardInstrumentations {
+@@ -673,7 +597,7 @@ class StandardInstrumentations {
+ PrintCrashIRInstrumentation PrintCrashIR;
+ IRChangedTester ChangeTester;
+ VerifyInstrumentation Verify;
+- DroppedVariableStats DroppedStats;
++ DroppedVariableStatsIR DroppedStatsIR;
+
+ bool VerifyEach;
+
+diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
+index 7b47c0e6f75d..263d4a9ee94d 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
++ DroppedVariableStats.cpp
+ DwarfEHPrepare.cpp
+ EarlyIfConversion.cpp
+ EdgeBundles.cpp
+diff --git a/llvm/lib/CodeGen/DroppedVariableStats.cpp b/llvm/lib/CodeGen/DroppedVariableStats.cpp
+new file mode 100644
+index 000000000000..122fcad1293f
+--- /dev/null
++++ b/llvm/lib/CodeGen/DroppedVariableStats.cpp
+@@ -0,0 +1,194 @@
++///===- DroppedVariableStats.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_value that get dropped due to an optimization pass.
++///
++///===---------------------------------------------------------------------===//
++
++#include "llvm/CodeGen/DroppedVariableStats.h"
++#include "llvm/IR/DebugInfoMetadata.h"
++#include "llvm/IR/InstIterator.h"
++#include "llvm/IR/Module.h"
++
++using namespace llvm;
++
++bool DroppedVariableStats::isScopeChildOfOrEqualTo(const DIScope *Scope,
++ const DIScope *DbgValScope) {
++ while (Scope != nullptr) {
++ if (VisitedScope.find(Scope) == VisitedScope.end()) {
++ VisitedScope.insert(Scope);
++ if (Scope == DbgValScope) {
++ VisitedScope.clear();
++ return true;
++ }
++ Scope = Scope->getScope();
++ } else {
++ VisitedScope.clear();
++ return false;
++ }
++ }
++ return false;
++}
++
++bool DroppedVariableStats::isInlinedAtChildOfOrEqualTo(
++ const DILocation *InlinedAt, const DILocation *DbgValInlinedAt) {
++ if (DbgValInlinedAt == InlinedAt)
++ return true;
++ if (!DbgValInlinedAt)
++ return false;
++ auto *IA = InlinedAt;
++ while (IA) {
++ if (IA == DbgValInlinedAt)
++ return true;
++ IA = IA->getInlinedAt();
++ }
++ return false;
++}
++
++void DroppedVariableStats::calculateDroppedStatsAndPrint(
++ DebugVariables &DbgVariables, StringRef FuncName, StringRef PassID,
++ StringRef FuncOrModName, StringRef PassLevel, const Function *Func) {
++ unsigned DroppedCount = 0;
++ DenseSet<VarID> &DebugVariablesBeforeSet = DbgVariables.DebugVariablesBefore;
++ DenseSet<VarID> &DebugVariablesAfterSet = DbgVariables.DebugVariablesAfter;
++ DenseMap<VarID, DILocation *> &InlinedAtsMap = InlinedAts.back()[FuncName];
++ // Find an Instruction that shares the same scope as the dropped #dbg_value or
++ // has a scope that is the child of the scope of the #dbg_value, and has an
++ // inlinedAt equal to the inlinedAt of the #dbg_value or it's inlinedAt chain
++ // contains the inlinedAt of the #dbg_value, if such an Instruction is found,
++ // debug information is dropped.
++ for (VarID Var : DebugVariablesBeforeSet) {
++ if (DebugVariablesAfterSet.contains(Var))
++ continue;
++ visitEveryInstruction(DroppedCount, InlinedAtsMap, Var);
++ removeVarFromAllSets(Var, Func);
++ }
++ if (DroppedCount > 0) {
++ llvm::outs() << PassLevel << ", " << PassID << ", " << DroppedCount << ", "
++ << FuncOrModName << "\n";
++ PassDroppedVariables = true;
++ } else
++ PassDroppedVariables = false;
++}
++
++bool DroppedVariableStats::updateDroppedCount(
++ DILocation *DbgLoc, const DIScope *Scope, const DIScope *DbgValScope,
++ DenseMap<VarID, DILocation *> &InlinedAtsMap, VarID Var,
++ unsigned &DroppedCount) {
++
++ // If the Scope is a child of, or equal to the DbgValScope and is inlined at
++ // the Var's InlinedAt location, return true to signify that the Var has been
++ // dropped.
++ if (isScopeChildOfOrEqualTo(Scope, DbgValScope))
++ if (isInlinedAtChildOfOrEqualTo(DbgLoc->getInlinedAt(),
++ InlinedAtsMap[Var])) {
++ // Found another instruction in the variable's scope, so there exists a
++ // break point at which the variable could be observed. Count it as
++ // dropped.
++ DroppedCount++;
++ return true;
++ }
++ return false;
++}
++
++void DroppedVariableStats::run(DebugVariables &DbgVariables, StringRef FuncName,
++ bool Before) {
++ auto &VarIDSet = (Before ? DbgVariables.DebugVariablesBefore
++ : DbgVariables.DebugVariablesAfter);
++ auto &InlinedAtsMap = InlinedAts.back();
++ if (Before)
++ InlinedAtsMap.try_emplace(FuncName, DenseMap<VarID, DILocation *>());
++ VarIDSet = DenseSet<VarID>();
++ visitEveryDebugRecord(VarIDSet, InlinedAtsMap, FuncName, Before);
++}
++
++void DroppedVariableStats::populateVarIDSetAndInlinedMap(
++ const DILocalVariable *DbgVar, DebugLoc DbgLoc, DenseSet<VarID> &VarIDSet,
++ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
++ StringRef FuncName, bool Before) {
++ VarID Key{DbgVar->getScope(), DbgLoc->getInlinedAtScope(), DbgVar};
++ VarIDSet.insert(Key);
++ if (Before)
++ InlinedAtsMap[FuncName].try_emplace(Key, DbgLoc.getInlinedAt());
++}
++
++void DroppedVariableStatsIR::runOnFunction(const Function *F, bool Before) {
++ auto &DebugVariables = DebugVariablesStack.back()[F];
++ auto FuncName = F->getName();
++ Func = F;
++ run(DebugVariables, FuncName, Before);
++}
++
++void DroppedVariableStatsIR::calculateDroppedVarStatsOnFunction(
++ const Function *F, StringRef PassID, StringRef FuncOrModName,
++ StringRef PassLevel) {
++ Func = F;
++ StringRef FuncName = F->getName();
++ DebugVariables &DbgVariables = DebugVariablesStack.back()[F];
++ calculateDroppedStatsAndPrint(DbgVariables, FuncName, PassID, FuncOrModName,
++ PassLevel, Func);
++}
++
++void DroppedVariableStatsIR::runOnModule(const Module *M, bool Before) {
++ for (auto &F : *M)
++ runOnFunction(&F, Before);
++}
++
++void DroppedVariableStatsIR::calculateDroppedVarStatsOnModule(
++ const Module *M, StringRef PassID, StringRef FuncOrModName,
++ StringRef PassLevel) {
++ for (auto &F : *M) {
++ calculateDroppedVarStatsOnFunction(&F, PassID, FuncOrModName, PassLevel);
++ }
++}
++
++void DroppedVariableStatsIR::registerCallbacks(
++ PassInstrumentationCallbacks &PIC) {
++ if (!DroppedVariableStatsEnabled)
++ return;
++
++ PIC.registerBeforeNonSkippedPassCallback(
++ [this](StringRef P, Any IR) { return runBeforePass(IR); });
++ PIC.registerAfterPassCallback(
++ [this](StringRef P, Any IR, const PreservedAnalyses &PA) {
++ return runAfterPass(P, IR);
++ });
++ PIC.registerAfterPassInvalidatedCallback(
++ [this](StringRef P, const PreservedAnalyses &PA) { return cleanup(); });
++}
++
++void DroppedVariableStatsIR::visitEveryInstruction(
++ unsigned &DroppedCount, DenseMap<VarID, DILocation *> &InlinedAtsMap,
++ VarID Var) {
++ const DIScope *DbgValScope = std::get<0>(Var);
++ for (const auto &I : instructions(Func)) {
++ auto *DbgLoc = I.getDebugLoc().get();
++ if (!DbgLoc)
++ continue;
++ if (updateDroppedCount(DbgLoc, DbgLoc->getScope(), DbgValScope,
++ InlinedAtsMap, Var, DroppedCount))
++ break;
++ }
++}
++
++void DroppedVariableStatsIR::visitEveryDebugRecord(
++ DenseSet<VarID> &VarIDSet,
++ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
++ StringRef FuncName, bool Before) {
++ for (const auto &I : instructions(Func)) {
++ for (DbgRecord &DR : I.getDbgRecordRange()) {
++ if (auto *Dbg = dyn_cast<DbgVariableRecord>(&DR)) {
++ auto *DbgVar = Dbg->getVariable();
++ auto DbgLoc = DR.getDebugLoc();
++ populateVarIDSetAndInlinedMap(DbgVar, DbgLoc, VarIDSet, InlinedAtsMap,
++ FuncName, Before);
++ }
++ }
++ }
++}
+diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
+index 6259f8f736c8..b766517e68eb 100644
+--- a/llvm/lib/Passes/StandardInstrumentations.cpp
++++ b/llvm/lib/Passes/StandardInstrumentations.cpp
+@@ -2462,7 +2462,7 @@ StandardInstrumentations::StandardInstrumentations(
+ PrintChanged == ChangePrinter::ColourDiffVerbose ||
+ PrintChanged == ChangePrinter::ColourDiffQuiet),
+ WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
+- Verify(DebugLogging), DroppedStats(DroppedVarStats),
++ Verify(DebugLogging), DroppedStatsIR(DroppedVarStats),
+ VerifyEach(VerifyEach) {}
+
+ PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
+@@ -2523,180 +2523,6 @@ void PrintCrashIRInstrumentation::registerCallbacks(
+ });
+ }
+
+-void DroppedVariableStats::registerCallbacks(
+- PassInstrumentationCallbacks &PIC) {
+- if (!DroppedVarStats)
+- return;
+-
+- PIC.registerBeforeNonSkippedPassCallback(
+- [this](StringRef P, Any IR) { return this->runBeforePass(P, IR); });
+- PIC.registerAfterPassCallback(
+- [this](StringRef P, Any IR, const PreservedAnalyses &PA) {
+- return this->runAfterPass(P, IR, PA);
+- });
+- PIC.registerAfterPassInvalidatedCallback(
+- [this](StringRef P, const PreservedAnalyses &PA) {
+- return this->runAfterPassInvalidated(P, PA);
+- });
+-}
+-
+-void DroppedVariableStats::runBeforePass(StringRef PassID, Any IR) {
+- DebugVariablesStack.push_back({DenseMap<const Function *, DebugVariables>()});
+- InlinedAts.push_back({DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
+- if (auto *M = unwrapIR<Module>(IR))
+- return this->runOnModule(M, true);
+- if (auto *F = unwrapIR<Function>(IR))
+- return this->runOnFunction(F, true);
+-}
+-
+-void DroppedVariableStats::runOnFunction(const Function *F, bool Before) {
+- auto &DebugVariables = DebugVariablesStack.back()[F];
+- auto &VarIDSet = (Before ? DebugVariables.DebugVariablesBefore
+- : DebugVariables.DebugVariablesAfter);
+- auto &InlinedAtsMap = InlinedAts.back();
+- auto FuncName = F->getName();
+- if (Before)
+- InlinedAtsMap.try_emplace(FuncName, DenseMap<VarID, DILocation *>());
+- VarIDSet = DenseSet<VarID>();
+- for (const auto &I : instructions(F)) {
+- for (DbgRecord &DR : I.getDbgRecordRange()) {
+- if (auto *Dbg = dyn_cast<DbgVariableRecord>(&DR)) {
+- auto *DbgVar = Dbg->getVariable();
+- auto DbgLoc = DR.getDebugLoc();
+- VarID Key{DbgVar->getScope(), DbgLoc->getInlinedAtScope(), DbgVar};
+- VarIDSet.insert(Key);
+- if (Before)
+- InlinedAtsMap[FuncName].try_emplace(Key, DbgLoc.getInlinedAt());
+- }
+- }
+- }
+-}
+-
+-void DroppedVariableStats::runOnModule(const Module *M, bool Before) {
+- for (auto &F : *M)
+- runOnFunction(&F, Before);
+-}
+-
+-void DroppedVariableStats::removeVarFromAllSets(VarID Var, const Function *F) {
+- // Do not remove Var from the last element, it will be popped from the stack.
+- for (auto &DebugVariablesMap : llvm::drop_end(DebugVariablesStack))
+- DebugVariablesMap[F].DebugVariablesBefore.erase(Var);
+-}
+-
+-void DroppedVariableStats::calculateDroppedVarStatsOnModule(
+- const Module *M, StringRef PassID, std::string FuncOrModName,
+- std::string PassLevel) {
+- for (auto &F : *M) {
+- calculateDroppedVarStatsOnFunction(&F, PassID, FuncOrModName, PassLevel);
+- }
+-}
+-
+-void DroppedVariableStats::calculateDroppedVarStatsOnFunction(
+- const Function *F, StringRef PassID, std::string FuncOrModName,
+- std::string PassLevel) {
+- unsigned DroppedCount = 0;
+- StringRef FuncName = F->getName();
+- DebugVariables &DbgVariables = DebugVariablesStack.back()[F];
+- DenseSet<VarID> &DebugVariablesBeforeSet = DbgVariables.DebugVariablesBefore;
+- DenseSet<VarID> &DebugVariablesAfterSet = DbgVariables.DebugVariablesAfter;
+- DenseMap<VarID, DILocation *> &InlinedAtsMap = InlinedAts.back()[FuncName];
+- // Find an Instruction that shares the same scope as the dropped #dbg_value or
+- // has a scope that is the child of the scope of the #dbg_value, and has an
+- // inlinedAt equal to the inlinedAt of the #dbg_value or it's inlinedAt chain
+- // contains the inlinedAt of the #dbg_value, if such an Instruction is found,
+- // debug information is dropped.
+- for (VarID Var : DebugVariablesBeforeSet) {
+- if (DebugVariablesAfterSet.contains(Var))
+- continue;
+- const DIScope *DbgValScope = std::get<0>(Var);
+- for (const auto &I : instructions(F)) {
+- auto *DbgLoc = I.getDebugLoc().get();
+- if (!DbgLoc)
+- continue;
+-
+- auto *Scope = DbgLoc->getScope();
+- if (isScopeChildOfOrEqualTo(Scope, DbgValScope)) {
+- if (isInlinedAtChildOfOrEqualTo(DbgLoc->getInlinedAt(),
+- InlinedAtsMap[Var])) {
+- // Found another instruction in the variable's scope, so there exists
+- // a break point at which the variable could be observed. Count it as
+- // dropped.
+- DroppedCount++;
+- break;
+- }
+- }
+- }
+- removeVarFromAllSets(Var, F);
+- }
+- if (DroppedCount > 0) {
+- llvm::outs() << PassLevel << ", " << PassID << ", " << DroppedCount << ", "
+- << FuncOrModName << "\n";
+- PassDroppedVariables = true;
+- } else
+- PassDroppedVariables = false;
+-}
+-
+-void DroppedVariableStats::runAfterPassInvalidated(
+- StringRef PassID, const PreservedAnalyses &PA) {
+- DebugVariablesStack.pop_back();
+- InlinedAts.pop_back();
+-}
+-
+-void DroppedVariableStats::runAfterPass(StringRef PassID, Any IR,
+- const PreservedAnalyses &PA) {
+- std::string PassLevel;
+- std::string FuncOrModName;
+- if (auto *M = unwrapIR<Module>(IR)) {
+- this->runOnModule(M, false);
+- PassLevel = "Module";
+- FuncOrModName = M->getName();
+- calculateDroppedVarStatsOnModule(M, PassID, FuncOrModName, PassLevel);
+- } else if (auto *F = unwrapIR<Function>(IR)) {
+- this->runOnFunction(F, false);
+- PassLevel = "Function";
+- FuncOrModName = F->getName();
+- calculateDroppedVarStatsOnFunction(F, PassID, FuncOrModName, PassLevel);
+- }
+-
+- DebugVariablesStack.pop_back();
+- InlinedAts.pop_back();
+-}
+-
+-bool DroppedVariableStats::isScopeChildOfOrEqualTo(DIScope *Scope,
+- const DIScope *DbgValScope) {
+- while (Scope != nullptr) {
+- if (VisitedScope.find(Scope) == VisitedScope.end()) {
+- VisitedScope.insert(Scope);
+- if (Scope == DbgValScope) {
+- VisitedScope.clear();
+- return true;
+- }
+- Scope = Scope->getScope();
+- } else {
+- VisitedScope.clear();
+- return false;
+- }
+- }
+- return false;
+-}
+-
+-bool DroppedVariableStats::isInlinedAtChildOfOrEqualTo(
+- const DILocation *InlinedAt, const DILocation *DbgValInlinedAt) {
+- if (DbgValInlinedAt == InlinedAt)
+- return true;
+- if (!DbgValInlinedAt)
+- return false;
+- if (!InlinedAt)
+- return false;
+- auto *IA = InlinedAt;
+- while (IA) {
+- if (IA == DbgValInlinedAt)
+- return true;
+- IA = IA->getInlinedAt();
+- }
+- return false;
+-}
+-
+ void StandardInstrumentations::registerCallbacks(
+ PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM) {
+ PrintIR.registerCallbacks(PIC);
+@@ -2712,7 +2538,7 @@ void StandardInstrumentations::registerCallbacks(
+ WebsiteChangeReporter.registerCallbacks(PIC);
+ ChangeTester.registerCallbacks(PIC);
+ PrintCrashIR.registerCallbacks(PIC);
+- DroppedStats.registerCallbacks(PIC);
++ DroppedStatsIR.registerCallbacks(PIC);
+ if (MAM)
+ PreservedCFGChecker.registerCallbacks(PIC, *MAM);
+
+diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
+index 963cdcc0275e..807fd1a9b7b5 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
++ DroppedVariableStatsIRTest.cpp
+ DwarfStringPoolEntryRefTest.cpp
+ InstrRefLDVTest.cpp
+ LowLevelTypeTest.cpp
+diff --git a/llvm/unittests/IR/DroppedVariableStatsTest.cpp b/llvm/unittests/CodeGen/DroppedVariableStatsIRTest.cpp
+similarity index 91%
+rename from llvm/unittests/IR/DroppedVariableStatsTest.cpp
+rename to llvm/unittests/CodeGen/DroppedVariableStatsIRTest.cpp
+index 61f3a87bb355..094ec7b65763 100644
+--- a/llvm/unittests/IR/DroppedVariableStatsTest.cpp
++++ b/llvm/unittests/CodeGen/DroppedVariableStatsIRTest.cpp
+@@ -1,5 +1,4 @@
+-//===- unittests/IR/DroppedVariableStatsTest.cpp - TimePassesHandler tests
+-//----------===//
++//===- unittests/IR/DroppedVariableStatsIRTest.cpp ------------------------===//
+ //
+ // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ // See https://llvm.org/LICENSE.txt for license information.
+@@ -8,6 +7,7 @@
+ //===----------------------------------------------------------------------===//
+
+ #include "llvm/AsmParser/Parser.h"
++#include "llvm/CodeGen/DroppedVariableStats.h"
+ #include "llvm/IR/Function.h"
+ #include "llvm/IR/InstIterator.h"
+ #include "llvm/IR/LegacyPassManager.h"
+@@ -44,7 +44,7 @@ namespace {
+ // 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(DroppedVariableStats, BothDeleted) {
++TEST(DroppedVariableStatsIR, BothDeleted) {
+ PassInstrumentationCallbacks PIC;
+ PassInstrumentation PI(&PIC);
+
+@@ -79,9 +79,8 @@ TEST(DroppedVariableStats, BothDeleted) {
+ std::unique_ptr<llvm::Module> M = parseIR(C, IR);
+ ASSERT_TRUE(M);
+
+- DroppedVariableStats Stats(true);
+- Stats.runBeforePass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())));
++ DroppedVariableStatsIR Stats(true);
++ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
+
+ // This loop simulates an IR pass that drops debug information.
+ for (auto &F : *M) {
+@@ -92,16 +91,15 @@ TEST(DroppedVariableStats, BothDeleted) {
+ }
+ break;
+ }
+- PreservedAnalyses PA;
+ Stats.runAfterPass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
++ llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ 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(DroppedVariableStats, DbgValLost) {
++TEST(DroppedVariableStatsIR, DbgValLost) {
+ PassInstrumentationCallbacks PIC;
+ PassInstrumentation PI(&PIC);
+
+@@ -136,9 +134,8 @@ TEST(DroppedVariableStats, DbgValLost) {
+ std::unique_ptr<llvm::Module> M = parseIR(C, IR);
+ ASSERT_TRUE(M);
+
+- DroppedVariableStats Stats(true);
+- Stats.runBeforePass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())));
++ DroppedVariableStatsIR Stats(true);
++ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
+
+ // This loop simulates an IR pass that drops debug information.
+ for (auto &F : *M) {
+@@ -148,16 +145,15 @@ TEST(DroppedVariableStats, DbgValLost) {
+ }
+ break;
+ }
+- PreservedAnalyses PA;
+ Stats.runAfterPass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
++ llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ 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(DroppedVariableStats, UnrelatedScopes) {
++TEST(DroppedVariableStatsIR, UnrelatedScopes) {
+ PassInstrumentationCallbacks PIC;
+ PassInstrumentation PI(&PIC);
+
+@@ -193,9 +189,8 @@ TEST(DroppedVariableStats, UnrelatedScopes) {
+ std::unique_ptr<llvm::Module> M = parseIR(C, IR);
+ ASSERT_TRUE(M);
+
+- DroppedVariableStats Stats(true);
+- Stats.runBeforePass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())));
++ DroppedVariableStatsIR Stats(true);
++ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
+
+ // This loop simulates an IR pass that drops debug information.
+ for (auto &F : *M) {
+@@ -205,16 +200,15 @@ TEST(DroppedVariableStats, UnrelatedScopes) {
+ }
+ break;
+ }
+- PreservedAnalyses PA;
+ Stats.runAfterPass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
++ llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ 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(DroppedVariableStats, ChildScopes) {
++TEST(DroppedVariableStatsIR, ChildScopes) {
+ PassInstrumentationCallbacks PIC;
+ PassInstrumentation PI(&PIC);
+
+@@ -250,9 +244,8 @@ TEST(DroppedVariableStats, ChildScopes) {
+ std::unique_ptr<llvm::Module> M = parseIR(C, IR);
+ ASSERT_TRUE(M);
+
+- DroppedVariableStats Stats(true);
+- Stats.runBeforePass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())));
++ DroppedVariableStatsIR Stats(true);
++ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
+
+ // This loop simulates an IR pass that drops debug information.
+ for (auto &F : *M) {
+@@ -262,9 +255,8 @@ TEST(DroppedVariableStats, ChildScopes) {
+ }
+ break;
+ }
+- PreservedAnalyses PA;
+ Stats.runAfterPass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
++ llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ ASSERT_EQ(Stats.getPassDroppedVariables(), true);
+ }
+
+@@ -272,7 +264,7 @@ TEST(DroppedVariableStats, ChildScopes) {
+ // 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(DroppedVariableStats, InlinedAt) {
++TEST(DroppedVariableStatsIR, InlinedAt) {
+ PassInstrumentationCallbacks PIC;
+ PassInstrumentation PI(&PIC);
+
+@@ -308,9 +300,8 @@ TEST(DroppedVariableStats, InlinedAt) {
+ std::unique_ptr<llvm::Module> M = parseIR(C, IR);
+ ASSERT_TRUE(M);
+
+- DroppedVariableStats Stats(true);
+- Stats.runBeforePass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())));
++ DroppedVariableStatsIR Stats(true);
++ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
+
+ // This loop simulates an IR pass that drops debug information.
+ for (auto &F : *M) {
+@@ -320,9 +311,8 @@ TEST(DroppedVariableStats, InlinedAt) {
+ }
+ break;
+ }
+- PreservedAnalyses PA;
+ Stats.runAfterPass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
++ llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ ASSERT_EQ(Stats.getPassDroppedVariables(), false);
+ }
+
+@@ -330,7 +320,7 @@ TEST(DroppedVariableStats, InlinedAt) {
+ // 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(DroppedVariableStats, InlinedAtShared) {
++TEST(DroppedVariableStatsIR, InlinedAtShared) {
+ PassInstrumentationCallbacks PIC;
+ PassInstrumentation PI(&PIC);
+
+@@ -366,9 +356,8 @@ TEST(DroppedVariableStats, InlinedAtShared) {
+ std::unique_ptr<llvm::Module> M = parseIR(C, IR);
+ ASSERT_TRUE(M);
+
+- DroppedVariableStats Stats(true);
+- Stats.runBeforePass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())));
++ DroppedVariableStatsIR Stats(true);
++ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
+
+ // This loop simulates an IR pass that drops debug information.
+ for (auto &F : *M) {
+@@ -378,9 +367,8 @@ TEST(DroppedVariableStats, InlinedAtShared) {
+ }
+ break;
+ }
+- PreservedAnalyses PA;
+ Stats.runAfterPass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
++ llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ ASSERT_EQ(Stats.getPassDroppedVariables(), true);
+ }
+
+@@ -388,7 +376,7 @@ TEST(DroppedVariableStats, InlinedAtShared) {
+ // 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(DroppedVariableStats, InlinedAtChild) {
++TEST(DroppedVariableStatsIR, InlinedAtChild) {
+ PassInstrumentationCallbacks PIC;
+ PassInstrumentation PI(&PIC);
+
+@@ -425,9 +413,8 @@ TEST(DroppedVariableStats, InlinedAtChild) {
+ std::unique_ptr<llvm::Module> M = parseIR(C, IR);
+ ASSERT_TRUE(M);
+
+- DroppedVariableStats Stats(true);
+- Stats.runBeforePass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())));
++ DroppedVariableStatsIR Stats(true);
++ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
+
+ // This loop simulates an IR pass that drops debug information.
+ for (auto &F : *M) {
+@@ -437,9 +424,8 @@ TEST(DroppedVariableStats, InlinedAtChild) {
+ }
+ break;
+ }
+- PreservedAnalyses PA;
+ Stats.runAfterPass("Test",
+- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
++ llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ ASSERT_EQ(Stats.getPassDroppedVariables(), true);
+ }
+
+diff --git a/llvm/unittests/IR/CMakeLists.txt b/llvm/unittests/IR/CMakeLists.txt
+index ed93ee547d22..e5c8630f3eed 100644
+--- a/llvm/unittests/IR/CMakeLists.txt
++++ b/llvm/unittests/IR/CMakeLists.txt
+@@ -43,7 +43,6 @@ add_llvm_unittest(IRTests
+ ShuffleVectorInstTest.cpp
+ StructuralHashTest.cpp
+ TimePassesTest.cpp
+- DroppedVariableStatsTest.cpp
+ TypesTest.cpp
+ UseTest.cpp
+ UserTest.cpp
+--
+2.46.2
+
diff --git a/llvm/include/llvm/CodeGen/DroppedVariableStats.h b/llvm/include/llvm/CodeGen/DroppedVariableStats.h
new file mode 100644
index 00000000000000..bdef7d3ef479e6
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/DroppedVariableStats.h
@@ -0,0 +1,224 @@
+///===- DroppedVariableStats.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_value that get dropped due to an optimization pass.
+///
+///===---------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_DROPPEDVARIABLESTATS_H
+#define LLVM_CODEGEN_DROPPEDVARIABLESTATS_H
+
+#include "llvm/CodeGen/MachinePassManager.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassInstrumentation.h"
+
+namespace llvm {
+
+/// A unique key that represents a debug variable.
+/// First const DIScope *: Represents the scope of the debug variable.
+/// Second const DIScope *: Represents the InlinedAt scope of the debug
+/// variable. const DILocalVariable *: It is a pointer to the debug variable
+/// itself.
+using VarID =
+ std::tuple<const DIScope *, const DIScope *, const DILocalVariable *>;
+
+/// A base class to collect and print dropped debug information variable
+/// statistics.
+class DroppedVariableStats {
+public:
+ DroppedVariableStats(bool DroppedVarStatsEnabled)
+ : DroppedVariableStatsEnabled(DroppedVarStatsEnabled) {
+ if (DroppedVarStatsEnabled)
+ llvm::outs()
+ << "Pass Level, Pass Name, Num of Dropped Variables, Func or "
+ "Module Name\n";
+ };
+
+ virtual ~DroppedVariableStats();
+
+ // We intend this to be unique per-compilation, thus no copies.
+ DroppedVariableStats(const DroppedVariableStats &) = delete;
+ void operator=(const DroppedVariableStats &) = delete;
+
+ bool getPassDroppedVariables() { return PassDroppedVariables; }
+
+protected:
+ void setup() {
+ DebugVariablesStack.push_back(
+ {DenseMap<const Function *, DebugVariables>()});
+ InlinedAts.push_back(
+ {DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
+ }
+
+ void cleanup() {
+ assert(!DebugVariablesStack.empty() &&
+ "DebugVariablesStack shouldn't be empty!");
+ assert(!InlinedAts.empty() && "InlinedAts shouldn't be empty!");
+ DebugVariablesStack.pop_back();
+ InlinedAts.pop_back();
+ }
+
+ bool DroppedVariableStatsEnabled = false;
+ struct DebugVariables {
+ /// DenseSet of VarIDs before an optimization pass has run.
+ DenseSet<VarID> DebugVariablesBefore;
+ /// DenseSet of VarIDs after an optimization pass has run.
+ DenseSet<VarID> DebugVariablesAfter;
+ };
+
+protected:
+ /// A stack of a DenseMap, that maps DebugVariables for every pass to an
+ /// llvm::Function. A stack is used because an optimization pass can call
+ /// other passes.
+ SmallVector<DenseMap<const Function *, DebugVariables>> DebugVariablesStack;
+
+ /// A DenseSet tracking whether a scope was visited before.
+ DenseSet<const DIScope *> VisitedScope;
+ /// A stack of DenseMaps, which map the name of an llvm::Function to a
+ /// DenseMap of VarIDs and their inlinedAt locations before an optimization
+ /// pass has run.
+ SmallVector<DenseMap<StringRef, DenseMap<VarID, DILocation *>>> InlinedAts;
+ /// Calculate the number of dropped variables in an llvm::Function or
+ /// llvm::MachineFunction and print the relevant information to stdout.
+ void calculateDroppedStatsAndPrint(DebugVariables &DbgVariables,
+ StringRef FuncName, StringRef PassID,
+ StringRef FuncOrModName,
+ StringRef PassLevel, const Function *Func);
+
+ /// Check if a \p Var has been dropped or is a false positive. Also update the
+ /// \p DroppedCount if a debug variable is dropped.
+ bool updateDroppedCount(DILocation *DbgLoc, const DIScope *Scope,
+ const DIScope *DbgValScope,
+ DenseMap<VarID, DILocation *> &InlinedAtsMap,
+ VarID Var, unsigned &DroppedCount);
+ /// Run code to populate relevant data structures over an llvm::Function or
+ /// llvm::MachineFunction.
+ void run(DebugVariables &DbgVariables, StringRef FuncName, bool Before);
+ /// Populate the VarIDSet and InlinedAtMap with the relevant information
+ /// needed for before and after pass analysis to determine dropped variable
+ /// status.
+ void populateVarIDSetAndInlinedMap(
+ const DILocalVariable *DbgVar, DebugLoc DbgLoc, DenseSet<VarID> &VarIDSet,
+ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
+ StringRef FuncName, bool Before);
+ /// Visit every llvm::Instruction or llvm::MachineInstruction and check if the
+ /// debug variable denoted by its ID \p Var may have been dropped by an
+ /// optimization pass.
+ virtual void
+ visitEveryInstruction(unsigned &DroppedCount,
+ DenseMap<VarID, DILocation *> &InlinedAtsMap,
+ VarID Var) = 0;
+ /// Visit every debug record in an llvm::Function or llvm::MachineFunction
+ /// and call populateVarIDSetAndInlinedMap on it.
+ virtual void visitEveryDebugRecord(
+ DenseSet<VarID> &VarIDSet,
+ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
+ StringRef FuncName, bool Before) = 0;
+
+private:
+ /// Remove a dropped debug variable's VarID from all Sets in the
+ /// DroppedVariablesBefore stack.
+ void removeVarFromAllSets(VarID Var, const Function *F) {
+ // Do not remove Var from the last element, it will be popped from the
+ // stack.
+ for (auto &DebugVariablesMap : llvm::drop_end(DebugVariablesStack))
+ DebugVariablesMap[F].DebugVariablesBefore.erase(Var);
+ }
+ /// Return true if \p Scope is the same as \p DbgValScope or a child scope of
+ /// \p DbgValScope, return false otherwise.
+ bool isScopeChildOfOrEqualTo(const DIScope *Scope,
+ const DIScope *DbgValScope);
+ /// Return true if \p InlinedAt is the same as \p DbgValInlinedAt or part of
+ /// the InlinedAt chain, return false otherwise.
+ bool isInlinedAtChildOfOrEqualTo(const DILocation *InlinedAt,
+ const DILocation *DbgValInlinedAt);
+ bool PassDroppedVariables = false;
+};
+
+/// A class to collect and print dropped debug information due to LLVM IR
+/// optimization passes. After every LLVM IR pass is run, it will print how many
+/// #dbg_values were dropped due to that pass.
+class DroppedVariableStatsIR : public DroppedVariableStats {
+public:
+ DroppedVariableStatsIR(bool DroppedVarStatsEnabled)
+ : llvm::DroppedVariableStats(DroppedVarStatsEnabled) {}
+
+ void runBeforePass(Any IR) {
+ setup();
+ if (const auto *M = unwrapIR<Module>(IR))
+ return this->runOnModule(M, true);
+ if (const auto *F = unwrapIR<Function>(IR))
+ return this->runOnFunction(F, true);
+ }
+
+ void runAfterPass(StringRef P, Any IR) {
+ if (const auto *M = unwrapIR<Module>(IR))
+ runAfterPassModule(P, M);
+ else if (const auto *F = unwrapIR<Function>(IR))
+ runAfterPassFunction(P, F);
+ cleanup();
+ }
+
+ void registerCallbacks(PassInstrumentationCallbacks &PIC);
+
+private:
+ const Function *Func;
+
+ void runAfterPassFunction(StringRef PassID, const Function *F) {
+ runOnFunction(F, false);
+ calculateDroppedVarStatsOnFunction(F, PassID, F->getName().str(),
+ "Function");
+ }
+
+ void runAfterPassModule(StringRef PassID, const Module *M) {
+ runOnModule(M, false);
+ calculateDroppedVarStatsOnModule(M, PassID, M->getName().str(), "Module");
+ }
+ /// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
+ /// after a pass has run to facilitate dropped variable calculation for an
+ /// llvm::Function.
+ void runOnFunction(const Function *F, bool Before);
+ /// Iterate over all Instructions in a Function and report any dropped debug
+ /// information.
+ void calculateDroppedVarStatsOnFunction(const Function *F, StringRef PassID,
+ StringRef FuncOrModName,
+ StringRef PassLevel);
+ /// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
+ /// after a pass has run to facilitate dropped variable calculation for an
+ /// llvm::Module. Calls runOnFunction on every Function in the Module.
+ void runOnModule(const Module *M, bool Before);
+ /// Iterate over all Functions in a Module and report any dropped debug
+ /// information. Will call calculateDroppedVarStatsOnFunction on every
+ /// Function.
+ void calculateDroppedVarStatsOnModule(const Module *M, StringRef PassID,
+ StringRef FuncOrModName,
+ StringRef PassLevel);
+ /// Override base class method to run on an llvm::Function specifically.
+ virtual void
+ visitEveryInstruction(unsigned &DroppedCount,
+ DenseMap<VarID, DILocation *> &InlinedAtsMap,
+ VarID Var) override;
+ /// Override base class method to run on #dbg_values specifically.
+ virtual void visitEveryDebugRecord(
+ DenseSet<VarID> &VarIDSet,
+ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
+ StringRef FuncName, bool Before) override;
+
+ template <typename IRUnitT> static const IRUnitT *unwrapIR(Any IR) {
+ const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR);
+ return IRPtr ? *IRPtr : nullptr;
+ }
+};
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h
index 9301a12c740eec..12a34c099eaffe 100644
--- a/llvm/include/llvm/Passes/StandardInstrumentations.h
+++ b/llvm/include/llvm/Passes/StandardInstrumentations.h
@@ -19,6 +19,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/CodeGen/DroppedVariableStats.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DebugInfoMetadata.h"
@@ -579,83 +580,6 @@ class PrintCrashIRInstrumentation {
static void SignalHandler(void *);
};
-/// A class to collect and print dropped debug information variable statistics.
-/// After every LLVM IR pass is run, it will print how many #dbg_values were
-/// dropped due to that pass.
-class DroppedVariableStats {
-public:
- DroppedVariableStats(bool DroppedVarStatsEnabled) {
- if (DroppedVarStatsEnabled)
- llvm::outs()
- << "Pass Level, Pass Name, Num of Dropped Variables, Func or "
- "Module Name\n";
- };
- // We intend this to be unique per-compilation, thus no copies.
- DroppedVariableStats(const DroppedVariableStats &) = delete;
- void operator=(const DroppedVariableStats &) = delete;
-
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- void runBeforePass(StringRef PassID, Any IR);
- void runAfterPass(StringRef PassID, Any IR, const PreservedAnalyses &PA);
- void runAfterPassInvalidated(StringRef PassID, const PreservedAnalyses &PA);
- bool getPassDroppedVariables() { return PassDroppedVariables; }
-
-private:
- bool PassDroppedVariables = false;
- /// A unique key that represents a #dbg_value.
- using VarID =
- std::tuple<const DIScope *, const DIScope *, const DILocalVariable *>;
-
- struct DebugVariables {
- /// DenseSet of VarIDs before an optimization pass has run.
- DenseSet<VarID> DebugVariablesBefore;
- /// DenseSet of VarIDs after an optimization pass has run.
- DenseSet<VarID> DebugVariablesAfter;
- };
-
- /// A stack of a DenseMap, that maps DebugVariables for every pass to an
- /// llvm::Function. A stack is used because an optimization pass can call
- /// other passes.
- SmallVector<DenseMap<const Function *, DebugVariables>> DebugVariablesStack;
-
- /// A DenseSet tracking whether a scope was visited before.
- DenseSet<const DIScope *> VisitedScope;
- /// A stack of DenseMaps, which map the name of an llvm::Function to a
- /// DenseMap of VarIDs and their inlinedAt locations before an optimization
- /// pass has run.
- SmallVector<DenseMap<StringRef, DenseMap<VarID, DILocation *>>> InlinedAts;
-
- /// Iterate over all Functions in a Module and report any dropped debug
- /// information. Will call calculateDroppedVarStatsOnFunction on every
- /// Function.
- void calculateDroppedVarStatsOnModule(const Module *M, StringRef PassID,
- std::string FuncOrModName,
- std::string PassLevel);
- /// Iterate over all Instructions in a Function and report any dropped debug
- /// information.
- void calculateDroppedVarStatsOnFunction(const Function *F, StringRef PassID,
- std::string FuncOrModName,
- std::string PassLevel);
- /// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
- /// after a pass has run to facilitate dropped variable calculation for an
- /// llvm::Function.
- void runOnFunction(const Function *F, bool Before);
- /// Populate DebugVariablesBefore, DebugVariablesAfter, InlinedAts before or
- /// after a pass has run to facilitate dropped variable calculation for an
- /// llvm::Module. Calls runOnFunction on every Function in the Module.
- void runOnModule(const Module *M, bool Before);
- /// Remove a dropped #dbg_value VarID from all Sets in the
- /// DroppedVariablesBefore stack.
- void removeVarFromAllSets(VarID Var, const Function *F);
- /// Return true if \p Scope is the same as \p DbgValScope or a child scope of
- /// \p DbgValScope, return false otherwise.
- bool isScopeChildOfOrEqualTo(DIScope *Scope, const DIScope *DbgValScope);
- /// Return true if \p InlinedAt is the same as \p DbgValInlinedAt or part of
- /// the InlinedAt chain, return false otherwise.
- bool isInlinedAtChildOfOrEqualTo(const DILocation *InlinedAt,
- const DILocation *DbgValInlinedAt);
-};
-
/// This class provides an interface to register all the standard pass
/// instrumentations and manages their state (if any).
class StandardInstrumentations {
@@ -673,7 +597,7 @@ class StandardInstrumentations {
PrintCrashIRInstrumentation PrintCrashIR;
IRChangedTester ChangeTester;
VerifyInstrumentation Verify;
- DroppedVariableStats DroppedStats;
+ DroppedVariableStatsIR DroppedStatsIR;
bool VerifyEach;
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index 7b47c0e6f75dbe..263d4a9ee94d2e 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
+ DroppedVariableStats.cpp
DwarfEHPrepare.cpp
EarlyIfConversion.cpp
EdgeBundles.cpp
diff --git a/llvm/lib/CodeGen/DroppedVariableStats.cpp b/llvm/lib/CodeGen/DroppedVariableStats.cpp
new file mode 100644
index 00000000000000..22b54a0b19019f
--- /dev/null
+++ b/llvm/lib/CodeGen/DroppedVariableStats.cpp
@@ -0,0 +1,196 @@
+///===- DroppedVariableStats.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_value that get dropped due to an optimization pass.
+///
+///===---------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/DroppedVariableStats.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Module.h"
+
+using namespace llvm;
+
+DroppedVariableStats::~DroppedVariableStats() {}
+
+bool DroppedVariableStats::isScopeChildOfOrEqualTo(const DIScope *Scope,
+ const DIScope *DbgValScope) {
+ while (Scope != nullptr) {
+ if (VisitedScope.find(Scope) == VisitedScope.end()) {
+ VisitedScope.insert(Scope);
+ if (Scope == DbgValScope) {
+ VisitedScope.clear();
+ return true;
+ }
+ Scope = Scope->getScope();
+ } else {
+ VisitedScope.clear();
+ return false;
+ }
+ }
+ return false;
+}
+
+bool DroppedVariableStats::isInlinedAtChildOfOrEqualTo(
+ const DILocation *InlinedAt, const DILocation *DbgValInlinedAt) {
+ if (DbgValInlinedAt == InlinedAt)
+ return true;
+ if (!DbgValInlinedAt)
+ return false;
+ auto *IA = InlinedAt;
+ while (IA) {
+ if (IA == DbgValInlinedAt)
+ return true;
+ IA = IA->getInlinedAt();
+ }
+ return false;
+}
+
+void DroppedVariableStats::calculateDroppedStatsAndPrint(
+ DebugVariables &DbgVariables, StringRef FuncName, StringRef PassID,
+ StringRef FuncOrModName, StringRef PassLevel, const Function *Func) {
+ unsigned DroppedCount = 0;
+ DenseSet<VarID> &DebugVariablesBeforeSet = DbgVariables.DebugVariablesBefore;
+ DenseSet<VarID> &DebugVariablesAfterSet = DbgVariables.DebugVariablesAfter;
+ DenseMap<VarID, DILocation *> &InlinedAtsMap = InlinedAts.back()[FuncName];
+ // Find an Instruction that shares the same scope as the dropped #dbg_value or
+ // has a scope that is the child of the scope of the #dbg_value, and has an
+ // inlinedAt equal to the inlinedAt of the #dbg_value or it's inlinedAt chain
+ // contains the inlinedAt of the #dbg_value, if such an Instruction is found,
+ // debug information is dropped.
+ for (VarID Var : DebugVariablesBeforeSet) {
+ if (DebugVariablesAfterSet.contains(Var))
+ continue;
+ visitEveryInstruction(DroppedCount, InlinedAtsMap, Var);
+ removeVarFromAllSets(Var, Func);
+ }
+ if (DroppedCount > 0) {
+ llvm::outs() << PassLevel << ", " << PassID << ", " << DroppedCount << ", "
+ << FuncOrModName << "\n";
+ PassDroppedVariables = true;
+ } else
+ PassDroppedVariables = false;
+}
+
+bool DroppedVariableStats::updateDroppedCount(
+ DILocation *DbgLoc, const DIScope *Scope, const DIScope *DbgValScope,
+ DenseMap<VarID, DILocation *> &InlinedAtsMap, VarID Var,
+ unsigned &DroppedCount) {
+
+ // If the Scope is a child of, or equal to the DbgValScope and is inlined at
+ // the Var's InlinedAt location, return true to signify that the Var has been
+ // dropped.
+ if (isScopeChildOfOrEqualTo(Scope, DbgValScope))
+ if (isInlinedAtChildOfOrEqualTo(DbgLoc->getInlinedAt(),
+ InlinedAtsMap[Var])) {
+ // Found another instruction in the variable's scope, so there exists a
+ // break point at which the variable could be observed. Count it as
+ // dropped.
+ DroppedCount++;
+ return true;
+ }
+ return false;
+}
+
+void DroppedVariableStats::run(DebugVariables &DbgVariables, StringRef FuncName,
+ bool Before) {
+ auto &VarIDSet = (Before ? DbgVariables.DebugVariablesBefore
+ : DbgVariables.DebugVariablesAfter);
+ auto &InlinedAtsMap = InlinedAts.back();
+ if (Before)
+ InlinedAtsMap.try_emplace(FuncName, DenseMap<VarID, DILocation *>());
+ VarIDSet = DenseSet<VarID>();
+ visitEveryDebugRecord(VarIDSet, InlinedAtsMap, FuncName, Before);
+}
+
+void DroppedVariableStats::populateVarIDSetAndInlinedMap(
+ const DILocalVariable *DbgVar, DebugLoc DbgLoc, DenseSet<VarID> &VarIDSet,
+ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
+ StringRef FuncName, bool Before) {
+ VarID Key{DbgVar->getScope(), DbgLoc->getInlinedAtScope(), DbgVar};
+ VarIDSet.insert(Key);
+ if (Before)
+ InlinedAtsMap[FuncName].try_emplace(Key, DbgLoc.getInlinedAt());
+}
+
+void DroppedVariableStatsIR::runOnFunction(const Function *F, bool Before) {
+ auto &DebugVariables = DebugVariablesStack.back()[F];
+ auto FuncName = F->getName();
+ Func = F;
+ run(DebugVariables, FuncName, Before);
+}
+
+void DroppedVariableStatsIR::calculateDroppedVarStatsOnFunction(
+ const Function *F, StringRef PassID, StringRef FuncOrModName,
+ StringRef PassLevel) {
+ Func = F;
+ StringRef FuncName = F->getName();
+ DebugVariables &DbgVariables = DebugVariablesStack.back()[F];
+ calculateDroppedStatsAndPrint(DbgVariables, FuncName, PassID, FuncOrModName,
+ PassLevel, Func);
+}
+
+void DroppedVariableStatsIR::runOnModule(const Module *M, bool Before) {
+ for (auto &F : *M)
+ runOnFunction(&F, Before);
+}
+
+void DroppedVariableStatsIR::calculateDroppedVarStatsOnModule(
+ const Module *M, StringRef PassID, StringRef FuncOrModName,
+ StringRef PassLevel) {
+ for (auto &F : *M) {
+ calculateDroppedVarStatsOnFunction(&F, PassID, FuncOrModName, PassLevel);
+ }
+}
+
+void DroppedVariableStatsIR::registerCallbacks(
+ PassInstrumentationCallbacks &PIC) {
+ if (!DroppedVariableStatsEnabled)
+ return;
+
+ PIC.registerBeforeNonSkippedPassCallback(
+ [this](StringRef P, Any IR) { return runBeforePass(IR); });
+ PIC.registerAfterPassCallback(
+ [this](StringRef P, Any IR, const PreservedAnalyses &PA) {
+ return runAfterPass(P, IR);
+ });
+ PIC.registerAfterPassInvalidatedCallback(
+ [this](StringRef P, const PreservedAnalyses &PA) { return cleanup(); });
+}
+
+void DroppedVariableStatsIR::visitEveryInstruction(
+ unsigned &DroppedCount, DenseMap<VarID, DILocation *> &InlinedAtsMap,
+ VarID Var) {
+ const DIScope *DbgValScope = std::get<0>(Var);
+ for (const auto &I : instructions(Func)) {
+ auto *DbgLoc = I.getDebugLoc().get();
+ if (!DbgLoc)
+ continue;
+ if (updateDroppedCount(DbgLoc, DbgLoc->getScope(), DbgValScope,
+ InlinedAtsMap, Var, DroppedCount))
+ break;
+ }
+}
+
+void DroppedVariableStatsIR::visitEveryDebugRecord(
+ DenseSet<VarID> &VarIDSet,
+ DenseMap<StringRef, DenseMap<VarID, DILocation *>> &InlinedAtsMap,
+ StringRef FuncName, bool Before) {
+ for (const auto &I : instructions(Func)) {
+ for (DbgRecord &DR : I.getDbgRecordRange()) {
+ if (auto *Dbg = dyn_cast<DbgVariableRecord>(&DR)) {
+ auto *DbgVar = Dbg->getVariable();
+ auto DbgLoc = DR.getDebugLoc();
+ populateVarIDSetAndInlinedMap(DbgVar, DbgLoc, VarIDSet, InlinedAtsMap,
+ FuncName, Before);
+ }
+ }
+ }
+}
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index 6259f8f736c80b..b766517e68eba5 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -2462,7 +2462,7 @@ StandardInstrumentations::StandardInstrumentations(
PrintChanged == ChangePrinter::ColourDiffVerbose ||
PrintChanged == ChangePrinter::ColourDiffQuiet),
WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
- Verify(DebugLogging), DroppedStats(DroppedVarStats),
+ Verify(DebugLogging), DroppedStatsIR(DroppedVarStats),
VerifyEach(VerifyEach) {}
PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
@@ -2523,180 +2523,6 @@ void PrintCrashIRInstrumentation::registerCallbacks(
});
}
-void DroppedVariableStats::registerCallbacks(
- PassInstrumentationCallbacks &PIC) {
- if (!DroppedVarStats)
- return;
-
- PIC.registerBeforeNonSkippedPassCallback(
- [this](StringRef P, Any IR) { return this->runBeforePass(P, IR); });
- PIC.registerAfterPassCallback(
- [this](StringRef P, Any IR, const PreservedAnalyses &PA) {
- return this->runAfterPass(P, IR, PA);
- });
- PIC.registerAfterPassInvalidatedCallback(
- [this](StringRef P, const PreservedAnalyses &PA) {
- return this->runAfterPassInvalidated(P, PA);
- });
-}
-
-void DroppedVariableStats::runBeforePass(StringRef PassID, Any IR) {
- DebugVariablesStack.push_back({DenseMap<const Function *, DebugVariables>()});
- InlinedAts.push_back({DenseMap<StringRef, DenseMap<VarID, DILocation *>>()});
- if (auto *M = unwrapIR<Module>(IR))
- return this->runOnModule(M, true);
- if (auto *F = unwrapIR<Function>(IR))
- return this->runOnFunction(F, true);
-}
-
-void DroppedVariableStats::runOnFunction(const Function *F, bool Before) {
- auto &DebugVariables = DebugVariablesStack.back()[F];
- auto &VarIDSet = (Before ? DebugVariables.DebugVariablesBefore
- : DebugVariables.DebugVariablesAfter);
- auto &InlinedAtsMap = InlinedAts.back();
- auto FuncName = F->getName();
- if (Before)
- InlinedAtsMap.try_emplace(FuncName, DenseMap<VarID, DILocation *>());
- VarIDSet = DenseSet<VarID>();
- for (const auto &I : instructions(F)) {
- for (DbgRecord &DR : I.getDbgRecordRange()) {
- if (auto *Dbg = dyn_cast<DbgVariableRecord>(&DR)) {
- auto *DbgVar = Dbg->getVariable();
- auto DbgLoc = DR.getDebugLoc();
- VarID Key{DbgVar->getScope(), DbgLoc->getInlinedAtScope(), DbgVar};
- VarIDSet.insert(Key);
- if (Before)
- InlinedAtsMap[FuncName].try_emplace(Key, DbgLoc.getInlinedAt());
- }
- }
- }
-}
-
-void DroppedVariableStats::runOnModule(const Module *M, bool Before) {
- for (auto &F : *M)
- runOnFunction(&F, Before);
-}
-
-void DroppedVariableStats::removeVarFromAllSets(VarID Var, const Function *F) {
- // Do not remove Var from the last element, it will be popped from the stack.
- for (auto &DebugVariablesMap : llvm::drop_end(DebugVariablesStack))
- DebugVariablesMap[F].DebugVariablesBefore.erase(Var);
-}
-
-void DroppedVariableStats::calculateDroppedVarStatsOnModule(
- const Module *M, StringRef PassID, std::string FuncOrModName,
- std::string PassLevel) {
- for (auto &F : *M) {
- calculateDroppedVarStatsOnFunction(&F, PassID, FuncOrModName, PassLevel);
- }
-}
-
-void DroppedVariableStats::calculateDroppedVarStatsOnFunction(
- const Function *F, StringRef PassID, std::string FuncOrModName,
- std::string PassLevel) {
- unsigned DroppedCount = 0;
- StringRef FuncName = F->getName();
- DebugVariables &DbgVariables = DebugVariablesStack.back()[F];
- DenseSet<VarID> &DebugVariablesBeforeSet = DbgVariables.DebugVariablesBefore;
- DenseSet<VarID> &DebugVariablesAfterSet = DbgVariables.DebugVariablesAfter;
- DenseMap<VarID, DILocation *> &InlinedAtsMap = InlinedAts.back()[FuncName];
- // Find an Instruction that shares the same scope as the dropped #dbg_value or
- // has a scope that is the child of the scope of the #dbg_value, and has an
- // inlinedAt equal to the inlinedAt of the #dbg_value or it's inlinedAt chain
- // contains the inlinedAt of the #dbg_value, if such an Instruction is found,
- // debug information is dropped.
- for (VarID Var : DebugVariablesBeforeSet) {
- if (DebugVariablesAfterSet.contains(Var))
- continue;
- const DIScope *DbgValScope = std::get<0>(Var);
- for (const auto &I : instructions(F)) {
- auto *DbgLoc = I.getDebugLoc().get();
- if (!DbgLoc)
- continue;
-
- auto *Scope = DbgLoc->getScope();
- if (isScopeChildOfOrEqualTo(Scope, DbgValScope)) {
- if (isInlinedAtChildOfOrEqualTo(DbgLoc->getInlinedAt(),
- InlinedAtsMap[Var])) {
- // Found another instruction in the variable's scope, so there exists
- // a break point at which the variable could be observed. Count it as
- // dropped.
- DroppedCount++;
- break;
- }
- }
- }
- removeVarFromAllSets(Var, F);
- }
- if (DroppedCount > 0) {
- llvm::outs() << PassLevel << ", " << PassID << ", " << DroppedCount << ", "
- << FuncOrModName << "\n";
- PassDroppedVariables = true;
- } else
- PassDroppedVariables = false;
-}
-
-void DroppedVariableStats::runAfterPassInvalidated(
- StringRef PassID, const PreservedAnalyses &PA) {
- DebugVariablesStack.pop_back();
- InlinedAts.pop_back();
-}
-
-void DroppedVariableStats::runAfterPass(StringRef PassID, Any IR,
- const PreservedAnalyses &PA) {
- std::string PassLevel;
- std::string FuncOrModName;
- if (auto *M = unwrapIR<Module>(IR)) {
- this->runOnModule(M, false);
- PassLevel = "Module";
- FuncOrModName = M->getName();
- calculateDroppedVarStatsOnModule(M, PassID, FuncOrModName, PassLevel);
- } else if (auto *F = unwrapIR<Function>(IR)) {
- this->runOnFunction(F, false);
- PassLevel = "Function";
- FuncOrModName = F->getName();
- calculateDroppedVarStatsOnFunction(F, PassID, FuncOrModName, PassLevel);
- }
-
- DebugVariablesStack.pop_back();
- InlinedAts.pop_back();
-}
-
-bool DroppedVariableStats::isScopeChildOfOrEqualTo(DIScope *Scope,
- const DIScope *DbgValScope) {
- while (Scope != nullptr) {
- if (VisitedScope.find(Scope) == VisitedScope.end()) {
- VisitedScope.insert(Scope);
- if (Scope == DbgValScope) {
- VisitedScope.clear();
- return true;
- }
- Scope = Scope->getScope();
- } else {
- VisitedScope.clear();
- return false;
- }
- }
- return false;
-}
-
-bool DroppedVariableStats::isInlinedAtChildOfOrEqualTo(
- const DILocation *InlinedAt, const DILocation *DbgValInlinedAt) {
- if (DbgValInlinedAt == InlinedAt)
- return true;
- if (!DbgValInlinedAt)
- return false;
- if (!InlinedAt)
- return false;
- auto *IA = InlinedAt;
- while (IA) {
- if (IA == DbgValInlinedAt)
- return true;
- IA = IA->getInlinedAt();
- }
- return false;
-}
-
void StandardInstrumentations::registerCallbacks(
PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM) {
PrintIR.registerCallbacks(PIC);
@@ -2712,7 +2538,7 @@ void StandardInstrumentations::registerCallbacks(
WebsiteChangeReporter.registerCallbacks(PIC);
ChangeTester.registerCallbacks(PIC);
PrintCrashIR.registerCallbacks(PIC);
- DroppedStats.registerCallbacks(PIC);
+ DroppedStatsIR.registerCallbacks(PIC);
if (MAM)
PreservedCFGChecker.registerCallbacks(PIC, *MAM);
diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index 963cdcc0275e16..807fd1a9b7b568 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
+ DroppedVariableStatsIRTest.cpp
DwarfStringPoolEntryRefTest.cpp
InstrRefLDVTest.cpp
LowLevelTypeTest.cpp
diff --git a/llvm/unittests/IR/DroppedVariableStatsTest.cpp b/llvm/unittests/CodeGen/DroppedVariableStatsIRTest.cpp
similarity index 91%
rename from llvm/unittests/IR/DroppedVariableStatsTest.cpp
rename to llvm/unittests/CodeGen/DroppedVariableStatsIRTest.cpp
index 61f3a87bb355e0..094ec7b6576344 100644
--- a/llvm/unittests/IR/DroppedVariableStatsTest.cpp
+++ b/llvm/unittests/CodeGen/DroppedVariableStatsIRTest.cpp
@@ -1,5 +1,4 @@
-//===- unittests/IR/DroppedVariableStatsTest.cpp - TimePassesHandler tests
-//----------===//
+//===- unittests/IR/DroppedVariableStatsIRTest.cpp ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -8,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/AsmParser/Parser.h"
+#include "llvm/CodeGen/DroppedVariableStats.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/LegacyPassManager.h"
@@ -44,7 +44,7 @@ namespace {
// 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(DroppedVariableStats, BothDeleted) {
+TEST(DroppedVariableStatsIR, BothDeleted) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);
@@ -79,9 +79,8 @@ TEST(DroppedVariableStats, BothDeleted) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);
- DroppedVariableStats Stats(true);
- Stats.runBeforePass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ DroppedVariableStatsIR Stats(true);
+ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
@@ -92,16 +91,15 @@ TEST(DroppedVariableStats, BothDeleted) {
}
break;
}
- PreservedAnalyses PA;
Stats.runAfterPass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
+ llvm::Any(const_cast<const llvm::Module *>(M.get())));
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(DroppedVariableStats, DbgValLost) {
+TEST(DroppedVariableStatsIR, DbgValLost) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);
@@ -136,9 +134,8 @@ TEST(DroppedVariableStats, DbgValLost) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);
- DroppedVariableStats Stats(true);
- Stats.runBeforePass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ DroppedVariableStatsIR Stats(true);
+ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
@@ -148,16 +145,15 @@ TEST(DroppedVariableStats, DbgValLost) {
}
break;
}
- PreservedAnalyses PA;
Stats.runAfterPass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
+ llvm::Any(const_cast<const llvm::Module *>(M.get())));
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(DroppedVariableStats, UnrelatedScopes) {
+TEST(DroppedVariableStatsIR, UnrelatedScopes) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);
@@ -193,9 +189,8 @@ TEST(DroppedVariableStats, UnrelatedScopes) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);
- DroppedVariableStats Stats(true);
- Stats.runBeforePass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ DroppedVariableStatsIR Stats(true);
+ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
@@ -205,16 +200,15 @@ TEST(DroppedVariableStats, UnrelatedScopes) {
}
break;
}
- PreservedAnalyses PA;
Stats.runAfterPass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
+ llvm::Any(const_cast<const llvm::Module *>(M.get())));
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(DroppedVariableStats, ChildScopes) {
+TEST(DroppedVariableStatsIR, ChildScopes) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);
@@ -250,9 +244,8 @@ TEST(DroppedVariableStats, ChildScopes) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);
- DroppedVariableStats Stats(true);
- Stats.runBeforePass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ DroppedVariableStatsIR Stats(true);
+ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
@@ -262,9 +255,8 @@ TEST(DroppedVariableStats, ChildScopes) {
}
break;
}
- PreservedAnalyses PA;
Stats.runAfterPass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
+ llvm::Any(const_cast<const llvm::Module *>(M.get())));
ASSERT_EQ(Stats.getPassDroppedVariables(), true);
}
@@ -272,7 +264,7 @@ TEST(DroppedVariableStats, ChildScopes) {
// 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(DroppedVariableStats, InlinedAt) {
+TEST(DroppedVariableStatsIR, InlinedAt) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);
@@ -308,9 +300,8 @@ TEST(DroppedVariableStats, InlinedAt) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);
- DroppedVariableStats Stats(true);
- Stats.runBeforePass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ DroppedVariableStatsIR Stats(true);
+ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
@@ -320,9 +311,8 @@ TEST(DroppedVariableStats, InlinedAt) {
}
break;
}
- PreservedAnalyses PA;
Stats.runAfterPass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
+ llvm::Any(const_cast<const llvm::Module *>(M.get())));
ASSERT_EQ(Stats.getPassDroppedVariables(), false);
}
@@ -330,7 +320,7 @@ TEST(DroppedVariableStats, InlinedAt) {
// 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(DroppedVariableStats, InlinedAtShared) {
+TEST(DroppedVariableStatsIR, InlinedAtShared) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);
@@ -366,9 +356,8 @@ TEST(DroppedVariableStats, InlinedAtShared) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);
- DroppedVariableStats Stats(true);
- Stats.runBeforePass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ DroppedVariableStatsIR Stats(true);
+ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
@@ -378,9 +367,8 @@ TEST(DroppedVariableStats, InlinedAtShared) {
}
break;
}
- PreservedAnalyses PA;
Stats.runAfterPass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
+ llvm::Any(const_cast<const llvm::Module *>(M.get())));
ASSERT_EQ(Stats.getPassDroppedVariables(), true);
}
@@ -388,7 +376,7 @@ TEST(DroppedVariableStats, InlinedAtShared) {
// 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(DroppedVariableStats, InlinedAtChild) {
+TEST(DroppedVariableStatsIR, InlinedAtChild) {
PassInstrumentationCallbacks PIC;
PassInstrumentation PI(&PIC);
@@ -425,9 +413,8 @@ TEST(DroppedVariableStats, InlinedAtChild) {
std::unique_ptr<llvm::Module> M = parseIR(C, IR);
ASSERT_TRUE(M);
- DroppedVariableStats Stats(true);
- Stats.runBeforePass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())));
+ DroppedVariableStatsIR Stats(true);
+ Stats.runBeforePass(llvm::Any(const_cast<const llvm::Module *>(M.get())));
// This loop simulates an IR pass that drops debug information.
for (auto &F : *M) {
@@ -437,9 +424,8 @@ TEST(DroppedVariableStats, InlinedAtChild) {
}
break;
}
- PreservedAnalyses PA;
Stats.runAfterPass("Test",
- llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
+ llvm::Any(const_cast<const llvm::Module *>(M.get())));
ASSERT_EQ(Stats.getPassDroppedVariables(), true);
}
diff --git a/llvm/unittests/IR/CMakeLists.txt b/llvm/unittests/IR/CMakeLists.txt
index ed93ee547d2231..e5c8630f3eed77 100644
--- a/llvm/unittests/IR/CMakeLists.txt
+++ b/llvm/unittests/IR/CMakeLists.txt
@@ -43,7 +43,6 @@ add_llvm_unittest(IRTests
ShuffleVectorInstTest.cpp
StructuralHashTest.cpp
TimePassesTest.cpp
- DroppedVariableStatsTest.cpp
TypesTest.cpp
UseTest.cpp
UserTest.cpp
More information about the llvm-commits
mailing list