From: Reid Kleckner Date: Fri, 25 Mar 2016 17:54:46 +0000 (+0000) Subject: Consider regmasks when computing register-based DBG_VALUE live ranges X-Git-Tag: llvmorg-3.9.0-rc1~10897 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f6f04f8fc890763e21e36d0caeca78aa43c8e577;p=platform%2Fupstream%2Fllvm.git 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 --- diff --git a/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp b/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp index 5ce2550..21d816b 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp @@ -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 #include 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 -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; } diff --git a/llvm/lib/CodeGen/LiveDebugValues.cpp b/llvm/lib/CodeGen/LiveDebugValues.cpp index b9937e5..d3cbac8 100644 --- a/llvm/lib/CodeGen/LiveDebugValues.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues.cpp @@ -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 @@ -208,18 +209,33 @@ 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; - // Remove ranges of all aliased registers. - for (MCRegAliasIterator RAI(MO.getReg(), TRI, true); RAI.isValid(); ++RAI) + 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(), + [&](const VarLoc &V) { + return (*RAI == + 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) { - return (*RAI == - isDescribedByReg(*V.MI)); + unsigned Reg = isDescribedByReg(*V.MI); + return Reg && Reg != SP && + MO.clobbersPhysReg(Reg); }), OpenRanges.end()); + } } } diff --git a/llvm/test/DebugInfo/MIR/X86/live-debug-values.mir b/llvm/test/DebugInfo/MIR/X86/live-debug-values.mir index 80f3952..3c72a86 100644 --- a/llvm/test/DebugInfo/MIR/X86/live-debug-values.mir +++ b/llvm/test/DebugInfo/MIR/X86/live-debug-values.mir @@ -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 --- | diff --git a/llvm/test/DebugInfo/X86/array.ll b/llvm/test/DebugInfo/X86/array.ll index 4ffe0a7..0714950 100644 --- a/llvm/test/DebugInfo/X86/array.ll +++ b/llvm/test/DebugInfo/X86/array.ll @@ -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" diff --git a/llvm/test/DebugInfo/X86/bbjoin.ll b/llvm/test/DebugInfo/X86/bbjoin.ll index fea7491..7bf2a30 100644 --- a/llvm/test/DebugInfo/X86/bbjoin.ll +++ b/llvm/test/DebugInfo/X86/bbjoin.ll @@ -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 diff --git a/llvm/test/DebugInfo/X86/dbg-value-regmask-clobber.ll b/llvm/test/DebugInfo/X86/dbg-value-regmask-clobber.ll new file mode 100644 index 0000000..d868e85 --- /dev/null +++ b/llvm/test/DebugInfo/X86/dbg-value-regmask-clobber.ll @@ -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) diff --git a/llvm/test/DebugInfo/X86/debug-loc-asan.ll b/llvm/test/DebugInfo/X86/debug-loc-asan.ll index 2e01355..f1bb298 100644 --- a/llvm/test/DebugInfo/X86/debug-loc-asan.ll +++ b/llvm/test/DebugInfo/X86/debug-loc-asan.ll @@ -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 diff --git a/llvm/test/DebugInfo/X86/live-debug-values.ll b/llvm/test/DebugInfo/X86/live-debug-values.ll index 615d498..cdd83f7 100644 --- a/llvm/test/DebugInfo/X86/live-debug-values.ll +++ b/llvm/test/DebugInfo/X86/live-debug-values.ll @@ -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" diff --git a/llvm/test/DebugInfo/X86/pr19307.ll b/llvm/test/DebugInfo/X86/pr19307.ll index 39a8007..66fa27d 100644 --- a/llvm/test/DebugInfo/X86/pr19307.ll +++ b/llvm/test/DebugInfo/X86/pr19307.ll @@ -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: