mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Change the optimizer to only make specializations [fragile] if both the original callee is [fragile] *and* the caller is [fragile]. Otherwise, the specialized callee might be [fragile] even if it is never called from a [fragile] function, which inhibits the optimizer from devirtualizing calls inside the specialization. This opens up some missed optimization opportunities in the performance inliner and devirtualization, which currently reject fragile->non-fragile references: TEST | OLD_MIN | NEW_MIN | DELTA (%) | SPEEDUP --- | --- | --- | --- | --- DictionaryRemoveOfObjects | 38391 | 35859 | -6.6% | **1.07x** Hanoi | 5853 | 5288 | -9.7% | **1.11x** Phonebook | 18287 | 14988 | -18.0% | **1.22x** SetExclusiveOr_OfObjects | 20001 | 15906 | -20.5% | **1.26x** SetUnion_OfObjects | 16490 | 12370 | -25.0% | **1.33x** Right now, passes other than performance inlining and devirtualization of class methods are not checking invariants on [fragile] functions at all, which was incorrect; as part of the work on building the standard library with -enable-resilience, I added these checks, which regressed performance with resilience disabled. This patch makes up for these regressions. Furthermore, once SIL type lowering is aware of resilience, this will allow the stack promotion pass to make further optimizations after specializing [fragile] callees.
100 lines
3.6 KiB
C++
100 lines
3.6 KiB
C++
//===--- GenericCloner.h - Specializes generic functions -------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This contains the definition of a cloner class for creating specialized
|
|
// versions of generic functions by substituting concrete types.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SIL_GENERICCLONER_H
|
|
#define SWIFT_SIL_GENERICCLONER_H
|
|
|
|
#include "swift/AST/Type.h"
|
|
#include "swift/SIL/SILFunction.h"
|
|
#include "swift/SIL/SILInstruction.h"
|
|
#include "swift/SIL/TypeSubstCloner.h"
|
|
#include "swift/SILOptimizer/Utils/Local.h"
|
|
#include "swift/SILOptimizer/Utils/Generics.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include <functional>
|
|
|
|
namespace swift {
|
|
|
|
class GenericCloner : public TypeSubstCloner<GenericCloner> {
|
|
IsFragile_t Fragile;
|
|
const ReabstractionInfo &ReInfo;
|
|
CloneCollector::CallbackType Callback;
|
|
|
|
public:
|
|
friend class SILCloner<GenericCloner>;
|
|
|
|
GenericCloner(SILFunction *F,
|
|
IsFragile_t Fragile,
|
|
const ReabstractionInfo &ReInfo,
|
|
TypeSubstitutionMap &ContextSubs,
|
|
ArrayRef<Substitution> ParamSubs,
|
|
StringRef NewName,
|
|
CloneCollector::CallbackType Callback)
|
|
: TypeSubstCloner(*initCloned(F, Fragile, ReInfo, NewName), *F, ContextSubs,
|
|
ParamSubs), ReInfo(ReInfo), Callback(Callback) {
|
|
assert(F->getDebugScope()->Parent != getCloned()->getDebugScope()->Parent);
|
|
}
|
|
/// Clone and remap the types in \p F according to the substitution
|
|
/// list in \p Subs. Parameters are re-abstracted (changed from indirect to
|
|
/// direct) according to \p ReInfo.
|
|
static SILFunction *
|
|
cloneFunction(SILFunction *F,
|
|
IsFragile_t Fragile,
|
|
const ReabstractionInfo &ReInfo,
|
|
TypeSubstitutionMap &ContextSubs,
|
|
ArrayRef<Substitution> ParamSubs,
|
|
StringRef NewName,
|
|
CloneCollector::CallbackType Callback =nullptr) {
|
|
// Clone and specialize the function.
|
|
GenericCloner SC(F, Fragile, ReInfo, ContextSubs, ParamSubs,
|
|
NewName, 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(Orig, Cloned);
|
|
|
|
SILClonerWithScopes<GenericCloner>::postProcess(Orig, Cloned);
|
|
}
|
|
|
|
private:
|
|
static SILFunction *initCloned(SILFunction *Orig,
|
|
IsFragile_t Fragile,
|
|
const ReabstractionInfo &ReInfo,
|
|
StringRef NewName);
|
|
/// Clone the body of the function into the empty function that was created
|
|
/// by initCloned.
|
|
void populateCloned();
|
|
SILFunction *getCloned() { return &getBuilder().getFunction(); }
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|