Skip to content

Commit 7c2bdd8

Browse files
authored
Merge pull request #4913 from slavapestov/reapply-thunk-generic-signature
Re-apply thunk generic signature optimization
2 parents bb660c4 + c65c1b5 commit 7c2bdd8

File tree

11 files changed

+132
-81
lines changed

11 files changed

+132
-81
lines changed

lib/AST/ASTContext.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2551,6 +2551,9 @@ void ASTContext::dumpArchetypeContext(ArchetypeType *archetype,
25512551
void ASTContext::dumpArchetypeContext(ArchetypeType *archetype,
25522552
llvm::raw_ostream &os,
25532553
unsigned indent) const {
2554+
if (archetype->isOpenedExistential())
2555+
return;
2556+
25542557
archetype = archetype->getPrimary();
25552558
if (!archetype)
25562559
return;

lib/SIL/SILInstructions.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ static void buildTypeDependentOperands(
6868
for (auto archetype : OpenedArchetypes) {
6969
auto Def = OpenedArchetypesState.getOpenedArchetypeDef(
7070
F.getModule().Types.getLoweredType(archetype).getSwiftRValueType());
71+
assert(Def);
7172
assert(getOpenedArchetypeOf(Def->getType().getSwiftRValueType()) &&
7273
"Opened archetype operands should be of an opened existential type");
7374
TypeDependentOperands.push_back(Def);

lib/SILGen/SILGenBridging.cpp

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -350,22 +350,30 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,
350350
blockInterfaceTy->getParameters().end(),
351351
std::back_inserter(params));
352352

353-
auto genericSig = F.getLoweredFunctionType()->getGenericSignature();
354-
auto genericEnv = F.getGenericEnvironment();
355353
auto extInfo =
356354
SILFunctionType::ExtInfo()
357355
.withRepresentation(SILFunctionType::Representation::CFunctionPointer);
358356

359-
// The block invoke function must be pseudogeneric. This should be OK for now
360-
// since a bridgeable function's parameters and returns should all be
361-
// trivially representable in ObjC so not need to exercise the type metadata.
362-
//
363-
// Ultimately we may need to capture generic parameters in block storage, but
364-
// that will require a redesign of the interface to support dependent-layout
365-
// context. Currently we don't capture anything directly into a block but a
366-
// Swift closure, but that's totally dumb.
367-
if (genericSig)
368-
extInfo = extInfo.withIsPseudogeneric();
357+
CanGenericSignature genericSig;
358+
GenericEnvironment *genericEnv = nullptr;
359+
ArrayRef<Substitution> subs;
360+
if (fnTy->hasArchetype() || blockTy->hasArchetype()) {
361+
genericSig = F.getLoweredFunctionType()->getGenericSignature();
362+
genericEnv = F.getGenericEnvironment();
363+
364+
subs = F.getForwardingSubstitutions();
365+
366+
// The block invoke function must be pseudogeneric. This should be OK for now
367+
// since a bridgeable function's parameters and returns should all be
368+
// trivially representable in ObjC so not need to exercise the type metadata.
369+
//
370+
// Ultimately we may need to capture generic parameters in block storage, but
371+
// that will require a redesign of the interface to support dependent-layout
372+
// context. Currently we don't capture anything directly into a block but a
373+
// Swift closure, but that's totally dumb.
374+
if (genericSig)
375+
extInfo = extInfo.withIsPseudogeneric();
376+
}
369377

370378
auto invokeTy =
371379
SILFunctionType::get(genericSig,
@@ -404,7 +412,7 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,
404412

405413
auto stackBlock = B.createInitBlockStorageHeader(loc, storage, invokeFn,
406414
SILType::getPrimitiveObjectType(blockTy),
407-
getForwardingSubstitutions());
415+
subs);
408416

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

633+
auto genericEnv = F.getGenericEnvironment();
634+
625635
// Declare the thunk.
626636
auto blockTy = block.getType().castTo<SILFunctionType>();
637+
627638
auto thunkTy = buildThunkType(block, funcTy, substFnTy, subs);
628-
auto thunk = SGM.getOrCreateReabstractionThunk(F.getGenericEnvironment(),
639+
if (!thunkTy->isPolymorphic())
640+
genericEnv = nullptr;
641+
642+
auto thunk = SGM.getOrCreateReabstractionThunk(genericEnv,
629643
thunkTy,
630644
blockTy,
631645
funcTy,
@@ -634,7 +648,7 @@ SILGenFunction::emitBlockToFunc(SILLocation loc,
634648
// Build it if necessary.
635649
if (thunk->empty()) {
636650
SILGenFunction thunkSGF(SGM, *thunk);
637-
thunk->setGenericEnvironment(F.getGenericEnvironment());
651+
thunk->setGenericEnvironment(genericEnv);
638652
auto loc = RegularLocation::getAutoGeneratedLocation();
639653
buildBlockToFuncThunkBody(thunkSGF, loc, blockTy, funcTy);
640654
}

lib/SILGen/SILGenPoly.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2314,11 +2314,24 @@ CanSILFunctionType SILGenFunction::buildThunkType(
23142314
// on the result type.
23152315
assert(expectedType->getExtInfo().hasContext());
23162316

2317-
// Just use the generic signature from the context.
2318-
// This isn't necessarily optimal.
2319-
auto genericSig = F.getLoweredFunctionType()->getGenericSignature();
2320-
auto subsArray = F.getForwardingSubstitutions();
2321-
subs.append(subsArray.begin(), subsArray.end());
2317+
auto extInfo = expectedType->getExtInfo()
2318+
.withRepresentation(SILFunctionType::Representation::Thin);
2319+
2320+
// Use the generic signature from the context if the thunk involves
2321+
// generic parameters.
2322+
CanGenericSignature genericSig;
2323+
GenericEnvironment *genericEnv = nullptr;
2324+
if (expectedType->hasArchetype() || sourceType->hasArchetype()) {
2325+
genericSig = F.getLoweredFunctionType()->getGenericSignature();
2326+
genericEnv = F.getGenericEnvironment();
2327+
auto subsArray = F.getForwardingSubstitutions();
2328+
subs.append(subsArray.begin(), subsArray.end());
2329+
2330+
// If our parent function was pseudogeneric, this thunk must also be
2331+
// pseudogeneric, since we have no way to pass generic parameters.
2332+
if (F.getLoweredFunctionType()->isPseudogeneric())
2333+
extInfo = extInfo.withIsPseudogeneric();
2334+
}
23222335

23232336
// Add the function type as the parameter.
23242337
SmallVector<SILParameterInfo, 4> params;
@@ -2328,14 +2341,6 @@ CanSILFunctionType SILGenFunction::buildThunkType(
23282341
sourceType->getExtInfo().hasContext()
23292342
? DefaultThickCalleeConvention
23302343
: ParameterConvention::Direct_Unowned});
2331-
2332-
auto extInfo = expectedType->getExtInfo()
2333-
.withRepresentation(SILFunctionType::Representation::Thin);
2334-
2335-
// If our parent function was pseudogeneric, this thunk must also be
2336-
// pseudogeneric, since we have no way to pass generic parameters.
2337-
if (F.getLoweredFunctionType()->isPseudogeneric())
2338-
extInfo = extInfo.withIsPseudogeneric();
23392344

23402345
// Map the parameter and expected types out of context to get the interface
23412346
// type of the thunk.
@@ -2406,10 +2411,15 @@ static ManagedValue createThunk(SILGenFunction &gen,
24062411
// Declare the thunk.
24072412
SmallVector<Substitution, 4> substitutions;
24082413
CanSILFunctionType substFnType;
2414+
24092415
auto thunkType = gen.buildThunkType(fn, expectedType,
24102416
substFnType, substitutions);
2417+
auto genericEnv = gen.F.getGenericEnvironment();
2418+
if (!thunkType->isPolymorphic())
2419+
genericEnv = nullptr;
2420+
24112421
auto thunk = gen.SGM.getOrCreateReabstractionThunk(
2412-
gen.F.getGenericEnvironment(),
2422+
genericEnv,
24132423
thunkType,
24142424
fn.getType().castTo<SILFunctionType>(),
24152425
expectedType,
@@ -2418,7 +2428,7 @@ static ManagedValue createThunk(SILGenFunction &gen,
24182428
// Build it if necessary.
24192429
if (thunk->empty()) {
24202430
// Borrow the context archetypes from the enclosing function.
2421-
thunk->setGenericEnvironment(gen.F.getGenericEnvironment());
2431+
thunk->setGenericEnvironment(genericEnv);
24222432
SILGenFunction thunkSGF(gen.SGM, *thunk);
24232433
auto loc = RegularLocation::getAutoGeneratedLocation();
24242434
buildThunkBody(thunkSGF, loc,

lib/SILOptimizer/Analysis/EscapeAnalysis.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,8 +561,10 @@ bool EscapeAnalysis::ConnectionGraph::isReachable(CGNode *From, CGNode *To) {
561561
From->isInWorkList = true;
562562
for (unsigned Idx = 0; Idx < WorkList.size(); ++Idx) {
563563
CGNode *Reachable = WorkList[Idx];
564-
if (Reachable == To)
564+
if (Reachable == To) {
565+
clearWorkListFlags(WorkList);
565566
return true;
567+
}
566568
for (Predecessor Pred : Reachable->Preds) {
567569
CGNode *PredNode = Pred.getPointer();
568570
if (!PredNode->isInWorkList) {

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -91,22 +91,6 @@ SILInstruction *SILCombiner::visitPartialApplyInst(PartialApplyInst *PAI) {
9191
return nullptr;
9292
}
9393

94-
static bool canCombinePartialApply(const PartialApplyInst *PAI) {
95-
// Only process partial apply if the callee is a known function.
96-
auto *FRI = dyn_cast<FunctionRefInst>(PAI->getCallee());
97-
if (!FRI)
98-
return false;
99-
100-
// Make sure that the substitution list of the PAI does not contain any
101-
// archetypes.
102-
ArrayRef<Substitution> Subs = PAI->getSubstitutions();
103-
for (Substitution S : Subs)
104-
if (S.getReplacement()->getCanonicalType()->hasArchetype())
105-
return false;
106-
107-
return true;
108-
}
109-
11094
// Helper class performing the apply{partial_apply(x,y)}(z) -> apply(z,x,y)
11195
// peephole.
11296
class PartialApplyCombiner {
@@ -132,9 +116,6 @@ class PartialApplyCombiner {
132116

133117
SILBuilder &Builder;
134118

135-
// Function referenced by partial_apply.
136-
FunctionRefInst *FRI;
137-
138119
SILCombiner *SilCombiner;
139120

140121
bool processSingleApply(FullApplySite AI);
@@ -146,7 +127,7 @@ class PartialApplyCombiner {
146127
PartialApplyCombiner(PartialApplyInst *PAI, SILBuilder &Builder,
147128
SILCombiner *SilCombiner)
148129
: isFirstTime(true), PAI(PAI), Builder(Builder),
149-
FRI(nullptr), SilCombiner(SilCombiner) {}
130+
SilCombiner(SilCombiner) {}
150131
SILInstruction *combine();
151132
};
152133

@@ -280,10 +261,8 @@ bool PartialApplyCombiner::processSingleApply(FullApplySite AI) {
280261
for (auto Op : PAI->getArguments()) {
281262
auto Arg = Op;
282263
// If there is new temporary for this argument, use it instead.
283-
if (isa<AllocStackInst>(Arg)) {
284-
if (ArgToTmp.count(Arg)) {
285-
Op = ArgToTmp.lookup(Arg);
286-
}
264+
if (ArgToTmp.count(Arg)) {
265+
Op = ArgToTmp.lookup(Arg);
287266
}
288267
Args.push_back(Op);
289268
}
@@ -314,24 +293,23 @@ bool PartialApplyCombiner::processSingleApply(FullApplySite AI) {
314293
}
315294
}
316295

317-
auto *F = FRI->getReferencedFunction();
318-
SILType FnType = F->getLoweredType();
319-
SILType ResultTy = F->getLoweredFunctionType()->getSILResult();
296+
auto Callee = PAI->getCallee();
297+
auto FnType = PAI->getSubstCalleeSILType();
298+
SILType ResultTy = PAI->getSubstCalleeType()->getSILResult();
320299
ArrayRef<Substitution> Subs = PAI->getSubstitutions();
321-
if (!Subs.empty()) {
322-
FnType = FnType.substGenericArgs(PAI->getModule(), Subs);
323-
ResultTy = FnType.getAs<SILFunctionType>()->getSILResult();
324-
}
300+
301+
// The partial_apply might be substituting in an open existential type.
302+
Builder.addOpenedArchetypeOperands(PAI);
325303

326304
FullApplySite NAI;
327305
if (auto *TAI = dyn_cast<TryApplyInst>(AI))
328306
NAI =
329-
Builder.createTryApply(AI.getLoc(), FRI, FnType, Subs, Args,
307+
Builder.createTryApply(AI.getLoc(), Callee, FnType, Subs, Args,
330308
TAI->getNormalBB(), TAI->getErrorBB());
331309
else
332310
NAI =
333-
Builder.createApply(AI.getLoc(), FRI, FnType, ResultTy, Subs, Args,
334-
cast<ApplyInst>(AI)->isNonThrowing());
311+
Builder.createApply(AI.getLoc(), Callee, FnType, ResultTy, Subs, Args,
312+
cast<ApplyInst>(AI)->isNonThrowing());
335313

336314
// We also need to release the partial_apply instruction itself because it
337315
// is consumed by the apply_instruction.
@@ -365,11 +343,11 @@ bool PartialApplyCombiner::processSingleApply(FullApplySite AI) {
365343
/// by iterating over all uses of the partial_apply and searching
366344
/// for the pattern to transform.
367345
SILInstruction *PartialApplyCombiner::combine() {
368-
if (!canCombinePartialApply(PAI))
369-
return nullptr;
370-
371-
// Only process partial apply if the callee is a known function.
372-
FRI = dyn_cast<FunctionRefInst>(PAI->getCallee());
346+
// We need to model @unowned_inner_pointer better before we can do the
347+
// peephole here.
348+
for (auto R : PAI->getSubstCalleeType()->getAllResults())
349+
if (R.getConvention() == ResultConvention::UnownedInnerPointer)
350+
return nullptr;
373351

374352
// Iterate over all uses of the partial_apply
375353
// and look for applies that use it as a callee.

test/SILGen/generic_closures.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ class NestedGeneric<U> {
109109
}
110110

111111
// CHECK-LABEL: sil hidden @_TFC16generic_closures13NestedGeneric20nested_reabstraction{{.*}}
112-
// CHECK: [[REABSTRACT:%.*]] = function_ref @_TTRG__rXFo___XFo_iT__iT__
113-
// CHECK: partial_apply [[REABSTRACT]]<U, T>
112+
// CHECK: [[REABSTRACT:%.*]] = function_ref @_TTRXFo___XFo_iT__iT__
113+
// CHECK: partial_apply [[REABSTRACT]]
114114
func nested_reabstraction<T>(_ x: T) -> Optionable<() -> ()> {
115115
return .some({})
116116
}
@@ -213,8 +213,8 @@ func outer_generic<T>(t: T, i: Int) {
213213
let _: () -> () = inner_generic_nocapture
214214
// 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
215215
// CHECK: [[CLOSURE:%.*]] = partial_apply [[FN]]<T, ()>() : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0) -> @out τ_1_0
216-
// CHECK: [[THUNK:%.*]] = function_ref @_TTRGrXFo_iT__iT__XFo___
217-
// CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [[THUNK]]<T>([[CLOSURE]])
216+
// CHECK: [[THUNK:%.*]] = function_ref @_TTRXFo_iT__iT__XFo___
217+
// CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [[THUNK]]([[CLOSURE]])
218218
// CHECK: strong_release [[THUNK_CLOSURE]]
219219

220220
// 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
@@ -223,8 +223,8 @@ func outer_generic<T>(t: T, i: Int) {
223223

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

test/SILGen/generic_objc_block_bridge.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ class Tubb<GenericParamName>: Butt {
1414
}
1515
}
1616

17-
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRGrXFdCb_dSi_dSi_XFo_dSi_dSi_ : $@convention(thin) <GenericParamName> (Int, @owned @convention(block) (Int) -> Int) -> Int {
17+
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRXFdCb_dSi_dSi_XFo_dSi_dSi_ : $@convention(thin) (Int, @owned @convention(block) (Int) -> Int) -> Int {

test/SILGen/objc_blocks_bridging.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,6 @@ struct GenericStruct<T> {
150150
}
151151
}
152152

153-
// 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) () -> ()) -> ()
154-
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRgrXFdCb___XFo___ : $@convention(thin) @pseudogeneric <T> (@owned @convention(block) () -> ()) -> ()
153+
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRXFo_oXFo_____XFdCb_dXFdCb_____ : $@convention(c) (@inout_aliasable @block_storage @callee_owned (@owned @callee_owned () -> ()) -> (), @convention(block) () -> ()) -> ()
154+
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRXFdCb___XFo___ : $@convention(thin) (@owned @convention(block) () -> ()) -> ()
155155

test/SILGen/property_abstraction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,5 @@ func setBuilder<F: Factory where F.Product == MyClass>(_ factory: inout F) {
128128
// CHECK: [[F1:%.*]] = thin_to_thick_function [[F0]]
129129
// CHECK: [[SETTER:%.*]] = witness_method $F, #Factory.builder!setter.1
130130
// CHECK: [[REABSTRACTOR:%.*]] = function_ref @_TTR
131-
// CHECK: [[F2:%.*]] = partial_apply [[REABSTRACTOR]]<F>([[F1]])
131+
// CHECK: [[F2:%.*]] = partial_apply [[REABSTRACTOR]]([[F1]])
132132
// CHECK: apply [[SETTER]]<F, MyClass>([[F2]], [[PB]])

0 commit comments

Comments
 (0)