43
43
44
44
STATISTIC (NumInvocationFunctionsChanged,
45
45
" Number of invocation functions rewritten" );
46
- STATISTIC (NumStaticPartialApplicationForwarders,
47
- " Number of static partial application forwarder thunks generated" );
46
+ STATISTIC (NumUnsupportedChangesToInvocationFunctions,
47
+ " Number of invocation functions that could be rewritten, but aren't yet" );
48
+ STATISTIC (NumPartialApplyCalleesWithNonPartialApplyUses,
49
+ " Number of invocation functions with non-partial_apply uses" );
50
+ STATISTIC (NumPartialApplyCalleesPossiblyUsedExternally,
51
+ " Number of invocation functions possibly used externally" );
52
+ STATISTIC (NumPartialApplyCalleesDeclarationOnly,
53
+ " Number of invocation functions that are declaration-only" );
54
+ STATISTIC (NumPartialApplyCalleesWithMismatchedPartialApplies,
55
+ " Number of invocation functions that have mismatched partial_apply sites" );
48
56
STATISTIC (NumDynamicPartialApplicationForwarders,
49
57
" Number of dynamic partial application forwarder thunks generated" );
50
58
@@ -61,8 +69,8 @@ struct KnownCallee {
61
69
llvm::SetVector<FunctionRefInst *> FunctionRefs;
62
70
// / The set of partial application sites.
63
71
llvm::SetVector<PartialApplyInst *> PartialApplications;
64
- // / Whether the callee has non-partial-apply uses .
65
- bool HasNonPartialApplyUses = false ;
72
+ // / If the callee has a non-partial-apply use, this points to an arbitrary one .
73
+ SILInstruction *NonPartialApplyUse = nullptr ;
66
74
};
67
75
68
76
class PartialApplySimplificationPass : public SILModuleTransform {
@@ -128,7 +136,9 @@ static bool isSimplePartialApply(PartialApplyInst *i) {
128
136
auto argTy = i->getArguments ()[0 ]->getType ();
129
137
130
138
if (i->getFunctionType ()->isNoEscape ()) {
131
- // TODO
139
+ if (argTy.isAddress ()) {
140
+ return true ;
141
+ }
132
142
return false ;
133
143
} else {
134
144
if (!argTy.isObject ()) {
@@ -166,7 +176,7 @@ void PartialApplySimplificationPass::scanFunction(SILFunction *f,
166
176
}
167
177
168
178
// Record if the function has uses that aren't partial applies.
169
- knownCallee.HasNonPartialApplyUses = true ;
179
+ knownCallee.NonPartialApplyUse = frUse-> getUser () ;
170
180
}
171
181
}
172
182
@@ -197,8 +207,10 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
197
207
198
208
// If the subject of the partial application has other uses that aren't
199
209
// partial applications, then thunk it.
200
- if (pa.HasNonPartialApplyUses ) {
201
- LLVM_DEBUG (llvm::dbgs () << " Callee has non-partial_apply uses; thunking\n " );
210
+ if (pa.NonPartialApplyUse ) {
211
+ LLVM_DEBUG (llvm::dbgs () << " Callee has non-partial_apply uses; thunking\n " ;
212
+ pa.NonPartialApplyUse ->print (llvm::dbgs ()));
213
+ ++NumPartialApplyCalleesWithNonPartialApplyUses;
202
214
goto create_forwarding_thunks;
203
215
}
204
216
@@ -207,10 +219,12 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
207
219
// signature. We'll always use forwarding thunks in this case.
208
220
if (callee->isPossiblyUsedExternally ()) {
209
221
LLVM_DEBUG (llvm::dbgs () << " Callee is possibly used externally; thunking\n " );
222
+ ++NumPartialApplyCalleesPossiblyUsedExternally;
210
223
goto create_forwarding_thunks;
211
224
}
212
225
if (callee->empty ()) {
213
226
LLVM_DEBUG (llvm::dbgs () << " Callee is a declaration only; thunking\n " );
227
+ ++NumPartialApplyCalleesDeclarationOnly;
214
228
goto create_forwarding_thunks;
215
229
}
216
230
@@ -229,11 +243,15 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
229
243
i != e;
230
244
++i) {
231
245
auto thisPA = *i;
232
- if (examplePA->getType () != thisPA->getType ()) {
246
+ if (examplePA->getNumArguments () != thisPA->getNumArguments ()
247
+ || examplePA->getFunctionType ()->getCalleeConvention ()
248
+ != thisPA->getFunctionType ()->getCalleeConvention ()
249
+ || !examplePA->getFunctionType ()->getExtInfo ()
250
+ .isEqualTo (thisPA->getFunctionType ()->getExtInfo (), true )) {
233
251
LLVM_DEBUG (llvm::dbgs () << " Mismatched partial application arguments; thunking:\n " ;
234
252
thisPA->print (llvm::dbgs ());
235
253
examplePA->print (llvm::dbgs ()));
236
-
254
+ ++NumPartialApplyCalleesWithMismatchedPartialApplies;
237
255
goto create_forwarding_thunks;
238
256
}
239
257
}
@@ -290,44 +308,49 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
290
308
291
309
// Instead of the applied arguments, we receive a box containing the
292
310
// values for those arguments. Work out what that box type is.
293
- // TODO: We need a representation of boxes that are nonescaping and/or
311
+ // TODO: We need a representation of boxes that
294
312
// capture the generic environment to represent partial applications in
295
313
// their full generality.
296
- if (examplePA->getFunctionType ()->isNoEscape ()) {
297
- LLVM_DEBUG (llvm::dbgs () << " TODO: Nonescaping partial_apply not yet implemented\n " );
298
- return ;
299
- }
300
314
if (origTy->getInvocationGenericSignature ()) {
301
315
LLVM_DEBUG (llvm::dbgs () << " TODO: generic partial_apply not yet implemented\n " );
316
+ ++NumUnsupportedChangesToInvocationFunctions;
302
317
return ;
303
318
}
304
319
305
- // TODO: SILBoxType is only implemented for a single field right now, so
306
- // represent the captures as a tuple.
307
- #if MULTI_FIELD_BOXES_ARE_SUPPORTED
308
- auto newBoxLayout = SILLayout::get (C,
309
- origTy->getInvocationGenericSignature (),
310
- boxFields,
311
- /* capturesGenerics*/ !origTy->getInvocationGenericSignature ().isNull ());
312
- #else
320
+ // TODO: SILBoxType is only implemented for a single field right now, and we
321
+ // don't yet have a corresponding type for nonescaping captures, so
322
+ // represent the captures as a tuple for now.
313
323
llvm::SmallVector<TupleTypeElt, 4 > tupleElts;
314
324
for (auto field : boxFields) {
315
325
tupleElts.push_back (TupleTypeElt (field.getLoweredType ()));
316
326
}
317
327
auto tupleTy = TupleType::get (tupleElts, C)->getCanonicalType ();
318
- SILField tupleField (tupleTy, /* mutable*/ false );
319
328
320
- auto newBoxLayout = SILLayout::get (C,
321
- origTy->getInvocationGenericSignature (),
322
- tupleField,
323
- /* capturesGenerics*/ false );
324
- #endif
325
- SubstitutionMap identitySubstitutionMap;
326
- if (auto origSig = origTy->getInvocationGenericSignature ()) {
327
- identitySubstitutionMap = origSig->getIdentitySubstitutionMap ();
329
+ CanType contextTy;
330
+ SILParameterInfo contextParam;
331
+
332
+ bool isNoEscape = examplePA->getFunctionType ()->isNoEscape ();
333
+ if (isNoEscape) {
334
+ contextTy = tupleTy;
335
+ // Nonescaping closures borrow their context from the outer frame.
336
+ contextParam = SILParameterInfo (contextTy,
337
+ ParameterConvention::Indirect_In_Guaranteed);
338
+ } else {
339
+ SILField tupleField (tupleTy, /* mutable*/ false );
340
+ auto newBoxLayout = SILLayout::get (C,
341
+ origTy->getInvocationGenericSignature (),
342
+ tupleField,
343
+ /* capturesGenerics*/ false );
344
+ SubstitutionMap identitySubstitutionMap;
345
+ if (auto origSig = origTy->getInvocationGenericSignature ()) {
346
+ identitySubstitutionMap = origSig->getIdentitySubstitutionMap ();
347
+ }
348
+ contextTy = SILBoxType::get (C, newBoxLayout, identitySubstitutionMap);
349
+ contextParam = SILParameterInfo (contextTy,
350
+ paResultTy->getCalleeConvention ());
328
351
}
329
- auto newBoxTy = SILBoxType::get (C, newBoxLayout, identitySubstitutionMap);
330
- newParams.push_back (SILParameterInfo (newBoxTy, paResultTy-> getCalleeConvention ()) );
352
+
353
+ newParams.push_back (contextParam );
331
354
332
355
auto newExtInfo = origTy->getExtInfo ()
333
356
.withRepresentation (SILFunctionTypeRepresentation::Method);
@@ -352,22 +375,25 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
352
375
callee->rewriteLoweredTypeUnsafe (newTy);
353
376
354
377
// Update the entry block.
355
- auto boxConvention = examplePA->getFunctionType ()->getCalleeConvention ();
356
378
{
357
379
SILBuilder B (*callee);
358
380
auto &entry = *callee->begin ();
359
381
360
- // Insert an argument for the box before the originally applied args.
361
- auto boxArgTy = callee->mapTypeIntoContext (
362
- SILType::getPrimitiveObjectType (newBoxTy));
363
- ValueOwnershipKind boxOwnership (*callee, boxArgTy,
364
- SILArgumentConvention (boxConvention));
382
+ // Insert an argument for the context before the originally applied args.
383
+ auto contextArgTy = callee->mapTypeIntoContext (
384
+ SILType::getPrimitiveObjectType (contextTy));
385
+ if (isIndirectFormalParameter (contextParam.getConvention ())) {
386
+ contextArgTy = contextArgTy.getAddressType ();
387
+ }
365
388
389
+ ValueOwnershipKind contextOwnership (*callee, contextArgTy,
390
+ SILArgumentConvention (contextParam.getConvention ()));
391
+
366
392
auto numUnappliedArgs = numUnapplied + origTy->getNumIndirectFormalResults ();
367
393
368
- auto boxArg = entry.insertFunctionArgument (numUnappliedArgs,
369
- boxArgTy ,
370
- boxOwnership );
394
+ auto contextArg = entry.insertFunctionArgument (numUnappliedArgs,
395
+ contextArgTy ,
396
+ contextOwnership );
371
397
auto appliedBBArgs = entry.getArguments ().slice (numUnappliedArgs + 1 );
372
398
373
399
// Replace the original arguments applied by the partial_apply, by
@@ -379,15 +405,16 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
379
405
auto appliedArg = appliedBBArgs[i];
380
406
auto param = partiallyAppliedParams[i];
381
407
382
- #if MULTI_FIELD_BOXES_ARE_SUPPORTED
383
- SILValue proj = B.createProjectBox (loc, boxArg, i);
384
- #else
385
- SILValue proj = B.createProjectBox (loc, boxArg, 0 );
408
+ SILValue proj;
409
+ if (isNoEscape) {
410
+ proj = contextArg;
411
+ } else {
412
+ proj = B.createProjectBox (loc, contextArg, 0 );
413
+ }
386
414
if (boxFields.size () > 1 ) {
387
415
proj = B.createTupleElementAddr (loc, proj, i);
388
416
}
389
- #endif
390
- // Load the value out of the box according to the current ownership
417
+ // Load the value out of the context according to the current ownership
391
418
// mode of the function and the calling convention for the parameter.
392
419
SILValue projectedArg;
393
420
if (callee->hasOwnership ()) {
@@ -466,7 +493,7 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
466
493
case ParameterConvention::Indirect_InoutAliasable: {
467
494
// The box capture is a RawPointer with the value of the capture
468
495
// address.
469
- auto ptrVal = B.createLoad (loc, proj, LoadOwnershipQualifier::Trivial );
496
+ auto ptrVal = B.createLoad (loc, proj, LoadOwnershipQualifier::Unqualified );
470
497
projectedArg = B.createPointerToAddress (loc, ptrVal,
471
498
appliedArg->getType (),
472
499
/* strict*/ conv == ParameterConvention::Indirect_Inout);
@@ -480,11 +507,11 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
480
507
}
481
508
482
509
// If the box is callee-consumed, we can release it now.
483
- if (boxConvention == ParameterConvention::Direct_Owned) {
510
+ if (contextParam. getConvention () == ParameterConvention::Direct_Owned) {
484
511
if (callee->hasOwnership ()) {
485
- B.createDestroyValue (loc, boxArg );
512
+ B.createDestroyValue (loc, contextArg );
486
513
} else {
487
- B.createStrongRelease (loc, boxArg , Atomicity::Atomic);
514
+ B.createStrongRelease (loc, contextArg , Atomicity::Atomic);
488
515
}
489
516
}
490
517
@@ -509,24 +536,39 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
509
536
B.setInsertionPoint (pa);
510
537
511
538
auto newFunctionRef = B.createFunctionRef (loc, callee);
512
- auto boxTy = SILBoxType::get (C, newBoxLayout, pa->getSubstitutionMap ());
513
- auto newBox = B.createAllocBox (loc, boxTy,
514
- /* debug variable*/ None,
515
- /* dynamic lifetime*/ false ,
516
- /* reflection*/ true );
539
+ SILValue contextBuffer, contextProj;
540
+ auto contextStorageTy = SILType::getPrimitiveAddressType (contextTy)
541
+ .subst (getModule ()->Types , pa->getSubstitutionMap ());
542
+ if (isNoEscape) {
543
+ auto contextAlloc = B.createAllocStack (loc, contextStorageTy);
544
+ contextBuffer = contextProj = contextAlloc;
545
+
546
+ // We'll need to deallocate the context buffer after the end of the
547
+ // original partial_apply's lifetime.
548
+ auto deallocStackUses = pa->getUsersOfType <DeallocStackInst>();
549
+ assert (deallocStackUses.begin () != deallocStackUses.end ());
550
+ for (auto use : deallocStackUses) {
551
+ B.setInsertionPoint (use->getNextInstruction ());
552
+ B.createDeallocStack (loc, contextBuffer);
553
+ }
554
+ B.setInsertionPoint (contextAlloc->getNextInstruction ());
555
+ } else {
556
+ contextBuffer = B.createAllocBox (loc,
557
+ contextStorageTy.castTo <SILBoxType>(),
558
+ /* debug variable*/ None,
559
+ /* dynamic lifetime*/ false ,
560
+ /* reflection*/ true );
561
+ contextProj = B.createProjectBox (loc, contextBuffer, 0 );
562
+ }
517
563
518
564
// Transfer the formerly partially-applied arguments into the box.
519
565
auto appliedArgs = pa->getArguments ();
520
566
for (unsigned i = 0 ; i < appliedArgs.size (); ++i) {
521
567
auto arg = appliedArgs[i];
522
- #if MULTI_FIELD_BOXES_ARE_SUPPORTED
523
- SILValue proj = B.createProjectBox (loc, newBox, i);
524
- #else
525
- SILValue proj = B.createProjectBox (loc, newBox, 0 );
568
+ SILValue proj = contextProj;
526
569
if (boxFields.size () > 1 ) {
527
570
proj = B.createTupleElementAddr (loc, proj, i);
528
571
}
529
- #endif
530
572
auto param = partiallyAppliedParams[i];
531
573
532
574
switch (auto conv = param.getConvention ()) {
@@ -563,10 +605,15 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
563
605
}
564
606
565
607
// Partially apply the new box to create the closure.
608
+ auto paConvention = isNoEscape ? ParameterConvention::Direct_Guaranteed
609
+ : contextParam.getConvention ();
610
+ auto paOnStack = isNoEscape ? PartialApplyInst::OnStack
611
+ : PartialApplyInst::NotOnStack;
566
612
auto newPA = B.createPartialApply (loc, newFunctionRef,
567
613
pa->getSubstitutionMap (),
568
- SILValue (newBox),
569
- boxConvention);
614
+ contextBuffer,
615
+ paConvention,
616
+ paOnStack);
570
617
assert (isSimplePartialApply (newPA)
571
618
&& " partial apply wasn't simple after transformation?" );
572
619
pa->replaceAllUsesWith (newPA);
@@ -592,6 +639,7 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
592
639
593
640
void PartialApplySimplificationPass::processDynamicCallee (PartialApplyInst *pa){
594
641
// TODO
642
+ ++NumDynamicPartialApplicationForwarders;
595
643
}
596
644
597
645
SILTransform *swift::createPartialApplySimplification () {
0 commit comments