diff --git a/docs/SIL.rst b/docs/SIL.rst index dbec42f0d60fb..67b6713d787dc 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -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 @@ -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 ``````````````````````` :: diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index cd2eb978a7407..9da1de0aec104 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -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, diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index bf94d647a595a..38785b0c9ca1f 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -1671,6 +1671,24 @@ visitOpenExistentialBoxInst(OpenExistentialBoxInst *Inst) { getOpType(Inst->getType()))); } +template +void +SILCloner:: +visitOpenExistentialBoxValueInst(OpenExistentialBoxValueInst *Inst) { + // Create a new archetype for this opened existential type. + auto archetypeTy + = Inst->getType().getSwiftRValueType()->castTo(); + 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 void SILCloner::visitInitExistentialAddrInst(InitExistentialAddrInst *Inst) { diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 20111027ff58a..f5d07aac208bc 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -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 +{ + 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 diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index 0a552ffb98fce..f00b961552af5 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -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) diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 35cfdd8c06086..a81c189dfc24c 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -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); @@ -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()); diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index ea258ff8913c2..b0f31a966a101 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -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: { @@ -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; diff --git a/lib/SIL/SILInstruction.cpp b/lib/SIL/SILInstruction.cpp index 93819ef8c9efc..074705fa17a33 100644 --- a/lib/SIL/SILInstruction.cpp +++ b/lib/SIL/SILInstruction.cpp @@ -1042,7 +1042,8 @@ bool SILInstruction::isTriviallyDuplicatable() const { if (isa(this) || isa(this) || isa(this) || - isa(this)) { + isa(this) || isa(this) || + isa(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 diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp index a943748c0ced1..223010aa5fce0 100644 --- a/lib/SIL/SILInstructions.cpp +++ b/lib/SIL/SILInstructions.cpp @@ -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) diff --git a/lib/SIL/SILOpenedArchetypesTracker.cpp b/lib/SIL/SILOpenedArchetypesTracker.cpp index 5cccf64ef9a05..77cead09433bd 100644 --- a/lib/SIL/SILOpenedArchetypesTracker.cpp +++ b/lib/SIL/SILOpenedArchetypesTracker.cpp @@ -138,8 +138,8 @@ void SILOpenedArchetypesTracker::handleDeleteNotification( /// \returns The found archetype or empty type otherwise. CanArchetypeType swift::getOpenedArchetypeOf(const SILInstruction *I) { if (isa(I) || isa(I) || - isa(I) || isa(I) || - isa(I)) { + isa(I) || isa(I) || + isa(I) || isa(I)) { auto Ty = getOpenedArchetypeOf(I->getType().getSwiftRValueType()); assert(Ty && Ty->isOpenedExistential() && "Type should be an opened archetype"); diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp index fc6089776c366..482a5c1617f2b 100644 --- a/lib/SIL/SILOwnershipVerifier.cpp +++ b/lib/SIL/SILOwnershipVerifier.cpp @@ -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) diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp index 474cbd1a3cd41..51feda5bf7c3f 100644 --- a/lib/SIL/SILPrinter.cpp +++ b/lib/SIL/SILPrinter.cpp @@ -1525,6 +1525,9 @@ class SILPrinter : public SILVisitor { 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(); } diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index 5457b24c79f3c..e3acfc5b57d7a 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -2409,6 +2409,28 @@ class SILVerifier : public SILVerifierBase { "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(), diff --git a/lib/SIL/ValueOwnershipKindClassifier.cpp b/lib/SIL/ValueOwnershipKindClassifier.cpp index 8a9b7a09ac0a9..db49396a817f0 100644 --- a/lib/SIL/ValueOwnershipKindClassifier.cpp +++ b/lib/SIL/ValueOwnershipKindClassifier.cpp @@ -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) diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp index af61d8621b6d5..6ed71a2ba2094 100644 --- a/lib/SILOptimizer/Utils/SILInliner.cpp +++ b/lib/SILOptimizer/Utils/SILInliner.cpp @@ -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: diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index a341b09127459..e699fe118b19d 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -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) diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index b1630806d3aab..576d2a551954d 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -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: diff --git a/test/SIL/Parser/opaque_values_parse.sil b/test/SIL/Parser/opaque_values_parse.sil index f06eb3e8888c0..cb7b20410f9f5 100644 --- a/test/SIL/Parser/opaque_values_parse.sil +++ b/test/SIL/Parser/opaque_values_parse.sil @@ -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 diff --git a/test/SIL/Serialization/opaque_values_serialize.sil b/test/SIL/Serialization/opaque_values_serialize.sil index 63c3ac242f640..a0f8f5c9740aa 100644 --- a/test/SIL/Serialization/opaque_values_serialize.sil +++ b/test/SIL/Serialization/opaque_values_serialize.sil @@ -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 diff --git a/utils/sil-mode.el b/utils/sil-mode.el index 735a44d2b57c9..a14f807eba16d 100644 --- a/utils/sil-mode.el +++ b/utils/sil-mode.el @@ -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" diff --git a/utils/vim/syntax/sil.vim b/utils/vim/syntax/sil.vim index 6dc67b370f578..76e39180192e9 100644 --- a/utils/vim/syntax/sil.vim +++ b/utils/vim/syntax/sil.vim @@ -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