| //===--- IRGenDebugInfo.h - Debug Info Support ------------------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines IR codegen support for debug information. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_IRGEN_DEBUGINFO_H |
| #define SWIFT_IRGEN_DEBUGINFO_H |
| |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/ADT/PointerUnion.h" |
| #include "llvm/IR/ValueHandle.h" |
| #include "llvm/IR/DebugInfo.h" |
| #include "llvm/IR/DIBuilder.h" |
| #include "llvm/Support/Allocator.h" |
| |
| #include "swift/AST/Module.h" |
| #include "swift/SIL/SILLocation.h" |
| #include "swift/SIL/SILBasicBlock.h" |
| |
| #include "DebugTypeInfo.h" |
| #include "IRBuilder.h" |
| #include "IRGenFunction.h" |
| #include "IRGenModule.h" |
| #include "GenType.h" |
| |
| #include <set> |
| |
| namespace llvm { |
| class DIBuilder; |
| } |
| |
| namespace swift { |
| |
| class ASTContext; |
| class AllocStackInst; |
| class ClangImporter; |
| class IRGenOptions; |
| class SILArgument; |
| class SILDebugScope; |
| class SILModule; |
| |
| enum class SILFunctionTypeRepresentation : uint8_t; |
| |
| namespace irgen { |
| |
| class IRGenFunction; |
| |
| typedef struct { |
| unsigned Line, Col; |
| const char *Filename; |
| } Location; |
| |
| typedef struct { Location LocForLinetable, Loc; } FullLocation; |
| |
| typedef llvm::DenseMap<const llvm::MDString *, llvm::TrackingMDNodeRef> |
| TrackingDIRefMap; |
| |
| enum IndirectionKind : bool { DirectValue = false, IndirectValue = true }; |
| enum ArtificialKind : bool { RealValue = false, ArtificialValue = true }; |
| |
| /// IRGenDebugInfo - Helper object that keeps track of the current |
| /// CompileUnit, File, LexicalScope, and translates SILLocations into |
| /// <llvm::DebugLoc>s. |
| class IRGenDebugInfo { |
| friend class ArtificialLocation; |
| const IRGenOptions &Opts; |
| ClangImporter &CI; |
| SourceManager &SM; |
| llvm::Module &M; |
| llvm::DIBuilder DBuilder; |
| IRGenModule &IGM; |
| |
| // Various caches. |
| llvm::DenseMap<const SILDebugScope *, llvm::TrackingMDNodeRef> ScopeCache; |
| llvm::DenseMap<const char *, llvm::TrackingMDNodeRef> DIFileCache; |
| llvm::DenseMap<TypeBase *, llvm::TrackingMDNodeRef> DITypeCache; |
| llvm::StringMap<llvm::TrackingMDNodeRef> DIModuleCache; |
| TrackingDIRefMap DIRefMap; |
| llvm::SmallPtrSet<const llvm::DIType *, 16> IndirectEnumCases; |
| |
| llvm::BumpPtrAllocator DebugInfoNames; |
| StringRef CWDName; /// The current working directory. |
| llvm::DICompileUnit *TheCU = nullptr; /// The current compilation unit. |
| llvm::DIFile *MainFile = nullptr; /// The main file. |
| llvm::DIModule *MainModule = nullptr; /// The current module. |
| llvm::MDNode *EntryPointFn; /// Scope of SWIFT_ENTRY_POINT_FUNCTION. |
| TypeAliasDecl *MetadataTypeDecl; /// The type decl for swift.type. |
| llvm::DIType *InternalType; /// Catch-all type for opaque internal types. |
| |
| Location LastDebugLoc; /// The last location that was emitted. |
| const SILDebugScope *LastScope; /// The scope of that last location. |
| bool IsLibrary; /// Whether this is a library or a top level module. |
| #ifndef NDEBUG |
| /// The basic block where the location was last changed. |
| llvm::BasicBlock *LastBasicBlock; |
| bool lineNumberIsSane(IRBuilder &Builder, unsigned Line); |
| #endif |
| |
| /// Used by pushLoc. |
| SmallVector<std::pair<Location, const SILDebugScope *>, 8> LocationStack; |
| |
| // FIXME: move this to something more local in type generation. |
| CanGenericSignature CurGenerics; |
| class GenericsRAII { |
| IRGenDebugInfo &Self; |
| GenericContextScope Scope; |
| CanGenericSignature OldGenerics; |
| public: |
| GenericsRAII(IRGenDebugInfo &self, CanGenericSignature generics) |
| : Self(self), Scope(self.IGM, generics), OldGenerics(self.CurGenerics) { |
| if (generics) self.CurGenerics = generics; |
| } |
| |
| ~GenericsRAII() { |
| Self.CurGenerics = OldGenerics; |
| } |
| }; |
| |
| public: |
| IRGenDebugInfo(const IRGenOptions &Opts, ClangImporter &CI, IRGenModule &IGM, |
| llvm::Module &M, SourceFile *SF); |
| |
| /// Finalize the llvm::DIBuilder owned by this object. |
| void finalize(); |
| |
| /// Update the IRBuilder's current debug location to the location |
| /// Loc and the lexical scope DS. |
| void setCurrentLoc(IRBuilder &Builder, const SILDebugScope *DS, |
| Optional<SILLocation> Loc = None); |
| |
| void clearLoc(IRBuilder &Builder) { |
| LastDebugLoc = {}; |
| LastScope = nullptr; |
| Builder.SetCurrentDebugLocation(llvm::DebugLoc()); |
| } |
| |
| /// Push the current debug location onto a stack and initialize the |
| /// IRBuilder to an empty location. |
| void pushLoc() { |
| LocationStack.push_back(std::make_pair(LastDebugLoc, LastScope)); |
| LastDebugLoc = {}; |
| LastScope = nullptr; |
| } |
| |
| /// Restore the current debug location from the stack. |
| void popLoc() { |
| std::tie(LastDebugLoc, LastScope) = LocationStack.pop_back_val(); |
| } |
| |
| /// Emit the final line 0 location for the unified trap block at the |
| /// end of the function. |
| void setArtificialTrapLocation(IRBuilder &Builder, const SILDebugScope *Scope) { |
| auto DL = llvm::DebugLoc::get(0, 0, getOrCreateScope(Scope)); |
| Builder.SetCurrentDebugLocation(DL); |
| } |
| |
| /// Emit debug info for an import declaration. |
| void emitImport(ImportDecl *D); |
| |
| /// Emit debug info for the given function. |
| /// \param DS The parent scope of the function. |
| /// \param Fn The IR representation of the function. |
| /// \param Rep The calling convention of the function. |
| /// \param Ty The signature of the function. |
| llvm::DISubprogram *emitFunction(SILModule &SILMod, const SILDebugScope *DS, |
| llvm::Function *Fn, |
| SILFunctionTypeRepresentation Rep, |
| SILType Ty, DeclContext *DeclCtx = nullptr); |
| |
| /// Emit debug info for a given SIL function. |
| llvm::DISubprogram *emitFunction(SILFunction &SILFn, llvm::Function *Fn); |
| |
| /// Convenience function useful for functions without any source |
| /// location. Internally calls emitFunction, emits a debug |
| /// scope, and finally sets it using setCurrentLoc. |
| inline void emitArtificialFunction(IRGenFunction &IGF, llvm::Function *Fn, |
| SILType SILTy = SILType()) { |
| emitArtificialFunction(*IGF.IGM.SILMod, IGF.Builder, Fn, SILTy); |
| } |
| |
| void emitArtificialFunction(SILModule &SILMod, IRBuilder &Builder, |
| llvm::Function *Fn, SILType SILTy = SILType()); |
| |
| /// Emit a dbg.declare intrinsic at the current insertion point and |
| /// the Builder's current debug location. |
| void emitVariableDeclaration(IRBuilder &Builder, |
| ArrayRef<llvm::Value *> Storage, |
| DebugTypeInfo Ty, const SILDebugScope *DS, |
| StringRef Name, unsigned ArgNo = 0, |
| IndirectionKind = DirectValue, |
| ArtificialKind = RealValue); |
| |
| /// Emit a dbg.declare or dbg.value intrinsic, depending on Storage. |
| void emitDbgIntrinsic(llvm::BasicBlock *BB, llvm::Value *Storage, |
| llvm::DILocalVariable *Var, llvm::DIExpression *Expr, |
| unsigned Line, unsigned Col, llvm::DILocalScope *Scope, |
| const SILDebugScope *DS); |
| |
| /// Create debug metadata for a global variable. |
| void emitGlobalVariableDeclaration(llvm::GlobalValue *Storage, StringRef Name, |
| StringRef LinkageName, |
| DebugTypeInfo DebugType, |
| Optional<SILLocation> Loc); |
| |
| /// Emit debug metadata for type metadata (for generic types). So meta. |
| void emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata, |
| StringRef Name); |
| |
| /// Return the DIBuilder. |
| llvm::DIBuilder &getBuilder() { return DBuilder; } |
| |
| /// Removes the function from the Functions map again. |
| void eraseFunction(llvm::Function *Fn); |
| |
| private: |
| StringRef BumpAllocatedString(const char *Data, size_t Length); |
| StringRef BumpAllocatedString(std::string S); |
| StringRef BumpAllocatedString(StringRef S); |
| |
| llvm::DIType *createType(DebugTypeInfo DbgTy, StringRef MangledName, |
| llvm::DIScope *Scope, llvm::DIFile *File); |
| llvm::DIType *getOrCreateType(DebugTypeInfo DbgTy); |
| llvm::DIScope *getOrCreateScope(const SILDebugScope *DS); |
| llvm::DIScope *getOrCreateContext(DeclContext *DC); |
| llvm::MDNode *createInlinedAt(const SILDebugScope *Scope); |
| |
| llvm::DIFile *getOrCreateFile(const char *Filename); |
| llvm::DIType *getOrCreateDesugaredType(Type Ty, DebugTypeInfo DTI); |
| StringRef getName(const FuncDecl &FD); |
| StringRef getName(SILLocation L); |
| StringRef getMangledName(TypeAliasDecl *Decl); |
| StringRef getMangledName(DebugTypeInfo DTI); |
| llvm::DITypeRefArray createParameterTypes(CanSILFunctionType FnTy, |
| DeclContext *DeclCtx); |
| llvm::DITypeRefArray createParameterTypes(SILType SILTy, |
| DeclContext *DeclCtx); |
| void createParameterType(llvm::SmallVectorImpl<llvm::Metadata *> &Parameters, |
| SILType CanTy, DeclContext *DeclCtx); |
| llvm::DINodeArray getTupleElements(TupleType *TupleTy, llvm::DIScope *Scope, |
| llvm::DIFile *File, unsigned Flags, |
| DeclContext *DeclContext, |
| unsigned &SizeInBits); |
| llvm::DIFile *getFile(llvm::DIScope *Scope); |
| llvm::DIModule *getOrCreateModule(ModuleDecl::ImportedModule M); |
| llvm::DIModule *getOrCreateModule(StringRef Key, llvm::DIScope *Parent, |
| StringRef Name, StringRef IncludePath); |
| llvm::DIScope *getModule(StringRef MangledName); |
| llvm::DINodeArray getStructMembers(NominalTypeDecl *D, Type BaseTy, |
| llvm::DIScope *Scope, llvm::DIFile *File, |
| unsigned Flags, unsigned &SizeInBits); |
| llvm::DICompositeType * |
| createStructType(DebugTypeInfo DbgTy, NominalTypeDecl *Decl, Type BaseTy, |
| llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line, |
| unsigned SizeInBits, unsigned AlignInBits, unsigned Flags, |
| llvm::DIType *DerivedFrom, unsigned RuntimeLang, |
| StringRef UniqueID); |
| llvm::DIDerivedType *createMemberType(DebugTypeInfo DTI, StringRef Name, |
| unsigned &OffsetInBits, |
| llvm::DIScope *Scope, |
| llvm::DIFile *File, unsigned Flags); |
| llvm::DINodeArray getEnumElements(DebugTypeInfo DbgTy, EnumDecl *D, |
| llvm::DIScope *Scope, llvm::DIFile *File, |
| unsigned Flags); |
| llvm::DICompositeType *createEnumType(DebugTypeInfo DbgTy, EnumDecl *Decl, |
| StringRef MangledName, |
| llvm::DIScope *Scope, |
| llvm::DIFile *File, unsigned Line, |
| unsigned Flags); |
| llvm::DIType *createPointerSizedStruct(llvm::DIScope *Scope, StringRef Name, |
| llvm::DIFile *File, unsigned Line, |
| unsigned Flags, StringRef MangledName); |
| llvm::DIType *createPointerSizedStruct(llvm::DIScope *Scope, StringRef Name, |
| llvm::DIType *PointeeTy, |
| llvm::DIFile *File, unsigned Line, |
| unsigned Flags, StringRef MangledName); |
| uint64_t getSizeOfBasicType(DebugTypeInfo DbgTy); |
| TypeAliasDecl *getMetadataType(); |
| }; |
| |
| /// \brief An RAII object that autorestores the debug location. |
| class AutoRestoreLocation { |
| IRGenDebugInfo *DI; |
| public: |
| AutoRestoreLocation(IRGenDebugInfo *DI) : DI(DI) { |
| if (DI) |
| DI->pushLoc(); |
| } |
| |
| /// \brief Autorestore everything back to normal. |
| ~AutoRestoreLocation() { |
| if (DI) |
| DI->popLoc(); |
| } |
| }; |
| |
| /// \brief An RAII object that temporarily switches to |
| /// an artificial debug location that has a valid scope, but no line |
| /// information. This is useful when emitting compiler-generated |
| /// instructions (e.g., ARC-inserted calls to release()) that have no |
| /// source location associated with them. The DWARF specification |
| /// allows the compiler to use the special line number 0 to indicate |
| /// code that cannot be attributed to any source location. |
| class ArtificialLocation : public AutoRestoreLocation { |
| public: |
| /// \brief Set the current location to line 0, but within scope DS. |
| ArtificialLocation(const SILDebugScope *DS, IRGenDebugInfo *DI, |
| IRBuilder &Builder) |
| : AutoRestoreLocation(DI) { |
| if (DI) { |
| auto DL = llvm::DebugLoc::get(0, 0, DI->getOrCreateScope(DS)); |
| Builder.SetCurrentDebugLocation(DL); |
| } |
| } |
| }; |
| |
| /// \brief An RAII object that temporarily switches to an |
| /// empty location. This is how the function prologue is represented. |
| class PrologueLocation : public AutoRestoreLocation { |
| public: |
| /// \brief Set the current location to an empty location. |
| PrologueLocation(IRGenDebugInfo *DI, IRBuilder &Builder) |
| : AutoRestoreLocation(DI) { |
| if (DI) |
| DI->clearLoc(Builder); |
| } |
| }; |
| |
| } // irgen |
| } // swift |
| |
| #endif |