//===--- IRGenDebugInfo.cpp - Debug Info Support --------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements IR debug info generation for Swift. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "debug-info" #include "IRGenDebugInfo.h" #include "GenOpaque.h" #include "GenType.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/Expr.h" #include "swift/AST/IRGenOptions.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/Pattern.h" #include "swift/Basic/Dwarf.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Version.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Demangling/ManglingMacros.h" #include "swift/Serialization/SerializedModuleLoader.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/AST/ExternalASTSource.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Serialization/ASTReader.h" #include "llvm/Config/config.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/IntrinsicInst.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" #ifndef NDEBUG #include "swift/AST/ASTDemangler.h" #endif using namespace swift; using namespace irgen; llvm::cl::opt VerifyLineTable( "verify-linetable", llvm::cl::init(false), llvm::cl::desc( "Verify that the debug locations within one scope are contiguous.")); namespace { using TrackingDIRefMap = llvm::DenseMap; class IRGenDebugInfoImpl : public IRGenDebugInfo { friend class IRGenDebugInfoImpl; const IRGenOptions &Opts; ClangImporter &CI; SourceManager &SM; llvm::Module &M; llvm::DIBuilder DBuilder; IRGenModule &IGM; const PathRemapper &DebugPrefixMap; /// Various caches. /// @{ llvm::DenseMap ScopeCache; llvm::DenseMap InlinedAtCache; llvm::DenseMap DebugLocCache; llvm::DenseMap DITypeCache; llvm::DenseMap DIModuleCache; llvm::StringMap DIFileCache; TrackingDIRefMap DIRefMap; /// @} /// A list of replaceable fwddecls that need to be RAUWed at the end. std::vector> ReplaceMap; /// The set of imported modules. llvm::DenseSet ImportedModules; llvm::BumpPtrAllocator DebugInfoNames; /// The current working directory. StringRef CWDName; /// User-provided -D macro definitions. SmallString<0> ConfigMacros; /// The current compilation unit. llvm::DICompileUnit *TheCU = nullptr; /// The main file. llvm::DIFile *MainFile = nullptr; /// The current module. llvm::DIModule *MainModule = nullptr; /// Scope of SWIFT_ENTRY_POINT_FUNCTION. llvm::DIScope *EntryPointFn = nullptr; /// The artificial type decls for named archetypes. llvm::StringMap MetadataTypeDeclCache; /// Catch-all type for opaque internal types. llvm::DIType *InternalType = nullptr; /// The last location that was emitted. SILLocation::DebugLoc LastDebugLoc; /// The scope of that last location. const SILDebugScope *LastScope = nullptr; /// Used by pushLoc. SmallVector, 8> LocationStack; #ifndef NDEBUG using UUSTuple = std::pair, StringRef>; struct DebugLocKey : public UUSTuple { DebugLocKey(SILLocation::DebugLoc DL) : UUSTuple({{DL.Line, DL.Column}, DL.Filename}) {} inline bool operator==(const SILLocation::DebugLoc &DL) const { return first.first == DL.Line && first.second == DL.Column && second.equals(DL.Filename); } }; llvm::DenseSet PreviousLineEntries; SILLocation::DebugLoc PreviousDebugLoc; #endif public: IRGenDebugInfoImpl(const IRGenOptions &Opts, ClangImporter &CI, IRGenModule &IGM, llvm::Module &M, StringRef MainOutputFilenameForDebugInfo, StringRef PrivateDiscriminator); void finalize(); void setCurrentLoc(IRBuilder &Builder, const SILDebugScope *DS, SILLocation Loc); void addFailureMessageToCurrentLoc(IRBuilder &Builder, StringRef failureMsg); void clearLoc(IRBuilder &Builder); void pushLoc(); void popLoc(); void setInlinedTrapLocation(IRBuilder &Builder, const SILDebugScope *Scope); void setEntryPointLoc(IRBuilder &Builder); llvm::DIScope *getEntryPointFn(); llvm::DIScope *getOrCreateScope(const SILDebugScope *DS); void emitImport(ImportDecl *D); llvm::DISubprogram *emitFunction(const SILDebugScope *DS, llvm::Function *Fn, SILFunctionTypeRepresentation Rep, SILType Ty, DeclContext *DeclCtx = nullptr); llvm::DISubprogram *emitFunction(SILFunction &SILFn, llvm::Function *Fn); void emitArtificialFunction(IRBuilder &Builder, llvm::Function *Fn, SILType SILTy); void emitVariableDeclaration(IRBuilder &Builder, ArrayRef Storage, DebugTypeInfo Ty, const SILDebugScope *DS, ValueDecl *VarDecl, SILDebugVariable VarInfo, IndirectionKind = DirectValue, ArtificialKind = RealValue); void emitDbgIntrinsic(IRBuilder &Builder, llvm::Value *Storage, llvm::DILocalVariable *Var, llvm::DIExpression *Expr, unsigned Line, unsigned Col, llvm::DILocalScope *Scope, const SILDebugScope *DS); void emitGlobalVariableDeclaration(llvm::GlobalVariable *Storage, StringRef Name, StringRef LinkageName, DebugTypeInfo DebugType, bool IsLocalToUnit, bool InFixedBuffer, Optional Loc); void emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata, unsigned Depth, unsigned Index, StringRef Name); /// Return the DIBuilder. llvm::DIBuilder &getBuilder() { return DBuilder; } /// Decode (and cache) a SourceLoc. SILLocation::DebugLoc decodeSourceLoc(SourceLoc SL); IRGenDebugInfoFormat getDebugInfoFormat() { return Opts.DebugInfoFormat; } private: static StringRef getFilenameFromDC(const DeclContext *DC) { if (auto *LF = dyn_cast(DC)) return LF->getFilename(); if (auto *SF = dyn_cast(DC)) return SF->getFilename(); if (auto *M = dyn_cast(DC)) return M->getModuleFilename(); return {}; } using DebugLoc = SILLocation::DebugLoc; DebugLoc getDeserializedLoc(Pattern *) { return {}; } DebugLoc getDeserializedLoc(Expr *) { return {}; } DebugLoc getDeserializedLoc(Decl *D) { DebugLoc L; const DeclContext *DC = D->getDeclContext()->getModuleScopeContext(); StringRef Filename = getFilenameFromDC(DC); if (!Filename.empty()) L.Filename = Filename; return L; } /// Use the Swift SM to figure out the actual line/column of a SourceLoc. template DebugLoc getSwiftDebugLoc(IRGenDebugInfo &DI, WithLoc *ASTNode, bool End) { if (!ASTNode) return {}; SourceLoc Loc = End ? ASTNode->getEndLoc() : ASTNode->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(ASTNode); return DI.decodeSourceLoc(Loc); } DebugLoc getDebugLoc(IRGenDebugInfo &DI, Pattern *P, bool End = false) { return getSwiftDebugLoc(DI, P, End); } DebugLoc getDebugLoc(IRGenDebugInfo &DI, Expr *E, bool End = false) { return getSwiftDebugLoc(DI, E, End); } DebugLoc getDebugLoc(IRGenDebugInfo &DI, Decl *D, bool End = false) { DebugLoc L; if (!D) return L; if (auto *ClangDecl = D->getClangDecl()) { clang::SourceLocation ClangSrcLoc = ClangDecl->getBeginLoc(); clang::SourceManager &ClangSM = CI.getClangASTContext().getSourceManager(); clang::PresumedLoc PresumedLoc = ClangSM.getPresumedLoc(ClangSrcLoc); if (!PresumedLoc.isValid()) return L; L.Line = PresumedLoc.getLine(); L.Column = PresumedLoc.getColumn(); L.Filename = PresumedLoc.getFilename(); return L; } return getSwiftDebugLoc(DI, D, End); } DebugLoc getStartLocation(Optional OptLoc) { if (!OptLoc) return {}; return decodeSourceLoc(OptLoc->getStartSourceLoc()); } DebugLoc sanitizeCodeViewDebugLoc(DebugLoc DLoc) { if (Opts.DebugInfoFormat == IRGenDebugInfoFormat::CodeView) // When WinDbg finds two locations with the same line but different // columns, the user must select an address when they break on that // line. Also, clang does not emit column locations in CodeView for C++. DLoc.Column = 0; return DLoc; } DebugLoc decodeDebugLoc(SILLocation Loc) { if (Loc.isDebugInfoLoc()) return sanitizeCodeViewDebugLoc(Loc.getDebugInfoLoc()); return decodeSourceLoc(Loc.getDebugSourceLoc()); } DebugLoc getDebugLocation(Optional OptLoc) { if (!OptLoc || (Opts.DebugInfoFormat != IRGenDebugInfoFormat::CodeView && OptLoc->isInPrologue())) return {}; return decodeDebugLoc(*OptLoc); } /// Strdup a raw char array using the bump pointer. StringRef 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 BumpAllocatedString(std::string S) { return BumpAllocatedString(S.c_str(), S.length()); } /// Strdup StringRef S using the bump pointer. StringRef BumpAllocatedString(StringRef S) { return BumpAllocatedString(S.data(), S.size()); } /// Return the size reported by a type. static unsigned getSizeInBits(llvm::DIType *Ty) { // 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(); if (!Ty) return 0; } return Ty->getSizeInBits(); } #ifndef NDEBUG /// Return the size reported by the variable's type. static unsigned getSizeInBits(const llvm::DILocalVariable *Var) { llvm::DIType *Ty = Var->getType(); return getSizeInBits(Ty); } #endif /// Determine whether this debug scope belongs to an explicit closure. static bool isExplicitClosure(const SILFunction *SILFn) { if (SILFn && SILFn->hasLocation()) if (Expr *E = SILFn->getLocation().getAsASTNode()) if (isa(E)) return true; return false; } llvm::MDNode *createInlinedAt(const SILDebugScope *DS) { auto *CS = DS->InlinedCallSite; if (!CS) return nullptr; auto CachedInlinedAt = InlinedAtCache.find(CS); if (CachedInlinedAt != InlinedAtCache.end()) return cast(CachedInlinedAt->second); auto L = decodeDebugLoc(CS->Loc); auto Scope = getOrCreateScope(CS->Parent.dyn_cast()); // Pretend transparent functions don't exist. if (!Scope) return createInlinedAt(CS); auto InlinedAt = llvm::DebugLoc::get(L.Line, L.Column, Scope, createInlinedAt(CS)); InlinedAtCache.insert( {CS, llvm::TrackingMDNodeRef(InlinedAt.getAsMDNode())}); return InlinedAt; } #ifndef NDEBUG /// Perform a couple of sanity checks on scopes. static bool parentScopesAreSane(const SILDebugScope *DS) { auto *Parent = DS; while ((Parent = Parent->Parent.dyn_cast())) { if (!DS->InlinedCallSite) assert(!Parent->InlinedCallSite && "non-inlined scope has an inlined parent"); } return true; } /// Assert that within one lexical block, each location is only visited once. bool lineEntryIsSane(SILLocation::DebugLoc DL, const SILDebugScope *DS); #endif llvm::DIFile *getOrCreateFile(StringRef Filename) { if (Filename.empty()) Filename = SILLocation::getCompilerGeneratedDebugLoc().Filename; // 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); } // Detect the main file. StringRef MainFileName = MainFile->getFilename(); if (MainFile && Filename.endswith(MainFileName)) { SmallString<256> AbsThisFile, AbsMainFile; AbsThisFile = Filename; llvm::sys::fs::make_absolute(AbsThisFile); if (llvm::sys::path::is_absolute(MainFileName)) AbsMainFile = MainFileName; else llvm::sys::path::append(AbsMainFile, MainFile->getDirectory(), MainFileName); if (AbsThisFile == DebugPrefixMap.remapPath(AbsMainFile)) { DIFileCache[Filename] = llvm::TrackingMDNodeRef(MainFile); return MainFile; } } return createFile(Filename, None, None); } /// This is effectively \p clang::CGDebugInfo::createFile(). llvm::DIFile * createFile(StringRef FileName, Optional> CSInfo, Optional Source) { StringRef Dir; StringRef File; SmallString<128> DirBuf; SmallString<128> FileBuf; std::string RemappedFileString = DebugPrefixMap.remapPath(FileName); SmallString<128> RemappedFile = StringRef(RemappedFileString); llvm::sys::path::remove_dots(RemappedFile); std::string CurDir = DebugPrefixMap.remapPath(Opts.DebugCompilationDir); if (llvm::sys::path::is_absolute(RemappedFile)) { // Strip the common prefix (if it is more than just "/") from current // directory and FileName for a more space-efficient encoding. auto FileIt = llvm::sys::path::begin(RemappedFile); auto FileE = llvm::sys::path::end(RemappedFile); auto CurDirIt = llvm::sys::path::begin(CurDir); auto CurDirE = llvm::sys::path::end(CurDir); for (; CurDirIt != CurDirE && *CurDirIt == *FileIt; ++CurDirIt, ++FileIt) llvm::sys::path::append(DirBuf, *CurDirIt); if (std::distance(llvm::sys::path::begin(CurDir), CurDirIt) == 1) { // Don't strip the common prefix if it is only the root "/" // since that would make LLVM diagnostic locations confusing. Dir = {}; File = RemappedFile; } else { for (; FileIt != FileE; ++FileIt) llvm::sys::path::append(FileBuf, *FileIt); Dir = DirBuf; File = FileBuf; } } else { File = RemappedFile; // Leave & friends as is, without directory. if (!(File.startswith("<") && File.endswith(">"))) Dir = CurDir; } llvm::DIFile *F = DBuilder.createFile(File, Dir, CSInfo, Source); DIFileCache[FileName].reset(F); return F; } StringRef getName(const FuncDecl &FD) { // Getters and Setters are anonymous functions, so we forge a name // using its parent declaration. if (auto accessor = dyn_cast(&FD)) if (ValueDecl *VD = accessor->getStorage()) { const char *Kind; switch (accessor->getAccessorKind()) { case AccessorKind::Get: Kind = ".get"; break; case AccessorKind::Set: Kind = ".set"; break; case AccessorKind::WillSet: Kind = ".willset"; break; case AccessorKind::DidSet: Kind = ".didset"; break; case AccessorKind::Address: Kind = ".addressor"; break; case AccessorKind::MutableAddress: Kind = ".mutableAddressor"; break; case AccessorKind::Read: Kind = ".read"; break; case AccessorKind::Modify: Kind = ".modify"; break; } SmallVector Buf; StringRef Name = (VD->getBaseName().userFacingName() + Twine(Kind)).toStringRef(Buf); return BumpAllocatedString(Name); } if (FD.hasName()) return FD.getBaseIdentifier().str(); return StringRef(); } StringRef 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) { LLVM_DEBUG(llvm::dbgs() << "Unexpected function type: "; SILTy.print(llvm::dbgs()); llvm::dbgs() << "\n"); return CanSILFunctionType(); } return FnTy; } llvm::DIScope *getOrCreateContext(DeclContext *DC) { if (!DC) return TheCU; if (isa(DC)) if (auto *Decl = IGM.getSILModule().lookUpFunction(SILDeclRef( cast(DC), SILDeclRef::Kind::Func))) return getOrCreateScope(Decl->getDebugScope()); switch (DC->getContextKind()) { // The interesting cases are already handled above. case DeclContextKind::AbstractFunctionDecl: case DeclContextKind::AbstractClosureExpr: // We don't model these in DWARF. case DeclContextKind::SerializedLocal: case DeclContextKind::Initializer: case DeclContextKind::ExtensionDecl: case DeclContextKind::SubscriptDecl: case DeclContextKind::EnumElementDecl: case DeclContextKind::TopLevelCodeDecl: return getOrCreateContext(DC->getParent()); case DeclContextKind::Module: return getOrCreateModule( {ModuleDecl::AccessPathTy(), cast(DC)}); case DeclContextKind::FileUnit: // A module may contain multiple files. return getOrCreateContext(DC->getParent()); case DeclContextKind::GenericTypeDecl: { auto *NTD = cast(DC); auto *Ty = NTD->getDeclaredType().getPointer(); if (auto *DITy = getTypeOrNull(Ty)) return DITy; // Create a Forward-declared type. auto Loc = getDebugLoc(*this, NTD); auto File = getOrCreateFile(Loc.Filename); auto Line = Loc.Line; auto FwdDecl = DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_structure_type, NTD->getName().str(), getOrCreateContext(DC->getParent()), File, Line, llvm::dwarf::DW_LANG_Swift, 0, 0); ReplaceMap.emplace_back( std::piecewise_construct, std::make_tuple(Ty), std::make_tuple(static_cast(FwdDecl))); return FwdDecl; } } return TheCU; } void createParameterType(llvm::SmallVectorImpl &Parameters, SILType type) { auto RealType = type.getASTType(); auto DbgTy = DebugTypeInfo::getFromTypeInfo(RealType, IGM.getTypeInfo(type)); Parameters.push_back(getOrCreateType(DbgTy)); } // This is different from SILFunctionType::getAllResultsType() in some subtle // ways. static SILType getResultTypeForDebugInfo(IRGenModule &IGM, CanSILFunctionType fnTy) { if (fnTy->getNumResults() == 1) { return fnTy->getResults()[0].getSILStorageType(IGM.getSILModule(), fnTy); } else if (!fnTy->getNumIndirectFormalResults()) { return fnTy->getDirectFormalResultsType(IGM.getSILModule()); } else { SmallVector eltTys; for (auto &result : fnTy->getResults()) { eltTys.push_back(result.getReturnValueType(IGM.getSILModule(), fnTy)); } return SILType::getPrimitiveAddressType( CanType(TupleType::get(eltTys, fnTy->getASTContext()))); } } llvm::DITypeRefArray createParameterTypes(SILType SILTy) { if (!SILTy) return nullptr; return createParameterTypes(SILTy.castTo()); } llvm::DITypeRefArray createParameterTypes(CanSILFunctionType FnTy) { SmallVector Parameters; GenericContextScope scope(IGM, FnTy->getInvocationGenericSignature()); // The function return type is the first element in the list. createParameterType(Parameters, getResultTypeForDebugInfo(IGM, FnTy)); // 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, IGM.silConv.getSILType(Param, FnTy)); 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::DIModule *getOrCreateModule(const void *Key, llvm::DIScope *Parent, StringRef Name, StringRef IncludePath, uint64_t Signature = ~1ULL, StringRef ASTFile = StringRef()) { // Look in the cache first. auto Val = DIModuleCache.find(Key); if (Val != DIModuleCache.end()) return cast(Val->second); std::string RemappedIncludePath = DebugPrefixMap.remapPath(IncludePath); // For Clang modules / PCH, create a Skeleton CU pointing to the PCM/PCH. if (!Opts.DisableClangModuleSkeletonCUs) { bool CreateSkeletonCU = !ASTFile.empty(); bool IsRootModule = !Parent; if (CreateSkeletonCU && IsRootModule) { llvm::DIBuilder DIB(M); DIB.createCompileUnit(IGM.ObjCInterop ? llvm::dwarf::DW_LANG_ObjC : llvm::dwarf::DW_LANG_C99, DIB.createFile(Name, RemappedIncludePath), TheCU->getProducer(), true, StringRef(), 0, ASTFile, llvm::DICompileUnit::FullDebug, Signature); DIB.finalize(); } } llvm::DIModule *M = DBuilder.createModule(Parent, Name, ConfigMacros, RemappedIncludePath); DIModuleCache.insert({Key, llvm::TrackingMDNodeRef(M)}); return M; } using ASTSourceDescriptor = clang::ExternalASTSource::ASTSourceDescriptor; /// Create a DIModule from a clang module or PCH. /// The clang::Module pointer is passed separately because the recursive case /// needs to fudge the AST descriptor. llvm::DIModule *getOrCreateModule(ASTSourceDescriptor Desc, const clang::Module *ClangModule) { // PCH files don't have a signature field in the control block, // but LLVM detects skeleton CUs by looking for a non-zero DWO id. // We use the lower 64 bits for debug info. uint64_t Signature = Desc.getSignature() ? (uint64_t)Desc.getSignature()[1] << 32 | Desc.getSignature()[0] : ~1ULL; // Handle Clang modules. if (ClangModule) { llvm::DIModule *Parent = nullptr; if (ClangModule->Parent) { // The loading of additional modules by Sema may trigger an out-of-date // PCM rebuild in the Clang module dependencies of the additional // module. A PCM rebuild causes the ModuleManager to unload previously // loaded ASTFiles. For this reason we must use the cached ASTFile // information here instead of the potentially dangling pointer to the // ASTFile that is stored in the clang::Module object. // // Note: The implementation here assumes that all clang submodules // belong to the same PCM file. ASTSourceDescriptor ParentDescriptor(*ClangModule->Parent); Parent = getOrCreateModule({ParentDescriptor.getModuleName(), ParentDescriptor.getPath(), Desc.getASTFile(), Desc.getSignature()}, ClangModule->Parent); } return getOrCreateModule(ClangModule, Parent, Desc.getModuleName(), Desc.getPath(), Signature, Desc.getASTFile()); } // Handle PCH. return getOrCreateModule(Desc.getASTFile().bytes_begin(), nullptr, Desc.getModuleName(), Desc.getPath(), Signature, Desc.getASTFile()); }; static Optional getClangModule(const ModuleDecl &M) { for (auto *FU : M.getFiles()) if (auto *CMU = dyn_cast_or_null(FU)) if (auto Desc = CMU->getASTSourceDescriptor()) return Desc; return None; } llvm::DIModule *getOrCreateModule(ModuleDecl::ImportedModule IM) { ModuleDecl *M = IM.second; if (Optional ModuleDesc = getClangModule(*M)) return getOrCreateModule(*ModuleDesc, ModuleDesc->getModuleOrNull()); StringRef Path = getFilenameFromDC(M); StringRef Name = M->getName().str(); return getOrCreateModule(M, TheCU, Name, Path); } TypeAliasDecl *getMetadataType(StringRef ArchetypeName) { TypeAliasDecl *&Entry = MetadataTypeDeclCache[ArchetypeName]; if (Entry) return Entry; SourceLoc NoLoc; Entry = new (IGM.Context) TypeAliasDecl( NoLoc, NoLoc, IGM.Context.getIdentifier(ArchetypeName), NoLoc, /*genericparams*/ nullptr, IGM.Context.TheBuiltinModule); Entry->setUnderlyingType(IGM.Context.TheRawPointerType); return Entry; } /// Return the DIFile that is the ancestor of Scope. llvm::DIFile *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: Scope = cast(Scope)->getFile(); break; default: return MainFile; } if (Scope) return MainFile; } return cast(Scope); } 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); } StringRef getMangledName(DebugTypeInfo DbgTy) { if (DbgTy.IsMetadataType) return MetadataTypeDeclCache.find(DbgTy.getDecl()->getName().str()) ->getKey(); Type Ty = DbgTy.getType(); if (!Ty->hasTypeParameter()) Ty = Ty->mapTypeOutOfContext(); // Strip off top level of type sugar (except for type aliases). // We don't want Optional and T? to get different debug types. while (true) { if (auto *ParenTy = dyn_cast(Ty.getPointer())) { Ty = ParenTy->getUnderlyingType(); continue; } if (auto *SugarTy = dyn_cast(Ty.getPointer())) { Ty = SugarTy->getSinglyDesugaredType(); continue; } break; } // TODO: Eliminate substitutions in SILFunctionTypes for now. // On platforms where the substitutions affect representation, we will need // to preserve this info and teach type reconstruction about it. Ty = Ty->replaceSubstitutedSILFunctionTypesWithUnsubstituted(IGM.getSILModule()); Mangle::ASTMangler Mangler; std::string Result = Mangler.mangleTypeForDebugger( Ty, nullptr); if (!Opts.DisableRoundTripDebugTypes) { // Make sure we can reconstruct mangled types for the debugger. #ifndef NDEBUG auto &Ctx = Ty->getASTContext(); Type Reconstructed = Demangle::getTypeForMangling(Ctx, Result); if (!Reconstructed) { llvm::errs() << "Failed to reconstruct type for " << Result << "\n"; llvm::errs() << "Original type:\n"; Ty->dump(llvm::errs()); abort(); } else if (!Reconstructed->isEqual(Ty)) { llvm::errs() << "Incorrect reconstructed type for " << Result << "\n"; llvm::errs() << "Original type:\n"; Ty->dump(llvm::errs()); llvm::errs() << "Reconstructed type:\n"; Reconstructed->dump(llvm::errs()); abort(); } #endif } return BumpAllocatedString(Result); } llvm::DIDerivedType *createMemberType(DebugTypeInfo DbgTy, StringRef Name, unsigned &OffsetInBits, llvm::DIScope *Scope, llvm::DIFile *File, llvm::DINode::DIFlags Flags) { unsigned SizeOfByte = CI.getTargetInfo().getCharWidth(); auto *Ty = getOrCreateType(DbgTy); auto *DITy = DBuilder.createMemberType(Scope, Name, File, 0, SizeOfByte * DbgTy.size.getValue(), 0, OffsetInBits, Flags, Ty); OffsetInBits += getSizeInBits(Ty); OffsetInBits = llvm::alignTo(OffsetInBits, SizeOfByte * DbgTy.align.getValue()); return DITy; } llvm::DINodeArray getTupleElements(TupleType *TupleTy, llvm::DIScope *Scope, llvm::DIFile *File, llvm::DINode::DIFlags Flags, unsigned &SizeInBits) { SmallVector Elements; unsigned OffsetInBits = 0; auto genericSig = IGM.getCurGenericContext(); for (auto ElemTy : TupleTy->getElementTypes()) { auto &elemTI = IGM.getTypeInfoForUnlowered( AbstractionPattern(genericSig, ElemTy->getCanonicalType()), ElemTy); auto DbgTy = DebugTypeInfo::getFromTypeInfo(ElemTy, elemTI); Elements.push_back(createMemberType(DbgTy, StringRef(), OffsetInBits, Scope, File, Flags)); } SizeInBits = OffsetInBits; return DBuilder.getOrCreateArray(Elements); } llvm::DINodeArray getStructMembers(NominalTypeDecl *D, Type BaseTy, llvm::DIScope *Scope, llvm::DIFile *File, llvm::DINode::DIFlags Flags, unsigned &SizeInBits) { SmallVector Elements; unsigned OffsetInBits = 0; for (VarDecl *VD : D->getStoredProperties()) { auto memberTy = BaseTy->getTypeOfMember(IGM.getSwiftModule(), VD, nullptr); auto DbgTy = DebugTypeInfo::getFromTypeInfo( VD->getInterfaceType(), IGM.getTypeInfoForUnlowered( IGM.getSILTypes().getAbstractionPattern(VD), memberTy)); Elements.push_back(createMemberType(DbgTy, VD->getName().str(), OffsetInBits, Scope, File, Flags)); } if (OffsetInBits > SizeInBits) SizeInBits = OffsetInBits; return DBuilder.getOrCreateArray(Elements); } llvm::DICompositeType * createStructType(DebugTypeInfo DbgTy, NominalTypeDecl *Decl, Type BaseTy, llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line, unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags, llvm::DIType *DerivedFrom, unsigned RuntimeLang, StringRef UniqueID) { 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, 0, Flags, UniqueID)); #ifndef NDEBUG if (UniqueID.empty()) assert(!Name.empty() && "no mangled name and no human readable name given"); else assert((UniqueID.startswith("_T") || UniqueID.startswith(MANGLING_PREFIX_STR)) && "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; } llvm::DINodeArray getEnumElements(DebugTypeInfo DbgTy, EnumDecl *ED, llvm::DIScope *Scope, llvm::DIFile *File, llvm::DINode::DIFlags Flags) { SmallVector Elements; for (auto *ElemDecl : ED->getAllElements()) { // FIXME Support enums. // Swift Enums can be both like DWARF enums and discriminated unions. DebugTypeInfo ElemDbgTy; if (ED->hasRawType()) // An enum with a raw type (enum E : Int {}), similar to a // DWARF enum. // // The storage occupied by the enum may be smaller than the // one of the raw type as long as it is large enough to hold // all enum values. Use the raw type for the debug type, but // the storage size from the enum. ElemDbgTy = DebugTypeInfo(ED->getRawType(), DbgTy.StorageType, DbgTy.size, DbgTy.align, true, false); else if (auto ArgTy = ElemDecl->getArgumentInterfaceType()) { // A discriminated union. This should really be described as a // DW_TAG_variant_type. For now only describing the data. ArgTy = ElemDecl->getParentEnum()->mapTypeIntoContext(ArgTy); auto &TI = IGM.getTypeInfoForUnlowered(ArgTy); ElemDbgTy = DebugTypeInfo::getFromTypeInfo(ArgTy, TI); } else { // Discriminated union case without argument. Fallback to Int // as the element type; there is no storage here. Type IntTy = IGM.Context.getIntDecl()->getDeclaredType(); ElemDbgTy = DebugTypeInfo(IntTy, DbgTy.StorageType, Size(0), Alignment(1), true, false); } unsigned Offset = 0; auto MTy = createMemberType(ElemDbgTy, ElemDecl->getBaseIdentifier().str(), Offset, Scope, File, Flags); Elements.push_back(MTy); } return DBuilder.getOrCreateArray(Elements); } llvm::DICompositeType *createEnumType(DebugTypeInfo DbgTy, EnumDecl *Decl, StringRef MangledName, llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line, llvm::DINode::DIFlags Flags) { unsigned SizeOfByte = CI.getTargetInfo().getCharWidth(); unsigned SizeInBits = DbgTy.size.getValue() * SizeOfByte; // Default, since Swift doesn't allow specifying a custom alignment. unsigned AlignInBits = 0; // 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; } llvm::DIType *getOrCreateDesugaredType(Type Ty, DebugTypeInfo DbgTy) { DebugTypeInfo BlandDbgTy(Ty, DbgTy.StorageType, DbgTy.size, DbgTy.align, DbgTy.DefaultAlignment, DbgTy.IsMetadataType); return getOrCreateType(BlandDbgTy); } uint64_t 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.getLargestLegalIntTypeSizeInBits()); return BitWidth; } /// Create a sized container for a sizeless type. Used to represent /// BoundGenericEnums that may have different sizes depending on what they are /// bound to, but still share a mangled name. llvm::DIType *createOpaqueStructWithSizedContainer( llvm::DIScope *Scope, StringRef Name, llvm::DIFile *File, unsigned Line, unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags, StringRef MangledName) { // Let the MDNode folding set do the work of uniquing the inner type. This // should be cheap. llvm::DICompositeType *UniqueType = DBuilder.createStructType( Scope, Name, File, Line, 0, 0, Flags, nullptr, DBuilder.getOrCreateArray(ArrayRef()), llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); llvm::Metadata *Elements[] = { DBuilder.createMemberType(Scope, "", File, 0, SizeInBits, AlignInBits, 0, Flags, UniqueType)}; return DBuilder.createStructType( Scope, "", File, Line, SizeInBits, AlignInBits, Flags, /* DerivedFrom */ nullptr, DBuilder.getOrCreateArray(Elements), llvm::dwarf::DW_LANG_Swift); } llvm::DIType *createPointerSizedStruct(llvm::DIScope *Scope, StringRef Name, llvm::DIFile *File, unsigned Line, llvm::DINode::DIFlags Flags, StringRef MangledName) { if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) { 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); } else { unsigned SizeInBits = CI.getTargetInfo().getPointerWidth(0); return createOpaqueStruct(Scope, Name, File, Line, SizeInBits, 0, Flags, MangledName); } } llvm::DIType *createPointerSizedStruct(llvm::DIScope *Scope, StringRef Name, llvm::DIType *PointeeTy, llvm::DIFile *File, unsigned Line, llvm::DINode::DIFlags Flags, StringRef MangledName) { unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); auto PtrTy = DBuilder.createPointerType(PointeeTy, PtrSize, 0); llvm::Metadata *Elements[] = {DBuilder.createMemberType( Scope, "ptr", File, 0, PtrSize, 0, 0, Flags, PtrTy)}; return DBuilder.createStructType( Scope, Name, File, Line, PtrSize, 0, Flags, /* DerivedFrom */ nullptr, DBuilder.getOrCreateArray(Elements), llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); } llvm::DIType * createDoublePointerSizedStruct(llvm::DIScope *Scope, StringRef Name, llvm::DIType *PointeeTy, llvm::DIFile *File, unsigned Line, llvm::DINode::DIFlags Flags, StringRef MangledName) { unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); llvm::Metadata *Elements[] = { DBuilder.createMemberType( Scope, "ptr", File, 0, PtrSize, 0, 0, Flags, DBuilder.createPointerType(PointeeTy, PtrSize, 0)), DBuilder.createMemberType( Scope, "_", File, 0, PtrSize, 0, 0, Flags, DBuilder.createPointerType(nullptr, PtrSize, 0))}; return DBuilder.createStructType( Scope, Name, File, Line, 2 * PtrSize, 0, Flags, /* DerivedFrom */ nullptr, DBuilder.getOrCreateArray(Elements), llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); } llvm::DIType *createFixedValueBufferStruct(llvm::DIType *PointeeTy) { unsigned Line = 0; unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); llvm::DINode::DIFlags Flags = llvm::DINode::FlagArtificial; llvm::DIFile *File = MainFile; llvm::DIScope *Scope = TheCU; llvm::Metadata *Elements[] = {DBuilder.createMemberType( Scope, "contents", File, 0, PtrSize, 0, 0, Flags, PointeeTy)}; return DBuilder.createStructType( Scope, "$swift.fixedbuffer", File, Line, 3 * PtrSize, 0, Flags, /* DerivedFrom */ nullptr, DBuilder.getOrCreateArray(Elements), llvm::dwarf::DW_LANG_Swift, nullptr); } llvm::DIType *createFunctionPointer(DebugTypeInfo DbgTy, llvm::DIScope *Scope, unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags, StringRef MangledName) { auto FwdDecl = llvm::TempDINode(DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_subroutine_type, MangledName, Scope, MainFile, 0, llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags, MangledName)); auto TH = llvm::TrackingMDNodeRef(FwdDecl.get()); DITypeCache[DbgTy.getType()] = TH; CanSILFunctionType FunTy; TypeBase *BaseTy = DbgTy.getType(); if (auto *SILFnTy = dyn_cast(BaseTy)) FunTy = 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)) { auto *fTy = cast(BaseTy); auto *nongenericTy = FunctionType::get(fTy->getParams(), fTy->getResult(), fTy->getExtInfo()); FunTy = IGM.getLoweredType(nongenericTy).castTo(); } else FunTy = IGM.getLoweredType(BaseTy).castTo(); auto Params = createParameterTypes(FunTy); auto FnTy = DBuilder.createSubroutineType(Params, Flags); llvm::DIType *DITy; if (FunTy->getRepresentation() == SILFunctionType::Representation::Thick) { if (SizeInBits == 2 * CI.getTargetInfo().getPointerWidth(0)) // This is a FunctionPairTy: { i8*, %swift.refcounted* }. DITy = createDoublePointerSizedStruct(Scope, MangledName, FnTy, MainFile, 0, Flags, MangledName); else // This is a generic function as noted above. DITy = createOpaqueStruct(Scope, MangledName, MainFile, 0, SizeInBits, AlignInBits, Flags, MangledName); } else { assert(SizeInBits == CI.getTargetInfo().getPointerWidth(0)); DITy = createPointerSizedStruct(Scope, MangledName, FnTy, MainFile, 0, Flags, MangledName); } DBuilder.replaceTemporary(std::move(FwdDecl), DITy); return DITy; } llvm::DIType *createTuple(DebugTypeInfo DbgTy, llvm::DIScope *Scope, unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags, StringRef MangledName) { TypeBase *BaseTy = DbgTy.getType(); auto *TupleTy = BaseTy->castTo(); auto FwdDecl = llvm::TempDINode(DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, MainFile, 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, RealSize); // FIXME: Handle %swift.opaque members and make this into an assertion. if (!RealSize) RealSize = SizeInBits; auto DITy = DBuilder.createStructType( Scope, MangledName, MainFile, 0, RealSize, AlignInBits, Flags, nullptr, // DerivedFrom Elements, llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); DBuilder.replaceTemporary(std::move(FwdDecl), DITy); return DITy; } llvm::DIType *createOpaqueStruct(llvm::DIScope *Scope, StringRef Name, llvm::DIFile *File, unsigned Line, unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags, StringRef MangledName) { return DBuilder.createStructType( Scope, Name, File, Line, SizeInBits, AlignInBits, Flags, /* DerivedFrom */ nullptr, DBuilder.getOrCreateArray(ArrayRef()), llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); } llvm::DIType *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; unsigned AlignInBits = DbgTy.DefaultAlignment ? 0 : DbgTy.align.getValue() * SizeOfByte; unsigned Encoding = 0; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; TypeBase *BaseTy = DbgTy.getType(); if (!BaseTy) { LLVM_DEBUG(llvm::dbgs() << "Type without TypeBase: "; DbgTy.getType()->dump(llvm::dbgs()); 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::BuiltinIntegerLiteral: { 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::BuiltinNativeObject: { unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); auto PTy = DBuilder.createPointerType(nullptr, PtrSize, 0, /* DWARFAddressSpace */ None, MangledName); return DBuilder.createObjectPointerType(PTy); } case TypeKind::BuiltinBridgeObject: { unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); auto PTy = DBuilder.createPointerType(nullptr, PtrSize, 0, /* DWARFAddressSpace */ None, MangledName); return DBuilder.createObjectPointerType(PTy); } case TypeKind::BuiltinRawPointer: { unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0); return DBuilder.createPointerType(nullptr, PtrSize, 0, /* DWARFAddressSpace */ None, 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(); auto L = getDebugLoc(*this, Decl); auto *File = getOrCreateFile(L.Filename); if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) return createStructType(DbgTy, Decl, StructTy, Scope, File, L.Line, SizeInBits, AlignInBits, Flags, nullptr, // DerivedFrom llvm::dwarf::DW_LANG_Swift, MangledName); else return createOpaqueStruct(Scope, Decl->getName().str(), File, L.Line, SizeInBits, AlignInBits, Flags, 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(); auto L = getDebugLoc(*this, Decl); assert(SizeInBits == CI.getTargetInfo().getPointerWidth(0)); 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. auto L = getDebugLoc(*this, Decl); auto File = getOrCreateFile(L.Filename); return createOpaqueStruct(Scope, Decl ? Decl->getNameStr() : MangledName, File, L.Line, SizeInBits, AlignInBits, Flags, MangledName); } case TypeKind::ProtocolComposition: { auto *Decl = DbgTy.getDecl(); auto L = getDebugLoc(*this, Decl); auto File = getOrCreateFile(L.Filename); // FIXME: emit types // auto ProtocolCompositionTy = BaseTy->castTo(); return createOpaqueStruct(Scope, Decl ? Decl->getNameStr() : MangledName, File, L.Line, SizeInBits, AlignInBits, Flags, MangledName); } case TypeKind::UnboundGeneric: { auto *UnboundTy = BaseTy->castTo(); auto *Decl = UnboundTy->getDecl(); auto L = getDebugLoc(*this, Decl); assert(SizeInBits == CI.getTargetInfo().getPointerWidth(0)); return createPointerSizedStruct(Scope, Decl ? Decl->getNameStr() : MangledName, File, L.Line, Flags, MangledName); } case TypeKind::BoundGenericStruct: { auto *StructTy = BaseTy->castTo(); auto *Decl = StructTy->getDecl(); auto L = getDebugLoc(*this, Decl); return createOpaqueStructWithSizedContainer( Scope, Decl ? Decl->getNameStr() : "", File, L.Line, SizeInBits, AlignInBits, Flags, MangledName); } case TypeKind::BoundGenericClass: { auto *ClassTy = BaseTy->castTo(); auto *Decl = ClassTy->getDecl(); auto L = getDebugLoc(*this, Decl); // TODO: We may want to peek at Decl->isObjC() and set this // attribute accordingly. assert(SizeInBits == CI.getTargetInfo().getPointerWidth(0)); return createPointerSizedStruct(Scope, Decl ? Decl->getNameStr() : MangledName, File, L.Line, Flags, MangledName); } case TypeKind::Tuple: { // Tuples are also represented as structs. if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) return createTuple(DbgTy, Scope, SizeInBits, AlignInBits, Flags, MangledName); else return createOpaqueStruct(Scope, MangledName, MainFile, 0, SizeInBits, AlignInBits, Flags, MangledName); } case TypeKind::InOut: break; case TypeKind::OpaqueTypeArchetype: case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: case TypeKind::NestedArchetype: { auto *Archetype = BaseTy->castTo(); AssociatedTypeDecl *assocType = nullptr; if (auto nested = dyn_cast(Archetype)) assocType = nested->getAssocType(); auto L = getDebugLoc(*this, assocType); 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.getLoweredType(ProtocolDecl->getInterfaceType()) .getASTType(); auto PDbgTy = DebugTypeInfo::getFromTypeInfo( ProtocolDecl->getInterfaceType(), IGM.getTypeInfoForLowered(PTy)); auto PDITy = getOrCreateType(PDbgTy); Protocols.push_back( DBuilder.createInheritance(FwdDecl.get(), PDITy, 0, 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; auto L = getDebugLoc(*this, 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::GenericFunction: { if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) return createFunctionPointer(DbgTy, Scope, SizeInBits, AlignInBits, Flags, MangledName); else return createOpaqueStruct(Scope, MangledName, MainFile, 0, SizeInBits, AlignInBits, Flags, MangledName); } case TypeKind::Enum: { auto *EnumTy = BaseTy->castTo(); auto *Decl = EnumTy->getDecl(); auto L = getDebugLoc(*this, Decl); auto *File = getOrCreateFile(L.Filename); if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) return createEnumType(DbgTy, Decl, MangledName, Scope, File, L.Line, Flags); else return createOpaqueStruct(Scope, Decl->getName().str(), File, L.Line, SizeInBits, AlignInBits, Flags, MangledName); } case TypeKind::BoundGenericEnum: { auto *EnumTy = BaseTy->castTo(); auto *Decl = EnumTy->getDecl(); auto L = getDebugLoc(*this, Decl); auto *File = getOrCreateFile(L.Filename); return createOpaqueStructWithSizedContainer( Scope, Decl->getName().str(), File, L.Line, SizeInBits, AlignInBits, Flags, MangledName); } case TypeKind::BuiltinVector: { (void)MangledName; // FIXME emit the name somewhere. auto *BuiltinVectorTy = BaseTy->castTo(); auto ElemTy = BuiltinVectorTy->getElementType(); auto ElemDbgTy = DebugTypeInfo::getFromTypeInfo( ElemTy, IGM.getTypeInfoForUnlowered(ElemTy)); unsigned Count = BuiltinVectorTy->getNumElements(); auto Subscript = DBuilder.getOrCreateSubrange(0, Count ? Count : -1); return DBuilder.createVectorType(SizeInBits, AlignInBits, getOrCreateType(ElemDbgTy), DBuilder.getOrCreateArray(Subscript)); } // Reference storage types. #define REF_STORAGE(Name, ...) \ case TypeKind::Name##Storage: #include "swift/AST/ReferenceStorage.def" { auto *ReferenceTy = cast(BaseTy); auto CanTy = ReferenceTy->getReferentType(); auto L = getDebugLoc(*this, DbgTy.getDecl()); auto File = getOrCreateFile(L.Filename); return DBuilder.createTypedef(getOrCreateDesugaredType(CanTy, DbgTy), MangledName, File, L.Line, File); } // Sugared types. case TypeKind::TypeAlias: { auto *TypeAliasTy = cast(BaseTy); auto *Decl = TypeAliasTy->getDecl(); auto L = getDebugLoc(*this, Decl); auto AliasedTy = TypeAliasTy->getSinglyDesugaredType(); auto File = getOrCreateFile(L.Filename); // For TypeAlias 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.DefaultAlignment, false); return DBuilder.createTypedef(getOrCreateType(AliasedDbgTy), MangledName, File, L.Line, Scope); } case TypeKind::Paren: { auto Ty = cast(BaseTy)->getUnderlyingType(); return getOrCreateDesugaredType(Ty, DbgTy); } // SyntaxSugarType derivations. case TypeKind::Dictionary: case TypeKind::ArraySlice: case TypeKind::Optional: { auto *SyntaxSugarTy = cast(BaseTy); auto *CanTy = SyntaxSugarTy->getSinglyDesugaredType(); return getOrCreateDesugaredType(CanTy, DbgTy); } case TypeKind::DependentMember: case TypeKind::GenericTypeParam: { // FIXME: Provide a more meaningful debug type. return DBuilder.createStructType( Scope, MangledName, File, 0, SizeInBits, AlignInBits, Flags, nullptr, nullptr, llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); } // The following types exist primarily for internal use by the type // checker. case TypeKind::Error: case TypeKind::Unresolved: case TypeKind::LValue: case TypeKind::TypeVariable: case TypeKind::Module: case TypeKind::SILBlockStorage: case TypeKind::SILBox: case TypeKind::SILToken: case TypeKind::BuiltinUnsafeValueBuffer: LLVM_DEBUG(llvm::dbgs() << "Unhandled type: "; DbgTy.getType()->dump(llvm::dbgs()); llvm::dbgs() << "\n"); MangledName = ""; } return DBuilder.createBasicType(MangledName, SizeInBits, Encoding); } /// Determine if there exists a name mangling for the given type. static bool canMangle(TypeBase *Ty) { switch (Ty->getKind()) { case TypeKind::GenericFunction: // Not yet supported. case TypeKind::SILBlockStorage: // Not supported at all. case TypeKind::SILBox: return false; default: return true; } } llvm::DIType *getTypeOrNull(TypeBase *Ty) { auto CachedType = DITypeCache.find(Ty); if (CachedType != DITypeCache.end()) { // Verify that the information still exists. if (llvm::Metadata *Val = CachedType->second) { auto DITy = cast(Val); return DITy; } } return nullptr; } /// The private discriminator is represented as an inline namespace. llvm::DIScope *getFilePrivateScope(llvm::DIScope *Parent, TypeDecl *Decl) { // Retrieve the private discriminator. auto *MSC = Decl->getDeclContext()->getModuleScopeContext(); auto *FU = cast(MSC); Identifier PD = FU->getDiscriminatorForPrivateValue(Decl); bool ExportSymbols = true; return DBuilder.createNameSpace(Parent, PD.str(), ExportSymbols); } llvm::DIType *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. if (auto *DITy = getTypeOrNull(DbgTy.getType())) 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. llvm::DIScope *Scope = nullptr; // Make sure to retrieve the context of the type alias, not the pointee. DeclContext *Context = nullptr; const Decl *TypeDecl = nullptr; const clang::Decl *ClangDecl = nullptr; if (auto Alias = dyn_cast(DbgTy.getType())) { TypeAliasDecl *AliasDecl = Alias->getDecl(); TypeDecl = AliasDecl; Context = AliasDecl->getParent(); ClangDecl = AliasDecl->getClangDecl(); } else if (auto *ND = DbgTy.getType()->getNominalOrBoundGenericNominal()) { TypeDecl = ND; Context = ND->getParent(); ClangDecl = ND->getClangDecl(); } if (ClangDecl) { clang::ASTReader &Reader = *CI.getClangInstance().getASTReader(); auto Idx = ClangDecl->getOwningModuleID(); auto SubModuleDesc = Reader.getSourceDescriptor(Idx); auto TopLevelModuleDesc = getClangModule(*TypeDecl->getModuleContext()); if (SubModuleDesc) { if (TopLevelModuleDesc) // Describe the submodule, but substitute the cached ASTFile from // the toplevel module. The ASTFile pointer in SubModule may be // dangling and cant be trusted. Scope = getOrCreateModule({SubModuleDesc->getModuleName(), SubModuleDesc->getPath(), TopLevelModuleDesc->getASTFile(), TopLevelModuleDesc->getSignature()}, SubModuleDesc->getModuleOrNull()); else if (SubModuleDesc->getModuleOrNull() == nullptr) // This is (bridging header) PCH. Scope = getOrCreateModule(*SubModuleDesc, nullptr); } } if (!Scope) Scope = getOrCreateContext(Context); // Scope outermost fileprivate decls in an inline private discriminator // namespace. if (auto *Decl = DbgTy.getDecl()) if (Decl->isOutermostPrivateOrFilePrivateScope()) Scope = getFilePrivateScope(Scope, Decl); 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; } }; IRGenDebugInfoImpl::IRGenDebugInfoImpl(const IRGenOptions &Opts, ClangImporter &CI, IRGenModule &IGM, llvm::Module &M, StringRef MainOutputFilenameForDebugInfo, StringRef PD) : Opts(Opts), CI(CI), SM(IGM.Context.SourceMgr), M(M), DBuilder(M), IGM(IGM), DebugPrefixMap(Opts.DebugPrefixMap) { assert(Opts.DebugInfoLevel > IRGenDebugInfoLevel::None && "no debug info should be generated"); llvm::SmallString<256> SourcePath; if (MainOutputFilenameForDebugInfo.empty()) SourcePath = ""; else SourcePath = MainOutputFilenameForDebugInfo; unsigned Lang = llvm::dwarf::DW_LANG_Swift; std::string Producer = version::getSwiftFullVersion( IGM.Context.LangOpts.EffectiveLanguageVersion); unsigned Major, Minor; std::tie(Major, Minor) = version::getSwiftNumericVersion(); unsigned MajorRuntimeVersion = Major; // No split DWARF on Darwin. StringRef SplitName = StringRef(); // Note that File + Dir need not result in a valid path. // The directory part of the main file is the current working directory. MainFile = DBuilder.createFile(DebugPrefixMap.remapPath(SourcePath), DebugPrefixMap.remapPath(Opts.DebugCompilationDir)); StringRef Sysroot = IGM.Context.SearchPathOpts.SDKPath; StringRef SDK; { auto B = llvm::sys::path::rbegin(Sysroot); auto E = llvm::sys::path::rend(Sysroot); auto It = std::find_if(B, E, [](auto SDK) { return SDK.endswith(".sdk"); }); if (It != E) SDK = *It; } TheCU = DBuilder.createCompileUnit( Lang, MainFile, Producer, Opts.shouldOptimize(), Opts.getDebugFlags(PD), MajorRuntimeVersion, SplitName, Opts.DebugInfoLevel > IRGenDebugInfoLevel::LineTables ? llvm::DICompileUnit::FullDebug : llvm::DICompileUnit::LineTablesOnly, /* DWOId */ 0, /* SplitDebugInlining */ true, /* DebugInfoForProfiling */ false, llvm::DICompileUnit::DebugNameTableKind::Default, /* RangesBaseAddress */ false, Sysroot, SDK); // Because the swift compiler relies on Clang to setup the Module, // the clang CU is always created first. Several dwarf-reading // tools (older versions of ld64, and lldb) can get confused if the // first CU in an object is empty, so ensure that the Swift CU comes // first by rearranging the list of CUs in the LLVM module. llvm::NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu"); SmallVector CUs; for (auto *N : CU_Nodes->operands()) CUs.push_back(cast(N)); CU_Nodes->dropAllReferences(); for (auto CU = CUs.rbegin(), CE = CUs.rend(); CU != CE; ++CU) CU_Nodes->addOperand(*CU); // Create a module for the current compile unit. auto *MDecl = IGM.getSwiftModule(); llvm::sys::path::remove_filename(SourcePath); MainModule = getOrCreateModule(MDecl, TheCU, Opts.ModuleName, SourcePath); DBuilder.createImportedModule(MainFile, MainModule, MainFile, 0); // Macro definitions that were defined by the user with "-Xcc -D" on the // command line. This does not include any macros defined by ClangImporter. llvm::raw_svector_ostream OS(ConfigMacros); unsigned I = 0; // Translate the macro definitions back into a commmand line. for (auto &Macro : Opts.ClangDefines) { if (++I > 1) OS << ' '; OS << '"'; for (char c : Macro) switch (c) { case '\\': OS << "\\\\"; break; case '"': OS << "\\\""; break; default: OS << c; } OS << '"'; } } void IRGenDebugInfoImpl::finalize() { assert(LocationStack.empty() && "Mismatch of pushLoc() and popLoc()."); // Get the list of imported modules (which may actually be different // from all ImportDecls). ModuleDecl::ImportFilter ImportFilter; ImportFilter |= ModuleDecl::ImportFilterKind::Public; ImportFilter |= ModuleDecl::ImportFilterKind::Private; ImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; SmallVector ModuleWideImports; IGM.getSwiftModule()->getImportedModules(ModuleWideImports, ImportFilter); for (auto M : ModuleWideImports) if (!ImportedModules.count(M.second)) DBuilder.createImportedModule(MainFile, getOrCreateModule(M), MainFile, 0); // Finalize all replaceable forward declarations. for (auto &Ty : ReplaceMap) { llvm::TempMDNode FwdDecl(cast(Ty.second)); llvm::Metadata *Replacement; if (auto *FullType = getTypeOrNull(Ty.first)) Replacement = FullType; else Replacement = Ty.second; DBuilder.replaceTemporary(std::move(FwdDecl), cast(Replacement)); } // Finalize the DIBuilder. DBuilder.finalize(); } #ifndef NDEBUG bool IRGenDebugInfoImpl::lineEntryIsSane(SILLocation::DebugLoc DL, const SILDebugScope *DS) { // All bets are off for optimized code. if (!VerifyLineTable || Opts.shouldOptimize()) return true; // We entered a new lexical block. if (DS != LastScope) PreviousLineEntries.clear(); if (DL.Line == 0 || DL == PreviousDebugLoc) return true; // Save the last non-zero line entry. PreviousDebugLoc = DL; auto ItNew = PreviousLineEntries.insert(DebugLocKey(DL)); // Return true iff DL was not yet in PreviousLineEntries. return ItNew.second; } #endif void IRGenDebugInfoImpl::setCurrentLoc(IRBuilder &Builder, const SILDebugScope *DS, SILLocation Loc) { assert(DS && "empty scope"); auto *Scope = getOrCreateScope(DS); if (!Scope) return; // NOTE: In CodeView, zero is not an artificial line location. We try to // avoid those line locations near user code to reduce the number // of breaks in the linetables. SILLocation::DebugLoc L; SILFunction *Fn = DS->getInlinedFunction(); if (Fn && (Fn->isThunk() || Fn->isTransparent())) { L = SILLocation::getCompilerGeneratedDebugLoc(); } else if (DS == LastScope && Loc.isAutoGenerated()) { // Reuse the last source location if we are still in the same // scope to get a more contiguous line table. L = LastDebugLoc; } else if (DS == LastScope && (Loc.is() || Loc.isLineZero(SM)) && Opts.DebugInfoFormat == IRGenDebugInfoFormat::CodeView) { // If the scope has not changed and the line number is either zero or // artificial, we want to keep the most recent debug location. L = LastDebugLoc; } else { // Decode the location. L = getDebugLocation(Loc); // Otherwise use a line 0 artificial location, but the file from the // location. If we are emitting CodeView, we do not want to use line zero // since it does not represent an artificial line location. if (Loc.isAutoGenerated() && Opts.DebugInfoFormat != IRGenDebugInfoFormat::CodeView) { L.Line = 0; L.Column = 0; } } 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); } // FIXME: Enable this assertion. assert(lineEntryIsSane(L, DS) && "non-contiguous debug location in same scope at -Onone"); LastDebugLoc = L; LastScope = DS; auto *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.Column, Scope, InlinedAt); Builder.SetCurrentDebugLocation(DL); } void IRGenDebugInfoImpl::addFailureMessageToCurrentLoc(IRBuilder &Builder, StringRef failureMsg) { auto TrapLoc = Builder.getCurrentDebugLocation(); // Create a function in the debug info which has failureMsg as name. // TrapSc is the SIL debug scope which corresponds to TrapSP in the LLVM debug // info. RegularLocation ALoc = RegularLocation::getAutoGeneratedLocation(); const SILDebugScope *TrapSc = new (IGM.getSILModule()) SILDebugScope(ALoc); llvm::DISubroutineType *DIFnTy = DBuilder.createSubroutineType(nullptr); std::string FuncName = "Swift runtime failure: "; FuncName += failureMsg; llvm::DISubprogram *TrapSP = DBuilder.createFunction( MainModule, FuncName, StringRef(), TrapLoc->getFile(), 0, DIFnTy, 0, llvm::DINode::FlagArtificial, llvm::DISubprogram::SPFlagDefinition, nullptr, nullptr, nullptr); ScopeCache[TrapSc] = llvm::TrackingMDNodeRef(TrapSP); LastScope = TrapSc; assert(parentScopesAreSane(TrapSc) && "parent scope sanity check failed"); // Wrap the existing TrapLoc into the failure function. auto DL = llvm::DebugLoc::get(0, 0, TrapSP, TrapLoc); Builder.SetCurrentDebugLocation(DL); } void IRGenDebugInfoImpl::clearLoc(IRBuilder &Builder) { LastDebugLoc = {}; LastScope = nullptr; Builder.SetCurrentDebugLocation(llvm::DebugLoc()); } /// Push the current debug location onto a stack and initialize the /// IRBuilder to an empty location. void IRGenDebugInfoImpl::pushLoc() { LocationStack.push_back(std::make_pair(LastDebugLoc, LastScope)); LastDebugLoc = {}; LastScope = nullptr; } /// Restore the current debug location from the stack. void IRGenDebugInfoImpl::popLoc() { std::tie(LastDebugLoc, LastScope) = LocationStack.pop_back_val(); } /// This is done for WinDbg to avoid having two non-contiguous sets of /// instructions because the ``@llvm.trap`` instruction gets placed at the end /// of the function. void IRGenDebugInfoImpl::setInlinedTrapLocation(IRBuilder &Builder, const SILDebugScope *Scope) { if (Opts.DebugInfoFormat != IRGenDebugInfoFormat::CodeView) return; // The @llvm.trap could be inlined into a chunk of code that was also inlined. // If this is the case then simply using the LastScope's location would // generate debug info that claimed Function A owned Block X and Block X // thought it was owned by Function B. Therefore, we need to find the last // inlined scope to point to. const SILDebugScope *TheLastScope = LastScope; while (TheLastScope->InlinedCallSite && TheLastScope->InlinedCallSite != TheLastScope) { TheLastScope = TheLastScope->InlinedCallSite; } auto LastLocation = llvm::DebugLoc::get( LastDebugLoc.Line, LastDebugLoc.Column, getOrCreateScope(TheLastScope)); // FIXME: This location should point to stdlib instead of being artificial. auto DL = llvm::DebugLoc::get(0, 0, getOrCreateScope(Scope), LastLocation); Builder.SetCurrentDebugLocation(DL); } void IRGenDebugInfoImpl::setEntryPointLoc(IRBuilder &Builder) { auto DL = llvm::DebugLoc::get(0, 0, getEntryPointFn(), nullptr); Builder.SetCurrentDebugLocation(DL); } llvm::DIScope *IRGenDebugInfoImpl::getEntryPointFn() { // Lazily create EntryPointFn. if (!EntryPointFn) { EntryPointFn = DBuilder.createReplaceableCompositeType( llvm::dwarf::DW_TAG_subroutine_type, SWIFT_ENTRY_POINT_FUNCTION, MainFile, MainFile, 0); } return EntryPointFn; } llvm::DIScope *IRGenDebugInfoImpl::getOrCreateScope(const SILDebugScope *DS) { if (DS == nullptr) 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 an (inlined) function scope, the function may // not have been created yet. if (auto *SILFn = DS->Parent.dyn_cast()) { auto *FnScope = SILFn->getDebugScope(); // FIXME: This is a bug in the SIL deserialization. if (!FnScope) 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 (!SILFn->getName().empty() && !SILFn->isZombie()) Fn = IGM.getAddrOfSILFunction(SILFn, NotForDefinition); auto *SP = emitFunction(*SILFn, Fn); // Cache it. ScopeCache[DS] = llvm::TrackingMDNodeRef(SP); return SP; } auto *ParentScope = DS->Parent.get(); llvm::DIScope *Parent = getOrCreateScope(ParentScope); assert(isa(Parent) && "not a local scope"); if (Opts.DebugInfoLevel <= IRGenDebugInfoLevel::LineTables) return Parent; assert(DS->Parent && "lexical block must have a parent subprogram"); auto L = getStartLocation(DS->Loc); llvm::DIFile *File = getOrCreateFile(L.Filename); auto *DScope = DBuilder.createLexicalBlock(Parent, File, L.Line, L.Column); // Cache it. ScopeCache[DS] = llvm::TrackingMDNodeRef(DScope); return DScope; } void IRGenDebugInfoImpl::emitImport(ImportDecl *D) { if (Opts.DebugInfoLevel <= IRGenDebugInfoLevel::LineTables) return; assert(D->getModule() && "compiler-synthesized ImportDecl is incomplete"); ModuleDecl::ImportedModule Imported = {D->getModulePath(), D->getModule()}; auto DIMod = getOrCreateModule(Imported); auto L = getDebugLoc(*this, D); auto *File = getOrCreateFile(L.Filename); DBuilder.createImportedModule(File, DIMod, File, L.Line); ImportedModules.insert(Imported.second); } llvm::DISubprogram *IRGenDebugInfoImpl::emitFunction(SILFunction &SILFn, llvm::Function *Fn) { auto *DS = SILFn.getDebugScope(); assert(DS && "SIL function has no debug scope"); (void)DS; return emitFunction(SILFn.getDebugScope(), Fn, SILFn.getRepresentation(), SILFn.getLoweredType(), SILFn.getDeclContext()); } llvm::DISubprogram * IRGenDebugInfoImpl::emitFunction(const SILDebugScope *DS, llvm::Function *Fn, SILFunctionTypeRepresentation Rep, SILType SILTy, DeclContext *DeclCtx) { auto Cached = ScopeCache.find(DS); if (Cached != ScopeCache.end()) { auto SP = cast(Cached->second); // If we created the DISubprogram for a forward declaration, // attach it to the function now. if (!Fn->getSubprogram() && !Fn->isDeclaration()) Fn->setSubprogram(SP); return SP; } // Some IRGen-generated helper functions don't have a corresponding // SIL function, hence the dyn_cast. auto *SILFn = DS ? DS->Parent.dyn_cast() : nullptr; StringRef LinkageName; if (Fn) LinkageName = Fn->getName(); else if (DS) LinkageName = SILFn->getName(); else llvm_unreachable("function has no mangled name"); StringRef Name; if (DS) { if (DS->Loc.isSILFile()) Name = SILFn->getName(); else Name = getName(DS->Loc); } /// The source line used for the function prologue. unsigned ScopeLine = 0; SILLocation::DebugLoc L; if (!DS || (SILFn && (SILFn->isBare() || SILFn->isThunk() || SILFn->isTransparent()))) { // Bare functions and thunks should not have any line numbers. This // is especially important for shared functions like reabstraction // thunk helpers, where DS->Loc is an arbitrary location of whichever use // was emitted first. L = SILLocation::getCompilerGeneratedDebugLoc(); } else { L = decodeDebugLoc(DS->Loc); ScopeLine = L.Line; if (!DS->Loc.isDebugInfoLoc()) L = decodeSourceLoc(DS->Loc.getSourceLoc()); } auto Line = L.Line; auto File = getOrCreateFile(L.Filename); llvm::DIScope *Scope = MainModule; if (SILFn && SILFn->getDeclContext()) Scope = getOrCreateContext(SILFn->getDeclContext()->getParent()); // We know that main always comes from MainFile. if (LinkageName == SWIFT_ENTRY_POINT_FUNCTION) { File = MainFile; Line = 1; Name = LinkageName; } CanSILFunctionType FnTy = getFunctionType(SILTy); auto Params = Opts.DebugInfoLevel > IRGenDebugInfoLevel::LineTables ? createParameterTypes(SILTy) : nullptr; llvm::DISubroutineType *DIFnTy = DBuilder.createSubroutineType(Params); llvm::DITemplateParameterArray TemplateParameters = nullptr; llvm::DISubprogram *Decl = nullptr; // Various flags. llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; // 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 toplevel code, which, although it does not // have a Swift name, does appear prominently in the source code. // ObjC thunks should also not show up in the linetable, because we // never want to set a breakpoint there. if ((Name.empty() && LinkageName != SWIFT_ENTRY_POINT_FUNCTION && !isExplicitClosure(SILFn)) || (Rep == SILFunctionTypeRepresentation::ObjCMethod) || isAllocatingConstructor(Rep, DeclCtx)) { Flags |= llvm::DINode::FlagArtificial; ScopeLine = 0; } if (FnTy && FnTy->getRepresentation() == SILFunctionType::Representation::Block) Flags |= llvm::DINode::FlagAppleBlock; // Get the throws information. llvm::DITypeArray Error = nullptr; if (FnTy) if (auto ErrorInfo = FnTy->getOptionalErrorResult()) { auto DTI = DebugTypeInfo::getFromTypeInfo( ErrorInfo->getReturnValueType(IGM.getSILModule(), FnTy), IGM.getTypeInfo(IGM.silConv.getSILType(*ErrorInfo, FnTy))); Error = DBuilder.getOrCreateArray({getOrCreateType(DTI)}).get(); } llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::toSPFlags( /*IsLocalToUnit=*/Fn ? Fn->hasInternalLinkage() : true, /*IsDefinition=*/true, /*IsOptimized=*/Opts.shouldOptimize()); // Construct the DISubprogram. llvm::DISubprogram *SP = DBuilder.createFunction( Scope, Name, LinkageName, File, Line, DIFnTy, ScopeLine, Flags, SPFlags, TemplateParameters, Decl, Error); if (Fn && !Fn->isDeclaration()) Fn->setSubprogram(SP); // RAUW the entry point function forward declaration with the real thing. if (LinkageName == SWIFT_ENTRY_POINT_FUNCTION) { if (EntryPointFn) { 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; } void IRGenDebugInfoImpl::emitArtificialFunction(IRBuilder &Builder, llvm::Function *Fn, SILType SILTy) { RegularLocation ALoc = RegularLocation::getAutoGeneratedLocation(); const SILDebugScope *Scope = new (IGM.getSILModule()) SILDebugScope(ALoc); emitFunction(Scope, Fn, SILFunctionTypeRepresentation::Thin, SILTy); /// Reusing the current file would be wrong: An objc thunk, for example, could /// be triggered from any random location. Use a placeholder name instead. setCurrentLoc(Builder, Scope, ALoc); } void IRGenDebugInfoImpl::emitVariableDeclaration( IRBuilder &Builder, ArrayRef Storage, DebugTypeInfo DbgTy, const SILDebugScope *DS, ValueDecl *VarDecl, SILDebugVariable VarInfo, IndirectionKind Indirection, ArtificialKind Artificial) { assert(DS && "variable has no scope"); if (Opts.DebugInfoLevel <= IRGenDebugInfoLevel::LineTables) return; // We cannot yet represent opened existentials. if (DbgTy.Type->hasOpenedExistential()) return; if (!DbgTy.size) DbgTy.size = getStorageSize(IGM.DataLayout, Storage); auto *Scope = dyn_cast_or_null(getOrCreateScope(DS)); assert(Scope && "variable has no local scope"); auto Loc = getDebugLoc(*this, VarDecl); // FIXME: this should be the scope of the type's declaration. // If this is an argument, attach it to the current function scope. if (VarInfo.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"); if (VarInfo.Constant) DITy = DBuilder.createQualifiedType(llvm::dwarf::DW_TAG_const_type, DITy); unsigned Line = Loc.Line; // Self is always an artificial argument, so are variables without location. if (!Line || (VarInfo.ArgNo > 0 && VarInfo.Name == IGM.Context.Id_self.str())) Artificial = ArtificialValue; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (Artificial || DITy->isArtificial() || DITy == InternalType) Flags |= llvm::DINode::FlagArtificial; // This could be Opts.Optimize if we would also unique DIVariables here. bool Optimized = false; // Create the descriptor for the variable. llvm::DILocalVariable *Var = (VarInfo.ArgNo > 0) ? DBuilder.createParameterVariable(Scope, VarInfo.Name, VarInfo.ArgNo, Unit, Line, DITy, Optimized, Flags) : DBuilder.createAutoVariable(Scope, VarInfo.Name, Unit, Line, DITy, Optimized, Flags); // Running variables for the current/previous piece. bool IsPiece = Storage.size() > 1; uint64_t SizeOfByte = CI.getTargetInfo().getCharWidth(); unsigned AlignInBits = SizeOfByte; unsigned OffsetInBits = 0; unsigned SizeInBits = 0; for (llvm::Value *Piece : Storage) { SmallVector Operands; if (Indirection) Operands.push_back(llvm::dwarf::DW_OP_deref); if (IsPiece) { // Advance the offset and align it for the next piece. OffsetInBits += llvm::alignTo(SizeInBits, AlignInBits); SizeInBits = IGM.DataLayout.getTypeSizeInBits(Piece->getType()); AlignInBits = IGM.DataLayout.getABITypeAlignment(Piece->getType()); if (!AlignInBits) AlignInBits = SizeOfByte; // Sanity checks. assert(SizeInBits && "zero-sized piece"); assert(SizeInBits < getSizeInBits(Var) && "piece covers entire var"); assert(OffsetInBits + SizeInBits <= getSizeInBits(Var) && "pars > totum"); // Add the piece DWARF expression. Operands.push_back(llvm::dwarf::DW_OP_LLVM_fragment); Operands.push_back(OffsetInBits); Operands.push_back(SizeInBits); } emitDbgIntrinsic(Builder, Piece, Var, DBuilder.createExpression(Operands), Line, Loc.Column, Scope, DS); } // Emit locationless intrinsic for variables that were optimized away. if (Storage.empty()) emitDbgIntrinsic(Builder, llvm::ConstantInt::get(IGM.Int64Ty, 0), Var, DBuilder.createExpression(), Line, Loc.Column, Scope, DS); } void IRGenDebugInfoImpl::emitDbgIntrinsic( IRBuilder &Builder, llvm::Value *Storage, llvm::DILocalVariable *Var, llvm::DIExpression *Expr, unsigned Line, unsigned Col, llvm::DILocalScope *Scope, const SILDebugScope *DS) { // Set the location/scope of the intrinsic. auto *InlinedAt = createInlinedAt(DS); auto DL = llvm::DebugLoc::get(Line, Col, Scope, InlinedAt); auto *BB = Builder.GetInsertBlock(); // An alloca may only be described by exactly one dbg.declare. if (isa(Storage) && !llvm::FindDbgAddrUses(Storage).empty()) return; // A dbg.declare is only meaningful if there is a single alloca for // the variable that is live throughout the function. if (auto *Alloca = dyn_cast(Storage)) { auto *ParentBB = Alloca->getParent(); auto InsertBefore = std::next(Alloca->getIterator()); if (InsertBefore != ParentBB->end()) DBuilder.insertDeclare(Alloca, Var, Expr, DL, &*InsertBefore); else DBuilder.insertDeclare(Alloca, Var, Expr, DL, ParentBB); } else if (isa(Storage) && cast(Storage)->getIntrinsicID() == llvm::Intrinsic::coro_alloca_get) { // FIXME: The live range of a coroutine alloca within the function may be // limited, so using a dbg.addr instead of a dbg.declare would be more // appropriate. DBuilder.insertDeclare(Storage, Var, Expr, DL, BB); } else { // Insert a dbg.value at the current insertion point. DBuilder.insertDbgValueIntrinsic(Storage, Var, Expr, DL, BB); } } void IRGenDebugInfoImpl::emitGlobalVariableDeclaration( llvm::GlobalVariable *Var, StringRef Name, StringRef LinkageName, DebugTypeInfo DbgTy, bool IsLocalToUnit, bool InFixedBuffer, Optional Loc) { if (Opts.DebugInfoLevel <= IRGenDebugInfoLevel::LineTables) return; llvm::DIType *DITy = getOrCreateType(DbgTy); VarDecl *VD = nullptr; if (Loc) VD = dyn_cast_or_null(Loc->getAsASTNode()); if (!VD || VD->isLet()) DITy = DBuilder.createQualifiedType(llvm::dwarf::DW_TAG_const_type, DITy); if (DITy->isArtificial() || DITy == InternalType || !Loc) // 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; if (InFixedBuffer) DITy = createFixedValueBufferStruct(DITy); auto L = getStartLocation(Loc); auto File = getOrCreateFile(L.Filename); // Emit it as global variable of the current module. llvm::DIExpression *Expr = nullptr; if (!Var) Expr = DBuilder.createConstantValueExpression(0); auto *GV = DBuilder.createGlobalVariableExpression( MainModule, Name, LinkageName, File, L.Line, DITy, IsLocalToUnit, true, Expr); if (Var) Var->addDebugInfo(GV); } void IRGenDebugInfoImpl::emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata, unsigned Depth, unsigned Index, StringRef Name) { if (Opts.DebugInfoLevel <= IRGenDebugInfoLevel::LineTables) return; // Don't emit debug info in transparent functions. auto *DS = IGF.getDebugScope(); if (!DS || DS->getInlinedFunction()->isTransparent()) return; llvm::SmallString<8> Buf; static const char *Tau = u8"\u03C4"; llvm::raw_svector_ostream OS(Buf); OS << '$' << Tau << '_' << Depth << '_' << Index; auto DbgTy = DebugTypeInfo::getArchetype( getMetadataType(Name)->getDeclaredInterfaceType().getPointer(), Metadata->getType(), Size(CI.getTargetInfo().getPointerWidth(0)), Alignment(CI.getTargetInfo().getPointerAlign(0))); emitVariableDeclaration(IGF.Builder, Metadata, DbgTy, IGF.getDebugScope(), nullptr, {OS.str().str(), 0, false}, // swift.type is already a pointer type, // having a shadow copy doesn't add another // layer of indirection. DirectValue, ArtificialValue); } SILLocation::DebugLoc IRGenDebugInfoImpl::decodeSourceLoc(SourceLoc SL) { auto &Cached = DebugLocCache[SL.getOpaquePointerValue()]; if (Cached.Filename.empty()) Cached = sanitizeCodeViewDebugLoc(SILLocation::decode(SL, SM)); return Cached; } } // anonymous namespace std::unique_ptr IRGenDebugInfo::createIRGenDebugInfo( const IRGenOptions &Opts, ClangImporter &CI, IRGenModule &IGM, llvm::Module &M, StringRef MainOutputFilenameForDebugInfo, StringRef PrivateDiscriminator) { return std::make_unique(Opts, CI, IGM, M, MainOutputFilenameForDebugInfo, PrivateDiscriminator); } IRGenDebugInfo::~IRGenDebugInfo() {} // Forwarding to the private implementation. void IRGenDebugInfo::finalize() { static_cast(this)->finalize(); } void IRGenDebugInfo::setCurrentLoc(IRBuilder &Builder, const SILDebugScope *DS, SILLocation Loc) { static_cast(this)->setCurrentLoc(Builder, DS, Loc); } void IRGenDebugInfo::addFailureMessageToCurrentLoc(IRBuilder &Builder, StringRef failureMsg) { static_cast(this)-> addFailureMessageToCurrentLoc(Builder, failureMsg); } void IRGenDebugInfo::clearLoc(IRBuilder &Builder) { static_cast(this)->clearLoc(Builder); } void IRGenDebugInfo::pushLoc() { static_cast(this)->pushLoc(); } void IRGenDebugInfo::popLoc() { static_cast(this)->popLoc(); } void IRGenDebugInfo::setInlinedTrapLocation(IRBuilder &Builder, const SILDebugScope *Scope) { static_cast(this)->setInlinedTrapLocation(Builder, Scope); } void IRGenDebugInfo::setEntryPointLoc(IRBuilder &Builder) { static_cast(this)->setEntryPointLoc(Builder); } llvm::DIScope *IRGenDebugInfo::getEntryPointFn() { return static_cast(this)->getEntryPointFn(); } llvm::DIScope *IRGenDebugInfo::getOrCreateScope(const SILDebugScope *DS) { return static_cast(this)->getOrCreateScope(DS); } void IRGenDebugInfo::emitImport(ImportDecl *D) { static_cast(this)->emitImport(D); } llvm::DISubprogram * IRGenDebugInfo::emitFunction(const SILDebugScope *DS, llvm::Function *Fn, SILFunctionTypeRepresentation Rep, SILType Ty, DeclContext *DeclCtx, GenericEnvironment *GE) { return static_cast(this)->emitFunction(DS, Fn, Rep, Ty, DeclCtx); } llvm::DISubprogram *IRGenDebugInfo::emitFunction(SILFunction &SILFn, llvm::Function *Fn) { return static_cast(this)->emitFunction(SILFn, Fn); } void IRGenDebugInfo::emitArtificialFunction(IRBuilder &Builder, llvm::Function *Fn, SILType SILTy) { static_cast(this)->emitArtificialFunction(Builder, Fn, SILTy); } void IRGenDebugInfo::emitVariableDeclaration( IRBuilder &Builder, ArrayRef Storage, DebugTypeInfo Ty, const SILDebugScope *DS, ValueDecl *VarDecl, SILDebugVariable VarInfo, IndirectionKind Indirection, ArtificialKind Artificial) { static_cast(this)->emitVariableDeclaration( Builder, Storage, Ty, DS, VarDecl, VarInfo, Indirection, Artificial); } void IRGenDebugInfo::emitDbgIntrinsic(IRBuilder &Builder, llvm::Value *Storage, llvm::DILocalVariable *Var, llvm::DIExpression *Expr, unsigned Line, unsigned Col, llvm::DILocalScope *Scope, const SILDebugScope *DS) { static_cast(this)->emitDbgIntrinsic( Builder, Storage, Var, Expr, Line, Col, Scope, DS); } void IRGenDebugInfo::emitGlobalVariableDeclaration( llvm::GlobalVariable *Storage, StringRef Name, StringRef LinkageName, DebugTypeInfo DebugType, bool IsLocalToUnit, bool InFixedBuffer, Optional Loc) { static_cast(this)->emitGlobalVariableDeclaration( Storage, Name, LinkageName, DebugType, IsLocalToUnit, InFixedBuffer, Loc); } void IRGenDebugInfo::emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata, unsigned Depth, unsigned Index, StringRef Name) { static_cast(this)->emitTypeMetadata( IGF, Metadata, Depth, Index, Name); } llvm::DIBuilder &IRGenDebugInfo::getBuilder() { return static_cast(this)->getBuilder(); } SILLocation::DebugLoc IRGenDebugInfo::decodeSourceLoc(SourceLoc SL) { return static_cast(this)->decodeSourceLoc(SL); } AutoRestoreLocation::AutoRestoreLocation(IRGenDebugInfo *DI, IRBuilder &Builder) : DI(DI), Builder(Builder) { if (DI) SavedLocation = Builder.getCurrentDebugLocation(); } /// Autorestore everything back to normal. AutoRestoreLocation::~AutoRestoreLocation() { if (DI) Builder.SetCurrentDebugLocation(SavedLocation); } ArtificialLocation::ArtificialLocation(const SILDebugScope *DS, IRGenDebugInfo *DI, IRBuilder &Builder) : AutoRestoreLocation(DI, Builder) { if (DI) { unsigned Line = 0; auto *Scope = DI->getOrCreateScope(DS); if (static_cast(DI)->getDebugInfoFormat() == IRGenDebugInfoFormat::CodeView) { // In CodeView, line zero is not an artificial line location and so we // try to use the location of the scope. if (auto *LB = dyn_cast(Scope)) Line = LB->getLine(); else if (auto *SP = dyn_cast(Scope)) Line = SP->getLine(); } auto DL = llvm::DebugLoc::get(Line, 0, Scope); Builder.SetCurrentDebugLocation(DL); } } PrologueLocation::PrologueLocation(IRGenDebugInfo *DI, IRBuilder &Builder) : AutoRestoreLocation(DI, Builder) { if (DI) DI->clearLoc(Builder); }