Improve the performance of IRGenDebugInfo

This commit changes how inline information is stored in SILDebugScope
from a tree to a linear chain of inlined call sites (similar to what
LLVM is using). This makes creating inlined SILDebugScopes slightly
more expensive, but makes lowering SILDebugScopes into LLVM metadata
much faster because entire inlined-at chains can now be cached. This
means that SIL is no longer preserve the inlining history (i.e., ((a
was inlined into b) was inlined into c) is represented the same as (a
was inlined into (b was inlined into c)), but this information was not
used by anyone.

On my late 2012 i7 iMac, this saves about 4 seconds when compiling the
RelWithDebInfo x86_64 swift standard library — or 40% of IRGen time.

rdar://problem/28311051
This commit is contained in:
Adrian Prantl
2017-04-03 15:46:56 -07:00
parent 3e28874bd0
commit 5ea2d13f5e
11 changed files with 196 additions and 180 deletions

View File

@@ -46,82 +46,28 @@ public:
/// An optional chain of inlined call sites.
///
/// If this scope is inlined, this points to a special "scope" that
/// holds only the location of the call site. The parent scope will be
/// the scope of the inlined call site.
///
/// Note that compared to the inlinedAt chain in llvm::DILocation
/// SILDebugScope represents an inline tree.
/// holds the location of the call site.
const SILDebugScope *InlinedCallSite;
SILDebugScope(SILLocation Loc, SILFunction *SILFn,
const SILDebugScope *ParentScope = nullptr,
const SILDebugScope *InlinedCallSite = nullptr)
: Loc(Loc), InlinedCallSite(InlinedCallSite) {
if (ParentScope)
Parent = ParentScope;
else {
assert(SILFn && "no parent provided");
Parent = SILFn;
}
}
const SILDebugScope *InlinedCallSite = nullptr);
/// Create a scope for an artificial function.
SILDebugScope(SILLocation Loc)
: Loc(Loc), InlinedCallSite(nullptr) {}
/// Create an inlined version of CalleeScope.
SILDebugScope(const SILDebugScope *CallSiteScope,
const SILDebugScope *CalleeScope)
: Loc(CalleeScope->Loc), Parent(CalleeScope),
InlinedCallSite(CallSiteScope) {
assert(CallSiteScope && CalleeScope);
if (InlinedCallSite)
assert(!InlinedCallSite->InlinedCallSite &&
"a call site scope cannot have an inlined call site");
}
SILDebugScope(SILLocation Loc);
/// Return the function this scope originated from before being inlined.
SILFunction *getInlinedFunction() const {
if (Parent.isNull())
return nullptr;
const SILDebugScope *Scope = this;
while (Scope->Parent.is<const SILDebugScope *>())
Scope = Scope->Parent.get<const SILDebugScope *>();
assert(Scope->Parent.is<SILFunction *>() && "orphaned scope");
return Scope->Parent.get<SILFunction *>();
}
/// Return this scope without inline information.
const SILDebugScope *getInlinedScope() const {
return InlinedCallSite ? Parent.get<const SILDebugScope*>() : this;
}
SILFunction *getInlinedFunction() const;
/// Return the parent function of this scope. If the scope was
/// inlined this recursively returns the function it was inlined
/// into.
SILFunction *getParentFunction() const {
if (InlinedCallSite)
return InlinedCallSite->Parent.get<const SILDebugScope *>()
->getParentFunction();
if (auto *ParentScope = Parent.dyn_cast<const SILDebugScope *>())
return ParentScope->getParentFunction();
return Parent.get<SILFunction *>();
}
typedef SmallVector<const SILDebugScope *, 8> InlineScopeList;
static void flatten(const SILDebugScope *DS, InlineScopeList &List);
// Return a flattened representation of the inline scope tree that
// is equivalent to the reversed inlined-at chain.
InlineScopeList flattenedInlineTree() const {
InlineScopeList List;
flatten(this, List);
return List;
}
SILFunction *getParentFunction() const;
#ifndef NDEBUG
void dump(SourceManager &SM, llvm::raw_ostream &OS = llvm::errs(),
unsigned Indent = 0) const;
#endif
};
#ifndef NDEBUG

View File

@@ -410,10 +410,13 @@ public:
SourceLoc getSourceLoc() const;
SourceLoc getStartSourceLoc() const;
SourceLoc getEndSourceLoc() const;
SourceRange getSourceRange() const {
return {getStartSourceLoc(), getEndSourceLoc()};
}
DebugLoc getDebugInfoLoc() const {
assert(isDebugInfoLoc());
return Loc.DebugInfoLoc;
}
/// Fingerprint a DebugLoc for use in a DenseMap.
typedef std::pair<std::pair<unsigned, unsigned>, StringRef> DebugLocKey;

View File

@@ -51,7 +51,7 @@ public:
CloneCollector::CallbackType Callback = nullptr)
: TypeSubstCloner<SILInliner>(To, From, ApplySubs,
OpenedArchetypesTracker, true),
IKind(IKind), CalleeEntryBB(nullptr), CallSiteScope(nullptr),
IKind(IKind), CalleeEntryBB(nullptr),
Callback(Callback) {
}
@@ -114,7 +114,7 @@ private:
/// Alternatively, it can be the SIL file location of the call site (in case
/// of SIL-to-SIL transformations).
Optional<SILLocation> Loc;
const SILDebugScope *CallSiteScope;
const SILDebugScope *CallSiteScope = nullptr;
SILFunction *CalleeFunction;
llvm::SmallDenseMap<const SILDebugScope *,
const SILDebugScope *> InlinedScopeCache;

View File

@@ -190,7 +190,7 @@ SILLocation::DebugLoc getDeserializedLoc(Decl *D) {
/// Use the SM to figure out the actual line/column of a SourceLoc.
template <typename WithLoc>
SILLocation::DebugLoc getDebugLoc(SourceManager &SM, WithLoc *S,
SILLocation::DebugLoc getDebugLoc(IRGenDebugInfo &DI, WithLoc *S,
bool End = false) {
SILLocation::DebugLoc L;
if (S == nullptr)
@@ -203,22 +203,37 @@ SILLocation::DebugLoc getDebugLoc(SourceManager &SM, WithLoc *S,
// the module.
return getDeserializedLoc(S);
return SILLocation::decode(Loc, SM);
return DI.decodeSourceLoc(Loc);
}
/// Return the start of the location's source range.
static SILLocation::DebugLoc getStartLocation(Optional<SILLocation> OptLoc,
SourceManager &SM) {
if (!OptLoc) return {};
return SILLocation::decode(OptLoc->getStartSourceLoc(), SM);
SILLocation::DebugLoc
IRGenDebugInfo::getStartLocation(Optional<SILLocation> OptLoc) {
if (!OptLoc)
return {};
return decodeSourceLoc(OptLoc->getStartSourceLoc());
}
/// Return the debug location from a SILLocation.
static SILLocation::DebugLoc getDebugLocation(Optional<SILLocation> OptLoc,
SourceManager &SM) {
SILLocation::DebugLoc
IRGenDebugInfo::decodeSourceLoc(SourceLoc SL) {
auto &Cached = DebugLocCache[SL.getOpaquePointerValue()];
if (Cached.Filename.empty())
Cached = SILLocation::decode(SL, SM);
return Cached;
}
SILLocation::DebugLoc
IRGenDebugInfo::decodeDebugLoc(SILLocation Loc) {
if (Loc.isDebugInfoLoc())
return Loc.getDebugInfoLoc();
return decodeSourceLoc(Loc.getDebugSourceLoc());
}
SILLocation::DebugLoc
IRGenDebugInfo::getDebugLocation(Optional<SILLocation> OptLoc) {
if (!OptLoc || OptLoc->isInPrologue())
return {};
return OptLoc->decodeDebugLoc(SM);
return decodeDebugLoc(*OptLoc);
}
@@ -240,33 +255,19 @@ static bool isAbstractClosure(const SILLocation &Loc) {
}
llvm::MDNode *IRGenDebugInfo::createInlinedAt(const SILDebugScope *DS) {
llvm::MDNode *InlinedAt = nullptr;
if (DS) {
// The inlined-at chain, starting with the innermost (noninlined) scope.
auto Scopes = DS->flattenedInlineTree();
auto *CS = DS->InlinedCallSite;
if (!CS)
return nullptr;
// See if we share a common prefix with the last chain of inline scopes.
unsigned N = 0;
while (N < LastInlineChain.size() && N < Scopes.size() &&
LastInlineChain[N].first == Scopes[N])
InlinedAt = LastInlineChain[N++].second;
LastInlineChain.resize(N);
auto CachedInlinedAt = InlinedAtCache.find(CS);
if (CachedInlinedAt != InlinedAtCache.end())
return cast<llvm::MDNode>(CachedInlinedAt->second);
// Construct the new suffix.
for (; N < Scopes.size(); ++N) {
auto *CS = Scopes[N];
// In SIL the inlined-at information is part of the scopes, in
// LLVM IR it is part of the location. Transforming the inlined-at
// SIL scope to a location means skipping the inlined-at scope.
auto *Parent = CS->Parent.get<const SILDebugScope *>();
auto *ParentScope = getOrCreateScope(Parent);
auto L = CS->Loc.decodeDebugLoc(SM);
InlinedAt = llvm::DebugLoc::get(L.Line, L.Column, ParentScope, InlinedAt);
// Cache the suffix.
LastInlineChain.push_back({CS, llvm::TrackingMDNodeRef(InlinedAt)});
}
}
auto L = decodeDebugLoc(CS->Loc);
auto Scope = getOrCreateScope(CS->Parent.dyn_cast<const SILDebugScope *>());
auto InlinedAt =
llvm::DebugLoc::get(L.Line, L.Column, Scope, createInlinedAt(CS));
InlinedAtCache.insert({CS, llvm::TrackingMDNodeRef(InlinedAt.getAsMDNode())});
return InlinedAt;
}
@@ -299,13 +300,11 @@ bool IRGenDebugInfo::lineNumberIsSane(IRBuilder &Builder, unsigned Line) {
void IRGenDebugInfo::setCurrentLoc(IRBuilder &Builder, const SILDebugScope *DS,
Optional<SILLocation> Loc) {
assert(DS && "empty scope");
// Inline info is emitted as part of the location below; extract the
// original scope here.
auto *Scope = getOrCreateScope(DS->getInlinedScope());
auto *Scope = getOrCreateScope(DS);
if (!Scope)
return;
auto L = getDebugLocation(Loc, SM);
auto L = getDebugLocation(Loc);
auto *File = getOrCreateFile(L.Filename);
if (File->getFilename() != Scope->getFilename()) {
// We changed files in the middle of a scope. This happens, for
@@ -364,7 +363,7 @@ llvm::DIScope *IRGenDebugInfo::getOrCreateScope(const SILDebugScope *DS) {
return MainFile;
// Try to find it in the cache first.
auto CachedScope = ScopeCache.find(DS);
auto CachedScope = ScopeCache.find(LocalScope(DS));
if (CachedScope != ScopeCache.end())
return cast<llvm::DIScope>(CachedScope->second);
@@ -376,7 +375,7 @@ llvm::DIScope *IRGenDebugInfo::getOrCreateScope(const SILDebugScope *DS) {
if (!FnScope)
SILFn->setDebugScope(DS);
auto CachedScope = ScopeCache.find(FnScope);
auto CachedScope = ScopeCache.find(LocalScope(FnScope));
if (CachedScope != ScopeCache.end())
return cast<llvm::DIScope>(CachedScope->second);
@@ -388,7 +387,7 @@ llvm::DIScope *IRGenDebugInfo::getOrCreateScope(const SILDebugScope *DS) {
auto *SP = emitFunction(*SILFn, Fn);
// Cache it.
ScopeCache[DS] = llvm::TrackingMDNodeRef(SP);
ScopeCache[LocalScope(DS)] = llvm::TrackingMDNodeRef(SP);
return SP;
}
@@ -400,13 +399,12 @@ llvm::DIScope *IRGenDebugInfo::getOrCreateScope(const SILDebugScope *DS) {
return Parent;
assert(DS->Parent && "lexical block must have a parent subprogram");
auto L = getStartLocation(DS->Loc, SM);
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);
ScopeCache[LocalScope(DS)] = llvm::TrackingMDNodeRef(DScope);
return DScope;
}
@@ -549,7 +547,7 @@ llvm::DIScope *IRGenDebugInfo::getOrCreateContext(DeclContext *DC) {
return DITy;
// Create a Forward-declared type.
auto Loc = getDebugLoc(SM, NTD);
auto Loc = getDebugLoc(*this, NTD);
auto File = getOrCreateFile(Loc.Filename);
auto Line = Loc.Line;
auto FwdDecl = DBuilder.createReplaceableCompositeType(
@@ -630,7 +628,7 @@ llvm::DISubprogram *
IRGenDebugInfo::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
SILFunctionTypeRepresentation Rep, SILType SILTy,
DeclContext *DeclCtx, GenericEnvironment *GE) {
auto Cached = ScopeCache.find(DS);
auto Cached = ScopeCache.find(LocalScope(DS));
if (Cached != ScopeCache.end()) {
auto SP = cast<llvm::DISubprogram>(Cached->second);
// If we created the DISubprogram for a forward declaration,
@@ -666,10 +664,10 @@ IRGenDebugInfo::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
// thunk helpers, where DS->Loc is an arbitrary location of whichever use
// was emitted first.
if (DS && (!SILFn || (!SILFn->isBare() && !SILFn->isThunk()))) {
L = DS->Loc.decodeDebugLoc(SM);
L = decodeDebugLoc(DS->Loc);
ScopeLine = L.Line;
if (!DS->Loc.isDebugInfoLoc())
L = SILLocation::decode(DS->Loc.getSourceLoc(), SM);
L = decodeSourceLoc(DS->Loc.getSourceLoc());
}
auto Line = L.Line;
@@ -740,7 +738,7 @@ IRGenDebugInfo::emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
if (!DS)
return nullptr;
ScopeCache[DS] = llvm::TrackingMDNodeRef(SP);
ScopeCache[LocalScope(DS)] = llvm::TrackingMDNodeRef(SP);
return SP;
}
@@ -757,7 +755,7 @@ void IRGenDebugInfo::emitImport(ImportDecl *D) {
return;
}
auto DIMod = getOrCreateModule({D->getModulePath(), M});
auto L = getDebugLoc(SM, D);
auto L = getDebugLoc(*this, D);
DBuilder.createImportedModule(getOrCreateFile(L.Filename), DIMod, L.Line);
}
@@ -896,7 +894,7 @@ void IRGenDebugInfo::emitVariableDeclaration(
auto *Scope = dyn_cast<llvm::DILocalScope>(getOrCreateScope(DS));
assert(Scope && "variable has no local scope");
auto Loc = getDebugLoc(SM, VarDecl);
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.
@@ -1022,7 +1020,7 @@ void IRGenDebugInfo::emitGlobalVariableDeclaration(
// would confuse both the user and LLDB.
return;
auto L = getStartLocation(Loc, SM);
auto L = getStartLocation(Loc);
auto File = getOrCreateFile(L.Filename);
// Emit it as global variable of the current module.
@@ -1473,7 +1471,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
case TypeKind::Struct: {
auto *StructTy = BaseTy->castTo<StructType>();
auto *Decl = StructTy->getDecl();
auto L = getDebugLoc(SM, Decl);
auto L = getDebugLoc(*this, Decl);
auto *File = getOrCreateFile(L.Filename);
if (Opts.DebugInfoKind > IRGenDebugInfoKind::ASTTypes)
return createStructType(DbgTy, Decl, StructTy, Scope, File, L.Line,
@@ -1491,7 +1489,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
// used to differentiate them from C++ and ObjC classes.
auto *ClassTy = BaseTy->castTo<ClassType>();
auto *Decl = ClassTy->getDecl();
auto L = getDebugLoc(SM, Decl);
auto L = getDebugLoc(*this, Decl);
if (auto *ClangDecl = Decl->getClangDecl()) {
auto ClangSrcLoc = ClangDecl->getLocStart();
clang::SourceManager &ClangSM =
@@ -1531,7 +1529,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
auto *ProtocolTy = BaseTy->castTo<ProtocolType>();
auto *Decl = ProtocolTy->getDecl();
// FIXME: (LLVM branch) This should probably be a DW_TAG_interface_type.
auto L = getDebugLoc(SM, Decl);
auto L = getDebugLoc(*this, Decl);
auto File = getOrCreateFile(L.Filename);
return createOpaqueStruct(Scope, Decl ? Decl->getNameStr() : MangledName,
File, L.Line, SizeInBits, AlignInBits, Flags,
@@ -1540,7 +1538,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
case TypeKind::ProtocolComposition: {
auto *Decl = DbgTy.getDecl();
auto L = getDebugLoc(SM, Decl);
auto L = getDebugLoc(*this, Decl);
auto File = getOrCreateFile(L.Filename);
// FIXME: emit types
@@ -1553,7 +1551,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
case TypeKind::UnboundGeneric: {
auto *UnboundTy = BaseTy->castTo<UnboundGenericType>();
auto *Decl = UnboundTy->getDecl();
auto L = getDebugLoc(SM, Decl);
auto L = getDebugLoc(*this, Decl);
assert(SizeInBits == CI.getTargetInfo().getPointerWidth(0));
return createPointerSizedStruct(Scope,
Decl ? Decl->getNameStr() : MangledName,
@@ -1563,7 +1561,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
case TypeKind::BoundGenericStruct: {
auto *StructTy = BaseTy->castTo<BoundGenericStructType>();
auto *Decl = StructTy->getDecl();
auto L = getDebugLoc(SM, Decl);
auto L = getDebugLoc(*this, Decl);
return createOpaqueStruct(Scope, Decl ? Decl->getNameStr() : MangledName,
File, L.Line, SizeInBits, AlignInBits, Flags,
MangledName);
@@ -1572,7 +1570,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
case TypeKind::BoundGenericClass: {
auto *ClassTy = BaseTy->castTo<BoundGenericClassType>();
auto *Decl = ClassTy->getDecl();
auto L = getDebugLoc(SM, Decl);
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));
@@ -1608,7 +1606,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
case TypeKind::Archetype: {
auto *Archetype = BaseTy->castTo<ArchetypeType>();
auto L = getDebugLoc(SM, Archetype->getAssocType());
auto L = getDebugLoc(*this, Archetype->getAssocType());
auto Superclass = Archetype->getSuperclass();
auto DerivedFrom = Superclass.isNull()
? nullptr
@@ -1645,7 +1643,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
case TypeKind::Metatype: {
// Metatypes are (mostly) singleton type descriptors, often without storage.
Flags |= llvm::DINode::FlagArtificial;
auto L = getDebugLoc(SM, DbgTy.getDecl());
auto L = getDebugLoc(*this, DbgTy.getDecl());
auto File = getOrCreateFile(L.Filename);
return DBuilder.createStructType(
Scope, MangledName, File, L.Line, SizeInBits, AlignInBits, Flags,
@@ -1667,7 +1665,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
case TypeKind::Enum: {
auto *EnumTy = BaseTy->castTo<EnumType>();
auto *Decl = EnumTy->getDecl();
auto L = getDebugLoc(SM, Decl);
auto L = getDebugLoc(*this, Decl);
auto *File = getOrCreateFile(L.Filename);
if (Opts.DebugInfoKind > IRGenDebugInfoKind::ASTTypes)
return createEnumType(DbgTy, Decl, MangledName, Scope, File, L.Line,
@@ -1680,7 +1678,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
case TypeKind::BoundGenericEnum: {
auto *EnumTy = BaseTy->castTo<BoundGenericEnumType>();
auto *Decl = EnumTy->getDecl();
auto L = getDebugLoc(SM, Decl);
auto L = getDebugLoc(*this, Decl);
auto *File = getOrCreateFile(L.Filename);
if (Opts.DebugInfoKind > IRGenDebugInfoKind::ASTTypes)
return createEnumType(DbgTy, Decl, MangledName, Scope, File, L.Line,
@@ -1709,7 +1707,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
case TypeKind::WeakStorage: {
auto *ReferenceTy = cast<ReferenceStorageType>(BaseTy);
auto CanTy = ReferenceTy->getReferentType();
auto L = getDebugLoc(SM, DbgTy.getDecl());
auto L = getDebugLoc(*this, DbgTy.getDecl());
auto File = getOrCreateFile(L.Filename);
return DBuilder.createTypedef(getOrCreateDesugaredType(CanTy, DbgTy),
MangledName, File, L.Line, File);
@@ -1721,7 +1719,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
auto *NameAliasTy = cast<NameAliasType>(BaseTy);
auto *Decl = NameAliasTy->getDecl();
auto L = getDebugLoc(SM, Decl);
auto L = getDebugLoc(*this, Decl);
auto AliasedTy = NameAliasTy->getSinglyDesugaredType();
auto File = getOrCreateFile(L.Filename);
// For NameAlias types, the DeclContext for the aliasED type is

View File

@@ -61,14 +61,24 @@ class IRGenDebugInfo {
llvm::DIBuilder DBuilder;
IRGenModule &IGM;
// Various caches.
llvm::DenseMap<const SILDebugScope *, llvm::TrackingMDNodeRef> ScopeCache;
/// Used for caching SILDebugScopes without inline information.
typedef std::pair<const void *, void *> LocalScopeHash;
struct LocalScope : public LocalScopeHash {
LocalScope(const SILDebugScope *DS)
: LocalScopeHash({DS->Loc.getOpaquePointerValue(),
DS->Parent.getOpaqueValue()}) {}
};
/// Various caches.
/// @{
llvm::DenseMap<LocalScopeHash, llvm::TrackingMDNodeRef> ScopeCache;
llvm::DenseMap<const SILDebugScope *, llvm::TrackingMDNodeRef> InlinedAtCache;
llvm::DenseMap<llvm::StringRef, llvm::TrackingMDNodeRef> DIFileCache;
llvm::DenseMap<const void *, SILLocation::DebugLoc> DebugLocCache;
llvm::DenseMap<TypeBase *, llvm::TrackingMDNodeRef> DITypeCache;
llvm::StringMap<llvm::TrackingMDNodeRef> DIModuleCache;
TrackingDIRefMap DIRefMap;
std::vector<std::pair<const SILDebugScope *, llvm::TrackingMDNodeRef>>
LastInlineChain;
/// @}
/// A list of replaceable fwddecls that need to be RAUWed at the end.
std::vector<std::pair<TypeBase *, llvm::TrackingMDRef>> ReplaceMap;
@@ -207,7 +217,17 @@ public:
/// Return the DIBuilder.
llvm::DIBuilder &getBuilder() { return DBuilder; }
/// Decode (and cache) a SourceLoc.
SILLocation::DebugLoc decodeSourceLoc(SourceLoc SL);
private:
/// Decode (and cache) a SILLocation.
SILLocation::DebugLoc decodeDebugLoc(SILLocation Loc);
/// Return the debug location from a SILLocation.
SILLocation::DebugLoc getDebugLocation(Optional<SILLocation> OptLoc);
/// Return the start of the location's source range.
SILLocation::DebugLoc getStartLocation(Optional<SILLocation> OptLoc);
StringRef BumpAllocatedString(const char *Data, size_t Length);
StringRef BumpAllocatedString(std::string S);
StringRef BumpAllocatedString(StringRef S);

View File

@@ -13,6 +13,7 @@ add_swift_library(swiftSIL STATIC
SILBasicBlock.cpp
SILBuilder.cpp
SILCoverageMap.cpp
SILDebugScope.cpp
SILDeclRef.cpp
SILDefaultWitnessTable.cpp
SILFunction.cpp

57
lib/SIL/SILDebugScope.cpp Normal file
View File

@@ -0,0 +1,57 @@
//===--- SILDebugScope.h - DebugScopes for SIL code -------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// This file defines a container for scope information used to
/// generate debug info.
///
//===----------------------------------------------------------------------===//
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILFunction.h"
using namespace swift;
SILDebugScope::SILDebugScope(SILLocation Loc, SILFunction *SILFn,
const SILDebugScope *ParentScope ,
const SILDebugScope *InlinedCallSite)
: Loc(Loc), InlinedCallSite(InlinedCallSite) {
if (ParentScope)
Parent = ParentScope;
else {
assert(SILFn && "no parent provided");
Parent = SILFn;
}
}
SILDebugScope::SILDebugScope(SILLocation Loc)
: Loc(Loc), InlinedCallSite(nullptr) {}
SILFunction *SILDebugScope::getInlinedFunction() const {
if (Parent.isNull())
return nullptr;
const SILDebugScope *Scope = this;
while (Scope->Parent.is<const SILDebugScope *>())
Scope = Scope->Parent.get<const SILDebugScope *>();
assert(Scope->Parent.is<SILFunction *>() && "orphaned scope");
return Scope->Parent.get<SILFunction *>();
}
SILFunction *SILDebugScope::getParentFunction() const {
if (InlinedCallSite)
return InlinedCallSite->getParentFunction();
if (auto *ParentScope = Parent.dyn_cast<const SILDebugScope *>())
return ParentScope->getParentFunction();
return Parent.get<SILFunction *>();
}

View File

@@ -744,17 +744,17 @@ public:
*this << ":in_prologue";
}
if (!DS)
return;
// Print inlined-at location, if any.
if (DS) {
SILFunction *InlinedF = DS->getInlinedFunction();
auto InlineScopes = DS->flattenedInlineTree();
for (auto *CS : reversed(InlineScopes)) {
const SILDebugScope *CS = DS;
while ((CS = CS->InlinedCallSite)) {
*this << ": ";
if (InlinedF) {
if (auto *InlinedF = CS->getInlinedFunction())
*this << demangleSymbol(InlinedF->getName());
} else {
else
*this << '?';
}
*this << " perf_inlined_at ";
auto CallSite = CS->Loc;
if (!CallSite.isNull() && CallSite.isASTNode())
@@ -762,9 +762,6 @@ public:
PrintState.OS, M.getASTContext().SourceMgr, LastBufferID);
else
*this << "?";
InlinedF = CS->getInlinedFunction();
}
}
}
@@ -2440,17 +2437,7 @@ void SILCoverageMap::dump() const {
print(llvm::errs());
}
void SILDebugScope::flatten(const SILDebugScope *DS,
SILDebugScope::InlineScopeList &List) {
if (DS) {
if (auto *CS = DS->InlinedCallSite) {
flatten(CS->Parent.dyn_cast<const SILDebugScope *>(), List);
List.push_back(CS);
}
flatten(DS->Parent.dyn_cast<const SILDebugScope *>(), List);
}
}
#ifndef NDEBUG
void SILDebugScope::dump(SourceManager &SM, llvm::raw_ostream &OS,
unsigned Indent) const {
OS << "{\n";
@@ -2478,6 +2465,7 @@ void SILDebugScope::dump(SourceManager &SM, llvm::raw_ostream &OS,
}
OS << "}\n";
}
#endif
void SILSpecializeAttr::print(llvm::raw_ostream &OS) const {
SILPrintContext Ctx(OS);

View File

@@ -71,10 +71,10 @@ bool SILInliner::inlineFunction(FullApplySite AI, ArrayRef<SILValue> Args) {
// Performance inlining. Construct a proper inline scope pointing
// back to the call site.
CallSiteScope = new (F.getModule())
SILDebugScope(AI.getLoc(), &F, AIScope);
assert(CallSiteScope->getParentFunction() == &F);
SILDebugScope(AI.getLoc(), nullptr, AIScope, AIScope->InlinedCallSite);
}
assert(CallSiteScope && "call site has no scope");
assert(CallSiteScope->getParentFunction() == &F);
// Increment the ref count for the inlined function, so it doesn't
// get deleted before we can emit abstract debug info for it.
@@ -198,20 +198,22 @@ void SILInliner::visitDebugValueAddrInst(DebugValueAddrInst *Inst) {
const SILDebugScope *
SILInliner::getOrCreateInlineScope(const SILDebugScope *CalleeScope) {
assert(CalleeScope);
if (!CalleeScope)
return CallSiteScope;
auto it = InlinedScopeCache.find(CalleeScope);
if (it != InlinedScopeCache.end())
return it->second;
auto InlineScope = new (getBuilder().getFunction().getModule())
SILDebugScope(CallSiteScope, CalleeScope);
assert(CallSiteScope->Parent == InlineScope->InlinedCallSite->Parent);
InlinedScopeCache.insert({CalleeScope, InlineScope});
return InlineScope;
auto &M = getBuilder().getFunction().getModule();
auto InlinedAt =
getOrCreateInlineScope(CalleeScope->InlinedCallSite);
auto *InlinedScope = new (M) SILDebugScope(
CalleeScope->Loc, CalleeScope->Parent.dyn_cast<SILFunction *>(),
CalleeScope->Parent.dyn_cast<const SILDebugScope *>(), InlinedAt);
InlinedScopeCache.insert({CalleeScope, InlinedScope});
return InlinedScope;
}
//===----------------------------------------------------------------------===//
// Cost Model
//===----------------------------------------------------------------------===//

View File

@@ -51,3 +51,4 @@ public func f(_ i : Int) -> Int { // 301
// CHECK-SAME: inlinedAt: ![[L2:.*]])
// CHECK: ![[L2]] = !DILocation(line: 203, column: 13, scope: ![[G_SCOPE]],
// CHECK-SAME: inlinedAt: ![[L3]])

View File

@@ -7,7 +7,7 @@ import Swift
import SwiftShims
//CHECK-LABEL: caller_function
//CHECK-LABEL: sil @caller_function
//CHECK-NOT: try_apply
//CHECK: throw {{.*}} : $Error
sil @caller_function : $@convention(thin) () -> @error Error {
@@ -24,7 +24,7 @@ bb2(%5 : $Error): // Preds: bb0
throw %5 : $Error // id: %6
}
//CHECK-LABEL: callee_function
//CHECK-LABEL: sil [always_inline] @callee_function
//CHECK: return
// main.inner () throws -> ()