blob: 177b85a6b21e9ba67cb87268c89c153077de2e31 [file] [log] [blame]
//===--- 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