Skip to content

Commit 4b6cfaf

Browse files
author
Joe Shajrawi
authored
Merge pull request #7796 from shajrawi/deinit_existential
Support for deinit of opaque existentials: deinit_existential_opaque instruction + SILGen support
2 parents 933190f + 16b6cb5 commit 4b6cfaf

22 files changed

+119
-29
lines changed

docs/SIL.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3743,6 +3743,7 @@ container may use one of several representations:
37433743

37443744
* `init_existential_opaque`_
37453745
* `open_existential_opaque`_
3746+
* `deinit_existential_opaque`_
37463747

37473748
- **Class existential containers**: If a protocol type is constrained by one or
37483749
more class protocols, then the existential container for that type is
@@ -3847,6 +3848,22 @@ existential containers that have been partially initialized by
38473848
``init_existential_addr`` but haven't had their contained value initialized.
38483849
A fully initialized existential must be destroyed with ``destroy_addr``.
38493850

3851+
deinit_existential_opaque
3852+
`````````````````````````
3853+
::
3854+
3855+
sil-instruction ::= 'deinit_existential_opaque' sil-operand
3856+
3857+
deinit_existential_opaque %0 : $P
3858+
// %0 must be of a $P opaque type for non-class protocol or protocol
3859+
// composition type P
3860+
3861+
Undoes the partial initialization performed by
3862+
``init_existential_opaque``. ``deinit_existential_opaque`` is only valid for
3863+
existential containers that have been partially initialized by
3864+
``init_existential_opaque`` but haven't had their contained value initialized.
3865+
A fully initialized existential must be destroyed with ``destroy_value``.
3866+
38503867
open_existential_addr
38513868
`````````````````````
38523869
::

include/swift/SIL/PatternMatch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ UNARY_OP_MATCH_WITH_ARG_MATCHER(InitExistentialAddrInst)
369369
UNARY_OP_MATCH_WITH_ARG_MATCHER(InitExistentialOpaqueInst)
370370
UNARY_OP_MATCH_WITH_ARG_MATCHER(InitExistentialRefInst)
371371
UNARY_OP_MATCH_WITH_ARG_MATCHER(DeinitExistentialAddrInst)
372+
UNARY_OP_MATCH_WITH_ARG_MATCHER(DeinitExistentialOpaqueInst)
372373
UNARY_OP_MATCH_WITH_ARG_MATCHER(ProjectBlockStorageInst)
373374
UNARY_OP_MATCH_WITH_ARG_MATCHER(StrongRetainInst)
374375
UNARY_OP_MATCH_WITH_ARG_MATCHER(StrongReleaseInst)

include/swift/SIL/SILBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,12 @@ class SILBuilder {
11791179
getSILDebugLocation(Loc), Existential));
11801180
}
11811181

1182+
DeinitExistentialOpaqueInst *
1183+
createDeinitExistentialOpaque(SILLocation Loc, SILValue Existential) {
1184+
return insert(new (F.getModule()) DeinitExistentialOpaqueInst(
1185+
getSILDebugLocation(Loc), Existential));
1186+
}
1187+
11821188
ProjectBlockStorageInst *createProjectBlockStorage(SILLocation Loc,
11831189
SILValue Storage) {
11841190
auto CaptureTy = Storage->getType()

include/swift/SIL/SILCloner.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,6 +1648,15 @@ SILCloner<ImplClass>::visitDeinitExistentialAddrInst(DeinitExistentialAddrInst *
16481648
getOpValue(Inst->getOperand())));
16491649
}
16501650

1651+
template <typename ImplClass>
1652+
void SILCloner<ImplClass>::visitDeinitExistentialOpaqueInst(
1653+
DeinitExistentialOpaqueInst *Inst) {
1654+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1655+
doPostProcess(
1656+
Inst, getBuilder().createDeinitExistentialOpaque(
1657+
getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand())));
1658+
}
1659+
16511660
template<typename ImplClass>
16521661
void
16531662
SILCloner<ImplClass>::visitCopyBlockInst(CopyBlockInst *Inst) {

include/swift/SIL/SILInstruction.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4176,6 +4176,15 @@ class DeinitExistentialAddrInst
41764176
: UnaryInstructionBase(DebugLoc, Existential) {}
41774177
};
41784178

4179+
class DeinitExistentialOpaqueInst
4180+
: public UnaryInstructionBase<ValueKind::DeinitExistentialOpaqueInst,
4181+
SILInstruction, /*HAS_RESULT*/ false> {
4182+
friend SILBuilder;
4183+
4184+
DeinitExistentialOpaqueInst(SILDebugLocation DebugLoc, SILValue Existential)
4185+
: UnaryInstructionBase(DebugLoc, Existential) {}
4186+
};
4187+
41794188
/// Projects the capture storage address from a @block_storage address.
41804189
class ProjectBlockStorageInst
41814190
: public UnaryInstructionBase<ValueKind::ProjectBlockStorageInst,

include/swift/SIL/SILNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
227227
INST(InitExistentialOpaqueInst, SILInstruction, init_existential_opaque, MayWrite, DoesNotRelease)
228228
INST(DeinitExistentialAddrInst, SILInstruction, deinit_existential_addr, MayHaveSideEffects,
229229
DoesNotRelease)
230+
INST(DeinitExistentialOpaqueInst, SILInstruction, deinit_existential_opaque, MayHaveSideEffects,
231+
DoesNotRelease)
230232
INST(OpenExistentialAddrInst, SILInstruction, open_existential_addr, MayRead, DoesNotRelease)
231233
INST(InitExistentialRefInst, SILInstruction, init_existential_ref, None, DoesNotRelease)
232234
INST(OpenExistentialRefInst, SILInstruction, open_existential_ref, None, DoesNotRelease)

lib/IRGen/IRGenSIL.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,8 @@ class IRGenSILFunction :
887887
void visitInitExistentialMetatypeInst(InitExistentialMetatypeInst *i);
888888
void visitInitExistentialRefInst(InitExistentialRefInst *i);
889889
void visitDeinitExistentialAddrInst(DeinitExistentialAddrInst *i);
890-
890+
void visitDeinitExistentialOpaqueInst(DeinitExistentialOpaqueInst *i);
891+
891892
void visitAllocExistentialBoxInst(AllocExistentialBoxInst *i);
892893
void visitOpenExistentialBoxInst(OpenExistentialBoxInst *i);
893894
void visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i);
@@ -4504,6 +4505,11 @@ void IRGenSILFunction::visitDeinitExistentialAddrInst(
45044505
i->getOperand()->getType());
45054506
}
45064507

4508+
void IRGenSILFunction::visitDeinitExistentialOpaqueInst(
4509+
swift::DeinitExistentialOpaqueInst *i) {
4510+
llvm_unreachable("unsupported instruction during IRGen");
4511+
}
4512+
45074513
void IRGenSILFunction::visitOpenExistentialAddrInst(OpenExistentialAddrInst *i) {
45084514
SILType baseTy = i->getOperand()->getType();
45094515
Address base = getLoweredAddress(i->getOperand());

lib/Parse/ParseSIL.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3724,6 +3724,12 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
37243724
ResultVal = B.createDeinitExistentialAddr(InstLoc, Val);
37253725
break;
37263726
}
3727+
case ValueKind::DeinitExistentialOpaqueInst: {
3728+
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
3729+
return true;
3730+
ResultVal = B.createDeinitExistentialOpaque(InstLoc, Val);
3731+
break;
3732+
}
37273733
case ValueKind::InitExistentialAddrInst: {
37283734
CanType Ty;
37293735
SourceLoc TyLoc;

lib/SIL/SILOwnershipVerifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ CONSTANT_OWNERSHIP_INST(Trivial, false, DeallocValueBuffer)
457457
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, CheckedCastBranch)
458458
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, SwitchEnum)
459459
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, InitExistentialOpaque)
460+
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, DeinitExistentialOpaque)
460461
#undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
461462

462463
#define ACCEPTS_ANY_OWNERSHIP_INST(INST) \

lib/SIL/SILPrinter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,6 +1522,9 @@ class SILPrinter : public SILVisitor<SILPrinter> {
15221522
void visitDeinitExistentialAddrInst(DeinitExistentialAddrInst *DEI) {
15231523
*this << getIDAndType(DEI->getOperand());
15241524
}
1525+
void visitDeinitExistentialOpaqueInst(DeinitExistentialOpaqueInst *DEI) {
1526+
*this << getIDAndType(DEI->getOperand());
1527+
}
15251528
void visitDeallocExistentialBoxInst(DeallocExistentialBoxInst *DEI) {
15261529
*this << getIDAndType(DEI->getOperand()) << ", $" << DEI->getConcreteType();
15271530
}

lib/SIL/SILValue.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ NO_RESULT_OWNERSHIP_INST(DestroyValue)
331331
NO_RESULT_OWNERSHIP_INST(AllocGlobal)
332332
NO_RESULT_OWNERSHIP_INST(InjectEnumAddr)
333333
NO_RESULT_OWNERSHIP_INST(DeinitExistentialAddr)
334+
NO_RESULT_OWNERSHIP_INST(DeinitExistentialOpaque)
334335
NO_RESULT_OWNERSHIP_INST(CondFail)
335336

336337
// Terminators. These do not produce SILValue, so they do not have a

lib/SIL/SILVerifier.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2390,10 +2390,19 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
23902390
SILType exType = DEI->getOperand()->getType();
23912391
require(exType.isAddress(),
23922392
"deinit_existential_addr must be applied to an address");
2393-
require(exType.canUseExistentialRepresentation(F.getModule(),
2394-
ExistentialRepresentation::Opaque),
2395-
"deinit_existential_addr must be applied to an opaque "
2396-
"existential");
2393+
require(exType.canUseExistentialRepresentation(
2394+
F.getModule(), ExistentialRepresentation::Opaque),
2395+
"deinit_existential_addr must be applied to an opaque existential");
2396+
}
2397+
2398+
void checkDeinitExistentialOpaqueInst(DeinitExistentialOpaqueInst *DEI) {
2399+
SILType exType = DEI->getOperand()->getType();
2400+
require(!exType.isAddress(),
2401+
"deinit_existential_opaque must not be applied to an address");
2402+
require(
2403+
exType.canUseExistentialRepresentation(
2404+
F.getModule(), ExistentialRepresentation::Opaque),
2405+
"deinit_existential_opaque must be applied to an opaque existential");
23972406
}
23982407

23992408
void checkDeallocExistentialBoxInst(DeallocExistentialBoxInst *DEBI) {

lib/SIL/TypeLowering.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,11 +1105,6 @@ namespace {
11051105
llvm_unreachable("destroy address");
11061106
}
11071107

1108-
void emitDestroyRValue(SILBuilder &B, SILLocation loc,
1109-
SILValue value) const override {
1110-
llvm_unreachable("destroy value");
1111-
}
1112-
11131108
void emitCopyInto(SILBuilder &B, SILLocation loc,
11141109
SILValue src, SILValue dest, IsTake_t isTake,
11151110
IsInitialization_t isInit) const override {

lib/SILGen/SILGenConvert.cpp

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -781,26 +781,25 @@ SILGenFunction::emitOpenExistential(
781781
SILType existentialType = existentialValue.getType();
782782
switch (existentialType.getPreferredExistentialRepresentation(SGM.M)) {
783783
case ExistentialRepresentation::Opaque: {
784+
SILValue archetypeValue;
784785
if (existentialType.isAddress()) {
785786
OpenedExistentialAccess allowedAccess =
786787
getOpenedExistentialAccessFor(accessKind);
787-
SILValue archetypeValue = B.createOpenExistentialAddr(
788-
loc, existentialValue.forward(*this), loweredOpenedType,
789-
allowedAccess);
790-
if (existentialValue.hasCleanup()) {
791-
canConsume = true;
792-
// Leave a cleanup to deinit the existential container.
793-
enterDeinitExistentialCleanup(existentialValue.getValue(), CanType(),
794-
ExistentialRepresentation::Opaque);
795-
archetypeMV = emitManagedBufferWithCleanup(archetypeValue);
796-
} else {
797-
canConsume = false;
798-
archetypeMV = ManagedValue::forUnmanaged(archetypeValue);
799-
}
788+
archetypeValue =
789+
B.createOpenExistentialAddr(loc, existentialValue.forward(*this),
790+
loweredOpenedType, allowedAccess);
800791
} else {
801-
SILValue archetypeValue = B.createOpenExistentialOpaque(
792+
archetypeValue = B.createOpenExistentialOpaque(
802793
loc, existentialValue.forward(*this), loweredOpenedType);
803-
assert(!existentialValue.hasCleanup());
794+
}
795+
796+
if (existentialValue.hasCleanup()) {
797+
canConsume = true;
798+
// Leave a cleanup to deinit the existential container.
799+
enterDeinitExistentialCleanup(existentialValue.getValue(), CanType(),
800+
ExistentialRepresentation::Opaque);
801+
archetypeMV = emitManagedBufferWithCleanup(archetypeValue);
802+
} else {
804803
canConsume = false;
805804
archetypeMV = ManagedValue::forUnmanaged(archetypeValue);
806805
}

lib/SILGen/SILGenDecl.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1233,7 +1233,11 @@ namespace {
12331233
case ExistentialRepresentation::Metatype:
12341234
llvm_unreachable("cannot cleanup existential");
12351235
case ExistentialRepresentation::Opaque:
1236-
gen.B.createDeinitExistentialAddr(l, existentialAddr);
1236+
if (gen.silConv.useLoweredAddresses()) {
1237+
gen.B.createDeinitExistentialAddr(l, existentialAddr);
1238+
} else {
1239+
gen.B.createDeinitExistentialOpaque(l, existentialAddr);
1240+
}
12371241
break;
12381242
case ExistentialRepresentation::Boxed:
12391243
gen.B.createDeallocExistentialBox(l, concreteFormalType,

lib/SILGen/SILGenExpr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,8 @@ ManagedValue SILGenFunction::emitManagedBufferWithCleanup(SILValue v) {
290290

291291
ManagedValue SILGenFunction::emitManagedBufferWithCleanup(SILValue v,
292292
const TypeLowering &lowering) {
293-
assert(lowering.getLoweredType().getAddressType() == v->getType());
293+
assert(lowering.getLoweredType().getAddressType() == v->getType() ||
294+
!silConv.useLoweredAddresses());
294295
if (lowering.isTrivial())
295296
return ManagedValue::forUnmanaged(v);
296297

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
337337
case ValueKind::DeallocStackInst:
338338
case ValueKind::DeallocValueBufferInst:
339339
case ValueKind::DeinitExistentialAddrInst:
340+
case ValueKind::DeinitExistentialOpaqueInst:
340341
case ValueKind::DestroyAddrInst:
341342
case ValueKind::ProjectValueBufferInst:
342343
case ValueKind::ProjectBoxInst:

lib/Serialization/DeserializeSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,6 +1353,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
13531353
REFCOUNTING_INSTRUCTION(UnmanagedAutoreleaseValue)
13541354
REFCOUNTING_INSTRUCTION(SetDeallocating)
13551355
UNARY_INSTRUCTION(DeinitExistentialAddr)
1356+
UNARY_INSTRUCTION(DeinitExistentialOpaque)
13561357
UNARY_INSTRUCTION(EndBorrowArgument)
13571358
UNARY_INSTRUCTION(DestroyAddr)
13581359
UNARY_INSTRUCTION(IsNonnull)

lib/Serialization/SerializeSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
10471047
case ValueKind::DeallocStackInst:
10481048
case ValueKind::DeallocRefInst:
10491049
case ValueKind::DeinitExistentialAddrInst:
1050+
case ValueKind::DeinitExistentialOpaqueInst:
10501051
case ValueKind::DestroyAddrInst:
10511052
case ValueKind::IsNonnullInst:
10521053
case ValueKind::LoadInst:

test/SILGen/opaque_values_silgen.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,3 +290,20 @@ var foo_var : Foo = s180_______return_foo()
290290
func s190___return_foo_var() -> Foo {
291291
return foo_var
292292
}
293+
294+
// Tests deinit of opaque existentials
295+
// ---
296+
// CHECK-LABEL: sil hidden @_T020opaque_values_silgen21s200______use_foo_varyyF : $@convention(thin) () -> () {
297+
// CHECK: bb0:
298+
// CHECK: [[GLOBAL:%.*]] = global_addr {{.*}} : $*Foo
299+
// CHECK: [[LOAD_GLOBAL:%.*]] = load [copy] [[GLOBAL]] : $*Foo
300+
// CHECK: [[OPEN_VAR:%.*]] = open_existential_opaque [[LOAD_GLOBAL]] : $Foo
301+
// CHECK: [[WITNESS:%.*]] = witness_method $@opened
302+
// CHECK: apply [[WITNESS]]
303+
// CHECK: destroy_value [[OPEN_VAR]]
304+
// CHECK: deinit_existential_opaque [[LOAD_GLOBAL]] : $Foo
305+
// CHECK: return %{{.*}} : $()
306+
// CHECK-LABEL: } // end sil function '_T020opaque_values_silgen21s200______use_foo_varyyF'
307+
func s200______use_foo_var() {
308+
foo_var.foo()
309+
}

utils/sil-mode.el

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@
121121
;; Protocol and Protocol Composition Types
122122
`(,(regexp-opt '("init_existential_addr" "deinit_existential_addr"
123123
"open_existential_addr"
124-
"init_existential_opaque" "open_existential_opaque"
124+
"init_existential_opaque" "deinit_existential_opaque"
125+
"open_existential_opaque"
125126
"alloc_existential_box" "project_existential_box"
126127
"open_existential_box" "dealloc_existential_box"
127128
"init_existential_ref" "open_existential_ref"

utils/vim/syntax/sil.vim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ syn keyword swiftApplyKeyword apply try_apply skipwhite
3636
syn keyword swiftKeyword metatype value_metatype existential_metatype skipwhite
3737
syn keyword swiftKeyword retain_value release_value tuple tuple_extract tuple_element_addr struct struct_extract struct_element_addr ref_element_addr skipwhite
3838
syn keyword swiftKeyword init_enum_data_addr unchecked_enum_data unchecked_take_enum_data_addr inject_enum_addr skipwhite
39-
syn keyword swiftKeyword init_existential_addr init_existential_opaque init_existential_metatype deinit_existential_addr open_existential_addr open_existential_box open_existential_metatype init_existential_ref open_existential_ref open_existential_opaque skipwhite
39+
syn keyword swiftKeyword init_existential_addr init_existential_opaque init_existential_metatype deinit_existential_addr deinit_existential_opaque open_existential_addr open_existential_box open_existential_metatype init_existential_ref open_existential_ref open_existential_opaque skipwhite
4040
syn keyword swiftKeyword upcast address_to_pointer pointer_to_address pointer_to_thin_function unchecked_addr_cast unchecked_ref_cast unchecked_ref_cast_addr ref_to_raw_pointer ref_to_bridge_object ref_to_unmanaged unmanaged_to_ref raw_pointer_to_ref skipwhite
4141
syn keyword swiftKeyword convert_function thick_to_objc_metatype thin_function_to_pointer objc_to_thick_metatype thin_to_thick_function is_nonnull unchecked_ref_bit_cast unchecked_trivial_bit_cast bridge_object_to_ref bridge_object_to_word unchecked_bitwise_cast skipwhite
4242
syn keyword swiftKeyword objc_existential_metatype_to_object objc_metatype_to_object objc_protocol skipwhite

0 commit comments

Comments
 (0)