//===--- 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 "swift/SIL/SILDebugScope.h" #include "DebugTypeInfo.h" #include "IRBuilder.h" #include "IRGenFunction.h" #include "IRGenModule.h" #include "GenType.h" #include 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 { SILLocation::DebugLoc LocForLinetable, Loc; } FullLocation; typedef llvm::DenseMap 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 /// 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 ScopeCache; llvm::DenseMap DIFileCache; llvm::DenseMap DITypeCache; llvm::StringMap DIModuleCache; TrackingDIRefMap DIRefMap; llvm::SmallPtrSet 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. SILLocation::DebugLoc 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, 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); } /// 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 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 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 *CallSite); 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 &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(); }; /// 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