| //===--- SILLocation.h - Location information for SIL nodes -----*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_SIL_LOCATION_H |
| #define SWIFT_SIL_LOCATION_H |
| |
| #include "llvm/ADT/PointerUnion.h" |
| #include "swift/Basic/SourceLoc.h" |
| #include "swift/Basic/SourceManager.h" |
| #include "swift/AST/TypeAlignments.h" |
| |
| #include <cstddef> |
| #include <type_traits> |
| |
| namespace swift { |
| |
| class SourceLoc; |
| class ReturnStmt; |
| class BraceStmt; |
| class AbstractClosureExpr; |
| class AbstractFunctionDecl; |
| |
| /// This is a pointer to the AST node that a SIL instruction was |
| /// derived from. This may be null if AST information is unavailable or |
| /// stripped. |
| /// |
| /// FIXME: This should eventually include inlining history, generics |
| /// instantiation info, etc (when we get to it). |
| /// |
| class SILLocation { |
| private: |
| template <class T, class Enable = void> |
| struct base_type; |
| |
| template <class T> |
| struct base_type<T, |
| typename std::enable_if<std::is_base_of<Decl, T>::value>::type> { |
| using type = Decl; |
| }; |
| |
| template <class T> |
| struct base_type<T, |
| typename std::enable_if<std::is_base_of<Expr, T>::value>::type> { |
| using type = Expr; |
| }; |
| |
| template <class T> |
| struct base_type<T, |
| typename std::enable_if<std::is_base_of<Stmt, T>::value>::type> { |
| using type = Stmt; |
| }; |
| |
| template <class T> |
| struct base_type<T, |
| typename std::enable_if<std::is_base_of<Pattern, T>::value>::type> { |
| using type = Pattern; |
| }; |
| |
| using ASTNodeTy = llvm::PointerUnion<Stmt *, Expr *, Decl *, Pattern *>; |
| |
| public: |
| enum LocationKind : unsigned { |
| RegularKind = 1, |
| ReturnKind = 2, |
| ImplicitReturnKind = 3, |
| InlinedKind = 4, |
| MandatoryInlinedKind = 5, |
| CleanupKind = 6, |
| ArtificialUnreachableKind = 7 |
| }; |
| |
| enum StorageKind : unsigned { |
| UnknownKind = 0, |
| ASTNodeKind = 1 << 3, |
| SILFileKind = 1 << 4, |
| DebugInfoKind = 1 << 3 | 1 << 4 |
| }; |
| |
| struct DebugLoc { |
| unsigned Line; |
| unsigned Column; |
| StringRef Filename; |
| |
| DebugLoc(unsigned Line = 0, unsigned Column = 0, |
| StringRef Filename = StringRef()) |
| : Line(Line), Column(Column), Filename(Filename) {} |
| |
| inline bool operator==(const DebugLoc &R) const { |
| return Line == R.Line && Column == R.Column && |
| Filename.equals(R.Filename); |
| } |
| }; |
| |
| protected: |
| union UnderlyingLocation { |
| UnderlyingLocation() : DebugInfoLoc({}) {} |
| UnderlyingLocation(ASTNodeTy N) : ASTNode(N) {} |
| UnderlyingLocation(SourceLoc L) : SILFileLoc(L) {} |
| UnderlyingLocation(DebugLoc D) |
| : DebugInfoLoc({D.Filename.data(), D.Line, D.Column}) {} |
| struct ASTNodeLoc { |
| ASTNodeLoc(ASTNodeTy N) : Primary(N) {} |
| /// Primary AST location, always used for diagnostics. |
| ASTNodeTy Primary; |
| /// Sometimes the location for diagnostics needs to be |
| /// different than the one used to emit the line table. If |
| /// HasDebugLoc is set, this is used for the debug info. |
| ASTNodeTy ForDebugger; |
| } ASTNode; |
| |
| /// A location inside a textual .sil file. |
| SourceLoc SILFileLoc; |
| |
| /// A deserialized source location. |
| /// |
| /// This represents \e most of the information in a SILLocation::DebugLoc, |
| /// but for bit-packing purposes the length of the filename is stored in |
| /// the SILLocation's ExtraStorageData instead of here. |
| /// |
| /// \sa SILLocation::getDebugInfoLoc |
| struct CompactDebugLoc { |
| const char *FilenameData; |
| unsigned Line; |
| unsigned Column; |
| } DebugInfoLoc; |
| } Loc; |
| |
| /// The kind of this SIL location. |
| unsigned KindData; |
| |
| /// Extra data that's not in UnderlyingLocation to keep the size of |
| /// SILLocation down. |
| unsigned ExtraStorageData = 0; |
| |
| enum { |
| LocationKindBits = 3, |
| LocationKindMask = 7, |
| |
| StorageKindBits = 2, |
| StorageKindMask = (1 << 3) | (1 << 4), |
| SpecialFlagsMask = ~ (LocationKindMask | StorageKindMask), |
| |
| /// Used to mark this instruction as part of auto-generated |
| /// code block. |
| AutoGeneratedBit = 5, |
| |
| /// Used to redefine the default source location used to |
| /// represent this SILLocation. For example, when the host instruction |
| /// is known to correspond to the beginning or the end of the source |
| /// range of the ASTNode. |
| PointsToStartBit = 6, |
| PointsToEndBit = 7, |
| |
| /// Used to notify that this instruction belongs to the top- |
| /// level (module) scope. |
| /// |
| /// FIXME: If Module becomes a Decl, this could be removed. |
| IsInTopLevel = 8, |
| |
| /// Marks this instruction as belonging to the function prologue. |
| IsInPrologue = 9 |
| }; |
| |
| template <typename T> |
| T *getNodeAs(ASTNodeTy Node) const { |
| using base = typename base_type<T>::type*; |
| return dyn_cast_or_null<T>(Node.dyn_cast<base>()); |
| } |
| |
| template <typename T> |
| bool isNode(ASTNodeTy Node) const { |
| assert(isASTNode()); |
| if (Loc.ASTNode.Primary.is<typename base_type<T>::type*>()) |
| return isa<T>(Node.get<typename base_type<T>::type*>()); |
| return false; |
| } |
| |
| template <typename T> |
| T *castNodeTo(ASTNodeTy Node) const { |
| return cast<T>(Node.get<typename base_type<T>::type*>()); |
| } |
| |
| /// \defgroup SILLocation constructors. |
| /// @{ |
| |
| /// This constructor is used to support getAs operation. |
| SILLocation() { assert(Loc.DebugInfoLoc.Line == 0); } |
| SILLocation(LocationKind K, unsigned Flags = 0) : KindData(K | Flags) { |
| assert(Loc.DebugInfoLoc.Line == 0); |
| } |
| |
| SILLocation(Stmt *S, LocationKind K, unsigned Flags = 0) |
| : Loc(S), KindData(K | Flags) { |
| setStorageKind(ASTNodeKind); |
| assert(isASTNode()); |
| } |
| |
| SILLocation(Expr *E, LocationKind K, unsigned Flags = 0) |
| : Loc(E), KindData(K | Flags) { |
| setStorageKind(ASTNodeKind); |
| assert(isASTNode()); |
| } |
| |
| SILLocation(Decl *D, LocationKind K, unsigned Flags = 0) |
| : Loc(D), KindData(K | Flags) { |
| setStorageKind(ASTNodeKind); |
| assert(isASTNode()); |
| } |
| |
| SILLocation(Pattern *P, LocationKind K, unsigned Flags = 0) |
| : Loc(P), KindData(K | Flags) { |
| setStorageKind(ASTNodeKind); |
| assert(isASTNode()); |
| } |
| |
| SILLocation(SourceLoc L, LocationKind K, unsigned Flags = 0) |
| : Loc(L), KindData(K | Flags) { |
| setStorageKind(SILFileKind); |
| assert(isSILFile()); |
| } |
| |
| SILLocation(DebugLoc L, LocationKind K, unsigned Flags = 0) |
| : KindData(K | Flags) { |
| setDebugInfoLoc(L); |
| } |
| /// @} |
| |
| private: |
| friend class ImplicitReturnLocation; |
| friend class MandatoryInlinedLocation; |
| friend class InlinedLocation; |
| friend class CleanupLocation; |
| |
| void setLocationKind(LocationKind K) { KindData |= (K & LocationKindMask); } |
| void setStorageKind(StorageKind K) { KindData |= (K & StorageKindMask); } |
| unsigned getSpecialFlags() const { return KindData & SpecialFlagsMask; } |
| void setSpecialFlags(unsigned Flags) { |
| KindData |= (Flags & SpecialFlagsMask); |
| } |
| |
| SourceLoc getSourceLoc(ASTNodeTy N) const; |
| SourceLoc getStartSourceLoc(ASTNodeTy N) const; |
| SourceLoc getEndSourceLoc(ASTNodeTy N) const; |
| |
| public: |
| |
| /// When an ASTNode gets implicitly converted into a SILLocation we |
| /// construct a RegularLocation. Since RegularLocations represent the majority |
| /// of locations, this greatly simplifies the user code. |
| SILLocation(Stmt *S) : Loc(S), KindData(RegularKind) { |
| setStorageKind(ASTNodeKind); |
| assert(isASTNode()); |
| } |
| SILLocation(Expr *E) : Loc(E), KindData(RegularKind) { |
| setStorageKind(ASTNodeKind); |
| assert(isASTNode()); |
| } |
| SILLocation(Decl *D) : Loc(D), KindData(RegularKind) { |
| setStorageKind(ASTNodeKind); |
| assert(isASTNode()); |
| } |
| SILLocation(Pattern *P) : Loc(P), KindData(RegularKind) { |
| setStorageKind(ASTNodeKind); |
| assert(isASTNode()); |
| } |
| |
| static SILLocation invalid() { return SILLocation(); } |
| |
| /// Check if the location wraps an AST node or a valid SIL file |
| /// location. |
| /// |
| /// Artificial locations and the top-level module locations will be null. |
| bool isNull() const { |
| switch (getStorageKind()) { |
| case ASTNodeKind: return Loc.ASTNode.Primary.isNull(); |
| case DebugInfoKind: return ExtraStorageData == 0; |
| case SILFileKind: return Loc.SILFileLoc.isInvalid(); |
| default: return true; |
| } |
| } |
| explicit operator bool() const { return !isNull(); } |
| |
| /// Return whether this location is backed by an AST node. |
| bool isASTNode() const { return getStorageKind() == ASTNodeKind; } |
| |
| /// Return whether this location came from a SIL file. |
| bool isSILFile() const { return getStorageKind() == SILFileKind; } |
| |
| /// Return whether this location came from a textual SIL file. |
| bool isDebugInfoLoc() const { return getStorageKind() == DebugInfoKind; } |
| |
| /// Marks the location as coming from auto-generated body. |
| void markAutoGenerated() { KindData |= (1 << AutoGeneratedBit); } |
| |
| /// Returns true if the location represents an artificially generated |
| /// body, such as thunks or default destructors. |
| /// |
| /// These locations should not be included in the debug line table. |
| /// These might also need special handling by the debugger since they might |
| /// contain calls, which the debugger could be able to step into. |
| bool isAutoGenerated() const { return KindData & (1 << AutoGeneratedBit); } |
| |
| /// Returns true if the line number of this location is zero. |
| bool isLineZero(const SourceManager &SM) const { |
| return decodeDebugLoc(SM).Line == 0; |
| } |
| |
| /// Changes the default source location position to point to start of |
| /// the AST node. |
| void pointToStart() { KindData |= (1 << PointsToStartBit); } |
| |
| /// Changes the default source location position to point to the end of |
| /// the AST node. |
| void pointToEnd() { KindData |= (1 << PointsToEndBit); } |
| |
| /// Mark this location as the location corresponding to the top-level |
| /// (module-level) code. |
| void markAsInTopLevel() { KindData |= (1 << IsInTopLevel); } |
| |
| /// Check is this location is associated with the top level/module. |
| bool isInTopLevel() const { return KindData & (1 << IsInTopLevel); } |
| |
| /// Mark this location as being part of the function |
| /// prologue, which means that it deals with setting up the stack |
| /// frame. The first breakpoint location in a function is at the end |
| /// of the prologue. |
| void markAsPrologue() { KindData |= (1 << IsInPrologue); } |
| |
| /// Check is this location is part of a function's implicit prologue. |
| bool isInPrologue() const { return KindData & (1 << IsInPrologue); } |
| |
| /// Add an ASTNode to use as the location for debugging |
| /// purposes if this location is different from the location used |
| /// for diagnostics. |
| template <typename T> |
| void setDebugLoc(T *ASTNodeForDebugging) { |
| assert(!hasDebugLoc() && "DebugLoc already present"); |
| assert(isASTNode() && "not an AST location"); |
| Loc.ASTNode.ForDebugger = ASTNodeForDebugging; |
| } |
| bool hasDebugLoc() const { |
| return isASTNode() && !Loc.ASTNode.ForDebugger.isNull(); |
| } |
| |
| /// Populate this empty SILLocation with a DebugLoc. |
| void setDebugInfoLoc(DebugLoc L) { |
| ExtraStorageData = L.Filename.size(); |
| assert(ExtraStorageData == L.Filename.size() && |
| "file name is longer than 32 bits"); |
| Loc = L; |
| setStorageKind(DebugInfoKind); |
| } |
| |
| /// Check if the corresponding source code location definitely points |
| /// to the start of the AST node. |
| bool alwaysPointsToStart() const { return KindData & (1 << PointsToStartBit);} |
| |
| /// Check if the corresponding source code location definitely points |
| /// to the end of the AST node. |
| bool alwaysPointsToEnd() const { return KindData & (1 << PointsToEndBit); } |
| |
| LocationKind getKind() const { |
| return LocationKind(KindData & LocationKindMask); |
| } |
| StorageKind getStorageKind() const { |
| return StorageKind(KindData & StorageKindMask); |
| } |
| |
| template <typename T> |
| bool is() const { |
| return T::isKind(*this); |
| } |
| |
| template <typename T> |
| T castTo() const { |
| assert(T::isKind(*this)); |
| T t; |
| SILLocation& tr = t; |
| tr = *this; |
| return t; |
| } |
| |
| template <typename T> |
| Optional<T> getAs() const { |
| if (!T::isKind(*this)) |
| return Optional<T>(); |
| T t; |
| SILLocation& tr = t; |
| tr = *this; |
| return t; |
| } |
| |
| /// If the current value is of the specified AST unit type T, |
| /// return it, otherwise return null. |
| template <typename T> T *getAsASTNode() const { |
| return isASTNode() ? getNodeAs<T>(Loc.ASTNode.Primary) : nullptr; |
| } |
| |
| /// Returns true if the Location currently points to the AST node |
| /// matching type T. |
| template <typename T> bool isASTNode() const { |
| return isASTNode() && isNode<T>(Loc.ASTNode.Primary); |
| } |
| |
| /// Returns the primary value as the specified AST node type. If the |
| /// specified type is incorrect, asserts. |
| template <typename T> T *castToASTNode() const { |
| assert(isASTNode()); |
| return castNodeTo<T>(Loc.ASTNode.Primary); |
| } |
| |
| /// If the DebugLoc is of the specified AST unit type T, |
| /// return it, otherwise return null. |
| template <typename T> T *getDebugLocAsASTNode() const { |
| assert(hasDebugLoc() && "no debug location"); |
| return getNodeAs<T>(Loc.ASTNode.ForDebugger); |
| } |
| |
| /// Return the location as a DeclContext or null. |
| DeclContext *getAsDeclContext() const; |
| |
| /// Convert a specialized location kind into a regular location. |
| SILLocation getAsRegularLocation() { |
| SILLocation RegularLoc = *this; |
| RegularLoc.setLocationKind(RegularKind); |
| return RegularLoc; |
| } |
| |
| SourceLoc getDebugSourceLoc() const; |
| SourceLoc getSourceLoc() const; |
| SourceLoc getStartSourceLoc() const; |
| SourceLoc getEndSourceLoc() const; |
| SourceRange getSourceRange() const { |
| return {getStartSourceLoc(), getEndSourceLoc()}; |
| } |
| DebugLoc getDebugInfoLoc() const { |
| assert(isDebugInfoLoc()); |
| return DebugLoc(Loc.DebugInfoLoc.Line, Loc.DebugInfoLoc.Column, |
| StringRef(Loc.DebugInfoLoc.FilenameData, ExtraStorageData)); |
| } |
| |
| /// Fingerprint a DebugLoc for use in a DenseMap. |
| using DebugLocKey = std::pair<std::pair<unsigned, unsigned>, StringRef>; |
| struct DebugLocHash : public DebugLocKey { |
| DebugLocHash(DebugLoc L) : DebugLocKey({{L.Line, L.Column}, L.Filename}) {} |
| }; |
| |
| /// Extract the line, column, and filename. |
| static DebugLoc decode(SourceLoc Loc, const SourceManager &SM); |
| |
| /// Return the decoded debug location. |
| LLVM_NODISCARD DebugLoc decodeDebugLoc(const SourceManager &SM) const { |
| return isDebugInfoLoc() ? getDebugInfoLoc() |
| : decode(getDebugSourceLoc(), SM); |
| } |
| |
| /// Compiler-generated locations may be applied to instructions without any |
| /// clear correspondence to an AST node in an otherwise normal function. |
| static DebugLoc getCompilerGeneratedDebugLoc() { |
| return {0, 0, "<compiler-generated>"}; |
| } |
| |
| /// Pretty-print the value. |
| void dump(const SourceManager &SM) const; |
| void print(raw_ostream &OS, const SourceManager &SM) const; |
| |
| /// Returns an opaque pointer value for the debug location that may |
| /// be used to unique debug locations. |
| const void *getOpaquePointerValue() const { |
| if (isSILFile()) |
| return Loc.SILFileLoc.getOpaquePointerValue(); |
| if (isASTNode()) |
| return Loc.ASTNode.Primary.getOpaqueValue(); |
| else |
| return 0; |
| } |
| unsigned getOpaqueKind() const { return KindData; } |
| |
| inline bool operator==(const SILLocation& R) const { |
| return KindData == R.KindData && |
| Loc.ASTNode.Primary.getOpaqueValue() == |
| R.Loc.ASTNode.Primary.getOpaqueValue() && |
| Loc.ASTNode.ForDebugger.getOpaqueValue() == |
| R.Loc.ASTNode.ForDebugger.getOpaqueValue(); |
| } |
| |
| inline bool operator!=(const SILLocation &R) const { return !(*this == R); } |
| }; |
| |
| /// Allowed on any instruction. |
| class RegularLocation : public SILLocation { |
| public: |
| RegularLocation(Stmt *S) : SILLocation(S, RegularKind) {} |
| RegularLocation(Expr *E) : SILLocation(E, RegularKind) {} |
| RegularLocation(Decl *D) : SILLocation(D, RegularKind) {} |
| RegularLocation(Pattern *P) : SILLocation(P, RegularKind) {} |
| RegularLocation(SourceLoc L) : SILLocation(L, RegularKind) {} |
| RegularLocation(DebugLoc L) : SILLocation(L, RegularKind) {} |
| |
| /// Returns a location representing the module. |
| static RegularLocation getModuleLocation() { |
| RegularLocation Loc; |
| Loc.markAsInTopLevel(); |
| return Loc; |
| } |
| |
| /// If the current value is of the specified AST unit type T, |
| /// return it, otherwise return null. |
| template <typename T> T *getAs() const { return getNodeAs<T>(Loc.ASTNode); } |
| |
| /// Returns true if the Location currently points to the AST node |
| /// matching type T. |
| template <typename T> bool is() const { return isNode<T>(Loc.ASTNode); } |
| |
| /// Returns the primary value as the specified AST node type. If the |
| /// specified type is incorrect, asserts. |
| template <typename T> T *castTo() const { return castNodeTo<T>(Loc.ASTNode); } |
| |
| /// Compiler-generated locations may be applied to instructions without any |
| /// clear correspondence to an AST node in an otherwise normal function. |
| /// The auto-generated bit also turns off certain diagnostics passes such. |
| static RegularLocation getAutoGeneratedLocation() { |
| RegularLocation AL(getCompilerGeneratedDebugLoc()); |
| AL.markAutoGenerated(); |
| return AL; |
| } |
| |
| /// Returns a location that is compiler-generated, but with a hint as to where |
| /// it may have been generated from. These locations will have an artificial |
| /// line location of zero in DWARF, but in CodeView we want to use the given |
| /// line since line zero does not represent an artificial line in CodeView. |
| template <typename InputLocTy> |
| static RegularLocation getAutoGeneratedLocation(InputLocTy L) { |
| RegularLocation AL(L); |
| AL.markAutoGenerated(); |
| return AL; |
| } |
| |
| private: |
| RegularLocation() : SILLocation(RegularKind) {} |
| |
| friend class SILLocation; |
| static bool isKind(const SILLocation& L) { |
| return L.getKind() == RegularKind; |
| } |
| }; |
| |
| /// Used to represent a return instruction in user code. |
| /// |
| /// Allowed on an BranchInst, ReturnInst. |
| class ReturnLocation : public SILLocation { |
| public: |
| ReturnLocation(ReturnStmt *RS); |
| |
| /// Construct the return location for a constructor or a destructor. |
| ReturnLocation(BraceStmt *BS); |
| |
| ReturnStmt *get(); |
| |
| private: |
| friend class SILLocation; |
| static bool isKind(const SILLocation& L) { |
| return L.getKind() == ReturnKind; |
| } |
| }; |
| |
| /// Used on the instruction that was generated to represent an implicit |
| /// return from a function. |
| /// |
| /// Allowed on an BranchInst, ReturnInst. |
| class ImplicitReturnLocation : public SILLocation { |
| public: |
| |
| ImplicitReturnLocation(AbstractClosureExpr *E); |
| |
| ImplicitReturnLocation(ReturnStmt *S); |
| |
| ImplicitReturnLocation(AbstractFunctionDecl *AFD); |
| |
| /// Construct from a RegularLocation; preserve all special bits. |
| /// |
| /// Note, this can construct an implicit return for an arbitrary expression |
| /// (specifically, in case of auto-generated bodies). |
| static SILLocation getImplicitReturnLoc(SILLocation L); |
| |
| AbstractClosureExpr *get(); |
| |
| private: |
| friend class SILLocation; |
| static bool isKind(const SILLocation& L) { |
| return L.getKind() == ImplicitReturnKind; |
| } |
| ImplicitReturnLocation() : SILLocation(ImplicitReturnKind) {} |
| }; |
| |
| /// Marks instructions that correspond to inlined function body and |
| /// setup code. This location should not be used for inlined transparent |
| /// bodies, see MandatoryInlinedLocation. |
| /// |
| /// This location wraps the call site ASTNode. |
| /// |
| /// Allowed on any instruction except for ReturnInst. |
| class InlinedLocation : public SILLocation { |
| public: |
| InlinedLocation(Expr *CallSite) : SILLocation(CallSite, InlinedKind) {} |
| InlinedLocation(Stmt *S) : SILLocation(S, InlinedKind) {} |
| InlinedLocation(Pattern *P) : SILLocation(P, InlinedKind) {} |
| InlinedLocation(Decl *D) : SILLocation(D, InlinedKind) {} |
| |
| /// Constructs an inlined location when the call site is represented by a |
| /// SILFile location. |
| InlinedLocation(SourceLoc L) : SILLocation(InlinedKind) { |
| setStorageKind(SILFileKind); |
| Loc.SILFileLoc = L; |
| } |
| |
| static InlinedLocation getInlinedLocation(SILLocation L); |
| |
| private: |
| friend class SILLocation; |
| static bool isKind(const SILLocation& L) { |
| return L.getKind() == InlinedKind; |
| } |
| InlinedLocation() : SILLocation(InlinedKind) {} |
| |
| InlinedLocation(Expr *E, unsigned F) : SILLocation(E, InlinedKind, F) {} |
| InlinedLocation(Stmt *S, unsigned F) : SILLocation(S, InlinedKind, F) {} |
| InlinedLocation(Pattern *P, unsigned F) : SILLocation(P, InlinedKind, F) {} |
| InlinedLocation(Decl *D, unsigned F) : SILLocation(D, InlinedKind, F) {} |
| InlinedLocation(SourceLoc L, unsigned F) : SILLocation(L, InlinedKind, F) {} |
| |
| static InlinedLocation getModuleLocation(unsigned Flags) { |
| auto L = InlinedLocation(); |
| L.setSpecialFlags(Flags); |
| return L; |
| } |
| |
| }; |
| |
| /// Marks instructions that correspond to inlined function body and |
| /// setup code for transparent functions, inlined as part of mandatory inlining |
| /// pass. |
| /// |
| /// This location wraps the call site ASTNode. |
| /// |
| /// Allowed on any instruction except for ReturnInst. |
| class MandatoryInlinedLocation : public SILLocation { |
| public: |
| MandatoryInlinedLocation(Expr *CallSite) : |
| SILLocation(CallSite, MandatoryInlinedKind) {} |
| MandatoryInlinedLocation(Stmt *S) : SILLocation(S, MandatoryInlinedKind) {} |
| MandatoryInlinedLocation(Pattern *P) : SILLocation(P, MandatoryInlinedKind) {} |
| MandatoryInlinedLocation(Decl *D) : SILLocation(D, MandatoryInlinedKind) {} |
| |
| /// Constructs an inlined location when the call site is represented by a |
| /// SILFile location. |
| MandatoryInlinedLocation(SourceLoc L) |
| : SILLocation(L, MandatoryInlinedKind) {} |
| |
| static MandatoryInlinedLocation getMandatoryInlinedLocation(SILLocation L); |
| static MandatoryInlinedLocation getAutoGeneratedLocation(); |
| |
| static MandatoryInlinedLocation getModuleLocation(unsigned Flags) { |
| auto L = MandatoryInlinedLocation(); |
| L.setSpecialFlags(Flags); |
| return L; |
| } |
| |
| private: |
| friend class SILLocation; |
| static bool isKind(const SILLocation& L) { |
| return L.getKind() == MandatoryInlinedKind; |
| } |
| MandatoryInlinedLocation() : SILLocation(MandatoryInlinedKind) {} |
| MandatoryInlinedLocation(Expr *E, unsigned F) |
| : SILLocation(E, MandatoryInlinedKind, F) {} |
| MandatoryInlinedLocation(Stmt *S, unsigned F) |
| : SILLocation(S, MandatoryInlinedKind, F) {} |
| MandatoryInlinedLocation(Pattern *P, unsigned F) |
| : SILLocation(P, MandatoryInlinedKind, F) {} |
| MandatoryInlinedLocation(Decl *D, unsigned F) |
| : SILLocation(D, MandatoryInlinedKind, F) {} |
| MandatoryInlinedLocation(SourceLoc L, unsigned F) |
| : SILLocation(L, MandatoryInlinedKind, F) {} |
| MandatoryInlinedLocation(DebugLoc L, unsigned F) |
| : SILLocation(L, MandatoryInlinedKind, F) {} |
| }; |
| |
| /// Used on the instruction performing auto-generated cleanup such as |
| /// deallocs, destructor calls. |
| /// |
| /// The cleanups are performed after completing the evaluation of the AST Node |
| /// wrapped inside the SILLocation. This location wraps the statement |
| /// representing the enclosing scope, for example, FuncDecl, ParenExpr. The |
| /// scope's end location points to the SourceLoc that shows when the operation |
| /// is performed at runtime. |
| /// |
| /// Allowed on any instruction except for ReturnInst. |
| /// Locations of an inlined destructor should also be represented by this. |
| class CleanupLocation : public SILLocation { |
| public: |
| CleanupLocation(Expr *E) : SILLocation(E, CleanupKind) {} |
| CleanupLocation(Stmt *S) : SILLocation(S, CleanupKind) {} |
| CleanupLocation(Pattern *P) : SILLocation(P, CleanupKind) {} |
| CleanupLocation(Decl *D) : SILLocation(D, CleanupKind) {} |
| |
| static CleanupLocation get(SILLocation L); |
| |
| /// Returns a location representing a cleanup on the module level. |
| static CleanupLocation getModuleCleanupLocation() { |
| CleanupLocation Loc; |
| Loc.markAsInTopLevel(); |
| return Loc; |
| } |
| |
| private: |
| friend class SILLocation; |
| static bool isKind(const SILLocation& L) { |
| return L.getKind() == CleanupKind; |
| } |
| CleanupLocation() : SILLocation(CleanupKind) {} |
| |
| CleanupLocation(Expr *E, unsigned F) : SILLocation(E, CleanupKind, F) {} |
| CleanupLocation(Stmt *S, unsigned F) : SILLocation(S, CleanupKind, F) {} |
| CleanupLocation(Pattern *P, unsigned F) : SILLocation(P, CleanupKind, F) {} |
| CleanupLocation(Decl *D, unsigned F) : SILLocation(D, CleanupKind, F) {} |
| }; |
| |
| /// Used to represent an unreachable location that was |
| /// auto-generated and has no correspondence to user code. It should |
| /// not be used in diagnostics or for debugging. |
| /// |
| /// Differentiates an unreachable instruction, which is generated by |
| /// DCE, from an unreachable instruction in user code (output of SILGen). |
| /// Allowed on an unreachable instruction. |
| class ArtificialUnreachableLocation : public SILLocation { |
| public: |
| ArtificialUnreachableLocation() : SILLocation(ArtificialUnreachableKind) {} |
| private: |
| friend class SILLocation; |
| static bool isKind(const SILLocation& L) { |
| return (L.getKind() == ArtificialUnreachableKind); |
| } |
| }; |
| |
| class SILDebugScope; |
| |
| /// A SILLocation paired with a SILDebugScope. |
| class SILDebugLocation { |
| const SILDebugScope *debugScope; |
| SILLocation location; |
| |
| public: |
| SILDebugLocation() |
| : debugScope(nullptr), |
| location(RegularLocation::getAutoGeneratedLocation()) {} |
| SILDebugLocation(SILLocation location, const SILDebugScope *debugScope) |
| : debugScope(debugScope), location(location) {} |
| SILLocation getLocation() const { return location; } |
| const SILDebugScope *getScope() const { return debugScope; } |
| operator bool() const { return bool(location) && debugScope; } |
| }; |
| |
| } // end swift namespace |
| |
| |
| #endif |