blob: bdf9d6210c8214e34589eb35f4ef16ae7069cec4 [file] [log] [blame]
//===--- UsePrespecialized.cpp - use pre-specialized functions ------------===//
// This source file is part of the 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 for license information
// See for the list of Swift project authors
#define DEBUG_TYPE "use-prespecialized"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/SILOptimizer/Utils/Generics.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "swift/SILOptimizer/Utils/SpecializationMangler.h"
#include "llvm/Support/Debug.h"
using namespace swift;
namespace {
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))
/// A simple pass which replaces each apply of a generic function by an apply
/// of the corresponding pre-specialized function, if such a pre-specialization
/// exists.
class UsePrespecialized: public SILModuleTransform {
~UsePrespecialized() override { }
void run() override {
auto &M = *getModule();
for (auto &F : M) {
if (replaceByPrespecialized(F)) {
invalidateAnalysis(&F, SILAnalysis::InvalidationKind::Everything);
bool replaceByPrespecialized(SILFunction &F);
} // end anonymous namespace
// Analyze the function and replace each apply of
// a generic function by an apply of the corresponding
// pre-specialized function, if such a pre-specialization exists.
bool UsePrespecialized::replaceByPrespecialized(SILFunction &F) {
bool Changed = false;
auto &M = F.getModule();
llvm::SmallVector<ApplySite, 16> NewApplies;
collectApplyInst(F, NewApplies);
for (auto &AI : NewApplies) {
auto *ReferencedF = AI.getReferencedFunctionOrNull();
if (!ReferencedF)
LLVM_DEBUG(llvm::dbgs() << "Trying to use specialized function for:\n";
// Check if it is a call of a generic function.
// If this is the case, check if there is a specialization
// available for it already and use this specialization
// instead of the generic version.
if (!AI.hasSubstitutions())
SubstitutionMap Subs = AI.getSubstitutionMap();
// Bail if any generic type parameters are unbound.
// TODO: Remove this limitation once public partial specializations
// are supported and can be provided by other modules.
if (Subs.hasArchetypes())
ReabstractionInfo ReInfo(M.getSwiftModule(), M.isWholeModule(), AI,
ReferencedF, Subs, IsNotSerialized);
if (!ReInfo.canBeSpecialized())
auto SpecType = ReInfo.getSpecializedType();
// Bail if any generic types parameters of the concrete type
// are unbound.
if (SpecType->hasArchetype())
// Create a name of the specialization. All external pre-specializations
// are serialized without bodies. Thus use IsNotSerialized here.
Mangle::GenericSpecializationMangler NewGenericMangler(ReferencedF,
std::string ClonedName = NewGenericMangler.mangleReabstracted(Subs,
SILFunction *NewF = nullptr;
// If we already have this specialization, reuse it.
auto PrevF = M.lookUpFunction(ClonedName);
if (PrevF) {
LLVM_DEBUG(llvm::dbgs() << "Found a specialization: " << ClonedName
<< "\n");
if (PrevF->getLinkage() != SILLinkage::SharedExternal)
NewF = PrevF;
else {
LLVM_DEBUG(llvm::dbgs() << "Wrong linkage: " << (int)PrevF->getLinkage()
<< "\n");
if (!PrevF || !NewF) {
// Check for the existence of this function in another module without
// loading the function body.
PrevF = lookupPrespecializedSymbol(M, ClonedName);
LLVM_DEBUG(llvm::dbgs() << "Checked if there is a specialization in a "
"different module: "
<< PrevF << "\n");
if (!PrevF)
assert(PrevF->isExternalDeclaration() &&
"Prespecialized function should be an external declaration");
NewF = PrevF;
if (!NewF)
// An existing specialization was found.
LLVM_DEBUG(llvm::dbgs() << "Found a specialization of "
<< ReferencedF->getName()
<< " : " << NewF->getName() << "\n");
auto NewAI = replaceWithSpecializedFunction(AI, NewF, ReInfo);
switch (AI.getKind()) {
case ApplySiteKind::ApplyInst:
case ApplySiteKind::PartialApplyInst:
case ApplySiteKind::TryApplyInst:
case ApplySiteKind::BeginApplyInst:
recursivelyDeleteTriviallyDeadInstructions(AI.getInstruction(), true);
Changed = true;
return Changed;
SILTransform *swift::createUsePrespecialized() {
return new UsePrespecialized();