mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This updates the performance inliner to iterate on inlining in cases where devirtualization or specialization after the first pass of inlining expose new opportunities for inlining. Similarly, in some cases inlining exposes new opportunities for devirtualization, e.g. when we inline an initializer and can now see an alloc_ref that allows us to devirtualize some class_methods. The implementation currently has some inefficiencies which increase the swift compilation time for the stdlib by around 3% (this is swift-time only, no LLVM time, so overall time does not grow by this much). Unfortunately the (unchanged) current implementation of the core inlining trades off improved estimates of code growth for increased compile time, and that plays a part in why compile time increases as much as it does. Despite this, I have some ideas on how to win some of that time back in future patches. Performance differences are mixed, and this will likely require some further inliner tuning to reduce or remove some of the losses seen here at -O. I will open radars for the losses. Wins: DeltaBlue 10.2% EditDistance 13.8% SwiftStructuresInsertionSort 32.6% SwiftStructuresStack 34.9% Losses: PopFrontArrayGeneric -12.7% PrimeNum -19.0% RC4 -30.7% Sim2DArray -14.6% There were a handful of wins and losses at Onone and Ounchecked as well. I'll review the perf testing output and open radars accordingly. The new test case shows an example of the power of the closer integration here. We are able to completely devirtualize and inline a series of class_method applies (10 deep in this case, but in theory substantially deeper) in a single pass of the inliner, whereas before we could only do a single level per pass of inlining & devirtualization. Swift SVN r27561
122 lines
4.3 KiB
C++
122 lines
4.3 KiB
C++
//===- Generics.cpp ---- Utilities for transforming generics ----*- C++ -*-===//
|
|
//
|
|
// 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-utility"
|
|
|
|
#include "swift/SILPasses/Utils/Generics.h"
|
|
|
|
#include "swift/SILPasses/Utils/GenericCloner.h"
|
|
|
|
using namespace swift;
|
|
|
|
// 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<FullApplyCollector::value_type> &NewApplyPairs) {
|
|
NewFunction = nullptr;
|
|
|
|
assert(NewApplyPairs.empty() && "Expected no new applies in vector yet!");
|
|
assert(Apply.hasSubstitutions() && "Expected an apply with substitutions!");
|
|
|
|
auto *F = cast<FunctionRefInst>(Apply.getCallee())->getReferencedFunction();
|
|
assert(F->isDefinition() && "Expected definition to specialize!");
|
|
|
|
DEBUG(llvm::dbgs() << " ApplyInst: " << *Apply.getInstruction());
|
|
|
|
// Create the substitution maps.
|
|
TypeSubstitutionMap InterfaceSubs
|
|
= F->getLoweredFunctionType()->getGenericSignature()
|
|
->getSubstitutionMap(Apply.getSubstitutions());
|
|
|
|
TypeSubstitutionMap ContextSubs
|
|
= F->getContextGenericParams()
|
|
->getSubstitutionMap(Apply.getSubstitutions());
|
|
|
|
// We do not support partial specialization.
|
|
if (hasUnboundGenericTypes(InterfaceSubs)) {
|
|
DEBUG(llvm::dbgs() << " Can not specialize with interface subs.\n");
|
|
return ApplySite();
|
|
}
|
|
|
|
llvm::SmallString<64> ClonedName;
|
|
{
|
|
llvm::raw_svector_ostream buffer(ClonedName);
|
|
ArrayRef<Substitution> Subs = Apply.getSubstitutions();
|
|
Mangle::Mangler M(buffer);
|
|
Mangle::GenericSpecializationMangler Mangler(M, F, Subs);
|
|
Mangler.mangle();
|
|
}
|
|
|
|
SILFunction *NewF;
|
|
auto &M = Apply.getInstruction()->getModule();
|
|
// If we already have this specialization, reuse it.
|
|
if (auto PrevF = M.lookUpFunction(ClonedName)) {
|
|
NewF = PrevF;
|
|
|
|
#ifndef NDEBUG
|
|
// Make sure that NewF's subst type matches the expected type.
|
|
auto Subs = Apply.getSubstitutions();
|
|
auto FTy =
|
|
F->getLoweredFunctionType()->substGenericArgs(M,
|
|
M.getSwiftModule(),
|
|
Subs);
|
|
assert(FTy == NewF->getLoweredFunctionType() &&
|
|
"Previously specialized function does not match expected type.");
|
|
#endif
|
|
} else {
|
|
FullApplyCollector Collector;
|
|
|
|
// Create a new function.
|
|
NewF = GenericCloner::cloneFunction(F, InterfaceSubs, ContextSubs,
|
|
ClonedName, Apply,
|
|
Collector.getCallback());
|
|
for (auto &P : Collector.getApplyPairs())
|
|
NewApplyPairs.push_back(P);
|
|
|
|
NewFunction = NewF;
|
|
}
|
|
|
|
return replaceWithSpecializedFunction(Apply, NewF);
|
|
}
|