Skip to content

Commit 4db2a46

Browse files
committed
Add SIL instruction: open_existential_box_value.
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.
1 parent f657ad2 commit 4db2a46

21 files changed

+129
-5
lines changed

docs/SIL.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3859,6 +3859,7 @@ container may use one of several representations:
38593859
* `alloc_existential_box`_
38603860
* `project_existential_box`_
38613861
* `open_existential_box`_
3862+
* `open_existential_box_value`_
38623863
* `dealloc_existential_box`_
38633864

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

4122+
open_existential_box_value
4123+
``````````````````````````
4124+
::
4125+
4126+
sil-instruction ::= 'open_existential_box_value' sil-operand 'to' sil-type
4127+
4128+
%1 = open_existential_box_value %0 : $P to $@opened P
4129+
// %0 must be a value of boxed protocol or protocol composition type $P
4130+
// %@opened P must be a unique archetype that refers to an opened
4131+
// existential type P
4132+
// %1 will be of type $@opened P
4133+
4134+
Projects the value inside a boxed existential container, and uses the enclosed
4135+
type and protocol conformance metadata to bind the opened archetype ``$@opened
4136+
P``.
4137+
41214138
dealloc_existential_box
41224139
```````````````````````
41234140
::

include/swift/SIL/SILBuilder.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,15 @@ class SILBuilder {
12261226
return I;
12271227
}
12281228

1229+
OpenExistentialBoxValueInst *
1230+
createOpenExistentialBoxValue(SILLocation Loc, SILValue Operand, SILType Ty) {
1231+
auto *I = insert(new (F.getModule()) OpenExistentialBoxValueInst(
1232+
getSILDebugLocation(Loc), Operand, Ty));
1233+
if (OpenedArchetypesTracker)
1234+
OpenedArchetypesTracker->registerOpenedArchetypes(I);
1235+
return I;
1236+
}
1237+
12291238
InitExistentialAddrInst *
12301239
createInitExistentialAddr(SILLocation Loc, SILValue Existential,
12311240
CanType FormalConcreteType,

include/swift/SIL/SILCloner.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,24 @@ visitOpenExistentialBoxInst(OpenExistentialBoxInst *Inst) {
16711671
getOpType(Inst->getType())));
16721672
}
16731673

1674+
template<typename ImplClass>
1675+
void
1676+
SILCloner<ImplClass>::
1677+
visitOpenExistentialBoxValueInst(OpenExistentialBoxValueInst *Inst) {
1678+
// Create a new archetype for this opened existential type.
1679+
auto archetypeTy
1680+
= Inst->getType().getSwiftRValueType()->castTo<ArchetypeType>();
1681+
registerOpenedExistentialRemapping(
1682+
archetypeTy,
1683+
ArchetypeType::getOpened(archetypeTy->getOpenedExistentialType()));
1684+
1685+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1686+
doPostProcess(Inst,
1687+
getBuilder().createOpenExistentialBoxValue(getOpLocation(Inst->getLoc()),
1688+
getOpValue(Inst->getOperand()),
1689+
getOpType(Inst->getType())));
1690+
}
1691+
16741692
template<typename ImplClass>
16751693
void
16761694
SILCloner<ImplClass>::visitInitExistentialAddrInst(InitExistentialAddrInst *Inst) {

include/swift/SIL/SILInstruction.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4745,6 +4745,17 @@ class OpenExistentialBoxInst
47454745
SILType ty);
47464746
};
47474747

4748+
/// Given a boxed existential container, "opens" the existential by returning a
4749+
/// fresh archetype T, which also captures the (dynamic) conformances.
4750+
class OpenExistentialBoxValueInst
4751+
: public UnaryInstructionBase<ValueKind::OpenExistentialBoxValueInst>
4752+
{
4753+
friend SILBuilder;
4754+
4755+
OpenExistentialBoxValueInst(SILDebugLocation DebugLoc, SILValue operand,
4756+
SILType ty);
4757+
};
4758+
47484759
/// Given an address to an uninitialized buffer of
47494760
/// a protocol type, initializes its existential container to contain a concrete
47504761
/// value of the given type, and returns the address of the uninitialized

include/swift/SIL/SILNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
245245
INST(OpenExistentialMetatypeInst, SILInstruction, open_existential_metatype, None, DoesNotRelease)
246246
INST(OpenExistentialBoxInst, SILInstruction, open_existential_box, MayRead, DoesNotRelease)
247247
INST(OpenExistentialValueInst, SILInstruction, open_existential_value, MayRead, DoesNotRelease)
248+
INST(OpenExistentialBoxValueInst, SILInstruction, open_existential_box_value, MayRead, DoesNotRelease)
248249

249250
// Blocks
250251
INST(ProjectBlockStorageInst, SILInstruction, project_block_storage, None, DoesNotRelease)

lib/IRGen/IRGenSIL.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,7 @@ class IRGenSILFunction :
942942

943943
void visitAllocExistentialBoxInst(AllocExistentialBoxInst *i);
944944
void visitOpenExistentialBoxInst(OpenExistentialBoxInst *i);
945+
void visitOpenExistentialBoxValueInst(OpenExistentialBoxValueInst *i);
945946
void visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i);
946947
void visitDeallocExistentialBoxInst(DeallocExistentialBoxInst *i);
947948

@@ -4925,6 +4926,11 @@ void IRGenSILFunction::visitOpenExistentialBoxInst(OpenExistentialBoxInst *i) {
49254926
setLoweredAddress(i, addr);
49264927
}
49274928

4929+
void IRGenSILFunction::visitOpenExistentialBoxValueInst(
4930+
OpenExistentialBoxValueInst *i) {
4931+
llvm_unreachable("unsupported instruction during IRGen");
4932+
}
4933+
49284934
void
49294935
IRGenSILFunction::visitProjectExistentialBoxInst(ProjectExistentialBoxInst *i) {
49304936
const LoweredValue &val = getLoweredValue(i->getOperand());

lib/ParseSIL/ParseSIL.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2182,6 +2182,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
21822182
}
21832183
case ValueKind::OpenExistentialAddrInst:
21842184
case ValueKind::OpenExistentialBoxInst:
2185+
case ValueKind::OpenExistentialBoxValueInst:
21852186
case ValueKind::OpenExistentialMetatypeInst:
21862187
case ValueKind::OpenExistentialRefInst:
21872188
case ValueKind::OpenExistentialValueInst: {
@@ -2230,6 +2231,9 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) {
22302231
case ValueKind::OpenExistentialBoxInst:
22312232
ResultVal = B.createOpenExistentialBox(InstLoc, Val, Ty);
22322233
break;
2234+
case ValueKind::OpenExistentialBoxValueInst:
2235+
ResultVal = B.createOpenExistentialBoxValue(InstLoc, Val, Ty);
2236+
break;
22332237
case ValueKind::OpenExistentialValueInst:
22342238
ResultVal = B.createOpenExistentialValue(InstLoc, Val, Ty);
22352239
break;

lib/SIL/SILInstruction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1042,7 +1042,8 @@ bool SILInstruction::isTriviallyDuplicatable() const {
10421042

10431043
if (isa<OpenExistentialAddrInst>(this) || isa<OpenExistentialRefInst>(this) ||
10441044
isa<OpenExistentialMetatypeInst>(this) ||
1045-
isa<OpenExistentialValueInst>(this)) {
1045+
isa<OpenExistentialValueInst>(this) || isa<OpenExistentialBoxInst>(this) ||
1046+
isa<OpenExistentialBoxValueInst>(this)) {
10461047
// Don't know how to duplicate these properly yet. Inst.clone() per
10471048
// instruction does not work. Because the follow-up instructions need to
10481049
// reuse the same archetype uuid which would only work if we used a

lib/SIL/SILInstructions.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,6 +1777,11 @@ OpenExistentialBoxInst::OpenExistentialBoxInst(
17771777
: UnaryInstructionBase(DebugLoc, operand, ty) {
17781778
}
17791779

1780+
OpenExistentialBoxValueInst::OpenExistentialBoxValueInst(
1781+
SILDebugLocation DebugLoc, SILValue operand, SILType ty)
1782+
: UnaryInstructionBase(DebugLoc, operand, ty) {
1783+
}
1784+
17801785
OpenExistentialValueInst::OpenExistentialValueInst(SILDebugLocation DebugLoc,
17811786
SILValue Operand,
17821787
SILType SelfTy)

lib/SIL/SILOpenedArchetypesTracker.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ void SILOpenedArchetypesTracker::handleDeleteNotification(
138138
/// \returns The found archetype or empty type otherwise.
139139
CanArchetypeType swift::getOpenedArchetypeOf(const SILInstruction *I) {
140140
if (isa<OpenExistentialAddrInst>(I) || isa<OpenExistentialRefInst>(I) ||
141-
isa<OpenExistentialBoxInst>(I) || isa<OpenExistentialMetatypeInst>(I) ||
142-
isa<OpenExistentialValueInst>(I)) {
141+
isa<OpenExistentialBoxInst>(I) || isa<OpenExistentialBoxValueInst>(I) ||
142+
isa<OpenExistentialMetatypeInst>(I) || isa<OpenExistentialValueInst>(I)) {
143143
auto Ty = getOpenedArchetypeOf(I->getType().getSwiftRValueType());
144144
assert(Ty && Ty->isOpenedExistential() &&
145145
"Type should be an opened archetype");

lib/SIL/SILOwnershipVerifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,7 @@ ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, BridgeObjectToWord)
585585
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, CopyBlock)
586586
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, DynamicMethod)
587587
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, OpenExistentialBox)
588+
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, OpenExistentialBoxValue)
588589
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, RefTailAddr)
589590
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, RefToRawPointer)
590591
ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP(false, RefToUnmanaged)

lib/SIL/SILPrinter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,9 @@ class SILPrinter : public SILVisitor<SILPrinter> {
15251525
void visitOpenExistentialBoxInst(OpenExistentialBoxInst *OI) {
15261526
*this << getIDAndType(OI->getOperand()) << " to " << OI->getType();
15271527
}
1528+
void visitOpenExistentialBoxValueInst(OpenExistentialBoxValueInst *OI) {
1529+
*this << getIDAndType(OI->getOperand()) << " to " << OI->getType();
1530+
}
15281531
void visitOpenExistentialValueInst(OpenExistentialValueInst *OI) {
15291532
*this << getIDAndType(OI->getOperand()) << " to " << OI->getType();
15301533
}

lib/SIL/SILVerifier.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2409,6 +2409,28 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
24092409
"SILFunction");
24102410
}
24112411

2412+
void checkOpenExistentialBoxValueInst(OpenExistentialBoxValueInst *OEI) {
2413+
SILType operandType = OEI->getOperand()->getType();
2414+
require(operandType.isObject(),
2415+
"open_existential_box operand must not be address");
2416+
2417+
require(operandType.canUseExistentialRepresentation(F.getModule(),
2418+
ExistentialRepresentation::Boxed),
2419+
"open_existential_box operand must be boxed existential");
2420+
2421+
CanType resultInstanceTy = OEI->getType().getSwiftRValueType();
2422+
2423+
require(!OEI->getType().isAddress(),
2424+
"open_existential_box_value result must not be an address");
2425+
2426+
auto archetype = getOpenedArchetypeOf(resultInstanceTy);
2427+
require(archetype,
2428+
"open_existential_box_value result not an opened existential archetype");
2429+
require(OpenedArchetypes.getOpenedArchetypeDef(archetype) == OEI,
2430+
"Archetype opened by open_existential_box_value should be "
2431+
"registered in SILFunction");
2432+
}
2433+
24122434
void checkOpenExistentialMetatypeInst(OpenExistentialMetatypeInst *I) {
24132435
SILType operandType = I->getOperand()->getType();
24142436
require(operandType.isObject(),

lib/SIL/ValueOwnershipKindClassifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ FORWARDING_OWNERSHIP_INST(ConvertFunction)
269269
FORWARDING_OWNERSHIP_INST(InitExistentialRef)
270270
FORWARDING_OWNERSHIP_INST(OpenExistentialRef)
271271
FORWARDING_OWNERSHIP_INST(OpenExistentialValue)
272+
FORWARDING_OWNERSHIP_INST(OpenExistentialBoxValue)
272273
FORWARDING_OWNERSHIP_INST(RefToBridgeObject)
273274
FORWARDING_OWNERSHIP_INST(SelectValue)
274275
FORWARDING_OWNERSHIP_INST(Struct)

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
400400
case ValueKind::LoadWeakInst:
401401
case ValueKind::OpenExistentialAddrInst:
402402
case ValueKind::OpenExistentialBoxInst:
403+
case ValueKind::OpenExistentialBoxValueInst:
403404
case ValueKind::OpenExistentialMetatypeInst:
404405
case ValueKind::OpenExistentialRefInst:
405406
case ValueKind::OpenExistentialValueInst:

lib/Serialization/DeserializeSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
889889
ONEOPERAND_ONETYPE_INST(OpenExistentialMetatype)
890890
ONEOPERAND_ONETYPE_INST(OpenExistentialBox)
891891
ONEOPERAND_ONETYPE_INST(OpenExistentialValue)
892+
ONEOPERAND_ONETYPE_INST(OpenExistentialBoxValue)
892893
// Conversion instructions.
893894
ONEOPERAND_ONETYPE_INST(UncheckedRefCast)
894895
ONEOPERAND_ONETYPE_INST(UncheckedAddrCast)

lib/Serialization/SerializeSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
12571257
case ValueKind::OpenExistentialMetatypeInst:
12581258
case ValueKind::OpenExistentialBoxInst:
12591259
case ValueKind::OpenExistentialValueInst:
1260+
case ValueKind::OpenExistentialBoxValueInst:
12601261
case ValueKind::UncheckedRefCastInst:
12611262
case ValueKind::UncheckedAddrCastInst:
12621263
case ValueKind::UncheckedTrivialBitCastInst:

test/SIL/Parser/opaque_values_parse.sil

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ bb0(%0 : $T):
5757
return %t : $()
5858
}
5959

60+
// CHECK-LABEL: sil @openExistentialBoxValue : $@convention(thin) (@in Error) -> () {
61+
// CHECK: bb0([[ARG:%.*]] : $Error):
62+
// CHECK: open_existential_box_value [[ARG]] : $Error to $@opened("{{.*}}") Error
63+
// CHECK-LABEL: } // end sil function 'openExistentialBoxValue'
64+
sil @openExistentialBoxValue : $@convention(thin) (@in Error) -> () {
65+
bb0(%0 : $Error):
66+
%o = open_existential_box_value %0 : $Error to $@opened("2E9EACA6-FD59-11E6-B016-685B3593C495") Error
67+
%t = tuple ()
68+
return %t : $()
69+
}
70+
6071
// CHECK-LABEL: sil @openExistentialValue : $@convention(thin) (@in Foo) -> () {
6172
// CHECK: bb0([[ARG:%.*]] : $Foo):
6273
// CHECK: open_existential_value [[ARG]] : $Foo to $@opened("2E9EACA6-FD59-11E6-B016-685B3593C496") Foo

test/SIL/Serialization/opaque_values_serialize.sil

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ bb0(%0 : $T):
6363
return %t : $()
6464
}
6565

66+
// CHECK-LABEL: sil @openExistentialBoxValue : $@convention(thin) (@in Error) -> () {
67+
// CHECK: bb0([[ARG:%.*]] : $Error):
68+
// CHECK: open_existential_box_value [[ARG]] : $Error to $@opened({{.*}}) Error
69+
// CHECK-LABEL: } // end sil function 'openExistentialBoxValue'
70+
sil @openExistentialBoxValue : $@convention(thin) (@in Error) -> () {
71+
bb0(%0 : $Error):
72+
%o = open_existential_box_value %0 : $Error to $@opened("2E9EACA6-FD59-11E6-B016-685B3593C495") Error
73+
%t = tuple ()
74+
return %t : $()
75+
}
76+
6677
// CHECK-LABEL: sil @openExistentialValue : $@convention(thin) (@in Foo) -> () {
6778
// CHECK: bb0([[ARG:%.*]] : $Foo):
6879
// CHECK: open_existential_value [[ARG]] : $Foo to $@opened({{.*}}) Foo

utils/sil-mode.el

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@
133133
`(,(regexp-opt '("init_existential_addr" "deinit_existential_addr"
134134
"open_existential_addr"
135135
"init_existential_value" "deinit_existential_value"
136-
"open_existential_value"
136+
"open_existential_value" "open_existential_box_value"
137137
"alloc_existential_box" "project_existential_box"
138138
"open_existential_box" "dealloc_existential_box"
139139
"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 retain_value_addr release_value_addr 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_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
39+
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
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)