369 changes: 280 additions & 89 deletions llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp

Large diffs are not rendered by default.

63 changes: 47 additions & 16 deletions llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,9 @@ class MLocTracker {
void writeRegMask(const MachineOperand *MO, unsigned CurBB, unsigned InstID);

/// Find LocIdx for SpillLoc \p L, creating a new one if it's not tracked.
SpillLocationNo getOrTrackSpillLoc(SpillLoc L);
/// Returns None when in scenarios where a spill slot could be tracked, but
/// we would likely run into resource limitations.
Optional<SpillLocationNo> getOrTrackSpillLoc(SpillLoc L);

// Get LocIdx of a spill ID.
LocIdx getSpillMLoc(unsigned SpillID) {
Expand Down Expand Up @@ -678,7 +680,7 @@ class VLocTracker {
/// movement of values between locations inside of a block is handled at a
/// much later stage, in the TransferTracker class.
MapVector<DebugVariable, DbgValue> Vars;
DenseMap<DebugVariable, const DILocation *> Scopes;
SmallDenseMap<DebugVariable, const DILocation *, 8> Scopes;
MachineBasicBlock *MBB = nullptr;
const OverlapMap &OverlappingFragments;
DbgValueProperties EmptyProperties;
Expand Down Expand Up @@ -747,6 +749,11 @@ class VLocTracker {
Scopes[Overlapped] = Loc;
}
}

void clear() {
Vars.clear();
Scopes.clear();
}
};

// XXX XXX docs
Expand Down Expand Up @@ -862,6 +869,12 @@ class InstrRefBasedLDV : public LDVImpl {
OverlapMap OverlapFragments;
VarToFragments SeenFragments;

/// Mapping of DBG_INSTR_REF instructions to their values, for those
/// DBG_INSTR_REFs that call resolveDbgPHIs. These variable references solve
/// a mini SSA problem caused by DBG_PHIs being cloned, this collection caches
/// the result.
DenseMap<MachineInstr *, Optional<ValueIDNum>> SeenDbgPHIs;

/// True if we need to examine call instructions for stack clobbers. We
/// normally assume that they don't clobber SP, but stack probes on Windows
/// do.
Expand All @@ -873,7 +886,8 @@ class InstrRefBasedLDV : public LDVImpl {
StringRef StackProbeSymbolName;

/// Tests whether this instruction is a spill to a stack slot.
bool isSpillInstruction(const MachineInstr &MI, MachineFunction *MF);
Optional<SpillLocationNo> isSpillInstruction(const MachineInstr &MI,
MachineFunction *MF);

/// Decide if @MI is a spill instruction and return true if it is. We use 2
/// criteria to make this decision:
Expand All @@ -891,7 +905,8 @@ class InstrRefBasedLDV : public LDVImpl {

/// Given a spill instruction, extract the spill slot information, ensure it's
/// tracked, and return the spill number.
SpillLocationNo extractSpillBaseRegAndOffset(const MachineInstr &MI);
Optional<SpillLocationNo>
extractSpillBaseRegAndOffset(const MachineInstr &MI);

/// Observe a single instruction while stepping through a block.
void process(MachineInstr &MI, ValueIDNum **MLiveOuts = nullptr,
Expand Down Expand Up @@ -940,6 +955,12 @@ class InstrRefBasedLDV : public LDVImpl {
ValueIDNum **MLiveIns, MachineInstr &Here,
uint64_t InstrNum);

Optional<ValueIDNum> resolveDbgPHIsImpl(MachineFunction &MF,
ValueIDNum **MLiveOuts,
ValueIDNum **MLiveIns,
MachineInstr &Here,
uint64_t InstrNum);

/// Step through the function, recording register definitions and movements
/// in an MLocTracker. Convert the observations into a per-block transfer
/// function in \p MLocTransfer, suitable for using with the machine value
Expand Down Expand Up @@ -1050,18 +1071,6 @@ class InstrRefBasedLDV : public LDVImpl {
const LiveIdxT &LiveOuts, ValueIDNum **MOutLocs,
const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders);

/// Given the solutions to the two dataflow problems, machine value locations
/// in \p MInLocs and live-in variable values in \p SavedLiveIns, runs the
/// TransferTracker class over the function to produce live-in and transfer
/// DBG_VALUEs, then inserts them. Groups of DBG_VALUEs are inserted in the
/// order given by AllVarsNumbering -- this could be any stable order, but
/// right now "order of appearence in function, when explored in RPO", so
/// that we can compare explictly against VarLocBasedImpl.
void emitLocations(MachineFunction &MF, LiveInsT SavedLiveIns,
ValueIDNum **MOutLocs, ValueIDNum **MInLocs,
DenseMap<DebugVariable, unsigned> &AllVarsNumbering,
const TargetPassConfig &TPC);

/// Take collections of DBG_VALUE instructions stored in TTracker, and
/// install them into their output blocks. Preserves a stable order of
/// DBG_VALUEs produced (which would otherwise cause nondeterminism) through
Expand All @@ -1072,6 +1081,28 @@ class InstrRefBasedLDV : public LDVImpl {
/// RPOT block ordering.
void initialSetup(MachineFunction &MF);

/// Produce a map of the last lexical scope that uses a block, using the
/// scopes DFSOut number. Mapping is block-number to DFSOut.
/// \p EjectionMap Pre-allocated vector in which to install the built ma.
/// \p ScopeToDILocation Mapping of LexicalScopes to their DILocations.
/// \p AssignBlocks Map of blocks where assignments happen for a scope.
void makeDepthFirstEjectionMap(SmallVectorImpl<unsigned> &EjectionMap,
const ScopeToDILocT &ScopeToDILocation,
ScopeToAssignBlocksT &AssignBlocks);

/// When determining per-block variable values and emitting to DBG_VALUEs,
/// this function explores by lexical scope depth. Doing so means that per
/// block information can be fully computed before exploration finishes,
/// allowing us to emit it and free data structures earlier than otherwise.
/// It's also good for locality.
bool depthFirstVLocAndEmit(
unsigned MaxNumBlocks, const ScopeToDILocT &ScopeToDILocation,
const ScopeToVarsT &ScopeToVars, ScopeToAssignBlocksT &ScopeToBlocks,
LiveInsT &Output, ValueIDNum **MOutLocs, ValueIDNum **MInLocs,
SmallVectorImpl<VLocTracker> &AllTheVLocs, MachineFunction &MF,
DenseMap<DebugVariable, unsigned> &AllVarsNumbering,
const TargetPassConfig &TPC);

bool ExtendRanges(MachineFunction &MF, MachineDominatorTree *DomTree,
TargetPassConfig *TPC, unsigned InputBBLimit,
unsigned InputDbgValLimit) override;
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/LiveDebugValues/LiveDebugValues.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ bool LiveDebugValues::runOnMachineFunction(MachineFunction &MF) {
}

bool llvm::debuginfoShouldUseDebugInstrRef(const Triple &T) {
// Enable by default on x86_64, disable if explicitly turned off on cmdline.
if (T.getArch() == llvm::Triple::x86_64 &&
ValueTrackingVariableLocations != cl::boolOrDefault::BOU_FALSE)
return true;

// Enable if explicitly requested on command line.
return ValueTrackingVariableLocations == cl::boolOrDefault::BOU_TRUE;
}
65 changes: 63 additions & 2 deletions llvm/test/DebugInfo/MIR/InstrRef/single-assign-propagation.mir
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# RUN: llc %s -march=x86-64 -run-pass=livedebugvalues -o - \
# RUN: -experimental-debug-variable-locations=true \
# RUN: | FileCheck %s -implicit-check-not=DBG_VALUE
# RUN: | FileCheck %s -implicit-check-not=DBG_VALUE \
# RUN: --check-prefixes=CHECK,COMMON
# RUN: llc %s -march=x86-64 -run-pass=livedebugvalues -o - \
# RUN: -experimental-debug-variable-locations=false \
# RUN: | FileCheck %s --check-prefixes=VARLOC -implicit-check-not=DBG_VALUE
# RUN: | FileCheck %s -implicit-check-not=DBG_VALUE \
# RUN: --check-prefixes=VARLOC,COMMON
#
# This test is designed to stimulate a simplification of variable-value
# propagation in InstrRefBasedLDV. When we only have a single assignment of
Expand Down Expand Up @@ -63,12 +65,23 @@
# VARLOC-LABEL: bb.3:
# VARLOC: DBG_VALUE
#
## Common tail for 'test2' -- this is checking that the assignment of undef or
## $noreg in single-assignment mode doesn't lead to trouble further down the
## line, specifically assertion failures.
#
# COMMON-LABEL: name: test2
# COMMON: DBG_VALUE $noreg
--- |
define i32 @_Z8bb_to_bb() local_unnamed_addr !dbg !12 {
entry:
ret i32 0, !dbg !17
}

define i32 @test2() local_unnamed_addr !dbg !112 {
entry:
ret i32 0, !dbg !117
}

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!7, !8, !9, !10}
!llvm.ident = !{!11}
Expand All @@ -94,6 +107,13 @@
!18 = distinct !DILexicalBlock(scope: !12, file: !1, line: 1, column: 1)
!19 = distinct !DILexicalBlock(scope: !12, file: !1, line: 1, column: 1)
!20 = !DILocation(line: 10, scope: !19)
!112 = distinct !DISubprogram(name: "test2", linkageName: "102", scope: !1, file: !1, line: 6, type: !13, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !115)
!115 = !{!116}
!116 = !DILocalVariable(name: "myVar", scope: !118, file: !1, line: 7, type: !6)
!117 = !DILocation(line: 10, scope: !118)
!118 = distinct !DILexicalBlock(scope: !112, file: !1, line: 1, column: 1)
!119 = distinct !DILexicalBlock(scope: !112, file: !1, line: 1, column: 1)
!120 = !DILocation(line: 10, scope: !119)

...
---
Expand Down Expand Up @@ -136,3 +156,44 @@ body: |
bb.6:
RET 0, debug-location !17
...
---
name: test2
debugValueSubstitutions:
- { srcinst: 4, srcop: 0, dstinst: 3, dstop: 0, subreg: 0 }
body: |
bb.0.entry:
successors: %bb.1, %bb.5, %bb.6
$rax = MOV64ri 1, debug-instr-number 1, debug-location !117
JCC_1 %bb.5, 1, implicit $eflags
JCC_1 %bb.6, 2, implicit $eflags
JMP_1 %bb.1
bb.1:
successors: %bb.2, %bb.3
DBG_VALUE $noreg, $noreg, !116, !DIExpression(), debug-location !117
JCC_1 %bb.3, 1, implicit $eflags, debug-location !117
bb.2:
successors: %bb.4
JMP_1 %bb.4, debug-location !120
bb.3:
successors: %bb.4
JMP_1 %bb.4, debug-location !117
bb.4:
successors: %bb.5, %bb.6
JCC_1 %bb.5, 1, implicit $eflags, debug-location !117
JMP_1 %bb.6, debug-location !117
bb.5:
RET 0, debug-location !117
bb.6:
RET 0, debug-location !117
90 changes: 90 additions & 0 deletions llvm/test/DebugInfo/MIR/InstrRef/spill-slot-limits.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# RUN: llc %s -o - -experimental-debug-variable-locations \
# RUN: -mtriple=x86_64-unknown-unknown \
# RUN: -run-pass=livedebugvalues -livedebugvalues-max-stack-slots=0 | \
# RUN: FileCheck %s --implicit-check-not=DBG_VALUE
# RUN: llc %s -o - -experimental-debug-variable-locations \
# RUN: -mtriple=x86_64-unknown-unknown \
# RUN: -run-pass=livedebugvalues -livedebugvalues-max-stack-slots=100 | \
# RUN: FileCheck %s --check-prefixes=NOLIMIT --implicit-check-not=DBG_VALUE
#
# Test that spills of live values to the stack are NOT tracked by
# LiveDebugValues if an internal accounting limit is exceeded -- in this test,
# set to zero. This is to avoid scenarios where we track thousands of stack
# slots, which can show up with autogenerated code and/or asan.
#
# This is a copy of livedebugvalues_stackslot_subregs.mir, here the stack slot
# limit is set to zero, meaning the spill shouldn't be tracked.
#
## Capture variable num,
# CHECK: ![[VARNUM:[0-9]+]] = !DILocalVariable
#
## There should be no variable location, just a single DBG_VALUE $noreg.
# CHECK: DBG_VALUE $noreg
#
## And then another.
# CHECK: DBG_VALUE $noreg
#
## Test that if there's no limit, we _do_ get some locations.
# NOLIMIT: DBG_INSTR_REF 1, 0
# NOLIMIT-NEXT: DBG_VALUE $esi
#
# NOLIMIT: DBG_INSTR_REF 5,
# NOLIMIT-NEXT: DBG_VALUE $rsp
--- |
define i8 @test(i32 %bar) local_unnamed_addr !dbg !7 {
entry:
ret i8 0, !dbg !12
}

declare dso_local void @ext(i64)

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5, !6}
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
!1 = !DIFile(filename: "foo.cpp", directory: ".")
!2 = !DIBasicType(name: "int", size: 8, encoding: DW_ATE_signed)
!3 = !{i32 2, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 2}
!6 = !{i32 7, !"PIC Level", i32 2}
!7 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: !1, file: !1, line: 6, type: !8, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10)
!8 = !DISubroutineType(types: !9)
!9 = !{!2, !2}
!10 = !{!11}
!11 = !DILocalVariable(name: "baz", scope: !7, file: !1, line: 7, type: !2)
!12 = !DILocation(line: 10, scope: !7)
...
---
name: test
tracksRegLiveness: true
liveins:
- { reg: '$rdi', virtual-reg: '' }
stack:
- { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
stack-id: default, callee-saved-register: '', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
body: |
bb.0:
liveins: $rdi, $rax, $rbx
$eax = MOV32ri 0, debug-instr-number 1
$edi = COPY $eax
MOV64mr $rsp, 1, $noreg, 16, $noreg, $rdi :: (store 8 into %stack.0)
$rsi = MOV64rm $rsp, 1, $noreg, 8, $noreg :: (load 8 from %stack.0)
MOV64mr $rsp, 1, $noreg, 16, $noreg, $rbx :: (store 8 into %stack.0)
$rax = MOV64ri 0
$rdi = MOV64ri 0
DBG_INSTR_REF 1, 0, !11, !DIExpression(), debug-location !12
; This shouldn't find anything -- we have disabled tracking of spills.
; In addition to plain spills, spills that are folded into instructions
; shouldn't be tracked either.
INC32m $rsp, 1, $noreg, 4, $noreg, implicit-def dead $eflags, debug-instr-number 5, debug-location !12 :: (store (s32) into %stack.0)
DBG_INSTR_REF 5, 1000000, !11, !DIExpression(), debug-location !12
; Shouldn't be able to find the reference to instr 5's memory operand.
RET64 $rsi, debug-location !12
...
4 changes: 0 additions & 4 deletions llvm/test/DebugInfo/X86/instr-ref-flag.ll
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@
;; by llc by default, and that it can be turned explicitly on or off as
;; desired.

;; Xfail due to faults found in the discussion on
;; https://reviews.llvm.org/D116821
; XFAIL: *

; INSTRREFON: DBG_INSTR_REF
; INSTRREFOFF: DBG_VALUE

Expand Down
14 changes: 7 additions & 7 deletions llvm/unittests/CodeGen/InstrRefLDVTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ TEST_F(InstrRefLDVTest, MTransferCopies) {
// it's not completely clear why, but here we only care about correctly
// identifying the slot, not that all the surrounding data is correct.
SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
SpillLocationNo SpillNo = MTracker->getOrTrackSpillLoc(L);
SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
unsigned SpillLocID = MTracker->getLocID(SpillNo, {64, 0});
LocIdx SpillLoc = MTracker->getSpillMLoc(SpillLocID);
ValueIDNum V = MTracker->readMLoc(SpillLoc);
Expand Down Expand Up @@ -766,7 +766,7 @@ TEST_F(InstrRefLDVTest, MTransferSubregSpills) {
ValueIDNum DefNum(0, 1, RegLoc);
// Read the corresponding subreg field from the stack.
SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
SpillLocationNo SpillNo = MTracker->getOrTrackSpillLoc(L);
SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
unsigned SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
Expand Down Expand Up @@ -803,7 +803,7 @@ TEST_F(InstrRefLDVTest, MTransferSubregSpills) {
// $rbx should contain something else; today it's a def at the spill point
// of the 4 byte value.
SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
SpillLocationNo SpillNo = MTracker->getOrTrackSpillLoc(L);
SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
unsigned SpillID = MTracker->getLocID(SpillNo, {64, 0});
LocIdx Spill64Loc = MTracker->getSpillMLoc(SpillID);
ValueIDNum DefAtSpill64(0, 3, Spill64Loc);
Expand All @@ -817,7 +817,7 @@ TEST_F(InstrRefLDVTest, MTransferSubregSpills) {
LocIdx RegLoc = MTracker->getRegMLoc(getRegByName(SubRegNames[I]));
ValueIDNum DefNum(0, 1, RegLoc);
// Read the corresponding subreg field from the stack.
SpillNo = MTracker->getOrTrackSpillLoc(L);
SpillNo = *MTracker->getOrTrackSpillLoc(L);
SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
Expand Down Expand Up @@ -846,7 +846,7 @@ TEST_F(InstrRefLDVTest, MTransferSubregSpills) {

for (unsigned int I = 0; I < 5; ++I) {
// Read subreg fields from the stack.
SpillLocationNo SpillNo = MTracker->getOrTrackSpillLoc(L);
SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
unsigned SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
Expand All @@ -859,7 +859,7 @@ TEST_F(InstrRefLDVTest, MTransferSubregSpills) {

// Read xmm0's position and ensure it has a value. Should be the live-in
// value to the block, as IMPLICIT_DEF isn't a real def.
SpillNo = MTracker->getOrTrackSpillLoc(L);
SpillNo = *MTracker->getOrTrackSpillLoc(L);
SpillID = MTracker->getLocID(SpillNo, {128, 0});
LocIdx Spill128Loc = MTracker->getSpillMLoc(SpillID);
SpillValue = MTracker->readMLoc(Spill128Loc);
Expand Down Expand Up @@ -1097,7 +1097,7 @@ TEST_F(InstrRefLDVTest, MLocDiamondSpills) {

// Create a stack location and ensure it's tracked.
SpillLoc SL = {getRegByName("RSP"), StackOffset::getFixed(-8)};
SpillLocationNo SpillNo = MTracker->getOrTrackSpillLoc(SL);
SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(SL);
ASSERT_EQ(MTracker->getNumLocs(), 10u); // Tracks all possible stack locs.
// Locations are: RSP, stack slots from 2^3 bits wide up to 2^9 for zmm regs,
// then slots for sub_8bit_hi and sub_16bit_hi ({8, 8} and {16, 16}).
Expand Down