Files
swift-mirror/lib/IRGen/IRGenDebugInfo.cpp
2013-08-08 21:20:07 +00:00

988 lines
36 KiB
C++

//===--- IRGenDebugInfo.h - Debug Info Support-----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 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 implements IR debug info generatio for Swift.
//
//===----------------------------------------------------------------------===//
#include "IRGenDebugInfo.h"
#include "GenType.h"
#include "Linking.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
#include "llvm/DebugInfo.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Module.h"
#include "swift/AST/ModuleLoader.h"
#include "swift/AST/Pattern.h"
#include "swift/Basic/Punycode.h"
#include "swift/Basic/SourceManager.h"
#include "swift/IRGen/Options.h"
#include "swift/SIL/Mangle.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILModule.h"
using namespace swift;
using namespace irgen;
//===--- BEGIN "TO BE FIXED IN A SWIFT BRANCH OF LLVM" ---===//
//
// DWARF constants.
//
// The first unused language value in DWARF v5 is DW_LANG_Haskell+1 =
// 0x19. We can't use it, because LLVM asserts that there are no
// languages >DW_LANG_Python=0x14. Wouldn't it would be much more
// appropriate to use a constant in DW_LANG_lo_user..DW_LANG_hi_user
// anyway, you may ask? Well, CompileUnit::constructTypeDIE() will
// always use a DW_FORM_data1, which is too small for that range! And
// by fixing that in LLVM we would hint at developing a new language.
// So instead, let's hijack a language with a very low potential for
// accidental conflicts for now.
static const unsigned DW_LANG_Swift = 0xf;
static const unsigned DW_LANG_ObjC = llvm::dwarf::DW_LANG_ObjC; // For symmetry.
//
// Reuse some existing tag so the verifier doesn't complain.
static const unsigned DW_TAG_meta_type = llvm::dwarf::DW_TAG_restrict_type;
//
//===--------- END "TO BE FIXED IN A SWIFT BRANCH OF LLVM" --------===//
/// Strdup a raw char array using the bump pointer.
static
StringRef BumpAllocatedString(const char* Data, size_t Length,
llvm::BumpPtrAllocator &BP) {
char *Ptr = BP.Allocate<char>(Length);
memcpy(Ptr, Data, Length);
return StringRef(Ptr, Length);
}
/// Strdup S using the bump pointer.
static
StringRef BumpAllocatedString(std::string S, llvm::BumpPtrAllocator &BP) {
return BumpAllocatedString(S.c_str(), S.length(), BP);
}
/// Strdup StringRef S using the bump pointer.
static
StringRef BumpAllocatedString(StringRef S, llvm::BumpPtrAllocator &BP) {
return BumpAllocatedString(S.data(), S.size(), BP);
}
IRGenDebugInfo::IRGenDebugInfo(const Options &Opts,
const clang::TargetInfo &TargetInfo,
TypeConverter &Types,
SourceManager &SM,
llvm::Module &M)
: Opts(Opts), TargetInfo(TargetInfo), SM(SM), DBuilder(M), Types(Types),
LastFn(nullptr), LastLoc({}), LastScope(nullptr) {
assert(Opts.DebugInfo);
StringRef Dir, Filename;
StringRef MainFilename = Opts.MainInputFilename;
if (MainFilename.empty()) {
Filename = "<unknown>";
Dir = getCurrentDirname();
} else {
// Separate path and filename.
Filename = BumpAllocatedString(llvm::sys::path::filename(MainFilename),
DebugInfoNames);
llvm::SmallString<512> Path(MainFilename);
llvm::sys::path::remove_filename(Path);
llvm::sys::fs::make_absolute(Path);
Dir = BumpAllocatedString(Path, DebugInfoNames);
}
// The fallback file.
llvm::SmallString<512> MainFileBuf(Dir);
llvm::sys::path::append(MainFileBuf, Filename);
MainFile = getOrCreateFile(MainFileBuf.c_str());
unsigned Lang = DW_LANG_Swift;
std::string buf;
llvm::raw_string_ostream OS(buf);
OS << "Swift version ? (based on LLVM " << PACKAGE_VERSION << ")";
StringRef Producer = BumpAllocatedString(OS.str(), DebugInfoNames);
bool IsOptimized = Opts.OptLevel > 0;
StringRef Flags = Opts.DWARFDebugFlags;
// FIXME.
unsigned RuntimeVersion = 1;
// FIXME.
StringRef SplitName = StringRef();
TheCU = DBuilder.createCompileUnit(Lang, Filename, Dir, Producer,
IsOptimized, Flags, RuntimeVersion,
SplitName);
}
void IRGenDebugInfo::finalize() {
assert(LocationStack.empty() && "Mismatch of pushLoc() and popLoc().");
// The default for a function is to be in the file-level scope.
for (auto FVH: Functions) {
auto F = llvm::DISubprogram(cast<llvm::MDNode>(FVH.second));
auto Scope = F.getContext();
if (Scope.isType() && llvm::DIType(Scope).isForwardDecl())
Scope->replaceAllUsesWith(MainFile);
}
DBuilder.finalize();
}
Location getDeserializedLoc(Pattern*) { return {}; }
Location getDeserializedLoc(Expr*) { return {}; }
Location getDeserializedLoc(Stmt*) { return {}; }
Location getDeserializedLoc(Decl* D) {
Location L = {};
if (auto LM = dyn_cast<LoadedModule>(D->getModuleContext())) {
L.Filename = LM->getDebugModuleName();
L.Line = 1;
}
return L;
}
/// Use the SM to figure out the actual line/column of a SourceLoc.
template<typename WithLoc>
Location getStartLoc(SourceManager &SM, WithLoc *S) {
Location L = {};
if (S == nullptr) return L;
SourceLoc Start = S->getStartLoc();
int BufferIndex = SM->FindBufferContainingLoc(Start.Value);
if (BufferIndex == -1)
// This may be a deserialized or clang-imported decl. And modules
// don't come with SourceLocs right now. Get at least the name of
// the module.
return getDeserializedLoc(S);
L.Filename = SM->getMemoryBuffer((unsigned)BufferIndex)->getBufferIdentifier();
std::tie(L.Line, L.Col) = SM->getLineAndColumn(Start.Value, BufferIndex);
return L;
}
/// getStartLoc - extract the start location from a SILLocation.
static Location getStartLoc(SourceManager &SM, SILLocation Loc) {
if (Expr* E = Loc.getAs<Expr>()) return getStartLoc(SM, E);
if (Stmt* S = Loc.getAs<Stmt>()) return getStartLoc(SM, S);
if (Decl* D = Loc.getAs<Decl>()) return getStartLoc(SM, D);
if (Pattern* P = Loc.getAs<Pattern>()) return getStartLoc(SM, P);
Location None = {};
return None;
}
/// getStartLocForLinetable - extract the start location from a SILLocation.
static Location getStartLocForLinetable(SourceManager &SM, SILLocation Loc) {
if (Expr* E = Loc.getAs<Expr>()) {
// Implicit closures should not show up in the line table. Note
// that the closure function still has a valid DW_AT_decl_line.
if (E->getKind() == ExprKind::ImplicitClosure)
return {};
return getStartLoc(SM, E);
}
if (Stmt* S = Loc.getAs<Stmt>()) return getStartLoc(SM, S);
if (Decl* D = Loc.getAs<Decl>()) return getStartLoc(SM, D);
if (Pattern* P = Loc.getAs<Pattern>()) return getStartLoc(SM, P);
Location None = {};
return None;
}
/// Determine whether this debug scope belongs to a pipe closure.
static bool isPipeClosure(SILDebugScope *DS) {
if (DS)
if (Expr* E = DS->Loc.getAs<Expr>())
if (E->getKind() == ExprKind::PipeClosure)
return true;
return false;
}
void IRGenDebugInfo::setCurrentLoc(IRBuilder& Builder,
SILDebugScope *DS,
SILLocation Loc) {
Location L = getStartLocForLinetable(SM, Loc);
llvm::DIDescriptor Scope = getOrCreateScope(DS);
if (!Scope.Verify()) return;
if (L.Filename && L.Filename != getStartLoc(SM, DS->Loc).Filename) {
// We changed files in the middle of a scope. This happens, for
// example, when constructors are inlined. Create a new scope to
// reflect this.
Scope = DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(L.Filename));
}
if (L.Line == 0 && DS == LastScope) {
// Reuse the last source location if we are still in the same
// scope to get a more contiguous line table.
L.Line = LastLoc.Line;
L.Col = LastLoc.Col;
}
LastLoc = L;
LastScope = DS;
llvm::MDNode *InlinedAt = 0;
auto DL = llvm::DebugLoc::get(L.Line, L.Col, Scope, InlinedAt);
// TODO: Write a strongly-worded letter to the person that came up
// with a pair of functions spelled "get" and "Set".
Builder.SetCurrentDebugLocation(DL);
}
/// getOrCreateScope - Translate a SILDebugScope into an llvm::DIDescriptor.
llvm::DIDescriptor IRGenDebugInfo::getOrCreateScope(SILDebugScope *DS) {
if (DS == 0)
return MainFile;
// Try to find it in the cache first.
auto CachedScope = ScopeCache.find(DS);
if (CachedScope != ScopeCache.end()) {
return llvm::DIDescriptor(cast<llvm::MDNode>(CachedScope->second));
}
Location L = getStartLoc(SM, DS->Loc);
llvm::DIFile File = getOrCreateFile(L.Filename);
llvm::DIDescriptor Parent = getOrCreateScope(DS->Parent);
if (Parent == 0)
Parent = File;
llvm::DILexicalBlock DScope =
DBuilder.createLexicalBlock(Parent, File, L.Line, L.Col);
// Cache it.
ScopeCache[DS] = llvm::WeakVH(DScope);
return DScope;
}
/// getCurrentDirname - Return the current working directory.
StringRef IRGenDebugInfo::getCurrentDirname() {
// FIXME: Clang has a global option to set the compilation
// directory. Do we have something similar for swift?
if (!CWDName.empty())
return CWDName;
llvm::SmallString<256> CWD;
llvm::sys::fs::current_path(CWD);
return BumpAllocatedString(CWD.str(), DebugInfoNames);
}
/// getOrCreateFile - Translate filenames into DIFiles.
llvm::DIFile IRGenDebugInfo::getOrCreateFile(const char *Filename) {
if (!Filename)
return MainFile;
// Look in the cache first.
auto CachedFile = DIFileCache.find(Filename);
if (CachedFile != DIFileCache.end()) {
// Verify that the information still exists.
if (llvm::Value *V = CachedFile->second)
return llvm::DIFile(cast<llvm::MDNode>(V));
}
// Create a new one.
StringRef File = BumpAllocatedString(llvm::sys::path::filename(Filename),
DebugInfoNames);
llvm::SmallString<512> Path(Filename);
llvm::sys::path::remove_filename(Path);
llvm::error_code ec = llvm::sys::fs::make_absolute(Path);
// Basically ignore any error.
assert(ec == llvm::errc::success);
(void)ec; // Silence the unused variable warning
llvm::DIFile F =
DBuilder.createFile(File, BumpAllocatedString(Path, DebugInfoNames));
// Cache it.
DIFileCache[Filename] = llvm::WeakVH(F);
return F;
}
/// Attempt to figure out the unmangled name of a function.
StringRef IRGenDebugInfo::getName(const FuncDecl& FD) {
// Getters and Setters are anonymous functions, so we forge a name
// using its parent declaration.
if (FD.isGetterOrSetter())
if (Decl* D = FD.getGetterOrSetterDecl()) {
if (ValueDecl* VD = dyn_cast<ValueDecl>(D)) {
bool IsGetter = FD.getGetterDecl();
llvm::SmallVector<char, 64> Buf;
StringRef Name = (VD->getName().str() +
Twine(IsGetter ? ".get" : ".set")).toStringRef(Buf);
return BumpAllocatedString(Name, DebugInfoNames);
}
}
if (!FD.getName().empty())
return FD.getName().str();
return StringRef();
}
/// Attempt to figure out the unmangled name of a function.
StringRef IRGenDebugInfo::getName(SILLocation L) {
if (L.isNull())
return StringRef();
if (FuncExpr* FE = L.getAs<FuncExpr>())
if (FuncDecl* FD = FE->getDecl())
return getName(*FD);
if (FuncDecl* FD = L.getAs<FuncDecl>())
return getName(*FD);
if (L.is<ConstructorDecl>())
return "constructor";
return StringRef();
}
static AnyFunctionType* getFunctionType(SILType SILTy) {
TypeBase* Ty = SILTy.getSwiftType().getPointer();
if (!Ty)
return nullptr;
auto FnTy = dyn_cast<AnyFunctionType>(Ty);
if (!FnTy) {
DEBUG(llvm::dbgs() << "Unexpected function type: "; SILTy.dump();
llvm::dbgs() << "\n");
return nullptr;
}
return FnTy;
}
/// Create the array of function parameters for FnTy.
llvm::DIArray IRGenDebugInfo::createParameterTypes(SILModule &SILMod,
SILType SILTy,
llvm::FunctionType *IRTy,
llvm::DIDescriptor Scope) {
if (!SILTy.getSwiftType())
return llvm::DIArray();
SILFunctionTypeInfo *TypeInfo = SILTy.getFunctionTypeInfo(SILMod);
if (!TypeInfo) return llvm::DIArray();
llvm::SmallVector<llvm::Value *, 16> Parameters;
// Actually, the input type is either a single type or a tuple
// type. We currently represent a function with one n-tuple argument
// as an n-ary function.
unsigned I = 0;
for (auto Param : TypeInfo->getInputTypes()) {
CanType CTy = Param.getSwiftType();
DebugTypeInfo DTy(CTy, Types.getCompleteTypeInfo(CTy));
Parameters.push_back(getOrCreateType(DTy, Scope));
++I;
}
return DBuilder.getOrCreateArray(Parameters);
}
void IRGenDebugInfo::emitFunction(SILModule &SILMod, SILDebugScope *DS,
llvm::Function *Fn,
AbstractCC CC, SILType SILTy) {
StringRef Name;
Location L = {};
if (DS) {
L = getStartLoc(SM, DS->Loc);
Name = getName(DS->Loc);
}
assert(Fn);
auto LinkageName = Fn->getName();
auto File = getOrCreateFile(L.Filename);
// This placeholder scope gets RAUW'd when the namespaces are
// created after we are finished with the entire translation unit.
auto Scope = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_subroutine_type,
LinkageName, MainFile, MainFile, 0);
auto Line = L.Line;
// This is the source line used for the function prologue.
unsigned ScopeLine = 0;
AnyFunctionType* FnTy = getFunctionType(SILTy);
auto Params = createParameterTypes(SILMod, SILTy, Fn->getFunctionType(),
Scope);
llvm::DICompositeType DIFnTy = DBuilder.createSubroutineType(File, Params);
llvm::DIArray TemplateParameters;
llvm::DISubprogram Decl;
// Various flags
bool IsLocalToUnit = false;
bool IsDefinition = true;
bool IsOptimized = Opts.OptLevel > 0;
unsigned Flags = 0;
// Mark everything that is not visible from the source code (i.e.,
// does not have a Swift name) as artificial, so the debugger can
// ignore it. Explicit closures are exempt from this rule. We also
// make an exception for top_level_code, which albeit it does not
// have a Swift name, it does appear prominently in the source code.
if (Name.empty() && LinkageName != "top_level_code" && !isPipeClosure(DS))
Flags |= llvm::DIDescriptor::FlagArtificial;
if (FnTy && FnTy->isBlock())
Flags |= llvm::DIDescriptor::FlagAppleBlock;
switch (CC) {
// FIXME: We need to invent new DWARF attributes for the CC, but we
// can't do that without patching the LLVM backend.
// Hijacking a completely different field for now.
case AbstractCC::C:
case AbstractCC::ObjCMethod:
IsLocalToUnit = true;
break;
case AbstractCC::Method:
case AbstractCC::Freestanding:
IsLocalToUnit = false;
}
llvm::DISubprogram SP =
DBuilder.createFunction(Scope, Name, LinkageName, File, Line,
DIFnTy, IsLocalToUnit, IsDefinition,
ScopeLine,
Flags, IsOptimized, Fn, TemplateParameters, Decl);
ScopeCache[DS] = llvm::WeakVH(SP);
Functions[LinkageName] = llvm::WeakVH(SP);
}
static bool isNonAscii(StringRef str) {
for (unsigned char c : str) {
if (c >= 0x80)
return true;
}
return false;
}
// Mangle a single non-operator identifier.
static void mangleIdent(llvm::raw_string_ostream &OS, StringRef Id) {
// If the identifier contains non-ASCII character, we mangle with an initial
// X and Punycode the identifier string.
llvm::SmallString<32> PunycodeBuf;
if (isNonAscii(Id)) {
OS << 'X';
Punycode::encodePunycode(Id, PunycodeBuf);
Id = PunycodeBuf;
}
OS << Id.size() << Id;
OS.flush();
return;
}
void IRGenDebugInfo::emitImport(ImportDecl *D) {
// Imports are visited after SILFunctions.
llvm::DIScope Namespace = MainFile;
std::string Printed, Mangled("_T");
{
llvm::raw_string_ostream MS(Mangled), PS(Printed);
bool first = true;
for (auto elt : D->getModulePath()) {
if (first) first = false;
else PS << '.';
auto Component = elt.first.str();
PS << Component;
// We model each component of the access path as a namespace.
mangleIdent(MS, Component);
Namespace = getOrCreateNamespace(Namespace, Component, MainFile, 1);
}
}
// Create the imported module.
StringRef Name = BumpAllocatedString(Printed, DebugInfoNames);
Location L = getStartLoc(SM, D);
auto Import = DBuilder.createImportedModule(TheCU,
llvm::DINameSpace(Namespace),
L.Line, Name);
// Add all functions that belong to this namespace to it.
//
// TODO: Since we have the mangled names anyway, this part is purely
// cosmetic and we may consider removing it.
for (auto F = Functions.lower_bound(Mangled); F != Functions.end(); ++F) {
if (Mangled != F->first.substr(0, Mangled.length()))
break;
auto SP = llvm::DISubprogram(cast<llvm::MDNode>(F->second));
// RAUW the context of the function with the namespace.
auto Scope = SP.getContext();
if (Scope.isType() && llvm::DIType(Scope).isForwardDecl())
Scope->replaceAllUsesWith(Namespace);
auto ImportedDecl =
DBuilder.createImportedDeclaration(llvm::DIScope(Import), SP, L.Line);
SP->replaceAllUsesWith(ImportedDecl);
}
}
/// Return a cached namespace for a mangled access path or create a new one.
llvm::DIScope IRGenDebugInfo::getOrCreateNamespace(llvm::DIScope Namespace,
std::string MangledName,
llvm::DIFile File,
unsigned Line) {
// Look in the cache first.
auto CachedNS = DINameSpaceCache.find(MangledName);
if (CachedNS != DINameSpaceCache.end())
// Verify that the information still exists.
if (llvm::Value *Val = CachedNS->second)
return llvm::DINameSpace(cast<llvm::MDNode>(Val));
auto NS = DBuilder.createNameSpace(Namespace, MangledName, MainFile, Line);
DINameSpaceCache[MangledName] = llvm::WeakVH(NS);
return NS;
}
void IRGenDebugInfo::emitFunction(SILFunction *SILFn, llvm::Function *Fn) {
emitFunction(SILFn->getModule(),
SILFn->getDebugScope(), Fn,
SILFn->getAbstractCC(),
SILFn->getLoweredType());
}
void IRGenDebugInfo::emitArtificialFunction(SILModule &SILMod,
IRBuilder &Builder,
llvm::Function *Fn) {
SILDebugScope *Scope = new (SILMod) SILDebugScope();
emitFunction(SILMod, Scope, Fn, AbstractCC::Freestanding, SILType());
setCurrentLoc(Builder, Scope);
}
/// Return the position of Arg in Fn's signature, counting from 1.
unsigned IRGenDebugInfo::getArgNo(SILFunction *Fn, SILArgument *Arg) {
// Based on the assumption that arguments will appear in order in the
// instruction stream, make one attempt to reuse the last iterator.
// LastFn also acts as a sentinel for LastArg/End.
if (Fn == LastFn) {
++LastArg; ++LastArgNo;
if (LastArg != LastEnd && *LastArg == Arg)
return LastArgNo;
}
// Otherwise perform a linear scan through all the arguments.
LastArgNo = 1;
if (!Fn->empty()) {
const SILBasicBlock &FirstBB = Fn->front();
LastArg = FirstBB.bbarg_begin();
LastEnd = FirstBB.bbarg_end();
LastFn = Fn;
while (LastArg != LastEnd) {
if (*LastArg == Arg)
return LastArgNo;
++LastArg; ++LastArgNo;
}
}
DEBUG(llvm::dbgs() << "Failed to find argument number for ";
Arg->dump(); llvm::dbgs() << "\nIn:"; Fn->dump());
return 0;
}
void IRGenDebugInfo::emitStackVariableDeclaration(IRBuilder& Builder,
llvm::Value *Storage,
DebugTypeInfo Ty,
const llvm::Twine &Name,
AllocStackInst *i) {
// Make a best effort to find out if this variable is actually an
// argument of the current function. This is done by looking at the
// source of the first store to this alloca. Unless we start
// enriching SIL with debug metadata or debug intrinsics, that's the
// best we can do.
for (auto Use : i->getUses())
if (auto Store = dyn_cast<StoreInst>(Use->getUser()))
if (auto SILArg = dyn_cast<SILArgument>(Store->getSrc())) {
assert(i && i->getParent() && i->getParent()->getParent() );
auto Fn = i->getParent()->getParent();
emitArgVariableDeclaration(Builder, Storage, Ty, Name, getArgNo(Fn, SILArg));
return;
}
emitVariableDeclaration(Builder, Storage, Ty, Name,
llvm::dwarf::DW_TAG_auto_variable);
}
void IRGenDebugInfo::emitArgVariableDeclaration(IRBuilder& Builder,
llvm::Value *Storage,
DebugTypeInfo Ty,
const llvm::Twine &Name,
unsigned ArgNo) {
emitVariableDeclaration(Builder, Storage, Ty, Name,
llvm::dwarf::DW_TAG_arg_variable, ArgNo);
}
/// Return the DIFile that is the ancestor of Scope.
llvm::DIFile IRGenDebugInfo::getFile(llvm::DIDescriptor Scope) {
while (!Scope.isFile()) {
switch (Scope.getTag()) {
case llvm::dwarf::DW_TAG_lexical_block:
Scope = llvm::DILexicalBlock(Scope).getContext();
break;
case llvm::dwarf::DW_TAG_subprogram:
Scope = llvm::DISubprogram(Scope).getContext();
break;
default:
return MainFile;
}
if (Scope.Verify())
return MainFile;
}
llvm::DIFile File(Scope);
assert(File.Verify());
return File;
}
void IRGenDebugInfo::emitVariableDeclaration(IRBuilder& Builder,
llvm::Value *Storage,
DebugTypeInfo Ty,
const llvm::Twine &Name,
unsigned Tag,
unsigned ArgNo) {
llvm::DebugLoc DL = Builder.getCurrentDebugLocation();
llvm::DIDescriptor Scope(DL.getScope(Builder.getContext()));
if (!Scope.Verify())
return;
llvm::DIFile Unit = getFile(Scope);
llvm::DIType DTy = getOrCreateType(Ty, Scope);
// If there is no debug info for this type then do not emit debug info
// for this variable.
if (!DTy)
return;
unsigned Line = DL.getLine();
unsigned Flags = 0;
// Create the descriptor for the variable.
llvm::DIVariable D =
DBuilder.createLocalVariable(Tag, Scope, Name.str(), Unit, Line, DTy,
Opts.OptLevel > 0, Flags, ArgNo);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
Call->setDebugLoc(llvm::DebugLoc::get(Line, DL.getCol(), Scope));
}
void IRGenDebugInfo::emitGlobalVariableDeclaration(llvm::GlobalValue *Var,
StringRef Name,
StringRef LinkageName,
DebugTypeInfo DebugType,
SILLocation Loc) {
Location L = getStartLoc(SM, Loc);
llvm::DIFile Unit = getOrCreateFile(L.Filename);
// FIXME: Can there be nested types?
llvm::DIDescriptor DContext = Unit;
DBuilder.createStaticVariable(DContext, Name, LinkageName, Unit,
L.Line, getOrCreateType(DebugType, Unit),
Var->hasInternalLinkage(), Var, nullptr);
}
/// Return the mangled name of any nominal type, including the global
/// _Tt prefix, which marks the Swift namespace for types in DWARF.
StringRef IRGenDebugInfo::getMangledName(CanType CanTy) {
llvm::SmallString<128> Buffer;
LinkEntity::forDebuggerTypeMangling(CanTy).mangle(Buffer);
return BumpAllocatedString(Buffer, DebugInfoNames);
}
/// Return an array with the DITypes for each of a tuple's elements.
llvm::DIArray IRGenDebugInfo::getTupleElements(TupleType *TupleTy,
llvm::DIDescriptor Scope) {
llvm::SmallVector<llvm::Value *, 16> Elements;
for (auto Elem : TupleTy->getElementTypes()) {
CanType CTy = Elem->getCanonicalType();
DebugTypeInfo DTy(CTy, Types.getCompleteTypeInfo(CTy));
Elements.push_back(getOrCreateType(DTy, Scope));
}
return DBuilder.getOrCreateArray(Elements);
}
/// 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 final goal, once we forked LLVM, 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 IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
llvm::DIDescriptor Scope,
llvm::DIFile File) {
StringRef Name;
// FIXME: For SizeInBits, clang uses the actual size of the type on
// the target machine instead of the storage size that is alloca'd
// in the LLVM IR. For all types that are boxed in a struct, we are
// emitting the storage size of the struct, but it may be necessary
// to emit the (target!) size of the underlying basic type.
unsigned SizeOfByte = TargetInfo.getCharWidth();
uint64_t SizeInBits = DbgTy.SizeInBytes * SizeOfByte;
uint64_t AlignInBits = DbgTy.AlignmentInBytes * SizeOfByte;
unsigned Encoding = 0;
unsigned Flags = 0;
TypeBase* BaseTy = DbgTy.Ty.getPointer();
if (!BaseTy) {
DEBUG(llvm::dbgs() << "Type without TypeBase: "; DbgTy.Ty.dump();
llvm::dbgs() << "\n");
Name = "<null>";
return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
Name, Scope, File, /*Line*/ 0,
DW_LANG_Swift, SizeInBits, AlignInBits);
}
switch (BaseTy->getKind()) {
case TypeKind::BuiltinInteger: {
SizeInBits = TargetInfo.getIntWidth();
Name = "_TtSi";
break;
}
case TypeKind::BuiltinFloat: {
SizeInBits = TargetInfo.getFloatWidth();
Name = "_TtSf";
break;
}
case TypeKind::BuiltinObjCPointer: {
// The builtin opaque Objective-C pointer type. Useful for pushing
// an Objective-C type through swift.
auto IdTy = DBuilder.
createStructType(Scope, "objc_object", File, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray(), DW_LANG_ObjC);
return DBuilder.createPointerType(IdTy, SizeInBits, AlignInBits);
}
case TypeKind::BuiltinObjectPointer: {
Name = getMangledName(DbgTy.Ty->getCanonicalType());
auto PTy = DBuilder.createPointerType(llvm::DIType(), SizeInBits, AlignInBits, Name);
return DBuilder.createObjectPointerType(PTy);
}
case TypeKind::BuiltinRawPointer:
Name = getMangledName(DbgTy.Ty->getCanonicalType());
return DBuilder.createPointerType(llvm::DIType(), SizeInBits, AlignInBits, Name);
// Even builtin swift types usually come boxed in a struct.
case TypeKind::Struct: {
auto StructTy = BaseTy->castTo<StructType>();
if (auto Decl = StructTy->getDecl()) {
Location L = getStartLoc(SM, Decl);
Name = getMangledName(DbgTy.Ty->getCanonicalType());
return DBuilder.createStructType(Scope, Name,
getOrCreateFile(L.Filename), L.Line,
SizeInBits, AlignInBits, Flags,
llvm::DIType(), // DerivedFrom
llvm::DIArray(), // Elements
DW_LANG_Swift);
}
DEBUG(llvm::dbgs() << "Struct without Decl: "; DbgTy.Ty.dump();
llvm::dbgs() << "\n");
break;
}
case TypeKind::Class: {
// Classes are represented as DW_TAG_structure_type. This way the
// DW_AT_APPLE_runtime_class( DW_LANG_Swift ) attribute can be
// used to differentiate them from C++ and ObjC classes.
auto ClassTy = BaseTy->castTo<ClassType>();
if (auto Decl = ClassTy->getDecl()) {
Name = getMangledName(DbgTy.Ty->getCanonicalType());
Location L = getStartLoc(SM, Decl);
auto Attrs = Decl->getAttrs();
auto RuntimeLang = Attrs.isObjC() ? DW_LANG_ObjC : DW_LANG_Swift;
return DBuilder.createStructType(Scope, Name,
getOrCreateFile(L.Filename), L.Line,
SizeInBits, AlignInBits, Flags,
llvm::DIType(), // DerivedFrom
llvm::DIArray(), // Elements
RuntimeLang);
}
DEBUG(llvm::dbgs() << "Class without Decl: "; DbgTy.Ty.dump();
llvm::dbgs() << "\n");
break;
}
case TypeKind::Protocol: {
Name = getMangledName(DbgTy.Ty->getCanonicalType());
break;
}
case TypeKind::BoundGenericStruct: {
auto StructTy = BaseTy->castTo<BoundGenericStructType>();
if (auto Decl = StructTy->getDecl()) {
Location L = getStartLoc(SM, Decl);
Name = Decl->getName().str();
return DBuilder.createStructType(Scope, Name,
getOrCreateFile(L.Filename), L.Line,
SizeInBits, AlignInBits, Flags,
llvm::DIType(), // DerivedFrom
llvm::DIArray(), // Elements
DW_LANG_Swift);
}
DEBUG(llvm::dbgs() << "Bound Generic struct without Decl: ";
DbgTy.Ty.dump(); llvm::dbgs() << "\n");
break;
}
case TypeKind::BoundGenericClass: {
auto ClassTy = BaseTy->castTo<BoundGenericClassType>();
if (auto Decl = ClassTy->getDecl()) {
Location L = getStartLoc(SM, Decl);
Name = Decl->getName().str();
auto Attrs = Decl->getAttrs();
auto RuntimeLang = Attrs.isObjC() ? DW_LANG_ObjC : DW_LANG_Swift;
return DBuilder.createStructType(Scope, Name,
getOrCreateFile(L.Filename), L.Line,
SizeInBits, AlignInBits, Flags,
llvm::DIType(), // DerivedFrom
llvm::DIArray(), // Elements
RuntimeLang);
}
DEBUG(llvm::dbgs() << "Bound Generic class without Decl: ";
DbgTy.Ty.dump(); llvm::dbgs() << "\n");
break;
}
case TypeKind::Tuple: {
auto TupleTy = BaseTy->castTo<TupleType>();
// Tuples are represented as structs. In contrast to actual
// structs, we do emit all the element types of a tuple, since
// tuples typiclly don't have any declaration associated with
// them.
Name = "<tuple>";
// We could use the mangled Name instead of emitting the typ, but no:
// FIXME: getMangledName(DbgTy.CanTy) crashes if one of the elements
// is an ArcheType.
return DBuilder.createStructType(Scope, Name,
File, 0,
SizeInBits, AlignInBits, Flags,
llvm::DIType(), // DerivedFrom
getTupleElements(TupleTy, Scope),
DW_LANG_Swift);
}
case TypeKind::LValue: {
// FIXME: handle LValueTy->getQualifiers();
auto LValueTy = BaseTy->castTo<LValueType>();
auto CanTy = LValueTy->getObjectType()->getCanonicalType();
return getOrCreateType(DebugTypeInfo(CanTy, SizeInBits, AlignInBits), Scope);
}
case TypeKind::Archetype: {
// FIXME
auto Archetype = BaseTy->castTo<ArchetypeType>();
Name = Archetype->getName().str();
break;
}
case TypeKind::MetaType: {
// Metatypes are (mostly) singleton type descriptors, often without storage.
auto Metatype = BaseTy->castTo<MetaTypeType>();
auto CanTy = Metatype->getInstanceType()->getCanonicalType();
// The type this metatype is describing.
auto InstanceDTI = DebugTypeInfo(CanTy, SizeInBits, AlignInBits);
return DBuilder.createQualifiedType(DW_TAG_meta_type,
getOrCreateType(InstanceDTI, Scope));
}
case TypeKind::Function: {
// FIXME: auto Function = BaseTy->castTo<AnyFunctionType>();
// FIXME: handle parameters.
auto FnTy = DBuilder.createSubroutineType(getFile(Scope), llvm::DIArray());
return DBuilder.createPointerType(FnTy, SizeInBits, AlignInBits);
}
case TypeKind::Union: {
Name = getMangledName(DbgTy.Ty->getCanonicalType());
break;
}
// Sugared types.
case TypeKind::NameAlias: {
// We cannot use BaseTy->castTo<>(), because it will use the desugared type!
auto NameAliasTy = cast<NameAliasType>(BaseTy);
if (auto Decl = NameAliasTy->getDecl()) {
Name = Decl->getName().str();
Location L = getStartLoc(SM, Decl);
auto AliasedTy = Decl->hasUnderlyingType()
? Decl->getUnderlyingType()
: NameAliasTy->getDesugaredType();
auto CanDTI = DebugTypeInfo(AliasedTy, SizeInBits, AlignInBits);
return DBuilder.createTypedef(getOrCreateType(CanDTI, Scope), Name,
getOrCreateFile(L.Filename), L.Line, Scope);
}
DEBUG(llvm::dbgs() << "Name alias without Decl: ";
DbgTy.Ty.dump(); llvm::dbgs() << "\n");
break;
}
case TypeKind::ArraySlice: {
auto ArraySliceTy = cast<ArraySliceType>(BaseTy);
auto CanTy = ArraySliceTy->getDesugaredType();
auto CanDTI = DebugTypeInfo(CanTy, SizeInBits, AlignInBits);
return getOrCreateType(CanDTI, Scope);
}
default:
DEBUG(llvm::dbgs() << "Unhandled type: "; DbgTy.Ty.dump();
llvm::dbgs() << "\n");
Name = "<unknown>";
}
return DBuilder.createBasicType(Name, SizeInBits, AlignInBits, Encoding);
}
/// Get the DIType corresponding to this DebugTypeInfo from the cache,
/// or build a fresh DIType otherwise.
llvm::DIType IRGenDebugInfo::getOrCreateType(DebugTypeInfo DbgTy,
llvm::DIDescriptor Scope) {
// Is this an empty type?
if (DbgTy.Ty.isNull())
// We use the empty type as an index into DenseMap.
return createType(DbgTy, Scope, getFile(Scope));
// Look in the cache first.
auto CachedType = DITypeCache.find(DbgTy);
if (CachedType != DITypeCache.end()) {
// Verify that the information still exists.
if (llvm::Value *Val = CachedType->second) {
auto DITy = llvm::DIType(cast<llvm::MDNode>(Val));
if (DITy.Verify())
return DITy;
}
}
llvm::DIType DITy = createType(DbgTy, Scope, getFile(Scope));
DITy.Verify();
DITypeCache[DbgTy] = llvm::WeakVH(DITy);
return DITy;
}