Skip to content

Commit

Permalink
Add SIL instruction: open_existential_box_value.
Browse files Browse the repository at this point in the history
This has the same semantics as open_existential_box, but returns an object value
instead of an address.

This is used in SIL opaque values mode. Attempting to reuse open_existential_box
in this mode causes SIL type inconsistencies that are too difficult to work
around. Adding this instruction allows for consistent handling of opaque values.

The original versions of several of these currently redundant instructions will
be removed once the SIL representation stabilizes.
  • Loading branch information
atrick committed Jul 18, 2017
1 parent f657ad2 commit 4db2a46
Show file tree
Hide file tree
Showing 21 changed files with 129 additions and 5 deletions.
17 changes: 17 additions & 0 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3859,6 +3859,7 @@ container may use one of several representations:
* `alloc_existential_box`_
* `project_existential_box`_
* `open_existential_box`_
* `open_existential_box_value`_
* `dealloc_existential_box`_

Some existential types may additionally support specialized representations
Expand Down Expand Up @@ -4118,6 +4119,22 @@ the owning box and the enclosing function; in order to "open" a boxed
existential that has directly adopted a class reference, temporary scratch
space may need to have been allocated.

open_existential_box_value
``````````````````````````
::

sil-instruction ::= 'open_existential_box_value' sil-operand 'to' sil-type

%1 = open_existential_box_value %0 : $P to $@opened P
// %0 must be a value of boxed protocol or protocol composition type $P
// %@opened P must be a unique archetype that refers to an opened
// existential type P
// %1 will be of type $@opened P

Projects the value inside a boxed existential container, and uses the enclosed
type and protocol conformance metadata to bind the opened archetype ``$@opened
P``.

dealloc_existential_box
```````````````````````
::
Expand Down
9 changes: 9 additions & 0 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,15 @@ class SILBuilder {
return I;
}

OpenExistentialBoxValueInst *
createOpenExistentialBoxValue(SILLocation Loc, SILValue Operand, SILType Ty) {
auto *I = insert(new (F.getModule()) OpenExistentialBoxValueInst(
getSILDebugLocation(Loc), Operand, Ty));
if (OpenedArchetypesTracker)
OpenedArchetypesTracker->registerOpenedArchetypes(I);
return I;
}

InitExistentialAddrInst *
createInitExistentialAddr(SILLocation Loc, SILValue Existential,
CanType FormalConcreteType,
Expand Down
18 changes: 18 additions & 0 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -1671,6 +1671,24 @@ visitOpenExistentialBoxInst(OpenExistentialBoxInst *Inst) {
getOpType(Inst->getType())));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::
visitOpenExistentialBoxValueInst(OpenExistentialBoxValueInst *Inst) {
// Create a new archetype for this opened existential type.
auto archetypeTy
= Inst->getType().getSwiftRValueType()->castTo<ArchetypeType>();
registerOpenedExistentialRemapping(
archetypeTy,
ArchetypeType::getOpened(archetypeTy->getOpenedExistentialType()));

getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
doPostProcess(Inst,
getBuilder().createOpenExistentialBoxValue(getOpLocation(Inst->getLoc()),
getOpValue(Inst->getOperand()),
getOpType(Inst->getType())));
}

template<typename ImplClass>
void
SILCloner<ImplClass>::visitInitExistentialAddrInst(InitExistentialAddrInst *Inst) {
Expand Down
11 changes: 11 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -4745,6 +4745,17 @@ class OpenExistentialBoxInst
SILType ty);
};

/// Given a boxed existential container, "opens" the existential by returning a
/// fresh archetype T, which also captures the (dynamic) conformances.
class OpenExistentialBoxValueInst
: public UnaryInstructionBase<ValueKind::OpenExistentialBoxValueInst>
{
friend SILBuilder;

OpenExistentialBoxValueInst(SILDebugLocation DebugLoc, SILValue operand,
SILType ty);
};

/// Given an address to an uninitialized buffer of
/// a protocol type, initializes its existential container to contain a concrete
/// value of the given type, and returns the address of the uninitialized
Expand Down
1 change: 1 addition & 0 deletions include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
INST(OpenExistentialMetatypeInst, SILInstruction, open_existential_metatype, None, DoesNotRelease)
INST(OpenExistentialBoxInst, SILInstruction, open_existential_box, MayRead, DoesNotRelease)
INST(OpenExistentialValueInst, SILInstruction, open_existential_value, MayRead, DoesNotRelease)
INST(OpenExistentialBoxValueInst, SILInstruction, open_existential_box_value, MayRead, DoesNotRelease)

// Blocks
INST(ProjectBlockStorageInst, SILInstruction, project_block_storage, None, DoesNotRelease)
Expand Down
6 changes: 6 additions & 0 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,7 @@ class IRGenSILFunction :

void visitAllocExistentialBoxInst(AllocExistentialBoxInst *i);
void visitOpenExistentialBoxInst(OpenExistentialBoxInst *i);
void visitOpenExistentialBoxValueInst(OpenExistentialBoxValueInst *i);
void visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i);
void visitDeallocExistentialBoxInst(DeallocExistentialBoxInst *i);

Expand Down Expand Up @@ -4925,6 +4926,11 @@ void IRGenSILFunction::visitOpenExistentialBoxInst(OpenExistentialBoxInst *i) {
setLoweredAddress(i, addr);
}

void IRGenSILFunction::visitOpenExistentialBoxValueInst(
OpenExistentialBoxValueInst *i) {
llvm_unreachable("unsupported instruction during IRGen");
}

void
IRGenSILFunction::visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i) {
const LoweredValue &val = getLoweredValue(i->getOperand());
Expand Down
4 changes: 4 additions & 0 deletions lib/ParseSIL/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2182,6 +2182,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
}
case ValueKind::OpenExistentialAddrInst:
case ValueKind::OpenExistentialBoxInst:
case ValueKind::OpenExistentialBoxValueInst:
case ValueKind::OpenExistentialMetatypeInst:
case ValueKind::OpenExistentialRefInst:
case ValueKind::OpenExistentialValueInst: {
Expand Down Expand Up @@ -2230,6 +2231,9 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
case ValueKind::OpenExistentialBoxInst:
ResultVal = B.createOpenExistentialBox(InstLoc, Val, Ty);
break;
case ValueKind::OpenExistentialBoxValueInst:
ResultVal = B.createOpenExistentialBoxValue(InstLoc, Val, Ty);
break;
case ValueKind::OpenExistentialValueInst:
ResultVal = B.createOpenExistentialValue(InstLoc, Val, Ty);
break;
Expand Down
3 changes: 2 additions & 1 deletion lib/SIL/SILInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1042,7 +1042,8 @@ bool SILInstruction::isTriviallyDuplicatable() const {

if (isa<OpenExistentialAddrInst>(this) || isa<OpenExistentialRefInst>(this) ||
isa<OpenExistentialMetatypeInst>(this) ||
isa<OpenExistentialValueInst>(this)) {
isa<OpenExistentialValueInst>(this) || isa<OpenExistentialBoxInst>(this) ||
isa<OpenExistentialBoxValueInst>(this)) {
// Don't know how to duplicate these properly yet. Inst.clone() per
// instruction does not work. Because the follow-up instructions need to
// reuse the same archetype uuid which would only work if we used a
Expand Down
5 changes: 5 additions & 0 deletions lib/SIL/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1777,6 +1777,11 @@ OpenExistentialBoxInst::OpenExistentialBoxInst(
: UnaryInstructionBase(DebugLoc, operand, ty) {
}

OpenExistentialBoxValueInst::OpenExistentialBoxValueInst(
SILDebugLocation DebugLoc, SILValue operand, SILType ty)
: UnaryInstructionBase(DebugLoc, operand, ty) {
}

OpenExistentialValueInst::OpenExistentialValueInst(SILDebugLocation DebugLoc,
SILValue Operand,
SILType SelfTy)
Expand Down
4 changes: 2 additions & 2 deletions lib/SIL/SILOpenedArchetypesTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ void SILOpenedArchetypesTracker::handleDeleteNotification(
/// \returns The found archetype or empty type otherwise.
CanArchetypeType swift::getOpenedArchetypeOf(const SILInstruction *I) {
if (isa<OpenExistentialAddrInst>(I) || isa<OpenExistentialRefInst>(I) ||
isa<OpenExistentialBoxInst>(I) || isa<OpenExistentialMetatypeInst>(I) ||
isa<OpenExistentialValueInst>(I)) {
isa<OpenExistentialBoxInst>(I) || isa<OpenExistentialBoxValueInst>(I) ||
isa<OpenExistentialMetatypeInst>(I) || isa<OpenExistentialValueInst>(I)) {
auto Ty = getOpenedArchetypeOf(I->getType().getSwiftRValueType());
assert(Ty && Ty->isOpenedExistential() &&
"Type should be an opened archetype");
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/SILOwnershipVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,7 @@ ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, BridgeObjectToWord)
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, CopyBlock)
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, DynamicMethod)
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, OpenExistentialBox)
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, OpenExistentialBoxValue)
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, RefTailAddr)
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, RefToRawPointer)
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, RefToUnmanaged)
Expand Down
3 changes: 3 additions & 0 deletions lib/SIL/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,9 @@ class SILPrinter : public SILVisitor<SILPrinter> {
void visitOpenExistentialBoxInst(OpenExistentialBoxInst *OI) {
*this << getIDAndType(OI->getOperand()) << " to " << OI->getType();
}
void visitOpenExistentialBoxValueInst(OpenExistentialBoxValueInst *OI) {
*this << getIDAndType(OI->getOperand()) << " to " << OI->getType();
}
void visitOpenExistentialValueInst(OpenExistentialValueInst *OI) {
*this << getIDAndType(OI->getOperand()) << " to " << OI->getType();
}
Expand Down
22 changes: 22 additions & 0 deletions lib/SIL/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2409,6 +2409,28 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
"SILFunction");
}

void checkOpenExistentialBoxValueInst(OpenExistentialBoxValueInst *OEI) {
SILType operandType = OEI->getOperand()->getType();
require(operandType.isObject(),
"open_existential_box operand must not be address");

require(operandType.canUseExistentialRepresentation(F.getModule(),
ExistentialRepresentation::Boxed),
"open_existential_box operand must be boxed existential");

CanType resultInstanceTy = OEI->getType().getSwiftRValueType();

require(!OEI->getType().isAddress(),
"open_existential_box_value result must not be an address");

auto archetype = getOpenedArchetypeOf(resultInstanceTy);
require(archetype,
"open_existential_box_value result not an opened existential archetype");
require(OpenedArchetypes.getOpenedArchetypeDef(archetype) == OEI,
"Archetype opened by open_existential_box_value should be "
"registered in SILFunction");
}

void checkOpenExistentialMetatypeInst(OpenExistentialMetatypeInst *I) {
SILType operandType = I->getOperand()->getType();
require(operandType.isObject(),
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/ValueOwnershipKindClassifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ FORWARDING_OWNERSHIP_INST(ConvertFunction)
FORWARDING_OWNERSHIP_INST(InitExistentialRef)
FORWARDING_OWNERSHIP_INST(OpenExistentialRef)
FORWARDING_OWNERSHIP_INST(OpenExistentialValue)
FORWARDING_OWNERSHIP_INST(OpenExistentialBoxValue)
FORWARDING_OWNERSHIP_INST(RefToBridgeObject)
FORWARDING_OWNERSHIP_INST(SelectValue)
FORWARDING_OWNERSHIP_INST(Struct)
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 @@ -400,6 +400,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
case ValueKind::LoadWeakInst:
case ValueKind::OpenExistentialAddrInst:
case ValueKind::OpenExistentialBoxInst:
case ValueKind::OpenExistentialBoxValueInst:
case ValueKind::OpenExistentialMetatypeInst:
case ValueKind::OpenExistentialRefInst:
case ValueKind::OpenExistentialValueInst:
Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/DeserializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
ONEOPERAND_ONETYPE_INST(OpenExistentialMetatype)
ONEOPERAND_ONETYPE_INST(OpenExistentialBox)
ONEOPERAND_ONETYPE_INST(OpenExistentialValue)
ONEOPERAND_ONETYPE_INST(OpenExistentialBoxValue)
// Conversion instructions.
ONEOPERAND_ONETYPE_INST(UncheckedRefCast)
ONEOPERAND_ONETYPE_INST(UncheckedAddrCast)
Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/SerializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
case ValueKind::OpenExistentialMetatypeInst:
case ValueKind::OpenExistentialBoxInst:
case ValueKind::OpenExistentialValueInst:
case ValueKind::OpenExistentialBoxValueInst:
case ValueKind::UncheckedRefCastInst:
case ValueKind::UncheckedAddrCastInst:
case ValueKind::UncheckedTrivialBitCastInst:
Expand Down
11 changes: 11 additions & 0 deletions test/SIL/Parser/opaque_values_parse.sil
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ bb0(%0 : $T):
return %t : $()
}

// CHECK-LABEL: sil @openExistentialBoxValue : $@convention(thin) (@in Error) -> () {
// CHECK: bb0([[ARG:%.*]] : $Error):
// CHECK: open_existential_box_value [[ARG]] : $Error to $@opened("{{.*}}") Error
// CHECK-LABEL: } // end sil function 'openExistentialBoxValue'
sil @openExistentialBoxValue : $@convention(thin) (@in Error) -> () {
bb0(%0 : $Error):
%o = open_existential_box_value %0 : $Error to $@opened("2E9EACA6-FD59-11E6-B016-685B3593C495") Error
%t = tuple ()
return %t : $()
}

// CHECK-LABEL: sil @openExistentialValue : $@convention(thin) (@in Foo) -> () {
// CHECK: bb0([[ARG:%.*]] : $Foo):
// CHECK: open_existential_value [[ARG]] : $Foo to $@opened("2E9EACA6-FD59-11E6-B016-685B3593C496") Foo
Expand Down
11 changes: 11 additions & 0 deletions test/SIL/Serialization/opaque_values_serialize.sil
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ bb0(%0 : $T):
return %t : $()
}

// CHECK-LABEL: sil @openExistentialBoxValue : $@convention(thin) (@in Error) -> () {
// CHECK: bb0([[ARG:%.*]] : $Error):
// CHECK: open_existential_box_value [[ARG]] : $Error to $@opened({{.*}}) Error
// CHECK-LABEL: } // end sil function 'openExistentialBoxValue'
sil @openExistentialBoxValue : $@convention(thin) (@in Error) -> () {
bb0(%0 : $Error):
%o = open_existential_box_value %0 : $Error to $@opened("2E9EACA6-FD59-11E6-B016-685B3593C495") Error
%t = tuple ()
return %t : $()
}

// CHECK-LABEL: sil @openExistentialValue : $@convention(thin) (@in Foo) -> () {
// CHECK: bb0([[ARG:%.*]] : $Foo):
// CHECK: open_existential_value [[ARG]] : $Foo to $@opened({{.*}}) Foo
Expand Down
2 changes: 1 addition & 1 deletion utils/sil-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
`(,(regexp-opt '("init_existential_addr" "deinit_existential_addr"
"open_existential_addr"
"init_existential_value" "deinit_existential_value"
"open_existential_value"
"open_existential_value" "open_existential_box_value"
"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 retain_value_addr release_value_addr 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_value init_existential_metatype deinit_existential_addr deinit_existential_value open_existential_addr open_existential_box open_existential_metatype init_existential_ref open_existential_ref open_existential_value skipwhite
syn keyword swiftKeyword init_existential_addr init_existential_value init_existential_metatype deinit_existential_addr deinit_existential_value open_existential_addr open_existential_box open_existential_box_value open_existential_metatype init_existential_ref open_existential_ref open_existential_value 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

0 comments on commit 4db2a46

Please sign in to comment.