mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
327 lines
13 KiB
C++
327 lines
13 KiB
C++
//===--- 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 <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 { SILLocation::DebugLoc 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.
|
|
|
|
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<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);
|
|
}
|
|
|
|
/// 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 *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<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();
|
|
};
|
|
|
|
/// 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
|