//===--- IRGenDebugInfo.h - Debug Info Support ------------------*- 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 // //===----------------------------------------------------------------------===// // // This file defines IR codegen support for debug information. // //===----------------------------------------------------------------------===// #ifndef SWIFT_IRGEN_DEBUGINFO_H #define SWIFT_IRGEN_DEBUGINFO_H #include "DebugTypeInfo.h" #include "IRBuilder.h" #include "IRGenFunction.h" #include "IRGenModule.h" #include "swift/SIL/SILLocation.h" #include "llvm/IR/DIBuilder.h" #include "llvm/Support/Allocator.h" #include 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 llvm::DenseMap TrackingDIRefMap; enum IndirectionKind : bool { DirectValue = false, IndirectValue = true }; enum ArtificialKind : bool { RealValue = false, ArtificialValue = true }; /// Helper object that keeps track of the current CompileUnit, File, /// LexicalScope, and knows how to translate a \c SILLocation into an /// \c llvm::DebugLoc. class IRGenDebugInfo { friend class ArtificialLocation; const IRGenOptions &Opts; ClangImporter &CI; SourceManager &SM; llvm::Module &M; llvm::DIBuilder DBuilder; IRGenModule &IGM; /// Used for caching SILDebugScopes without inline information. typedef std::pair LocalScopeHash; struct LocalScope : public LocalScopeHash { LocalScope(const SILDebugScope *DS) : LocalScopeHash({DS->Loc.getOpaquePointerValue(), DS->Parent.getOpaqueValue()}) {} }; /// Various caches. /// @{ llvm::DenseMap ScopeCache; llvm::DenseMap InlinedAtCache; llvm::DenseMap DIFileCache; llvm::DenseMap DebugLocCache; llvm::DenseMap DITypeCache; llvm::StringMap DIModuleCache; TrackingDIRefMap DIRefMap; /// @} /// A list of replaceable fwddecls that need to be RAUWed at the end. std::vector> ReplaceMap; 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::DIScope *EntryPointFn = nullptr; /// Scope of SWIFT_ENTRY_POINT_FUNCTION. TypeAliasDecl *MetadataTypeDecl; /// The type decl for swift.type. llvm::DIType *InternalType; /// Catch-all type for opaque internal types. SILLocation::DebugLoc LastDebugLoc; /// The last location that was emitted. const SILDebugScope *LastScope; /// The scope of that last location. #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, 8> LocationStack; 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 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); } /// Set the location for SWIFT_ENTRY_POINT_FUNCTION. void setEntryPointLoc(IRBuilder &Builder); /// Return the scope for SWIFT_ENTRY_POINT_FUNCTION. llvm::DIScope *getEntryPointFn(); /// Emit debug info for an import declaration. /// /// The DWARF output for import decls is similar to that of a using /// directive in C++: /// import Foundation /// --> /// 0: DW_TAG_imported_module /// DW_AT_import(*1) /// 1: DW_TAG_module // instead of DW_TAG_namespace. /// DW_AT_name("Foundation") /// 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(const SILDebugScope *DS, llvm::Function *Fn, SILFunctionTypeRepresentation Rep, SILType Ty, DeclContext *DeclCtx = nullptr, GenericEnvironment *GE = 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.Builder, Fn, SILTy); } void emitArtificialFunction(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 Storage, DebugTypeInfo Ty, const SILDebugScope *DS, ValueDecl *VarDecl, StringRef Name, unsigned ArgNo = 0, IndirectionKind = DirectValue, ArtificialKind = RealValue); /// Emit a dbg.declare or dbg.value intrinsic, depending on Storage. void emitDbgIntrinsic(IRBuilder &Builder, 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::GlobalVariable *Storage, StringRef Name, StringRef LinkageName, DebugTypeInfo DebugType, bool IsLocalToUnit, Optional 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; } /// Decode (and cache) a SourceLoc. SILLocation::DebugLoc decodeSourceLoc(SourceLoc SL); private: /// Decode (and cache) a SILLocation. SILLocation::DebugLoc decodeDebugLoc(SILLocation Loc); /// Return the debug location from a SILLocation. SILLocation::DebugLoc getDebugLocation(Optional OptLoc); /// Return the start of the location's source range. SILLocation::DebugLoc getStartLocation(Optional OptLoc); StringRef BumpAllocatedString(const char *Data, size_t Length); StringRef BumpAllocatedString(std::string S); StringRef BumpAllocatedString(StringRef S); /// Construct a DIType from a DebugTypeInfo object. /// /// At this point we do not plan to emit full DWARF for all swift /// types, the goal is to emit only the name and provenance of the /// type, where possible. A can import the type definition directly /// from the module/framework/source file the type is specified in. /// For this reason we emit the fully qualified (=mangled) name for /// each type whenever possible. /// /// The ultimate goal is to emit something like a /// DW_TAG_APPLE_ast_ref_type (an external reference) instead of a /// local reference to the type. llvm::DIType *createType(DebugTypeInfo DbgTy, StringRef MangledName, llvm::DIScope *Scope, llvm::DIFile *File); /// Get a previously created type from the cache. llvm::DIType *getTypeOrNull(TypeBase *Ty); /// Get the DIType corresponding to this DebugTypeInfo from the cache, /// or build a fresh DIType otherwise. There is the underlying /// assumption that no two types that share the same canonical type /// can have different storage size or alignment. llvm::DIType *getOrCreateType(DebugTypeInfo DbgTy); /// Translate a SILDebugScope into an llvm::DIDescriptor. llvm::DIScope *getOrCreateScope(const SILDebugScope *DS); /// Build the context chain for a given DeclContext. llvm::DIScope *getOrCreateContext(DeclContext *DC); /// Construct an LLVM inlined-at location from a SILDebugScope, /// reversing the order in the process. llvm::MDNode *createInlinedAt(const SILDebugScope *CallSite); /// Translate filenames into DIFiles. llvm::DIFile *getOrCreateFile(StringRef Filename); /// Return a DIType for Ty reusing any DeclContext found in DbgTy. llvm::DIType *getOrCreateDesugaredType(Type Ty, DebugTypeInfo DbgTy); /// Attempt to figure out the unmangled name of a function. StringRef getName(const FuncDecl &FD); /// Attempt to figure out the unmangled name of a function. StringRef getName(SILLocation L); StringRef getMangledName(TypeAliasDecl *Decl); /// Return the mangled name of any nominal type, including the global /// _Tt prefix, which marks the Swift namespace for types in DWARF. StringRef getMangledName(DebugTypeInfo DbgTy); /// Create the array of function parameters for a function type. llvm::DITypeRefArray createParameterTypes(CanSILFunctionType FnTy, DeclContext *DeclCtx, GenericEnvironment *GE); /// Create the array of function parameters for FnTy. SIL Version. llvm::DITypeRefArray createParameterTypes(SILType SILTy, DeclContext *DeclCtx, GenericEnvironment *GE); /// Create a single parameter type and push it. void createParameterType(llvm::SmallVectorImpl &Parameters, SILType CanTy, DeclContext *DeclCtx, GenericEnvironment *GE); /// Return an array with the DITypes for each of a tuple's elements. llvm::DINodeArray getTupleElements(TupleType *TupleTy, llvm::DIScope *Scope, llvm::DIFile *File, llvm::DINode::DIFlags Flags, DeclContext *DeclContext, GenericEnvironment *GE, unsigned &SizeInBits); llvm::DIFile *getFile(llvm::DIScope *Scope); llvm::DIModule *getOrCreateModule(ModuleDecl::ImportedModule M); /// Return a cached module for an access path or create a new one. llvm::DIModule *getOrCreateModule(StringRef Key, llvm::DIScope *Parent, StringRef Name, StringRef IncludePath); llvm::DIScope *getModule(StringRef MangledName); /// Return an array with the DITypes for each of a struct's elements. llvm::DINodeArray getStructMembers(NominalTypeDecl *D, Type BaseTy, llvm::DIScope *Scope, llvm::DIFile *File, llvm::DINode::DIFlags Flags, unsigned &SizeInBits); /// Create a temporary forward declaration for a struct and add it to /// the type cache so we can safely build recursive types. llvm::DICompositeType * createStructType(DebugTypeInfo DbgTy, NominalTypeDecl *Decl, Type BaseTy, llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line, unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags, llvm::DIType *DerivedFrom, unsigned RuntimeLang, StringRef UniqueID); /// Create a member of a struct, class, tuple, or enum. llvm::DIDerivedType *createMemberType(DebugTypeInfo DbgTy, StringRef Name, unsigned &OffsetInBits, llvm::DIScope *Scope, llvm::DIFile *File, llvm::DINode::DIFlags Flags); /// Return an array with the DITypes for each of an enum's elements. llvm::DINodeArray getEnumElements(DebugTypeInfo DbgTy, EnumDecl *D, llvm::DIScope *Scope, llvm::DIFile *File, llvm::DINode::DIFlags Flags); /// Create a temporary forward declaration for an enum and add it to /// the type cache so we can safely build recursive types. llvm::DICompositeType *createEnumType(DebugTypeInfo DbgTy, EnumDecl *Decl, StringRef MangledName, llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line, llvm::DINode::DIFlags Flags); /// Convenience function that creates a forward declaration for PointeeTy. llvm::DIType *createPointerSizedStruct(llvm::DIScope *Scope, StringRef Name, llvm::DIFile *File, unsigned Line, llvm::DINode::DIFlags Flags, StringRef MangledName); /// Create a pointer-sized struct with a mangled name and a single /// member of PointeeTy. llvm::DIType *createPointerSizedStruct(llvm::DIScope *Scope, StringRef Name, llvm::DIType *PointeeTy, llvm::DIFile *File, unsigned Line, llvm::DINode::DIFlags Flags, StringRef MangledName); /// Create a 2*pointer-sized struct with a mangled name and a single /// member of PointeeTy. llvm::DIType *createDoublePointerSizedStruct( llvm::DIScope *Scope, StringRef Name, llvm::DIType *PointeeTy, llvm::DIFile *File, unsigned Line, llvm::DINode::DIFlags Flags, StringRef MangledName); /// Create DWARF debug info for a function pointer type. llvm::DIType *createFunctionPointer(DebugTypeInfo DbgTy, llvm::DIScope *Scope, unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags, StringRef MangledName); /// Create DWARF debug info for a tuple type. llvm::DIType *createTuple(DebugTypeInfo DbgTy, llvm::DIScope *Scope, unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags, StringRef MangledName); /// Create an opaque struct with a mangled name. llvm::DIType *createOpaqueStruct(llvm::DIScope *Scope, StringRef Name, llvm::DIFile *File, unsigned Line, unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags, StringRef MangledName); uint64_t getSizeOfBasicType(DebugTypeInfo DbgTy); TypeAliasDecl *getMetadataType(); }; /// An RAII object that autorestores the debug location. class AutoRestoreLocation { IRGenDebugInfo *DI; IRBuilder &Builder; llvm::DebugLoc SavedLocation; public: AutoRestoreLocation(IRGenDebugInfo *DI, IRBuilder &Builder) : DI(DI), Builder(Builder) { if (DI) SavedLocation = Builder.getCurrentDebugLocation(); } /// Autorestore everything back to normal. ~AutoRestoreLocation() { if (DI) Builder.SetCurrentDebugLocation(SavedLocation); } }; /// 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: /// Set the current location to line 0, but within scope DS. ArtificialLocation(const SILDebugScope *DS, IRGenDebugInfo *DI, IRBuilder &Builder) : AutoRestoreLocation(DI, Builder) { if (DI) { auto DL = llvm::DebugLoc::get(0, 0, DI->getOrCreateScope(DS)); Builder.SetCurrentDebugLocation(DL); } } }; /// An RAII object that temporarily switches to an empty /// location. This is how the function prologue is represented. class PrologueLocation : public AutoRestoreLocation { public: /// Set the current location to an empty location. PrologueLocation(IRGenDebugInfo *DI, IRBuilder &Builder) : AutoRestoreLocation(DI, Builder) { if (DI) DI->clearLoc(Builder); } }; } // irgen } // swift #endif