diff --git a/llvm/include/llvm/IR/DebugLoc.h b/llvm/include/llvm/IR/DebugLoc.h index 6d79aa6b2aa01..484adbb6e6a6c 100644 --- a/llvm/include/llvm/IR/DebugLoc.h +++ b/llvm/include/llvm/IR/DebugLoc.h @@ -21,287 +21,286 @@ namespace llvm { - class LLVMContext; - class raw_ostream; - class DILocation; - class Function; +class LLVMContext; +class raw_ostream; +class DILocation; +class Function; #if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE #if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN - struct DbgLocOrigin { - static constexpr unsigned long MaxDepth = 16; - using StackTracesTy = - SmallVector>, 0>; - StackTracesTy StackTraces; - DbgLocOrigin(bool ShouldCollectTrace); - void addTrace(); - const StackTracesTy &getOriginStackTraces() const { return StackTraces; }; - }; +struct DbgLocOrigin { + static constexpr unsigned long MaxDepth = 16; + using StackTracesTy = + SmallVector>, 0>; + StackTracesTy StackTraces; + DbgLocOrigin(bool ShouldCollectTrace); + void addTrace(); + const StackTracesTy &getOriginStackTraces() const { return StackTraces; }; +}; #else - struct DbgLocOrigin { - DbgLocOrigin(bool) {} - }; +struct DbgLocOrigin { + DbgLocOrigin(bool) {} +}; #endif - // Used to represent different "kinds" of DebugLoc, expressing that the - // instruction it is part of is either normal and should contain a valid - // DILocation, or otherwise describing the reason why the instruction does - // not contain a valid DILocation. - enum class DebugLocKind : uint8_t { - // The instruction is expected to contain a valid DILocation. - Normal, - // The instruction is compiler-generated, i.e. it is not associated with any - // line in the original source. - CompilerGenerated, - // The instruction has intentionally had its source location removed, - // typically because it was moved outside of its original control-flow and - // presenting the prior source location would be misleading for debuggers - // or profilers. - Dropped, - // The instruction does not have a known or currently knowable source - // location, e.g. the attribution is ambiguous in a way that can't be - // represented, or determining the correct location is complicated and - // requires future developer effort. - Unknown, - // DebugLoc is attached to an instruction that we don't expect to be - // emitted, and so can omit a valid DILocation; we don't expect to ever try - // and emit these into the line table, and trying to do so is a sign that - // something has gone wrong (most likely a DebugLoc leaking from a transient - // compiler-generated instruction). - Temporary - }; - - // Extends TrackingMDNodeRef to also store a DebugLocKind and Origin, - // allowing Debugify to ignore intentionally-empty DebugLocs and display the - // code responsible for generating unintentionally-empty DebugLocs. - // Currently we only need to track the Origin of this DILoc when using a - // DebugLoc that is not annotated (i.e. has DebugLocKind::Normal) and has a - // null DILocation, so only collect the origin stacktrace in those cases. - class DILocAndCoverageTracking : public TrackingMDNodeRef, - public DbgLocOrigin { - public: - DebugLocKind Kind; - // Default constructor for empty DebugLocs. - DILocAndCoverageTracking() - : TrackingMDNodeRef(nullptr), DbgLocOrigin(true), - Kind(DebugLocKind::Normal) {} - // Valid or nullptr MDNode*, no annotative DebugLocKind. - DILocAndCoverageTracking(const MDNode *Loc) - : TrackingMDNodeRef(const_cast(Loc)), DbgLocOrigin(!Loc), - Kind(DebugLocKind::Normal) {} - LLVM_ABI DILocAndCoverageTracking(const DILocation *Loc); - // Explicit DebugLocKind, which always means a nullptr MDNode*. - DILocAndCoverageTracking(DebugLocKind Kind) - : TrackingMDNodeRef(nullptr), - DbgLocOrigin(Kind == DebugLocKind::Normal), Kind(Kind) {} - }; - template <> struct simplify_type { - using SimpleType = MDNode *; - - static MDNode *getSimplifiedValue(DILocAndCoverageTracking &MD) { - return MD.get(); - } - }; - template <> struct simplify_type { - using SimpleType = MDNode *; - - static MDNode *getSimplifiedValue(const DILocAndCoverageTracking &MD) { - return MD.get(); - } - }; - - using DebugLocTrackingRef = DILocAndCoverageTracking; +// Used to represent different "kinds" of DebugLoc, expressing that the +// instruction it is part of is either normal and should contain a valid +// DILocation, or otherwise describing the reason why the instruction does +// not contain a valid DILocation. +enum class DebugLocKind : uint8_t { + // The instruction is expected to contain a valid DILocation. + Normal, + // The instruction is compiler-generated, i.e. it is not associated with any + // line in the original source. + CompilerGenerated, + // The instruction has intentionally had its source location removed, + // typically because it was moved outside of its original control-flow and + // presenting the prior source location would be misleading for debuggers + // or profilers. + Dropped, + // The instruction does not have a known or currently knowable source + // location, e.g. the attribution is ambiguous in a way that can't be + // represented, or determining the correct location is complicated and + // requires future developer effort. + Unknown, + // DebugLoc is attached to an instruction that we don't expect to be + // emitted, and so can omit a valid DILocation; we don't expect to ever try + // and emit these into the line table, and trying to do so is a sign that + // something has gone wrong (most likely a DebugLoc leaking from a transient + // compiler-generated instruction). + Temporary +}; + +// Extends TrackingMDNodeRef to also store a DebugLocKind and Origin, +// allowing Debugify to ignore intentionally-empty DebugLocs and display the +// code responsible for generating unintentionally-empty DebugLocs. +// Currently we only need to track the Origin of this DILoc when using a +// DebugLoc that is not annotated (i.e. has DebugLocKind::Normal) and has a +// null DILocation, so only collect the origin stacktrace in those cases. +class DILocAndCoverageTracking : public TrackingMDNodeRef, public DbgLocOrigin { +public: + DebugLocKind Kind; + // Default constructor for empty DebugLocs. + DILocAndCoverageTracking() + : TrackingMDNodeRef(nullptr), DbgLocOrigin(true), + Kind(DebugLocKind::Normal) {} + // Valid or nullptr MDNode*, no annotative DebugLocKind. + DILocAndCoverageTracking(const MDNode *Loc) + : TrackingMDNodeRef(const_cast(Loc)), DbgLocOrigin(!Loc), + Kind(DebugLocKind::Normal) {} + LLVM_ABI DILocAndCoverageTracking(const DILocation *Loc); + // Explicit DebugLocKind, which always means a nullptr MDNode*. + DILocAndCoverageTracking(DebugLocKind Kind) + : TrackingMDNodeRef(nullptr), DbgLocOrigin(Kind == DebugLocKind::Normal), + Kind(Kind) {} +}; +template <> struct simplify_type { + using SimpleType = MDNode *; + + static MDNode *getSimplifiedValue(DILocAndCoverageTracking &MD) { + return MD.get(); + } +}; +template <> struct simplify_type { + using SimpleType = MDNode *; + + static MDNode *getSimplifiedValue(const DILocAndCoverageTracking &MD) { + return MD.get(); + } +}; + +using DebugLocTrackingRef = DILocAndCoverageTracking; #else - using DebugLocTrackingRef = TrackingMDNodeRef; +using DebugLocTrackingRef = TrackingMDNodeRef; #endif // LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE - /// A debug info location. - /// - /// This class is a wrapper around a tracking reference to an \a DILocation - /// pointer. - /// - /// To avoid extra includes, \a DebugLoc doubles the \a DILocation API with a - /// one based on relatively opaque \a MDNode pointers. - class DebugLoc { +/// A debug info location. +/// +/// This class is a wrapper around a tracking reference to an \a DILocation +/// pointer. +/// +/// To avoid extra includes, \a DebugLoc doubles the \a DILocation API with a +/// one based on relatively opaque \a MDNode pointers. +class DebugLoc { - DebugLocTrackingRef Loc; + DebugLocTrackingRef Loc; - public: - DebugLoc() = default; +public: + DebugLoc() = default; - /// Construct from an \a DILocation. - LLVM_ABI DebugLoc(const DILocation *L); + /// Construct from an \a DILocation. + LLVM_ABI DebugLoc(const DILocation *L); - /// Construct from an \a MDNode. - /// - /// Note: if \c N is not an \a DILocation, 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. - LLVM_ABI explicit DebugLoc(const MDNode *N); + /// Construct from an \a MDNode. + /// + /// Note: if \c N is not an \a DILocation, 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. + LLVM_ABI explicit DebugLoc(const MDNode *N); #if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE - DebugLoc(DebugLocKind Kind) : Loc(Kind) {} - DebugLocKind getKind() const { return Loc.Kind; } + DebugLoc(DebugLocKind Kind) : Loc(Kind) {} + DebugLocKind getKind() const { return Loc.Kind; } #endif #if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE - static inline DebugLoc getTemporary() { - return DebugLoc(DebugLocKind::Temporary); - } - static inline DebugLoc getUnknown() { - return DebugLoc(DebugLocKind::Unknown); - } - static inline DebugLoc getCompilerGenerated() { - return DebugLoc(DebugLocKind::CompilerGenerated); - } - static inline DebugLoc getDropped() { - return DebugLoc(DebugLocKind::Dropped); - } + static inline DebugLoc getTemporary() { + return DebugLoc(DebugLocKind::Temporary); + } + static inline DebugLoc getUnknown() { + return DebugLoc(DebugLocKind::Unknown); + } + static inline DebugLoc getCompilerGenerated() { + return DebugLoc(DebugLocKind::CompilerGenerated); + } + static inline DebugLoc getDropped() { + return DebugLoc(DebugLocKind::Dropped); + } #else - static inline DebugLoc getTemporary() { return DebugLoc(); } - static inline DebugLoc getUnknown() { return DebugLoc(); } - static inline DebugLoc getCompilerGenerated() { return DebugLoc(); } - static inline DebugLoc getDropped() { return DebugLoc(); } + static inline DebugLoc getTemporary() { return DebugLoc(); } + static inline DebugLoc getUnknown() { return DebugLoc(); } + static inline DebugLoc getCompilerGenerated() { return DebugLoc(); } + static inline DebugLoc getDropped() { return DebugLoc(); } #endif // LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE - /// When two instructions are combined into a single instruction we also - /// need to combine the original locations into a single location. - /// When the locations are the same we can use either location. - /// When they differ, we need a third location which is distinct from - /// either. If they share a common scope, use this scope and compare the - /// line/column pair of the locations with the common scope: - /// * if both match, keep the line and column; - /// * if only the line number matches, keep the line and set the column as - /// 0; - /// * otherwise set line and column as 0. - /// If they do not share a common scope the location is ambiguous and can't - /// be represented in a line entry. In this case, set line and column as 0 - /// and use the scope of any location. - /// - /// \p LocA \p LocB: The locations to be merged. - LLVM_ABI static DebugLoc getMergedLocation(DebugLoc LocA, DebugLoc LocB); - - /// Try to combine the vector of locations passed as input in a single one. - /// This function applies getMergedLocation() repeatedly left-to-right. - /// - /// \p Locs: The locations to be merged. - LLVM_ABI static DebugLoc getMergedLocations(ArrayRef Locs); - - /// If this DebugLoc is non-empty, returns this DebugLoc; otherwise, selects - /// \p Other. - /// In coverage-tracking builds, this also accounts for whether this or - /// \p Other have an annotative DebugLocKind applied, such that if both are - /// empty but exactly one has an annotation, we prefer that annotated - /// location. - DebugLoc orElse(DebugLoc Other) const { - if (*this) - return *this; + /// When two instructions are combined into a single instruction we also + /// need to combine the original locations into a single location. + /// When the locations are the same we can use either location. + /// When they differ, we need a third location which is distinct from + /// either. If they share a common scope, use this scope and compare the + /// line/column pair of the locations with the common scope: + /// * if both match, keep the line and column; + /// * if only the line number matches, keep the line and set the column as + /// 0; + /// * otherwise set line and column as 0. + /// If they do not share a common scope the location is ambiguous and can't + /// be represented in a line entry. In this case, set line and column as 0 + /// and use the scope of any location. + /// + /// \p LocA \p LocB: The locations to be merged. + LLVM_ABI static DebugLoc getMergedLocation(DebugLoc LocA, DebugLoc LocB); + + /// Try to combine the vector of locations passed as input in a single one. + /// This function applies getMergedLocation() repeatedly left-to-right. + /// + /// \p Locs: The locations to be merged. + LLVM_ABI static DebugLoc getMergedLocations(ArrayRef Locs); + + /// If this DebugLoc is non-empty, returns this DebugLoc; otherwise, selects + /// \p Other. + /// In coverage-tracking builds, this also accounts for whether this or + /// \p Other have an annotative DebugLocKind applied, such that if both are + /// empty but exactly one has an annotation, we prefer that annotated + /// location. + DebugLoc orElse(DebugLoc Other) const { + if (*this) + return *this; #if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE - if (Other) - return Other; - if (getKind() != DebugLocKind::Normal) - return *this; - if (Other.getKind() != DebugLocKind::Normal) - return Other; + if (Other) + return Other; + if (getKind() != DebugLocKind::Normal) return *this; -#else + if (Other.getKind() != DebugLocKind::Normal) return Other; + return *this; +#else + return Other; #endif // LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE - } + } #if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN - const DbgLocOrigin::StackTracesTy &getOriginStackTraces() const { - return Loc.getOriginStackTraces(); - } - DebugLoc getCopied() const { - DebugLoc NewDL = *this; - NewDL.Loc.addTrace(); - return NewDL; - } + const DbgLocOrigin::StackTracesTy &getOriginStackTraces() const { + return Loc.getOriginStackTraces(); + } + DebugLoc getCopied() const { + DebugLoc NewDL = *this; + NewDL.Loc.addTrace(); + return NewDL; + } #else - DebugLoc getCopied() const { return *this; } + DebugLoc getCopied() const { return *this; } #endif - /// Get the underlying \a DILocation. - /// - /// \pre !*this or \c isa(getAsMDNode()). - /// @{ - LLVM_ABI DILocation *get() const; - operator DILocation *() const { return get(); } - DILocation *operator->() const { return get(); } - DILocation &operator*() const { return *get(); } - /// @} - - /// Check for null. - /// - /// Check for null in a way that is safe with broken debug info. Unlike - /// the conversion to \c DILocation, this doesn't require that \c Loc is of - /// the right type. Important for cases like \a llvm::StripDebugInfo() and - /// \a Instruction::hasMetadata(). - explicit operator bool() const { return Loc; } - - /// Check whether this has a trivial destructor. - bool hasTrivialDestructor() const { return Loc.hasTrivialDestructor(); } - - enum { ReplaceLastInlinedAt = true }; - /// Rebuild the entire inlined-at chain for this instruction so that the top of - /// the chain now is inlined-at the new call site. - /// \param InlinedAt The new outermost inlined-at in the chain. - LLVM_ABI static DebugLoc - appendInlinedAt(const DebugLoc &DL, DILocation *InlinedAt, LLVMContext &Ctx, - DenseMap &Cache); - - /// Return true if the source locations match, ignoring isImplicitCode and - /// source atom info. - bool isSameSourceLocation(const DebugLoc &Other) const { - if (get() == Other.get()) - return true; - return ((bool)*this == (bool)Other) && getLine() == Other.getLine() && - getCol() == Other.getCol() && getScope() == Other.getScope() && - getInlinedAt() == Other.getInlinedAt(); - } - - LLVM_ABI unsigned getLine() const; - LLVM_ABI unsigned getCol() const; - LLVM_ABI MDNode *getScope() const; - LLVM_ABI DILocation *getInlinedAt() const; - - /// Get the fully inlined-at scope for a DebugLoc. - /// - /// Gets the inlined-at scope for a DebugLoc. - LLVM_ABI MDNode *getInlinedAtScope() const; - - /// Rebuild the entire inline-at chain by replacing the subprogram at the - /// end of the chain with NewSP. - LLVM_ABI static DebugLoc - replaceInlinedAtSubprogram(const DebugLoc &DL, DISubprogram &NewSP, - LLVMContext &Ctx, - DenseMap &Cache); - - /// 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 DILocation/DILocalScope API to - /// find the subprogram, and then DILocation::get(). - LLVM_ABI DebugLoc getFnDebugLoc() const; - - /// Return \c this as a bar \a MDNode. - MDNode *getAsMDNode() const { return Loc; } - - /// Check if the DebugLoc corresponds to an implicit code. - LLVM_ABI bool isImplicitCode() const; - LLVM_ABI void setImplicitCode(bool ImplicitCode); - - bool operator==(const DebugLoc &DL) const { return Loc == DL.Loc; } - bool operator!=(const DebugLoc &DL) const { return Loc != DL.Loc; } - - LLVM_ABI void dump() const; - - /// prints source location /path/to/file.exe:line:col @[inlined at] - LLVM_ABI void print(raw_ostream &OS) const; - }; + /// Get the underlying \a DILocation. + /// + /// \pre !*this or \c isa(getAsMDNode()). + /// @{ + LLVM_ABI DILocation *get() const; + operator DILocation *() const { return get(); } + DILocation *operator->() const { return get(); } + DILocation &operator*() const { return *get(); } + /// @} + + /// Check for null. + /// + /// Check for null in a way that is safe with broken debug info. Unlike + /// the conversion to \c DILocation, this doesn't require that \c Loc is of + /// the right type. Important for cases like \a llvm::StripDebugInfo() and + /// \a Instruction::hasMetadata(). + explicit operator bool() const { return Loc; } + + /// Check whether this has a trivial destructor. + bool hasTrivialDestructor() const { return Loc.hasTrivialDestructor(); } + + enum { ReplaceLastInlinedAt = true }; + /// Rebuild the entire inlined-at chain for this instruction so that the top + /// of the chain now is inlined-at the new call site. + /// \param InlinedAt The new outermost inlined-at in the chain. + LLVM_ABI static DebugLoc + appendInlinedAt(const DebugLoc &DL, DILocation *InlinedAt, LLVMContext &Ctx, + DenseMap &Cache); + + /// Return true if the source locations match, ignoring isImplicitCode and + /// source atom info. + bool isSameSourceLocation(const DebugLoc &Other) const { + if (get() == Other.get()) + return true; + return ((bool)*this == (bool)Other) && getLine() == Other.getLine() && + getCol() == Other.getCol() && getScope() == Other.getScope() && + getInlinedAt() == Other.getInlinedAt(); + } + + LLVM_ABI unsigned getLine() const; + LLVM_ABI unsigned getCol() const; + LLVM_ABI MDNode *getScope() const; + LLVM_ABI DILocation *getInlinedAt() const; + + /// Get the fully inlined-at scope for a DebugLoc. + /// + /// Gets the inlined-at scope for a DebugLoc. + LLVM_ABI MDNode *getInlinedAtScope() const; + + /// Rebuild the entire inline-at chain by replacing the subprogram at the + /// end of the chain with NewSP. + LLVM_ABI static DebugLoc + replaceInlinedAtSubprogram(const DebugLoc &DL, DISubprogram &NewSP, + LLVMContext &Ctx, + DenseMap &Cache); + + /// 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 DILocation/DILocalScope API to + /// find the subprogram, and then DILocation::get(). + LLVM_ABI DebugLoc getFnDebugLoc() const; + + /// Return \c this as a bar \a MDNode. + MDNode *getAsMDNode() const { return Loc; } + + /// Check if the DebugLoc corresponds to an implicit code. + LLVM_ABI bool isImplicitCode() const; + LLVM_ABI void setImplicitCode(bool ImplicitCode); + + bool operator==(const DebugLoc &DL) const { return Loc == DL.Loc; } + bool operator!=(const DebugLoc &DL) const { return Loc != DL.Loc; } + + LLVM_ABI void dump() const; + + /// prints source location /path/to/file.exe:line:col @[inlined at] + LLVM_ABI void print(raw_ostream &OS) const; +}; } // end namespace llvm diff --git a/llvm/lib/IR/DebugLoc.cpp b/llvm/lib/IR/DebugLoc.cpp index bfba6e0cab6bf..a3c98aec98c81 100644 --- a/llvm/lib/IR/DebugLoc.cpp +++ b/llvm/lib/IR/DebugLoc.cpp @@ -31,7 +31,7 @@ void DbgLocOrigin::addTrace() { auto &[Depth, StackTrace] = StackTraces.emplace_back(); Depth = sys::getStackTrace(StackTrace); } -#endif +#endif // LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN #if LLVM_ENABLE_DEBUGLOC_TRACKING_COVERAGE DILocAndCoverageTracking::DILocAndCoverageTracking(const DILocation *L) @@ -83,16 +83,14 @@ DebugLoc DebugLoc::getFnDebugLoc() const { } bool DebugLoc::isImplicitCode() const { - if (DILocation *Loc = get()) { + if (DILocation *Loc = get()) return Loc->isImplicitCode(); - } return true; } void DebugLoc::setImplicitCode(bool ImplicitCode) { - if (DILocation *Loc = get()) { + if (DILocation *Loc = get()) Loc->setImplicitCode(ImplicitCode); - } } DebugLoc DebugLoc::replaceInlinedAtSubprogram(