//===--- 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 generation for Swift. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "debug-info" #include "IRGenDebugInfo.h" #include "GenOpaque.h" #include "GenType.h" #include "Linking.h" #include "swift/AST/Expr.h" #include "swift/AST/IRGenOptions.h" #include "swift/AST/Mangle.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/Pattern.h" #include "swift/Basic/Dwarf.h" #include "swift/Basic/Punycode.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Version.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILModule.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Config/config.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/Module.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/Local.h" using namespace swift; using namespace irgen; /// Strdup a raw char array using the bump pointer. StringRef IRGenDebugInfo::BumpAllocatedString(const char *Data, size_t Length) { char *Ptr = DebugInfoNames.Allocate(Length+1); memcpy(Ptr, Data, Length); *(Ptr+Length) = 0; return StringRef(Ptr, Length); } /// Strdup S using the bump pointer. StringRef IRGenDebugInfo::BumpAllocatedString(std::string S) { return BumpAllocatedString(S.c_str(), S.length()); } /// Strdup StringRef S using the bump pointer. StringRef IRGenDebugInfo::BumpAllocatedString(StringRef S) { return BumpAllocatedString(S.data(), S.size()); } 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. std::string PunycodeBuf; (void) isNonAscii; if (isNonAscii(Id)) { OS << 'X'; Punycode::encodePunycodeUTF8(Id, PunycodeBuf); Id = PunycodeBuf; } OS << Id.size() << Id; OS.flush(); return; } /// Return the size reported by a type. static unsigned getSizeInBits(llvm::DIType *Ty, const TrackingDIRefMap &Map) { // Follow derived types until we reach a type that // reports back a size. while (isa(Ty) && !Ty->getSizeInBits()) { auto *DT = cast(Ty); Ty = DT->getBaseType().resolve(Map); if (!Ty) return 0; } return Ty->getSizeInBits(); } /// Return the size reported by the variable's type. static unsigned getSizeInBits(const llvm::DILocalVariable *Var, const TrackingDIRefMap &Map) { llvm::DIType *Ty = Var->getType().resolve(Map); return getSizeInBits(Ty, Map); } IRGenDebugInfo::IRGenDebugInfo(const IRGenOptions &Opts, ClangImporter &CI, IRGenModule &IGM, llvm::Module &M, SourceFile *SF) : Opts(Opts), CI(CI), SM(IGM.Context.SourceMgr), M(M), DBuilder(M), IGM(IGM), EntryPointFn(nullptr), MetadataTypeDecl(nullptr), InternalType(nullptr), LastDebugLoc({}), LastScope(nullptr) { assert(Opts.DebugInfoKind > IRGenDebugInfoKind::None && "no debug info should be generated"); StringRef SourceFileName = SF ? SF->getFilename() : StringRef(Opts.MainInputFilename); StringRef Dir, Filename; if (SourceFileName.empty()) { Filename = ""; Dir = getCurrentDirname(); } else { // Separate path and filename. Filename = BumpAllocatedString(llvm::sys::path::filename(SourceFileName)); llvm::SmallString<512> Path(SourceFileName); llvm::sys::path::remove_filename(Path); llvm::sys::fs::make_absolute(Path); llvm::SmallString<512> NPath; llvm::sys::path::native(Twine(Path), NPath); Dir = BumpAllocatedString(NPath); } // The fallback file. MainFilename = Dir; llvm::sys::path::append(MainFilename, Filename); MainFile = getOrCreateFile(MainFilename.c_str()); unsigned Lang = llvm::dwarf::DW_LANG_Swift; StringRef Producer = BumpAllocatedString(version::getSwiftFullVersion()); bool IsOptimized = Opts.Optimize; StringRef Flags = Opts.DWARFDebugFlags; unsigned Major, Minor; std::tie(Major, Minor) = version::getSwiftNumericVersion(); unsigned RuntimeVersion = Major*100 + Minor; // No split DWARF on Darwin. StringRef SplitName = StringRef(); TheCU = DBuilder. createCompileUnit(Lang, Filename, Dir, Producer, IsOptimized, Flags, RuntimeVersion, SplitName, Opts.DebugInfoKind == IRGenDebugInfoKind::LineTables ? llvm::DIBuilder::LineTablesOnly : llvm::DIBuilder::FullDebug); if (auto *MainFunc = IGM.SILMod->lookUpFunction(SWIFT_ENTRY_POINT_FUNCTION)) { IsLibrary = false; auto *MainIGM = IGM.dispatcher.getGenModule(MainFunc->getDeclContext()); // Don't create the function type if we are in a different llvm module than // the module where @main is defined. This is the case for non-primary // modules when doing multi-threaded whole-module compilation. if (MainIGM == &IGM) { EntryPointFn = DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_subroutine_type, SWIFT_ENTRY_POINT_FUNCTION, MainFile, MainFile, 0); } } // Create a module for the current compile unit. MainModule = getOrCreateModule(TheCU, Opts.ModuleName, MainFile); std::string Mangled("_TF"); llvm::raw_string_ostream MS(Mangled); if (Opts.ModuleName == IGM.Context.StdlibModuleName.str()) MS << "S"; else mangleIdent(MS, Opts.ModuleName); createImportedModule(Opts.ModuleName, MS.str(), MainModule, 1); } static const char *getFilenameFromDC(const DeclContext *DC) { if (auto LF = dyn_cast(DC)) { // FIXME: Today, the subclasses of LoadedFile happen to return StringRefs // that are backed by null-terminated strings, but that's certainly not // guaranteed in the future. StringRef Fn = LF->getFilename(); assert(((Fn.size() == 0) || (Fn.data()[Fn.size()] == '\0')) && "not a C string"); return Fn.data(); } if (auto SF = dyn_cast(DC)) return SF->getFilename().data(); else if (auto M = dyn_cast(DC)) return M->getModuleFilename().data(); else return nullptr; } Location getDeserializedLoc(Pattern*) { return {}; } Location getDeserializedLoc(Expr*) { return {}; } Location getDeserializedLoc(Stmt*) { return {}; } Location getDeserializedLoc(Decl* D) { Location L = {}; const DeclContext *DC = D->getDeclContext()->getModuleScopeContext(); if (const char *Filename = getFilenameFromDC(DC)) { L.Filename = Filename; L.Line = 0; } return L; } Location getLoc(SourceManager &SM, SourceLoc Loc) { Location L = {}; if (Loc.isValid()) { L.Filename = SM.getBufferIdentifierForLoc(Loc); std::tie(L.Line, L.Col) = SM.getLineAndColumn(Loc); } return L; } /// Use the SM to figure out the actual line/column of a SourceLoc. template Location getLoc(SourceManager &SM, WithLoc *S, bool End = false) { Location L = {}; if (S == nullptr) return L; SourceLoc Loc = End ? S->getEndLoc() : S->getStartLoc(); if (Loc.isInvalid()) // 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); return getLoc(SM, Loc); } /// \brief Return the start of the location's source range. static Location getStartLocation(SourceManager &SM, Optional OptLoc) { if (!OptLoc) return {}; return getLoc(SM, OptLoc->getStartSourceLoc()); } /// \brief Return the debug location from a SILLocation. static Location getDebugLocation(SourceManager &SM, Optional OptLoc) { if (!OptLoc) return {}; return getLoc(SM, OptLoc->getDebugSourceLoc()); } /// \brief Extract the start location from a SILLocation. /// /// This returns a FullLocation, which contains the location that /// should be used for the linetable and the "true" AST location (used /// for, e.g., variable declarations). static FullLocation getLocation(SourceManager &SM, Optional OptLoc) { if (!OptLoc) return {}; SILLocation Loc = OptLoc.getValue(); return { getLoc(SM, Loc.getDebugSourceLoc()), getLoc(SM, Loc.getSourceLoc())}; } /// Determine whether this debug scope belongs to an explicit closure. static bool isExplicitClosure(SILDebugScope *DS) { if (DS) if (Expr *E = DS->Loc.getAsASTNode()) if (isa(E)) return true; return false; } /// Determine whether this location is some kind of closure. static bool isAbstractClosure(const SILLocation &Loc) { if (Expr *E = Loc.getAsASTNode()) if (isa(E)) return true; return false; } /// Construct an inlined-at location from a SILScope. llvm::MDNode* IRGenDebugInfo::createInlinedAt(SILDebugScope *InlinedScope) { assert(InlinedScope); assert(InlinedScope->InlinedCallSite && "not an inlined scope"); SILDebugScope *CallSite = InlinedScope->InlinedCallSite; #ifndef NDEBUG auto *S = getOrCreateScope(InlinedScope); while (!isa(S)) { auto *LB = dyn_cast(S); S = LB->getScope(); assert(S && "Lexical block parent chain must contain a subprogram"); } #endif auto ParentScope = getOrCreateScope(CallSite->Parent); llvm::MDNode *InlinedAt = nullptr; // If this is itself an inlined location, recursively create the // inlined-at location for it. if (CallSite->InlinedCallSite) InlinedAt = createInlinedAt(CallSite); auto InlineLoc = getLoc(SM, CallSite->Loc.getDebugSourceLoc()); return llvm::DebugLoc::get(InlineLoc.Line, InlineLoc.Col, ParentScope, InlinedAt); } #ifndef NDEBUG /// Perform a couple of sanity checks on scopes. static bool parentScopesAreSane(SILDebugScope *DS) { SILDebugScope *Parent = DS->Parent; while (Parent) { if (!DS->InlinedCallSite) { assert(!Parent->InlinedCallSite && "non-inlined scope has an inlined parent"); assert(DS->SILFn == Parent->SILFn && "non-inlined parent scope from different function?"); } Parent = Parent->Parent; } return true; } bool IRGenDebugInfo::lineNumberIsSane(IRBuilder &Builder, unsigned Line) { if (IGM.Opts.Optimize) return true; // Assert monotonically increasing line numbers within the same basic block; llvm::BasicBlock *CurBasicBlock = Builder.GetInsertBlock(); if (CurBasicBlock == LastBasicBlock) { return Line >= LastDebugLoc.Line; } LastBasicBlock = CurBasicBlock; return true; } #endif void IRGenDebugInfo::setCurrentLoc(IRBuilder &Builder, SILDebugScope *DS, Optional Loc) { // In LLVM IR, the function prologue has neither location nor scope. if (Loc && Loc->isInPrologue()) return; assert(DS && "empty scope"); auto *Scope = getOrCreateScope(DS); if (!Scope) return; Location L = getDebugLocation(SM, Loc); auto *File = getOrCreateFile(L.Filename); if (File->getFilename() != Scope->getFilename()) { // We changed files in the middle of a scope. This happens, for // example, when constructors are inlined. Create a new scope to // reflect this. auto File = getOrCreateFile(L.Filename); Scope = DBuilder.createLexicalBlockFile(Scope, File); } // Both the code that is used to set up a closure object and the // (beginning of) the closure itself has the AbstractClosureExpr as // location. We are only interested in the latter case and want to // ignore the setup code. // // callWithClosure( // { // <-- a breakpoint here should only stop inside of the closure. // foo(); // }) // // The actual closure has a closure expression as scope. if (Loc && isAbstractClosure(*Loc) && DS && !isAbstractClosure(DS->Loc) && Loc->getKind() != SILLocation::ImplicitReturnKind) return; 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 = LastDebugLoc; } //FIXME: Enable this assertion. //assert(lineNumberIsSane(Builder, L.Line) && // "-Onone, but line numbers are not monotonically increasing within bb"); LastDebugLoc = L; LastScope = DS; llvm::MDNode *InlinedAt = nullptr; if (DS->InlinedCallSite) { assert(Scope && "Inlined location without a lexical scope"); InlinedAt = createInlinedAt(DS); } assert(((!InlinedAt) || (InlinedAt && Scope)) && "inlined w/o scope"); assert(parentScopesAreSane(DS) && "parent scope sanity check failed"); 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::DIScope *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 cast(CachedScope->second); // If this is a (inlined) function scope, the function may // not have been created yet. if (!DS->Parent || DS->Loc.getKind() == SILLocation::SILFileKind || DS->Loc.isASTNode() || DS->Loc.isASTNode() || DS->Loc.isASTNode()) { auto *FnScope = DS->SILFn->getDebugScope(); // FIXME: This is a bug in the SIL deserialization. if (!FnScope) DS->SILFn->setDebugScope(DS); auto CachedScope = ScopeCache.find(FnScope); if (CachedScope != ScopeCache.end()) return cast(CachedScope->second); // Force the debug info for the function to be emitted, even if it // is external or has been inlined. llvm::Function *Fn = nullptr; if (!DS->SILFn->getName().empty() && !DS->SILFn->isZombie()) Fn = IGM.getAddrOfSILFunction(DS->SILFn, NotForDefinition); auto *SP = emitFunction(*DS->SILFn, Fn); // Cache it. ScopeCache[DS] = llvm::TrackingMDNodeRef(SP); return SP; } llvm::DIScope *Parent = getOrCreateScope(DS->Parent); if (Opts.DebugInfoKind == IRGenDebugInfoKind::LineTables) return Parent; assert(DS->Parent && "lexical block must have a parent subprogram"); Location L = getStartLocation(SM, DS->Loc); llvm::DIFile *File = getOrCreateFile(L.Filename); auto *DScope = DBuilder.createLexicalBlock(Parent, File, L.Line, L.Col); // Cache it. ScopeCache[DS] = llvm::TrackingMDNodeRef(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()); } /// 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::Metadata *V = CachedFile->second) return cast(V); } // Create a new one. StringRef File = BumpAllocatedString(llvm::sys::path::filename(Filename)); llvm::SmallString<512> Path(Filename); llvm::sys::path::remove_filename(Path); llvm::DIFile *F = DBuilder.createFile(File, BumpAllocatedString(Path)); // Cache it. DIFileCache[Filename] = llvm::TrackingMDNodeRef(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.isAccessor()) if (ValueDecl *VD = FD.getAccessorStorageDecl()) { const char *Kind; switch (FD.getAccessorKind()) { case AccessorKind::NotAccessor: llvm_unreachable("this is an accessor"); case AccessorKind::IsGetter: Kind = ".get"; break; case AccessorKind::IsSetter: Kind = ".set"; break; case AccessorKind::IsWillSet: Kind = ".willset"; break; case AccessorKind::IsDidSet: Kind = ".didset"; break; case AccessorKind::IsMaterializeForSet: Kind = ".materialize"; break; case AccessorKind::IsAddressor: Kind = ".addressor"; break; case AccessorKind::IsMutableAddressor: Kind = ".mutableAddressor"; break; } SmallVector Buf; StringRef Name = (VD->getName().str() + Twine(Kind)).toStringRef(Buf); return BumpAllocatedString(Name); } if (FD.hasName()) 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 (FuncDecl *FD = L.getAsASTNode()) return getName(*FD); if (L.isASTNode()) return "init"; if (L.isASTNode()) return "deinit"; return StringRef(); } static CanSILFunctionType getFunctionType(SILType SILTy) { if (!SILTy) return CanSILFunctionType(); auto FnTy = SILTy.getAs(); if (!FnTy) { DEBUG(llvm::dbgs() << "Unexpected function type: "; SILTy.dump(); llvm::dbgs() << "\n"); return CanSILFunctionType(); } return FnTy; } /// Build the context chain for a given DeclContext. llvm::DIScope *IRGenDebugInfo::getOrCreateContext(DeclContext *DC) { if (!DC) return TheCU; switch (DC->getContextKind()) { // TODO: Create a cache for functions. case DeclContextKind::AbstractClosureExpr: case DeclContextKind::AbstractFunctionDecl: // We don't model these in DWARF. case DeclContextKind::SerializedLocal: case DeclContextKind::Initializer: case DeclContextKind::ExtensionDecl: return getOrCreateContext(DC->getParent()); case DeclContextKind::TopLevelCodeDecl: return cast(EntryPointFn); case DeclContextKind::Module: { auto File = getOrCreateFile(getFilenameFromDC(DC)); return getOrCreateModule(TheCU, cast(DC)->getName().str(), File); } case DeclContextKind::FileUnit: // A module may contain multiple files. return getOrCreateContext(DC->getParent()); case DeclContextKind::NominalTypeDecl: { auto CachedType = DITypeCache.find( cast(DC)->getDeclaredType().getPointer()); if (CachedType != DITypeCache.end()) { // Verify that the information still exists. if (llvm::Metadata *Val = CachedType->second) return cast(Val); } // Create a Forward-declared type. auto *TyDecl = cast(DC); auto Loc = getLoc(SM, TyDecl); auto File = getOrCreateFile(Loc.Filename); auto Line = Loc.Line; auto FwdDecl = DBuilder.createForwardDecl( llvm::dwarf::DW_TAG_structure_type, TyDecl->getName().str(), getOrCreateContext(DC->getParent()), File, Line, llvm::dwarf::DW_LANG_Swift, 0, 0); return FwdDecl; } } return TheCU; } /// Create a single parameter type and push it. void IRGenDebugInfo::createParameterType( llvm::SmallVectorImpl &Parameters, SILType type, DeclContext *DeclCtx) { // FIXME: This use of getSwiftType() is extremely suspect. DebugTypeInfo DbgTy(type.getSwiftType(), IGM.getTypeInfo(type), DeclCtx); Parameters.push_back(getOrCreateType(DbgTy)); } /// Create the array of function parameters for FnTy. SIL Version. llvm::DITypeRefArray IRGenDebugInfo::createParameterTypes(SILType SILTy, DeclContext *DeclCtx) { if (!SILTy) return nullptr; return createParameterTypes(SILTy.castTo(), DeclCtx); } /// Create the array of function parameters for a function type. llvm::DITypeRefArray IRGenDebugInfo::createParameterTypes(CanSILFunctionType FnTy, DeclContext *DeclCtx) { SmallVector Parameters; GenericsRAII scope(*this, FnTy->getGenericSignature()); // The function return type is the first element in the list. createParameterType(Parameters, FnTy->getSemanticResultSILType(), DeclCtx); // 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. for (auto Param : FnTy->getParameters()) createParameterType(Parameters, Param.getSILType(), DeclCtx); return DBuilder.getOrCreateTypeArray(Parameters); } /// FIXME: replace this condition with something more sane. static bool isAllocatingConstructor(SILFunctionTypeRepresentation Rep, DeclContext *DeclCtx) { return Rep != SILFunctionTypeRepresentation::Method && DeclCtx && isa(DeclCtx); } llvm::DISubprogram *IRGenDebugInfo::emitFunction( SILModule &SILMod, SILDebugScope *DS, llvm::Function *Fn, SILFunctionTypeRepresentation Rep, SILType SILTy, DeclContext *DeclCtx) { // Returned a previously cached entry for an abstract (inlined) function. auto cached = ScopeCache.find(DS); if (cached != ScopeCache.end()) return cast(cached->second); StringRef LinkageName; if (Fn) LinkageName = Fn->getName(); else if (DS) LinkageName = DS->SILFn->getName(); else llvm_unreachable("function has no mangled name"); StringRef Name; if (DS) { if (DS->Loc.getKind() == SILLocation::SILFileKind) Name = DS->SILFn->getName(); else Name = getName(DS->Loc); } Location L = {}; unsigned ScopeLine = 0; /// The source line used for the function prologue. // Bare functions and thunks should not have any line numbers. This // is especially important for shared functions like reabstraction // thunk helpers, where getLocation() returns an arbitrary location // of whichever use was emitted first. if (DS && (!DS->SILFn || (!DS->SILFn->isBare() && !DS->SILFn->isThunk()))) { auto FL = getLocation(SM, DS->Loc); L = FL.Loc; ScopeLine = FL.LocForLinetable.Line; } auto File = getOrCreateFile(L.Filename); auto Scope = MainModule; auto Line = L.Line; // We know that main always comes from MainFile. if (LinkageName == SWIFT_ENTRY_POINT_FUNCTION) { if (!L.Filename) File = MainFile; Line = 1; Name = LinkageName; } CanSILFunctionType FnTy = getFunctionType(SILTy); auto Params = Opts.DebugInfoKind == IRGenDebugInfoKind::LineTables ? nullptr : createParameterTypes(SILTy, DeclCtx); llvm::DISubroutineType *DIFnTy = DBuilder.createSubroutineType(File, Params); llvm::MDNode *TemplateParameters = nullptr; llvm::DISubprogram *Decl = nullptr; // Various flags bool IsLocalToUnit = Fn ? Fn->hasInternalLinkage() : true; bool IsDefinition = true; bool IsOptimized = Opts.Optimize; 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 main, which, albeit it does not // have a Swift name, does appear prominently in the source code. if ((Name.empty() && LinkageName != SWIFT_ENTRY_POINT_FUNCTION && !isExplicitClosure(DS)) || // ObjC thunks should also not show up in the linetable, because we // never want to set a breakpoint there. (Rep == SILFunctionTypeRepresentation::ObjCMethod) || isAllocatingConstructor(Rep, DeclCtx)) { Flags |= llvm::DINode::FlagArtificial; ScopeLine = 0; } if (FnTy && FnTy->getRepresentation() == SILFunctionType::Representation::Block) Flags |= llvm::DINode::FlagAppleBlock; llvm::DISubprogram *SP = DBuilder.createFunction( Scope, Name, LinkageName, File, Line, DIFnTy, IsLocalToUnit, IsDefinition, ScopeLine, Flags, IsOptimized, Fn, TemplateParameters, Decl); // RAUW the entry point function forward declaration with the real thing. if (LinkageName == SWIFT_ENTRY_POINT_FUNCTION) { assert(EntryPointFn->isTemporary() && "more than one entry point function"); EntryPointFn->replaceAllUsesWith(SP); llvm::MDNode::deleteTemporary(EntryPointFn); EntryPointFn = SP; } if (!DS) return nullptr; ScopeCache[DS] = llvm::TrackingMDNodeRef(SP); return SP; } /// TODO: This is no longer needed. void IRGenDebugInfo::eraseFunction(llvm::Function *Fn) {} /// 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 IRGenDebugInfo::emitImport(ImportDecl *D) { if (Opts.DebugInfoKind == IRGenDebugInfoKind::LineTables) return; // Imports are visited after SILFunctions. llvm::MDModule *Module = MainModule; swift::Module *M = IGM.Context.getModule(D->getModulePath()); if (!M && D->getModulePath()[0].first.str() == "Builtin") M = IGM.Context.TheBuiltinModule; if (!M) { assert(M && "Could not find module for import decl."); return; } auto File = getOrCreateFile(getFilenameFromDC(M->getFiles().front())); std::string Printed, Mangled("_T"); { llvm::raw_string_ostream MS(Mangled), PS(Printed); bool first = true; for (auto elt : D->getModulePath()) { auto Component = elt.first.str(); // We model each component of the access path as a module. if (first && Component == D->getASTContext().StdlibModuleName.str()) MS << "S"; else mangleIdent(MS, Component); Module = getOrCreateModule(Module, Component, File); if (first) first = false; else PS << '.'; PS << Component; } } StringRef Name = BumpAllocatedString(Printed); unsigned Line = getLoc(SM, D).Line; createImportedModule(Name, Mangled, Module, Line); } // Create an imported module and import declarations for all functions // from that module. void IRGenDebugInfo::createImportedModule(StringRef Name, StringRef Mangled, llvm::MDModule *Module, unsigned Line) { llvm::SmallString<512> Path(Module->getDirectory()); llvm::sys::path::append(Path, Module->getFilename()); auto File = getOrCreateFile(BumpAllocatedString(Path).data()); DBuilder.createImportedModule(File, Module, Line); } /// Return a cached module for an access path or create a new one. llvm::MDModule *IRGenDebugInfo::getOrCreateModule(llvm::DIScope *Parent, std::string Name, llvm::DIFile *File) { // Look in the cache first. auto CachedM = DIModuleCache.find(Name); if (CachedM != DIModuleCache.end()) // Verify that the information still exists. if (llvm::Metadata *Val = CachedM->second) return cast(Val); auto M = DBuilder.createModule(Parent, Name, File, 1); DIModuleCache[Name] = llvm::TrackingMDNodeRef(M); return M; } llvm::DISubprogram *IRGenDebugInfo::emitFunction(SILFunction &SILFn, llvm::Function *Fn) { auto *DS = SILFn.getDebugScope(); if (DS && !DS->SILFn) DS->SILFn = &SILFn; return emitFunction(SILFn.getModule(), SILFn.getDebugScope(), Fn, SILFn.getRepresentation(), SILFn.getLoweredType(), SILFn.getDeclContext()); } void IRGenDebugInfo::emitArtificialFunction(SILModule &SILMod, IRBuilder &Builder, llvm::Function *Fn, SILType SILTy) { RegularLocation ALoc = RegularLocation::getAutoGeneratedLocation(); SILDebugScope *Scope = new (SILMod) SILDebugScope(ALoc); emitFunction(SILMod, Scope, Fn, SILFunctionTypeRepresentation::Thin, SILTy); setCurrentLoc(Builder, Scope); } TypeAliasDecl *IRGenDebugInfo::getMetadataType() { if (!MetadataTypeDecl) MetadataTypeDecl = new (IGM.Context) TypeAliasDecl( SourceLoc(), IGM.Context.getIdentifier("$swift.type"), SourceLoc(), TypeLoc::withoutLoc(IGM.Context.TheRawPointerType), IGM.Context.TheBuiltinModule); return MetadataTypeDecl; } void IRGenDebugInfo::emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata, StringRef Name) { if (Opts.DebugInfoKind == IRGenDebugInfoKind::LineTables) return; auto TName = BumpAllocatedString(("$swift.type." + Name).str()); DebugTypeInfo DbgTy(getMetadataType(), Metadata->getType(), (Size)CI.getTargetInfo().getPointerWidth(0), (Alignment)CI.getTargetInfo().getPointerAlign(0)); emitVariableDeclaration(IGF.Builder, Metadata, DbgTy, IGF.getDebugScope(), TName, llvm::dwarf::DW_TAG_auto_variable, 0, // swift.type is a already pointer type, // having a shadow copy doesn't add another // layer of indirection. DirectValue, ArtificialValue); } void IRGenDebugInfo::emitStackVariableDeclaration( IRBuilder &B, ArrayRef Storage, DebugTypeInfo DbgTy, SILDebugScope *DS, StringRef Name, IndirectionKind Indirection) { emitVariableDeclaration(B, Storage, DbgTy, DS, Name, llvm::dwarf::DW_TAG_auto_variable, 0, Indirection, RealValue); } void IRGenDebugInfo::emitArgVariableDeclaration( IRBuilder &Builder, ArrayRef Storage, DebugTypeInfo DbgTy, SILDebugScope *DS, StringRef Name, unsigned ArgNo, IndirectionKind Indirection, ArtificialKind IsArtificial) { assert(ArgNo > 0); if (Name == IGM.Context.Id_self.str()) emitVariableDeclaration(Builder, Storage, DbgTy, DS, Name, llvm::dwarf::DW_TAG_arg_variable, ArgNo, DirectValue, ArtificialValue); else emitVariableDeclaration(Builder, Storage, DbgTy, DS, Name, llvm::dwarf::DW_TAG_arg_variable, ArgNo, Indirection, IsArtificial); } /// Return the DIFile that is the ancestor of Scope. llvm::DIFile *IRGenDebugInfo::getFile(llvm::DIScope *Scope) { while (!isa(Scope)) { switch (Scope->getTag()) { case llvm::dwarf::DW_TAG_lexical_block: Scope = cast(Scope)->getScope(); break; case llvm::dwarf::DW_TAG_subprogram: { // Scopes are not indexed by UID. llvm::DITypeIdentifierMap EmptyMap; Scope = cast(Scope)->getScope().resolve(EmptyMap); break; } default: return MainFile; } if (Scope) return MainFile; } return cast(Scope); } /// Return the storage size of an explosion value. static uint64_t getSizeFromExplosionValue(const clang::TargetInfo &TI, llvm::Value *V) { llvm::Type *Ty = V->getType(); if (unsigned PrimitiveSize = Ty->getPrimitiveSizeInBits()) return PrimitiveSize; else if (Ty->isPointerTy()) return TI.getPointerWidth(0); else llvm_unreachable("unhandled type of explosion value"); } /// A generator that recursively returns the size of each element of a /// composite type. class ElementSizes { const TrackingDIRefMap &DIRefMap; SmallVector Stack; public: ElementSizes(const llvm::DIType *DITy, const TrackingDIRefMap &DIRefMap) : DIRefMap(DIRefMap), Stack(1, DITy) {} struct SizeAlign { uint64_t SizeInBits, AlignInBits; }; struct SizeAlign getNext() { if (Stack.empty()) return {0, 0}; auto *Cur = Stack.pop_back_val(); if (isa(Cur) && Cur->getTag() != llvm::dwarf::DW_TAG_subroutine_type) { auto *CTy = cast(Cur); auto Elts = CTy->getElements(); unsigned N = Cur->getTag() == llvm::dwarf::DW_TAG_union_type ? std::min(1U, Elts.size()) // For unions, pick any one. : Elts.size(); if (N) { // Push all elements in reverse order. // FIXME: With a little more state we don't need to actually // store them on the Stack. for (unsigned I = N; I > 0; --I) Stack.push_back(cast(Elts[I - 1])); return getNext(); } } switch (Cur->getTag()) { case llvm::dwarf::DW_TAG_member: case llvm::dwarf::DW_TAG_typedef: { // Replace top of stack. auto *DTy = cast(Cur); Stack.push_back(DTy->getBaseType().resolve(DIRefMap)); return getNext(); } default: return {Cur->getSizeInBits(), Cur->getAlignInBits()}; } } }; static Size getStorageSize(const llvm::DataLayout &DL, ArrayRef Storage) { unsigned size = 0; for (llvm::Value *Piece : Storage) size += DL.getTypeSizeInBits(Piece->getType()); return Size(size); } void IRGenDebugInfo::emitVariableDeclaration( IRBuilder &Builder, ArrayRef Storage, DebugTypeInfo DbgTy, SILDebugScope *DS, StringRef Name, unsigned Tag, unsigned ArgNo, IndirectionKind Indirection, ArtificialKind Artificial) { // FIXME: Make this an assertion. //assert(DS && "variable has no scope"); if (!DS) return; if (Opts.DebugInfoKind == IRGenDebugInfoKind::LineTables) return; if (!DbgTy.size) DbgTy.size = getStorageSize(IGM.DataLayout, Storage); auto *Scope = dyn_cast(getOrCreateScope(DS)); assert(Scope && "variable has no local scope"); Location Loc = getLoc(SM, DbgTy.getDecl()); // FIXME: this should be the scope of the type's declaration. // If this is an argument, attach it to the current function scope. if (ArgNo > 0) { while (isa(Scope)) Scope = cast(Scope)->getScope(); } assert(Scope && isa(Scope) && "variable has no scope"); llvm::DIFile *Unit = getFile(Scope); llvm::DIType *DITy = getOrCreateType(DbgTy); assert(DITy && "could not determine debug type of variable"); unsigned Line = Loc.Line; unsigned Flags = 0; if (Artificial || DITy->isArtificial() || DITy == InternalType) Flags |= llvm::DINode::FlagArtificial; // Create the descriptor for the variable. llvm::DILocalVariable *Var = nullptr; llvm::DIExpression *Expr = DBuilder.createExpression(); if (Indirection) { // Classes are always passed by reference. int64_t Addr[] = { llvm::dwarf::DW_OP_deref }; Expr = DBuilder.createExpression(Addr); // FIXME: assert(Flags == 0 && "Complex variables cannot have flags"); } Var = DBuilder.createLocalVariable( Tag, Scope, Name, Unit, Line, DITy, false /* could be Opts.Optimize if we also unique DIVariables here */, Flags, ArgNo); // Insert a debug intrinsic into the current block. unsigned OffsetInBits = 0; auto *BB = Builder.GetInsertBlock(); bool IsPiece = Storage.size() > 1; uint64_t SizeOfByte = CI.getTargetInfo().getCharWidth(); unsigned VarSizeInBits = getSizeInBits(Var, DIRefMap); ElementSizes EltSizes(DITy, DIRefMap); auto Dim = EltSizes.getNext(); for (llvm::Value *Piece : Storage) { assert((Piece->getType()->isPointerTy() || VarSizeInBits > 0) && "zero-sized variable"); // There are variables without storage, such as "struct { func foo() {} }". // Emit them as constant 0. if (isa(Piece)) Piece = llvm::ConstantInt::get(llvm::Type::getInt64Ty(M.getContext()), 0); if (IsPiece) { // Try to get the size from the type if possible. auto StorageSize = getSizeFromExplosionValue(CI.getTargetInfo(), Piece); // FIXME: Occasionally, there is a discrepancy between the AST // type and the Storage type. Usually this is due to reference // counting. if (!Dim.SizeInBits || (StorageSize && Dim.SizeInBits > StorageSize)) Dim.SizeInBits = StorageSize; // FIXME: Occasionally we miss out that the Storage is acually a // refcount wrapper. Silently skip these for now. if (OffsetInBits+Dim.SizeInBits > VarSizeInBits) break; if (OffsetInBits == 0 && Dim.SizeInBits == VarSizeInBits) break; if (Dim.SizeInBits == 0) break; assert(Dim.SizeInBits < VarSizeInBits && "piece covers entire var"); assert(OffsetInBits+Dim.SizeInBits <= VarSizeInBits && "pars > totum"); SmallVector Elts; if (Indirection) Elts.push_back(llvm::dwarf::DW_OP_deref); Elts.push_back(llvm::dwarf::DW_OP_bit_piece); Elts.push_back(OffsetInBits); Elts.push_back(Dim.SizeInBits); Expr = DBuilder.createExpression(Elts); auto Size = Dim.SizeInBits; Dim = EltSizes.getNext(); OffsetInBits += llvm::RoundUpToAlignment(Size, Dim.AlignInBits ? Dim.AlignInBits : SizeOfByte); } emitDbgIntrinsic(BB, Piece, Var, Expr, Line, Loc.Col, Scope, DS); } // Emit locationless intrinsic for variables that were optimized away. if (Storage.size() == 0) { auto *undef = llvm::UndefValue::get(DbgTy.StorageType); emitDbgIntrinsic(BB, undef, Var, Expr, Line, Loc.Col, Scope, DS); } } void IRGenDebugInfo::emitDbgIntrinsic(llvm::BasicBlock *BB, llvm::Value *Storage, llvm::DILocalVariable *Var, llvm::DIExpression *Expr, unsigned Line, unsigned Col, llvm::DILocalScope *Scope, SILDebugScope *DS) { // Set the location/scope of the intrinsic. llvm::MDNode *InlinedAt = nullptr; if (DS && DS->InlinedCallSite) { assert(Scope && "Inlined location without a lexical scope"); InlinedAt = createInlinedAt(DS); } auto DL = llvm::DebugLoc::get(Line, Col, Scope, InlinedAt); // An alloca may only be described by exactly one dbg.declare. if (isa(Storage) && llvm::FindAllocaDbgDeclare(Storage)) return; // A dbg.declare is only meaningful if there is a single alloca for // the variable that is live throughout the function. With SIL // optimizations this is not guranteed and a variable can end up in // two allocas (for example, one function inlined twice). if (!Opts.Optimize && (isa(Storage) || isa(Storage))) DBuilder.insertDeclare(Storage, Var, Expr, DL, BB); else DBuilder.insertDbgValueIntrinsic(Storage, 0, Var, Expr, DL, BB); } void IRGenDebugInfo::emitGlobalVariableDeclaration(llvm::GlobalValue *Var, StringRef Name, StringRef LinkageName, DebugTypeInfo DbgTy, Optional Loc) { if (Opts.DebugInfoKind == IRGenDebugInfoKind::LineTables) return; llvm::DIType *Ty = getOrCreateType(DbgTy); if (Ty->isArtificial() || Ty == InternalType || Var->getVisibility() == llvm::GlobalValue::HiddenVisibility) // FIXME: Really these should be marked as artificial, but LLVM // currently has no support for flags to be put on global // variables. In the mean time, elide these variables, they // would confuse both the user and LLDB. return; Location L = getStartLocation(SM, Loc); auto File = getOrCreateFile(L.Filename); // Emit it as global variable of the current module. DBuilder.createGlobalVariable(MainModule, Name, LinkageName, File, L.Line, Ty, 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(DebugTypeInfo DbgTy) { if (MetadataTypeDecl && DbgTy.getDecl() == MetadataTypeDecl) return BumpAllocatedString(DbgTy.getDecl()->getName().str()); llvm::SmallString<160> Buffer; { llvm::raw_svector_ostream S(Buffer); Mangle::Mangler M(S, /* DWARF */ true); M.mangleTypeForDebugger(DbgTy.getType(), DbgTy.getDeclContext()); } assert(!Buffer.empty() && "mangled name came back empty"); return BumpAllocatedString(Buffer); } /// Create a member of a struct, class, tuple, or enum. llvm::DIDerivedType * IRGenDebugInfo::createMemberType(DebugTypeInfo DbgTy, StringRef Name, unsigned &OffsetInBits, llvm::DIScope *Scope, llvm::DIFile *File, unsigned Flags) { unsigned SizeOfByte = CI.getTargetInfo().getCharWidth(); auto *Ty = getOrCreateType(DbgTy); auto *DITy = DBuilder.createMemberType( Scope, Name, File, 0, SizeOfByte * DbgTy.size.getValue(), SizeOfByte * DbgTy.align.getValue(), OffsetInBits, Flags, Ty); OffsetInBits += getSizeInBits(Ty, DIRefMap); OffsetInBits = llvm::RoundUpToAlignment(OffsetInBits, SizeOfByte * DbgTy.align.getValue()); return DITy; } /// Return an array with the DITypes for each of a tuple's elements. llvm::DINodeArray IRGenDebugInfo::getTupleElements( TupleType *TupleTy, llvm::DIScope *Scope, llvm::DIFile *File, unsigned Flags, DeclContext *DeclContext, unsigned &SizeInBits) { SmallVector Elements; unsigned OffsetInBits = 0; for (auto ElemTy : TupleTy->getElementTypes()) { auto &elemTI = IGM.getTypeInfoForUnlowered(AbstractionPattern(CurGenerics, ElemTy->getCanonicalType()), ElemTy); DebugTypeInfo DbgTy(ElemTy, elemTI, DeclContext); Elements.push_back( createMemberType(DbgTy, StringRef(), OffsetInBits, Scope, File, Flags)); } SizeInBits = OffsetInBits; return DBuilder.getOrCreateArray(Elements); } /// Return an array with the DITypes for each of a struct's elements. llvm::DINodeArray IRGenDebugInfo::getStructMembers(NominalTypeDecl *D, Type BaseTy, llvm::DIScope *Scope, llvm::DIFile *File, unsigned Flags, unsigned &SizeInBits) { SmallVector Elements; unsigned OffsetInBits = 0; for (VarDecl *VD : D->getStoredProperties()) { auto memberTy = BaseTy->getTypeOfMember(IGM.SILMod->getSwiftModule(), VD, nullptr); DebugTypeInfo DbgTy(VD, IGM.getTypeInfoForUnlowered( IGM.SILMod->Types.getAbstractionPattern(VD), memberTy)); Elements.push_back(createMemberType(DbgTy, VD->getName().str(), OffsetInBits, Scope, File, Flags)); } if (OffsetInBits > SizeInBits) SizeInBits = OffsetInBits; return DBuilder.getOrCreateArray(Elements); } /// Create a temporary forward declaration for a struct and add it to /// the type cache so we can safely build recursive types. llvm::DICompositeType *IRGenDebugInfo::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) { StringRef Name = Decl->getName().str(); // Forward declare this first because types may be recursive. auto FwdDecl = llvm::TempDIType( DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_structure_type, Name, Scope, File, Line, llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags, UniqueID)); #ifndef NDEBUG if (UniqueID.empty()) assert(!Name.empty() && "no mangled name and no human readable name given"); else assert(UniqueID.size() > 2 && UniqueID[0] == '_' && UniqueID[1] == 'T' && "UID is not a mangled name"); #endif auto TH = llvm::TrackingMDNodeRef(FwdDecl.get()); DITypeCache[DbgTy.getType()] = TH; auto Members = getStructMembers(Decl, BaseTy, Scope, File, Flags, SizeInBits); auto DITy = DBuilder.createStructType( Scope, Name, File, Line, SizeInBits, AlignInBits, Flags, DerivedFrom, Members, RuntimeLang, nullptr, UniqueID); DBuilder.replaceTemporary(std::move(FwdDecl), DITy); return DITy; } /// Return an array with the DITypes for each of an enum's elements. llvm::DINodeArray IRGenDebugInfo::getEnumElements(DebugTypeInfo DbgTy, EnumDecl *D, llvm::DIScope *Scope, llvm::DIFile *File, unsigned Flags) { SmallVector Elements; for (auto *ElemDecl : D->getAllElements()) { // FIXME Support enums. // Swift Enums can be both like DWARF enums and DWARF unions. // They should probably be emitted as DW_TAG_variant_type. if (ElemDecl->hasType()) { // Use Decl as DeclContext. DebugTypeInfo ElemDbgTy; if (ElemDecl->hasArgumentType()) ElemDbgTy = DebugTypeInfo(ElemDecl->getArgumentType(), DbgTy.StorageType, DbgTy.size, DbgTy.align, D); else if (D->hasRawType()) ElemDbgTy = DebugTypeInfo(D->getRawType(), DbgTy.StorageType, DbgTy.size, DbgTy.align, D); else // Fallback to Int as the element type. ElemDbgTy = DebugTypeInfo(IGM.Context.getIntDecl()->getDeclaredType(), DbgTy.StorageType, DbgTy.size, DbgTy.align, D); unsigned Offset = 0; auto MTy = createMemberType(ElemDbgTy, ElemDecl->getName().str(), Offset, Scope, File, Flags); Elements.push_back(MTy); } } return DBuilder.getOrCreateArray(Elements); } /// Create a temporary forward declaration for an enum and add it to /// the type cache so we can safely build recursive types. llvm::DICompositeType *IRGenDebugInfo::createEnumType( DebugTypeInfo DbgTy, EnumDecl *Decl, StringRef MangledName, llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line, unsigned Flags) { unsigned SizeOfByte = CI.getTargetInfo().getCharWidth(); unsigned SizeInBits = DbgTy.size.getValue() * SizeOfByte; unsigned AlignInBits = DbgTy.align.getValue() * SizeOfByte; // FIXME: Is DW_TAG_union_type the right thing here? // Consider using a DW_TAG_variant_type instead. auto FwdDecl = llvm::TempDIType( DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_union_type, MangledName, Scope, File, Line, llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags, MangledName)); auto TH = llvm::TrackingMDNodeRef(FwdDecl.get()); DITypeCache[DbgTy.getType()] = TH; auto DITy = DBuilder.createUnionType( Scope, Decl->getName().str(), File, Line, SizeInBits, AlignInBits, Flags, getEnumElements(DbgTy, Decl, Scope, File, Flags), llvm::dwarf::DW_LANG_Swift, MangledName); DBuilder.replaceTemporary(std::move(FwdDecl), DITy); return DITy; } /// Return a DIType for Ty reusing any DeclContext found in DbgTy. llvm::DIType *IRGenDebugInfo::getOrCreateDesugaredType(Type Ty, DebugTypeInfo DbgTy) { DebugTypeInfo BlandDbgTy(Ty, DbgTy.StorageType, DbgTy.size, DbgTy.align, DbgTy.getDeclContext()); return getOrCreateType(BlandDbgTy); } uint64_t IRGenDebugInfo::getSizeOfBasicType(DebugTypeInfo DbgTy) { uint64_t SizeOfByte = CI.getTargetInfo().getCharWidth(); uint64_t BitWidth = DbgTy.size.getValue() * SizeOfByte; llvm::Type *StorageType = DbgTy.StorageType ? DbgTy.StorageType : IGM.DataLayout.getSmallestLegalIntType( IGM.getLLVMContext(), BitWidth); if (StorageType) return IGM.DataLayout.getTypeSizeInBits(StorageType); // This type is too large to fit in a register. assert(BitWidth > IGM.DataLayout.getLargestLegalIntTypeSize()); return BitWidth; } /// Convenience function that creates a forward declaration for PointeeTy. llvm::DIType *IRGenDebugInfo::createPointerSizedStruct( llvm::DIScope *Scope, StringRef Name, llvm::DIFile *File, unsigned Line, unsigned Flags, StringRef MangledName) { auto FwdDecl = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, Name, Scope, File, Line, llvm::dwarf::DW_LANG_Swift, 0, 0); return createPointerSizedStruct(Scope, Name, FwdDecl, File, Line, Flags, MangledName); } /// Create a pointer-sized struct with a mangled name and a single /// member of PointeeTy. llvm::DIType *IRGenDebugInfo::createPointerSizedStruct( llvm::DIScope *Scope, StringRef Name, llvm::DIType *PointeeTy, llvm::DIFile *File, unsigned Line, unsigned Flags, StringRef MangledName) { unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); unsigned PtrAlign = CI.getTargetInfo().getPointerAlign(0); auto PtrTy = DBuilder.createPointerType(PointeeTy, PtrSize, PtrAlign); llvm::Metadata *Elements[] = { DBuilder.createMemberType(Scope, "pointer", File, 0, PtrSize, PtrAlign, 0, Flags, PtrTy) }; return DBuilder.createStructType( Scope, Name, File, Line, PtrSize, PtrAlign, Flags, nullptr, // DerivedFrom DBuilder.getOrCreateArray(Elements), llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); } /// 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 *IRGenDebugInfo::createType(DebugTypeInfo DbgTy, StringRef MangledName, llvm::DIScope *Scope, llvm::DIFile *File) { // 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. uint64_t SizeOfByte = CI.getTargetInfo().getCharWidth(); uint64_t SizeInBits = DbgTy.size.getValue() * SizeOfByte; // Prefer the actual storage size over the DbgTy. if (DbgTy.StorageType && DbgTy.StorageType->isSized()) { uint64_t Storage = IGM.DataLayout.getTypeSizeInBits(DbgTy.StorageType); if (Storage) SizeInBits = Storage; } uint64_t AlignInBits = DbgTy.align.getValue() * SizeOfByte; unsigned Encoding = 0; unsigned Flags = 0; TypeBase *BaseTy = DbgTy.getType(); if (!BaseTy) { DEBUG(llvm::dbgs() << "Type without TypeBase: "; DbgTy.getType()->dump(); llvm::dbgs() << "\n"); if (!InternalType) { StringRef Name = ""; InternalType = DBuilder.createForwardDecl( llvm::dwarf::DW_TAG_structure_type, Name, Scope, File, /*Line*/ 0, llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits); } return InternalType; } // Here goes! switch (BaseTy->getKind()) { case TypeKind::BuiltinInteger: { Encoding = llvm::dwarf::DW_ATE_unsigned; SizeInBits = getSizeOfBasicType(DbgTy); break; } case TypeKind::BuiltinFloat: { auto *FloatTy = BaseTy->castTo(); // Assuming that the bitwidth and FloatTy->getFPKind() are identical. SizeInBits = FloatTy->getBitWidth(); Encoding = llvm::dwarf::DW_ATE_float; break; } case TypeKind::BuiltinUnknownObject: { // The builtin opaque Objective-C pointer type. Useful for pushing // an Objective-C type through swift. unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); unsigned PtrAlign = CI.getTargetInfo().getPointerAlign(0); auto IdTy = DBuilder.createForwardDecl( llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, File, 0, llvm::dwarf::DW_LANG_ObjC, 0, 0); return DBuilder.createPointerType(IdTy, PtrSize, PtrAlign, MangledName); } case TypeKind::BuiltinNativeObject: { unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); unsigned PtrAlign = CI.getTargetInfo().getPointerAlign(0); auto PTy = DBuilder.createPointerType(nullptr, PtrSize, PtrAlign, MangledName); return DBuilder.createObjectPointerType(PTy); } case TypeKind::BuiltinBridgeObject: { unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); unsigned PtrAlign = CI.getTargetInfo().getPointerAlign(0); auto PTy = DBuilder.createPointerType(nullptr, PtrSize, PtrAlign, MangledName); return DBuilder.createObjectPointerType(PTy); } case TypeKind::BuiltinRawPointer: { unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); unsigned PtrAlign = CI.getTargetInfo().getPointerAlign(0); return DBuilder.createPointerType(nullptr, PtrSize, PtrAlign, MangledName); } case TypeKind::DynamicSelf: { // Self. We don't have a way to represent instancetype in DWARF, // so we emit the static type instead. This is similar to what we // do with instancetype in Objective-C. auto *DynamicSelfTy = BaseTy->castTo(); auto SelfTy = getOrCreateDesugaredType(DynamicSelfTy->getSelfType(), DbgTy); return DBuilder.createTypedef(SelfTy, MangledName, File, 0, File); } // Even builtin swift types usually come boxed in a struct. case TypeKind::Struct: { auto *StructTy = BaseTy->castTo(); auto *Decl = StructTy->getDecl(); Location L = getLoc(SM, Decl); return createStructType(DbgTy, Decl, StructTy, Scope, getOrCreateFile(L.Filename), L.Line, SizeInBits, AlignInBits, Flags, nullptr, // DerivedFrom llvm::dwarf::DW_LANG_Swift, MangledName); } 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(); auto *Decl = ClassTy->getDecl(); Location L = getLoc(SM, Decl); if (auto *ClangDecl = Decl->getClangDecl()) { auto ClangSrcLoc = ClangDecl->getLocStart(); clang::SourceManager &ClangSM = CI.getClangASTContext().getSourceManager(); L.Line = ClangSM.getPresumedLineNumber(ClangSrcLoc); L.Filename = ClangSM.getBufferName(ClangSrcLoc); // Use "ObjectiveC" as default for implicit decls. // FIXME 1: Do something more clever based on the decl's mangled name. // FIXME 2: Clang submodules are not handled here. StringRef ModuleName = "ObjectiveC"; if (auto *OwningModule = ClangDecl->getOwningModule()) ModuleName = OwningModule->getTopLevelModuleName(); auto ModuleFile = getOrCreateFile(L.Filename); // This placeholder gets RAUW'd by finalize(). Scope = getOrCreateModule(ModuleFile, ModuleName, ModuleFile); } return createPointerSizedStruct(Scope, Decl->getNameStr(), getOrCreateFile(L.Filename), L.Line, Flags, MangledName); } case TypeKind::Protocol: { auto *ProtocolTy = BaseTy->castTo(); auto *Decl = ProtocolTy->getDecl(); // FIXME: (LLVM branch) This should probably be a DW_TAG_interface_type. Location L = getLoc(SM, Decl); auto File = getOrCreateFile(L.Filename); return createPointerSizedStruct(Scope, Decl ? Decl->getNameStr() : MangledName, File, L.Line, Flags, MangledName); } case TypeKind::ProtocolComposition: { auto *Decl = DbgTy.getDecl(); Location L = getLoc(SM, Decl); auto File = getOrCreateFile(L.Filename); // FIXME: emit types // auto ProtocolCompositionTy = BaseTy->castTo(); return createPointerSizedStruct(Scope, Decl ? Decl->getNameStr() : MangledName, File, L.Line, Flags, MangledName); } case TypeKind::UnboundGeneric: { auto *UnboundTy = BaseTy->castTo(); auto *Decl = UnboundTy->getDecl(); Location L = getLoc(SM, Decl); return createPointerSizedStruct(Scope, Decl ? Decl->getNameStr() : MangledName, File, L.Line, Flags, MangledName); } case TypeKind::BoundGenericStruct: { auto *StructTy = BaseTy->castTo(); auto *Decl = StructTy->getDecl(); Location L = getLoc(SM, Decl); return createPointerSizedStruct(Scope, Decl ? Decl->getNameStr() : MangledName, File, L.Line, Flags, MangledName); } case TypeKind::BoundGenericClass: { auto *ClassTy = BaseTy->castTo(); auto *Decl = ClassTy->getDecl(); Location L = getLoc(SM, Decl); // TODO: We may want to peek at Decl->isObjC() and set this // attribute accordingly. return createPointerSizedStruct(Scope, Decl ? Decl->getNameStr() : MangledName, File, L.Line, Flags, MangledName); } case TypeKind::Tuple: { auto *TupleTy = BaseTy->castTo(); // Tuples are also represented as structs. auto FwdDecl = llvm::TempDINode( DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, File, 0, llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags, MangledName)); DITypeCache[DbgTy.getType()] = llvm::TrackingMDNodeRef(FwdDecl.get()); unsigned RealSize; auto Elements = getTupleElements(TupleTy, Scope, MainFile, Flags, DbgTy.getDeclContext(), RealSize); // FIXME: Handle %swift.opaque members and make this into an assertion. if (!RealSize) RealSize = SizeInBits; auto DITy = DBuilder.createStructType( Scope, MangledName, File, 0, RealSize, AlignInBits, Flags, nullptr, // DerivedFrom Elements, llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); DBuilder.replaceTemporary(std::move(FwdDecl), DITy); return DITy; } case TypeKind::InOut: { // This is an inout type. Naturally we would be emitting them as // DW_TAG_reference_type types, but LLDB can deal better with pointer-sized // struct that has the appropriate mangled name. auto ObjectTy = BaseTy->castTo()->getObjectType(); auto DT = getOrCreateDesugaredType(ObjectTy, DbgTy); return createPointerSizedStruct(Scope, MangledName, DT, File, 0, Flags, BaseTy->isUnspecializedGeneric() ? StringRef() : MangledName); } case TypeKind::Archetype: { auto *Archetype = BaseTy->castTo(); Location L = getLoc(SM, Archetype->getAssocType()); auto Superclass = Archetype->getSuperclass(); auto DerivedFrom = Superclass.isNull() ? nullptr : getOrCreateDesugaredType(Superclass, DbgTy); auto FwdDecl = llvm::TempDIType( DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, File, L.Line, llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags, MangledName)); // Emit the protocols the archetypes conform to. SmallVector Protocols; for (auto *ProtocolDecl : Archetype->getConformsTo()) { auto PTy = IGM.SILMod->Types.getLoweredType(ProtocolDecl->getType()) .getSwiftRValueType(); auto PDbgTy = DebugTypeInfo(ProtocolDecl, IGM.getTypeInfoForLowered(PTy)); auto PDITy = getOrCreateType(PDbgTy); Protocols.push_back(DBuilder.createInheritance(FwdDecl.get(), PDITy, 0, Flags)); } auto DITy = DBuilder.createStructType( Scope, MangledName, File, L.Line, SizeInBits, AlignInBits, Flags, DerivedFrom, DBuilder.getOrCreateArray(Protocols), llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); DBuilder.replaceTemporary(std::move(FwdDecl), DITy); return DITy; } case TypeKind::ExistentialMetatype: case TypeKind::Metatype: { // Metatypes are (mostly) singleton type descriptors, often without storage. Flags |= llvm::DINode::FlagArtificial; Location L = getLoc(SM, DbgTy.getDecl()); auto File = getOrCreateFile(L.Filename); return DBuilder.createStructType( Scope, MangledName, File, L.Line, SizeInBits, AlignInBits, Flags, nullptr, nullptr, llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); } case TypeKind::SILFunction: case TypeKind::Function: case TypeKind::PolymorphicFunction: case TypeKind::GenericFunction: { auto FwdDecl = llvm::TempDINode( DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_subroutine_type, MangledName, Scope, File, 0, llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags, MangledName)); auto TH = llvm::TrackingMDNodeRef(FwdDecl.get()); DITypeCache[DbgTy.getType()] = TH; CanSILFunctionType FunctionTy; if (auto *SILFnTy = dyn_cast(BaseTy)) FunctionTy = CanSILFunctionType(SILFnTy); // FIXME: Handling of generic parameters in SIL type lowering is in flux. // DebugInfo doesn't appear to care about the generic context, so just // throw it away before lowering. else if (isa(BaseTy) || isa(BaseTy)) { auto *fTy = cast(BaseTy); auto *nongenericTy = FunctionType::get(fTy->getInput(), fTy->getResult(), fTy->getExtInfo()); FunctionTy = IGM.SILMod->Types.getLoweredType(nongenericTy) .castTo(); } else FunctionTy = IGM.SILMod->Types.getLoweredType(BaseTy).castTo(); auto Params = createParameterTypes(FunctionTy, DbgTy.getDeclContext()); // Functions are actually stored as a Pointer or a FunctionPairTy: // { i8*, %swift.refcounted* } auto FnTy = DBuilder.createSubroutineType(MainFile, Params, Flags); auto DITy = createPointerSizedStruct(Scope, MangledName, FnTy, MainFile, 0, Flags, MangledName); DBuilder.replaceTemporary(std::move(FwdDecl), DITy); return DITy; } case TypeKind::Enum: { auto *EnumTy = BaseTy->castTo(); auto *Decl = EnumTy->getDecl(); Location L = getLoc(SM, Decl); return createEnumType(DbgTy, Decl, MangledName, Scope, getOrCreateFile(L.Filename), L.Line, Flags); } case TypeKind::BoundGenericEnum: { auto *EnumTy = BaseTy->castTo(); auto *Decl = EnumTy->getDecl(); Location L = getLoc(SM, Decl); return createEnumType(DbgTy, Decl, MangledName, Scope, getOrCreateFile(L.Filename), L.Line, Flags); } case TypeKind::BuiltinVector: { (void)MangledName; // FIXME emit the name somewhere. auto *BuiltinVectorTy = BaseTy->castTo(); DebugTypeInfo ElemDbgTy(BuiltinVectorTy->getElementType(), DbgTy.StorageType, DbgTy.size, DbgTy.align, DbgTy.getDeclContext()); auto Subscripts = nullptr; return DBuilder.createVectorType(BuiltinVectorTy->getNumElements(), AlignInBits, getOrCreateType(ElemDbgTy), Subscripts); } // Reference storage types. case TypeKind::UnownedStorage: case TypeKind::UnmanagedStorage: case TypeKind::WeakStorage: { auto *ReferenceTy = cast(BaseTy); auto CanTy = ReferenceTy->getReferentType(); Location L = getLoc(SM, DbgTy.getDecl()); auto File = getOrCreateFile(L.Filename); return DBuilder.createTypedef(getOrCreateDesugaredType(CanTy, DbgTy), MangledName, File, L.Line, File); } // Sugared types. case TypeKind::NameAlias: { auto *NameAliasTy = cast(BaseTy); auto *Decl = NameAliasTy->getDecl(); Location L = getLoc(SM, Decl); auto AliasedTy = Decl->getUnderlyingType(); auto File = getOrCreateFile(L.Filename); // For NameAlias types, the DeclContext for the aliasED type is // in the decl of the alias type. DebugTypeInfo AliasedDbgTy(AliasedTy, DbgTy.StorageType, DbgTy.size, DbgTy.align, DbgTy.getDeclContext()); return DBuilder.createTypedef(getOrCreateType(AliasedDbgTy), MangledName, File, L.Line, File); } case TypeKind::Substituted: { auto OrigTy = cast(BaseTy)->getReplacementType(); return getOrCreateDesugaredType(OrigTy, DbgTy); } case TypeKind::Paren: { auto Ty = cast(BaseTy)->getUnderlyingType(); return getOrCreateDesugaredType(Ty, DbgTy); } // SyntaxSugarType derivations. case TypeKind::ArraySlice: case TypeKind::Optional: case TypeKind::ImplicitlyUnwrappedOptional: { auto *SyntaxSugarTy = cast(BaseTy); auto *CanTy = SyntaxSugarTy->getSinglyDesugaredType(); return getOrCreateDesugaredType(CanTy, DbgTy); } case TypeKind::Dictionary: { auto *DictionaryTy = cast(BaseTy); auto *CanTy = DictionaryTy->getDesugaredType(); return getOrCreateDesugaredType(CanTy, DbgTy); } case TypeKind::GenericTypeParam: { auto *ParamTy = cast(BaseTy); // FIXME: Provide a more meaningful debug type. return DBuilder.createUnspecifiedType(ParamTy->getName().str()); } case TypeKind::DependentMember: { auto *MemberTy = cast(BaseTy); // FIXME: Provide a more meaningful debug type. return DBuilder.createUnspecifiedType(MemberTy->getName().str()); } // The following types exist primarily for internal use by the type // checker. case TypeKind::AssociatedType: case TypeKind::Error: case TypeKind::LValue: case TypeKind::TypeVariable: case TypeKind::Module: case TypeKind::SILBlockStorage: case TypeKind::SILBox: case TypeKind::BuiltinUnsafeValueBuffer: DEBUG(llvm::errs() << "Unhandled type: "; DbgTy.getType()->dump(); llvm::errs() << "\n"); MangledName = ""; } return DBuilder.createBasicType(MangledName, SizeInBits, AlignInBits, Encoding); } /// Determine if there exists a name mangling for the given type. static bool canMangle(TypeBase *Ty) { switch (Ty->getKind()) { case TypeKind::PolymorphicFunction: // Mangler crashes. case TypeKind::GenericFunction: // Not yet supported. case TypeKind::SILBlockStorage: // Not suported at all. case TypeKind::SILBox: return false; case TypeKind::InOut: { auto *ObjectTy = Ty->castTo()->getObjectType().getPointer(); return canMangle(ObjectTy); } default: return true; } } /// 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 *IRGenDebugInfo::getOrCreateType(DebugTypeInfo DbgTy) { // Is this an empty type? if (DbgTy.isNull()) // We can't use the empty type as an index into DenseMap. return createType(DbgTy, "", TheCU, MainFile); // Look in the cache first. auto CachedType = DITypeCache.find(DbgTy.getType()); if (CachedType != DITypeCache.end()) { // Verify that the information still exists. if (llvm::Metadata *Val = CachedType->second) { auto DITy = cast(Val); return DITy; } } // Second line of defense: Look up the mangled name. TypeBase*'s are // not necessarily unique, but name mangling is too expensive to do // every time. StringRef MangledName; llvm::MDString *UID = nullptr; if (canMangle(DbgTy.getType())) { MangledName = getMangledName(DbgTy); UID = llvm::MDString::get(IGM.getLLVMContext(), MangledName); if (llvm::Metadata *CachedTy = DIRefMap.lookup(UID)) { auto DITy = cast(CachedTy); return DITy; } } // Retrieve the context of the type, as opposed to the DeclContext // of the variable. // // FIXME: Builtin and qualified types in LLVM have no parent // scope. TODO: This can be fixed by extending DIBuilder. DeclContext *Context = DbgTy.getType()->getNominalOrBoundGenericNominal(); if (Context) Context = Context->getParent(); llvm::DIScope *Scope = getOrCreateContext(Context); llvm::DIType *DITy = createType(DbgTy, MangledName, Scope, getFile(Scope)); // Incrementally build the DIRefMap. if (auto *CTy = dyn_cast(DITy)) { #ifndef NDEBUG // Sanity check. if (llvm::Metadata *V = DIRefMap.lookup(UID)) { auto *CachedTy = cast(V); assert(CachedTy == DITy && "conflicting types for one UID"); } #endif // If this type supports a UID, enter it to the cache. if (auto UID = CTy->getRawIdentifier()) { assert(UID->getString() == MangledName && "Unique identifier is different from mangled name "); DIRefMap[UID] = llvm::TrackingMDNodeRef(DITy); } } // Store it in the cache. DITypeCache.insert({DbgTy.getType(), llvm::TrackingMDNodeRef(DITy)}); return DITy; } void IRGenDebugInfo::finalize() { assert(LocationStack.empty() && "Mismatch of pushLoc() and popLoc()."); // Finalize the DIBuilder. DBuilder.finalize(); }