[llvm] r264429 - Consider regmasks when computing register-based DBG_VALUE live ranges

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 25 10:54:46 PDT 2016


Author: rnk
Date: Fri Mar 25 12:54:46 2016
New Revision: 264429

URL: http://llvm.org/viewvc/llvm-project?rev=264429&view=rev
Log:
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

Added:
    llvm/trunk/test/DebugInfo/X86/dbg-value-regmask-clobber.ll
Modified:
    llvm/trunk/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp
    llvm/trunk/lib/CodeGen/LiveDebugValues.cpp
    llvm/trunk/test/DebugInfo/MIR/X86/live-debug-values.mir
    llvm/trunk/test/DebugInfo/X86/array.ll
    llvm/trunk/test/DebugInfo/X86/bbjoin.ll
    llvm/trunk/test/DebugInfo/X86/debug-loc-asan.ll
    llvm/trunk/test/DebugInfo/X86/live-debug-values.ll
    llvm/trunk/test/DebugInfo/X86/pr19307.ll

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp?rev=264429&r1=264428&r2=264429&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp Fri Mar 25 12:54:46 2016
@@ -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(RegDescr
   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 Ma
     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(cons
   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;
       }
 

Modified: llvm/trunk/lib/CodeGen/LiveDebugValues.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LiveDebugValues.cpp?rev=264429&r1=264428&r2=264429&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/LiveDebugValues.cpp (original)
+++ llvm/trunk/lib/CodeGen/LiveDebugValues.cpp Fri Mar 25 12:54:46 2016
@@ -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,18 +209,33 @@ void LiveDebugValues::transferDebugValue
 /// 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());
+    }
   }
 }
 

Modified: llvm/trunk/test/DebugInfo/MIR/X86/live-debug-values.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/MIR/X86/live-debug-values.mir?rev=264429&r1=264428&r2=264429&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/MIR/X86/live-debug-values.mir (original)
+++ llvm/trunk/test/DebugInfo/MIR/X86/live-debug-values.mir Fri Mar 25 12:54:46 2016
@@ -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
 
 
 --- |

Modified: llvm/trunk/test/DebugInfo/X86/array.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/array.ll?rev=264429&r1=264428&r2=264429&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/array.ll (original)
+++ llvm/trunk/test/DebugInfo/X86/array.ll Fri Mar 25 12:54:46 2016
@@ -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"

Modified: llvm/trunk/test/DebugInfo/X86/bbjoin.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/bbjoin.ll?rev=264429&r1=264428&r2=264429&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/bbjoin.ll (original)
+++ llvm/trunk/test/DebugInfo/X86/bbjoin.ll Fri Mar 25 12:54:46 2016
@@ -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

Added: llvm/trunk/test/DebugInfo/X86/dbg-value-regmask-clobber.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/dbg-value-regmask-clobber.ll?rev=264429&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/dbg-value-regmask-clobber.ll (added)
+++ llvm/trunk/test/DebugInfo/X86/dbg-value-regmask-clobber.ll Fri Mar 25 12:54:46 2016
@@ -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"
+
+ at 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)

Modified: llvm/trunk/test/DebugInfo/X86/debug-loc-asan.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/debug-loc-asan.ll?rev=264429&r1=264428&r2=264429&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/debug-loc-asan.ll (original)
+++ llvm/trunk/test/DebugInfo/X86/debug-loc-asan.ll Fri Mar 25 12:54:46 2016
@@ -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

Modified: llvm/trunk/test/DebugInfo/X86/live-debug-values.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/live-debug-values.ll?rev=264429&r1=264428&r2=264429&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/live-debug-values.ll (original)
+++ llvm/trunk/test/DebugInfo/X86/live-debug-values.ll Fri Mar 25 12:54:46 2016
@@ -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"

Modified: llvm/trunk/test/DebugInfo/X86/pr19307.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/pr19307.ll?rev=264429&r1=264428&r2=264429&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/pr19307.ll (original)
+++ llvm/trunk/test/DebugInfo/X86/pr19307.ll Fri Mar 25 12:54:46 2016
@@ -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:




More information about the llvm-commits mailing list