Reference-count inlined functions to keep them alive until we emit debug

info for them and generally clean up the inline scope handling a bit.
Fix the debug scope handling for all clients of SILCloner, especially
the SIL-level spezializers and inliners.
This also adds a ton of additional assertions that will ensure that
future optimization passes won't mess with the debug info in a way that
could confuse the LLVM backend.

Swift SVN r18984
This commit is contained in:
Adrian Prantl
2014-06-18 22:34:10 +00:00
parent 588fb22c40
commit b1a7a7af1b
14 changed files with 171 additions and 100 deletions

View File

@@ -145,29 +145,56 @@ template<typename ImplClass>
class SILClonerWithScopes : public SILCloner<ImplClass> {
friend class SILCloner<ImplClass>;
public:
SILClonerWithScopes(SILFunction &To) : SILCloner<ImplClass>(To) {}
SILClonerWithScopes(SILFunction &To) : SILCloner<ImplClass>(To) {
auto OrigScope = To.getDebugScope();
assert(OrigScope && "function without scope");
if (!OrigScope || OrigScope->SILFn == &To)
// Cloning into the same function, nothing to do.
return;
// If we are cloning the entire function, the scope of the cloned
// function needs to hash to a different value than the original
// scope, so create a copy.
auto ClonedScope = new (To.getModule()) SILDebugScope(*OrigScope);
ClonedScope->SILFn = &To;
To.setDebugScope(ClonedScope);
}
private:
llvm::SmallDenseMap<SILDebugScope *, SILDebugScope *> ClonedScopeCache;
SILDebugScope *getOrCreateClonedScope(SILDebugScope *OrigScope) {
auto &NewFn = SILCloner<ImplClass>::getBuilder().getFunction();
// Reparent top-level nodes into the new function.
if (!OrigScope || (!OrigScope->Parent && !OrigScope->InlinedCallSite)) {
assert(NewFn.getDebugScope()->SILFn == &NewFn);
return NewFn.getDebugScope();
}
auto it = ClonedScopeCache.find(OrigScope);
if (it != ClonedScopeCache.end())
return it->second;
auto Parent = OrigScope->Parent
? getOrCreateClonedScope(OrigScope->Parent) : nullptr;
auto &ClonedFn = SILCloner<ImplClass>::getBuilder().getFunction();
auto CloneScope = new (ClonedFn.getModule())
SILDebugScope(OrigScope->Loc, ClonedFn, Parent);
// Create an inline scope for the cloned instruction.
auto CloneScope = new (NewFn.getModule()) SILDebugScope(*OrigScope);
if (OrigScope->InlinedCallSite) {
// For inlined functions, we need to rewrite the inlined call site.
CloneScope->InlinedCallSite =
getOrCreateClonedScope(OrigScope->InlinedCallSite);
} else {
CloneScope->SILFn = &NewFn;
CloneScope->Parent = getOrCreateClonedScope(OrigScope->Parent);
}
ClonedScopeCache.insert({OrigScope, CloneScope});
return CloneScope;
}
protected:
/// Clone the SILDebugScope for the specialized function.
/// Clone the SILDebugScope for the cloned function.
void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
if (auto OrigScope = Orig->getDebugScope())
Cloned->setDebugScope(getOrCreateClonedScope(OrigScope));
auto ClonedScope = getOrCreateClonedScope(Orig->getDebugScope());
Cloned->setDebugScope(ClonedScope);
SILCloner<ImplClass>::postProcess(Orig, Cloned);
}
};
@@ -205,9 +232,6 @@ template<typename ImplClass>
void
SILCloner<ImplClass>::postProcess(SILInstruction *Orig,
SILInstruction *Cloned) {
// SILDebugScope *DebugScope = Orig->getDebugScope();
// if (DebugScope && !Cloned->getDebugScope())
// Cloned->setDebugScope(DebugScope);
assert((Orig->getDebugScope() ? Cloned->getDebugScope()!=nullptr : true) &&
"cloned function without a debug scope");
InstructionMap.insert(std::make_pair(Orig, Cloned));

View File

@@ -35,7 +35,7 @@ public:
/// 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.
SILDebugScope *InlineScope;
SILDebugScope *InlinedCallSite;
/// The SILFunction that the scope belongs to. Inlined functions may
/// be elided, so keep track of their type here.
/// FIXME: Storing this for every scope is wasteful. We only need
@@ -44,22 +44,21 @@ public:
SILDebugScope(SILLocation Loc,
SILFunction &SILFn,
SILDebugScope *Parent = nullptr,
SILDebugScope *InlineScope = nullptr)
: Loc(Loc), Parent(Parent), InlineScope(InlineScope),
SILDebugScope *Parent = nullptr)
: Loc(Loc), Parent(Parent), InlinedCallSite(nullptr),
SILFn(&SILFn)
{ }
/// Create a scope for an artificial function.
SILDebugScope(SILLocation Loc)
: Loc(Loc), Parent(nullptr), InlineScope(nullptr), SILFn(nullptr)
: Loc(Loc), Parent(nullptr), InlinedCallSite(nullptr), SILFn(nullptr)
{ }
/// Create an inlined version of CalleeScope.
SILDebugScope(SILDebugScope *CallSiteScope, SILDebugScope *CalleeScope,
SILFunction &SILFn)
SILFunction *InlinedFn)
: Loc(CalleeScope->Loc), Parent(CalleeScope->Parent),
InlineScope(CallSiteScope), SILFn(&SILFn) {
InlinedCallSite(CallSiteScope), SILFn(InlinedFn) {
assert(CallSiteScope && CalleeScope);
}

View File

@@ -120,7 +120,10 @@ public:
SILLocation getLoc() const { return Loc; }
SILDebugScope *getDebugScope() const { return DebugScope; }
SILInstruction *setDebugScope(SILDebugScope *DS) { DebugScope = DS; return this; }
SILInstruction *setDebugScope(SILDebugScope *DS) {
DebugScope = DS;
return this;
}
/// removeFromParent - This method unlinks 'self' from the containing basic
/// block, but does not delete it.

View File

@@ -102,6 +102,9 @@ private:
/// functions so that the destructor of \p functions is called first.
llvm::StringMap<SILFunction *> FunctionTable;
/// List of inlined functions referenced by the module.
llvm::DenseSet<SILFunction *> InlinedFunctions;
/// The list of SILFunctions in the module.
FunctionListType functions;
@@ -336,6 +339,11 @@ public:
IsBare_t isBareSILFunction,
IsTransparent_t isTransparent);
void markFunctionAsInlined(SILFunction *Fn) {
if (InlinedFunctions.insert(Fn).second)
Fn->incrementRefCount();
}
/// Look up the SILWitnessTable representing the lowering of a protocol
/// conformance, and collect the substitutions to apply to the referenced
/// witnesses, if any.

View File

@@ -67,7 +67,7 @@ private:
if (IKind == InlineKind::MandatoryInline)
// Transparent functions are inheriting the location of the call
// site. No soup, err, debugging for you!
Cloned->setDebugScope(CallSiteScope);
Cloned->setDebugScope(Orig->getDebugScope());
else
// Create an inlined version of the scope.
Cloned->setDebugScope(getOrCreateInlineScope(Orig));
@@ -81,7 +81,7 @@ private:
return InLoc;
// Inlined location wraps the call site that is being inlined, regardless
// of the input location.
return Loc.hasValue() ? Loc.getValue() : InLoc;
return Loc.hasValue() ? Loc.getValue() : SILLocation((Decl*)nullptr);
}
InlineKind IKind;

View File

@@ -340,28 +340,28 @@ static bool isAbstractClosure(const SILLocation &Loc) {
}
/// Construct an inlined-at location from a SILScope.
llvm::MDNode* IRGenDebugInfo::createInlinedAt(SILDebugScope &InlinedScope) {
assert(InlinedScope.InlineScope && "not an inlined scope");
SILDebugScope &Scope = *InlinedScope.InlineScope;
llvm::MDNode* IRGenDebugInfo::createInlinedAt(SILDebugScope *InlinedScope) {
assert(InlinedScope);
assert(InlinedScope->InlinedCallSite && "not an inlined scope");
SILDebugScope *CallSite = InlinedScope->InlinedCallSite;
#ifndef NDEBUG
llvm::DILexicalBlock LB(getOrCreateScope(&InlinedScope));
llvm::DILexicalBlock LB(getOrCreateScope(InlinedScope));
while (!LB.isSubprogram()) {
LB = llvm::DILexicalBlock(LB.getContext());
assert(LB && "Lexical block parent chain must contain a subprogram");
}
#endif
assert(Scope.Parent);
auto ParentScope = getOrCreateScope(Scope.Parent);
auto ParentScope = getOrCreateScope(CallSite->Parent);
llvm::MDNode *InlinedAt = nullptr;
// If this is itself an inlined location, recursively create the
// inlined-at location for it.
if (Scope.InlineScope)
InlinedAt = createInlinedAt(Scope);
if (CallSite->InlinedCallSite)
InlinedAt = createInlinedAt(CallSite);
auto InlineLoc = getLocation(SM, Scope.Loc).LocForLinetable;
auto InlineLoc = getLocation(SM, CallSite->Loc).LocForLinetable;
auto DL = llvm::DebugLoc::get(InlineLoc.Line, InlineLoc.Col,
ParentScope, InlinedAt);
return DL.getAsMDNode(IGM.getLLVMContext());
@@ -413,9 +413,9 @@ void IRGenDebugInfo::setCurrentLoc(IRBuilder &Builder, SILDebugScope *DS,
LastScope = DS;
llvm::MDNode *InlinedAt = nullptr;
if (DS && DS->InlineScope) {
if (DS && DS->InlinedCallSite) {
assert(Scope && "Inlined location without a lexical scope");
InlinedAt = createInlinedAt(*DS);
InlinedAt = createInlinedAt(DS);
}
assert(((!InlinedAt) || (InlinedAt && Scope)) && "inlined w/o scope");
@@ -438,26 +438,36 @@ llvm::DIDescriptor IRGenDebugInfo::getOrCreateScope(SILDebugScope *DS) {
// If this is a (inlined) function scope, the function may
// not have been created yet.
//assert(DS->InlinedFunction && "non-inlined function was elided");
if (DS->Loc.getKind() == SILLocation::SILFileKind ||
if (!DS->Parent ||
DS->Loc.getKind() == SILLocation::SILFileKind ||
DS->Loc.isASTNode<AbstractFunctionDecl>() ||
DS->Loc.isASTNode<AbstractClosureExpr>()) {
DS->Loc.isASTNode<AbstractClosureExpr>() ||
DS->Loc.isASTNode<EnumElementDecl>()) {
auto FnScope = DS->SILFn->getDebugScope();
// FIXME: This is a bug in the SIL deserialization.
if (!FnScope)
DS->SILFn->setDebugScope(DS);
auto CachedScope = ScopeCache.find(FnScope);
if (CachedScope != ScopeCache.end())
return llvm::DIDescriptor(cast<llvm::MDNode>(CachedScope->second));
// FIXME: This is a bug in the SIL deserialization.
if (!DS->SILFn->getDebugScope()) {
FnScope = DS;
DS->SILFn->setDebugScope(DS);
}
assert(DS->SILFn->getRefCount() > 0);
// Force the debug info for the function to be emitted, even if it
// is external.
emitFunction(*DS->SILFn, nullptr, true);
return llvm::DIDescriptor(cast<llvm::MDNode>(ScopeCache[FnScope]));
// is external or has been inlined.
llvm::Function *Fn = nullptr;
if (!DS->SILFn->getName().empty())
Fn = IGM.getAddrOfSILFunction(DS->SILFn, NotForDefinition);
llvm::DIDescriptor SP = emitFunction(*DS->SILFn, Fn, true);
// Cache it.
ScopeCache[DS] = llvm::WeakVH(SP);
return SP;
}
assert(DS->Parent && "lexical block must have a parent subprogram");
Location L = getLocation(SM, DS->Loc).Loc;
llvm::DIFile File = getOrCreateFile(L.Filename);
llvm::DIDescriptor Parent = getOrCreateScope(DS->Parent);
@@ -658,19 +668,28 @@ static bool isAllocatingConstructor(AbstractCC CC, DeclContext *DeclCtx) {
return CC != AbstractCC::Method && DeclCtx && isa<ConstructorDecl>(DeclCtx);
}
void IRGenDebugInfo::emitFunction(SILModule &SILMod, SILDebugScope *DS,
llvm::Function *Fn, AbstractCC CC,
SILType SILTy, DeclContext *DeclCtx) {
llvm::DIDescriptor IRGenDebugInfo::
emitFunction(SILModule &SILMod, SILDebugScope *DS, llvm::Function *Fn,
AbstractCC CC, SILType SILTy, DeclContext *DeclCtx) {
// Returned a previously cached entry for an abstract (inlined) function.
auto cached = ScopeCache.find(DS);
if (cached != ScopeCache.end())
return llvm::DIDescriptor(cast<llvm::MDNode>(cached->second));
StringRef Name;
Location L = {};
unsigned ScopeLine = 0; // The source line used for the function prologue.
if (DS) {
if (DS->Loc.getKind() == SILLocation::SILFileKind)
Name = DS->SILFn->getName();
else
Name = getName(DS->Loc);
auto FL = getLocation(SM, DS->Loc);
L = FL.Loc;
ScopeLine = FL.LocForLinetable.Line;
}
auto LinkageName = Fn ? Fn->getName() : "";
auto LinkageName = Fn ? Fn->getName() : Name;
auto File = getOrCreateFile(L.Filename);
auto Scope = MainModule;
auto Line = L.Line;
@@ -734,17 +753,10 @@ void IRGenDebugInfo::emitFunction(SILModule &SILMod, SILDebugScope *DS,
EntryPointFn->replaceAllUsesWith(SP);
if (!DS)
return;
return llvm::DIDescriptor();
// Replace any forward declarations referenced by inlined versions
// of this function with the real thing.
auto fwdDecl = ScopeCache.find(DS);
if (fwdDecl != ScopeCache.end()) {
//assert(llvm::DIType(cast<llvm::MDNode>(fwdDecl->second)).isForwardDecl()
// && "not a forward decl");
fwdDecl->second->replaceAllUsesWith(SP);
}
ScopeCache[DS] = llvm::WeakVH(SP);
return SP;
}
/// TODO: This is no longer needed.
@@ -826,11 +838,17 @@ llvm::DIModule IRGenDebugInfo::getOrCreateModule(llvm::DIScope Parent,
return M;
}
void IRGenDebugInfo::emitFunction(SILFunction &SILFn, llvm::Function *Fn,
llvm::DIDescriptor IRGenDebugInfo::emitFunction(SILFunction &SILFn,
llvm::Function *Fn,
bool Force) {
if (!Force && isAvailableExternally(SILFn.getLinkage()))
return;
emitFunction(SILFn.getModule(), SILFn.getDebugScope(), Fn,
return llvm::DIDescriptor();
auto DS = SILFn.getDebugScope();
if (DS && !DS->SILFn)
DS->SILFn = &SILFn;
return emitFunction(SILFn.getModule(), SILFn.getDebugScope(), Fn,
SILFn.getAbstractCC(), SILFn.getLoweredType(),
SILFn.getDeclContext());
}
@@ -980,8 +998,10 @@ void IRGenDebugInfo::emitVariableDeclaration(
IRBuilder &Builder, ArrayRef<llvm::Value *> Storage, DebugTypeInfo DbgTy,
SILDebugScope *DS, StringRef Name, unsigned Tag, unsigned ArgNo,
IndirectionKind Indirection, ArtificialKind Artificial) {
// FIXME: enable this assertion.
// assert(DS);
// FIXME: Make this an assertion.
if (!DS)
return;
llvm::DIDescriptor Scope = getOrCreateScope(DS);
Location Loc = getLoc(SM, DbgTy.getDecl());
@@ -1034,8 +1054,8 @@ void IRGenDebugInfo::emitVariableDeclaration(
}
// Create inlined variables.
if (DS && DS->InlineScope) {
auto InlinedAt = createInlinedAt(*DS);
if (DS && DS->InlinedCallSite) {
auto InlinedAt = createInlinedAt(DS);
Descriptor = createInlinedVariable(Descriptor, InlinedAt, M.getContext());
}
@@ -1104,9 +1124,9 @@ void IRGenDebugInfo::emitVariableDeclaration(
// Set the location/scope of the intrinsic.
llvm::MDNode *InlinedAt = nullptr;
if (DS && DS->InlineScope) {
if (DS && DS->InlinedCallSite) {
assert(Scope && "Inlined location without a lexical scope");
InlinedAt = createInlinedAt(*DS);
InlinedAt = createInlinedAt(DS);
}
Call->setDebugLoc(llvm::DebugLoc::get(Line, Loc.Col, Scope, InlinedAt));
}

View File

@@ -141,11 +141,13 @@ public:
/// \param Fn The IR representation of the function.
/// \param CC The calling convention of the function.
/// \param Ty The signature of the function.
void emitFunction(SILModule &SILMod, SILDebugScope *DS, llvm::Function *Fn,
AbstractCC CC, SILType Ty, DeclContext *DeclCtx = nullptr);
llvm::DIDescriptor emitFunction(SILModule &SILMod, SILDebugScope *DS,
llvm::Function *Fn, AbstractCC CC, SILType Ty,
DeclContext *DeclCtx = nullptr);
/// Emit debug info for a given SIL function.
void emitFunction(SILFunction &SILFn, llvm::Function *Fn, bool Force = false);
llvm::DIDescriptor emitFunction(SILFunction &SILFn, llvm::Function *Fn,
bool Force = false);
/// Convenience function useful for functions without any source
/// location. Internally calls emitFunction, emits a debug
@@ -216,7 +218,7 @@ private:
llvm::DIType getOrCreateType(DebugTypeInfo DbgTy);
llvm::DIDescriptor getOrCreateScope(SILDebugScope *DS);
llvm::DIScope getOrCreateContext(DeclContext *DC);
llvm::MDNode* createInlinedAt(SILDebugScope &Scope);
llvm::MDNode* createInlinedAt(SILDebugScope *Scope);
StringRef getCurrentDirname();
llvm::DIFile getOrCreateFile(const char *Filename);

View File

@@ -30,6 +30,7 @@
#include "swift/AST/ASTContext.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/SIL/PrettyStackTrace.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILLinkage.h"
#include "swift/SIL/SILModule.h"
@@ -763,6 +764,9 @@ emitPHINodesForBBArgs(IRGenSILFunction &IGF,
if (!silBB->empty()) {
SILInstruction &I = *silBB->begin();
auto DS = I.getDebugScope();
// FIXME: This should be an assertion.
if (DS && DS->SILFn != IGF.CurSILFn && !DS->InlinedCallSite)
DS = IGF.CurSILFn->getDebugScope();
if (!DS) DS = IGF.CurSILFn->getDebugScope();
IGF.IGM.DebugInfo->setCurrentLoc(IGF.Builder, DS, I.getLoc());
}
@@ -1324,6 +1328,12 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) {
}
auto DS = I.getDebugScope();
// FIXME: This should be an assertion.
if (DS && DS->SILFn != CurSILFn && !DS->InlinedCallSite) {
DS = CurSILFn->getDebugScope();
assert(DS->SILFn == CurSILFn);
}
if (!DS) DS = CurSILFn->getDebugScope();
if (!DS)
// Until DebugScopes are properly serialized, bare functions
@@ -2470,8 +2480,11 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) {
Decl->getType()->getLValueOrInOutObjectType(),
type);
auto Name = Decl->getName().str();
auto DS = i->getDebugScope();
if (!DS) DS = CurSILFn->getDebugScope();
assert(DS->SILFn == CurSILFn || DS->InlinedCallSite);
emitDebugVariableDeclaration(Builder, addr.getAddress().getAddress(),
DTI, i->getDebugScope(), Name);
DTI, DS, Name);
}
setLoweredAddress(i->getContainerResult(), addr.getContainer());

View File

@@ -93,6 +93,9 @@ SILModule::SILModule(Module *SwiftModule)
}
SILModule::~SILModule() {
for (SILFunction *F : InlinedFunctions)
F->decrementRefCount();
// Drop everything functions in this module reference.
//
// This is necessary since the functions may reference each other. We don't

View File

@@ -245,14 +245,10 @@ SILFunction *FunctionSignatureOptCloner::initCloned(
OldFTy->getGenericSignature(), OldFTy->getExtInfo(),
OldFTy->getCalleeConvention(), InterfaceParams, InterfaceResult, Ctx);
// This scope needs to hash to a different value than the original scope.
auto OrigScope = Orig.getDebugScope();
auto ClonedScope = new (M) SILDebugScope(*OrigScope);
// Create the new function.
SILFunction *NewF = SILFunction::create(
M, OptimizedLinkage, NewName, NewFTy, nullptr, Orig.getLocation(),
Orig.isBare(), Orig.isTransparent(), 0, ClonedScope,
Orig.isBare(), Orig.isTransparent(), 0, Orig.getDebugScope(),
Orig.getDeclContext());
// Return our newly created F for cloning.

View File

@@ -87,17 +87,13 @@ SILFunction *SpecializingCloner::initCloned(SILFunction *Orig,
&& "SILFunction missing DebugScope");
assert(!Orig->isGlobalInit() && "Global initializer cannot be cloned");
// This scope needs to hash to a different value than the original scope.
auto OrigScope = Orig->getDebugScope();
auto ClonedScope = OrigScope ? new (M) SILDebugScope(*OrigScope) : nullptr;
// Create a new empty function.
SILFunction *NewF =
SILFunction::create(M, getSpecializedLinkage(Orig->getLinkage()),
NewName, FTy, nullptr,
Orig->getLocation(), Orig->isBare(),
Orig->isTransparent(), 0,
ClonedScope, Orig->getDeclContext());
Orig->getDebugScope(), Orig->getDeclContext());
NumSpecialized++;
return NewF;

View File

@@ -66,7 +66,12 @@ bool SILInliner::inlineFunction(ApplyInst *AI,
AIScope = AI->getParent()->getParent()->getDebugScope();
CallSiteScope = new (F.getModule())
SILDebugScope(AI->getLoc(), F, AIScope, AIScope->InlineScope);
SILDebugScope(AI->getLoc(), F, AIScope);
CallSiteScope->InlinedCallSite = AIScope->InlinedCallSite;
// Increment the ref count for the inlined function, so it doesn't
// get deleted before we can emit abstract debug info for it.
F.getModule().markFunctionAsInlined(CalleeFunction);
assert(CallSiteScope ||
AI->getLoc().getKind() == SILLocation::MandatoryInlinedKind);
@@ -175,15 +180,18 @@ void SILInliner::visitDebugValueAddrInst(DebugValueAddrInst *Inst) {
SILDebugScope *SILInliner::getOrCreateInlineScope(SILInstruction *Orig) {
auto CalleeScope = Orig->getDebugScope();
// We need to fake a scope to add the inline info to it.
if (!CalleeScope)
return nullptr;
CalleeScope = Orig->getParent()->getParent()->getDebugScope();
auto it = InlinedScopeCache.find(CalleeScope);
if (it != InlinedScopeCache.end())
return it->second;
auto InlineScope = new (getBuilder().getFunction().getModule())
SILDebugScope(CallSiteScope, CalleeScope, *CalleeFunction);
SILDebugScope(CallSiteScope, CalleeScope, CalleeScope->SILFn);
assert(CallSiteScope->Parent == InlineScope->InlinedCallSite->Parent);
InlinedScopeCache.insert({CalleeScope, InlineScope});
return InlineScope;
}

View File

@@ -17,11 +17,9 @@ println(basic.foo(1, 2))
// DWARF: .debug_info
// DWARF: DW_TAG_module
// DWARF-NEXT: "Foo"
// DWARF: DW_TAG_module
// DWARF-NEXT: "Swift"
// DWARF: DW_TAG_module
// DWARF-NEXT: "basic"
// DWARF-DAG: "Foo"
// DWARF-DAG: "Swift"
// DWARF-DAG: "basic"
// DWARF-DAG: file_names{{.*}} Imports.swift
// DWARF-DAG: file_names{{.*}} Swift.swiftmodule

View File

@@ -1,20 +1,21 @@
// RUN: %swift -target x86_64-apple-darwin %s -O1 -sil-inline-threshold 100 -emit-ir -g -o - | FileCheck %s
// CHECK: define i32 @main
// CHECK: tail call { i64, i1 } @llvm.smul.with.overflow.i64(i64 %[[C:.*]], i64 %[[C]]), !dbg ![[SCOPE:.*]]
// CHECK: tail call { i64, i1 } @llvm.smul.with.overflow.i64(i64 %[[C:.*]], i64 %[[C]]), !dbg ![[MULSCOPE:.*]]
// CHECK: ![[TOPLEVEL:.*]] = {{.*}}; [ DW_TAG_file_type ] [{{.*}}/inlinescopes.swift]
// CHECK: ![[MAIN:.*]] = {{.*}}"main"{{.*}}[ DW_TAG_subprogram ]
// CHECK: metadata !{i32 786484, {{.*}}metadata !"_Tv12inlinescopes1ySi", metadata ![[TOPLEVEL]]{{.*}} ; [ DW_TAG_variable ] [y]
// CHECK: ![[INLINED_TOPLEVEL:.*]] = metadata !{i32 0, i32 0, metadata ![[MAIN:.*]], null}
// CHECK=DAG: ![[MAIN:.*]] = {{.*}}"main"{{.*}}[ DW_TAG_subprogram ]
// CHECK=DAG: metadata !{i32 786484, {{.*}}metadata !"_Tv12inlinescopes1ySi", metadata ![[TOPLEVEL]]{{.*}} ; [ DW_TAG_variable ] [y]
// CHECK-DAG: ![[INLINED_TOPLEVEL:.*]] = metadata !{i32 0, i32 0, metadata ![[MAIN:.*]], null}
func square(x : Int) -> Int {
// CHECK: ![[SCOPE]] = metadata !{i32 [[@LINE+2]], i32 {{.*}}, metadata ![[PARENT:.*]], metadata ![[INLINED:.*]]}
// CHECK: ![[PARENT]] = metadata !{i32 786443,
// CHECK-DAG: ![[MULSCOPE]] = metadata !{i32 [[@LINE+3]], i32 {{.*}}, metadata ![[MULBLOCK:.*]], metadata ![[INLINED:.*]]}
// CHECK-DAG: ![[MUL:.*]] = {{.*}}[ DW_TAG_subprogram ] [line 0] [def] [_TFSsoi1mFTSiSi_Si]
// CHECK-DAG: ![[MULBLOCK]] = {{.*}} metadata ![[MUL]]} ; [ DW_TAG_lexical_block ]
let res = x * x
return res
}
let c = Int(C_ARGC)
// CHECK: ![[INLINED]] = metadata !{i32 [[@LINE+1]], i32 {{.*}}, metadata !{{.*}}, metadata ![[INLINED_TOPLEVEL:.*]]}
// CHECK-DAG ![[INLINED]] = metadata !{i32 [[@LINE+1]], i32 {{.*}}, metadata !{{.*}}, metadata ![[INLINED_TOPLEVEL:.*]]}
let y = square(c)
println(y)