Skip to content

Re-apply thunk generic signature optimization #4913

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
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
3 changes: 3 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2551,6 +2551,9 @@ void ASTContext::dumpArchetypeContext(ArchetypeType *archetype,
void ASTContext::dumpArchetypeContext(ArchetypeType *archetype,
llvm::raw_ostream &os,
unsigned indent) const {
if (archetype->isOpenedExistential())
return;

archetype = archetype->getPrimary();
if (!archetype)
return;
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ static void buildTypeDependentOperands(
for (auto archetype : OpenedArchetypes) {
auto Def = OpenedArchetypesState.getOpenedArchetypeDef(
F.getModule().Types.getLoweredType(archetype).getSwiftRValueType());
assert(Def);
assert(getOpenedArchetypeOf(Def->getType().getSwiftRValueType()) &&
"Opened archetype operands should be of an opened existential type");
TypeDependentOperands.push_back(Def);
Expand Down
44 changes: 29 additions & 15 deletions lib/SILGen/SILGenBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,22 +350,30 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,
blockInterfaceTy->getParameters().end(),
std::back_inserter(params));

auto genericSig = F.getLoweredFunctionType()->getGenericSignature();
auto genericEnv = F.getGenericEnvironment();
auto extInfo =
SILFunctionType::ExtInfo()
.withRepresentation(SILFunctionType::Representation::CFunctionPointer);

// The block invoke function must be pseudogeneric. This should be OK for now
// since a bridgeable function's parameters and returns should all be
// trivially representable in ObjC so not need to exercise the type metadata.
//
// Ultimately we may need to capture generic parameters in block storage, but
// that will require a redesign of the interface to support dependent-layout
// context. Currently we don't capture anything directly into a block but a
// Swift closure, but that's totally dumb.
if (genericSig)
extInfo = extInfo.withIsPseudogeneric();
CanGenericSignature genericSig;
GenericEnvironment *genericEnv = nullptr;
ArrayRef<Substitution> subs;
if (fnTy->hasArchetype() || blockTy->hasArchetype()) {
genericSig = F.getLoweredFunctionType()->getGenericSignature();
genericEnv = F.getGenericEnvironment();

subs = F.getForwardingSubstitutions();

// The block invoke function must be pseudogeneric. This should be OK for now
// since a bridgeable function's parameters and returns should all be
// trivially representable in ObjC so not need to exercise the type metadata.
//
// Ultimately we may need to capture generic parameters in block storage, but
// that will require a redesign of the interface to support dependent-layout
// context. Currently we don't capture anything directly into a block but a
// Swift closure, but that's totally dumb.
if (genericSig)
extInfo = extInfo.withIsPseudogeneric();
}

auto invokeTy =
SILFunctionType::get(genericSig,
Expand Down Expand Up @@ -404,7 +412,7 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,

auto stackBlock = B.createInitBlockStorageHeader(loc, storage, invokeFn,
SILType::getPrimitiveObjectType(blockTy),
getForwardingSubstitutions());
subs);

// Copy the block so we have an independent heap object we can hand off.
auto heapBlock = B.createCopyBlock(loc, stackBlock);
Expand Down Expand Up @@ -622,10 +630,16 @@ SILGenFunction::emitBlockToFunc(SILLocation loc,
CanSILFunctionType substFnTy;
SmallVector<Substitution, 4> subs;

auto genericEnv = F.getGenericEnvironment();

// Declare the thunk.
auto blockTy = block.getType().castTo<SILFunctionType>();

auto thunkTy = buildThunkType(block, funcTy, substFnTy, subs);
auto thunk = SGM.getOrCreateReabstractionThunk(F.getGenericEnvironment(),
if (!thunkTy->isPolymorphic())
genericEnv = nullptr;

auto thunk = SGM.getOrCreateReabstractionThunk(genericEnv,
thunkTy,
blockTy,
funcTy,
Expand All @@ -634,7 +648,7 @@ SILGenFunction::emitBlockToFunc(SILLocation loc,
// Build it if necessary.
if (thunk->empty()) {
SILGenFunction thunkSGF(SGM, *thunk);
thunk->setGenericEnvironment(F.getGenericEnvironment());
thunk->setGenericEnvironment(genericEnv);
auto loc = RegularLocation::getAutoGeneratedLocation();
buildBlockToFuncThunkBody(thunkSGF, loc, blockTy, funcTy);
}
Expand Down
40 changes: 25 additions & 15 deletions lib/SILGen/SILGenPoly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2314,11 +2314,24 @@ CanSILFunctionType SILGenFunction::buildThunkType(
// on the result type.
assert(expectedType->getExtInfo().hasContext());

// Just use the generic signature from the context.
// This isn't necessarily optimal.
auto genericSig = F.getLoweredFunctionType()->getGenericSignature();
auto subsArray = F.getForwardingSubstitutions();
subs.append(subsArray.begin(), subsArray.end());
auto extInfo = expectedType->getExtInfo()
.withRepresentation(SILFunctionType::Representation::Thin);

// Use the generic signature from the context if the thunk involves
// generic parameters.
CanGenericSignature genericSig;
GenericEnvironment *genericEnv = nullptr;
if (expectedType->hasArchetype() || sourceType->hasArchetype()) {
genericSig = F.getLoweredFunctionType()->getGenericSignature();
genericEnv = F.getGenericEnvironment();
auto subsArray = F.getForwardingSubstitutions();
subs.append(subsArray.begin(), subsArray.end());

// If our parent function was pseudogeneric, this thunk must also be
// pseudogeneric, since we have no way to pass generic parameters.
if (F.getLoweredFunctionType()->isPseudogeneric())
extInfo = extInfo.withIsPseudogeneric();
}

// Add the function type as the parameter.
SmallVector<SILParameterInfo, 4> params;
Expand All @@ -2328,14 +2341,6 @@ CanSILFunctionType SILGenFunction::buildThunkType(
sourceType->getExtInfo().hasContext()
? DefaultThickCalleeConvention
: ParameterConvention::Direct_Unowned});

auto extInfo = expectedType->getExtInfo()
.withRepresentation(SILFunctionType::Representation::Thin);

// If our parent function was pseudogeneric, this thunk must also be
// pseudogeneric, since we have no way to pass generic parameters.
if (F.getLoweredFunctionType()->isPseudogeneric())
extInfo = extInfo.withIsPseudogeneric();

// Map the parameter and expected types out of context to get the interface
// type of the thunk.
Expand Down Expand Up @@ -2406,10 +2411,15 @@ static ManagedValue createThunk(SILGenFunction &gen,
// Declare the thunk.
SmallVector<Substitution, 4> substitutions;
CanSILFunctionType substFnType;

auto thunkType = gen.buildThunkType(fn, expectedType,
substFnType, substitutions);
auto genericEnv = gen.F.getGenericEnvironment();
if (!thunkType->isPolymorphic())
genericEnv = nullptr;

auto thunk = gen.SGM.getOrCreateReabstractionThunk(
gen.F.getGenericEnvironment(),
genericEnv,
thunkType,
fn.getType().castTo<SILFunctionType>(),
expectedType,
Expand All @@ -2418,7 +2428,7 @@ static ManagedValue createThunk(SILGenFunction &gen,
// Build it if necessary.
if (thunk->empty()) {
// Borrow the context archetypes from the enclosing function.
thunk->setGenericEnvironment(gen.F.getGenericEnvironment());
thunk->setGenericEnvironment(genericEnv);
SILGenFunction thunkSGF(gen.SGM, *thunk);
auto loc = RegularLocation::getAutoGeneratedLocation();
buildThunkBody(thunkSGF, loc,
Expand Down
4 changes: 3 additions & 1 deletion lib/SILOptimizer/Analysis/EscapeAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,8 +561,10 @@ bool EscapeAnalysis::ConnectionGraph::isReachable(CGNode *From, CGNode *To) {
From->isInWorkList = true;
for (unsigned Idx = 0; Idx < WorkList.size(); ++Idx) {
CGNode *Reachable = WorkList[Idx];
if (Reachable == To)
if (Reachable == To) {
clearWorkListFlags(WorkList);
return true;
}
for (Predecessor Pred : Reachable->Preds) {
CGNode *PredNode = Pred.getPointer();
if (!PredNode->isInWorkList) {
Expand Down
56 changes: 17 additions & 39 deletions lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,22 +91,6 @@ SILInstruction *SILCombiner::visitPartialApplyInst(PartialApplyInst *PAI) {
return nullptr;
}

static bool canCombinePartialApply(const PartialApplyInst *PAI) {
// Only process partial apply if the callee is a known function.
auto *FRI = dyn_cast<FunctionRefInst>(PAI->getCallee());
if (!FRI)
return false;

// Make sure that the substitution list of the PAI does not contain any
// archetypes.
ArrayRef<Substitution> Subs = PAI->getSubstitutions();
for (Substitution S : Subs)
if (S.getReplacement()->getCanonicalType()->hasArchetype())
return false;

return true;
}

// Helper class performing the apply{partial_apply(x,y)}(z) -> apply(z,x,y)
// peephole.
class PartialApplyCombiner {
Expand All @@ -132,9 +116,6 @@ class PartialApplyCombiner {

SILBuilder &Builder;

// Function referenced by partial_apply.
FunctionRefInst *FRI;

SILCombiner *SilCombiner;

bool processSingleApply(FullApplySite AI);
Expand All @@ -146,7 +127,7 @@ class PartialApplyCombiner {
PartialApplyCombiner(PartialApplyInst *PAI, SILBuilder &Builder,
SILCombiner *SilCombiner)
: isFirstTime(true), PAI(PAI), Builder(Builder),
FRI(nullptr), SilCombiner(SilCombiner) {}
SilCombiner(SilCombiner) {}
SILInstruction *combine();
};

Expand Down Expand Up @@ -280,10 +261,8 @@ bool PartialApplyCombiner::processSingleApply(FullApplySite AI) {
for (auto Op : PAI->getArguments()) {
auto Arg = Op;
// If there is new temporary for this argument, use it instead.
if (isa<AllocStackInst>(Arg)) {
if (ArgToTmp.count(Arg)) {
Op = ArgToTmp.lookup(Arg);
}
if (ArgToTmp.count(Arg)) {
Op = ArgToTmp.lookup(Arg);
}
Args.push_back(Op);
}
Expand Down Expand Up @@ -314,24 +293,23 @@ bool PartialApplyCombiner::processSingleApply(FullApplySite AI) {
}
}

auto *F = FRI->getReferencedFunction();
SILType FnType = F->getLoweredType();
SILType ResultTy = F->getLoweredFunctionType()->getSILResult();
auto Callee = PAI->getCallee();
auto FnType = PAI->getSubstCalleeSILType();
SILType ResultTy = PAI->getSubstCalleeType()->getSILResult();
ArrayRef<Substitution> Subs = PAI->getSubstitutions();
if (!Subs.empty()) {
FnType = FnType.substGenericArgs(PAI->getModule(), Subs);
ResultTy = FnType.getAs<SILFunctionType>()->getSILResult();
}

// The partial_apply might be substituting in an open existential type.
Builder.addOpenedArchetypeOperands(PAI);

FullApplySite NAI;
if (auto *TAI = dyn_cast<TryApplyInst>(AI))
NAI =
Builder.createTryApply(AI.getLoc(), FRI, FnType, Subs, Args,
Builder.createTryApply(AI.getLoc(), Callee, FnType, Subs, Args,
TAI->getNormalBB(), TAI->getErrorBB());
else
NAI =
Builder.createApply(AI.getLoc(), FRI, FnType, ResultTy, Subs, Args,
cast<ApplyInst>(AI)->isNonThrowing());
Builder.createApply(AI.getLoc(), Callee, FnType, ResultTy, Subs, Args,
cast<ApplyInst>(AI)->isNonThrowing());

// We also need to release the partial_apply instruction itself because it
// is consumed by the apply_instruction.
Expand Down Expand Up @@ -365,11 +343,11 @@ bool PartialApplyCombiner::processSingleApply(FullApplySite AI) {
/// by iterating over all uses of the partial_apply and searching
/// for the pattern to transform.
SILInstruction *PartialApplyCombiner::combine() {
if (!canCombinePartialApply(PAI))
return nullptr;

// Only process partial apply if the callee is a known function.
FRI = dyn_cast<FunctionRefInst>(PAI->getCallee());
// We need to model @unowned_inner_pointer better before we can do the
// peephole here.
for (auto R : PAI->getSubstCalleeType()->getAllResults())
if (R.getConvention() == ResultConvention::UnownedInnerPointer)
return nullptr;

// Iterate over all uses of the partial_apply
// and look for applies that use it as a callee.
Expand Down
12 changes: 6 additions & 6 deletions test/SILGen/generic_closures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ class NestedGeneric<U> {
}

// CHECK-LABEL: sil hidden @_TFC16generic_closures13NestedGeneric20nested_reabstraction{{.*}}
// CHECK: [[REABSTRACT:%.*]] = function_ref @_TTRG__rXFo___XFo_iT__iT__
// CHECK: partial_apply [[REABSTRACT]]<U, T>
// CHECK: [[REABSTRACT:%.*]] = function_ref @_TTRXFo___XFo_iT__iT__
// CHECK: partial_apply [[REABSTRACT]]
func nested_reabstraction<T>(_ x: T) -> Optionable<() -> ()> {
return .some({})
}
Expand Down Expand Up @@ -213,8 +213,8 @@ func outer_generic<T>(t: T, i: Int) {
let _: () -> () = inner_generic_nocapture
// CHECK: [[FN:%.*]] = function_ref @_TFF16generic_closures13outer_genericurFT1tx1iSi_T_L_23inner_generic_nocaptureu__rFT1uqd___qd__ : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0) -> @out τ_1_0
// CHECK: [[CLOSURE:%.*]] = partial_apply [[FN]]<T, ()>() : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0) -> @out τ_1_0
// CHECK: [[THUNK:%.*]] = function_ref @_TTRGrXFo_iT__iT__XFo___
// CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [[THUNK]]<T>([[CLOSURE]])
// CHECK: [[THUNK:%.*]] = function_ref @_TTRXFo_iT__iT__XFo___
// CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [[THUNK]]([[CLOSURE]])
// CHECK: strong_release [[THUNK_CLOSURE]]

// CHECK: [[FN:%.*]] = function_ref @_TFF16generic_closures13outer_genericurFT1tx1iSi_T_L_23inner_generic_nocaptureu__rFT1uqd___qd__ : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0) -> @out τ_1_0
Expand All @@ -223,8 +223,8 @@ func outer_generic<T>(t: T, i: Int) {

// CHECK: [[FN:%.*]] = function_ref @_TFF16generic_closures13outer_genericurFT1tx1iSi_T_L_14inner_generic1u__rfT1uqd___Si : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0, Int) -> Int
// CHECK: [[CLOSURE:%.*]] = partial_apply [[FN]]<T, ()>(%1) : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0, Int) -> Int
// CHECK: [[THUNK:%.*]] = function_ref @_TTRGrXFo_iT__dSi_XFo__dSi_
// CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [[THUNK]]<T>([[CLOSURE]])
// CHECK: [[THUNK:%.*]] = function_ref @_TTRXFo_iT__dSi_XFo__dSi_
// CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [[THUNK]]([[CLOSURE]])
// CHECK: strong_release [[THUNK_CLOSURE]]
let _: () -> Int = inner_generic1

Expand Down
2 changes: 1 addition & 1 deletion test/SILGen/generic_objc_block_bridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ class Tubb<GenericParamName>: Butt {
}
}

// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRGrXFdCb_dSi_dSi_XFo_dSi_dSi_ : $@convention(thin) <GenericParamName> (Int, @owned @convention(block) (Int) -> Int) -> Int {
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRXFdCb_dSi_dSi_XFo_dSi_dSi_ : $@convention(thin) (Int, @owned @convention(block) (Int) -> Int) -> Int {
4 changes: 2 additions & 2 deletions test/SILGen/objc_blocks_bridging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,6 @@ struct GenericStruct<T> {
}
}

// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRgrXFo_oXFo_____XFdCb_dXFdCb_____ : $@convention(c) @pseudogeneric <T> (@inout_aliasable @block_storage @callee_owned (@owned @callee_owned () -> ()) -> (), @convention(block) () -> ()) -> ()
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRgrXFdCb___XFo___ : $@convention(thin) @pseudogeneric <T> (@owned @convention(block) () -> ()) -> ()
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRXFo_oXFo_____XFdCb_dXFdCb_____ : $@convention(c) (@inout_aliasable @block_storage @callee_owned (@owned @callee_owned () -> ()) -> (), @convention(block) () -> ()) -> ()
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRXFdCb___XFo___ : $@convention(thin) (@owned @convention(block) () -> ()) -> ()

2 changes: 1 addition & 1 deletion test/SILGen/property_abstraction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,5 +128,5 @@ func setBuilder<F: Factory where F.Product == MyClass>(_ factory: inout F) {
// CHECK: [[F1:%.*]] = thin_to_thick_function [[F0]]
// CHECK: [[SETTER:%.*]] = witness_method $F, #Factory.builder!setter.1
// CHECK: [[REABSTRACTOR:%.*]] = function_ref @_TTR
// CHECK: [[F2:%.*]] = partial_apply [[REABSTRACTOR]]<F>([[F1]])
// CHECK: [[F2:%.*]] = partial_apply [[REABSTRACTOR]]([[F1]])
// CHECK: apply [[SETTER]]<F, MyClass>([[F2]], [[PB]])
Loading