DebugInfo: Write new DebugLoc API

Rewrite `DebugLoc` with a cleaner API that reflects its current status
as a wrapper around an `MDLocation` pointer.

  - Add accessors/constructors to/from `MDLocation`.
  - Simplify construction from `MDNode`.
  - Remove unnecessary `LLVMContext` from APIs.
  - Drop some API that isn't useful any more.
  - Rewrite documentation.

Actually, I've left the old API behind temporarily at the bottom of the
class so that I can update callers in separate commits.  I'll remove it
once the callers are updated.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@233573 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Duncan P. N. Exon Smith 2015-03-30 18:07:40 +00:00
parent 3584797a17
commit 1c13197c9f
2 changed files with 133 additions and 96 deletions

View File

@ -22,11 +22,15 @@ namespace llvm {
class LLVMContext; class LLVMContext;
class raw_ostream; class raw_ostream;
class MDNode; class MDLocation;
/// DebugLoc - Debug location id. This is carried by Instruction, SDNode, /// \brief A debug info location.
/// and MachineInstr to compactly encode file/line/scope information for an ///
/// operation. /// This class is a wrapper around a tracking reference to an \a MDLocation
/// pointer.
///
/// To avoid extra includes, \a DebugLoc doubles the \a MDLocation API with a
/// one based on relatively opaque \a MDNode pointers.
class DebugLoc { class DebugLoc {
TrackingMDNodeRef Loc; TrackingMDNodeRef Loc;
@ -43,66 +47,89 @@ namespace llvm {
return *this; return *this;
} }
/// \brief Construct from an \a MDLocation.
DebugLoc(MDLocation *L);
/// \brief Construct from an \a MDNode.
///
/// Note: if \c N is not an \a MDLocation, a verifier check will fail, and
/// accessors will crash. However, construction from other nodes is
/// supported in order to handle forward references when reading textual
/// IR.
explicit DebugLoc(MDNode *N);
MDLocation *get() const;
operator MDLocation *() const { return get(); }
MDLocation *operator->() const { return get(); }
MDLocation &operator*() const { return *get(); }
/// \brief Check whether this has a trivial destructor. /// \brief Check whether this has a trivial destructor.
bool hasTrivialDestructor() const { return Loc.hasTrivialDestructor(); } bool hasTrivialDestructor() const { return Loc.hasTrivialDestructor(); }
/// get - Get a new DebugLoc that corresponds to the specified line/col /// \brief Create a new DebugLoc.
/// scope/inline location. ///
/// Create a new DebugLoc at the specified line/col and scope/inline. This
/// forwards to \a MDLocation::get().
///
/// If \c !Scope, returns a default-constructed \a DebugLoc.
///
/// FIXME: Remove this. Users should use MDLocation::get().
static DebugLoc get(unsigned Line, unsigned Col, MDNode *Scope, static DebugLoc get(unsigned Line, unsigned Col, MDNode *Scope,
MDNode *InlinedAt = nullptr); MDNode *InlinedAt = nullptr);
/// getFromDILocation - Translate the DILocation quad into a DebugLoc. /// \brief Translate the DILexicalBlock into a DebugLoc.
static DebugLoc getFromDILocation(MDNode *N); ///
/// FIXME: Remove this. It has only one user, and the user just wants to
/// getFromDILexicalBlock - Translate the DILexicalBlock into a DebugLoc. /// pass an \a MDScope around.
static DebugLoc getFromDILexicalBlock(MDNode *N); static DebugLoc getFromDILexicalBlock(MDNode *N);
/// isUnknown - Return true if this is an unknown location.
bool isUnknown() const { return !Loc; }
unsigned getLine() const; unsigned getLine() const;
unsigned getCol() const; unsigned getCol() const;
/// getScope - This returns the scope pointer for this DebugLoc, or null if
/// invalid.
MDNode *getScope() const; MDNode *getScope() const;
MDLocation *getInlinedAt() const;
/// \brief Get the fully inlined-at scope for a DebugLoc.
///
/// Gets the inlined-at scope for a DebugLoc.
MDNode *getInlinedAtScope() const;
/// \brief Find the debug info location for the start of the function.
///
/// Walk up the scope chain of given debug loc and find line number info
/// for the function.
///
/// FIXME: Remove this. Users should use MDLocation/MDLocalScope API to
/// find the subprogram, and then MDLocation::get().
DebugLoc getFnDebugLoc() const;
/// \brief Return \c this as a bar \a MDNode.
MDNode *getAsMDNode() const { return Loc; }
bool operator==(const DebugLoc &DL) const { return Loc == DL.Loc; }
bool operator!=(const DebugLoc &DL) const { return Loc != DL.Loc; }
void dump() const;
/// \brief prints source location /path/to/file.exe:line:col @[inlined at]
void print(raw_ostream &OS) const;
// FIXME: Remove this old API once callers have been updated.
static DebugLoc getFromDILocation(MDNode *N) { return DebugLoc(N); }
bool isUnknown() const { return !Loc; }
MDNode *getScope(const LLVMContext &) const { return getScope(); } MDNode *getScope(const LLVMContext &) const { return getScope(); }
MDNode *getInlinedAt(const LLVMContext &) const;
/// getInlinedAt - This returns the InlinedAt pointer for this DebugLoc, or
/// null if invalid or not present.
MDNode *getInlinedAt() const;
MDNode *getInlinedAt(const LLVMContext &) const { return getInlinedAt(); }
/// getScopeAndInlinedAt - Return both the Scope and the InlinedAt values.
void getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA) const; void getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA) const;
void getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA, void getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA,
const LLVMContext &) const { const LLVMContext &) const {
return getScopeAndInlinedAt(Scope, IA); return getScopeAndInlinedAt(Scope, IA);
} }
MDNode *getScopeNode() const { return getInlinedAtScope(); }
/// getScopeNode - Get MDNode for DebugLoc's scope, or null if invalid.
MDNode *getScopeNode() const;
MDNode *getScopeNode(const LLVMContext &) const { return getScopeNode(); } MDNode *getScopeNode(const LLVMContext &) const { return getScopeNode(); }
// getFnDebugLoc - Walk up the scope chain of given debug loc and find line
// number info for the function.
DebugLoc getFnDebugLoc() const;
DebugLoc getFnDebugLoc(const LLVMContext &) const { DebugLoc getFnDebugLoc(const LLVMContext &) const {
return getFnDebugLoc(); return getFnDebugLoc();
} }
/// getAsMDNode - This method converts the compressed DebugLoc node into a
/// DILocation compatible MDNode.
MDNode *getAsMDNode() const;
MDNode *getAsMDNode(LLVMContext &) const { return getAsMDNode(); } MDNode *getAsMDNode(LLVMContext &) const { return getAsMDNode(); }
bool operator==(const DebugLoc &DL) const { return Loc == DL.Loc; }
bool operator!=(const DebugLoc &DL) const { return !(*this == DL); }
void dump() const;
void dump(const LLVMContext &) const { dump(); } void dump(const LLVMContext &) const { dump(); }
/// \brief prints source location /path/to/file.exe:line:col @[inlined at]
void print(raw_ostream &OS) const;
}; };
} // end namespace llvm } // end namespace llvm

View File

@ -16,28 +16,40 @@ using namespace llvm;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// DebugLoc Implementation // DebugLoc Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
DebugLoc::DebugLoc(MDLocation *L) : Loc(L) {}
DebugLoc::DebugLoc(MDNode *L) : Loc(L) {}
unsigned DebugLoc::getLine() const { return DILocation(Loc).getLineNumber(); } MDLocation *DebugLoc::get() const {
unsigned DebugLoc::getCol() const { return DILocation(Loc).getColumnNumber(); } return cast_or_null<MDLocation>(Loc.get());
MDNode *DebugLoc::getScope() const { return DILocation(Loc).getScope(); }
MDNode *DebugLoc::getInlinedAt() const {
return DILocation(Loc).getOrigLocation();
} }
/// Return both the Scope and the InlinedAt values. unsigned DebugLoc::getLine() const {
void DebugLoc::getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA) const { assert(get() && "Expected valid DebugLoc");
Scope = getScope(); return get()->getLine();
IA = getInlinedAt();
} }
MDNode *DebugLoc::getScopeNode() const { unsigned DebugLoc::getCol() const {
assert(get() && "Expected valid DebugLoc");
return get()->getColumn();
}
MDNode *DebugLoc::getScope() const {
assert(get() && "Expected valid DebugLoc");
return get()->getScope();
}
MDLocation *DebugLoc::getInlinedAt() const {
assert(get() && "Expected valid DebugLoc");
return get()->getInlinedAt();
}
MDNode *DebugLoc::getInlinedAtScope() const {
return cast<MDLocation>(Loc)->getInlinedAtScope(); return cast<MDLocation>(Loc)->getInlinedAtScope();
} }
DebugLoc DebugLoc::getFnDebugLoc() const { DebugLoc DebugLoc::getFnDebugLoc() const {
const MDNode *Scope = getScopeNode(); // FIXME: Add a method on \a MDLocation that does this work.
const MDNode *Scope = getInlinedAtScope();
DISubprogram SP = getDISubprogram(Scope); DISubprogram SP = getDISubprogram(Scope);
if (SP.isSubprogram()) if (SP.isSubprogram())
return DebugLoc::get(SP.getScopeLineNumber(), 0, SP); return DebugLoc::get(SP.getScopeLineNumber(), 0, SP);
@ -51,19 +63,7 @@ DebugLoc DebugLoc::get(unsigned Line, unsigned Col,
if (!Scope) if (!Scope)
return DebugLoc(); return DebugLoc();
return getFromDILocation( return MDLocation::get(Scope->getContext(), Line, Col, Scope, InlinedAt);
MDLocation::get(Scope->getContext(), Line, Col, Scope, InlinedAt));
}
/// getAsMDNode - This method converts the compressed DebugLoc node into a
/// DILocation-compatible MDNode.
MDNode *DebugLoc::getAsMDNode() const { return Loc; }
/// getFromDILocation - Translate the DILocation quad into a DebugLoc.
DebugLoc DebugLoc::getFromDILocation(MDNode *N) {
DebugLoc Loc;
Loc.Loc.reset(N);
return Loc;
} }
/// getFromDILexicalBlock - Translate the DILexicalBlock into a DebugLoc. /// getFromDILexicalBlock - Translate the DILexicalBlock into a DebugLoc.
@ -77,38 +77,48 @@ DebugLoc DebugLoc::getFromDILexicalBlock(MDNode *N) {
void DebugLoc::dump() const { void DebugLoc::dump() const {
#ifndef NDEBUG #ifndef NDEBUG
if (!isUnknown()) { if (!Loc)
dbgs() << getLine(); return;
if (getCol() != 0)
dbgs() << ',' << getCol(); dbgs() << getLine();
DebugLoc InlinedAtDL = DebugLoc::getFromDILocation(getInlinedAt()); if (getCol() != 0)
if (!InlinedAtDL.isUnknown()) { dbgs() << ',' << getCol();
dbgs() << " @ "; if (DebugLoc InlinedAtDL = DebugLoc(getInlinedAt())) {
InlinedAtDL.dump(); dbgs() << " @ ";
} else InlinedAtDL.dump();
dbgs() << "\n"; } else
} dbgs() << "\n";
#endif #endif
} }
void DebugLoc::print(raw_ostream &OS) const { void DebugLoc::print(raw_ostream &OS) const {
if (!isUnknown()) { if (!Loc)
// Print source line info. return;
DIScope Scope(getScope());
assert((!Scope || Scope.isScope()) && // Print source line info.
"Scope of a DebugLoc should be null or a DIScope."); DIScope Scope(getScope());
if (Scope) assert((!Scope || Scope.isScope()) &&
OS << Scope.getFilename(); "Scope of a DebugLoc should be null or a DIScope.");
else if (Scope)
OS << "<unknown>"; OS << Scope.getFilename();
OS << ':' << getLine(); else
if (getCol() != 0) OS << "<unknown>";
OS << ':' << getCol(); OS << ':' << getLine();
DebugLoc InlinedAtDL = DebugLoc::getFromDILocation(getInlinedAt()); if (getCol() != 0)
if (!InlinedAtDL.isUnknown()) { OS << ':' << getCol();
OS << " @[ ";
InlinedAtDL.print(OS); if (DebugLoc InlinedAtDL = getInlinedAt()) {
OS << " ]"; OS << " @[ ";
} InlinedAtDL.print(OS);
OS << " ]";
} }
} }
// FIXME: Remove this old API once callers have been updated.
MDNode *DebugLoc::getInlinedAt(const LLVMContext &) const {
return getInlinedAt();
}
void DebugLoc::getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA) const {
Scope = getScope();
IA = getInlinedAt();
}