Skip to content

Commit 26e592a

Browse files
committed
---
yaml --- r: 349457 b: refs/heads/master-next c: 61ec1fb h: refs/heads/master i: 349455: e2bd467
1 parent 08254f7 commit 26e592a

File tree

4 files changed

+136
-19
lines changed

4 files changed

+136
-19
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
refs/heads/master: 3574c513bbc5578dd9346b4ea9ab5995c5927bb5
3-
refs/heads/master-next: 88d727d9ea29e53980b70cc8a9a60db8386b4b0c
3+
refs/heads/master-next: 61ec1fb4a6ef89b62c107fd5292c291ad51b2c8b
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea
66
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-b: 66d897bfcf64a82cb9a87f5e663d889189d06d07

branches/master-next/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ void ExistentialSpecializerCloner::cloneArguments(
159159
GenericTypeParamType *GenericParam = iter->second;
160160
SILType GenericSILType =
161161
NewF.getLoweredType(NewF.mapTypeIntoContext(GenericParam));
162+
GenericSILType = GenericSILType.getCategoryType(
163+
ArgDesc.Arg->getType().getCategory());
162164
auto *NewArg = ClonedEntryBB->createFunctionArgument(GenericSILType);
163165
NewArg->setOwnershipKind(ValueOwnershipKind(
164166
NewF, GenericSILType, ArgDesc.Arg->getArgumentConvention()));
@@ -173,6 +175,7 @@ void ExistentialSpecializerCloner::cloneArguments(
173175
Ctx.AllocateCopy(NewConformances);
174176
auto ExistentialRepr =
175177
ArgDesc.Arg->getType().getPreferredExistentialRepresentation(M);
178+
auto &EAD = ExistentialArgDescriptor[ArgDesc.Index];
176179
switch (ExistentialRepr) {
177180
case ExistentialRepresentation::Opaque: {
178181
/// Create this sequence for init_existential_addr.:
@@ -190,7 +193,7 @@ void ExistentialSpecializerCloner::cloneArguments(
190193
InsertLoc, ASI, NewArg->getType().getASTType(), NewArg->getType(),
191194
Conformances);
192195

193-
bool origConsumed = ExistentialArgDescriptor[ArgDesc.Index].isConsumed;
196+
bool origConsumed = EAD.isConsumed;
194197
// If the existential is not consumed in the function body, then the one
195198
// we introduce here needs cleanup.
196199
if (!origConsumed)
@@ -204,16 +207,32 @@ void ExistentialSpecializerCloner::cloneArguments(
204207
break;
205208
}
206209
case ExistentialRepresentation::Class: {
210+
SILValue NewArgValue = NewArg;
211+
if (!NewArg->getType().isObject()) {
212+
NewArgValue = NewFBuilder.createLoad(InsertLoc, NewArg,
213+
LoadOwnershipQualifier::Unqualified);
214+
}
215+
207216
// FIXME_ownership: init_existential_ref always takes ownership of the
208217
// incoming reference. If the argument convention is borrowed
209218
// (!isConsumed), then we should create a copy_value here and add this new
210219
// existential to the CleanupValues vector.
211220

212221
/// Simple case: Create an init_existential.
213222
/// %5 = init_existential_ref %0 : $T : $T, $P
214-
auto *InitRef = NewFBuilder.createInitExistentialRef(
215-
InsertLoc, ArgDesc.Arg->getType(), NewArg->getType().getASTType(),
216-
NewArg, Conformances);
223+
SILValue InitRef = NewFBuilder.createInitExistentialRef(
224+
InsertLoc, ArgDesc.Arg->getType().getObjectType(),
225+
NewArg->getType().getASTType(),
226+
NewArgValue, Conformances);
227+
228+
if (!NewArg->getType().isObject()) {
229+
auto alloc = NewFBuilder.createAllocStack(InsertLoc,
230+
InitRef->getType());
231+
NewFBuilder.createStore(InsertLoc, InitRef, alloc,
232+
StoreOwnershipQualifier::Unqualified);
233+
InitRef = alloc;
234+
AllocStackInsts.push_back(alloc);
235+
}
217236

218237
entryArgs.push_back(InitRef);
219238
break;
@@ -369,7 +388,8 @@ void ExistentialTransform::populateThunkBody() {
369388
/// Create a basic block and the function arguments.
370389
auto *ThunkBody = F->createBasicBlock();
371390
for (auto &ArgDesc : ArgumentDescList) {
372-
ThunkBody->createFunctionArgument(ArgDesc.Arg->getType(), ArgDesc.Decl);
391+
auto argumentType = ArgDesc.Arg->getType();
392+
ThunkBody->createFunctionArgument(argumentType, ArgDesc.Decl);
373393
}
374394

375395
/// Builder to add new instructions in the Thunk.
@@ -394,7 +414,11 @@ void ExistentialTransform::populateThunkBody() {
394414
SmallVector<SILValue, 8> ApplyArgs;
395415
// Maintain a list of arg values to be destroyed. These are consumed by the
396416
// convention and require a copy.
397-
SmallVector<CopyAddrInst *, 8> TempCopyAddrInsts;
417+
struct Temp {
418+
SILValue DeallocStackEntry;
419+
SILValue DestroyValue;
420+
};
421+
SmallVector<Temp, 8> Temps;
398422
SmallDenseMap<GenericTypeParamType *, Type> GenericToOpenedTypeMap;
399423
for (auto &ArgDesc : ArgumentDescList) {
400424
auto iter = ArgToGenericTypeMap.find(ArgDesc.Index);
@@ -422,22 +446,32 @@ void ExistentialTransform::populateThunkBody() {
422446
// must pass in a copy.
423447
auto *ASI =
424448
Builder.createAllocStack(Loc, OpenedSILType);
425-
auto *CAI =
426-
Builder.createCopyAddr(Loc, archetypeValue, ASI, IsNotTake,
427-
IsInitialization_t::IsInitialization);
428-
TempCopyAddrInsts.push_back(CAI);
449+
Builder.createCopyAddr(Loc, archetypeValue, ASI, IsNotTake,
450+
IsInitialization_t::IsInitialization);
451+
Temps.push_back({ASI, OrigOperand});
429452
calleeArg = ASI;
430453
}
431454
ApplyArgs.push_back(calleeArg);
432455
break;
433456
}
434457
case ExistentialRepresentation::Class: {
435-
/// If the operand is not object type, we would need an explicit load.
458+
// If the operand is not object type, we need an explicit load.
459+
SILValue OrigValue = OrigOperand;
460+
if (!OrigOperand->getType().isObject()) {
461+
OrigValue = Builder.createLoad(Loc, OrigValue,
462+
LoadOwnershipQualifier::Unqualified);
463+
}
436464
// OpenExistentialRef forwards ownership, so it does the right thing
437465
// regardless of whether the argument is borrowed or consumed.
438-
assert(OrigOperand->getType().isObject());
439466
archetypeValue =
440-
Builder.createOpenExistentialRef(Loc, OrigOperand, OpenedSILType);
467+
Builder.createOpenExistentialRef(Loc, OrigValue, OpenedSILType);
468+
if (!OrigOperand->getType().isObject()) {
469+
SILValue ASI = Builder.createAllocStack(Loc, OpenedSILType);
470+
Builder.createStore(Loc, archetypeValue, ASI,
471+
StoreOwnershipQualifier::Unqualified);
472+
Temps.push_back({ASI, SILValue()});
473+
archetypeValue = ASI;
474+
}
441475
ApplyArgs.push_back(archetypeValue);
442476
break;
443477
}
@@ -511,7 +545,7 @@ void ExistentialTransform::populateThunkBody() {
511545
ReturnValue = Builder.createApply(Loc, FRI, SubMap, ApplyArgs);
512546
}
513547
auto cleanupLoc = RegularLocation::getAutoGeneratedLocation();
514-
for (CopyAddrInst *CAI : reversed(TempCopyAddrInsts)) {
548+
for (auto &Temp : reversed(Temps)) {
515549
// The original argument was copied into a temporary and consumed by the
516550
// callee as such:
517551
// bb (%consumedExistential : $*Protocol)
@@ -523,10 +557,10 @@ void ExistentialTransform::populateThunkBody() {
523557
// Destroy the original arument and deallocation the temporary:
524558
// destroy_addr %consumedExistential : $*Protocol
525559
// dealloc_stack %temp : $*T
526-
auto *consumedExistential = cast<SILFunctionArgument>(
527-
cast<OpenExistentialAddrInst>(CAI->getSrc())->getOperand());
528-
Builder.createDestroyAddr(cleanupLoc, consumedExistential);
529-
Builder.createDeallocStack(cleanupLoc, CAI->getDest());
560+
if (Temp.DestroyValue)
561+
Builder.createDestroyAddr(cleanupLoc, Temp.DestroyValue);
562+
if (Temp.DeallocStackEntry)
563+
Builder.createDeallocStack(cleanupLoc, Temp.DeallocStackEntry);
530564
}
531565
/// Set up the return results.
532566
if (NewF->isNoReturnFunction()) {
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// RUN: %target-sil-opt -wmo -enable-sil-verify-all -emit-sorted-sil %s -enable-existential-specializer -existential-specializer -inline -sil-combine -generic-specializer -devirtualizer 2>&1 | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Swift
6+
7+
protocol ClassProtocol: AnyObject { func method() }
8+
9+
class C: ClassProtocol { func method() {} }
10+
11+
// CHECK-LABEL: sil shared @$s28test_indirect_class_protocolTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : ClassProtocol> (@in τ_0_0) -> ()
12+
sil hidden @test_indirect_class_protocol : $@convention(thin) (@in ClassProtocol) -> () {
13+
// CHECK-NEXT: //
14+
// CHECK-NEXT: bb0(%0 : $*τ_0_0):
15+
// CHECK-NEXT: %1 = load %0
16+
// CHECK-NEXT: %2 = init_existential_ref %1
17+
// CHECK-NEXT: %3 = alloc_stack $ClassProtocol
18+
// CHECK-NEXT: store %2 to %3
19+
bb0(%0 : $*ClassProtocol):
20+
// CHECK-NEXT: destroy_addr %3
21+
destroy_addr %0 : $*ClassProtocol
22+
// CHECK-NEXT: dealloc_stack %3
23+
// CHECK-NEXT: return undef
24+
return undef : $()
25+
}
26+
27+
// CHECK-LABEL: sil shared @$s39test_indirect_class_protocol_guaranteedTf4e_n : $@convention(thin) <τ_0_0 where τ_0_0 : ClassProtocol> (@in_guaranteed τ_0_0) -> ()
28+
sil hidden @test_indirect_class_protocol_guaranteed : $@convention(thin) (@in_guaranteed ClassProtocol) -> () {
29+
// CHECK-NEXT: //
30+
// CHECK-NEXT: bb0(%0 : $*τ_0_0):
31+
// CHECK-NEXT: %1 = load %0
32+
// CHECK-NEXT: %2 = init_existential_ref %1
33+
// CHECK-NEXT: %3 = alloc_stack $ClassProtocol
34+
// CHECK-NEXT: store %2 to %3
35+
bb0(%0 : $*ClassProtocol):
36+
// CHECK-NEXT: %5 = load %3 : $*ClassProtocol
37+
%1 = load %0 : $*ClassProtocol
38+
// CHECK-NEXT: %6 = open_existential_ref %5
39+
%2 = open_existential_ref %1 : $ClassProtocol to $@opened("ABCDEF01-ABCD-ABCD-ABCD-ABCDEFABCDEF") ClassProtocol
40+
// CHECK-NEXT: %7 = witness_method $C, #ClassProtocol.method
41+
%f = witness_method $@opened("ABCDEF01-ABCD-ABCD-ABCD-ABCDEFABCDEF") ClassProtocol, #ClassProtocol.method!1 : <Self: ClassProtocol> (Self) -> () -> (), %2 : $@opened("ABCDEF01-ABCD-ABCD-ABCD-ABCDEFABCDEF") ClassProtocol : $@convention(witness_method : ClassProtocol) <Self: ClassProtocol> (@guaranteed Self) -> ()
42+
// CHECK-NEXT: %8 = unchecked_ref_cast %6
43+
// CHECK-NEXT: %9 = apply %7<C>(%8)
44+
apply %f<@opened("ABCDEF01-ABCD-ABCD-ABCD-ABCDEFABCDEF") ClassProtocol>(%2) : $@convention(witness_method : ClassProtocol) <Self: ClassProtocol> (@guaranteed Self) -> ()
45+
// CHECK-NEXT: dealloc_stack %3
46+
// CHECK-NEXT: return undef
47+
return undef : $()
48+
}
49+
50+
// CHECK-LABEL: sil hidden @invoke_indirect_class_protocol
51+
sil hidden @invoke_indirect_class_protocol : $@convention(thin) (@guaranteed C) -> () {
52+
bb0(%0 : $C):
53+
%1 = init_existential_ref %0 : $C : $C, $ClassProtocol
54+
55+
// CHECK: [[INPUT:%.*]] = alloc_stack $ClassProtocol
56+
%z = alloc_stack $ClassProtocol
57+
retain_value %1 : $ClassProtocol
58+
store %1 to %z : $*ClassProtocol
59+
60+
// CHECK: [[SPECIALIZATION:%.*]] = function_ref @$s39test_indirect_class_protocol_guaranteedTf4e_n
61+
%f = function_ref @test_indirect_class_protocol_guaranteed : $@convention(thin) (@in_guaranteed ClassProtocol) -> ()
62+
// CHECK-NEXT: [[INPUT_LOAD:%.*]] = load [[INPUT]]
63+
// CHECK-NEXT: [[INPUT_OPEN:%.*]] = open_existential_ref [[INPUT_LOAD]] : $ClassProtocol to $[[OPENED_TYPE:@opened(.*) ClassProtocol]]
64+
// CHECK-NEXT: [[INPUT_OPEN_BUF:%.*]] = alloc_stack $[[OPENED_TYPE]]
65+
// CHECK-NEXT: store [[INPUT_OPEN]] to [[INPUT_OPEN_BUF]]
66+
// CHECK-NEXT: apply [[SPECIALIZATION]]<[[OPENED_TYPE]]>([[INPUT_OPEN_BUF]])
67+
apply %f(%z) : $@convention(thin) (@in_guaranteed ClassProtocol) -> ()
68+
// CHECK-NEXT: dealloc_stack [[INPUT_OPEN_BUF]]
69+
70+
// CHECK: [[SPECIALIZATION:%.*]] = function_ref @$s28test_indirect_class_protocolTf4e_n
71+
%g = function_ref @test_indirect_class_protocol : $@convention(thin) (@in ClassProtocol) -> ()
72+
// CHECK-NEXT: [[INPUT_LOAD:%.*]] = load [[INPUT]]
73+
// CHECK-NEXT: [[INPUT_OPEN:%.*]] = open_existential_ref [[INPUT_LOAD]] : $ClassProtocol to $[[OPENED_TYPE:@opened(.*) ClassProtocol]]
74+
// CHECK-NEXT: [[INPUT_OPEN_BUF:%.*]] = alloc_stack $[[OPENED_TYPE]]
75+
// CHECK-NEXT: store [[INPUT_OPEN]] to [[INPUT_OPEN_BUF]]
76+
// CHECK-NEXT: apply [[SPECIALIZATION]]<[[OPENED_TYPE]]>([[INPUT_OPEN_BUF]])
77+
apply %g(%z) : $@convention(thin) (@in ClassProtocol) -> ()
78+
// CHECK-NEXT: dealloc_stack [[INPUT_OPEN_BUF]]
79+
80+
dealloc_stack %z : $*ClassProtocol
81+
return undef : $()
82+
}

branches/master-next/test/SILOptimizer/existential_specializer_soletype.sil

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,3 +380,4 @@ bb0(%0 : $S, %1 : $*P):
380380
%15 = tuple ()
381381
return %15 : $()
382382
}
383+

0 commit comments

Comments
 (0)