blob: 2d72b9788d3c1c627c30b27993308e5b32d7a900 [file] [log] [blame]
//===--- 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 <set>
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<const llvm::MDString *, llvm::TrackingMDNodeRef>
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<const void *, void *> LocalScopeHash;
struct LocalScope : public LocalScopeHash {
LocalScope(const SILDebugScope *DS)
: LocalScopeHash({DS->Loc.getOpaquePointerValue(),
DS->Parent.getOpaqueValue()}) {}
};
/// Various caches.
/// @{
llvm::DenseMap<LocalScopeHash, llvm::TrackingMDNodeRef> ScopeCache;
llvm::DenseMap<const SILDebugScope *, llvm::TrackingMDNodeRef> InlinedAtCache;
llvm::DenseMap<llvm::StringRef, llvm::TrackingMDNodeRef> DIFileCache;
llvm::DenseMap<const void *, SILLocation::DebugLoc> DebugLocCache;
llvm::DenseMap<TypeBase *, llvm::TrackingMDNodeRef> DITypeCache;
llvm::StringMap<llvm::TrackingMDNodeRef> DIModuleCache;
TrackingDIRefMap DIRefMap;
/// @}
/// A list of replaceable fwddecls that need to be RAUWed at the end.
std::vector<std::pair<TypeBase *, llvm::TrackingMDRef>> 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<std::pair<SILLocation::DebugLoc, const SILDebugScope *>, 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<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);
}
/// 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<llvm::Value *> 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<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; }
/// 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<SILLocation> OptLoc);
/// Return the start of the location's source range.
SILLocation::DebugLoc getStartLocation(Optional<SILLocation> 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<llvm::Metadata *> &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