]> granicus.if.org Git - llvm/commitdiff
Fix LLVM's use of DW_OP_bit_piece in DWARF expressions.
authorAdrian Prantl <aprantl@apple.com>
Fri, 9 Dec 2016 20:43:40 +0000 (20:43 +0000)
committerAdrian Prantl <aprantl@apple.com>
Fri, 9 Dec 2016 20:43:40 +0000 (20:43 +0000)
LLVM's use of DW_OP_bit_piece is incorrect and a based on a
misunderstanding of the wording in the DWARF specification. The offset
argument of DW_OP_bit_piece refers to the offset into the location
that is on the top of the DWARF expression stack, and not an offset
into the source variable. This has since also been clarified in the
DWARF specification.

This patch fixes all uses of DW_OP_bit_piece to emit the correct
offset and simplifies the DwarfExpression class to semi-automaticaly
emit empty DW_OP_pieces to adjust the offset of the source variable,
thus simplifying the code using DwarfExpression.

While this is an incompatible bugfix, in practice I don't expect this
to be much of a problem since LLVM's old interpretation and the
correct interpretation of DW_OP_bit_piece differ only when there are
gaps in the fragmented locations of the described variables or if
individual fragments are smaller than a byte. LLDB at least won't
interpret locations with gaps in them because is has no way to present
undefined bits in a variable, and there is a high probability that an
old-form expression will be malformed when interpreted correctly,
because the DW_OP_bit_piece offset will be outside of the location at
the top of the stack.

As a nice side-effect, this patch enables us to use a more efficient
encoding for subregisters: In order to express a sub-register at a
non-zero offset we now use a DW_OP_bit_piece instead of shifting the
value into place manually.

This patch also adds missing test coverage for code paths that weren't
exercised before.

<rdar://problem/29335809>
Differential Revision: https://reviews.llvm.org/D27550

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@289266 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
include/llvm/CodeGen/AsmPrinter.h
lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
lib/CodeGen/AsmPrinter/DwarfDebug.cpp
lib/CodeGen/AsmPrinter/DwarfExpression.cpp
lib/CodeGen/AsmPrinter/DwarfExpression.h
lib/CodeGen/AsmPrinter/DwarfUnit.cpp
lib/CodeGen/AsmPrinter/DwarfUnit.h
test/DebugInfo/AArch64/frameindices.ll
test/DebugInfo/MIR/ARM/lit.local.cfg [new file with mode: 0644]
test/DebugInfo/MIR/ARM/split-superreg-piece.mir [new file with mode: 0644]
test/DebugInfo/MIR/ARM/split-superreg.mir [new file with mode: 0644]
test/DebugInfo/MIR/X86/bit-piece-dh.mir [new file with mode: 0644]
test/DebugInfo/X86/PR26148.ll
test/DebugInfo/X86/dw_op_minus_direct.ll [new file with mode: 0644]

index 93c39819061137a3815aa88ea817fdb712076b52..c1be46ddd7b5c6e2195d49ca2b40dac4fa501a34 100644 (file)
@@ -468,10 +468,6 @@ public:
   /// Get the value for DW_AT_APPLE_isa. Zero if no isa encoding specified.
   virtual unsigned getISAEncoding() { return 0; }
 
-  /// EmitDwarfRegOp - Emit a dwarf register operation.
-  virtual void EmitDwarfRegOp(ByteStreamer &BS,
-                              const MachineLocation &MLoc) const;
-
   //===------------------------------------------------------------------===//
   // Dwarf Lowering Routines
   //===------------------------------------------------------------------===//
index c104c3cd948afebc7cc1a86839ead76bfe60d0cd..6c1cc7e519eacb6013c94da05f3b4e21f621c3a7 100644 (file)
@@ -174,36 +174,6 @@ void AsmPrinter::emitDwarfStringOffset(DwarfStringPoolEntryRef S) const {
   EmitInt32(S.getOffset());
 }
 
-/// EmitDwarfRegOp - Emit dwarf register operation.
-void AsmPrinter::EmitDwarfRegOp(ByteStreamer &Streamer,
-                                const MachineLocation &MLoc) const {
-  DebugLocDwarfExpression Expr(getDwarfVersion(), Streamer);
-  const MCRegisterInfo *MRI = MMI->getContext().getRegisterInfo();
-  int Reg = MRI->getDwarfRegNum(MLoc.getReg(), false);
-  if (Reg < 0) {
-    // We assume that pointers are always in an addressable register.
-    if (MLoc.isIndirect())
-      // FIXME: We have no reasonable way of handling errors in here. The
-      // caller might be in the middle of a dwarf expression. We should
-      // probably assert that Reg >= 0 once debug info generation is more
-      // mature.
-      return Expr.EmitOp(dwarf::DW_OP_nop,
-                         "nop (could not find a dwarf register number)");
-
-    // Attempt to find a valid super- or sub-register.
-    if (!Expr.AddMachineRegFragment(*MF->getSubtarget().getRegisterInfo(),
-                                    MLoc.getReg()))
-      Expr.EmitOp(dwarf::DW_OP_nop,
-                  "nop (could not find a dwarf register number)");
-    return;
-  }
-
-  if (MLoc.isIndirect())
-    Expr.AddRegIndirect(Reg, MLoc.getOffset());
-  else
-    Expr.AddReg(Reg);
-}
-
 //===----------------------------------------------------------------------===//
 // Dwarf Lowering Routines
 //===----------------------------------------------------------------------===//
index c615cea1d7cea305cb2076d7988caacde0e3b977..024f6d27836350ec46617942b9c48ea2ce622bc4 100644 (file)
@@ -180,7 +180,9 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE(
 
       if (Expr) {
         DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
+        DwarfExpr.addFragmentOffset(Expr);
         DwarfExpr.AddExpression(Expr);
+        DwarfExpr.finalize();
       }
     }
 
@@ -498,8 +500,10 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
         DIELoc *Loc = new (DIEValueAllocator) DIELoc;
         DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
         // If there is an expression, emit raw unsigned bytes.
+        DwarfExpr.addFragmentOffset(Expr);
         DwarfExpr.AddUnsignedConstant(DVInsn->getOperand(0).getImm());
         DwarfExpr.AddExpression(Expr);
+        DwarfExpr.finalize();
         addBlock(*VariableDie, dwarf::DW_AT_location, Loc);
       } else
         addConstantValue(*VariableDie, DVInsn->getOperand(0), DV.getType());
@@ -524,11 +528,13 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
     const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();
     int Offset = TFI->getFrameIndexReference(*Asm->MF, FI, FrameReg);
     assert(Expr != DV.getExpression().end() && "Wrong number of expressions");
+    DwarfExpr.addFragmentOffset(*Expr);
     DwarfExpr.AddMachineRegIndirect(*Asm->MF->getSubtarget().getRegisterInfo(),
                                     FrameReg, Offset);
     DwarfExpr.AddExpression(*Expr);
     ++Expr;
   }
+  DwarfExpr.finalize();
   addBlock(*VariableDie, dwarf::DW_AT_location, Loc);
 
   return VariableDie;
@@ -727,16 +733,22 @@ void DwarfCompileUnit::addVariableAddress(const DbgVariable &DV, DIE &Die,
 void DwarfCompileUnit::addAddress(DIE &Die, dwarf::Attribute Attribute,
                                   const MachineLocation &Location) {
   DIELoc *Loc = new (DIEValueAllocator) DIELoc;
+  DIEDwarfExpression Expr(*Asm, *this, *Loc);
 
   bool validReg;
   if (Location.isReg())
-    validReg = addRegisterFragment(*Loc, Location.getReg());
+    validReg = Expr.AddMachineReg(*Asm->MF->getSubtarget().getRegisterInfo(),
+                                  Location.getReg());
   else
-    validReg = addRegisterOffset(*Loc, Location.getReg(), Location.getOffset());
+    validReg =
+        Expr.AddMachineRegIndirect(*Asm->MF->getSubtarget().getRegisterInfo(),
+                                   Location.getReg(), Location.getOffset());
 
   if (!validReg)
     return;
 
+  Expr.finalize();
+
   // Now attach the location information to the DIE.
   addBlock(Die, Attribute, Loc);
 }
@@ -750,9 +762,11 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die,
                                          const MachineLocation &Location) {
   DIELoc *Loc = new (DIEValueAllocator) DIELoc;
   DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
-  DIExpressionCursor ExprCursor(DV.getSingleExpression());
+  const DIExpression *Expr = DV.getSingleExpression();
+  DIExpressionCursor ExprCursor(Expr);
   const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo();
   auto Reg = Location.getReg();
+  DwarfExpr.addFragmentOffset(Expr);
   bool ValidReg =
       Location.getOffset()
           ? DwarfExpr.AddMachineRegIndirect(TRI, Reg, Location.getOffset())
index 5ad0df769862dd52b14532d8c85abdda90d961ff..12949e0991df22644676dd0221159c49180f80c5 100644 (file)
@@ -1413,9 +1413,9 @@ void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer,
 static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
                               ByteStreamer &Streamer,
                               const DebugLocEntry::Value &Value,
-                              unsigned FragmentOffsetInBits) {
+                              DwarfExpression &DwarfExpr) {
   DIExpressionCursor ExprCursor(Value.getExpression());
-  DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer);
+  DwarfExpr.addFragmentOffset(Value.getExpression());
   // Regular entry.
   if (Value.isInt()) {
     if (BT && (BT->getEncoding() == dwarf::DW_ATE_signed ||
@@ -1425,23 +1425,16 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
       DwarfExpr.AddUnsignedConstant(Value.getInt());
   } else if (Value.isLocation()) {
     MachineLocation Loc = Value.getLoc();
-    if (!ExprCursor)
-      // Regular entry.
-      AP.EmitDwarfRegOp(Streamer, Loc);
-    else {
-      // Complex address entry.
-      const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo();
-      if (Loc.getOffset())
-        DwarfExpr.AddMachineRegIndirect(TRI, Loc.getReg(), Loc.getOffset());
-      else
-        DwarfExpr.AddMachineRegExpression(TRI, ExprCursor, Loc.getReg(),
-                                          FragmentOffsetInBits);
-    }
+    const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo();
+    if (Loc.getOffset())
+      DwarfExpr.AddMachineRegIndirect(TRI, Loc.getReg(), Loc.getOffset());
+    else
+      DwarfExpr.AddMachineRegExpression(TRI, ExprCursor, Loc.getReg());
   } else if (Value.isConstantFP()) {
     APInt RawBytes = Value.getConstantFP()->getValueAPF().bitcastToAPInt();
     DwarfExpr.AddUnsignedConstant(RawBytes);
   }
-  DwarfExpr.AddExpression(std::move(ExprCursor), FragmentOffsetInBits);
+  DwarfExpr.AddExpression(std::move(ExprCursor));
 }
 
 void DebugLocEntry::finalize(const AsmPrinter &AP,
@@ -1449,6 +1442,7 @@ void DebugLocEntry::finalize(const AsmPrinter &AP,
                              const DIBasicType *BT) {
   DebugLocStream::EntryBuilder Entry(List, Begin, End);
   BufferByteStreamer Streamer = Entry.getStreamer();
+  DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer);
   const DebugLocEntry::Value &Value = Values[0];
   if (Value.isFragment()) {
     // Emit all fragments that belong to the same variable and range.
@@ -1457,27 +1451,15 @@ void DebugLocEntry::finalize(const AsmPrinter &AP,
         }) && "all values are expected to be fragments");
     assert(std::is_sorted(Values.begin(), Values.end()) &&
            "fragments are expected to be sorted");
-   
-    unsigned Offset = 0;
-    for (auto Fragment : Values) {
-      const DIExpression *Expr = Fragment.getExpression();
-      unsigned FragmentOffset = Expr->getFragmentOffsetInBits();
-      unsigned FragmentSize = Expr->getFragmentSizeInBits();
-      assert(Offset <= FragmentOffset && "overlapping or duplicate fragments");
-      if (Offset < FragmentOffset) {
-        // DWARF represents gaps as pieces with no locations.
-        DebugLocDwarfExpression Expr(AP.getDwarfVersion(), Streamer);
-        Expr.AddOpPiece(FragmentOffset-Offset, 0);
-        Offset += FragmentOffset-Offset;
-      }
-      Offset += FragmentSize;
 
-      emitDebugLocValue(AP, BT, Streamer, Fragment, FragmentOffset);
-    }
+    for (auto Fragment : Values)
+      emitDebugLocValue(AP, BT, Streamer, Fragment, DwarfExpr);
+
   } else {
     assert(Values.size() == 1 && "only fragments may have >1 value");
-    emitDebugLocValue(AP, BT, Streamer, Value, 0);
+    emitDebugLocValue(AP, BT, Streamer, Value, DwarfExpr);
   }
+  DwarfExpr.finalize();
 }
 
 void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry) {
index fe999efa2c9038cf6bab82c2c496a107982c51bd..a17776f2ce9cab766e3f0647cc07d2f0f17673df 100644 (file)
@@ -46,7 +46,9 @@ void DwarfExpression::AddRegIndirect(int DwarfReg, int Offset, bool Deref) {
 }
 
 void DwarfExpression::AddOpPiece(unsigned SizeInBits, unsigned OffsetInBits) {
-  assert(SizeInBits > 0 && "piece has size zero");
+  if (!SizeInBits)
+    return;
+
   const unsigned SizeOfByte = 8;
   if (OffsetInBits > 0 || SizeInBits % SizeOfByte) {
     EmitOp(dwarf::DW_OP_bit_piece);
@@ -57,6 +59,7 @@ void DwarfExpression::AddOpPiece(unsigned SizeInBits, unsigned OffsetInBits) {
     unsigned ByteSize = SizeInBits / SizeOfByte;
     EmitUnsigned(ByteSize);
   }
+  this->OffsetInBits += SizeInBits;
 }
 
 void DwarfExpression::AddShr(unsigned ShiftBy) {
@@ -82,10 +85,8 @@ bool DwarfExpression::AddMachineRegIndirect(const TargetRegisterInfo &TRI,
   return true;
 }
 
-bool DwarfExpression::AddMachineRegFragment(const TargetRegisterInfo &TRI,
-                                            unsigned MachineReg,
-                                            unsigned FragmentSizeInBits,
-                                            unsigned FragmentOffsetInBits) {
+bool DwarfExpression::AddMachineReg(const TargetRegisterInfo &TRI,
+                                    unsigned MachineReg) {
   if (!TRI.isPhysicalRegister(MachineReg))
     return false;
 
@@ -94,8 +95,6 @@ bool DwarfExpression::AddMachineRegFragment(const TargetRegisterInfo &TRI,
   // If this is a valid register number, emit it.
   if (Reg >= 0) {
     AddReg(Reg);
-    if (FragmentSizeInBits)
-      AddOpPiece(FragmentSizeInBits, FragmentOffsetInBits);
     return true;
   }
 
@@ -108,24 +107,15 @@ bool DwarfExpression::AddMachineRegFragment(const TargetRegisterInfo &TRI,
       unsigned Size = TRI.getSubRegIdxSize(Idx);
       unsigned RegOffset = TRI.getSubRegIdxOffset(Idx);
       AddReg(Reg, "super-register");
-      if (FragmentOffsetInBits == RegOffset) {
-        AddOpPiece(Size, RegOffset);
-      } else {
-        // If this is part of a variable in a sub-register at a non-zero offset,
-        // we need to manually shift the value into place, since the
-        // DW_OP_LLVM_fragment describes the part of the variable, not the
-        // position of the subregister.
-        if (RegOffset)
-          AddShr(RegOffset);
-        AddOpPiece(Size, FragmentOffsetInBits);
-      }
+      // Use a DW_OP_bit_piece to describe the sub-register.
+      setSubRegisterPiece(Size, RegOffset);
       return true;
     }
   }
 
   // Otherwise, attempt to find a covering set of sub-register numbers.
   // For example, Q0 on ARM is a composition of D0+D1.
-  unsigned CurPos = FragmentOffsetInBits;
+  unsigned CurPos = 0;
   // The size of the register in bits, assuming 8 bits per byte.
   unsigned RegSize = TRI.getMinimalPhysRegClass(MachineReg)->getSize() * 8;
   // Keep track of the bits in the register we already emitted, so we
@@ -147,7 +137,10 @@ bool DwarfExpression::AddMachineRegFragment(const TargetRegisterInfo &TRI,
     // its range, emit a DWARF piece for it.
     if (Reg >= 0 && Intersection.any()) {
       AddReg(Reg, "sub-register");
-      AddOpPiece(Size, Offset == CurPos ? 0 : Offset);
+      // Emit a piece for the any gap in the coverage.
+      if (Offset > CurPos)
+        AddOpPiece(Offset - CurPos);
+      AddOpPiece(Size);
       CurPos = Offset + Size;
 
       // Mark it as emitted.
@@ -155,7 +148,7 @@ bool DwarfExpression::AddMachineRegFragment(const TargetRegisterInfo &TRI,
     }
   }
 
-  return CurPos > FragmentOffsetInBits;
+  return CurPos;
 }
 
 void DwarfExpression::AddStackValue() {
@@ -191,35 +184,21 @@ void DwarfExpression::AddUnsignedConstant(const APInt &Value) {
   }
 }
 
-static unsigned getOffsetOrZero(unsigned OffsetInBits,
-                                unsigned FragmentOffsetInBits) {
-  if (OffsetInBits == FragmentOffsetInBits)
-    return 0;
-  assert(OffsetInBits >= FragmentOffsetInBits && "overlapping fragments");
-  return OffsetInBits;
-}
-
 bool DwarfExpression::AddMachineRegExpression(const TargetRegisterInfo &TRI,
                                               DIExpressionCursor &ExprCursor,
                                               unsigned MachineReg,
                                               unsigned FragmentOffsetInBits) {
   if (!ExprCursor)
-    return AddMachineRegFragment(TRI, MachineReg);
+    return AddMachineReg(TRI, MachineReg);
 
   // Pattern-match combinations for which more efficient representations exist
   // first.
   bool ValidReg = false;
   auto Op = ExprCursor.peek();
   switch (Op->getOp()) {
-  case dwarf::DW_OP_LLVM_fragment: {
-    unsigned OffsetInBits = Op->getArg(0);
-    unsigned SizeInBits = Op->getArg(1);
-    // Piece always comes at the end of the expression.
-    AddMachineRegFragment(TRI, MachineReg, SizeInBits,
-                          getOffsetOrZero(OffsetInBits, FragmentOffsetInBits));
-    ExprCursor.take();
+  default:
+    ValidReg = AddMachineReg(TRI, MachineReg);
     break;
-  }
   case dwarf::DW_OP_plus:
   case dwarf::DW_OP_minus: {
     // [DW_OP_reg,Offset,DW_OP_plus, DW_OP_deref] --> [DW_OP_breg, Offset].
@@ -231,7 +210,7 @@ bool DwarfExpression::AddMachineRegExpression(const TargetRegisterInfo &TRI,
           TRI, MachineReg, Op->getOp() == dwarf::DW_OP_plus ? Offset : -Offset);
       ExprCursor.consume(2);
     } else
-      ValidReg = AddMachineRegFragment(TRI, MachineReg);
+      ValidReg = AddMachineReg(TRI, MachineReg);
     break;
   }
   case dwarf::DW_OP_deref:
@@ -250,10 +229,25 @@ void DwarfExpression::AddExpression(DIExpressionCursor &&ExprCursor,
     auto Op = ExprCursor.take();
     switch (Op->getOp()) {
     case dwarf::DW_OP_LLVM_fragment: {
-      unsigned OffsetInBits = Op->getArg(0);
-      unsigned SizeInBits   = Op->getArg(1);
-      AddOpPiece(SizeInBits,
-                 getOffsetOrZero(OffsetInBits, FragmentOffsetInBits));
+      unsigned SizeInBits = Op->getArg(1);
+      unsigned FragmentOffset = Op->getArg(0);
+      // The fragment offset must have already been adjusted by emitting an
+      // empty DW_OP_piece / DW_OP_bit_piece before we emitted the base
+      // location.
+      assert(OffsetInBits >= FragmentOffset && "fragment offset not added?");
+
+      // If \a AddMachineReg already emitted DW_OP_piece operations to represent
+      // a super-register by splicing together sub-registers, subtract the size
+      // of the pieces that was already emitted.
+      SizeInBits -= OffsetInBits - FragmentOffset;
+
+      // If \a AddMachineReg requested a DW_OP_bit_piece to stencil out a
+      // sub-register that is smaller than the current fragment's size, use it.
+      if (SubRegisterSizeInBits)
+        SizeInBits = std::min<unsigned>(SizeInBits, SubRegisterSizeInBits);
+      
+      AddOpPiece(SizeInBits, SubRegisterOffsetInBits);
+      setSubRegisterPiece(0, 0);
       break;
     }
     case dwarf::DW_OP_plus:
@@ -281,3 +275,20 @@ void DwarfExpression::AddExpression(DIExpressionCursor &&ExprCursor,
     }
   }
 }
+
+void DwarfExpression::finalize() {
+  if (SubRegisterSizeInBits)
+    AddOpPiece(SubRegisterSizeInBits, SubRegisterOffsetInBits);
+}
+
+void DwarfExpression::addFragmentOffset(const DIExpression *Expr) {
+  if (!Expr || !Expr->isFragment())
+    return;
+
+  uint64_t FragmentOffset = Expr->getFragmentOffsetInBits();
+  assert(FragmentOffset >= OffsetInBits &&
+         "overlapping or duplicate fragments");
+  if (FragmentOffset > OffsetInBits)
+    AddOpPiece(FragmentOffset - OffsetInBits);
+  OffsetInBits = FragmentOffset;
+}
index b24074bc9189b55200c474d72d65cc9157c1a137..bebf3db42c6144d99e65dd4cf548acf869ffa747 100644 (file)
@@ -39,6 +39,9 @@ public:
     End = Expr->expr_op_end();
   }
 
+  DIExpressionCursor(ArrayRef<uint64_t> Expr)
+      : Start(Expr.begin()), End(Expr.end()) {}
+
   /// Consume one operation.
   Optional<DIExpression::ExprOperand> take() {
     if (Start == End)
@@ -77,10 +80,26 @@ public:
 class DwarfExpression {
 protected:
   unsigned DwarfVersion;
+  /// Current Fragment Offset in Bits.
+  uint64_t OffsetInBits = 0;
+
+  /// Sometimes we need to add a DW_OP_bit_piece to describe a subregister. 
+  unsigned SubRegisterSizeInBits = 0;
+  unsigned SubRegisterOffsetInBits = 0;
+
+  /// Push a DW_OP_piece / DW_OP_bit_piece for emitting later, if one is needed
+  /// to represent a subregister.
+  void setSubRegisterPiece(unsigned SizeInBits, unsigned OffsetInBits) {
+    SubRegisterSizeInBits = SizeInBits;
+    SubRegisterOffsetInBits = OffsetInBits;
+  }
 
 public:
   DwarfExpression(unsigned DwarfVersion) : DwarfVersion(DwarfVersion) {}
-  virtual ~DwarfExpression() {}
+  virtual ~DwarfExpression() {};
+
+  /// This needs to be called last to commit any pending changes.
+  void finalize();
 
   /// Output a dwarf operand and an optional assembler comment.
   virtual void EmitOp(uint8_t Op, const char *Comment = nullptr) = 0;
@@ -97,9 +116,9 @@ public:
   /// Emit an (double-)indirect dwarf register operation.
   void AddRegIndirect(int DwarfReg, int Offset, bool Deref = false);
 
-  /// Emit a DW_OP_piece operation for a variable fragment.
-  /// \param OffsetInBits    This is the offset where the fragment appears
-  ///                        inside the *source variable*.
+  /// Emit a DW_OP_piece or DW_OP_bit_piece operation for a variable fragment.
+  /// \param OffsetInBits    This is an optional offset into the location that
+  /// is at the top of the DWARF stack.
   void AddOpPiece(unsigned SizeInBits, unsigned OffsetInBits = 0);
 
   /// Emit a shift-right dwarf expression.
@@ -125,10 +144,7 @@ public:
 
   /// Emit a partial DWARF register operation.
   ///
-  /// \param MachineReg           the register,
-  /// \param FragmentSizeInBits   size and
-  /// \param FragmentOffsetInBits offset of the fragment in bits, if this is
-  ///                             a fragment of an aggregate value.
+  /// \param MachineReg           The register number.
   ///
   /// If size and offset is zero an operation for the entire register is
   /// emitted: Some targets do not provide a DWARF register number for every
@@ -137,9 +153,7 @@ public:
   /// multiple subregisters that alias the register.
   ///
   /// \return false if no DWARF register exists for MachineReg.
-  bool AddMachineRegFragment(const TargetRegisterInfo &TRI, unsigned MachineReg,
-                          unsigned FragmentSizeInBits = 0,
-                          unsigned FragmentOffsetInBits = 0);
+  bool AddMachineReg(const TargetRegisterInfo &TRI, unsigned MachineReg);
 
   /// Emit a signed constant.
   void AddSignedConstant(int64_t Value);
@@ -167,6 +181,10 @@ public:
   ///                                 fragment inside the entire variable.
   void AddExpression(DIExpressionCursor &&Expr,
                      unsigned FragmentOffsetInBits = 0);
+
+  /// If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to
+  /// the fragment described by \c Expr.
+  void addFragmentOffset(const DIExpression *Expr);
 };
 
 /// DwarfExpression implementation for .debug_loc entries.
index 68fb5c986f924f7967c2dbda8a55227b034b73c3..4f90245c6d49e85bea1e386a02d5037c1050aef8 100644 (file)
@@ -371,22 +371,6 @@ void DwarfUnit::addSourceLine(DIE &Die, const DINamespace *NS) {
   addSourceLine(Die, NS->getLine(), NS->getFilename(), NS->getDirectory());
 }
 
-bool DwarfUnit::addRegisterFragment(DIELoc &TheDie, unsigned Reg,
-                                    unsigned SizeInBits,
-                                    unsigned OffsetInBits) {
-  DIEDwarfExpression Expr(*Asm, *this, TheDie);
-  Expr.AddMachineRegFragment(*Asm->MF->getSubtarget().getRegisterInfo(), Reg,
-                             SizeInBits, OffsetInBits);
-  return true;
-}
-
-bool DwarfUnit::addRegisterOffset(DIELoc &TheDie, unsigned Reg,
-                                  int64_t Offset) {
-  DIEDwarfExpression Expr(*Asm, *this, TheDie);
-  return Expr.AddMachineRegIndirect(*Asm->MF->getSubtarget().getRegisterInfo(),
-                                    Reg, Offset);
-}
-
 /* Byref variables, in Blocks, are declared by the programmer as "SomeType
    VarName;", but the compiler creates a __Block_byref_x_VarName struct, and
    gives the variable VarName either the struct, or a pointer to the struct, as
@@ -479,12 +463,17 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die,
   // Decode the original location, and use that as the start of the byref
   // variable's location.
   DIELoc *Loc = new (DIEValueAllocator) DIELoc;
+  SmallVector<uint64_t, 6> DIExpr;
+  DIEDwarfExpression Expr(*Asm, *this, *Loc);
 
   bool validReg;
   if (Location.isReg())
-    validReg = addRegisterFragment(*Loc, Location.getReg());
+    validReg = Expr.AddMachineReg(*Asm->MF->getSubtarget().getRegisterInfo(),
+                                  Location.getReg());
   else
-    validReg = addRegisterOffset(*Loc, Location.getReg(), Location.getOffset());
+    validReg =
+        Expr.AddMachineRegIndirect(*Asm->MF->getSubtarget().getRegisterInfo(),
+                                   Location.getReg(), Location.getOffset());
 
   if (!validReg)
     return;
@@ -492,27 +481,29 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die,
   // If we started with a pointer to the __Block_byref... struct, then
   // the first thing we need to do is dereference the pointer (DW_OP_deref).
   if (isPointer)
-    addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_deref);
+    DIExpr.push_back(dwarf::DW_OP_deref);
 
   // Next add the offset for the '__forwarding' field:
   // DW_OP_plus_uconst ForwardingFieldOffset.  Note there's no point in
   // adding the offset if it's 0.
   if (forwardingFieldOffset > 0) {
-    addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
-    addUInt(*Loc, dwarf::DW_FORM_udata, forwardingFieldOffset);
+    DIExpr.push_back(dwarf::DW_OP_plus);
+    DIExpr.push_back(forwardingFieldOffset);
   }
 
   // Now dereference the __forwarding field to get to the real __Block_byref
   // struct:  DW_OP_deref.
-  addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_deref);
+  DIExpr.push_back(dwarf::DW_OP_deref);
 
   // Now that we've got the real __Block_byref... struct, add the offset
   // for the variable's field to get to the location of the actual variable:
   // DW_OP_plus_uconst varFieldOffset.  Again, don't add if it's 0.
   if (varFieldOffset > 0) {
-    addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
-    addUInt(*Loc, dwarf::DW_FORM_udata, varFieldOffset);
+    DIExpr.push_back(dwarf::DW_OP_plus);
+    DIExpr.push_back(varFieldOffset);
   }
+  Expr.AddExpression(makeArrayRef(DIExpr));
+  Expr.finalize();
 
   // Now attach the location information to the DIE.
   addBlock(Die, Attribute, Loc);
index ed975cc80e128fd0c0a11806e56e3a6fe3c46db2..8654d6f0caf438f36941a28df9205dce16cd3644 100644 (file)
@@ -235,19 +235,6 @@ public:
   /// Add template parameters in buffer.
   void addTemplateParams(DIE &Buffer, DINodeArray TParams);
 
-  /// Add register operand for a source variable fragment of the specified size
-  /// and offset.
-  ///
-  /// \returns false if the register does not exist, e.g., because it was never
-  ///          materialized.
-  bool addRegisterFragment(DIELoc &TheDie, unsigned Reg,
-                           unsigned SizeInBits = 0, unsigned OffsetInBits = 0);
-
-  /// Add register offset.
-  /// \returns false if the register does not exist, e.g., because it was never
-  /// materialized.
-  bool addRegisterOffset(DIELoc &TheDie, unsigned Reg, int64_t Offset);
-
   // FIXME: Should be reformulated in terms of addComplexAddress.
   /// Start with the address based on the location provided, and generate the
   /// DWARF information necessary to find the actual Block variable (navigating
index 4514f0162c817147828b92e47cc0d2b78139c283..2c0d75aa47c6d425455ddeb711cee7cd5b5cee3d 100644 (file)
@@ -5,8 +5,8 @@
 ; CHECK: DW_TAG_inlined_subroutine
 ; CHECK:    "_Z3f111A"
 ; CHECK: DW_TAG_formal_parameter
-; CHECK: DW_AT_location [DW_FORM_block1]    (<0x0b> 91 51 9d 78 08 91 4a 9d 38 88 01 )
-;  -- fbreg -47, bit-piece 120 8 , fbreg -54, bit-piece 56 136 ------^
+; CHECK: DW_AT_location [DW_FORM_block1]    (<0x0c> 93 01 91 51 93 0f 93 01 91 4a 93 07 )
+;  -- piece 0x00000001, fbreg -47, piece 0x0000000f, piece 0x00000001, fbreg -54, piece 0x00000007 ------^
 ; CHECK: DW_AT_abstract_origin {{.*}} "p1"
 ;
 ; long a;
diff --git a/test/DebugInfo/MIR/ARM/lit.local.cfg b/test/DebugInfo/MIR/ARM/lit.local.cfg
new file mode 100644 (file)
index 0000000..98c6700
--- /dev/null
@@ -0,0 +1,3 @@
+if not 'ARM' in config.root.targets:
+    config.unsupported = True
+
diff --git a/test/DebugInfo/MIR/ARM/split-superreg-piece.mir b/test/DebugInfo/MIR/ARM/split-superreg-piece.mir
new file mode 100644 (file)
index 0000000..422e7ed
--- /dev/null
@@ -0,0 +1,125 @@
+# RUN: llc -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s
+# CHECK: .debug_info contents:
+# CHECK: DW_TAG_variable
+# CHECK-NEXT: DW_AT_location [DW_FORM_data4]   ([[OFS:.*]])
+# CHECK-NEXT: DW_AT_name {{.*}}"vec"
+# CHECK: .debug_loc contents:
+# CHECK: [[OFS]]: Beginning address offset: 0x0000000000000016
+# CHECK:             Ending address offset: 0x000000000000001e
+# CHECK:              Location description: 93 10 90 80 02 93 08 90 81 02 93 08 
+#                  piece 0x00000010, d0, piece 0x00000008, d1, piece 0x00000008
+--- |
+  ; Generate from (and then manually modified to incorporate a DW_OP_LLVM_fragment):
+  ; typedef float vec2 __attribute__((vector_size(16)));
+  ; vec2 v();
+  ; float f() {
+  ;   vec2 vec = v();
+  ;   return vec[0] + vec[1];
+  ; }
+
+  target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
+  target triple = "thumbv7s-apple-ios5.0.0"
+  
+  define float @f() local_unnamed_addr #0 !dbg !9 {
+  entry:
+    %call = tail call <4 x float> bitcast (<4 x float> (...)* @v to <4 x float> ()*)() #0, !dbg !19
+    tail call void @llvm.dbg.value(metadata <4 x float> %call, i64 0, metadata !14, metadata !20), !dbg !21
+    %vecext = extractelement <4 x float> %call, i32 0, !dbg !22
+    %vecext1 = extractelement <4 x float> %call, i32 1, !dbg !23
+    %add = fadd float %vecext, %vecext1, !dbg !24
+    ret float %add, !dbg !25
+  }
+  
+  declare arm_aapcs_vfpcc <4 x float> @v(...) local_unnamed_addr #0
+  
+  declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #0
+  
+  attributes #0 = { nounwind readnone }
+  
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!3, !4, !5, !6, !7}
+  !llvm.ident = !{!8}
+  
+  !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+  !1 = !DIFile(filename: "v.c", directory: "/")
+  !2 = !{}
+  !3 = !{i32 2, !"Dwarf Version", i32 2}
+  !4 = !{i32 2, !"Debug Info Version", i32 3}
+  !5 = !{i32 1, !"wchar_size", i32 4}
+  !6 = !{i32 1, !"min_enum_size", i32 4}
+  !7 = !{i32 1, !"PIC Level", i32 2}
+  !8 = !{!"clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)"}
+  !9 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !10, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, variables: !13)
+  !10 = !DISubroutineType(types: !11)
+  !11 = !{!12}
+  !12 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
+  !13 = !{!14}
+  !14 = !DILocalVariable(name: "vec", scope: !9, file: !1, line: 4, type: !15)
+  !15 = !DIDerivedType(tag: DW_TAG_typedef, name: "vec2", file: !1, line: 1, baseType: !16)
+  !16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 256, flags: DIFlagVector, elements: !17)
+  !17 = !{!18}
+  !18 = !DISubrange(count: 8)
+  !19 = !DILocation(line: 4, column: 13, scope: !9)
+  !20 = !DIExpression(DW_OP_LLVM_fragment, 128, 128)
+  !21 = !DILocation(line: 4, column: 7, scope: !9)
+  !22 = !DILocation(line: 5, column: 9, scope: !9)
+  !23 = !DILocation(line: 5, column: 18, scope: !9)
+  !24 = !DILocation(line: 5, column: 16, scope: !9)
+  !25 = !DILocation(line: 5, column: 2, scope: !9)
+
+...
+---
+name:            f
+alignment:       1
+exposesReturnsTwice: false
+legalized:       false
+regBankSelected: false
+selected:        false
+tracksRegLiveness: true
+calleeSavedRegisters: [ '%lr', '%d8', '%d9', '%d10', '%d11', '%d12', '%d13', 
+                        '%d14', '%d15', '%q4', '%q5', '%q6', '%q7', '%r4', 
+                        '%r5', '%r6', '%r7', '%r8', '%r10', '%r11', '%s16', 
+                        '%s17', '%s18', '%s19', '%s20', '%s21', '%s22', 
+                        '%s23', '%s24', '%s25', '%s26', '%s27', '%s28', 
+                        '%s29', '%s30', '%s31', '%d8_d10', '%d9_d11', '%d10_d12', 
+                        '%d11_d13', '%d12_d14', '%d13_d15', '%q4_q5', '%q5_q6', 
+                        '%q6_q7', '%q4_q5_q6_q7', '%r4_r5', '%r6_r7', '%r10_r11', 
+                        '%d8_d9_d10', '%d9_d10_d11', '%d10_d11_d12', '%d11_d12_d13', 
+                        '%d12_d13_d14', '%d13_d14_d15', '%d8_d10_d12', 
+                        '%d9_d11_d13', '%d10_d12_d14', '%d11_d13_d15', 
+                        '%d8_d10_d12_d14', '%d9_d11_d13_d15', '%d9_d10', 
+                        '%d11_d12', '%d13_d14', '%d9_d10_d11_d12', '%d11_d12_d13_d14' ]
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       4
+  offsetAdjustment: 0
+  maxAlignment:    4
+  adjustsStack:    true
+  hasCalls:        true
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+stack:           
+  - { id: 0, type: spill-slot, offset: -4, size: 4, alignment: 4, callee-saved-register: '%lr' }
+body:             |
+  bb.0.entry:
+    liveins: %lr
+  
+    early-clobber %sp = frame-setup t2STR_PRE killed undef %lr, %sp, -4, 14, _
+    frame-setup CFI_INSTRUCTION def_cfa_offset 4
+    frame-setup CFI_INSTRUCTION offset %lr, -4
+    tBL 14, _, @v, csr_ios, implicit-def dead %lr, implicit %sp, implicit-def %sp, implicit-def %r0, implicit-def %r1, implicit-def %r2, implicit-def %r3, debug-location !19
+    %d1 = VMOVDRR killed %r2, killed %r3, 14, _, implicit-def %q0, debug-location !19
+    %d0 = VMOVDRR killed %r0, killed %r1, 14, _, implicit killed %q0, implicit-def %q0, debug-location !19
+    DBG_VALUE debug-use %q0, debug-use _, !14, !20, debug-location !21
+    %s4 = VMOVS %s1, 14, _, implicit-def %d2, debug-location !24
+    %d0 = VADDfd %d0, killed %d2, 14, _, implicit killed %q0, debug-location !24
+    %r0 = VMOVRS %s0, 14, _, implicit killed %d0, debug-location !25
+    %lr, %sp = t2LDR_POST %sp, 4, 14, _, debug-location !25
+    tBX_RET 14, _, implicit %r0, debug-location !25
+
+...
diff --git a/test/DebugInfo/MIR/ARM/split-superreg.mir b/test/DebugInfo/MIR/ARM/split-superreg.mir
new file mode 100644 (file)
index 0000000..9b56f9f
--- /dev/null
@@ -0,0 +1,125 @@
+# RUN: llc -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s
+# CHECK: .debug_info contents:
+# CHECK: DW_TAG_variable
+# CHECK-NEXT: DW_AT_location [DW_FORM_data4]   ([[OFS:.*]])
+# CHECK-NEXT: DW_AT_name {{.*}}"vec"
+# CHECK: .debug_loc contents:
+# CHECK: [[OFS]]: Beginning address offset: 0x0000000000000016
+# CHECK:             Ending address offset: 0x000000000000001e
+# CHECK:              Location description: 90 80 02 93 08 90 81 02 93 08 
+#                                           d0, piece 0x00000008, d1, piece 0x00000008
+--- |
+  ; Generated from:
+  ; typedef float vec2 __attribute__((vector_size(16)));
+  ; vec2 v();
+  ; float f() {
+  ;   vec2 vec = v();
+  ;   return vec[0] + vec[1];
+  ; }
+
+  target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
+  target triple = "thumbv7s-apple-ios5.0.0"
+  
+  define float @f() local_unnamed_addr #0 !dbg !9 {
+  entry:
+    %call = tail call <4 x float> bitcast (<4 x float> (...)* @v to <4 x float> ()*)() #0, !dbg !19
+    tail call void @llvm.dbg.value(metadata <4 x float> %call, i64 0, metadata !14, metadata !20), !dbg !21
+    %vecext = extractelement <4 x float> %call, i32 0, !dbg !22
+    %vecext1 = extractelement <4 x float> %call, i32 1, !dbg !23
+    %add = fadd float %vecext, %vecext1, !dbg !24
+    ret float %add, !dbg !25
+  }
+  
+  declare arm_aapcs_vfpcc <4 x float> @v(...) local_unnamed_addr #0
+  
+  declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #0
+  
+  attributes #0 = { nounwind readnone }
+  
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!3, !4, !5, !6, !7}
+  !llvm.ident = !{!8}
+  
+  !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+  !1 = !DIFile(filename: "v.c", directory: "/")
+  !2 = !{}
+  !3 = !{i32 2, !"Dwarf Version", i32 2}
+  !4 = !{i32 2, !"Debug Info Version", i32 3}
+  !5 = !{i32 1, !"wchar_size", i32 4}
+  !6 = !{i32 1, !"min_enum_size", i32 4}
+  !7 = !{i32 1, !"PIC Level", i32 2}
+  !8 = !{!"clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)"}
+  !9 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !10, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, variables: !13)
+  !10 = !DISubroutineType(types: !11)
+  !11 = !{!12}
+  !12 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
+  !13 = !{!14}
+  !14 = !DILocalVariable(name: "vec", scope: !9, file: !1, line: 4, type: !15)
+  !15 = !DIDerivedType(tag: DW_TAG_typedef, name: "vec2", file: !1, line: 1, baseType: !16)
+  !16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 128, flags: DIFlagVector, elements: !17)
+  !17 = !{!18}
+  !18 = !DISubrange(count: 4)
+  !19 = !DILocation(line: 4, column: 13, scope: !9)
+  !20 = !DIExpression()
+  !21 = !DILocation(line: 4, column: 7, scope: !9)
+  !22 = !DILocation(line: 5, column: 9, scope: !9)
+  !23 = !DILocation(line: 5, column: 18, scope: !9)
+  !24 = !DILocation(line: 5, column: 16, scope: !9)
+  !25 = !DILocation(line: 5, column: 2, scope: !9)
+
+...
+---
+name:            f
+alignment:       1
+exposesReturnsTwice: false
+legalized:       false
+regBankSelected: false
+selected:        false
+tracksRegLiveness: true
+calleeSavedRegisters: [ '%lr', '%d8', '%d9', '%d10', '%d11', '%d12', '%d13', 
+                        '%d14', '%d15', '%q4', '%q5', '%q6', '%q7', '%r4', 
+                        '%r5', '%r6', '%r7', '%r8', '%r10', '%r11', '%s16', 
+                        '%s17', '%s18', '%s19', '%s20', '%s21', '%s22', 
+                        '%s23', '%s24', '%s25', '%s26', '%s27', '%s28', 
+                        '%s29', '%s30', '%s31', '%d8_d10', '%d9_d11', '%d10_d12', 
+                        '%d11_d13', '%d12_d14', '%d13_d15', '%q4_q5', '%q5_q6', 
+                        '%q6_q7', '%q4_q5_q6_q7', '%r4_r5', '%r6_r7', '%r10_r11', 
+                        '%d8_d9_d10', '%d9_d10_d11', '%d10_d11_d12', '%d11_d12_d13', 
+                        '%d12_d13_d14', '%d13_d14_d15', '%d8_d10_d12', 
+                        '%d9_d11_d13', '%d10_d12_d14', '%d11_d13_d15', 
+                        '%d8_d10_d12_d14', '%d9_d11_d13_d15', '%d9_d10', 
+                        '%d11_d12', '%d13_d14', '%d9_d10_d11_d12', '%d11_d12_d13_d14' ]
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       4
+  offsetAdjustment: 0
+  maxAlignment:    4
+  adjustsStack:    true
+  hasCalls:        true
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+stack:           
+  - { id: 0, type: spill-slot, offset: -4, size: 4, alignment: 4, callee-saved-register: '%lr' }
+body:             |
+  bb.0.entry:
+    liveins: %lr
+  
+    early-clobber %sp = frame-setup t2STR_PRE killed undef %lr, %sp, -4, 14, _
+    frame-setup CFI_INSTRUCTION def_cfa_offset 4
+    frame-setup CFI_INSTRUCTION offset %lr, -4
+    tBL 14, _, @v, csr_ios, implicit-def dead %lr, implicit %sp, implicit-def %sp, implicit-def %r0, implicit-def %r1, implicit-def %r2, implicit-def %r3, debug-location !19
+    %d1 = VMOVDRR killed %r2, killed %r3, 14, _, implicit-def %q0, debug-location !19
+    %d0 = VMOVDRR killed %r0, killed %r1, 14, _, implicit killed %q0, implicit-def %q0, debug-location !19
+    DBG_VALUE debug-use %q0, debug-use _, !14, !20, debug-location !21
+    %s4 = VMOVS %s1, 14, _, implicit-def %d2, debug-location !24
+    %d0 = VADDfd %d0, killed %d2, 14, _, implicit killed %q0, debug-location !24
+    %r0 = VMOVRS %s0, 14, _, implicit killed %d0, debug-location !25
+    %lr, %sp = t2LDR_POST %sp, 4, 14, _, debug-location !25
+    tBX_RET 14, _, implicit %r0, debug-location !25
+
+...
diff --git a/test/DebugInfo/MIR/X86/bit-piece-dh.mir b/test/DebugInfo/MIR/X86/bit-piece-dh.mir
new file mode 100644 (file)
index 0000000..34a10bd
--- /dev/null
@@ -0,0 +1,102 @@
+# RUN: llc -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s
+# CHECK: .debug_info contents:
+# CHECK: DW_TAG_variable
+# CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset]      ([[OFS:.*]])
+# CHECK-NEXT: DW_AT_name {{.*}}"dh"
+# CHECK: .debug_loc contents:
+# CHECK: [[OFS]]: Beginning address offset: 0x0000000000000002
+# CHECK:             Ending address offset: 0x000000000000000c
+# CHECK:              Location description: 51 9d 08 08
+#                                           rdx, bit-piece 8 8
+--- |
+  ; Manually created after:
+  ; char f(int i) {
+  ;   char dh = i>>8;
+  ;   return dh;
+  ; }
+
+  target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+  target triple = "x86_64-apple-macosx10.12.0"
+  
+  define signext i8 @f(i32 %i) local_unnamed_addr #0 !dbg !7 {
+  entry:
+    tail call void @llvm.dbg.value(metadata i32 %i, i64 0, metadata !13, metadata !15), !dbg !16
+    %shr1 = lshr i32 %i, 8, !dbg !17
+    %conv = trunc i32 %shr1 to i8, !dbg !18
+    tail call void @llvm.dbg.value(metadata i8 %conv, i64 0, metadata !14, metadata !15), !dbg !19
+    ret i8 %conv, !dbg !20
+  }
+  
+  declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #0
+  
+  attributes #0 = { nounwind readnone }
+  
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!3, !4, !5}
+  !llvm.ident = !{!6}
+  
+  !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 288677) (llvm/trunk 288679)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+  !1 = !DIFile(filename: "t.c", directory: "/")
+  !2 = !{}
+  !3 = !{i32 2, !"Dwarf Version", i32 4}
+  !4 = !{i32 2, !"Debug Info Version", i32 3}
+  !5 = !{i32 1, !"PIC Level", i32 2}
+  !6 = !{!"clang version 4.0.0 (trunk 288677) (llvm/trunk 288679)"}
+  !7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
+  !8 = !DISubroutineType(types: !9)
+  !9 = !{!10, !11}
+  !10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+  !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+  !12 = !{!13, !14}
+  !13 = !DILocalVariable(name: "i", arg: 1, scope: !7, file: !1, line: 1, type: !11)
+  !14 = !DILocalVariable(name: "dh", scope: !7, file: !1, line: 2, type: !10)
+  !15 = !DIExpression()
+  !16 = !DILocation(line: 1, column: 12, scope: !7)
+  !17 = !DILocation(line: 2, column: 14, scope: !7)
+  !18 = !DILocation(line: 2, column: 13, scope: !7)
+  !19 = !DILocation(line: 2, column: 8, scope: !7)
+  !20 = !DILocation(line: 3, column: 3, scope: !7)
+
+...
+---
+name:            f
+alignment:       4
+exposesReturnsTwice: false
+legalized:       false
+regBankSelected: false
+selected:        false
+tracksRegLiveness: true
+liveins:         
+  - { reg: '%edi' }
+frameInfo:       
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       8
+  offsetAdjustment: 0
+  maxAlignment:    0
+  adjustsStack:    false
+  hasCalls:        false
+  maxCallFrameSize: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+fixedStack:      
+  - { id: 0, type: spill-slot, offset: -16, size: 8, alignment: 16 }
+body:             |
+  bb.0.entry:
+    liveins: %edi, %rbp
+  
+    frame-setup PUSH64r killed %rbp, implicit-def %rsp, implicit %rsp
+    CFI_INSTRUCTION def_cfa_offset 16
+    CFI_INSTRUCTION offset %rbp, -16
+    %rbp = frame-setup MOV64rr %rsp
+    CFI_INSTRUCTION def_cfa_register %rbp
+    DBG_VALUE debug-use %dh, debug-use _, !14, !15, debug-location !16
+    %edi = SHR32ri killed %edi, 8, implicit-def dead %eflags, debug-location !17
+    %eax = MOVSX32rr8 %dil, implicit killed %edi, debug-location !20
+    %rbp = POP64r implicit-def %rsp, implicit %rsp, debug-location !20
+    RETQ %eax, debug-location !20
+
+...
index 0b2b082ad41e242b17afd0dd4b14cdfc38d73d44..b544ab5c1027f63056a15f963dc6174e1a729df0 100644 (file)
@@ -21,8 +21,8 @@
 ;
 ; CHECK: 0x00000025: Beginning address offset: 0x0000000000000004
 ; CHECK:                Ending address offset: 0x0000000000000004
-; CHECK:                 Location description: 10 03 93 04 55 93 04
-; constu 0x00000003, piece 0x00000004, rdi, piece 0x00000004
+; CHECK:                 Location description: 10 03 93 04 55 93 02
+; constu 0x00000003, piece 0x00000004, rdi, piece 0x00000002
 ; CHECK:             Beginning address offset: 0x0000000000000004
 ; CHECK:                Ending address offset: 0x0000000000000014
 ; CHECK:                 Location description: 10 03 93 04 10 00
diff --git a/test/DebugInfo/X86/dw_op_minus_direct.ll b/test/DebugInfo/X86/dw_op_minus_direct.ll
new file mode 100644 (file)
index 0000000..a84c506
--- /dev/null
@@ -0,0 +1,48 @@
+; Test dwarf codegen of DW_OP_minus.
+; RUN: llc -filetype=obj < %s | llvm-dwarfdump - | FileCheck %s
+
+; This was derived manually from:
+; int inc(int i) {
+;  return i+1;
+; }
+
+; CHECK: Beginning address offset: 0x0000000000000000
+; CHECK:    Ending address offset: 0x0000000000000004
+; CHECK:     Location description: 50 10 01 1c 93 04
+;                                  rax, constu 0x00000001, minus, piece 0x00000004
+source_filename = "minus.c"
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.12.0"
+
+define i32 @inc(i32 %i) local_unnamed_addr #1 !dbg !7 {
+entry:
+  %add = add nsw i32 %i, 1, !dbg !15
+  tail call void @llvm.dbg.value(metadata i32 %add, i64 0, metadata !12, metadata !13), !dbg !14
+  ret i32 %add, !dbg !16
+}
+
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1
+
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "minus.c", directory: "/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"PIC Level", i32 2}
+!6 = !{!"clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)"}
+!7 = distinct !DISubprogram(name: "inc", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12}
+!12 = !DILocalVariable(name: "i", arg: 1, scope: !7, file: !1, line: 1, type: !10)
+!13 = !DIExpression(DW_OP_minus, 1)
+!14 = !DILocation(line: 1, column: 13, scope: !7)
+!15 = !DILocation(line: 2, column: 11, scope: !7)
+!16 = !DILocation(line: 2, column: 3, scope: !7)