Document DIExpression.
[oota-llvm.git] / include / llvm / IR / DebugInfo.h
index 00652a72d83f3ef878c7f290bd015aa1acbb1174..6294b797389ad80594793e99bbb3cfc7c1b53cc3 100644 (file)
 #define LLVM_IR_DEBUGINFO_H
 
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/iterator_range.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Dwarf.h"
@@ -59,14 +59,14 @@ class DIObjCProperty;
 typedef DenseMap<const MDString *, MDNode *> DITypeIdentifierMap;
 
 class DIHeaderFieldIterator
-    : public std::iterator<std::input_iterator_tag, StringRef, std::ptrdiff_t,
+    : public std::iterator<std::forward_iterator_tag, StringRef, std::ptrdiff_t,
                            const StringRef *, StringRef> {
   StringRef Header;
   StringRef Current;
 
 public:
   DIHeaderFieldIterator() {}
-  DIHeaderFieldIterator(StringRef Header)
+  explicit DIHeaderFieldIterator(StringRef Header)
       : Header(Header), Current(Header.slice(0, Header.find('\0'))) {}
   StringRef operator*() const { return Current; }
   const StringRef * operator->() const { return &Current; }
@@ -99,6 +99,16 @@ public:
     return Header.slice(Current.end() - Header.begin() + 1, StringRef::npos);
   }
 
+  /// \brief Get the current field as a number.
+  ///
+  /// Convert the current field into a number.  Return \c 0 on error.
+  template <class T> T getNumber() const {
+    T Int;
+    if (getCurrent().getAsInteger(0, Int))
+      return 0;
+    return Int;
+  }
+
 private:
   void increment() {
     assert(Current.data() != nullptr && "Cannot increment past the end");
@@ -138,9 +148,8 @@ public:
     FlagObjectPointer     = 1 << 10,
     FlagVector            = 1 << 11,
     FlagStaticMember      = 1 << 12,
-    FlagIndirectVariable  = 1 << 13,
-    FlagLValueReference   = 1 << 14,
-    FlagRValueReference   = 1 << 15
+    FlagLValueReference   = 1 << 13,
+    FlagRValueReference   = 1 << 14
   };
 
 protected:
@@ -191,20 +200,26 @@ public:
                          DIHeaderFieldIterator());
   }
 
-  StringRef getHeaderField(unsigned Index) const {
+  DIHeaderFieldIterator header_begin() const {
+    return DIHeaderFieldIterator(getHeader());
+  }
+  DIHeaderFieldIterator header_end() const { return DIHeaderFieldIterator(); }
+
+  DIHeaderFieldIterator getHeaderIterator(unsigned Index) const {
     // Since callers expect an empty string for out-of-range accesses, we can't
     // use std::advance() here.
-    for (DIHeaderFieldIterator I(getHeader()), E; I != E; ++I, --Index)
+    for (auto I = header_begin(), E = header_end(); I != E; ++I, --Index)
       if (!Index)
-        return *I;
-    return StringRef();
+        return I;
+    return header_end();
+  }
+
+  StringRef getHeaderField(unsigned Index) const {
+    return *getHeaderIterator(Index);
   }
 
   template <class T> T getHeaderFieldAs(unsigned Index) const {
-    T Int;
-    if (getHeaderField(Index).getAsInteger(0, Int))
-      return 0;
-    return Int;
+    return getHeaderIterator(Index).getNumber<T>();
   }
 
   uint16_t getTag() const { return getHeaderFieldAs<uint16_t>(0); }
@@ -382,7 +397,7 @@ template <> DITypeRef DIDescriptor::getFieldAs<DITypeRef>(unsigned Elt) const;
 /// \brief Specialize DIRef constructor for DITypeRef.
 template <> DIRef<DIType>::DIRef(const Metadata *V);
 
-/// \briefThis is a wrapper for a type.
+/// \brief This is a wrapper for a type.
 ///
 /// FIXME: Types should be factored much better so that CV qualifiers and
 /// others do not require a huge and empty descriptor full of zeros.
@@ -816,11 +831,6 @@ public:
     return (getHeaderFieldAs<unsigned>(3) & FlagObjectPointer) != 0;
   }
 
-  /// \brief Return true if this variable is represented as a pointer.
-  bool isIndirect() const {
-    return (getHeaderFieldAs<unsigned>(3) & FlagIndirectVariable) != 0;
-  }
-
   /// \brief If this variable is inlined then return inline location.
   MDNode *getInlinedAt() const;
 
@@ -840,7 +850,13 @@ public:
   void printExtendedName(raw_ostream &OS) const;
 };
 
-/// \brief A complex location expression.
+/// \brief A complex location expression in postfix notation.
+///
+/// This is (almost) a DWARF expression that modifies the location of a
+/// variable or (or the location of a single piece of a variable).
+///
+/// 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.
 class DIExpression : public DIDescriptor {
   friend class DIDescriptor;
   void printInternal(raw_ostream &OS) const;
@@ -868,6 +884,55 @@ public:
   uint64_t getPieceOffset() const;
   /// \brief Return the size of this piece in bytes.
   uint64_t getPieceSize() const;
+
+  /// \brief An iterator for DIExpression elements.
+  class iterator
+      : public std::iterator<std::forward_iterator_tag, StringRef, unsigned,
+                             const uint64_t *, uint64_t> {
+    DIHeaderFieldIterator I;
+    iterator(DIHeaderFieldIterator I) : I(I) {}
+  public:
+    iterator() {}
+    iterator(const DIExpression &Expr) : I(++Expr.header_begin()) {}
+    uint64_t operator*() const { return I.getNumber<uint64_t>(); }
+    iterator &operator++() {
+      increment();
+      return *this;
+    }
+    iterator operator++(int) {
+      iterator X(*this);
+      increment();
+      return X;
+    }
+    bool operator==(const iterator &X) const {
+      return I == X.I;
+    }
+    bool operator!=(const iterator &X) const {
+      return !(*this == X);
+    }
+   
+    uint64_t getArg(unsigned N) const {
+      auto In = I;
+      std::advance(In, N);
+      return In.getNumber<uint64_t>();
+    }
+   
+    const DIHeaderFieldIterator& getBase() const { return I; }
+   
+  private:
+    void increment() {
+      switch (**this) {
+      case dwarf::DW_OP_piece: std::advance(I, 3); break;
+      case dwarf::DW_OP_plus:  std::advance(I, 2); break;
+      case dwarf::DW_OP_deref: std::advance(I, 1); break;
+      default:
+        assert("unsupported operand");
+      }
+    }
+  };
+
+  iterator begin() const;
+  iterator end() const;
 };
 
 /// \brief This object holds location information.
@@ -877,10 +942,26 @@ class DILocation : public DIDescriptor {
 public:
   explicit DILocation(const MDNode *N) : DIDescriptor(N) {}
 
-  unsigned getLineNumber() const { return getUnsignedField(0); }
-  unsigned getColumnNumber() const { return getUnsignedField(1); }
-  DIScope getScope() const { return getFieldAs<DIScope>(2); }
-  DILocation getOrigLocation() const { return getFieldAs<DILocation>(3); }
+  unsigned getLineNumber() const {
+    if (auto *L = dyn_cast_or_null<MDLocation>(DbgNode))
+      return L->getLine();
+    return 0;
+  }
+  unsigned getColumnNumber() const {
+    if (auto *L = dyn_cast_or_null<MDLocation>(DbgNode))
+      return L->getColumn();
+    return 0;
+  }
+  DIScope getScope() const {
+    if (auto *L = dyn_cast_or_null<MDLocation>(DbgNode))
+      return DIScope(dyn_cast_or_null<MDNode>(L->getScope()));
+    return DIScope(nullptr);
+  }
+  DILocation getOrigLocation() const {
+    if (auto *L = dyn_cast_or_null<MDLocation>(DbgNode))
+      return DILocation(dyn_cast_or_null<MDNode>(L->getInlinedAt()));
+    return DILocation(nullptr);
+  }
   StringRef getFilename() const { return getScope().getFilename(); }
   StringRef getDirectory() const { return getScope().getDirectory(); }
   bool Verify() const;
@@ -901,7 +982,9 @@ public:
     // sure this location is a lexical block before retrieving its
     // value.
     return getScope().isLexicalBlockFile()
-               ? getFieldAs<DILexicalBlockFile>(2).getDiscriminator()
+               ? DILexicalBlockFile(
+                     cast<MDNode>(cast<MDLocation>(DbgNode)->getScope()))
+                     .getDiscriminator()
                : 0;
   }
 
@@ -1024,6 +1107,9 @@ public:
   /// \brief Process DILocation.
   void processLocation(const Module &M, DILocation Loc);
 
+  /// \brief Process DIExpression.
+  void processExpression(DIExpression Expr);
+
   /// \brief Clear all lists.
   void reset();