Index: lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp +++ 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 @@ 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) { @@ -175,8 +157,19 @@ for (const auto &MI : MBB) { if (&MI == FirstEpilogueInst) break; - if (!MI.getFlag(MachineInstr::FrameSetup)) - applyToClobberedRegisters(MI, TRI, [&](unsigned r) { Regs.set(r); }); + if (!MI.getFlag(MachineInstr::FrameSetup)) { + for (const MachineOperand &MO : MI.operands()) { + // Look for register mask and register def operands. They clobber + // registers. + 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 +180,34 @@ 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, clobber some debug values. + 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; } Index: lib/CodeGen/LiveDebugValues.cpp =================================================================== --- lib/CodeGen/LiveDebugValues.cpp +++ 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 @@ /// 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()); + } } } Index: test/DebugInfo/MIR/X86/live-debug-values.mir =================================================================== --- test/DebugInfo/MIR/X86/live-debug-values.mir +++ 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 --- | Index: test/DebugInfo/Mips/dsr-fixed-objects.ll =================================================================== --- test/DebugInfo/Mips/dsr-fixed-objects.ll +++ test/DebugInfo/Mips/dsr-fixed-objects.ll @@ -22,13 +22,17 @@ declare void @foo(i32*) -; F0: DW_AT_location [DW_FORM_sec_offset] (0x00000014) -; F0: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000006b] = "x") +; F0: .debug_info contents: +; F0: DW_TAG_subprogram +; F0: DW_AT_name [DW_FORM_strp] {{.*}} "f0" +; F0: DW_TAG_variable +; F0-NEXT: DW_AT_location [DW_FORM_sec_offset] ([[loc_offset:0x.*]]) +; F0-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000006b] = "x") ; ; x -> DW_OP_reg1(51) -; F0: 0x00000014: Beginning address offset: 0x0000000000000028 -; F0: Ending address offset: 0x0000000000000030 -; F0: Location description: 51 +; F0: [[loc_offset]]: Beginning address offset: 0x0000000000000028 +; F0: Ending address offset: 0x0000000000000030 +; F0: Location description: 51 define i32 @f0(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e) !dbg !4 { entry: @@ -54,14 +58,19 @@ ret i32 %1, !dbg !45 } - -; F1: DW_AT_location [DW_FORM_sec_offset] (0x00000033) -; F1: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000006b] = "x") +; F1: .debug_info contents: +; F1: DW_TAG_subprogram +; F1: DW_AT_name [DW_FORM_strp] {{.*}} "f0" +; F1: DW_TAG_subprogram +; F1: DW_AT_name [DW_FORM_strp] {{.*}} "f1" +; F1: DW_TAG_variable +; F1-NEXT: DW_AT_location [DW_FORM_sec_offset] ([[loc_offset:0x.*]]) +; F1-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000006b] = "x") ; x -> DW_OP_reg1(51) -; F1: 0x00000033: Beginning address offset: 0x0000000000000080 -; F1: Ending address offset: 0x0000000000000088 -; F1: Location description: 51 +; F1: [[loc_offset]]: Beginning address offset: 0x0000000000000080 +; F1-NEXT: Ending address offset: 0x0000000000000088 +; F1-NEXT: Location description: 51 define i32 @f1(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e) !dbg !15 { entry: Index: test/DebugInfo/X86/array.ll =================================================================== --- test/DebugInfo/X86/array.ll +++ 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" Index: test/DebugInfo/X86/bbjoin.ll =================================================================== --- test/DebugInfo/X86/bbjoin.ll +++ 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 Index: test/DebugInfo/X86/dbg-value-regmask-clobber.ll =================================================================== --- /dev/null +++ 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) Index: test/DebugInfo/X86/debug-loc-asan.ll =================================================================== --- test/DebugInfo/X86/debug-loc-asan.ll +++ 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 Index: test/DebugInfo/X86/live-debug-values.ll =================================================================== --- test/DebugInfo/X86/live-debug-values.ll +++ 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" Index: test/DebugInfo/X86/pr19307.ll =================================================================== --- test/DebugInfo/X86/pr19307.ll +++ 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: Index: test/DebugInfo/X86/subregisters.ll =================================================================== --- test/DebugInfo/X86/subregisters.ll +++ test/DebugInfo/X86/subregisters.ll @@ -6,8 +6,14 @@ ; ; rdar://problem/16015314 ; -; CHECK: DW_AT_location [DW_FORM_block1] (<0x03> 54 93 04 ) -; CHECK: DW_AT_name [DW_FORM_strp]{{.*}} "a" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_location [DW_FORM_data4] (0x00000000) +; CHECK-NEXT: DW_AT_name [DW_FORM_strp]{{.*}} "a" +; +; CHECK: .debug_loc contents: +; CHECK: 0x00000000: Beginning address offset: 0x0000000000000002 +; CHECK: Ending address offset: 0x0000000000000014 +; CHECK: Location description: 54 93 04 ; ; struct bar { ; int a;