Files
swift-mirror/lib/SILPasses/GenericSpecializer.cpp
Mark Lacey 23b6bd84f6 Do not build the call graph just to maintain it.
Before this commit, passes that were attempting to maintain the call
graph would actually build it if it wasn't already valid, just for the
sake of maintaining it.

Now we only maintain it if we already had a valid call graph built.

Swift SVN r26873
2015-04-02 17:16:01 +00:00

158 lines
4.6 KiB
C++

//===-- Specializer.cpp ------ Performs Generic Specialization ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "generic-specializer"
#include "swift/SILPasses/Utils/Generics.h"
#include "swift/SILPasses/Passes.h"
#include "swift/AST/ASTContext.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "swift/SILAnalysis/CallGraphAnalysis.h"
#include "swift/SILPasses/Utils/Generics.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILPasses/Transforms.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/SmallString.h"
using namespace swift;
namespace {
struct GenericSpecializer {
GenericSpecializer() {}
private:
/// A worklist of functions to specialize.
std::vector<SILFunction*> Worklist;
bool specializeApplyInstGroup(llvm::SmallVectorImpl<ApplySite> &NewApplies);
public:
/// Collect and specialize calls in a specific order specified by
/// \p BotUpFuncList.
bool specialize(const std::vector<SILFunction *> &BotUpFuncList);
};
static void addApplyInst(ApplySite AI,
llvm::SmallVectorImpl<ApplySite> &NewApplies) {
if (!AI || !AI.hasSubstitutions())
return;
SILValue CalleeVal = AI.getCallee();
FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(CalleeVal);
if (!FRI)
return;
SILFunction *Callee = FRI->getReferencedFunction();
auto &M = AI.getInstruction()->getModule();
if (Callee->isExternalDeclaration())
if (!M.linkFunction(Callee, SILModule::LinkingMode::LinkAll))
return;
NewApplies.push_back(AI);
}
static void collectApplyInst(SILFunction &F,
llvm::SmallVectorImpl<ApplySite> &NewApplies) {
// Scan all of the instructions in this function in search of ApplyInsts.
for (auto &BB : F)
for (auto &I : BB)
if (ApplySite AI = ApplySite::isa(&I))
addApplyInst(AI, NewApplies);
}
bool
GenericSpecializer::specializeApplyInstGroup(
llvm::SmallVectorImpl<ApplySite> &NewApplies) {
bool Changed = false;
SILFunction *NewFunction;
for (auto &AI : NewApplies) {
if (trySpecializeApplyOfGeneric(AI, &NewFunction)) {
if (NewFunction)
Worklist.push_back(NewFunction);
Changed = true;
}
}
NewApplies.clear();
return Changed;
}
/// Collect and specialize calls in a specific order specified by
/// \p BotUpFuncList.
bool GenericSpecializer::specialize(const std::vector<SILFunction *>
&BotUpFuncList) {
// Initialize the worklist with a call-graph bottom-up list of functions.
// We specialize the functions in a top-down order, starting from the end
// of the list.
Worklist.insert(Worklist.begin(), BotUpFuncList.begin(),
BotUpFuncList.end());
llvm::SmallVector<ApplySite, 16> NewApplies;
bool Changed = false;
// Try to specialize generic calls.
while (Worklist.size()) {
SILFunction *F = Worklist.back();
Worklist.pop_back();
collectApplyInst(*F, NewApplies);
if (!NewApplies.empty())
Changed |= specializeApplyInstGroup(NewApplies);
assert(NewApplies.empty() && "Expected all applies processed!");
}
return Changed;
}
class SILGenericSpecializerTransform : public SILModuleTransform {
public:
SILGenericSpecializerTransform() {}
void run() override {
CallGraphAnalysis* CGA = PM->getAnalysis<CallGraphAnalysis>();
// Collect a call-graph bottom-up list of functions and specialize the
// functions in reverse order.
auto &CG = CGA->getOrBuildCallGraph();
auto GS = GenericSpecializer();
// Try to specialize generic calls.
bool Changed = GS.specialize(CG.getBottomUpFunctionOrder());
if (Changed) {
// Schedule another iteration of the transformation pipe.
PM->scheduleAnotherIteration();
// We are creating new functions and modifying calls, but we are
// preserving the branches in the existing functions.
invalidateAnalysis(SILAnalysis::PreserveKind::Branches);
}
}
StringRef getName() override { return "Generic Specialization"; }
};
} // end anonymous namespace
SILTransform *swift::createGenericSpecializer() {
return new SILGenericSpecializerTransform();
}