Skip to content

Support for deinit of opaque existentials: deinit_existential_opaque instruction + SILGen support #7796

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 1 commit into from
Feb 27, 2017
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
17 changes: 17 additions & 0 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3743,6 +3743,7 @@ container may use one of several representations:

* `init_existential_opaque`_
* `open_existential_opaque`_
* `deinit_existential_opaque`_

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

deinit_existential_opaque
`````````````````````````
::

sil-instruction ::= 'deinit_existential_opaque' sil-operand

deinit_existential_opaque %0 : $P
// %0 must be of a $P opaque type for non-class protocol or protocol
// composition type P

Undoes the partial initialization performed by
``init_existential_opaque``. ``deinit_existential_opaque`` is only valid for
existential containers that have been partially initialized by
``init_existential_opaque`` but haven't had their contained value initialized.
A fully initialized existential must be destroyed with ``destroy_value``.

open_existential_addr
`````````````````````
::
Expand Down
1 change: 1 addition & 0 deletions include/swift/SIL/PatternMatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ UNARY_OP_MATCH_WITH_ARG_MATCHER(InitExistentialAddrInst)
UNARY_OP_MATCH_WITH_ARG_MATCHER(InitExistentialOpaqueInst)
UNARY_OP_MATCH_WITH_ARG_MATCHER(InitExistentialRefInst)
UNARY_OP_MATCH_WITH_ARG_MATCHER(DeinitExistentialAddrInst)
UNARY_OP_MATCH_WITH_ARG_MATCHER(DeinitExistentialOpaqueInst)
UNARY_OP_MATCH_WITH_ARG_MATCHER(ProjectBlockStorageInst)
UNARY_OP_MATCH_WITH_ARG_MATCHER(StrongRetainInst)
UNARY_OP_MATCH_WITH_ARG_MATCHER(StrongReleaseInst)
Expand Down
6 changes: 6 additions & 0 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,12 @@ class SILBuilder {
getSILDebugLocation(Loc), Existential));
}

DeinitExistentialOpaqueInst *
createDeinitExistentialOpaque(SILLocation Loc, SILValue Existential) {
return insert(new (F.getModule()) DeinitExistentialOpaqueInst(
getSILDebugLocation(Loc), Existential));
}

ProjectBlockStorageInst *createProjectBlockStorage(SILLocation Loc,
SILValue Storage) {
auto CaptureTy = Storage->getType()
Expand Down
9 changes: 9 additions & 0 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,15 @@ SILCloner<ImplClass>::visitDeinitExistentialAddrInst(DeinitExistentialAddrInst *
getOpValue(Inst->getOperand())));
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitDeinitExistentialOpaqueInst(
DeinitExistentialOpaqueInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
doPostProcess(
Inst, getBuilder().createDeinitExistentialOpaque(
getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand())));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::visitCopyBlockInst(CopyBlockInst *Inst) {
Expand Down
9 changes: 9 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -4167,6 +4167,15 @@ class DeinitExistentialAddrInst
: UnaryInstructionBase(DebugLoc, Existential) {}
};

class DeinitExistentialOpaqueInst
: public UnaryInstructionBase<ValueKind::DeinitExistentialOpaqueInst,
SILInstruction, /*HAS_RESULT*/ false> {
friend SILBuilder;

DeinitExistentialOpaqueInst(SILDebugLocation DebugLoc, SILValue Existential)
: UnaryInstructionBase(DebugLoc, Existential) {}
};

/// Projects the capture storage address from a @block_storage address.
class ProjectBlockStorageInst
: public UnaryInstructionBase<ValueKind::ProjectBlockStorageInst,
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
INST(InitExistentialOpaqueInst, SILInstruction, init_existential_opaque, MayWrite, DoesNotRelease)
INST(DeinitExistentialAddrInst, SILInstruction, deinit_existential_addr, MayHaveSideEffects,
DoesNotRelease)
INST(DeinitExistentialOpaqueInst, SILInstruction, deinit_existential_opaque, MayHaveSideEffects,
DoesNotRelease)
INST(OpenExistentialAddrInst, SILInstruction, open_existential_addr, MayRead, DoesNotRelease)
INST(InitExistentialRefInst, SILInstruction, init_existential_ref, None, DoesNotRelease)
INST(OpenExistentialRefInst, SILInstruction, open_existential_ref, None, DoesNotRelease)
Expand Down
8 changes: 7 additions & 1 deletion lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,8 @@ class IRGenSILFunction :
void visitInitExistentialMetatypeInst(InitExistentialMetatypeInst *i);
void visitInitExistentialRefInst(InitExistentialRefInst *i);
void visitDeinitExistentialAddrInst(DeinitExistentialAddrInst *i);

void visitDeinitExistentialOpaqueInst(DeinitExistentialOpaqueInst *i);

void visitAllocExistentialBoxInst(AllocExistentialBoxInst *i);
void visitOpenExistentialBoxInst(OpenExistentialBoxInst *i);
void visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i);
Expand Down Expand Up @@ -4511,6 +4512,11 @@ void IRGenSILFunction::visitDeinitExistentialAddrInst(
i->getOperand()->getType());
}

void IRGenSILFunction::visitDeinitExistentialOpaqueInst(
swift::DeinitExistentialOpaqueInst *i) {
llvm_unreachable("unsupported instruction during IRGen");
}

void IRGenSILFunction::visitOpenExistentialAddrInst(OpenExistentialAddrInst *i) {
SILType baseTy = i->getOperand()->getType();
Address base = getLoweredAddress(i->getOperand());
Expand Down
6 changes: 6 additions & 0 deletions lib/Parse/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3724,6 +3724,12 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
ResultVal = B.createDeinitExistentialAddr(InstLoc, Val);
break;
}
case ValueKind::DeinitExistentialOpaqueInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeinitExistentialOpaque(InstLoc, Val);
break;
}
case ValueKind::InitExistentialAddrInst: {
CanType Ty;
SourceLoc TyLoc;
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/SILOwnershipVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ CONSTANT_OWNERSHIP_INST(Trivial, false, DeallocValueBuffer)
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, CheckedCastBranch)
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, SwitchEnum)
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, InitExistentialOpaque)
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, DeinitExistentialOpaque)
#undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST

#define ACCEPTS_ANY_OWNERSHIP_INST(INST) \
Expand Down
3 changes: 3 additions & 0 deletions lib/SIL/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,9 @@ class SILPrinter : public SILVisitor<SILPrinter> {
void visitDeinitExistentialAddrInst(DeinitExistentialAddrInst *DEI) {
*this << getIDAndType(DEI->getOperand());
}
void visitDeinitExistentialOpaqueInst(DeinitExistentialOpaqueInst *DEI) {
*this << getIDAndType(DEI->getOperand());
}
void visitDeallocExistentialBoxInst(DeallocExistentialBoxInst *DEI) {
*this << getIDAndType(DEI->getOperand()) << ", $" << DEI->getConcreteType();
}
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/SILValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ NO_RESULT_OWNERSHIP_INST(DestroyValue)
NO_RESULT_OWNERSHIP_INST(AllocGlobal)
NO_RESULT_OWNERSHIP_INST(InjectEnumAddr)
NO_RESULT_OWNERSHIP_INST(DeinitExistentialAddr)
NO_RESULT_OWNERSHIP_INST(DeinitExistentialOpaque)
NO_RESULT_OWNERSHIP_INST(CondFail)

// Terminators. These do not produce SILValue, so they do not have a
Expand Down
17 changes: 13 additions & 4 deletions lib/SIL/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2390,10 +2390,19 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
SILType exType = DEI->getOperand()->getType();
require(exType.isAddress(),
"deinit_existential_addr must be applied to an address");
require(exType.canUseExistentialRepresentation(F.getModule(),
ExistentialRepresentation::Opaque),
"deinit_existential_addr must be applied to an opaque "
"existential");
require(exType.canUseExistentialRepresentation(
F.getModule(), ExistentialRepresentation::Opaque),
"deinit_existential_addr must be applied to an opaque existential");
}

void checkDeinitExistentialOpaqueInst(DeinitExistentialOpaqueInst *DEI) {
SILType exType = DEI->getOperand()->getType();
require(!exType.isAddress(),
"deinit_existential_opaque must not be applied to an address");
require(
exType.canUseExistentialRepresentation(
F.getModule(), ExistentialRepresentation::Opaque),
"deinit_existential_opaque must be applied to an opaque existential");
}

void checkDeallocExistentialBoxInst(DeallocExistentialBoxInst *DEBI) {
Expand Down
5 changes: 0 additions & 5 deletions lib/SIL/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1105,11 +1105,6 @@ namespace {
llvm_unreachable("destroy address");
}

void emitDestroyRValue(SILBuilder &B, SILLocation loc,
SILValue value) const override {
llvm_unreachable("destroy value");
}

void emitCopyInto(SILBuilder &B, SILLocation loc,
SILValue src, SILValue dest, IsTake_t isTake,
IsInitialization_t isInit) const override {
Expand Down
29 changes: 14 additions & 15 deletions lib/SILGen/SILGenConvert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -781,26 +781,25 @@ SILGenFunction::emitOpenExistential(
SILType existentialType = existentialValue.getType();
switch (existentialType.getPreferredExistentialRepresentation(SGM.M)) {
case ExistentialRepresentation::Opaque: {
SILValue archetypeValue;
if (existentialType.isAddress()) {
OpenedExistentialAccess allowedAccess =
getOpenedExistentialAccessFor(accessKind);
SILValue archetypeValue = B.createOpenExistentialAddr(
loc, existentialValue.forward(*this), loweredOpenedType,
allowedAccess);
if (existentialValue.hasCleanup()) {
canConsume = true;
// Leave a cleanup to deinit the existential container.
enterDeinitExistentialCleanup(existentialValue.getValue(), CanType(),
ExistentialRepresentation::Opaque);
archetypeMV = emitManagedBufferWithCleanup(archetypeValue);
} else {
canConsume = false;
archetypeMV = ManagedValue::forUnmanaged(archetypeValue);
}
archetypeValue =
B.createOpenExistentialAddr(loc, existentialValue.forward(*this),
loweredOpenedType, allowedAccess);
} else {
SILValue archetypeValue = B.createOpenExistentialOpaque(
archetypeValue = B.createOpenExistentialOpaque(
loc, existentialValue.forward(*this), loweredOpenedType);
assert(!existentialValue.hasCleanup());
}

if (existentialValue.hasCleanup()) {
canConsume = true;
// Leave a cleanup to deinit the existential container.
enterDeinitExistentialCleanup(existentialValue.getValue(), CanType(),
ExistentialRepresentation::Opaque);
archetypeMV = emitManagedBufferWithCleanup(archetypeValue);
} else {
canConsume = false;
archetypeMV = ManagedValue::forUnmanaged(archetypeValue);
}
Expand Down
6 changes: 5 additions & 1 deletion lib/SILGen/SILGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,11 @@ namespace {
case ExistentialRepresentation::Metatype:
llvm_unreachable("cannot cleanup existential");
case ExistentialRepresentation::Opaque:
gen.B.createDeinitExistentialAddr(l, existentialAddr);
if (gen.silConv.useLoweredAddresses()) {
gen.B.createDeinitExistentialAddr(l, existentialAddr);
} else {
gen.B.createDeinitExistentialOpaque(l, existentialAddr);
}
break;
case ExistentialRepresentation::Boxed:
gen.B.createDeallocExistentialBox(l, concreteFormalType,
Expand Down
3 changes: 2 additions & 1 deletion lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,8 @@ ManagedValue SILGenFunction::emitManagedBufferWithCleanup(SILValue v) {

ManagedValue SILGenFunction::emitManagedBufferWithCleanup(SILValue v,
const TypeLowering &lowering) {
assert(lowering.getLoweredType().getAddressType() == v->getType());
assert(lowering.getLoweredType().getAddressType() == v->getType() ||
!silConv.useLoweredAddresses());
if (lowering.isTrivial())
return ManagedValue::forUnmanaged(v);

Expand Down
1 change: 1 addition & 0 deletions lib/SILOptimizer/Utils/SILInliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
case ValueKind::DeallocStackInst:
case ValueKind::DeallocValueBufferInst:
case ValueKind::DeinitExistentialAddrInst:
case ValueKind::DeinitExistentialOpaqueInst:
case ValueKind::DestroyAddrInst:
case ValueKind::ProjectValueBufferInst:
case ValueKind::ProjectBoxInst:
Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/DeserializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
UNARY_INSTRUCTION(UnmanagedAutoreleaseValue)
REFCOUNTING_INSTRUCTION(SetDeallocating)
UNARY_INSTRUCTION(DeinitExistentialAddr)
UNARY_INSTRUCTION(DeinitExistentialOpaque)
UNARY_INSTRUCTION(EndBorrowArgument)
UNARY_INSTRUCTION(DestroyAddr)
UNARY_INSTRUCTION(IsNonnull)
Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/SerializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
case ValueKind::DeallocStackInst:
case ValueKind::DeallocRefInst:
case ValueKind::DeinitExistentialAddrInst:
case ValueKind::DeinitExistentialOpaqueInst:
case ValueKind::DestroyAddrInst:
case ValueKind::IsNonnullInst:
case ValueKind::LoadInst:
Expand Down
17 changes: 17 additions & 0 deletions test/SILGen/opaque_values_silgen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,20 @@ var foo_var : Foo = s180_______return_foo()
func s190___return_foo_var() -> Foo {
return foo_var
}

// Tests deinit of opaque existentials
// ---
// CHECK-LABEL: sil hidden @_T020opaque_values_silgen21s200______use_foo_varyyF : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: [[GLOBAL:%.*]] = global_addr {{.*}} : $*Foo
// CHECK: [[LOAD_GLOBAL:%.*]] = load [copy] [[GLOBAL]] : $*Foo
// CHECK: [[OPEN_VAR:%.*]] = open_existential_opaque [[LOAD_GLOBAL]] : $Foo
// CHECK: [[WITNESS:%.*]] = witness_method $@opened
// CHECK: apply [[WITNESS]]
// CHECK: destroy_value [[OPEN_VAR]]
// CHECK: deinit_existential_opaque [[LOAD_GLOBAL]] : $Foo
// CHECK: return %{{.*}} : $()
// CHECK-LABEL: } // end sil function '_T020opaque_values_silgen21s200______use_foo_varyyF'
func s200______use_foo_var() {
foo_var.foo()
}
3 changes: 2 additions & 1 deletion utils/sil-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@
;; Protocol and Protocol Composition Types
`(,(regexp-opt '("init_existential_addr" "deinit_existential_addr"
"open_existential_addr"
"init_existential_opaque" "open_existential_opaque"
"init_existential_opaque" "deinit_existential_opaque"
"open_existential_opaque"
"alloc_existential_box" "project_existential_box"
"open_existential_box" "dealloc_existential_box"
"init_existential_ref" "open_existential_ref"
Expand Down
2 changes: 1 addition & 1 deletion utils/vim/syntax/sil.vim
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ syn keyword swiftApplyKeyword apply try_apply skipwhite
syn keyword swiftKeyword metatype value_metatype existential_metatype skipwhite
syn keyword swiftKeyword retain_value release_value tuple tuple_extract tuple_element_addr struct struct_extract struct_element_addr ref_element_addr skipwhite
syn keyword swiftKeyword init_enum_data_addr unchecked_enum_data unchecked_take_enum_data_addr inject_enum_addr skipwhite
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
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
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
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
syn keyword swiftKeyword objc_existential_metatype_to_object objc_metatype_to_object objc_protocol skipwhite
Expand Down