]> granicus.if.org Git - llvm/commitdiff
Align definition of DW_OP_plus with DWARF spec [3/3]
authorFlorian Hahn <florian.hahn@arm.com>
Wed, 14 Jun 2017 13:14:38 +0000 (13:14 +0000)
committerFlorian Hahn <florian.hahn@arm.com>
Wed, 14 Jun 2017 13:14:38 +0000 (13:14 +0000)
Summary:
This patch is part of 3 patches that together form a single patch, but must be introduced in stages in order not to break things.

The way that LLVM interprets DW_OP_plus in DIExpression nodes is basically that of the DW_OP_plus_uconst operator since LLVM expects an unsigned constant operand. This unnecessarily restricts the DW_OP_plus operator, preventing it from being used to describe the evaluation of runtime values on the expression stack. These patches try to align the semantics of DW_OP_plus and DW_OP_minus with that of the DWARF definition, which pops two elements off the expression stack, performs the operation and pushes the result back on the stack.

This is done in three stages:
• The first patch (LLVM) adds support for DW_OP_plus_uconst.
• The second patch (Clang) contains changes all its uses from DW_OP_plus to DW_OP_plus_uconst.
• The third patch (LLVM) changes the semantics of DW_OP_plus and DW_OP_minus to be in line with its DWARF meaning. This patch includes the bitcode upgrade from legacy DIExpressions.

Patch by Sander de Smalen.

Reviewers: echristo, pcc, aprantl

Reviewed By: aprantl

Subscribers: fhahn, javed.absar, aprantl, llvm-commits

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

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

33 files changed:
docs/LangRef.rst
include/llvm/IR/DebugInfoMetadata.h
lib/Bitcode/Reader/MetadataLoader.cpp
lib/Bitcode/Writer/BitcodeWriter.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/IR/DebugInfoMetadata.cpp
lib/IR/Metadata.cpp
test/Assembler/diexpression.ll
test/Bitcode/DIExpression-deref.ll
test/Bitcode/DIExpression-minus-upgrade.ll [new file with mode: 0644]
test/Bitcode/DIExpression-minus-upgrade.ll.bc [new file with mode: 0644]
test/Bitcode/DIGlobalVariableExpression.ll
test/CodeGen/ARM/debug-info-blocks.ll
test/CodeGen/X86/lea-opt-with-debug.mir
test/DebugInfo/Generic/block-asan.ll
test/DebugInfo/MIR/ARM/split-superreg-complex.mir
test/DebugInfo/X86/block-capture.ll
test/DebugInfo/X86/debug-info-block-captured-self.ll
test/DebugInfo/X86/debug-info-blocks.ll
test/DebugInfo/X86/dw_op_minus.ll
test/DebugInfo/X86/dw_op_minus_direct.ll
test/DebugInfo/X86/safestack-byval.ll
test/DebugInfo/X86/stack-value-dwarf2.ll
test/DebugInfo/X86/unattached-global.ll
test/Transforms/GlobalMerge/debug-info.ll
test/Transforms/InstCombine/debuginfo-dce.ll
test/Transforms/SafeStack/X86/debug-loc.ll
test/Transforms/SafeStack/X86/debug-loc2.ll
unittests/IR/MetadataTest.cpp

index 24362825d8220ef7385ec5dbff9107d5c09727d4..ec445489d8b9cb1efeff9efa68e6a21061bf4188 100644 (file)
@@ -4404,7 +4404,11 @@ referenced LLVM variable relates to the source language variable.
 The current supported vocabulary is limited:
 
 - ``DW_OP_deref`` dereferences the top of the expression stack.
-- ``DW_OP_plus, 93`` adds ``93`` to the working expression.
+- ``DW_OP_plus`` pops the last two entries from the expression stack, adds
+  them together and appends the result to the expression stack.
+- ``DW_OP_minus`` pops the last two entries from the expression stack, subtracts
+  the last entry from the second last entry and appends the result to the
+  expression stack.
 - ``DW_OP_plus_uconst, 93`` adds ``93`` to the working expression.
 - ``DW_OP_LLVM_fragment, 16, 8`` specifies the offset and size (``16`` and ``8``
   here, respectively) of the variable fragment from the working expression. Note
@@ -4427,10 +4431,10 @@ combined with a concrete location.
 .. code-block:: llvm
 
     !0 = !DIExpression(DW_OP_deref)
-    !1 = !DIExpression(DW_OP_plus, 3)
     !1 = !DIExpression(DW_OP_plus_uconst, 3)
+    !1 = !DIExpression(DW_OP_constu, 3, DW_OP_plus)
     !2 = !DIExpression(DW_OP_bit_piece, 3, 7)
-    !3 = !DIExpression(DW_OP_deref, DW_OP_plus, 3, DW_OP_LLVM_fragment, 3, 7)
+    !3 = !DIExpression(DW_OP_deref, DW_OP_constu, 3, DW_OP_plus, DW_OP_LLVM_fragment, 3, 7)
     !4 = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef)
     !5 = !DIExpression(DW_OP_constu, 42, DW_OP_stack_value)
 
index 2174e1f301ee12332dab5d52938c8c72df49fab1..9374fe4fae7667c0b31de04bc2ad65e7e5468a72 100644 (file)
@@ -2117,9 +2117,6 @@ public:
 /// variable, or the location of a single piece of a variable, or (when using
 /// DW_OP_stack_value) is the constant variable value.
 ///
-/// FIXME: Instead of DW_OP_plus taking an argument, this should use DW_OP_const
-/// and have DW_OP_plus consume the topmost elements on the stack.
-///
 /// TODO: Co-allocate the expression elements.
 /// TODO: Separate from MDNode, or otherwise drop Distinct and Temporary
 /// storage types.
index ee2fe2a0cc1883d583f17ac2a7cef7e72bdb2f7d..b1504a8034e0c02d2f299f1424a3e1fe57794bb2 100644 (file)
@@ -407,6 +407,11 @@ void PlaceholderQueue::flush(BitcodeReaderMetadataList &MetadataList) {
 
 } // anonynous namespace
 
+static Error error(const Twine &Message) {
+  return make_error<StringError>(
+      Message, make_error_code(BitcodeError::CorruptedBitcode));
+}
+
 class MetadataLoader::MetadataLoaderImpl {
   BitcodeReaderMetadataList MetadataList;
   BitcodeReaderValueList &ValueList;
@@ -533,6 +538,88 @@ class MetadataLoader::MetadataLoaderImpl {
             }
   }
 
+  /// Upgrade the expression from previous versions.
+  Error upgradeDIExpression(uint64_t FromVersion,
+                            MutableArrayRef<uint64_t> &Expr,
+                            SmallVectorImpl<uint64_t> &Buffer) {
+    auto N = Expr.size();
+    switch (FromVersion) {
+    default:
+      return error("Invalid record");
+    case 0:
+      if (N >= 3 && Expr[N - 3] == dwarf::DW_OP_bit_piece)
+        Expr[N - 3] = dwarf::DW_OP_LLVM_fragment;
+      LLVM_FALLTHROUGH;
+    case 1:
+      // Move DW_OP_deref to the end.
+      if (N && Expr[0] == dwarf::DW_OP_deref) {
+        auto End = Expr.end();
+        if (Expr.size() >= 3 &&
+            *std::prev(End, 3) == dwarf::DW_OP_LLVM_fragment)
+          End = std::prev(End, 3);
+        std::move(std::next(Expr.begin()), End, Expr.begin());
+        *std::prev(End) = dwarf::DW_OP_deref;
+      }
+      NeedDeclareExpressionUpgrade = true;
+      LLVM_FALLTHROUGH;
+    case 2: {
+      // Change DW_OP_plus to DW_OP_plus_uconst.
+      // Change DW_OP_minus to DW_OP_uconst, DW_OP_minus
+      auto SubExpr = ArrayRef<uint64_t>(Expr);
+      while (!SubExpr.empty()) {
+        // Skip past other operators with their operands
+        // for this version of the IR, obtained from
+        // from historic DIExpression::ExprOperand::getSize().
+        size_t HistoricSize;
+        switch (SubExpr.front()) {
+        default:
+          HistoricSize = 1;
+          break;
+        case dwarf::DW_OP_constu:
+        case dwarf::DW_OP_minus:
+        case dwarf::DW_OP_plus:
+          HistoricSize = 2;
+          break;
+        case dwarf::DW_OP_LLVM_fragment:
+          HistoricSize = 3;
+          break;
+        }
+
+        // If the expression is malformed, make sure we don't
+        // copy more elements than we should.
+        HistoricSize = std::min(SubExpr.size(), HistoricSize);
+        ArrayRef<uint64_t> Args = SubExpr.slice(1, HistoricSize-1);
+
+        switch (SubExpr.front()) {
+        case dwarf::DW_OP_plus:
+          Buffer.push_back(dwarf::DW_OP_plus_uconst);
+          Buffer.append(Args.begin(), Args.end());
+          break;
+        case dwarf::DW_OP_minus:
+          Buffer.push_back(dwarf::DW_OP_constu);
+          Buffer.append(Args.begin(), Args.end());
+          Buffer.push_back(dwarf::DW_OP_minus);
+          break;
+        default:
+          Buffer.push_back(*SubExpr.begin());
+          Buffer.append(Args.begin(), Args.end());
+          break;
+        }
+
+        // Continue with remaining elements.
+        SubExpr = SubExpr.slice(HistoricSize);
+      }
+      Expr = MutableArrayRef<uint64_t>(Buffer);
+      LLVM_FALLTHROUGH;
+    }
+    case 3:
+      // Up-to-date!
+      break;
+    }
+
+    return Error::success();
+  }
+
   void upgradeDebugInfo() {
     upgradeCUSubprograms();
     upgradeCUVariables();
@@ -590,11 +677,6 @@ public:
   void upgradeDebugIntrinsics(Function &F) { upgradeDeclareExpressions(F); }
 };
 
-static Error error(const Twine &Message) {
-  return make_error<StringError>(
-      Message, make_error_code(BitcodeError::CorruptedBitcode));
-}
-
 Expected<bool>
 MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock() {
   IndexCursor = Stream;
@@ -1551,34 +1633,13 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
     IsDistinct = Record[0] & 1;
     uint64_t Version = Record[0] >> 1;
     auto Elts = MutableArrayRef<uint64_t>(Record).slice(1);
-    unsigned N = Elts.size();
-    // Perform various upgrades.
-    switch (Version) {
-    case 0:
-      if (N >= 3 && Elts[N - 3] == dwarf::DW_OP_bit_piece)
-        Elts[N - 3] = dwarf::DW_OP_LLVM_fragment;
-      LLVM_FALLTHROUGH;
-    case 1:
-      // Move DW_OP_deref to the end.
-      if (N && Elts[0] == dwarf::DW_OP_deref) {
-        auto End = Elts.end();
-        if (Elts.size() >= 3 && *std::prev(End, 3) == dwarf::DW_OP_LLVM_fragment)
-          End = std::prev(End, 3);
-        std::move(std::next(Elts.begin()), End, Elts.begin());
-        *std::prev(End) = dwarf::DW_OP_deref;
-      }
-      NeedDeclareExpressionUpgrade = true;
-      LLVM_FALLTHROUGH;
-    case 2:
-      // Up-to-date!
-      break;
-    default:
-      return error("Invalid record");
-    }
+
+    SmallVector<uint64_t, 6> Buffer;
+    if (Error Err = upgradeDIExpression(Version, Elts, Buffer))
+      return Err;
 
     MetadataList.assignValue(
-        GET_OR_DISTINCT(DIExpression, (Context, makeArrayRef(Record).slice(1))),
-        NextMetadataNo);
+        GET_OR_DISTINCT(DIExpression, (Context, Elts)), NextMetadataNo);
     NextMetadataNo++;
     break;
   }
index d5879fec95cbe73e2f0bcfce0be73a1325c3bd55..e679424bf1f6e247d76ebb1364c066a9d44690c1 100644 (file)
@@ -1663,7 +1663,7 @@ void ModuleBitcodeWriter::writeDIExpression(const DIExpression *N,
                                             SmallVectorImpl<uint64_t> &Record,
                                             unsigned Abbrev) {
   Record.reserve(N->getElements().size() + 1);
-  const uint64_t Version = 2 << 1;
+  const uint64_t Version = 3 << 1;
   Record.push_back((uint64_t)N->isDistinct() | Version);
   Record.append(N->elements_begin(), N->elements_end());
 
index 04073b3aed68445dd10a1f6d74f7e63447377f69..dc39d1e6cb52505eab61cd43ada8edd5be707460 100644 (file)
@@ -552,7 +552,7 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
     int Offset = TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg);
     DwarfExpr.addFragmentOffset(Expr);
     SmallVector<uint64_t, 8> Ops;
-    Ops.push_back(dwarf::DW_OP_plus);
+    Ops.push_back(dwarf::DW_OP_plus_uconst);
     Ops.push_back(Offset);
     Ops.append(Expr->elements_begin(), Expr->elements_end());
     DIExpressionCursor Cursor(Ops);
@@ -821,7 +821,7 @@ void DwarfCompileUnit::addAddress(DIE &Die, dwarf::Attribute Attribute,
 
   SmallVector<uint64_t, 8> Ops;
   if (Location.isIndirect() && Location.getOffset()) {
-    Ops.push_back(dwarf::DW_OP_plus);
+    Ops.push_back(dwarf::DW_OP_plus_uconst);
     Ops.push_back(Location.getOffset());
   }
   DIExpressionCursor Cursor(Ops);
@@ -850,7 +850,7 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die,
 
   SmallVector<uint64_t, 8> Ops;
   if (Location.isIndirect() && Location.getOffset()) {
-    Ops.push_back(dwarf::DW_OP_plus);
+    Ops.push_back(dwarf::DW_OP_plus_uconst);
     Ops.push_back(Location.getOffset());
   }
   Ops.append(DIExpr->elements_begin(), DIExpr->elements_end());
index e3fd21a1fd702d8655eb75390ef06fbab9998ed8..75eb355bfb5434b0827606cb5343b478e40f2219 100644 (file)
@@ -1511,7 +1511,7 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
       DwarfExpr.setMemoryLocationKind();
     SmallVector<uint64_t, 8> Ops;
     if (Location.isIndirect() && Location.getOffset()) {
-      Ops.push_back(dwarf::DW_OP_plus);
+      Ops.push_back(dwarf::DW_OP_plus_uconst);
       Ops.push_back(Location.getOffset());
     }
     Ops.append(DIExpr->elements_begin(), DIExpr->elements_end());
index 73ce58e3ca52505be73c3d1ac15bf7a69fbd5aec..fe38ee805682c5f147cd57da88dce940b03efc4f 100644 (file)
@@ -254,15 +254,19 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
     ExprCursor.take();
   }
 
-  // [Reg, Offset, DW_OP_plus] --> [DW_OP_breg, Offset].
-  // [Reg, Offset, DW_OP_minus] --> [DW_OP_breg, -Offset].
+  // [Reg, DW_OP_constu, Offset, DW_OP_plus]  --> [DW_OP_breg, Offset]
+  // [Reg, DW_OP_constu, Offset, DW_OP_minus] --> [DW_OP_breg,-Offset]
   // If Reg is a subregister we need to mask it out before subtracting.
-  if (Op && ((Op->getOp() == dwarf::DW_OP_plus) ||
-             (Op->getOp() == dwarf::DW_OP_minus && !SubRegisterSizeInBits))) {
-    int Offset = Op->getArg(0);
-    SignedOffset = (Op->getOp() == dwarf::DW_OP_plus) ? Offset : -Offset;
-    ExprCursor.take();
+  if (Op && Op->getOp() == dwarf::DW_OP_constu) {
+    auto N = ExprCursor.peekNext();
+    if (N && (N->getOp() == dwarf::DW_OP_plus ||
+             (N->getOp() == dwarf::DW_OP_minus && !SubRegisterSizeInBits))) {
+      int Offset = Op->getArg(0);
+      SignedOffset = (N->getOp() == dwarf::DW_OP_minus) ? -Offset : Offset;
+      ExprCursor.consume(2);
+    }
   }
+
   if (FBReg)
     addFBReg(SignedOffset);
   else
@@ -326,18 +330,14 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
       LocationKind = Unknown;
       return;
     }
-    case dwarf::DW_OP_plus:
     case dwarf::DW_OP_plus_uconst:
       assert(LocationKind != Register);
       emitOp(dwarf::DW_OP_plus_uconst);
       emitUnsigned(Op->getArg(0));
       break;
+    case dwarf::DW_OP_plus:
     case dwarf::DW_OP_minus:
-      assert(LocationKind != Register);
-      // There is no DW_OP_minus_uconst.
-      emitOp(dwarf::DW_OP_constu);
-      emitUnsigned(Op->getArg(0));
-      emitOp(dwarf::DW_OP_minus);
+      emitOp(Op->getOp());
       break;
     case dwarf::DW_OP_deref: {
       assert(LocationKind != Register);
index de861320006729fa94de7fafda3db54668272949..728f8ad9225bc20e0c2b9457c9c3a36da42c4d3a 100644 (file)
@@ -42,6 +42,9 @@ public:
   DIExpressionCursor(ArrayRef<uint64_t> Expr)
       : Start(Expr.begin()), End(Expr.end()) {}
 
+  DIExpressionCursor(const DIExpressionCursor &C)
+      : Start(C.Start), End(C.End) {}
+
   /// Consume one operation.
   Optional<DIExpression::ExprOperand> take() {
     if (Start == End)
index 7f7d3e650e02e1338a6c4da385ef4524627f3686..708f5f7536ff1a1dcfc80cfd16e247fe37f55a59 100644 (file)
@@ -475,7 +475,7 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die,
 
   SmallVector<uint64_t, 9> Ops;
   if (Location.isIndirect() && Location.getOffset()) {
-    Ops.push_back(dwarf::DW_OP_plus);
+    Ops.push_back(dwarf::DW_OP_plus_uconst);
     Ops.push_back(Location.getOffset());
   }
   // If we started with a pointer to the __Block_byref... struct, then
@@ -487,7 +487,7 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die,
   // DW_OP_plus_uconst ForwardingFieldOffset.  Note there's no point in
   // adding the offset if it's 0.
   if (forwardingFieldOffset > 0) {
-    Ops.push_back(dwarf::DW_OP_plus);
+    Ops.push_back(dwarf::DW_OP_plus_uconst);
     Ops.push_back(forwardingFieldOffset);
   }
 
@@ -499,7 +499,7 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die,
   // 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) {
-    Ops.push_back(dwarf::DW_OP_plus);
+    Ops.push_back(dwarf::DW_OP_plus_uconst);
     Ops.push_back(varFieldOffset);
   }
 
index a34f8d9eac1c635ff2b00c75ca37d834883170c3..0bf68b4c53bbf2a344e35cc6685f76505d99a4e1 100644 (file)
@@ -598,9 +598,7 @@ unsigned DIExpression::ExprOperand::getSize() const {
   case dwarf::DW_OP_LLVM_fragment:
     return 3;
   case dwarf::DW_OP_constu:
-  case dwarf::DW_OP_plus:
   case dwarf::DW_OP_plus_uconst:
-  case dwarf::DW_OP_minus:
     return 2;
   default:
     return 1;
@@ -666,11 +664,12 @@ DIExpression::getFragmentInfo(expr_op_iterator Start, expr_op_iterator End) {
 void DIExpression::appendOffset(SmallVectorImpl<uint64_t> &Ops,
                                 int64_t Offset) {
   if (Offset > 0) {
-    Ops.push_back(dwarf::DW_OP_plus);
+    Ops.push_back(dwarf::DW_OP_plus_uconst);
     Ops.push_back(Offset);
   } else if (Offset < 0) {
-    Ops.push_back(dwarf::DW_OP_minus);
+    Ops.push_back(dwarf::DW_OP_constu);
     Ops.push_back(-Offset);
+    Ops.push_back(dwarf::DW_OP_minus);
   }
 }
 
@@ -679,17 +678,23 @@ bool DIExpression::extractIfOffset(int64_t &Offset) const {
     Offset = 0;
     return true;
   }
-  if (getNumElements() != 2)
-    return false;
-  if (Elements[0] == dwarf::DW_OP_plus ||
-      Elements[0] == dwarf::DW_OP_plus_uconst) {
+
+  if (getNumElements() == 2 && Elements[0] == dwarf::DW_OP_plus_uconst) {
     Offset = Elements[1];
     return true;
   }
-  if (Elements[0] == dwarf::DW_OP_minus) {
-    Offset = -Elements[1];
-    return true;
+
+  if (getNumElements() == 3 && Elements[0] == dwarf::DW_OP_constu) {
+    if (Elements[2] == dwarf::DW_OP_plus) {
+      Offset = Elements[1];
+      return true;
+    }
+    if (Elements[2] == dwarf::DW_OP_minus) {
+      Offset = -Elements[1];
+      return true;
+    }
   }
+
   return false;
 }
 
index 0b1bc9a8c270bf6540f225636d89596deefc633e..92e5798dcf21473f478972c42ceb3a37a1a54a31 100644 (file)
@@ -1470,7 +1470,7 @@ void GlobalObject::copyMetadata(const GlobalObject *Other, unsigned Offset) {
       if (E)
         OrigElements = E->getElements();
       std::vector<uint64_t> Elements(OrigElements.size() + 2);
-      Elements[0] = dwarf::DW_OP_plus;
+      Elements[0] = dwarf::DW_OP_plus_uconst;
       Elements[1] = Offset;
       std::copy(OrigElements.begin(), OrigElements.end(), Elements.begin() + 2);
       E = DIExpression::get(getContext(), Elements);
index 7d2d45b8bd0fb6242c76caca90430a8145845d44..39f4be70145af3cc7b43e41d416f2684db48e534 100644 (file)
@@ -6,15 +6,15 @@
 
 ; CHECK:      !0 = !DIExpression()
 ; CHECK-NEXT: !1 = !DIExpression(DW_OP_deref)
-; CHECK-NEXT: !2 = !DIExpression(DW_OP_plus, 3)
+; CHECK-NEXT: !2 = !DIExpression(DW_OP_constu, 3, DW_OP_plus)
 ; CHECK-NEXT: !3 = !DIExpression(DW_OP_LLVM_fragment, 3, 7)
-; CHECK-NEXT: !4 = !DIExpression(DW_OP_deref, DW_OP_plus, 3, DW_OP_LLVM_fragment, 3, 7)
+; CHECK-NEXT: !4 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 3, DW_OP_LLVM_fragment, 3, 7)
 ; CHECK-NEXT: !5 = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef)
 ; CHECK-NEXT: !6 = !DIExpression(DW_OP_plus_uconst, 3)
 !0 = !DIExpression()
 !1 = !DIExpression(DW_OP_deref)
-!2 = !DIExpression(DW_OP_plus, 3)
+!2 = !DIExpression(DW_OP_constu, 3, DW_OP_plus)
 !3 = !DIExpression(DW_OP_LLVM_fragment, 3, 7)
-!4 = !DIExpression(DW_OP_deref, DW_OP_plus, 3, DW_OP_LLVM_fragment, 3, 7)
+!4 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 3, DW_OP_LLVM_fragment, 3, 7)
 !5 = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef)
 !6 = !DIExpression(DW_OP_plus_uconst, 3)
index 3a161b8ee4d29915d5f86748fa039ee4ca7f896f..a03d6016523e66eb386f4c49eeb8d8f271726e22 100644 (file)
 !5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
 ; DW_OP_deref should be moved to the back of the expression.
 ;
-; CHECK: !DIExpression(DW_OP_plus, 0, DW_OP_deref, DW_OP_LLVM_fragment, 8, 32)
+; CHECK: !DIExpression(DW_OP_plus_uconst, 0, DW_OP_deref, DW_OP_LLVM_fragment, 8, 32)
 !6 = !DIExpression(DW_OP_deref, DW_OP_plus, 0, DW_OP_LLVM_fragment, 8, 32)
-; CHECK: !DIExpression(DW_OP_plus, 0, DW_OP_deref)
+; CHECK: !DIExpression(DW_OP_plus_uconst, 0, DW_OP_deref)
 !7 = !DIExpression(DW_OP_deref, DW_OP_plus, 0)
-; CHECK: !DIExpression(DW_OP_plus, 1, DW_OP_deref)
+; CHECK: !DIExpression(DW_OP_plus_uconst, 1, DW_OP_deref)
 !8 = !DIExpression(DW_OP_plus, 1, DW_OP_deref)
 ; CHECK: !DIExpression(DW_OP_deref)
 !9 = !DIExpression(DW_OP_deref)
diff --git a/test/Bitcode/DIExpression-minus-upgrade.ll b/test/Bitcode/DIExpression-minus-upgrade.ll
new file mode 100644 (file)
index 0000000..1f26eba
--- /dev/null
@@ -0,0 +1,16 @@
+; RUN: llvm-dis -o - %s.bc | FileCheck %s
+
+!llvm.dbg.cu = !{!1}
+!llvm.module.flags = !{!8, !9}
+
+!0 = distinct !DIGlobalVariable(name: "g", scope: !1, file: !2, line: 1, type: !5, isLocal: false, isDefinition: true)
+!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang (llvm/trunk 304286)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, globals: !4)
+!2 = !DIFile(filename: "a.c", directory: "/")
+!3 = !{}
+!4 = !{!7}
+!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+; CHECK: !DIExpression(DW_OP_constu, 42, DW_OP_minus)
+!6 = !DIExpression(DW_OP_minus, 42)
+!7 = !DIGlobalVariableExpression(var: !0, expr: !6)
+!8 = !{i32 2, !"Dwarf Version", i32 4}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
diff --git a/test/Bitcode/DIExpression-minus-upgrade.ll.bc b/test/Bitcode/DIExpression-minus-upgrade.ll.bc
new file mode 100644 (file)
index 0000000..354ba64
Binary files /dev/null and b/test/Bitcode/DIExpression-minus-upgrade.ll.bc differ
index f6796bbdb7a054fdbe6e95c1a57a4c91fe549a8c..31c3fda1b00adcf56dfb131eb28a256a467521bb 100644 (file)
@@ -14,7 +14,7 @@
 ; CHECK: ![[HVAR:[0-9]+]] = distinct !DIGlobalVariable(name: "h",
 ; CHECK: ![[IMPORTS]] = !{![[CIMPORT:[0-9]+]]}
 ; CHECK: ![[CIMPORT]] = !DIImportedEntity({{.*}}entity: ![[HVAR]]
-; CHECK: ![[GEXPR]] = !DIExpression(DW_OP_plus, 1)
+; CHECK: ![[GEXPR]] = !DIExpression(DW_OP_plus_uconst, 1)
 ; CHECK: ![[H]] = {{.*}}!DIGlobalVariableExpression(var: ![[HVAR]])
 
 @g = common global i32 0, align 4, !dbg !0
index 1e9d890e933374de6e53c928a00cce27a7ec878b..6019a9410b0337a3a8a6da680043a396180cc63a 100644 (file)
@@ -273,6 +273,6 @@ define hidden void @foobar_func_block_invoke_0(i8* %.block_descriptor, %0* %load
 !160 = !DIFile(filename: "header.h", directory: "/Volumes/Sandbox/llvm")
 !161 = !{!"header2.h", !"/Volumes/Sandbox/llvm"}
 !162 = !{i32 1, !"Debug Info Version", i32 3}
-!163 = !DIExpression(DW_OP_plus, 20, DW_OP_deref, DW_OP_plus, 4, DW_OP_deref, DW_OP_plus, 24)
-!164 = !DIExpression(DW_OP_deref, DW_OP_plus, 24)
-!165 = !DIExpression(DW_OP_deref, DW_OP_plus, 28)
+!163 = !DIExpression(DW_OP_plus_uconst, 20, DW_OP_deref, DW_OP_plus_uconst, 4, DW_OP_deref, DW_OP_plus_uconst, 24)
+!164 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 24)
+!165 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 28)
index 0a477706df15db31e6dd2320f71e9bf10c019624..03a745888b5a032e7581140508056814c5761b11 100644 (file)
@@ -49,7 +49,7 @@
   !5 = !{i32 2, !"Dwarf Version", i32 4}
   !6 = !{i32 2, !"Debug Info Version", i32 3}
   !7 = !{i32 1, !"PIC Level", i32 2}
-  !8 = !DIExpression(DW_OP_plus, 8, DW_OP_stack_value)
+  !8 = !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value)
   !9 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 7, type: !10, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: true, unit: !0, variables: !11)
   !10 = !DISubroutineType(types: !3)
   !11 = !{!12}
index f1f8b35df27c9d467866bbda3e8de352d1af5dc4..73df59bf3d5dfdd84063f20c4bea0593382ddffa 100644 (file)
@@ -13,7 +13,7 @@
 
 ; Check that the location of the ASAN instrumented __block variable is
 ; correct.
-; CHECK: !DIExpression(DW_OP_plus, 8, DW_OP_deref, DW_OP_plus, 24)
+; CHECK: !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref, DW_OP_plus_uconst, 24)
 
 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
 
@@ -79,7 +79,7 @@ attributes #3 = { nounwind }
 !19 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
 !20 = !DIDerivedType(tag: DW_TAG_member, name: "__size", size: 32, align: 32, offset: 160, file: !1, scope: !5, baseType: !19)
 !21 = !DIDerivedType(tag: DW_TAG_member, name: "x", size: 32, align: 32, offset: 192, file: !1, scope: !5, baseType: !19)
-!22 = !DIExpression(DW_OP_plus, 8, DW_OP_deref, DW_OP_plus, 24)
+!22 = !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref, DW_OP_plus_uconst, 24)
 !23 = !DILocation(line: 4, column: 15, scope: !4)
 !24 = !DILocation(line: 4, column: 3, scope: !4)
 !25 = !DILocation(line: 5, column: 3, scope: !4)
index 2e8d9977a649d3154d484f46d822c1c5b3e6c0ed..0ebde3c1eb355f1601b08b63a2702a338d96a5a5 100644 (file)
@@ -57,7 +57,7 @@
   !17 = !{!18}
   !18 = !DISubrange(count: 4)
   !19 = !DILocation(line: 4, column: 13, scope: !9)
-  !20 = !DIExpression(DW_OP_plus, 1, DW_OP_minus, 1)
+  !20 = !DIExpression(DW_OP_plus_uconst, 1, DW_OP_constu, 1, DW_OP_minus)
   !21 = !DILocation(line: 4, column: 7, scope: !9)
   !22 = !DILocation(line: 5, column: 9, scope: !9)
   !23 = !DILocation(line: 5, column: 18, scope: !9)
index 168040507eefa62b3e30d64f400c838efeb43c24..14927eef59d4993001dd88ece61069d2bdd15489 100644 (file)
@@ -123,7 +123,7 @@ attributes #3 = { nounwind }
 !66 = !DILocation(line: 2, column: 20, scope: !8)
 !67 = !DILocation(line: 2, column: 21, scope: !8)
 !68 = !DILocalVariable(name: "block", line: 2, scope: !8, file: !5, type: !25)
-!69 = !DIExpression(DW_OP_deref, DW_OP_plus, 32)
+!69 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 32)
 !70 = !DILocation(line: 2, column: 9, scope: !8)
 !71 = !DILocation(line: 2, column: 23, scope: !72)
 !72 = distinct !DILexicalBlock(line: 2, column: 21, file: !1, scope: !8)
index 1085eaef0d4e4e72703aa4b7dc10ce9f1e0aa87c..e1620af5025514da450605165f2888981fbd27d1 100644 (file)
@@ -107,5 +107,5 @@ define internal void @"__24-[Main initWithContext:]_block_invoke_2"(i8* %.block_
 !106 = !DILocation(line: 40, scope: !42)
 !107 = !DIFile(filename: "llvm/tools/clang/test/CodeGenObjC/debug-info-block-captured-self.m", directory: "")
 !108 = !{i32 1, !"Debug Info Version", i32 3}
-!109 = !DIExpression(DW_OP_plus, 32, DW_OP_deref)
-!110 = !DIExpression(DW_OP_plus, 32, DW_OP_deref)
+!109 = !DIExpression(DW_OP_plus_uconst, 32, DW_OP_deref)
+!110 = !DIExpression(DW_OP_plus_uconst, 32, DW_OP_deref)
index 859eef804bb15bab48c22e084b9703b036c4f112..b79ad89be27d6b1f4170049f3021dea0002dedfc 100644 (file)
@@ -380,4 +380,4 @@ attributes #3 = { nounwind }
 !108 = !DILocation(line: 61, scope: !36)
 !109 = !DILocation(line: 62, scope: !36)
 !110 = !{i32 1, !"Debug Info Version", i32 3}
-!111 = !DIExpression(DW_OP_deref, DW_OP_plus, 32)
+!111 = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 32)
index 8e65b489c27b0859cdc1b4b11143e4e41db9cc0b..30bf58378005f32ed55de77d214c59c40764b26d 100644 (file)
@@ -10,7 +10,7 @@
 ;   Capture(buf);
 ; }
 ; }
-; The interesting part is !DIExpression(DW_OP_minus, 400)
+; The interesting part is !DIExpression(DW_OP_constu, 400, DW_OP_minus)
 
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"
@@ -56,7 +56,7 @@ declare void @Capture(i32*)
 !14 = !{i32 2, !"Debug Info Version", i32 3}
 !15 = !{!"clang version 3.8.0 (trunk 248518) (llvm/trunk 248512)"}
 !16 = !DILocation(line: 5, column: 3, scope: !4)
-!17 = !DIExpression(DW_OP_minus, 400)
+!17 = !DIExpression(DW_OP_constu, 400, DW_OP_minus)
 !18 = !DILocation(line: 5, column: 7, scope: !4)
 !19 = !DILocation(line: 6, column: 11, scope: !4)
 !20 = !DILocation(line: 6, column: 3, scope: !4)
index 8d346be532e8743618a58b45192846123a346cf4..69f4b2c3ef6ab875aadc7fe94dfb70918e80c7c9 100644 (file)
@@ -51,7 +51,7 @@ attributes #1 = { nounwind readnone }
 !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, DW_OP_stack_value)
+!13 = !DIExpression(DW_OP_constu, 1, DW_OP_minus, DW_OP_stack_value)
 !14 = !DILocation(line: 1, column: 13, scope: !7)
 !15 = !DILocation(line: 2, column: 11, scope: !7)
 !16 = !DILocation(line: 2, column: 3, scope: !7)
index 42e94698818c912d0d9cef33e2def618ba27577d..8742c90bc2983223eecc29f8dadabe3e435b2e78 100644 (file)
@@ -14,7 +14,7 @@
 ; }
 
 ; CHECK: ![[ZZZ:.*]] = !DILocalVariable(name: "zzz",
-; CHECK: ![[ZZZ_EXPR:.*]] = !DIExpression(DW_OP_deref, DW_OP_minus, 400)
+; CHECK: ![[ZZZ_EXPR:.*]] = !DIExpression(DW_OP_deref, DW_OP_constu, 400, DW_OP_minus)
 ; CHECK: DBG_VALUE {{.*}} ![[ZZZ]], ![[ZZZ_EXPR]]
 
 %struct.S = type { [100 x i32] }
@@ -79,7 +79,7 @@ attributes #2 = { argmemonly nounwind }
 !20 = !{i32 2, !"Debug Info Version", i32 3}
 !21 = !{!"clang version 3.8.0 (trunk 254107) (llvm/trunk 254109)"}
 !22 = !DILocation(line: 8, column: 9, scope: !12)
-!23 = !DIExpression(DW_OP_deref, DW_OP_minus, 400)
+!23 = !DIExpression(DW_OP_deref, DW_OP_constu, 400, DW_OP_minus)
 !24 = !DILocation(line: 8, column: 28, scope: !12)
 !25 = !DIExpression()
 !26 = !DILocation(line: 9, column: 10, scope: !12)
index 61595f7861fe4b0f6311fdd2021f2815e05930d7..b653784ec668fa2faf38b58d330f559d2026e91d 100644 (file)
@@ -93,4 +93,4 @@ attributes #1 = { nounwind readnone }
 !15 = !DISubprogram(name: "<(lambda at test.ii:87:58)>", scope: !0, file: !1, line: 27, type: !6, isLocal: false, isDefinition: false, scopeLine: 27, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true, templateParams: !2)
 !16 = distinct !DILocation(line: 99, column: 21, scope: !17)
 !17 = !DILexicalBlockFile(scope: !5, file: !1, discriminator: 2)
-!18 = !DIExpression(DW_OP_plus, 4, DW_OP_stack_value, DW_OP_LLVM_fragment, 64, 32)
+!18 = !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value, DW_OP_LLVM_fragment, 64, 32)
index 5d4be7377ef4ef3c01bf43fd66cc8c3b8a249bc3..5e9af695c8dc01607c11d9815c2a7094e886d960 100644 (file)
@@ -12,7 +12,7 @@ target triple = "x86_64-unknown-linux-gnu"
 !1 = !{!2}
 !2 = !DIGlobalVariableExpression(var: !3, expr: !4)
 !3 = distinct !DIGlobalVariable(name: "a", scope: null, isLocal: false, isDefinition: true, type: !6)
-!4 = !DIExpression(DW_OP_plus, 4)
+!4 = !DIExpression(DW_OP_plus_uconst, 4)
 !5 = !DIFile(filename: "<stdin>", directory: "/")
 !6 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
 
index 97e0bb2148e9363fe94005fa2c860430e7edfc13..8d60f3662431cec8448f91b2e33ebd5d51a8da3e 100644 (file)
@@ -17,7 +17,7 @@ define void @use1() {
 ; CHECK: [[AVAR]] = !DIGlobalVariable(name: "a", scope: null, isLocal: false, isDefinition: true)
 ; CHECK: [[B]] = !DIGlobalVariableExpression(var: [[BVAR:![0-9]+]], expr: [[EXPR:![0-9]+]])
 ; CHECK: [[BVAR]] = !DIGlobalVariable(name: "b", scope: null, isLocal: false, isDefinition: true)
-; CHECK: [[EXPR]] = !DIExpression(DW_OP_plus, 4)
+; CHECK: [[EXPR]] = !DIExpression(DW_OP_plus_uconst, 4)
 
 !llvm.module.flags = !{!4, !5}
 
index 086743e80820b20e1afeb92732da7d6352efc8a8..50b8f1c6068e12ae3a02bc007ae0b9be5475bb91 100644 (file)
@@ -93,12 +93,12 @@ entry:
   ret void, !dbg !32
 }
 
-; CHECK: ![[LOAD_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_plus, 0)
-; CHECK: ![[BITCAST_EXPR]] = !DIExpression(DW_OP_plus, 0)
-; CHECK: ![[GEP0_EXPR]] = !DIExpression(DW_OP_minus, 8, DW_OP_plus, 0, DW_OP_stack_value)
-; CHECK: ![[GEP1_EXPR]] = !DIExpression(DW_OP_minus, 8, DW_OP_stack_value,
+; CHECK: ![[LOAD_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 0)
+; CHECK: ![[BITCAST_EXPR]] = !DIExpression(DW_OP_plus_uconst, 0)
+; CHECK: ![[GEP0_EXPR]] = !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_plus_uconst, 0, DW_OP_stack_value)
+; CHECK: ![[GEP1_EXPR]] = !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_stack_value,
 ; CHECK-SAME:                           DW_OP_LLVM_fragment, 0, 32)
-; CHECK: ![[GEP2_EXPR]] = !DIExpression(DW_OP_minus, 8, DW_OP_stack_value)
+; CHECK: ![[GEP2_EXPR]] = !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_stack_value)
 
 ; Function Attrs: nounwind readnone
 declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1
@@ -130,7 +130,7 @@ attributes #1 = { nounwind readnone }
 !17 = !{!18}
 !18 = !DILocalVariable(name: "entry", scope: !14, file: !1, line: 6, type: !4)
 !19 = !DILocation(line: 6, column: 17, scope: !14)
-!20 = !DIExpression(DW_OP_plus, 0)
+!20 = !DIExpression(DW_OP_plus_uconst, 0)
 !21 = !DILocation(line: 11, column: 1, scope: !14)
 !22 = distinct !DISubprogram(name: "scan", scope: !1, file: !1, line: 4, type: !15, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !17)
 !23 = !DILocation(line: 6, column: 17, scope: !22)
index 88cda693b29326f4f412b356d5d4c0501e300659..d6b217142bfefc4db10bd0d0703308e240fc52c2 100644 (file)
@@ -37,10 +37,10 @@ entry:
 
 ; CHECK-DAG: ![[VAR_ARG]] = !DILocalVariable(name: "zzz"
 ; 100 aligned up to 8
-; CHECK-DAG: ![[EXPR_ARG]] = !DIExpression(DW_OP_minus, 104)
+; CHECK-DAG: ![[EXPR_ARG]] = !DIExpression(DW_OP_constu, 104, DW_OP_minus
 
 ; CHECK-DAG: ![[VAR_LOCAL]] = !DILocalVariable(name: "xxx"
-; CHECK-DAG: ![[EXPR_LOCAL]] = !DIExpression(DW_OP_minus, 208)
+; CHECK-DAG: ![[EXPR_LOCAL]] = !DIExpression(DW_OP_constu, 208, DW_OP_minus
 
 ; Function Attrs: nounwind readnone
 declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
index 8059a722fd45c62a896d1b200c78017ba7d7bc86..731516c3c65edcf11e09f404c3b54a91f0643038 100644 (file)
@@ -84,8 +84,8 @@ attributes #4 = { nounwind }
 !13 = !DILocation(line: 5, column: 3, scope: !6)
 !14 = !DILocation(line: 6, column: 3, scope: !6)
 
-; CHECK-DAG: ![[X1_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_minus, 4)
-; CHECK-DAG: ![[X2_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_minus, 8)
+; CHECK-DAG: ![[X1_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_constu, 4, DW_OP_minus)
+; CHECK-DAG: ![[X2_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_constu, 8, DW_OP_minus)
 !15 = !DIExpression(DW_OP_deref)
 !16 = !DILocation(line: 5, column: 7, scope: !6)
 !17 = !DILocation(line: 8, column: 3, scope: !6)
@@ -95,4 +95,4 @@ attributes #4 = { nounwind }
 !21 = !DILocation(line: 10, column: 1, scope: !22)
 !22 = !DILexicalBlockFile(scope: !6, file: !1, discriminator: 1)
 !23 = !DIExpression()
-!24 = !DIExpression(DW_OP_minus, 42)
+!24 = !DIExpression(DW_OP_constu, 42, DW_OP_minus)
index a09a4239ec46e533984d95a339f7fb1602f77895..cb38b30f43e6cafca1b8f662ee274e03841bcd19 100644 (file)
@@ -2042,23 +2042,23 @@ TEST_F(DIExpressionTest, isValid) {
   EXPECT_TRUE(DIExpression::get(Context, None));
 
   // Valid constructions.
-  EXPECT_VALID(dwarf::DW_OP_plus, 6);
   EXPECT_VALID(dwarf::DW_OP_plus_uconst, 6);
+  EXPECT_VALID(dwarf::DW_OP_constu, 6, dwarf::DW_OP_plus);
   EXPECT_VALID(dwarf::DW_OP_deref);
   EXPECT_VALID(dwarf::DW_OP_LLVM_fragment, 3, 7);
-  EXPECT_VALID(dwarf::DW_OP_plus, 6, dwarf::DW_OP_deref);
-  EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus, 6);
+  EXPECT_VALID(dwarf::DW_OP_plus_uconst, 6, dwarf::DW_OP_deref);
+  EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus_uconst, 6);
   EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_LLVM_fragment, 3, 7);
-  EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus, 6,
+  EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus_uconst, 6,
                dwarf::DW_OP_LLVM_fragment, 3, 7);
 
   // Invalid constructions.
   EXPECT_INVALID(~0u);
-  EXPECT_INVALID(dwarf::DW_OP_plus);
+  EXPECT_INVALID(dwarf::DW_OP_plus, 0);
   EXPECT_INVALID(dwarf::DW_OP_plus_uconst);
   EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment);
   EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment, 3);
-  EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment, 3, 7, dwarf::DW_OP_plus, 3);
+  EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment, 3, 7, dwarf::DW_OP_plus_uconst, 3);
   EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment, 3, 7, dwarf::DW_OP_deref);
 
 #undef EXPECT_VALID