Update the generic specializer to maintain the call graph.

Swift SVN r27024
This commit is contained in:
Mark Lacey
2015-04-05 19:27:40 +00:00
parent 56de5fb95e
commit fea3321f59
12 changed files with 166 additions and 78 deletions

View File

@@ -34,6 +34,10 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
typedef SILClonerWithScopes<ImplClass> super;
void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
llvm_unreachable("Clients need to explicitly call a base class impl!");
}
public:
using SILClonerWithScopes<ImplClass>::asImpl;
using SILClonerWithScopes<ImplClass>::getBuilder;

View File

@@ -358,6 +358,7 @@ public:
void replaceApplyWithNew(FullApplySite Old,
llvm::SmallVectorImpl<FullApplySite> &NewApplies);
void addCallGraphNode(SILFunction *F) { CG.addCallGraphNode(F); }
void addEdgesForApply(FullApplySite AI) { CG.addEdgesForApply(AI); }
};
/// The Call Graph Analysis provides information about the call graph.

View File

@@ -24,32 +24,54 @@
#include "swift/SIL/TypeSubstCloner.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include <functional>
namespace swift {
class GenericCloner : public TypeSubstCloner<GenericCloner> {
std::function<void(SILInstruction *)> Callback;
public:
friend class SILCloner<GenericCloner>;
GenericCloner(SILFunction *F,
TypeSubstitutionMap &InterfaceSubs,
TypeSubstitutionMap &ContextSubs,
StringRef NewName,
ArrayRef<Substitution> ApplySubs)
ArrayRef<Substitution> ApplySubs,
std::function<void(SILInstruction *)> Callback)
: TypeSubstCloner(*initCloned(F, InterfaceSubs, NewName), *F, ContextSubs,
ApplySubs) {}
ApplySubs), Callback(Callback) {}
/// Clone and remap the types in \p F according to the substitution
/// list in \p Subs.
static SILFunction *cloneFunction(SILFunction *F,
TypeSubstitutionMap &InterfaceSubs,
TypeSubstitutionMap &ContextSubs,
StringRef NewName, ApplySite Caller) {
StringRef NewName, ApplySite Caller,
std::function<void(SILInstruction *)> Callback =nullptr) {
// Clone and specialize the function.
GenericCloner SC(F, InterfaceSubs, ContextSubs, NewName,
Caller.getSubstitutions());
Caller.getSubstitutions(), Callback);
SC.populateCloned();
SC.cleanUp(SC.getCloned());
return SC.getCloned();
}
protected:
// FIXME: We intentionally call SILClonerWithScopes here to ensure
// the debug scopes are set correctly for cloned
// functions. TypeSubstCloner, SILClonerWithScopes, and
// SILCloner desperately need refactoring and/or combining so
// that the obviously right things are happening for cloning
// vs. inlining.
void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
// Call client-supplied callback function.
if (Callback)
Callback(Cloned);
SILClonerWithScopes<GenericCloner>::postProcess(Orig, Cloned);
}
private:
static SILFunction *initCloned(SILFunction *Orig,
TypeSubstitutionMap &InterfaceSubs,

View File

@@ -19,15 +19,17 @@
#include "swift/AST/Mangle.h"
#include "swift/SIL/Mangle.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/TypeSubstCloner.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
namespace swift {
bool trySpecializeApplyOfGeneric(ApplySite Apply,
SILFunction **NewFunction =nullptr);
ApplySite trySpecializeApplyOfGeneric(ApplySite Apply,
SILFunction **NewFunction,
llvm::SmallVectorImpl<FullApplySite> &NewApplies);
} // end namespace swift

View File

@@ -17,6 +17,7 @@
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILCloner.h"
#include "llvm/ADT/SmallPtrSet.h"
#include <functional>
namespace swift {
class DominanceInfo;
@@ -72,10 +73,6 @@ ApplyInst *findApplyFromDevirtualizedResult(SILInstruction *I);
/// if possible.
void replaceDeadApply(FullApplySite Old, SILInstruction *New);
// Rewrite a call, which may previously have been a dynamic dispatch, to a
// known function reference.
void replaceWithSpecializedFunction(ApplySite site, SILFunction *NewF);
/// \brief Return true if the substitution map contains a
/// substitution that is an unbound generic type.
bool hasUnboundGenericTypes(TypeSubstitutionMap &SubsMap);
@@ -309,6 +306,26 @@ class CastOptimizer {
optimizeUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *Inst);
};
// Helper class that provides a callback that can be used in
// inliners/cloners for collecting FullApplySites.
class FullApplyCollector {
llvm::SmallVector<FullApplySite, 4> Applies;
void collect(SILInstruction *I) {
if (FullApplySite::isa(I))
Applies.push_back(FullApplySite(I));
}
public:
std::function<void(SILInstruction *)> getCallback() {
return std::bind(&FullApplyCollector::collect, this, std::placeholders::_1);
}
llvm::SmallVectorImpl<FullApplySite> &getFullApplies() {
return Applies;
}
};
} // end namespace swift
#endif

View File

@@ -156,6 +156,13 @@ bool CallGraph::tryGetCalleeSet(SILValue Callee,
return false;
auto *CalleeNode = getCallGraphNode(CalleeFn);
// FIXME: Consider whether we should create nodes for these
// initially.
if (!CalleeNode) {
addCallGraphNode(CalleeFn);
CalleeNode = getCallGraphNode(CalleeFn);
}
assert(CalleeNode &&
"Expected to have a call graph node for all functions!");

View File

@@ -199,6 +199,17 @@ public:
SILFunction *getCloned() { return &getBuilder().getFunction(); }
protected:
// FIXME: We intentionally call SILClonerWithScopes here to ensure
// the debug scopes are set correctly for cloned
// functions. TypeSubstCloner, SILClonerWithScopes, and
// SILCloner desperately need refactoring and/or combining so
// that the obviously right things are happening for cloning
// vs. inlining.
void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
SILClonerWithScopes<ClosureCloner>::postProcess(Orig, Cloned);
}
private:
static SILFunction *initCloned(SILFunction *Orig, StringRef ClonedName,
TypeSubstitutionMap &InterfaceSubs,

View File

@@ -28,20 +28,23 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
using namespace swift;
namespace {
struct GenericSpecializer {
GenericSpecializer() {}
GenericSpecializer(CallGraph &CG) : CG(CG) {}
private:
CallGraph &CG;
private:
/// A worklist of functions to specialize.
std::vector<SILFunction*> Worklist;
bool specializeApplyInstGroup(llvm::SmallVectorImpl<ApplySite> &NewApplies);
public:
public:
/// Collect and specialize calls in a specific order specified by
/// \p BotUpFuncList.
bool specialize(const std::vector<SILFunction *> &BotUpFuncList);
@@ -79,19 +82,47 @@ static void collectApplyInst(SILFunction &F,
bool
GenericSpecializer::specializeApplyInstGroup(
llvm::SmallVectorImpl<ApplySite> &NewApplies) {
llvm::SmallVectorImpl<ApplySite> &ApplyGroup) {
bool Changed = false;
SILFunction *NewFunction;
for (auto &AI : NewApplies) {
if (trySpecializeApplyOfGeneric(AI, &NewFunction)) {
if (NewFunction)
llvm::SmallVector<FullApplySite, 4> NewApplies;
CallGraphEditor Editor(CG);
for (auto AI : ApplyGroup) {
// FIXME: Need to add new applies from cloned functions to the call graph!.
auto Specialized = trySpecializeApplyOfGeneric(AI, &NewFunction,
NewApplies);
if (Specialized) {
// We need to add a call graph node first if there was a new
// function created, so that if we notify the call graph of the
// new apply it can look up the node.
if (NewFunction) {
Editor.addCallGraphNode(NewFunction);
Worklist.push_back(NewFunction);
}
// For full applications, we need to notify the call graph of
// the replacement of the old apply with a new one.
if (FullApplySite::isa(Specialized.getInstruction()))
Editor.replaceApplyWithNew(FullApplySite(AI.getInstruction()),
FullApplySite(Specialized.getInstruction()));
// We collect new applies from the cloned function during
// cloning, and need to reflect them in the call graph.
while (!NewApplies.empty()) {
Editor.addEdgesForApply(NewApplies.back());
NewApplies.pop_back();
}
AI.getInstruction()->replaceAllUsesWith(Specialized.getInstruction());
recursivelyDeleteTriviallyDeadInstructions(AI.getInstruction(), true);
Changed = true;
}
}
NewApplies.clear();
ApplyGroup.clear();
return Changed;
}
@@ -132,7 +163,7 @@ public:
// Collect a call-graph bottom-up list of functions and specialize the
// functions in reverse order.
auto &CG = CGA->getOrBuildCallGraph();
auto GS = GenericSpecializer();
auto GS = GenericSpecializer(CG);
// Try to specialize generic calls.
bool Changed = GS.specialize(CG.getBottomUpFunctionOrder());
@@ -142,8 +173,11 @@ public:
PM->scheduleAnotherIteration();
// We are creating new functions and modifying calls, but we are
// preserving the branches in the existing functions.
// preserving the branches in the existing functions, and we are
// maintaining the call graph.
CGA->lockInvalidation();
invalidateAnalysis(SILAnalysis::PreserveKind::Branches);
CGA->unlockInvalidation();
}
}

View File

@@ -756,20 +756,6 @@ static bool isProfitableInColdBlock(ApplyInst *AI) {
return true;
}
class FullApplyCollector {
private:
llvm::SmallVector<FullApplySite, 4> Applies;
public:
void collect(SILInstruction *I) {
if (FullApplySite::isa(I))
Applies.push_back(FullApplySite(I));
}
llvm::SmallVectorImpl<FullApplySite> &getFullApplies() {
return Applies;
}
};
void SILPerformanceInliner::collectCallSitesToInline(SILFunction *Caller,
SmallVectorImpl<ApplyInst *> &CallSitesToInline,
DominanceAnalysis *DA,
@@ -893,16 +879,14 @@ bool SILPerformanceInliner::inlineCallsIntoFunction(SILFunction *Caller,
Args.push_back(Arg);
FullApplyCollector Collector;
std::function<void(SILInstruction *)> Callback =
std::bind(&FullApplyCollector::collect, &Collector,
std::placeholders::_1);
// Notice that we will skip all of the newly inlined ApplyInsts. That's
// okay because we will visit them in our next invocation of the inliner.
TypeSubstitutionMap ContextSubs;
SILInliner Inliner(*Caller, *Callee,
SILInliner::InlineKind::PerformanceInline,
ContextSubs, AI->getSubstitutions(), Callback);
ContextSubs, AI->getSubstitutions(),
Collector.getCallback());
auto Success = Inliner.inlineFunction(AI, Args);
(void) Success;
// We've already determined we should be able to inline this, so

View File

@@ -18,7 +18,6 @@
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILValue.h"
#include "swift/SIL/TypeSubstCloner.h"
#include "swift/SILPasses/Utils/Local.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"

View File

@@ -18,10 +18,45 @@
using namespace swift;
bool swift::trySpecializeApplyOfGeneric(ApplySite Apply,
SILFunction **NewFunction) {
// Create a new apply based on an old one, but with a different
// function being applied.
static ApplySite replaceWithSpecializedFunction(ApplySite AI,
SILFunction *NewF) {
SILLocation Loc = AI.getLoc();
ArrayRef<Substitution> Subst;
SmallVector<SILValue, 4> Arguments;
for (auto &Op : AI.getArgumentOperands()) {
Arguments.push_back(Op.get());
}
SILBuilderWithScope<2> Builder(AI.getInstruction());
FunctionRefInst *FRI = Builder.createFunctionRef(Loc, NewF);
if (auto *TAI = dyn_cast<TryApplyInst>(AI))
return Builder.createTryApply(Loc, FRI, TAI->getSubstCalleeSILType(),
{}, Arguments, TAI->getNormalBB(),
TAI->getErrorBB());
if (isa<ApplyInst>(AI))
return Builder.createApply(Loc, FRI, Arguments);
if (auto *PAI = dyn_cast<PartialApplyInst>(AI))
return Builder.createPartialApply(Loc, FRI,
PAI->getSubstCalleeSILType(),
{},
Arguments,
PAI->getType());
llvm_unreachable("unhandled kind of apply");
}
ApplySite swift::trySpecializeApplyOfGeneric(ApplySite Apply,
SILFunction **NewFunction,
llvm::SmallVectorImpl<FullApplySite> &NewApplies) {
if (NewFunction)
*NewFunction = nullptr;
assert(NewApplies.empty() && "Expected no new applies in vector yet!");
assert(Apply.hasSubstitutions() && "Expected an apply with substitutions!");
@@ -42,7 +77,7 @@ bool swift::trySpecializeApplyOfGeneric(ApplySite Apply,
// We do not support partial specialization.
if (hasUnboundGenericTypes(InterfaceSubs)) {
DEBUG(llvm::dbgs() << " Can not specialize with interface subs.\n");
return false;
return ApplySite();
}
llvm::SmallString<64> ClonedName;
@@ -71,14 +106,17 @@ bool swift::trySpecializeApplyOfGeneric(ApplySite Apply,
"Previously specialized function does not match expected type.");
#endif
} else {
FullApplyCollector Collector;
// Create a new function.
NewF = GenericCloner::cloneFunction(F, InterfaceSubs, ContextSubs,
ClonedName, Apply);
ClonedName, Apply,
Collector.getCallback());
NewApplies = Collector.getFullApplies();
if (NewFunction)
*NewFunction = NewF;
}
// Replace all of the Apply functions with the new function.
replaceWithSpecializedFunction(Apply, NewF);
return true;
return replaceWithSpecializedFunction(Apply, NewF);
}

View File

@@ -197,37 +197,6 @@ void swift::replaceDeadApply(FullApplySite Old, SILInstruction *New) {
recursivelyDeleteTriviallyDeadInstructions(CalleeInst);
}
void swift::replaceWithSpecializedFunction(ApplySite AI, SILFunction *NewF) {
SILLocation Loc = AI.getLoc();
ArrayRef<Substitution> Subst;
SmallVector<SILValue, 4> Arguments;
for (auto &Op : AI.getArgumentOperands()) {
Arguments.push_back(Op.get());
}
SILBuilderWithScope<2> Builder(AI.getInstruction());
FunctionRefInst *FRI = Builder.createFunctionRef(Loc, NewF);
if (auto TAI = dyn_cast<TryApplyInst>(AI)) {
Builder.createTryApply(Loc, FRI, TAI->getSubstCalleeSILType(),
{}, Arguments, TAI->getNormalBB(),
TAI->getErrorBB());
} else {
SILInstruction *NAI = nullptr;
if (isa<ApplyInst>(AI))
NAI = Builder.createApply(Loc, FRI, Arguments);
if (auto PAI = dyn_cast<PartialApplyInst>(AI))
NAI = Builder.createPartialApply(Loc, FRI,
PAI->getSubstCalleeSILType(),
{},
Arguments,
PAI->getType());
AI.getInstruction()->replaceAllUsesWith(NAI);
}
recursivelyDeleteTriviallyDeadInstructions(AI.getInstruction(), true);
}
bool swift::hasUnboundGenericTypes(TypeSubstitutionMap &SubsMap) {
// Check whether any of the substitutions are dependent.
for (auto &entry : SubsMap)