[llvm] f7052da - [DWARF] Emit DW_AT_call_pc for tail calls

Vedant Kumar via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 24 12:02:28 PDT 2020


Author: Vedant Kumar
Date: 2020-03-24T12:01:55-07:00
New Revision: f7052da6db8f85814adb2e1a6742d607e774bb88

URL: https://github.com/llvm/llvm-project/commit/f7052da6db8f85814adb2e1a6742d607e774bb88
DIFF: https://github.com/llvm/llvm-project/commit/f7052da6db8f85814adb2e1a6742d607e774bb88.diff

LOG: [DWARF] Emit DW_AT_call_pc for tail calls

Record the address of a tail-calling branch instruction within its call
site entry using DW_AT_call_pc. This allows a debugger to determine the
address to use when creating aritificial frames.

This creates an extra attribute + relocation at tail call sites, which
constitute 3-5% of all call sites in xnu/clang respectively.

rdar://60307600

Differential Revision: https://reviews.llvm.org/D76336

Added: 
    llvm/test/tools/dsymutil/X86/Inputs/tail-call.cpp
    llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64
    llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64.o
    llvm/test/tools/dsymutil/X86/tail-call-linking.test

Modified: 
    llvm/include/llvm/DWARFLinker/DWARFLinker.h
    llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
    llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
    llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
    llvm/lib/DWARFLinker/DWARFLinker.cpp
    llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir
    llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
index 5b0108606ac9..af49665391bb 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
@@ -576,6 +576,9 @@ class DWARFLinker {
       /// Value of DW_AT_call_return_pc in the input DIE
       uint64_t OrigCallReturnPc = 0;
 
+      /// Value of DW_AT_call_pc in the input DIE
+      uint64_t OrigCallPc = 0;
+
       /// Offset to apply to PC addresses inside a function.
       int64_t PCOffset = 0;
 

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index 4a570dbbe339..889303b4278e 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -925,13 +925,12 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
     ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
 }
 
-/// Whether to use the GNU analog for a DWARF5 tag, attribute, or location atom.
-static bool useGNUAnalogForDwarf5Feature(DwarfDebug *DD) {
+bool DwarfCompileUnit::useGNUAnalogForDwarf5Feature() const {
   return DD->getDwarfVersion() == 4 && DD->tuneForGDB();
 }
 
 dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUTag(dwarf::Tag Tag) const {
-  if (!useGNUAnalogForDwarf5Feature(DD))
+  if (!useGNUAnalogForDwarf5Feature())
     return Tag;
   switch (Tag) {
   case dwarf::DW_TAG_call_site:
@@ -945,7 +944,7 @@ dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUTag(dwarf::Tag Tag) const {
 
 dwarf::Attribute
 DwarfCompileUnit::getDwarf5OrGNUAttr(dwarf::Attribute Attr) const {
-  if (!useGNUAnalogForDwarf5Feature(DD))
+  if (!useGNUAnalogForDwarf5Feature())
     return Attr;
   switch (Attr) {
   case dwarf::DW_AT_call_all_calls:
@@ -967,7 +966,7 @@ DwarfCompileUnit::getDwarf5OrGNUAttr(dwarf::Attribute Attr) const {
 
 dwarf::LocationAtom
 DwarfCompileUnit::getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const {
-  if (!useGNUAnalogForDwarf5Feature(DD))
+  if (!useGNUAnalogForDwarf5Feature())
     return Loc;
   switch (Loc) {
   case dwarf::DW_OP_entry_value:
@@ -981,6 +980,7 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE,
                                                  DIE *CalleeDIE,
                                                  bool IsTail,
                                                  const MCSymbol *PCAddr,
+                                                 const MCSymbol *CallAddr,
                                                  unsigned CallReg) {
   // Insert a call site entry DIE within ScopeDIE.
   DIE &CallSiteDIE = createAndAddDIE(getDwarf5OrGNUTag(dwarf::DW_TAG_call_site),
@@ -996,16 +996,33 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE,
                 *CalleeDIE);
   }
 
-  if (IsTail)
+  if (IsTail) {
     // Attach DW_AT_call_tail_call to tail calls for standards compliance.
     addFlag(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_tail_call));
 
+    // Attach the address of the branch instruction to allow the debugger to
+    // show where the tail call occurred. This attribute has no GNU analog.
+    //
+    // GDB works backwards from non-standard usage of DW_AT_low_pc (in DWARF4
+    // mode -- equivalently, in DWARF5 mode, DW_AT_call_return_pc) at tail-call
+    // site entries to figure out the PC of tail-calling branch instructions.
+    // This means it doesn't need the compiler to emit DW_AT_call_pc, so we
+    // don't emit it here.
+    //
+    // There's no need to tie non-GDB debuggers to this non-standardness, as it
+    // adds unnecessary complexity to the debugger. For non-GDB debuggers, emit
+    // the standard DW_AT_call_pc info.
+    if (!useGNUAnalogForDwarf5Feature())
+      addLabelAddress(CallSiteDIE, dwarf::DW_AT_call_pc, CallAddr);
+  }
+
   // Attach the return PC to allow the debugger to disambiguate call paths
   // from one function to another.
   //
   // The return PC is only really needed when the call /isn't/ a tail call, but
-  // for some reason GDB always expects it.
-  if (!IsTail || DD->tuneForGDB()) {
+  // GDB expects it in DWARF4 mode, even for tail calls (see the comment above
+  // the DW_AT_call_pc emission logic for an explanation).
+  if (!IsTail || useGNUAnalogForDwarf5Feature()) {
     assert(PCAddr && "Missing return PC information for a call");
     addLabelAddress(CallSiteDIE,
                     getDwarf5OrGNUAttr(dwarf::DW_AT_call_return_pc), PCAddr);

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
index 52e1c71a8e65..5d0afee4c3df 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
@@ -230,6 +230,10 @@ class DwarfCompileUnit final : public DwarfUnit {
 
   void constructAbstractSubprogramScopeDIE(LexicalScope *Scope);
 
+  /// Whether to use the GNU analog for a DWARF5 tag, attribute, or location
+  /// atom. Only applicable when emitting otherwise DWARF4-compliant debug info.
+  bool useGNUAnalogForDwarf5Feature() const;
+
   /// This takes a DWARF 5 tag and returns it or a GNU analog.
   dwarf::Tag getDwarf5OrGNUTag(dwarf::Tag Tag) const;
 
@@ -245,10 +249,12 @@ class DwarfCompileUnit final : public DwarfUnit {
   /// For indirect calls \p CalleeDIE is set to nullptr.
   /// \p IsTail specifies whether the call is a tail call.
   /// \p PCAddr points to the PC value after the call instruction.
+  /// \p CallAddr points to the PC value at the call instruction (or is null).
   /// \p CallReg is a register location for an indirect call. For direct calls
   /// the \p CallReg is set to 0.
   DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, DIE *CalleeDIE, bool IsTail,
-                                 const MCSymbol *PCAddr, unsigned CallReg);
+                                 const MCSymbol *PCAddr,
+                                 const MCSymbol *CallAddr, unsigned CallReg);
   /// Construct call site parameter DIEs for the \p CallSiteDIE. The \p Params
   /// were collected by the \ref collectCallSiteParameters.
   /// Note: The order of parameters does not matter, since debuggers recognize

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 529c88f2ac91..94ceab2c3b82 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -878,16 +878,21 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
       const MachineInstr *TopLevelCallMI =
           MI.isInsideBundle() ? &*getBundleStart(MI.getIterator()) : &MI;
 
-      // For tail calls, no return PC information is needed.
-      // For regular calls (and tail calls in GDB tuning), the return PC
-      // is needed to disambiguate paths in the call graph which could lead to
-      // some target function.
+      // For non-tail calls, the return PC is needed to disambiguate paths in
+      // the call graph which could lead to some target function. For tail
+      // calls, no return PC information is needed, unless tuning for GDB in
+      // DWARF4 mode in which case we fake a return PC for compatibility.
       const MCSymbol *PCAddr =
-          (IsTail && !tuneForGDB())
-              ? nullptr
-              : const_cast<MCSymbol *>(getLabelAfterInsn(TopLevelCallMI));
+          (!IsTail || CU.useGNUAnalogForDwarf5Feature())
+              ? const_cast<MCSymbol *>(getLabelAfterInsn(TopLevelCallMI))
+              : nullptr;
 
-      assert((IsTail || PCAddr) && "Call without return PC information");
+      // For tail calls, it's necessary to record the address of the branch
+      // instruction so that the debugger can show where the tail call occurred.
+      const MCSymbol *CallAddr =
+          IsTail ? getLabelBeforeInsn(TopLevelCallMI) : nullptr;
+
+      assert((IsTail || PCAddr) && "Non-tail call without return PC");
 
       LLVM_DEBUG(dbgs() << "CallSiteEntry: " << MF.getName() << " -> "
                         << (CalleeDecl ? CalleeDecl->getName()
@@ -896,8 +901,8 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
                                                        ->getName(CallReg)))
                         << (IsTail ? " [IsTail]" : "") << "\n");
 
-      DIE &CallSiteDIE = CU.constructCallSiteEntryDIE(ScopeDIE, CalleeDIE,
-                                                      IsTail, PCAddr, CallReg);
+      DIE &CallSiteDIE = CU.constructCallSiteEntryDIE(
+          ScopeDIE, CalleeDIE, IsTail, PCAddr, CallAddr, CallReg);
 
       // Optionally emit call-site-param debug info.
       if (emitDebugEntryValues()) {
@@ -1786,11 +1791,32 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU,
 
 // Process beginning of an instruction.
 void DwarfDebug::beginInstruction(const MachineInstr *MI) {
+  const MachineFunction &MF = *MI->getMF();
+  const auto *SP = MF.getFunction().getSubprogram();
+  bool NoDebug =
+      !SP || SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug;
+
+  // When describing calls, we need a label for the call instruction.
+  // TODO: Add support for targets with delay slots.
+  if (!NoDebug && SP->areAllCallsDescribed() &&
+      MI->isCandidateForCallSiteEntry(MachineInstr::AnyInBundle) &&
+      !MI->hasDelaySlot()) {
+    const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+    bool IsTail = TII->isTailCall(*MI);
+    // For tail calls, we need the address of the branch instruction for
+    // DW_AT_call_pc.
+    if (IsTail)
+      requestLabelBeforeInsn(MI);
+    // For non-tail calls, we need the return address for the call for
+    // DW_AT_call_return_pc. Under GDB tuning, this information is needed for
+    // tail calls as well.
+    requestLabelAfterInsn(MI);
+  }
+
   DebugHandlerBase::beginInstruction(MI);
   assert(CurMI);
 
-  const auto *SP = MI->getMF()->getFunction().getSubprogram();
-  if (!SP || SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug)
+  if (NoDebug)
     return;
 
   // Check if source location changes, but ignore DBG_VALUE and CFI locations.
@@ -1804,11 +1830,6 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
   unsigned LastAsmLine =
       Asm->OutStreamer->getContext().getCurrentDwarfLoc().getLine();
 
-  // Request a label after the call in order to emit AT_return_pc information
-  // in call site entries. TODO: Add support for targets with delay slots.
-  if (SP->areAllCallsDescribed() && MI->isCall() && !MI->hasDelaySlot())
-    requestLabelAfterInsn(MI);
-
   if (DL == PrevInstLoc) {
     // If we have an ongoing unspecified location, nothing to do here.
     if (!DL)

diff  --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
index 8464c04f801e..ab18cb005a3a 100644
--- a/llvm/lib/DWARFLinker/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp
@@ -1056,6 +1056,10 @@ unsigned DWARFLinker::DIECloner::cloneAddressAttribute(
     if (Die.getTag() == dwarf::DW_TAG_call_site)
       Addr = (Info.OrigCallReturnPc ? Info.OrigCallReturnPc : Addr) +
              Info.PCOffset;
+  } else if (AttrSpec.Attr == dwarf::DW_AT_call_pc) {
+    // Relocate the address of a branch instruction within a call site entry.
+    if (Die.getTag() == dwarf::DW_TAG_call_site)
+      Addr = (Info.OrigCallPc ? Info.OrigCallPc : Addr) + Info.PCOffset;
   }
 
   Die.addValue(DIEAlloc, static_cast<dwarf::Attribute>(AttrSpec.Attr),

diff  --git a/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir b/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir
index 63d03050918f..b60c10a04e59 100644
--- a/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir
+++ b/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir
@@ -1,16 +1,24 @@
 # Test the call site encoding in DWARF5 vs GNU extensions.
 #
+# === DWARF4, tune for gdb ===
 # RUN: llc -emit-call-site-info -dwarf-version 4 -debugger-tune=gdb -filetype=obj \
 # RUN:     -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s  \
-# RUN:     | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-GNU
+# RUN:     | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-GNU -implicit-check-not=DW_AT_call
 #
-# RUN: llc -emit-call-site-info -dwarf-version 5 -debugger-tune=lldb -filetype=obj \
+# === DWARF5, tune for gdb ===
+# RUN: llc -dwarf-version 5 -debugger-tune=gdb -emit-call-site-info -filetype=obj \
+# RUN:     -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s  \
+# RUN:     | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 -implicit-check-not=DW_AT_call
+#
+# === DWARF4, tune for lldb ===
+# RUN: llc -dwarf-version 4 -debugger-tune=lldb -emit-call-site-info -filetype=obj \
 # RUN:     -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s   \
-# RUN:     | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5
+# RUN:     | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 -implicit-check-not=DW_AT_call
 #
-# RUN: llc -emit-call-site-info -dwarf-version 5 -filetype=obj \
+# === DWARF5, tune for lldb ===
+# RUN: llc -dwarf-version 5 -debugger-tune=lldb -emit-call-site-info -filetype=obj \
 # RUN:     -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s   \
-# RUN:     | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5
+# RUN:     | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 -implicit-check-not=DW_AT_call
 #
 # RUN: llc -emit-call-site-info -dwarf-version 5 -filetype=obj -debugger-tune=sce \
 # RUN:     -emit-debug-entry-values -debug-entry-values -mtriple=x86_64-unknown-unknown \
@@ -49,6 +57,7 @@
 # CHECK-GNU:        DW_TAG_GNU_call_site
 # CHECK-GNU-NEXT:     DW_AT_abstract_origin
 # CHECK-GNU-NEXT:     DW_AT_GNU_tail_call
+# CHECK-GNU-NEXT:     DW_AT_low_pc
 #
 #
 # Check DWARF 5:
@@ -58,6 +67,9 @@
 # CHECK-DWARF5:        DW_TAG_call_site
 # CHECK-DWARF5-NEXT:     DW_AT_call_origin
 # CHECK-DWARF5-NEXT:     DW_AT_call_return_pc
+# CHECK-DWARF5:        DW_TAG_call_site
+# CHECK-DWARF5-NEXT:     DW_AT_call_origin
+# CHECK-DWARF5-NEXT:     DW_AT_call_return_pc
 # CHECK-DWARF5:          DW_TAG_call_site_parameter
 # CHECK-DWARF5-NEXT:       DW_AT_location
 # CHECK-DWARF5-NEXT:       DW_AT_call_value
@@ -67,6 +79,7 @@
 # CHECK-DWARF5:        DW_TAG_call_site
 # CHECK-DWARF5-NEXT:     DW_AT_call_origin
 # CHECK-DWARF5-NEXT:     DW_AT_call_tail_call
+# CHECK-DWARF5-NEXT:     DW_AT_call_pc
 #
 --- |
   ; ModuleID = 'call-site-attrs.c'

diff  --git a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll
index 931f77c72f78..3a34ff38809f 100644
--- a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll
+++ b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll
@@ -14,7 +14,7 @@
 
 ; RUN: %llc_dwarf -mtriple=x86_64-- < %s -o - | FileCheck %s -check-prefix=ASM
 ; RUN: %llc_dwarf -debugger-tune=lldb -mtriple=x86_64-- < %s -filetype=obj -o %t.o
-; RUN: llvm-dwarfdump %t.o -o - | FileCheck %s -check-prefix=OBJ -implicit-check-not=DW_TAG_call_site
+; RUN: llvm-dwarfdump %t.o -o - | FileCheck %s -check-prefix=OBJ -implicit-check-not=DW_TAG_call -implicit-check-not=DW_AT_call
 ; RUN: llvm-dwarfdump -verify %t.o 2>&1 | FileCheck %s -check-prefix=VERIFY
 ; RUN: llvm-dwarfdump -statistics %t.o | FileCheck %s -check-prefix=STATS
 ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis -o /dev/null
@@ -75,6 +75,7 @@ entry:
 ; OBJ:   DW_TAG_call_site
 ; OBJ:     DW_AT_call_origin ([[bat_sp]])
 ; OBJ:     DW_AT_call_tail_call
+; OBJ:     DW_AT_call_pc
 define void @_Z3foov() !dbg !25 {
 entry:
   tail call void @__has_no_subprogram()

diff  --git a/llvm/test/tools/dsymutil/X86/Inputs/tail-call.cpp b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.cpp
new file mode 100644
index 000000000000..57e512e7009d
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.cpp
@@ -0,0 +1,28 @@
+/*
+ * This file is used to test dsymutil support for call site entries with tail
+ * calls (DW_AT_call_pc).
+ *
+ * Instructions for regenerating binaries (on Darwin/x86_64):
+ *
+ * 1. Copy the source to a top-level directory to work around having absolute
+ *    paths in the symtab's OSO entries.
+ *
+ *    mkdir -p /Inputs/ && cp tail-call.c /Inputs && cd /Inputs
+ *
+ * 2. Compile with call site info enabled. -O2 is used to get tail call
+ *    promotion.
+ *
+ *    clang -g -O2 tail-call.c -c -o tail-call.macho.x86_64.o
+ *    clang tail-call.macho.x86_64.o -o tail-call.macho.x86_64
+ *
+ * 3. Copy the binaries back into the repo's Inputs directory. You'll need
+ *    -oso-prepend-path=%p to link.
+ */
+
+volatile int x;
+
+__attribute__((disable_tail_calls, noinline)) void func2() { x++; }
+
+__attribute__((noinline)) void func1() { func2(); /* tail */ }
+
+__attribute__((disable_tail_calls)) int main() { func1(); /* regular */ }

diff  --git a/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64 b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64
new file mode 100755
index 000000000000..d6098d0de5e4
Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64 
diff er

diff  --git a/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64.o b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64.o
new file mode 100644
index 000000000000..1d5726d12e34
Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64.o 
diff er

diff  --git a/llvm/test/tools/dsymutil/X86/tail-call-linking.test b/llvm/test/tools/dsymutil/X86/tail-call-linking.test
new file mode 100644
index 000000000000..29ae2cc544cf
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/tail-call-linking.test
@@ -0,0 +1,4 @@
+RUN: dsymutil -oso-prepend-path=%p %p/Inputs/tail-call.macho.x86_64 -o %t.dSYM
+RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -implicit-check-not=DW_AT_call_pc
+
+CHECK: DW_AT_call_pc  (0x0000000100000f95)


        


More information about the llvm-commits mailing list