blob: 91f3d9ccbd6556ac5eb534bddd1ef6cf98c169f9 [file] [log] [blame]
//===- unittests/CodeGen/DroppedVariableStatsMIRTest.cpp ------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/DroppedVariableStatsMIR.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/CodeGen/MIRParser/MIRParser.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Pass.h"
#include "llvm/Support/SourceMgr.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 TargetStr, StringRef CPU, StringRef FS) {
std::string Error;
Triple TT(TargetStr);
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
hasEHContTarget: 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--"), "", "");
if (!TM)
return;
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
hasEHContTarget: 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--"), "", "");
if (!TM)
return;
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
hasEHContTarget: 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--"), "", "");
if (!TM)
return;
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
hasEHContTarget: 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--"), "", "");
if (!TM)
return;
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
hasEHContTarget: 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--"), "", "");
if (!TM)
return;
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
hasEHContTarget: 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--"), "", "");
if (!TM)
return;
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
hasEHContTarget: 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--"), "", "");
if (!TM)
return;
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