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.

llvm-svn: 233573
This commit is contained in:
Duncan P. N. Exon Smith 2015-03-30 18:07:40 +00:00
parent d654eeb862
commit 86b0db4286
2 changed files with 133 additions and 96 deletions

View File

@ -22,11 +22,15 @@ namespace llvm {
class LLVMContext;
class raw_ostream;
class MDNode;
class MDLocation;
/// DebugLoc - Debug location id. This is carried by Instruction, SDNode,
/// and MachineInstr to compactly encode file/line/scope information for an
/// operation.
/// \brief A debug info location.
///
/// 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 {
TrackingMDNodeRef Loc;
@ -43,66 +47,89 @@ namespace llvm {
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.
bool hasTrivialDestructor() const { return Loc.hasTrivialDestructor(); }
/// get - Get a new DebugLoc that corresponds to the specified line/col
/// scope/inline location.
/// \brief Create a new DebugLoc.
///
/// 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,
MDNode *InlinedAt = nullptr);
/// getFromDILocation - Translate the DILocation quad into a DebugLoc.
static DebugLoc getFromDILocation(MDNode *N);
/// getFromDILexicalBlock - Translate the DILexicalBlock into a DebugLoc.
/// \brief Translate the DILexicalBlock into a DebugLoc.
///
/// FIXME: Remove this. It has only one user, and the user just wants to
/// pass an \a MDScope around.
static DebugLoc getFromDILexicalBlock(MDNode *N);
/// isUnknown - Return true if this is an unknown location.
bool isUnknown() const { return !Loc; }
unsigned getLine() const;
unsigned getCol() const;
/// getScope - This returns the scope pointer for this DebugLoc, or null if
/// invalid.
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(); }
/// 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.
MDNode *getInlinedAt(const LLVMContext &) const;
void getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA) const;
void getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA,
const LLVMContext &) const {
return getScopeAndInlinedAt(Scope, IA);
}
/// getScopeNode - Get MDNode for DebugLoc's scope, or null if invalid.
MDNode *getScopeNode() const;
MDNode *getScopeNode() const { return getInlinedAtScope(); }
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 {
return getFnDebugLoc();
}
/// getAsMDNode - This method converts the compressed DebugLoc node into a
/// DILocation compatible MDNode.
MDNode *getAsMDNode() const;
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(); }
/// \brief prints source location /path/to/file.exe:line:col @[inlined at]
void print(raw_ostream &OS) const;
};
} // end namespace llvm

View File

@ -16,28 +16,40 @@ using namespace llvm;
//===----------------------------------------------------------------------===//
// DebugLoc Implementation
//===----------------------------------------------------------------------===//
DebugLoc::DebugLoc(MDLocation *L) : Loc(L) {}
DebugLoc::DebugLoc(MDNode *L) : Loc(L) {}
unsigned DebugLoc::getLine() const { return DILocation(Loc).getLineNumber(); }
unsigned DebugLoc::getCol() const { return DILocation(Loc).getColumnNumber(); }
MDNode *DebugLoc::getScope() const { return DILocation(Loc).getScope(); }
MDNode *DebugLoc::getInlinedAt() const {
return DILocation(Loc).getOrigLocation();
MDLocation *DebugLoc::get() const {
return cast_or_null<MDLocation>(Loc.get());
}
/// Return both the Scope and the InlinedAt values.
void DebugLoc::getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA) const {
Scope = getScope();
IA = getInlinedAt();
unsigned DebugLoc::getLine() const {
assert(get() && "Expected valid DebugLoc");
return get()->getLine();
}
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();
}
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);
if (SP.isSubprogram())
return DebugLoc::get(SP.getScopeLineNumber(), 0, SP);
@ -51,19 +63,7 @@ DebugLoc DebugLoc::get(unsigned Line, unsigned Col,
if (!Scope)
return DebugLoc();
return getFromDILocation(
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;
return MDLocation::get(Scope->getContext(), Line, Col, Scope, InlinedAt);
}
/// getFromDILexicalBlock - Translate the DILexicalBlock into a DebugLoc.
@ -77,38 +77,48 @@ DebugLoc DebugLoc::getFromDILexicalBlock(MDNode *N) {
void DebugLoc::dump() const {
#ifndef NDEBUG
if (!isUnknown()) {
dbgs() << getLine();
if (getCol() != 0)
dbgs() << ',' << getCol();
DebugLoc InlinedAtDL = DebugLoc::getFromDILocation(getInlinedAt());
if (!InlinedAtDL.isUnknown()) {
dbgs() << " @ ";
InlinedAtDL.dump();
} else
dbgs() << "\n";
}
if (!Loc)
return;
dbgs() << getLine();
if (getCol() != 0)
dbgs() << ',' << getCol();
if (DebugLoc InlinedAtDL = DebugLoc(getInlinedAt())) {
dbgs() << " @ ";
InlinedAtDL.dump();
} else
dbgs() << "\n";
#endif
}
void DebugLoc::print(raw_ostream &OS) const {
if (!isUnknown()) {
// Print source line info.
DIScope Scope(getScope());
assert((!Scope || Scope.isScope()) &&
"Scope of a DebugLoc should be null or a DIScope.");
if (Scope)
OS << Scope.getFilename();
else
OS << "<unknown>";
OS << ':' << getLine();
if (getCol() != 0)
OS << ':' << getCol();
DebugLoc InlinedAtDL = DebugLoc::getFromDILocation(getInlinedAt());
if (!InlinedAtDL.isUnknown()) {
OS << " @[ ";
InlinedAtDL.print(OS);
OS << " ]";
}
if (!Loc)
return;
// Print source line info.
DIScope Scope(getScope());
assert((!Scope || Scope.isScope()) &&
"Scope of a DebugLoc should be null or a DIScope.");
if (Scope)
OS << Scope.getFilename();
else
OS << "<unknown>";
OS << ':' << getLine();
if (getCol() != 0)
OS << ':' << getCol();
if (DebugLoc InlinedAtDL = getInlinedAt()) {
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();
}