mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Update the generic specializer to maintain the call graph.
Swift SVN r27024
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!");
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user