Skip to content

Revert "[sil-capture-propagation] Switch to the new notifyAddFunction API" #8111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions include/swift/SILOptimizer/Utils/Generics.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@ class ReabstractionInfo {
/// to direct.
llvm::SmallBitVector Conversions;

/// If set, indirect to direct conversions should be performned by the generic
/// specializer.
bool ConvertIndirectToDirect;

/// The first NumResults bits in Conversions refer to formal indirect
/// out-parameters.
unsigned NumFormalIndirectResults;
Expand Down Expand Up @@ -134,8 +130,7 @@ class ReabstractionInfo {
/// If specialization is not possible getSpecializedType() will return an
/// invalid type.
ReabstractionInfo(ApplySite Apply, SILFunction *Callee,
SubstitutionList ParamSubs,
bool ConvertIndirectToDirect = true);
SubstitutionList ParamSubs);

/// Constructs the ReabstractionInfo for generic function \p Orig with
/// additional requirements. Requirements may contain new layout,
Expand All @@ -145,15 +140,14 @@ class ReabstractionInfo {
/// Returns true if the \p ParamIdx'th (non-result) formal parameter is
/// converted from indirect to direct.
bool isParamConverted(unsigned ParamIdx) const {
return ConvertIndirectToDirect &&
Conversions.test(ParamIdx + NumFormalIndirectResults);
return Conversions.test(ParamIdx + NumFormalIndirectResults);
}

/// Returns true if the \p ResultIdx'th formal result is converted from
/// indirect to direct.
bool isFormalResultConverted(unsigned ResultIdx) const {
assert(ResultIdx < NumFormalIndirectResults);
return ConvertIndirectToDirect && Conversions.test(ResultIdx);
return Conversions.test(ResultIdx);
}

/// Gets the total number of original function arguments.
Expand Down
122 changes: 30 additions & 92 deletions lib/SILOptimizer/IPO/CapturePropagation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,12 @@
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "capture-prop"
#include "swift/AST/GenericEnvironment.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/Utils/Generics.h"
#include "swift/SILOptimizer/Utils/SpecializationMangler.h"
#include "swift/Demangling/Demangle.h"
#include "swift/SIL/Mangle.h"
#include "swift/SIL/SILCloner.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/TypeSubstCloner.h"
#include "swift/SILOptimizer/Analysis/ColdBlockInfo.h"
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
Expand Down Expand Up @@ -102,17 +99,16 @@ namespace {
/// caller, so the cloned function will have a mix of locations from different
/// functions.
class CapturePropagationCloner
: public TypeSubstCloner<CapturePropagationCloner> {
using SuperTy = TypeSubstCloner<CapturePropagationCloner>;
: public SILClonerWithScopes<CapturePropagationCloner> {
using SuperTy = SILClonerWithScopes<CapturePropagationCloner>;
friend class SILVisitor<CapturePropagationCloner>;
friend class SILCloner<CapturePropagationCloner>;

SILFunction *OrigF;
bool IsCloningConstant;
public:
CapturePropagationCloner(SILFunction *OrigF, SILFunction *NewF,
SubstitutionList Subs)
: SuperTy(*NewF, *OrigF, Subs), OrigF(OrigF), IsCloningConstant(false) {}
CapturePropagationCloner(SILFunction *OrigF, SILFunction *NewF)
: SuperTy(*NewF), OrigF(OrigF), IsCloningConstant(false) {}

void cloneBlocks(OperandValueArrayRef Args);

Expand Down Expand Up @@ -223,20 +219,6 @@ void CapturePropagationCloner::cloneBlocks(
}
}

CanSILFunctionType getPartialApplyInterfaceResultType(PartialApplyInst *PAI) {
SILFunction *OrigF = PAI->getReferencedFunction();
// The new partial_apply will no longer take any arguments--they are all
// expressed as literals. So its callee signature will be the same as its
// return signature.
auto FTy = PAI->getType().castTo<SILFunctionType>();
CanGenericSignature CanGenericSig;
assert(!PAI->hasSubstitutions() || !hasArchetypes(PAI->getSubstitutions()));
FTy = cast<SILFunctionType>(
OrigF->mapTypeOutOfContext(FTy)->getCanonicalType());
auto NewFTy = FTy;
return NewFTy;
}

/// Given a partial_apply instruction, create a specialized callee by removing
/// all constant arguments and adding constant literals to the specialized
/// function body.
Expand All @@ -261,16 +243,12 @@ SILFunction *CapturePropagation::specializeConstClosure(PartialApplyInst *PAI,
// The new partial_apply will no longer take any arguments--they are all
// expressed as literals. So its callee signature will be the same as its
// return signature.
auto NewFTy = getPartialApplyInterfaceResultType(PAI);
NewFTy = Lowering::adjustFunctionType(NewFTy,
SILFunctionType::Representation::Thin);

GenericEnvironment *GenericEnv = nullptr;
if (NewFTy->getGenericSignature())
GenericEnv = OrigF->getGenericEnvironment();
CanSILFunctionType NewFTy =
Lowering::adjustFunctionType(PAI->getType().castTo<SILFunctionType>(),
SILFunctionType::Representation::Thin);
SILFunction *NewF = OrigF->getModule().createFunction(
SILLinkage::Shared, Name, NewFTy,
GenericEnv, OrigF->getLocation(), OrigF->isBare(),
OrigF->getGenericEnvironment(), OrigF->getLocation(), OrigF->isBare(),
OrigF->isTransparent(), Fragile, OrigF->isThunk(),
OrigF->getClassVisibility(), OrigF->getInlineStrategy(),
OrigF->getEffectsKind(),
Expand All @@ -281,28 +259,18 @@ SILFunction *CapturePropagation::specializeConstClosure(PartialApplyInst *PAI,
DEBUG(llvm::dbgs() << " Specialize callee as ";
NewF->printName(llvm::dbgs()); llvm::dbgs() << " " << NewFTy << "\n");

DEBUG(if (PAI->hasSubstitutions()) {
llvm::dbgs() << "CapturePropagation of generic partial_apply:\n";
PAI->dumpInContext();
});
CapturePropagationCloner cloner(OrigF, NewF, PAI->getSubstitutions());
CapturePropagationCloner cloner(OrigF, NewF);
cloner.cloneBlocks(PAI->getArguments());
assert(OrigF->getDebugScope()->Parent != NewF->getDebugScope()->Parent);
return NewF;
}

void CapturePropagation::rewritePartialApply(PartialApplyInst *OrigPAI,
SILFunction *SpecialF) {
DEBUG(llvm::dbgs() << "\n Rewriting a partial apply:\n";
OrigPAI->dumpInContext(); llvm::dbgs() << " with special function: "
<< SpecialF->getName() << "\n";
llvm::dbgs() << "\nThe function being rewritten is:\n";
OrigPAI->getFunction()->dump());

SILBuilderWithScope Builder(OrigPAI);
auto FuncRef = Builder.createFunctionRef(OrigPAI->getLoc(), SpecialF);
auto *T2TF = Builder.createThinToThickFunction(OrigPAI->getLoc(), FuncRef,
OrigPAI->getType());
auto *T2TF = Builder.createThinToThickFunction(OrigPAI->getLoc(),
FuncRef, OrigPAI->getType());
OrigPAI->replaceAllUsesWith(T2TF);
recursivelyDeleteTriviallyDeadInstructions(OrigPAI, true);
DEBUG(llvm::dbgs() << " Rewrote caller:\n" << *T2TF);
Expand Down Expand Up @@ -343,16 +311,12 @@ static bool onlyContainsReturnOrThrowOfArg(SILBasicBlock *BB) {

/// Checks if \p Orig is a thunk which calls another function but without
/// passing the trailing \p numDeadParams dead parameters.
/// If a generic specialization was performed for a generic capture,
/// GenericSpecialized contains a tuple:
/// (new specialized function, old function)
static SILFunction *getSpecializedWithDeadParams(
PartialApplyInst *PAI, SILFunction *Orig, int numDeadParams,
std::pair<SILFunction *, SILFunction *> &GenericSpecialized) {
static SILFunction *getSpecializedWithDeadParams(SILFunction *Orig,
int numDeadParams) {
SILBasicBlock &EntryBB = *Orig->begin();
unsigned NumArgs = EntryBB.getNumArguments();
SILModule &M = Orig->getModule();

// Check if all dead parameters have trivial types. We don't support non-
// trivial types because it's very hard to find places where we can release
// those parameters (as a replacement for the removed partial_apply).
Expand All @@ -364,20 +328,20 @@ static SILFunction *getSpecializedWithDeadParams(
}
SILFunction *Specialized = nullptr;
SILValue RetValue;

// Check all instruction of the entry block.
for (SILInstruction &I : EntryBB) {
if (auto FAS = FullApplySite::isa(&I)) {

// Check if this is the call of the specialized function.
// If the original partial_apply didn't have substitutions,
// also the specialized function must be not generic.
if (!PAI->hasSubstitutions() && FAS.hasSubstitutions())
// As the original function is not generic, also the specialized function
// must be not generic.
if (FAS.hasSubstitutions())
return nullptr;

// Is it the only call?
if (Specialized)
return nullptr;

Specialized = FAS.getReferencedFunction();
if (!Specialized)
return nullptr;
Expand Down Expand Up @@ -412,54 +376,29 @@ static SILFunction *getSpecializedWithDeadParams(
if (I.mayHaveSideEffects() || isa<TermInst>(&I))
return nullptr;
}

GenericSpecialized = std::make_pair(nullptr, nullptr);

if (PAI->hasSubstitutions()) {
if (Specialized->isExternalDeclaration())
return nullptr;
// Perform a generic specialization of the Specialized function.
ReabstractionInfo ReInfo(ApplySite(), Specialized, PAI->getSubstitutions(),
/* ConvertIndirectToDirect */ false);
GenericFuncSpecializer FuncSpecializer(Specialized,
ReInfo.getClonerParamSubstitutions(),
Specialized->isFragile(), ReInfo);

SILFunction *GenericSpecializedFunc = FuncSpecializer.trySpecialization();
if (!GenericSpecializedFunc)
return nullptr;
GenericSpecialized = std::make_pair(GenericSpecializedFunc, Specialized);
return GenericSpecializedFunc;
}
return Specialized;
}

bool CapturePropagation::optimizePartialApply(PartialApplyInst *PAI) {
// Check if the partial_apply has generic substitutions.
// FIXME: We could handle generic thunks if it's worthwhile.
if (PAI->hasSubstitutions())
return false;

SILFunction *SubstF = PAI->getReferencedFunction();
if (!SubstF)
return false;
if (SubstF->isExternalDeclaration())
return false;

if (PAI->hasSubstitutions() && hasArchetypes(PAI->getSubstitutions())) {
DEBUG(llvm::dbgs()
<< "CapturePropagation: cannot handle partial specialization "
"of partial_apply:\n";
PAI->dumpInContext());
return false;
}

assert(!SubstF->getLoweredFunctionType()->isPolymorphic() &&
"cannot specialize generic partial apply");

// First possibility: Is it a partial_apply where all partially applied
// arguments are dead?
std::pair<SILFunction *, SILFunction *> GenericSpecialized;
if (auto *NewFunc = getSpecializedWithDeadParams(
PAI, SubstF, PAI->getNumArguments(), GenericSpecialized)) {
if (SILFunction *NewFunc = getSpecializedWithDeadParams(SubstF,
PAI->getNumArguments())) {
rewritePartialApply(PAI, NewFunc);
if (GenericSpecialized.first) {
// Notify the pass manager about the new function.
notifyAddFunction(GenericSpecialized.first, GenericSpecialized.second);
}
return true;
}

Expand All @@ -472,8 +411,7 @@ bool CapturePropagation::optimizePartialApply(PartialApplyInst *PAI) {
return false;

DEBUG(llvm::dbgs() << "Specializing closure for constant arguments:\n"
<< " " << SubstF->getName() << "\n"
<< *PAI);
<< " " << SubstF->getName() << "\n" << *PAI);
++NumCapturesPropagated;
SILFunction *NewF = specializeConstClosure(PAI, SubstF);
rewritePartialApply(PAI, NewF);
Expand Down
5 changes: 1 addition & 4 deletions lib/SILOptimizer/Utils/Generics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,10 @@ bool ReabstractionInfo::canBeSpecialized(ApplySite Apply, SILFunction *Callee,
}

ReabstractionInfo::ReabstractionInfo(ApplySite Apply, SILFunction *Callee,
ArrayRef<Substitution> ParamSubs,
bool ConvertIndirectToDirect) {
ArrayRef<Substitution> ParamSubs) {
if (!prepareAndCheck(Apply, Callee, ParamSubs))
return;

this->ConvertIndirectToDirect = ConvertIndirectToDirect;

if (SpecializeGenericSubstitutions) {
specializeConcreteAndGenericSubstitutions(Apply, Callee, ParamSubs);
} else {
Expand Down
72 changes: 0 additions & 72 deletions test/SILOptimizer/capture_propagation.sil
Original file line number Diff line number Diff line change
Expand Up @@ -378,75 +378,3 @@ bb0:
return %2 : $@callee_owned (Int32, Int32) -> (Bool, @error Error)
}

// Test generic capture propagation

sil @_TFtest_generic_capture_propagation2_closure : $@convention(thin) <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T) -> () {
bb0(%0 : $Builtin.Int32, %1 : $Builtin.FPIEEE32, %2 : $Builtin.RawPointer, %3 : $*T):
%9999 = tuple()
return %9999 : $()
}

// CHECK-LABEL: sil @test_generic_capture_propagation2_caller
// CHECK: %[[CALLEE:[0-9]+]] = function_ref @test_generic_capture_propagation2_callee
// CHECK: %[[FR:[0-9]+]] = function_ref @{{.*}}test_generic_capture_propagation2_thunk : $@convention(thin) () -> ()
// CHECK: %[[CONVERTED:[0-9]+]] = thin_to_thick_function %[[FR]] : $@convention(thin) () -> () to $@callee_owned () -> ()
// CHECK-NOT: partial_apply
// CHECK: apply %[[CALLEE]](%[[CONVERTED]]) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECL-NOT: partial_apply
// CHECK: return
sil @test_generic_capture_propagation2_caller : $@convention(thin) () -> () {
%0 = integer_literal $Builtin.Int32, 0
%1 = float_literal $Builtin.FPIEEE32, 0
%2 = string_literal utf8 "123"
%3 = global_addr @globalinit_33_06E7F1D906492AE070936A9B58CBAE1C_token8 : $*Builtin.Word
%4 = function_ref @_TFtest_generic_capture_propagation2_closure : $@convention(thin) <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T) -> ()
%5 = thin_to_thick_function %4 : $@convention(thin) <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T) -> () to $@callee_owned <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T) -> ()
%6 = function_ref @test_generic_capture_propagation2_callee : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
%7 = function_ref @test_generic_capture_propagation2_thunk : $@convention(thin) <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T, @owned @callee_owned <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T) -> ()) -> ()
%8 = partial_apply %7<Builtin.Word>(%0, %1, %2, %3, %5) : $@convention(thin) <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T, @owned @callee_owned <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T) -> ()) -> ()
apply %6(%8) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
%9999 = tuple()
return %9999 : $()
}

sil shared @test_generic_capture_propagation2_thunk : $@convention(thin) <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T, @owned @callee_owned <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T) -> ()) -> () {
bb0(%0 : $Builtin.Int32, %1 : $Builtin.FPIEEE32, %2 : $Builtin.RawPointer, %3 : $*T, %4 : $@callee_owned <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T) -> ()):
apply %4<T>(%0, %1, %2, %3) : $@callee_owned <T> (Builtin.Int32, Builtin.FPIEEE32, Builtin.RawPointer, @in T) -> ()
%9999 = tuple()
return %9999 : $()
}

sil shared @test_generic_capture_propagation2_callee : $@convention(thin) (@owned @callee_owned () -> ()) -> () {
bb0(%0 : $@callee_owned () -> ()):
apply %0() : $@callee_owned () -> ()
%9999 = tuple()
return %9999 : $()
}

// Test dead partial applied arguments when using generics

sil @specialized_generic_nonthrowing_closure : $@convention(thin) <T> (@in T, @in T) -> Bool {
bb0(%0 : $*T, %1 : $*T):
%10 = integer_literal $Builtin.Int1, -1
%9999 = struct $Bool (%10 : $Builtin.Int1)
return %9999 : $Bool
}

sil @nonthrowing_generic_closure : $@convention(method) <T> (@in T, @in T, @thin T.Type) -> Bool {
bb0(%0 : $*T, %1 : $*T, %2 : $@thin T.Type):
%3 = function_ref @specialized_generic_nonthrowing_closure : $@convention(thin) <T> (@in T, @in T) -> Bool
%4 = apply %3<T>(%0, %1) : $@convention(thin) <T> (@in T, @in T) -> Bool
return %4 : $Bool
}

// CHECK-LABEL: sil @return_generic_nonthrowing_closure
// CHECK: [[F:%[0-9]+]] = function_ref @_TTSg5Vs5Int32__specialized_generic_nonthrowing_closure
// CHECK: [[R:%[0-9]+]] = thin_to_thick_function [[F]]
// CHECK: return [[R]]
sil @return_generic_nonthrowing_closure : $@convention(thin) () -> @owned @callee_owned (@in Int32, @in Int32) -> Bool {
bb0:
%0 = metatype $@thin Int32.Type
%1 = function_ref @nonthrowing_generic_closure : $@convention(method) <T> (@in T, @in T, @thin T.Type) -> Bool
%2 = partial_apply %1<Int32>(%0) : $@convention(method) <T>(@in T, @in T, @thin T.Type) -> Bool
return %2 : $@callee_owned (@in Int32, @in Int32) -> Bool
}