1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-02-01 05:01:59 +01:00

Consider regmasks when computing register-based DBG_VALUE live ranges

Now register parameters that aren't saved to the stack or CSRs are
considered dead after the first call. Previously the debugger would show
whatever was in the register.

Fixes PR26589

Reviewers: aprantl

Differential Revision: http://reviews.llvm.org/D17211

llvm-svn: 264429
This commit is contained in:
Reid Kleckner 2016-03-25 17:54:46 +00:00
parent 8945842662
commit bc7d490b15
9 changed files with 194 additions and 42 deletions

View File

@ -15,7 +15,9 @@
#include "llvm/IR/DebugInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include <algorithm>
#include <map>
using namespace llvm;
@ -122,26 +124,6 @@ static void clobberRegisterUses(RegDescribedVarsMap &RegVars, unsigned RegNo,
clobberRegisterUses(RegVars, I, HistMap, ClobberingInstr);
}
// \brief Collect all registers clobbered by @MI and apply the functor
// @Func to their RegNo.
// @Func should be a functor with a void(unsigned) signature. We're
// not using std::function here for performance reasons. It has a
// small but measurable impact. By using a functor instead of a
// std::set& here, we can avoid the overhead of constructing
// temporaries in calculateDbgValueHistory, which has a significant
// performance impact.
template<typename Callable>
static void applyToClobberedRegisters(const MachineInstr &MI,
const TargetRegisterInfo *TRI,
Callable Func) {
for (const MachineOperand &MO : MI.operands()) {
if (!MO.isReg() || !MO.isDef() || !MO.getReg())
continue;
for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); ++AI)
Func(*AI);
}
}
// \brief Returns the first instruction in @MBB which corresponds to
// the function epilogue, or nullptr if @MBB doesn't contain an epilogue.
static const MachineInstr *getFirstEpilogueInst(const MachineBasicBlock &MBB) {
@ -173,10 +155,23 @@ static void collectChangingRegs(const MachineFunction *MF,
auto FirstEpilogueInst = getFirstEpilogueInst(MBB);
for (const auto &MI : MBB) {
// Avoid looking at prologue or epilogue instructions.
if (&MI == FirstEpilogueInst)
break;
if (!MI.getFlag(MachineInstr::FrameSetup))
applyToClobberedRegisters(MI, TRI, [&](unsigned r) { Regs.set(r); });
if (MI.getFlag(MachineInstr::FrameSetup))
continue;
// Look for register defs and register masks. Register masks are
// typically on calls and they clobber everything not in the mask.
for (const MachineOperand &MO : MI.operands()) {
if (MO.isReg() && MO.isDef() && MO.getReg()) {
for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid();
++AI)
Regs.set(*AI);
} else if (MO.isRegMask()) {
Regs.setBitsNotInMask(MO.getRegMask());
}
}
}
}
}
@ -187,16 +182,35 @@ void llvm::calculateDbgValueHistory(const MachineFunction *MF,
BitVector ChangingRegs(TRI->getNumRegs());
collectChangingRegs(MF, TRI, ChangingRegs);
const TargetLowering *TLI = MF->getSubtarget().getTargetLowering();
unsigned SP = TLI->getStackPointerRegisterToSaveRestore();
RegDescribedVarsMap RegVars;
for (const auto &MBB : *MF) {
for (const auto &MI : MBB) {
if (!MI.isDebugValue()) {
// Not a DBG_VALUE instruction. It may clobber registers which describe
// some variables.
applyToClobberedRegisters(MI, TRI, [&](unsigned RegNo) {
if (ChangingRegs.test(RegNo))
clobberRegisterUses(RegVars, RegNo, Result, MI);
});
for (const MachineOperand &MO : MI.operands()) {
if (MO.isReg() && MO.isDef() && MO.getReg()) {
// If this is a register def operand, it may end a debug value
// range.
for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid();
++AI)
if (ChangingRegs.test(*AI))
clobberRegisterUses(RegVars, *AI, Result, MI);
} else if (MO.isRegMask()) {
// If this is a register mask operand, clobber all debug values in
// non-CSRs.
for (int I = ChangingRegs.find_first(); I != -1;
I = ChangingRegs.find_next(I)) {
// Don't consider SP to be clobbered by register masks.
if (unsigned(I) != SP && TRI->isPhysicalRegister(I) &&
MO.clobbersPhysReg(I)) {
clobberRegisterUses(RegVars, I, Result, MI);
}
}
}
}
continue;
}

View File

@ -30,6 +30,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include <queue>
@ -208,10 +209,12 @@ void LiveDebugValues::transferDebugValue(MachineInstr &MI,
/// A definition of a register may mark the end of a range.
void LiveDebugValues::transferRegisterDef(MachineInstr &MI,
VarLocList &OpenRanges) {
MachineFunction *MF = MI.getParent()->getParent();
const TargetLowering *TLI = MF->getSubtarget().getTargetLowering();
unsigned SP = TLI->getStackPointerRegisterToSaveRestore();
for (const MachineOperand &MO : MI.operands()) {
if (!(MO.isReg() && MO.isDef() && MO.getReg() &&
TRI->isPhysicalRegister(MO.getReg())))
continue;
if (MO.isReg() && MO.isDef() && MO.getReg() &&
TRI->isPhysicalRegister(MO.getReg())) {
// Remove ranges of all aliased registers.
for (MCRegAliasIterator RAI(MO.getReg(), TRI, true); RAI.isValid(); ++RAI)
OpenRanges.erase(std::remove_if(OpenRanges.begin(), OpenRanges.end(),
@ -220,6 +223,19 @@ void LiveDebugValues::transferRegisterDef(MachineInstr &MI,
isDescribedByReg(*V.MI));
}),
OpenRanges.end());
} else if (MO.isRegMask()) {
// Remove ranges of all clobbered registers. Register masks don't usually
// list SP as preserved. While the debug info may be off for an
// instruction or two around callee-cleanup calls, transferring the
// DEBUG_VALUE across the call is still a better user experience.
OpenRanges.erase(std::remove_if(OpenRanges.begin(), OpenRanges.end(),
[&](const VarLoc &V) {
unsigned Reg = isDescribedByReg(*V.MI);
return Reg && Reg != SP &&
MO.clobbersPhysReg(Reg);
}),
OpenRanges.end());
}
}
}

View File

@ -33,8 +33,7 @@
# DBG_VALUE for variable "n" is extended into BB#5 from its predecessors BB#3
# and BB#4.
# CHECK: bb.5.if.end.7:
# CHECK: DBG_VALUE debug-use %rsi, debug-use _, !13, !20, debug-location !22
# CHECK-NEXT: DBG_VALUE debug-use %ebx, debug-use _, !14, !20, debug-location !33
# CHECK: DBG_VALUE debug-use %ebx, debug-use _, !14, !20, debug-location !33
--- |

View File

@ -16,9 +16,9 @@
; Test that we only emit register-indirect locations for the array array.
; rdar://problem/14874886
;
; CHECK: ##DEBUG_VALUE: main:array <- [%R{{.*}}+0]
; CHECK: ##DEBUG_VALUE: main:array <- [%R{{.*}}+0]
; CHECK: ##DEBUG_VALUE: main:array <- [%R{{.*}}+0]
; FIXME: If we described this location as RSP-relative instead of RDI-relative
; the live range would be larger.
; CHECK: ##DEBUG_VALUE: main:array <- [%RDI+0]
; CHECK-NOT: ##DEBUG_VALUE: main:array <- %R{{.*}}
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.9.0"

View File

@ -14,7 +14,7 @@
; CHECK: DBG_VALUE 23, 0, ![[X]],
; CHECK: DBG_VALUE debug-use %rdi, debug-use _, ![[X]]
; CHECK: bb.1.if.then:
; CHECK: DBG_VALUE debug-use %rdi, debug-use _, ![[X]],
; CHECK: DBG_VALUE 43, 0, ![[X]],
; CHECK: bb.2.if.end:
; CHECK-NOT: DBG_VALUE 23, 0, ![[X]],
; CHECK: RETQ %eax

View File

@ -0,0 +1,117 @@
; RUN: llc < %s | FileCheck %s --check-prefix=ASM
; RUN: llc < %s -filetype=obj | llvm-dwarfdump - | FileCheck %s --check-prefix=DWARF
; Values in registers should be clobbered by calls, which use a regmask instead
; of individual register def operands.
; ASM: main: # @main
; ASM: #DEBUG_VALUE: main:argc <- %ECX
; ASM: movl $1, x(%rip)
; ASM: callq clobber
; ASM-NEXT: [[argc_range_end:.Ltmp[0-9]+]]:
; Previously LiveDebugValues would claim argc was still in ECX after the call.
; ASM-NOT: #DEBUG_VALUE: main:argc
; argc is the first debug location.
; ASM: .Ldebug_loc1:
; ASM-NEXT: .quad .Lfunc_begin0-.Lfunc_begin0
; ASM-NEXT: .quad [[argc_range_end]]-.Lfunc_begin0
; ASM-NEXT: .short 3 # Loc expr size
; ASM-NEXT: .byte 82 # super-register DW_OP_reg2
; ASM-NEXT: .byte 147 # DW_OP_piece
; ASM-NEXT: .byte 4 # 4
; argc is the first formal parameter.
; DWARF: .debug_info contents:
; DWARF: DW_TAG_formal_parameter
; DWARF-NEXT: DW_AT_location [DW_FORM_sec_offset] ([[argc_loc_offset:0x.*]])
; DWARF-NEXT: DW_AT_name [DW_FORM_strp] {{.*}} "argc"
; DWARF: .debug_loc contents:
; DWARF: [[argc_loc_offset]]: Beginning address offset: 0x0000000000000000
; DWARF-NEXT: Ending address offset: 0x0000000000000013
; DWARF-NEXT: Location description: 52 93 04
; ModuleID = 't.cpp'
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc18.0.0"
@x = common global i32 0, align 4
; Function Attrs: nounwind uwtable
define i32 @main(i32 %argc, i8** nocapture readnone %argv) #0 !dbg !4 {
entry:
tail call void @llvm.dbg.value(metadata i8** %argv, i64 0, metadata !12, metadata !21), !dbg !22
tail call void @llvm.dbg.value(metadata i32 %argc, i64 0, metadata !13, metadata !21), !dbg !23
store volatile i32 1, i32* @x, align 4, !dbg !24, !tbaa !25
tail call void @clobber() #3, !dbg !29
store volatile i32 2, i32* @x, align 4, !dbg !30, !tbaa !25
%0 = load volatile i32, i32* @x, align 4, !dbg !31, !tbaa !25
%tobool = icmp eq i32 %0, 0, !dbg !31
br i1 %tobool, label %if.else, label %if.then, !dbg !33
if.then: ; preds = %entry
store volatile i32 3, i32* @x, align 4, !dbg !34, !tbaa !25
br label %if.end, !dbg !36
if.else: ; preds = %entry
store volatile i32 4, i32* @x, align 4, !dbg !37, !tbaa !25
br label %if.end
if.end: ; preds = %if.else, %if.then
ret i32 0, !dbg !39
}
declare void @clobber()
; Function Attrs: nounwind readnone
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2
attributes #0 = { nounwind uwtable }
attributes #2 = { nounwind readnone }
attributes #3 = { nounwind }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!17, !18, !19}
!llvm.ident = !{!20}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.9.0 (trunk 260617) (llvm/trunk 260619)", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3, globals: !14)
!1 = !DIFile(filename: "t.cpp", directory: "D:\5Csrc\5Cllvm\5Cbuild")
!2 = !{}
!3 = !{!4}
!4 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 4, type: !5, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, variables: !11)
!5 = !DISubroutineType(types: !6)
!6 = !{!7, !7, !8}
!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64, align: 64)
!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64, align: 64)
!10 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
!11 = !{!12, !13}
!12 = !DILocalVariable(name: "argv", arg: 2, scope: !4, file: !1, line: 4, type: !8)
!13 = !DILocalVariable(name: "argc", arg: 1, scope: !4, file: !1, line: 4, type: !7)
!14 = !{!15}
!15 = !DIGlobalVariable(name: "x", scope: !0, file: !1, line: 1, type: !16, isLocal: false, isDefinition: true, variable: i32* @x)
!16 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7)
!17 = !{i32 2, !"Dwarf Version", i32 4}
!18 = !{i32 2, !"Debug Info Version", i32 3}
!19 = !{i32 1, !"PIC Level", i32 2}
!20 = !{!"clang version 3.9.0 (trunk 260617) (llvm/trunk 260619)"}
!21 = !DIExpression()
!22 = !DILocation(line: 4, column: 27, scope: !4)
!23 = !DILocation(line: 4, column: 14, scope: !4)
!24 = !DILocation(line: 5, column: 5, scope: !4)
!25 = !{!26, !26, i64 0}
!26 = !{!"int", !27, i64 0}
!27 = !{!"omnipotent char", !28, i64 0}
!28 = !{!"Simple C/C++ TBAA"}
!29 = !DILocation(line: 6, column: 3, scope: !4)
!30 = !DILocation(line: 7, column: 5, scope: !4)
!31 = !DILocation(line: 8, column: 7, scope: !32)
!32 = distinct !DILexicalBlock(scope: !4, file: !1, line: 8, column: 7)
!33 = !DILocation(line: 8, column: 7, scope: !4)
!34 = !DILocation(line: 9, column: 7, scope: !35)
!35 = distinct !DILexicalBlock(scope: !32, file: !1, line: 8, column: 10)
!36 = !DILocation(line: 10, column: 3, scope: !35)
!37 = !DILocation(line: 11, column: 7, scope: !38)
!38 = distinct !DILexicalBlock(scope: !32, file: !1, line: 10, column: 10)
!39 = !DILocation(line: 13, column: 1, scope: !4)

View File

@ -15,8 +15,12 @@
; CHECK: #DEBUG_VALUE: bar:y <- [%RDI+0]
; CHECK: movq %rdi, [[OFFSET:[0-9]+]](%rsp)
; CHECK-NEXT: [[START_LABEL:.Ltmp[0-9]+]]
; CHECK-NEXT: #DEBUG_VALUE: bar:y <- [complex expression]
; This location should be valid until the end of the function.
; CHECK: movq %rbp, %rsp
; CHECK-NEXT: [[END_LABEL:.Ltmp[0-9]+]]:
; CHECK: .Ldebug_loc{{[0-9]+}}:
; We expect two location ranges for the variable.
@ -27,7 +31,7 @@
; Then it's addressed via %rsp:
; CHECK: .quad [[START_LABEL]]-.Lfunc_begin0
; CHECK-NEXT: .Lfunc_end0-.Lfunc_begin0
; CHECK-NEXT: .quad [[END_LABEL]]-.Lfunc_begin0
; CHECK: DW_OP_breg7
; CHECK-NEXT: [[OFFSET]]
; CHECK: DW_OP_deref

View File

@ -31,7 +31,9 @@
; and BB#4.
; CHECK: .LBB0_5:
; CHECK-NEXT: #DEBUG_VALUE: main:n <- %EBX
; CHECK-NEXT: #DEBUG_VALUE: main:argv <- %RSI
; Other register values have been clobbered.
; CHECK-NOT: #DEBUG_VALUE:
; CHECK: movl %ecx, m(%rip)
; ModuleID = 'LiveDebugValues.c'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

View File

@ -14,7 +14,7 @@
; Location of "range" string is spilled from %rdx to stack and is
; addressed via %rbp.
; CHECK: movq %rdx, {{[-0-9]+}}(%rbp)
; CHECK-NEXT: [[START_LABEL:.Ltmp[0-9]+]]
; CHECK-NEXT: [[START_LABEL:.Ltmp[0-9]+]]:
; This location should be valid until the end of the function.
; Verify that we have proper range in debug_loc section: