From c44b23c95448530bd7def8b1e52eb3294e68b636 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 31 Jul 2023 12:08:11 -0700 Subject: [PATCH 01/10] [SIL] Doc: Tweaked load_weak comment. --- docs/SIL.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SIL.rst b/docs/SIL.rst index b15e735163183..7372e0dfefe44 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -5192,7 +5192,7 @@ weak reference count. This operation must be atomic with respect to the final ``strong_release`` on the operand heap object. It need not be atomic with respect to ``store_weak`` -operations on the same address. +or ``load_weak`` operations on the same address. store_weak `````````` From e135c5cac752c5ff25774d03aad57f4cd241e48c Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 31 Jul 2023 07:13:12 -0700 Subject: [PATCH 02/10] [SIL] Added strong_copy_weak_value. The new instruction unwraps an `@sil_weak` box and produces an owned value. It is only legal in opaque values mode and is transformed by `AddressLowering` to `load_weak`. --- docs/SIL.rst | 26 ++++- include/swift/SIL/SILBuilder.h | 98 +++++++++++-------- include/swift/SIL/SILCloner.h | 44 ++++++--- include/swift/SIL/SILInstruction.h | 12 ++- include/swift/SIL/SILNodes.def | 5 +- lib/IRGen/IRGenSIL.cpp | 36 +++++-- lib/SIL/IR/OperandOwnership.cpp | 4 +- lib/SIL/IR/SILPrinter.cpp | 7 +- lib/SIL/IR/ValueOwnership.cpp | 11 ++- lib/SIL/Parser/ParseSIL.cpp | 2 + lib/SIL/Utils/InstructionUtils.cpp | 5 +- lib/SIL/Verifier/SILVerifier.cpp | 7 ++ lib/SILGen/SILGenBuilder.cpp | 12 +++ lib/SILGen/SILGenBuilder.h | 4 + .../UtilityPasses/SerializeSILPass.cpp | 6 +- lib/SILOptimizer/Utils/SILInliner.cpp | 14 +-- lib/Serialization/DeserializeSIL.cpp | 2 + lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/SerializeSIL.cpp | 12 ++- test/SIL/Parser/opaque_values_parse.sil | 18 ++++ .../Serialization/opaque_values_serialize.sil | 16 +++ test/SIL/cloning_opaque_values.sil | 30 ++++++ 22 files changed, 266 insertions(+), 107 deletions(-) create mode 100644 test/SIL/cloning_opaque_values.sil diff --git a/docs/SIL.rst b/docs/SIL.rst index 7372e0dfefe44..a019518233e81 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -5192,7 +5192,28 @@ weak reference count. This operation must be atomic with respect to the final ``strong_release`` on the operand heap object. It need not be atomic with respect to ``store_weak`` -or ``load_weak`` operations on the same address. +or ``load_weak``/``strong_copy_weak_value`` operations on the same address. + +strong_copy_weak_value +`````````````````````` +:: + + sil-instruction ::= 'strong_copy_weak_value' sil-operand + + %1 = strong_copy_weak_value %0 : $@sil_weak Optional + // %1 will be a strong @owned value of type $Optional. + // $T must be a reference type + // $@sil_weak Optional must be address-only + +Only valid in opaque values mode. Lowered by AddressLowering to load_weak. + +If the heap object referenced by ``%0`` has not begun deallocation, increments +its strong reference count and produces the value ``Optional.some`` holding the +object. Otherwise, produces the value ``Optional.none``. + +This operation must be atomic with respect to the final ``strong_release`` on +the operand heap object. It need not be atomic with respect to ``store_weak`` +or ``load_weak``/``strong_copy_weak_value`` operations on the same address. store_weak `````````` @@ -5218,7 +5239,8 @@ currently be initialized. After the evaluation: This operation must be atomic with respect to the final ``strong_release`` on the operand (source) heap object. It need not be atomic with respect to -``store_weak`` or ``load_weak`` operations on the same address. +``store_weak`` or ``load_weak``/``strong_copy_weak_value`` operations on the +same address. load_unowned ```````````` diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index 40d0b1783d032..f3f5713094ce2 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -1061,20 +1061,28 @@ class SILBuilder { getSILDebugLocation(Loc), ArgumentsSpecification, getModule())); } -#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - Load##Name##Inst *createLoad##Name(SILLocation Loc, \ - SILValue src, \ - IsTake_t isTake) { \ - return insert(new (getModule()) \ - Load##Name##Inst(getSILDebugLocation(Loc), src, isTake)); \ - } \ - Store##Name##Inst *createStore##Name(SILLocation Loc, \ - SILValue value, \ - SILValue dest, \ - IsInitialization_t isInit) { \ - return insert(new (getModule()) \ - Store##Name##Inst(getSILDebugLocation(Loc), value, dest, isInit)); \ +#define COPYABLE_STORAGE_HELPER(Name) \ + StrongCopy##Name##ValueInst *createStrongCopy##Name##Value( \ + SILLocation Loc, SILValue operand) { \ + auto type = getFunction().getLoweredType( \ + operand->getType().getASTType().getReferenceStorageReferent()); \ + return insert(new (getModule()) StrongCopy##Name##ValueInst( \ + getSILDebugLocation(Loc), operand, type)); \ } + +#define LOADABLE_STORAGE_HELPER(Name) \ + Load##Name##Inst *createLoad##Name(SILLocation Loc, SILValue src, \ + IsTake_t isTake) { \ + return insert(new (getModule()) Load##Name##Inst(getSILDebugLocation(Loc), \ + src, isTake)); \ + } \ + Store##Name##Inst *createStore##Name(SILLocation Loc, SILValue value, \ + SILValue dest, \ + IsInitialization_t isInit) { \ + return insert(new (getModule()) Store##Name##Inst( \ + getSILDebugLocation(Loc), value, dest, isInit)); \ + } + #define LOADABLE_REF_STORAGE_HELPER(Name) \ Name##ToRefInst *create##Name##ToRef(SILLocation Loc, SILValue op, \ SILType ty) { \ @@ -1085,41 +1093,45 @@ class SILBuilder { SILType ty) { \ return insert(new (getModule()) \ RefTo##Name##Inst(getSILDebugLocation(Loc), op, ty)); \ - } \ - StrongCopy##Name##ValueInst *createStrongCopy##Name##Value( \ - SILLocation Loc, SILValue operand) { \ - auto type = getFunction().getLoweredType( \ - operand->getType().getASTType().getReferenceStorageReferent()); \ - return insert(new (getModule()) StrongCopy##Name##ValueInst( \ - getSILDebugLocation(Loc), operand, type)); \ } -#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - LOADABLE_REF_STORAGE_HELPER(Name) \ - StrongRetain##Name##Inst *createStrongRetain##Name(SILLocation Loc, \ - SILValue Operand, \ - Atomicity atomicity) { \ - return insert(new (getModule()) \ - StrongRetain##Name##Inst(getSILDebugLocation(Loc), Operand, atomicity)); \ - } \ - Name##RetainInst *create##Name##Retain(SILLocation Loc, SILValue Operand, \ - Atomicity atomicity) { \ - return insert(new (getModule()) \ - Name##RetainInst(getSILDebugLocation(Loc), Operand, atomicity)); \ - } \ - Name##ReleaseInst *create##Name##Release(SILLocation Loc, \ - SILValue Operand, \ - Atomicity atomicity) { \ - return insert(new (getModule()) \ - Name##ReleaseInst(getSILDebugLocation(Loc), Operand, atomicity)); \ - } -#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...") \ - ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, "...") -#define UNCHECKED_REF_STORAGE(Name, ...) \ +#define RETAINABLE_STORAGE_HELPER(Name) \ + StrongRetain##Name##Inst *createStrongRetain##Name( \ + SILLocation Loc, SILValue Operand, Atomicity atomicity) { \ + return insert(new (getModule()) StrongRetain##Name##Inst( \ + getSILDebugLocation(Loc), Operand, atomicity)); \ + } \ + Name##RetainInst *create##Name##Retain(SILLocation Loc, SILValue Operand, \ + Atomicity atomicity) { \ + return insert(new (getModule()) Name##RetainInst(getSILDebugLocation(Loc), \ + Operand, atomicity)); \ + } \ + Name##ReleaseInst *create##Name##Release(SILLocation Loc, SILValue Operand, \ + Atomicity atomicity) { \ + return insert(new (getModule()) Name##ReleaseInst( \ + getSILDebugLocation(Loc), Operand, atomicity)); \ + } + +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + COPYABLE_STORAGE_HELPER(Name) \ + LOADABLE_REF_STORAGE_HELPER(Name) \ + RETAINABLE_STORAGE_HELPER(Name) +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + COPYABLE_STORAGE_HELPER(Name) \ + LOADABLE_REF_STORAGE_HELPER(Name) \ + LOADABLE_STORAGE_HELPER(Name) \ + RETAINABLE_STORAGE_HELPER(Name) +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + COPYABLE_STORAGE_HELPER(Name) \ + LOADABLE_STORAGE_HELPER(Name) +#define UNCHECKED_REF_STORAGE(Name, ...) \ + COPYABLE_STORAGE_HELPER(Name) \ LOADABLE_REF_STORAGE_HELPER(Name) #include "swift/AST/ReferenceStorage.def" +#undef LOADABLE_STORAGE_HELPER #undef LOADABLE_REF_STORAGE_HELPER +#undef COPYABLE_STORAGE_HELPER +#undef RETAINABLE_STORAGE_HELPER CopyAddrInst *createCopyAddr(SILLocation Loc, SILValue srcAddr, SILValue destAddr, IsTake_t isTake, diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 05ac3044ee277..a95a801d5d8b2 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -1407,7 +1407,17 @@ SILCloner::visitDebugStepInst(DebugStepInst *Inst) { recordClonedInstruction(Inst, getBuilder().createDebugStep(Inst->getLoc())); } -#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ +#define COPYABLE_STORAGE_HELPER(Name, name) \ + template \ + void SILCloner::visitStrongCopy##Name##ValueInst( \ + StrongCopy##Name##ValueInst *Inst) { \ + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); \ + recordClonedInstruction(Inst, getBuilder().createStrongCopy##Name##Value( \ + getOpLocation(Inst->getLoc()), \ + getOpValue(Inst->getOperand()))); \ + } + +#define LOADABLE_STORAGE_HELPER(Name, name) \ template \ void SILCloner::visitLoad##Name##Inst(Load##Name##Inst *Inst) { \ getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); \ @@ -1441,17 +1451,8 @@ SILCloner::visitDebugStepInst(DebugStepInst *Inst) { Inst, getBuilder().create##Name##ToRef(getOpLocation(Inst->getLoc()), \ getOpValue(Inst->getOperand()), \ getOpType(Inst->getType()))); \ - } \ - template \ - void SILCloner::visitStrongCopy##Name##ValueInst( \ - StrongCopy##Name##ValueInst *Inst) { \ - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); \ - recordClonedInstruction(Inst, getBuilder().createStrongCopy##Name##Value( \ - getOpLocation(Inst->getLoc()), \ - getOpValue(Inst->getOperand()))); \ } -#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ - LOADABLE_REF_STORAGE_HELPER(Name, name) \ +#define RETAINABLE_STORAGE_HELPER(Name, name) \ template \ void SILCloner::visitStrongRetain##Name##Inst( \ StrongRetain##Name##Inst *Inst) { \ @@ -1478,13 +1479,26 @@ SILCloner::visitDebugStepInst(DebugStepInst *Inst) { getOpValue(Inst->getOperand()), \ Inst->getAtomicity())); \ } -#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ - NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, "...") \ - ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, "...") -#define UNCHECKED_REF_STORAGE(Name, name, ...) \ +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + COPYABLE_STORAGE_HELPER(Name, name) \ + LOADABLE_STORAGE_HELPER(Name, name) +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + COPYABLE_STORAGE_HELPER(Name, name) \ + LOADABLE_REF_STORAGE_HELPER(Name, name) \ + RETAINABLE_STORAGE_HELPER(Name, name) +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + COPYABLE_STORAGE_HELPER(Name, name) \ + LOADABLE_REF_STORAGE_HELPER(Name, name) \ + LOADABLE_STORAGE_HELPER(Name, name) \ + RETAINABLE_STORAGE_HELPER(Name, name) +#define UNCHECKED_REF_STORAGE(Name, name, ...) \ + COPYABLE_STORAGE_HELPER(Name, name) \ LOADABLE_REF_STORAGE_HELPER(Name, name) #include "swift/AST/ReferenceStorage.def" +#undef LOADABLE_STORAGE_HELPER #undef LOADABLE_REF_STORAGE_HELPER +#undef COPYABLE_STORAGE_HELPER +#undef RETAINABLE_STORAGE_HELPER template void diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 21dd870cf42e1..de0ea0d89f39a 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -8098,6 +8098,17 @@ class ExplicitCopyValueInst : UnaryInstructionBase(DebugLoc, operand, operand->getType()) {} }; +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + class StrongCopy##Name##ValueInst \ + : public UnaryInstructionBase< \ + SILInstructionKind::StrongCopy##Name##ValueInst, \ + SingleValueInstruction> { \ + friend class SILBuilder; \ + StrongCopy##Name##ValueInst(SILDebugLocation DebugLoc, SILValue operand, \ + SILType type) \ + : UnaryInstructionBase(DebugLoc, operand, \ + type.getReferenceStorageReferentType()) {} \ + }; #define UNCHECKED_REF_STORAGE(Name, ...) \ class StrongCopy##Name##ValueInst \ : public UnaryInstructionBase< \ @@ -8108,7 +8119,6 @@ class ExplicitCopyValueInst SILType type) \ : UnaryInstructionBase(DebugLoc, operand, type) {} \ }; - #define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ class StrongCopy##Name##ValueInst \ : public UnaryInstructionBase< \ diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index 65af4ca57e303..6bcb500abdcff 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -453,10 +453,7 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction) // alone by OSSA optimizations. SINGLE_VALUE_INST(ExplicitCopyValueInst, explicit_copy_value, SingleValueInstruction, None, DoesNotRelease) -#define UNCHECKED_REF_STORAGE(Name, name, ...) \ - SINGLE_VALUE_INST(StrongCopy##Name##ValueInst, strong_copy_##name##_value, \ - SingleValueInstruction, MayHaveSideEffects, DoesNotRelease) -#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ +#define REF_STORAGE(Name, name, ...) \ SINGLE_VALUE_INST(StrongCopy##Name##ValueInst, strong_copy_##name##_value, \ SingleValueInstruction, MayHaveSideEffects, DoesNotRelease) #include "swift/AST/ReferenceStorage.def" diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index f4eeb22e9b791..99aa32b39da48 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -1505,23 +1505,35 @@ class IRGenSILFunction : #define LOADABLE_REF_STORAGE_HELPER(Name) \ void visitRefTo##Name##Inst(RefTo##Name##Inst *i); \ - void visit##Name##ToRefInst(Name##ToRefInst *i); \ + void visit##Name##ToRefInst(Name##ToRefInst *i); +#define COPYABLE_STORAGE_HELPER(Name) \ void visitStrongCopy##Name##ValueInst(StrongCopy##Name##ValueInst *i); -#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - void visitLoad##Name##Inst(Load##Name##Inst *i); \ +#define LOADABLE_STORAGE_HELPER(Name) \ + void visitLoad##Name##Inst(Load##Name##Inst *i); \ void visitStore##Name##Inst(Store##Name##Inst *i); -#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - LOADABLE_REF_STORAGE_HELPER(Name) \ +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + LOADABLE_STORAGE_HELPER(Name) \ + COPYABLE_STORAGE_HELPER(Name) +#define RETAINABLE_STORAGE_HELPER(Name) \ void visitStrongRetain##Name##Inst(StrongRetain##Name##Inst *i); \ void visit##Name##RetainInst(Name##RetainInst *i); \ void visit##Name##ReleaseInst(Name##ReleaseInst *i); -#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...") \ - ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, "...") -#define UNCHECKED_REF_STORAGE(Name, ...) \ +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + LOADABLE_REF_STORAGE_HELPER(Name) \ + RETAINABLE_STORAGE_HELPER(Name) +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + LOADABLE_STORAGE_HELPER(Name) \ + COPYABLE_STORAGE_HELPER(Name) \ + LOADABLE_REF_STORAGE_HELPER(Name) \ + RETAINABLE_STORAGE_HELPER(Name) +#define UNCHECKED_REF_STORAGE(Name, ...) \ + COPYABLE_STORAGE_HELPER(Name) \ LOADABLE_REF_STORAGE_HELPER(Name) #include "swift/AST/ReferenceStorage.def" #undef LOADABLE_REF_STORAGE_HELPER +#undef LOADABLE_STORAGE_HELPER +#undef COPYABLE_STORAGE_HELPER +#undef RETAINABLE_STORAGE_HELPER }; } // end anonymous namespace @@ -5338,6 +5350,12 @@ static const ReferenceTypeInfo &getReferentTypeInfo(IRGenFunction &IGF, return cast(IGF.getTypeInfoForLowered(type)); } +void IRGenSILFunction::visitStrongCopyWeakValueInst( + swift::StrongCopyWeakValueInst *i) { + llvm::report_fatal_error( + "strong_copy_weak_value not lowered by AddressLowering!?"); +} + #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ void IRGenSILFunction::visitLoad##Name##Inst(swift::Load##Name##Inst *i) { \ Address source = getLoweredAddress(i->getOperand()); \ diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index d296b46db0bd0..1c78f2f7ff6bc 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -220,9 +220,7 @@ OPERAND_OWNERSHIP(InstantaneousUse, ClassMethod) OPERAND_OWNERSHIP(InstantaneousUse, SuperMethod) OPERAND_OWNERSHIP(InstantaneousUse, ClassifyBridgeObject) OPERAND_OWNERSHIP(InstantaneousUse, SetDeallocating) -#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - OPERAND_OWNERSHIP(InstantaneousUse, StrongCopy##Name##Value) -#define UNCHECKED_REF_STORAGE(Name, ...) \ +#define REF_STORAGE(Name, ...) \ OPERAND_OWNERSHIP(InstantaneousUse, StrongCopy##Name##Value) #include "swift/AST/ReferenceStorage.def" diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index b1caaa0ce80ef..5331a0febc95e 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2141,12 +2141,7 @@ class SILPrinter : public SILInstructionVisitor { *this << getIDAndType(I->getOperand()); } -#define UNCHECKED_REF_STORAGE(Name, ...) \ - void visitStrongCopy##Name##ValueInst(StrongCopy##Name##ValueInst *I) { \ - *this << getIDAndType(I->getOperand()); \ - } - -#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ +#define REF_STORAGE(Name, ...) \ void visitStrongCopy##Name##ValueInst(StrongCopy##Name##ValueInst *I) { \ *this << getIDAndType(I->getOperand()); \ } diff --git a/lib/SIL/IR/ValueOwnership.cpp b/lib/SIL/IR/ValueOwnership.cpp index 34db331c9c427..a9eb2c90486a2 100644 --- a/lib/SIL/IR/ValueOwnership.cpp +++ b/lib/SIL/IR/ValueOwnership.cpp @@ -49,15 +49,18 @@ class ValueOwnershipKindClassifier return OwnershipKind::OWNERSHIP; \ } -#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + CONSTANT_OWNERSHIP_INST(Owned, StrongCopy##Name##Value) \ CONSTANT_OWNERSHIP_INST(Owned, Load##Name) #define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ CONSTANT_OWNERSHIP_INST(Unowned, RefTo##Name) \ CONSTANT_OWNERSHIP_INST(Unowned, Name##ToRef) \ CONSTANT_OWNERSHIP_INST(Owned, StrongCopy##Name##Value) -#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...") \ - ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, "...") +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + CONSTANT_OWNERSHIP_INST(Owned, Load##Name) \ + CONSTANT_OWNERSHIP_INST(Unowned, RefTo##Name) \ + CONSTANT_OWNERSHIP_INST(Unowned, Name##ToRef) \ + CONSTANT_OWNERSHIP_INST(Owned, StrongCopy##Name##Value) #define UNCHECKED_REF_STORAGE(Name, ...) \ CONSTANT_OWNERSHIP_INST(None, RefTo##Name) \ CONSTANT_OWNERSHIP_INST(Unowned, Name##ToRef) \ diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 5affd663cd93f..7a3996569e23b 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -3648,6 +3648,8 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, REFCOUNTING_INSTRUCTION(RetainValueAddr) #define UNCHECKED_REF_STORAGE(Name, ...) \ UNARY_INSTRUCTION(StrongCopy##Name##Value) +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + UNARY_INSTRUCTION(StrongCopy##Name##Value) #define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ REFCOUNTING_INSTRUCTION(StrongRetain##Name) \ REFCOUNTING_INSTRUCTION(Name##Retain) \ diff --git a/lib/SIL/Utils/InstructionUtils.cpp b/lib/SIL/Utils/InstructionUtils.cpp index 72de536f4ae8c..aa1b5eab76ace 100644 --- a/lib/SIL/Utils/InstructionUtils.cpp +++ b/lib/SIL/Utils/InstructionUtils.cpp @@ -848,10 +848,7 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType) #include "swift/AST/ReferenceStorage.def" #undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE -#define UNCHECKED_REF_STORAGE(Name, ...) \ - case SILInstructionKind::StrongCopy##Name##ValueInst: \ - return RuntimeEffect::RefCounting; -#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ +#define REF_STORAGE(Name, ...) \ case SILInstructionKind::StrongCopy##Name##ValueInst: \ return RuntimeEffect::RefCounting; #include "swift/AST/ReferenceStorage.def" diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 30b94a169ca3a..f8ad81784dcb9 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -2975,6 +2975,13 @@ class SILVerifier : public SILVerifierBase { "'MoveOnly' types can only be copied in Raw SIL?!"); } + void checkStrongCopyWeakValueInst(StrongCopyWeakValueInst *I) { + require(!F.getModule().useLoweredAddresses(), + "strong_copy_weak_value is only valid in opaque values"); + require(I->getOperand()->getType().isAddressOnly(F), + "strong_copy_weak_value requires an address-only operand"); + } + void checkExplicitCopyValueInst(ExplicitCopyValueInst *I) { require(F.hasOwnership(), "explicit_copy_* is only valid in OSSA."); require(I->getOperand()->getType().isObject(), diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp index 00eceb9944099..3781cd5c2efa5 100644 --- a/lib/SILGen/SILGenBuilder.cpp +++ b/lib/SILGen/SILGenBuilder.cpp @@ -175,6 +175,18 @@ ManagedValue SILGenBuilder::createCopyValue(SILLocation loc, return SGF.emitManagedRValueWithCleanup(result, lowering); } +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + ManagedValue SILGenBuilder::createStrongCopy##Name##Value( \ + SILLocation loc, ManagedValue originalValue) { \ + assert(!SGF.useLoweredAddresses()); \ + auto ty = originalValue.getType(); \ + assert(ty.isAddressOnly(SGF.F)); \ + auto storageTy = originalValue.getType().castTo(); \ + (void)storageTy; \ + SILValue result = \ + createStrongCopy##Name##Value(loc, originalValue.getValue()); \ + return SGF.emitManagedRValueWithCleanup(result); \ + } #define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ ManagedValue SILGenBuilder::createStrongCopy##Name##Value( \ SILLocation loc, ManagedValue originalValue) { \ diff --git a/lib/SILGen/SILGenBuilder.h b/lib/SILGen/SILGenBuilder.h index 66cb0f9188ec0..0adea6a7e0739 100644 --- a/lib/SILGen/SILGenBuilder.h +++ b/lib/SILGen/SILGenBuilder.h @@ -132,6 +132,10 @@ class SILGenBuilder : public SILBuilder { /// values. ManagedValue createExplicitCopyValue(SILLocation Loc, ManagedValue operand); +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + using SILBuilder::createStrongCopy##Name##Value; \ + ManagedValue createStrongCopy##Name##Value(SILLocation loc, \ + ManagedValue originalValue); #define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ using SILBuilder::createStrongCopy##Name##Value; \ ManagedValue createStrongCopy##Name##Value(SILLocation loc, \ diff --git a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp index c269fd2955fb5..7bc687561fe4e 100644 --- a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp +++ b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp @@ -210,13 +210,9 @@ static bool hasOpaqueArchetype(TypeExpansionContext context, case SILInstructionKind::MarkUnresolvedReferenceBindingInst: case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst: case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst: -#define UNCHECKED_REF_STORAGE(Name, ...) \ - case SILInstructionKind::StrongCopy##Name##ValueInst: -#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ +#define REF_STORAGE(Name, ...) \ case SILInstructionKind::StrongCopy##Name##ValueInst: #include "swift/AST/ReferenceStorage.def" -#undef UNCHECKED_REF_STORAGE -#undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE case SILInstructionKind::UncheckedOwnershipConversionInst: case SILInstructionKind::IsUniqueInst: case SILInstructionKind::IsEscapingClosureInst: diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp index 2101fbb93e552..bf0f8cc0c8c93 100644 --- a/lib/SILOptimizer/Utils/SILInliner.cpp +++ b/lib/SILOptimizer/Utils/SILInliner.cpp @@ -1126,17 +1126,19 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) { case SILInstructionKind::Name##ToRefInst: \ case SILInstructionKind::RefTo##Name##Inst: \ case SILInstructionKind::StrongCopy##Name##ValueInst: -#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - case SILInstructionKind::Load##Name##Inst: \ - case SILInstructionKind::Store##Name##Inst: +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case SILInstructionKind::Load##Name##Inst: \ + case SILInstructionKind::Store##Name##Inst: \ + case SILInstructionKind::StrongCopy##Name##ValueInst: #define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ COMMON_ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name) \ case SILInstructionKind::Name##RetainInst: \ case SILInstructionKind::Name##ReleaseInst: \ case SILInstructionKind::StrongRetain##Name##Inst: -#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...") \ - ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, "...") +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case SILInstructionKind::Load##Name##Inst: \ + case SILInstructionKind::Store##Name##Inst: \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, "...") #define UNCHECKED_REF_STORAGE(Name, ...) \ COMMON_ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name) #include "swift/AST/ReferenceStorage.def" diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index e97c685ded1ce..367af14f2b2a2 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -2089,6 +2089,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, REFCOUNTING_INSTRUCTION(Name##Release) \ REFCOUNTING_INSTRUCTION(StrongRetain##Name) \ UNARY_INSTRUCTION(StrongCopy##Name##Value) +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + UNARY_INSTRUCTION(StrongCopy##Name##Value) #include "swift/AST/ReferenceStorage.def" REFCOUNTING_INSTRUCTION(RetainValue) REFCOUNTING_INSTRUCTION(RetainValueAddr) diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index ac160999ad3b0..dc63e1119617b 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 797; // checked_cast_br takes a formal type +const uint16_t SWIFTMODULE_VERSION_MINOR = 798; // added strong_copy_weak_value /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 629e9fe90990b..441935e6f1b04 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -1444,16 +1444,20 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { } #define UNCHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::StrongCopy##Name##ValueInst: -#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case SILInstructionKind::StrongCopy##Name##ValueInst: \ case SILInstructionKind::Load##Name##Inst: #define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::Name##RetainInst: \ case SILInstructionKind::Name##ReleaseInst: \ case SILInstructionKind::StrongRetain##Name##Inst: \ case SILInstructionKind::StrongCopy##Name##ValueInst: -#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...") \ - ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, "...") +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case SILInstructionKind::Load##Name##Inst: \ + case SILInstructionKind::Name##RetainInst: \ + case SILInstructionKind::Name##ReleaseInst: \ + case SILInstructionKind::StrongRetain##Name##Inst: \ + case SILInstructionKind::StrongCopy##Name##ValueInst: #include "swift/AST/ReferenceStorage.def" case SILInstructionKind::RetainValueInst: case SILInstructionKind::DestructureStructInst: diff --git a/test/SIL/Parser/opaque_values_parse.sil b/test/SIL/Parser/opaque_values_parse.sil index 153021a0bbb4f..3f7da2a0049e0 100644 --- a/test/SIL/Parser/opaque_values_parse.sil +++ b/test/SIL/Parser/opaque_values_parse.sil @@ -96,3 +96,21 @@ bb0(%0 : $S): return %t : $() } // CHECK-LABEL: } // end sil function 'parse_mutating' + +struct WeakBox { + weak var t: T? +} + +// Test strong_copy_weak_value parsing. + +// CHECK-LABEL: sil [ossa] @test_strong_copy_weak_value : {{.*}} { +// CHECK: bb0([[INSTANCE:%[^,]+]] : +// CHECK: [[WEAK_OPTIONAL:%[^,]+]] = struct_extract [[INSTANCE]] +// CHECK: strong_copy_weak_value [[WEAK_OPTIONAL]] +// CHECK-LABEL: } // end sil function 'test_strong_copy_weak_value' +sil [ossa] @test_strong_copy_weak_value : $@convention(thin) (@in_guaranteed WeakBox) -> @owned Optional { +bb0(%instance : @guaranteed $WeakBox): + %weak_optional = struct_extract %instance : $WeakBox, #WeakBox.t + %strong_optional = strong_copy_weak_value %weak_optional : $@sil_weak Optional + return %strong_optional : $Optional +} diff --git a/test/SIL/Serialization/opaque_values_serialize.sil b/test/SIL/Serialization/opaque_values_serialize.sil index 4b7060c97e9ac..b37aad2ef5550 100644 --- a/test/SIL/Serialization/opaque_values_serialize.sil +++ b/test/SIL/Serialization/opaque_values_serialize.sil @@ -82,3 +82,19 @@ bb0(%0 : $S): return %t : $() } // CHECK-LABEL: } // end sil function 'serialize_mutating' + +struct WeakBox { + weak var t: T? +} + +// CHECK-LABEL: sil [ossa] @test_strong_copy_weak_value : {{.*}} { +// CHECK: bb0([[INSTANCE:%[^,]+]] : +// CHECK: [[WEAK_OPTIONAL:%[^,]+]] = struct_extract [[INSTANCE]] +// CHECK: strong_copy_weak_value [[WEAK_OPTIONAL]] +// CHECK-LABEL: } // end sil function 'test_strong_copy_weak_value' +sil [ossa] @test_strong_copy_weak_value : $@convention(thin) (@in_guaranteed WeakBox) -> @owned Optional { +bb0(%instance : @guaranteed $WeakBox): + %weak_optional = struct_extract %instance : $WeakBox, #WeakBox.t + %strong_optional = strong_copy_weak_value %weak_optional : $@sil_weak Optional + return %strong_optional : $Optional +} diff --git a/test/SIL/cloning_opaque_values.sil b/test/SIL/cloning_opaque_values.sil new file mode 100644 index 0000000000000..b058744639d4f --- /dev/null +++ b/test/SIL/cloning_opaque_values.sil @@ -0,0 +1,30 @@ +// RUN: %target-sil-opt -enable-sil-verify-all -enable-sil-opaque-values -inline %s | %FileCheck %s + +// Check cloning of instructions that are only legal in opaque values mode. + +import Swift + +struct WeakBox { + weak var t: T? +} + + +// CHECK-LABEL: sil [ossa] @strong_copy_weak_value_caller : {{.*}} { +// CHECK: bb0([[INSTANCE:%[^,]+]] : +// CHECK: [[WEAK_OPTIONAL:%[^,]+]] = struct_extract [[INSTANCE]] +// CHECK: [[STRONG_OPTIONAL:%[^,]+]] = strong_copy_weak_value [[WEAK_OPTIONAL]] +// CHECK: return [[STRONG_OPTIONAL]] +// CHECK-LABEL: } // end sil function 'strong_copy_weak_value_caller' +sil [ossa] @strong_copy_weak_value_caller : $@convention(thin) (@in_guaranteed WeakBox) -> @owned Optional { +bb0(%instance : @guaranteed $WeakBox): + %callee = function_ref @strong_copy_weak_value : $@convention(thin) (@in_guaranteed WeakBox) -> @owned Optional + %retval = apply %callee(%instance) : $@convention(thin) (@in_guaranteed WeakBox) -> @owned Optional + return %retval : $Optional +} + +sil [always_inline] [ossa] @strong_copy_weak_value : $@convention(thin) (@in_guaranteed WeakBox) -> @owned Optional { +bb0(%instance : @guaranteed $WeakBox): + %weak_optional = struct_extract %instance : $WeakBox, #WeakBox.t + %strong_optional = strong_copy_weak_value %weak_optional : $@sil_weak Optional + return %strong_optional : $Optional +} From c007bae72302713e263d3bf115453778a3f17988 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 31 Jul 2023 07:22:41 -0700 Subject: [PATCH 03/10] [SIL] Added weak_copy_value. The new instruction wraps a value in a `@sil_weak` box and produces an owned value. It is only legal in opaque values mode and is transformed by `AddressLowering` to `store_weak`. --- docs/SIL.rst | 36 +++++++++++++++---- include/swift/SIL/SILBuilder.h | 10 ++++++ include/swift/SIL/SILCloner.h | 8 +++++ include/swift/SIL/SILInstruction.h | 11 ++++++ include/swift/SIL/SILNodes.def | 2 ++ lib/IRGen/IRGenSIL.cpp | 5 +++ lib/SIL/IR/OperandOwnership.cpp | 1 + lib/SIL/IR/SILPrinter.cpp | 4 +++ lib/SIL/IR/ValueOwnership.cpp | 1 + lib/SIL/Parser/ParseSIL.cpp | 1 + lib/SIL/Utils/InstructionUtils.cpp | 2 ++ lib/SIL/Verifier/SILVerifier.cpp | 7 ++++ lib/SILGen/SILGenBuilder.h | 4 +++ .../UtilityPasses/SerializeSILPass.cpp | 1 + lib/SILOptimizer/Utils/SILInliner.cpp | 1 + lib/Serialization/DeserializeSIL.cpp | 1 + lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/SerializeSIL.cpp | 1 + test/SIL/Parser/opaque_values_parse.sil | 14 ++++++++ .../Serialization/opaque_values_serialize.sil | 12 +++++++ test/SIL/cloning_opaque_values.sil | 23 ++++++++++++ 21 files changed, 140 insertions(+), 7 deletions(-) diff --git a/docs/SIL.rst b/docs/SIL.rst index a019518233e81..28afc3ab4428b 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -5191,8 +5191,9 @@ case, the strong reference count will be incremented before any changes to the weak reference count. This operation must be atomic with respect to the final ``strong_release`` on -the operand heap object. It need not be atomic with respect to ``store_weak`` -or ``load_weak``/``strong_copy_weak_value`` operations on the same address. +the operand heap object. It need not be atomic with respect to +``store_weak``/``weak_copy_value`` or ``load_weak``/``strong_copy_weak_value`` +operations on the same address. strong_copy_weak_value `````````````````````` @@ -5212,8 +5213,9 @@ its strong reference count and produces the value ``Optional.some`` holding the object. Otherwise, produces the value ``Optional.none``. This operation must be atomic with respect to the final ``strong_release`` on -the operand heap object. It need not be atomic with respect to ``store_weak`` -or ``load_weak``/``strong_copy_weak_value`` operations on the same address. +the operand heap object. It need not be atomic with respect to +``store_weak``/``weak_copy_value`` or ``load_weak``/``strong_copy_weak_value`` +operations on the same address. store_weak `````````` @@ -5239,8 +5241,30 @@ currently be initialized. After the evaluation: This operation must be atomic with respect to the final ``strong_release`` on the operand (source) heap object. It need not be atomic with respect to -``store_weak`` or ``load_weak``/``strong_copy_weak_value`` operations on the -same address. +``store_weak``/``weak_copy_value`` or ``load_weak``/``strong_copy_weak_value`` +operations on the same address. + +weak_copy_value +``````````````` +:: + + sil-instruction ::= 'weak_copy_value' sil-operand + + %1 = weak_copy_value %0 : $Optional + // %1 will be an @owned value of type $@sil_weak Optional. + // $T must be a reference type + // $@sil_weak Optional must be address-only + +Only valid in opaque values mode. Lowered by AddressLowering to store_weak. + +If ``%0`` is non-nil, produces the value ``@sil_weak Optional.some`` holding the +object and increments the weak reference count by 1. Otherwise, produces the +value ``Optional.none`` wrapped in a ``@sil_weak`` box. + +This operation must be atomic with respect to the final ``strong_release`` on +the operand (source) heap object. It need not be atomic with respect to +``store_weak``/``weak_copy_value`` or ``load_weak``/``strong_copy_weak_value`` +operations on the same address. load_unowned ```````````` diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index f3f5713094ce2..c36315fcb85ea 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -1061,6 +1061,16 @@ class SILBuilder { getSILDebugLocation(Loc), ArgumentsSpecification, getModule())); } + WeakCopyValueInst *createWeakCopyValue(SILLocation Loc, SILValue operand) { + assert(!getFunction().getModule().useLoweredAddresses()); + auto type = operand->getType() + .getReferenceStorageType(getFunction().getASTContext(), + ReferenceOwnership::Weak) + .getObjectType(); + return insert(new (getModule()) WeakCopyValueInst(getSILDebugLocation(Loc), + operand, type)); + } + #define COPYABLE_STORAGE_HELPER(Name) \ StrongCopy##Name##ValueInst *createStrongCopy##Name##Value( \ SILLocation Loc, SILValue operand) { \ diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index a95a801d5d8b2..6185f9be158dc 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -1407,6 +1407,14 @@ SILCloner::visitDebugStepInst(DebugStepInst *Inst) { recordClonedInstruction(Inst, getBuilder().createDebugStep(Inst->getLoc())); } +template +void SILCloner::visitWeakCopyValueInst(WeakCopyValueInst *Inst) { + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + recordClonedInstruction( + Inst, getBuilder().createWeakCopyValue(getOpLocation(Inst->getLoc()), + getOpValue(Inst->getOperand()))); +} + #define COPYABLE_STORAGE_HELPER(Name, name) \ template \ void SILCloner::visitStrongCopy##Name##ValueInst( \ diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index de0ea0d89f39a..4973e4f25d5e9 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -8098,6 +8098,17 @@ class ExplicitCopyValueInst : UnaryInstructionBase(DebugLoc, operand, operand->getType()) {} }; +class WeakCopyValueInst + : public UnaryInstructionBase { + friend class SILBuilder; + WeakCopyValueInst(SILDebugLocation DebugLoc, SILValue operand, SILType type) + : UnaryInstructionBase(DebugLoc, operand, type) { + assert(type.getReferenceStorageOwnership() == ReferenceOwnership::Weak); + assert(type.getReferenceStorageReferentType() == operand->getType()); + } +}; + #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ class StrongCopy##Name##ValueInst \ : public UnaryInstructionBase< \ diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index 6bcb500abdcff..513da24c7127c 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -453,6 +453,8 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction) // alone by OSSA optimizations. SINGLE_VALUE_INST(ExplicitCopyValueInst, explicit_copy_value, SingleValueInstruction, None, DoesNotRelease) + SINGLE_VALUE_INST(WeakCopyValueInst, weak_copy_value, + SingleValueInstruction, MayHaveSideEffects, DoesNotRelease) #define REF_STORAGE(Name, name, ...) \ SINGLE_VALUE_INST(StrongCopy##Name##ValueInst, strong_copy_##name##_value, \ SingleValueInstruction, MayHaveSideEffects, DoesNotRelease) diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 99aa32b39da48..1b87d3a716b55 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -1503,6 +1503,7 @@ class IRGenSILFunction : void visitHasSymbolInst(HasSymbolInst *i); + void visitWeakCopyValueInst(swift::WeakCopyValueInst *i); #define LOADABLE_REF_STORAGE_HELPER(Name) \ void visitRefTo##Name##Inst(RefTo##Name##Inst *i); \ void visit##Name##ToRefInst(Name##ToRefInst *i); @@ -5356,6 +5357,10 @@ void IRGenSILFunction::visitStrongCopyWeakValueInst( "strong_copy_weak_value not lowered by AddressLowering!?"); } +void IRGenSILFunction::visitWeakCopyValueInst(swift::WeakCopyValueInst *i) { + llvm::report_fatal_error("weak_copy_value not lowered by AddressLowering!?"); +} + #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ void IRGenSILFunction::visitLoad##Name##Inst(swift::Load##Name##Inst *i) { \ Address source = getLoweredAddress(i->getOperand()); \ diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index 1c78f2f7ff6bc..a2fda4ecbe9fa 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -220,6 +220,7 @@ OPERAND_OWNERSHIP(InstantaneousUse, ClassMethod) OPERAND_OWNERSHIP(InstantaneousUse, SuperMethod) OPERAND_OWNERSHIP(InstantaneousUse, ClassifyBridgeObject) OPERAND_OWNERSHIP(InstantaneousUse, SetDeallocating) +OPERAND_OWNERSHIP(InstantaneousUse, WeakCopyValue) #define REF_STORAGE(Name, ...) \ OPERAND_OWNERSHIP(InstantaneousUse, StrongCopy##Name##Value) #include "swift/AST/ReferenceStorage.def" diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 5331a0febc95e..7ace113169b1b 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2141,6 +2141,10 @@ class SILPrinter : public SILInstructionVisitor { *this << getIDAndType(I->getOperand()); } + void visitWeakCopyValueInst(WeakCopyValueInst *I) { + *this << getIDAndType(I->getOperand()); + } + #define REF_STORAGE(Name, ...) \ void visitStrongCopy##Name##ValueInst(StrongCopy##Name##ValueInst *I) { \ *this << getIDAndType(I->getOperand()); \ diff --git a/lib/SIL/IR/ValueOwnership.cpp b/lib/SIL/IR/ValueOwnership.cpp index a9eb2c90486a2..08774ac6523cb 100644 --- a/lib/SIL/IR/ValueOwnership.cpp +++ b/lib/SIL/IR/ValueOwnership.cpp @@ -49,6 +49,7 @@ class ValueOwnershipKindClassifier return OwnershipKind::OWNERSHIP; \ } +CONSTANT_OWNERSHIP_INST(Owned, WeakCopyValue) #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ CONSTANT_OWNERSHIP_INST(Owned, StrongCopy##Name##Value) \ CONSTANT_OWNERSHIP_INST(Owned, Load##Name) diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 7a3996569e23b..05daad56eb864 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -3646,6 +3646,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, REFCOUNTING_INSTRUCTION(RetainValue) REFCOUNTING_INSTRUCTION(ReleaseValueAddr) REFCOUNTING_INSTRUCTION(RetainValueAddr) + UNARY_INSTRUCTION(WeakCopyValue) #define UNCHECKED_REF_STORAGE(Name, ...) \ UNARY_INSTRUCTION(StrongCopy##Name##Value) #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ diff --git a/lib/SIL/Utils/InstructionUtils.cpp b/lib/SIL/Utils/InstructionUtils.cpp index aa1b5eab76ace..68eb65d7995b1 100644 --- a/lib/SIL/Utils/InstructionUtils.cpp +++ b/lib/SIL/Utils/InstructionUtils.cpp @@ -848,6 +848,8 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType) #include "swift/AST/ReferenceStorage.def" #undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE + case SILInstructionKind::WeakCopyValueInst: + return RuntimeEffect::RefCounting; #define REF_STORAGE(Name, ...) \ case SILInstructionKind::StrongCopy##Name##ValueInst: \ return RuntimeEffect::RefCounting; diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index f8ad81784dcb9..256e55582bbc3 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -2975,6 +2975,13 @@ class SILVerifier : public SILVerifierBase { "'MoveOnly' types can only be copied in Raw SIL?!"); } + void checkWeakCopyValueInst(WeakCopyValueInst *I) { + require(!F.getModule().useLoweredAddresses(), + "weak_copy_value is only valid in opaque values"); + require(I->getType().isAddressOnly(F), + "weak_copy_value must produce an address-only value"); + } + void checkStrongCopyWeakValueInst(StrongCopyWeakValueInst *I) { require(!F.getModule().useLoweredAddresses(), "strong_copy_weak_value is only valid in opaque values"); diff --git a/lib/SILGen/SILGenBuilder.h b/lib/SILGen/SILGenBuilder.h index 0adea6a7e0739..2891f7cc689e2 100644 --- a/lib/SILGen/SILGenBuilder.h +++ b/lib/SILGen/SILGenBuilder.h @@ -132,6 +132,10 @@ class SILGenBuilder : public SILBuilder { /// values. ManagedValue createExplicitCopyValue(SILLocation Loc, ManagedValue operand); + using SILBuilder::createWeakCopyValue; + + ManagedValue createWeakCopyValue(SILLocation loc, ManagedValue originalValue); + #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ using SILBuilder::createStrongCopy##Name##Value; \ ManagedValue createStrongCopy##Name##Value(SILLocation loc, \ diff --git a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp index 7bc687561fe4e..733f0957de399 100644 --- a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp +++ b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp @@ -210,6 +210,7 @@ static bool hasOpaqueArchetype(TypeExpansionContext context, case SILInstructionKind::MarkUnresolvedReferenceBindingInst: case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst: case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst: + case SILInstructionKind::WeakCopyValueInst: #define REF_STORAGE(Name, ...) \ case SILInstructionKind::StrongCopy##Name##ValueInst: #include "swift/AST/ReferenceStorage.def" diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp index bf0f8cc0c8c93..861adfd85988c 100644 --- a/lib/SILOptimizer/Utils/SILInliner.cpp +++ b/lib/SILOptimizer/Utils/SILInliner.cpp @@ -1122,6 +1122,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) { case SILInstructionKind::HopToExecutorInst: case SILInstructionKind::ExtractExecutorInst: case SILInstructionKind::HasSymbolInst: + case SILInstructionKind::WeakCopyValueInst: #define COMMON_ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name) \ case SILInstructionKind::Name##ToRefInst: \ case SILInstructionKind::RefTo##Name##Inst: \ diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 367af14f2b2a2..b2df776c4719d 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -2082,6 +2082,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, (Atomicity)Attr); \ break; + UNARY_INSTRUCTION(WeakCopyValue) #define UNCHECKED_REF_STORAGE(Name, ...) \ UNARY_INSTRUCTION(StrongCopy##Name##Value) #define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index dc63e1119617b..6d66abf9b5924 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 798; // added strong_copy_weak_value +const uint16_t SWIFTMODULE_VERSION_MINOR = 799; // added weak_copy_value /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 441935e6f1b04..07187a76c453e 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -1442,6 +1442,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { ListOfValues); break; } + case SILInstructionKind::WeakCopyValueInst: #define UNCHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::StrongCopy##Name##ValueInst: #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ diff --git a/test/SIL/Parser/opaque_values_parse.sil b/test/SIL/Parser/opaque_values_parse.sil index 3f7da2a0049e0..c196d3fee9f62 100644 --- a/test/SIL/Parser/opaque_values_parse.sil +++ b/test/SIL/Parser/opaque_values_parse.sil @@ -114,3 +114,17 @@ bb0(%instance : @guaranteed $WeakBox): %strong_optional = strong_copy_weak_value %weak_optional : $@sil_weak Optional return %strong_optional : $Optional } + +// Test weak_copy_value parsing. + +// CHECK-LABEL: sil [ossa] @test_weak_copy_value_1 : {{.*}} { +// CHECK: bb0([[VALUE:%[^,]+]] : +// CHECK: weak_copy_value [[VALUE]] +// CHECK-LABEL: } // end sil function 'test_weak_copy_value_1' +sil [ossa] @test_weak_copy_value_1 : $@convention(thin) (@owned Optional) -> @out WeakBox { +bb0(%value : @owned $Optional): + %weak_value = weak_copy_value %value : $Optional + destroy_value %value : $Optional + %retval = struct $WeakBox (%weak_value : $@sil_weak Optional) + return %retval : $WeakBox +} diff --git a/test/SIL/Serialization/opaque_values_serialize.sil b/test/SIL/Serialization/opaque_values_serialize.sil index b37aad2ef5550..104c9aa5038d8 100644 --- a/test/SIL/Serialization/opaque_values_serialize.sil +++ b/test/SIL/Serialization/opaque_values_serialize.sil @@ -98,3 +98,15 @@ bb0(%instance : @guaranteed $WeakBox): %strong_optional = strong_copy_weak_value %weak_optional : $@sil_weak Optional return %strong_optional : $Optional } + +// CHECK-LABEL: sil [ossa] @test_weak_copy_value_1 : {{.*}} { +// CHECK: bb0([[VALUE:%[^,]+]] : +// CHECK: weak_copy_value [[VALUE]] +// CHECK-LABEL: } // end sil function 'test_weak_copy_value_1' +sil [ossa] @test_weak_copy_value_1 : $@convention(thin) (@owned Optional) -> @out WeakBox { +bb0(%value : @owned $Optional): + %weak_value = weak_copy_value %value : $Optional + destroy_value %value : $Optional + %retval = struct $WeakBox (%weak_value : $@sil_weak Optional) + return %retval : $WeakBox +} diff --git a/test/SIL/cloning_opaque_values.sil b/test/SIL/cloning_opaque_values.sil index b058744639d4f..dc375f7c520a6 100644 --- a/test/SIL/cloning_opaque_values.sil +++ b/test/SIL/cloning_opaque_values.sil @@ -28,3 +28,26 @@ bb0(%instance : @guaranteed $WeakBox): %strong_optional = strong_copy_weak_value %weak_optional : $@sil_weak Optional return %strong_optional : $Optional } + +// CHECK-LABEL: sil [ossa] @weak_copy_value_caller : {{.*}} { +// CHECK: bb0([[STRONG_OPTIONAL:%[^,]+]] : +// CHECK: [[WEAK_OPTIONAL:%[^,]+]] = weak_copy_value [[STRONG_OPTIONAL]] +// CHECK: destroy_value [[STRONG_OPTIONAL]] +// CHECK: [[RETVAL:%[^,]+]] = struct $WeakBox ([[WEAK_OPTIONAL]] : +// CHECK: return [[RETVAL]] +// CHECK-LABEL: } // end sil function 'weak_copy_value_caller' +sil [ossa] @weak_copy_value_caller : $@convention(thin) (@owned Optional) -> @out WeakBox { +bb0(%value : @owned $Optional): + %callee = function_ref @weak_copy_value : $@convention(thin) (@owned Optional) -> @out WeakBox + %retval = apply %callee(%value) : $@convention(thin) (@owned Optional) -> @out WeakBox + return %retval : $WeakBox +} + +sil [always_inline] [ossa] @weak_copy_value : $@convention(thin) (@owned Optional) -> @out WeakBox { +bb0(%value : @owned $Optional): + %weak_value = weak_copy_value %value : $Optional + destroy_value %value : $Optional + %retval = struct $WeakBox (%weak_value : $@sil_weak Optional) + return %retval : $WeakBox +} + From 390d02f114927d1fea66dee79c8a950bec49b19c Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 28 Jul 2023 17:17:36 -0700 Subject: [PATCH 04/10] [AddressLowering] Handle weak copies. Lower the `strong_copy_weak_value` and `weak_copy_value` to `load_weak` and `store_weak` respectively. --- .../Mandatory/AddressLowering.cpp | 17 ++++++++++ test/SILOptimizer/address_lowering_lib.sil | 33 ++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.cpp b/lib/SILOptimizer/Mandatory/AddressLowering.cpp index 3df4f3a620b01..45d882a1ef85c 100644 --- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp +++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp @@ -3483,6 +3483,14 @@ class UseRewriter : SILInstructionVisitor { pass.deleter.forceDelete(sei); } + void visitStrongCopyWeakValueInst(StrongCopyWeakValueInst *scwvi) { + auto sourceAddr = addrMat.materializeAddress(use->get()); + SILValue value = + builder.createLoadWeak(scwvi->getLoc(), sourceAddr, IsNotTake); + scwvi->replaceAllUsesWith(value); + pass.deleter.forceDelete(scwvi); + } + // Extract from an opaque struct. void visitStructExtractInst(StructExtractInst *extractInst); @@ -4094,6 +4102,15 @@ class DefRewriter : SILInstructionVisitor { rewriteUnconditionalCheckedCastInst(uncondCheckedCast, pass); } + + void visitWeakCopyValueInst(WeakCopyValueInst *wcsvi) { + auto &storage = pass.valueStorageMap.getStorage(wcsvi); + auto destAddr = addrMat.recursivelyMaterializeStorage( + storage, /*intoPhiOperand=*/false); + + builder.createStoreWeak(wcsvi->getLoc(), wcsvi->getOperand(), destAddr, + IsInitialization); + } }; } // end anonymous namespace diff --git a/test/SILOptimizer/address_lowering_lib.sil b/test/SILOptimizer/address_lowering_lib.sil index 42938797d21a8..2379d64d29f81 100644 --- a/test/SILOptimizer/address_lowering_lib.sil +++ b/test/SILOptimizer/address_lowering_lib.sil @@ -1,4 +1,4 @@ -// RUN: %target-sil-opt -address-lowering -enable-sil-opaque-values -sil-verify-all %s | %FileCheck %s +// RUN: %target-sil-opt -address-lowering -emit-sorted-sil -enable-sil-opaque-values -sil-verify-all %s | %FileCheck %s // import Builtin import Swift @@ -29,3 +29,34 @@ bb0(%0 : @owned $Error): %ret = tuple () return %ret : $() } + +struct WeakBox { + weak var t: T? +} + +// CHECK-LABEL: sil [ossa] @test_strong_copy_weak_value : {{.*}} { +// CHECK: {{bb[0-9]+}}([[BOX_ADDR:%[^,]+]] : +// CHECK: [[VALUE_ADDR:%[^,]+]] = struct_element_addr [[BOX_ADDR]] : {{.*}}, #WeakBox.t +// CHECK: [[VALUE:%[^,]+]] = load_weak [[VALUE_ADDR]] : $*@sil_weak Optional +// CHECK: return [[VALUE]] : $Optional +// CHECK-LABEL: } // end sil function 'test_strong_copy_weak_value' +sil [ossa] @test_strong_copy_weak_value : $@convention(thin) (@in_guaranteed WeakBox) -> @owned Optional { +bb0(%instance : @guaranteed $WeakBox): + %weak_optional = struct_extract %instance : $WeakBox, #WeakBox.t + %strong_optional = strong_copy_weak_value %weak_optional : $@sil_weak Optional + return %strong_optional : $Optional +} + +// CHECK-LABEL: sil [ossa] @test_weak_copy_value_1 : {{.*}} { +// CHECK: {{bb[0-9]+}}([[RETVAL:%[^,]+]] : $*WeakBox, [[VALUE:%[^,]+]] : +// CHECK: [[VALUE_ADDR:%[^,]+]] = struct_element_addr [[RETVAL]] : {{.*}}, #WeakBox.t +// CHECK: store_weak [[VALUE]] to [init] [[VALUE_ADDR]] +// CHECK: destroy_value [[VALUE]] +// CHECK-LABEL: } // end sil function 'test_weak_copy_value_1' +sil [ossa] @test_weak_copy_value_1 : $@convention(thin) (@owned Optional) -> @out WeakBox { +bb0(%value : @owned $Optional): + %weak_value = weak_copy_value %value : $Optional + destroy_value %value : $Optional + %retval = struct $WeakBox (%weak_value : $@sil_weak Optional) + return %retval : $WeakBox +} From b616d14ff5fab11c503ed2e1168d854ac330a7e7 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 31 Jul 2023 07:23:27 -0700 Subject: [PATCH 05/10] [OpaqueValues] Emit weak copies. In opaque values mode, emit the new weak copy instructions to convert as follows: strong_copy_weak_value: `@owned $sil_weak T?` -> `@owned $T?` weak_copy_value: `@owned $T?` -> `@owned $@sil_weak T?` Doing so is necessary in opaque values mode where it is needed to deal with weak values directly rather than indirectly via `load_weak`s and `store_weak`s. --- lib/SILGen/SILGenLValue.cpp | 34 ++++++++++++++++++++++---- test/SILGen/opaque_values_silgen.swift | 19 +++++++++++++- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 0ba5fdf907b49..6aeab1555944a 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -4544,9 +4544,18 @@ ManagedValue SILGenFunction::emitConversionToSemanticRValue( switch (swiftStorageType->getOwnership()) { case ReferenceOwnership::Strong: llvm_unreachable("strong reference storage type should be impossible"); -#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - case ReferenceOwnership::Name: \ - /* Address-only storage types are handled with their underlying type. */ \ +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case ReferenceOwnership::Name: \ + if (!useLoweredAddresses()) { \ + auto refTy = src.getType(); \ + auto ty = refTy.getReferenceStorageReferentType(); \ + assert(ty); \ + assert(ty.getOptionalObjectType()); \ + (void)ty; \ + /* Copy the weak value, opening the @sil_weak box. */ \ + return B.createStrongCopy##Name##Value(loc, src); \ + } \ + /* Address-only storage types are handled with their underlying type. */ \ llvm_unreachable("address-only pointers are handled elsewhere"); #define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case ReferenceOwnership::Name: \ @@ -4827,11 +4836,26 @@ SILValue SILGenFunction::emitConversionFromSemanticValue(SILLocation loc, } auto swiftStorageType = storageType.castTo(); + if (!useLoweredAddresses() && storageType.isAddressOnly(F)) { + switch (swiftStorageType->getOwnership()) { + case ReferenceOwnership::Strong: + llvm_unreachable("strong reference storage type should be impossible"); + case ReferenceOwnership::Unmanaged: + llvm_unreachable("unimplemented"); + case ReferenceOwnership::Weak: { + auto value = B.createWeakCopyValue(loc, semanticValue); + B.emitDestroyValueOperation(loc, semanticValue); + return value; + } + case ReferenceOwnership::Unowned: + llvm_unreachable("unimplemented"); + } + } switch (swiftStorageType->getOwnership()) { case ReferenceOwnership::Strong: llvm_unreachable("strong reference storage type should be impossible"); -#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - case ReferenceOwnership::Name: \ +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case ReferenceOwnership::Name: \ llvm_unreachable("address-only types are never loadable"); #define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case ReferenceOwnership::Name: { \ diff --git a/test/SILGen/opaque_values_silgen.swift b/test/SILGen/opaque_values_silgen.swift index eadee0db3d8d6..b74b970e5049e 100644 --- a/test/SILGen/opaque_values_silgen.swift +++ b/test/SILGen/opaque_values_silgen.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-silgen -enable-sil-opaque-values -Xllvm -sil-full-demangle %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime +// RUN: %target-swift-emit-silgen -enable-sil-opaque-values -Xllvm -sil-full-demangle -primary-file %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime // Test SILGen -enable-sil-opaque-values with tests that depend on the stdlib. @@ -743,3 +743,20 @@ protocol MutatingFooable { func callMutatingFooOnInoutExistential(_ i: inout any MutatingFooable) { i.foo() } + +// CHECK-LABEL: sil {{.*}}[ossa] @$s20opaque_values_silgen7WeakBoxV1txSgvg : {{.*}} { +// CHECK: bb0([[INSTANCE:%[^,]+]] : +// CHECK: [[WEAK_OPTIONAL:%[^,]+]] = struct_extract [[INSTANCE]] +// CHECK: [[STRONG_OPTIONAL:%[^,]+]] = strong_copy_weak_value [[WEAK_OPTIONAL]] +// CHECK: return [[STRONG_OPTIONAL]] +// CHECK-LABEL: } // end sil function '$s20opaque_values_silgen7WeakBoxV1txSgvg' +// CHECK-LABEL: sil {{.*}}[ossa] @$s20opaque_values_silgen7WeakBoxV1tACyxGxSg_tcfC : {{.*}} { +// CHECK: bb0([[STRONG_OPTIONAL:%[^,]+]] : +// CHECK: [[WEAK_OPTIONAL:%[^,]+]] = weak_copy_value [[STRONG_OPTIONAL]] +// CHECK: destroy_value [[STRONG_OPTIONAL]] +// CHECK: [[INSTANCE:%[^,]+]] = struct $WeakBox ([[WEAK_OPTIONAL]] : +// CHECK: return [[INSTANCE]] +// CHECK-LABEL: } // end sil function '$s20opaque_values_silgen7WeakBoxV1tACyxGxSg_tcfC' +struct WeakBox { + weak var t: T? +} From 8cea33ad8fbffc9727f04ed9e1cfa61c30c03e54 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 8 Aug 2023 15:36:41 -0700 Subject: [PATCH 06/10] [SIL] Verifier: Disable opaque values for ref_to. The ref_to_* and *_to_ref instructions must not produce or take as their operands values of address-only type. The AddressLowering pass would trap on encountering such illegal instructions already. Enforce the invariant in the verifier. --- lib/SIL/Verifier/SILVerifier.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 256e55582bbc3..b4319e6da2779 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -2798,8 +2798,12 @@ class SILVerifier : public SILVerifierBase { requireReferenceStorageCapableValue(I->getOperand(), \ "Operand of ref_to_" #name); \ auto operandType = I->getOperand()->getType().getASTType(); \ + require(!I->getOperand()->getType().isAddressOnly(F), \ + "ref_to_" #name " may not take an address-only operand"); \ auto resultType = \ requireObjectType(Name##StorageType, I, "Result of ref_to_" #name); \ + require(!I->getType().isAddressOnly(F), \ + "ref_to_" #name " must not produce an address-only value"); \ requireSameType(resultType.getReferentType(), operandType, \ "Result of ref_to_" #name " does not have the " \ "operand's type as its referent type"); \ @@ -2807,8 +2811,12 @@ class SILVerifier : public SILVerifierBase { void check##Name##ToRefInst(Name##ToRefInst *I) { \ auto operandType = requireObjectType(Name##StorageType, I->getOperand(), \ "Operand of " #name "_to_ref"); \ + require(!I->getOperand()->getType().isAddressOnly(F), \ + #name "_to_ref may not take an address-only operand"); \ requireReferenceStorageCapableValue(I, "Result of " #name "_to_ref"); \ auto resultType = I->getType().getASTType(); \ + require(!I->getType().isAddressOnly(F), \ + #name "_to_ref may not produce an address-only value"); \ requireSameType(operandType.getReferentType(), resultType, \ "Operand of " #name "_to_ref does not have the " \ "operand's type as its referent type"); \ From 0cb3ce5f3cb96826e04170cb9d1c4053bbf83a4c Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 3 Aug 2023 06:46:15 -0700 Subject: [PATCH 07/10] [SIL] Doc: Tweaked {load,store}_unowned comment. --- docs/SIL.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/SIL.rst b/docs/SIL.rst index 28afc3ab4428b..4954b34bac33c 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -5285,7 +5285,8 @@ positive. Otherwise, traps. This operation must be atomic with respect to the final ``strong_release`` on the operand (source) heap object. It need not be atomic with respect to -``store_unowned`` or ``load_unowned`` operations on the same address. +``store_unowned`` or ``load_unowned``/``strong_copy_unowned_value`` operations +on the same address. store_unowned ````````````` @@ -5305,7 +5306,8 @@ The storage must be initialized iff ``[init]`` is not specified. This operation must be atomic with respect to the final ``strong_release`` on the operand (source) heap object. It need not be atomic with respect to -``store_unowned`` or ``load_unowned`` operations on the same address. +``store_unowned`` or ``load_unowned``/``strong_copy_unowned_value`` operations +on the same address. fix_lifetime From f938287710cbb0b5bbe1be0b7ad32c69d37f4b57 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 3 Aug 2023 06:33:21 -0700 Subject: [PATCH 08/10] [SIL] Added unowned_copy_value. --- docs/SIL.rst | 29 +++++++++++++--- include/swift/SIL/SILBuilder.h | 11 +++++++ include/swift/SIL/SILCloner.h | 9 +++++ include/swift/SIL/SILInstruction.h | 12 +++++++ include/swift/SIL/SILNodes.def | 3 ++ lib/IRGen/IRGenSIL.cpp | 7 ++++ lib/SIL/IR/OperandOwnership.cpp | 1 + lib/SIL/IR/SILPrinter.cpp | 4 +++ lib/SIL/IR/ValueOwnership.cpp | 1 + lib/SIL/Parser/ParseSIL.cpp | 1 + lib/SIL/Utils/InstructionUtils.cpp | 1 + lib/SIL/Verifier/SILVerifier.cpp | 7 ++++ .../UtilityPasses/SerializeSILPass.cpp | 1 + lib/SILOptimizer/Utils/SILInliner.cpp | 1 + lib/Serialization/DeserializeSIL.cpp | 1 + lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/SerializeSIL.cpp | 1 + test/SIL/Parser/opaque_values_parse_objc.sil | 22 +++++++++++++ .../opaque_values_serialize_objc.sil | 30 +++++++++++++++++ test/SIL/cloning_opaque_values.sil | 1 - test/SIL/cloning_opaque_values_objc.sil | 33 +++++++++++++++++++ 21 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 test/SIL/Parser/opaque_values_parse_objc.sil create mode 100644 test/SIL/Serialization/opaque_values_serialize_objc.sil create mode 100644 test/SIL/cloning_opaque_values_objc.sil diff --git a/docs/SIL.rst b/docs/SIL.rst index 4954b34bac33c..94a6b4fb027d2 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -5285,8 +5285,8 @@ positive. Otherwise, traps. This operation must be atomic with respect to the final ``strong_release`` on the operand (source) heap object. It need not be atomic with respect to -``store_unowned`` or ``load_unowned``/``strong_copy_unowned_value`` operations -on the same address. +``store_unowned``/``unowned_copy_value`` or +``load_unowned``/``strong_copy_unowned_value`` operations on the same address. store_unowned ````````````` @@ -5306,9 +5306,30 @@ The storage must be initialized iff ``[init]`` is not specified. This operation must be atomic with respect to the final ``strong_release`` on the operand (source) heap object. It need not be atomic with respect to -``store_unowned`` or ``load_unowned``/``strong_copy_unowned_value`` operations -on the same address. +``store_unowned``/``unowned_copy_value`` or +``load_unowned``/``strong_copy_unowned_value`` operations on the same address. +unowned_copy_value +`````````````````` +:: + + sil-instruction ::= 'unowned_copy_value' sil-operand + + %1 = unowned_copy_value %0 : $T + // %1 will be an @owned value of type $@sil_unowned T. + // $T must be a reference type + // $@sil_unowned T must be address-only + +Only valid in opaque values mode. Lowered by AddressLowering to store_unowned. + +Increments the unowned reference count of the object at ``%0``. + +Wraps the operand in an instance of ``@sil_unowned``. + +This operation must be atomic with respect to the final ``strong_release`` on +the operand (source) heap object. It need not be atomic with respect to +``store_unowned``/``unowned_copy_value`` or +``load_unowned``/``strong_copy_unowned_value`` operations on the same address. fix_lifetime ```````````` diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index c36315fcb85ea..f17c67a896ecf 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -1061,6 +1061,17 @@ class SILBuilder { getSILDebugLocation(Loc), ArgumentsSpecification, getModule())); } + UnownedCopyValueInst *createUnownedCopyValue(SILLocation Loc, + SILValue operand) { + assert(!getFunction().getModule().useLoweredAddresses()); + auto type = operand->getType() + .getReferenceStorageType(getFunction().getASTContext(), + ReferenceOwnership::Unowned) + .getObjectType(); + return insert(new (getModule()) UnownedCopyValueInst( + getSILDebugLocation(Loc), operand, type)); + } + WeakCopyValueInst *createWeakCopyValue(SILLocation Loc, SILValue operand) { assert(!getFunction().getModule().useLoweredAddresses()); auto type = operand->getType() diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 6185f9be158dc..4a41fa576c1c3 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -1407,6 +1407,15 @@ SILCloner::visitDebugStepInst(DebugStepInst *Inst) { recordClonedInstruction(Inst, getBuilder().createDebugStep(Inst->getLoc())); } +template +void SILCloner::visitUnownedCopyValueInst( + UnownedCopyValueInst *Inst) { + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + recordClonedInstruction( + Inst, getBuilder().createUnownedCopyValue( + getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand()))); +} + template void SILCloner::visitWeakCopyValueInst(WeakCopyValueInst *Inst) { getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 4973e4f25d5e9..552d54348b54d 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -8109,6 +8109,18 @@ class WeakCopyValueInst } }; +class UnownedCopyValueInst + : public UnaryInstructionBase { + friend class SILBuilder; + UnownedCopyValueInst(SILDebugLocation DebugLoc, SILValue operand, + SILType type) + : UnaryInstructionBase(DebugLoc, operand, type) { + assert(type.getReferenceStorageOwnership() == ReferenceOwnership::Unowned); + assert(type.getReferenceStorageReferentType() == operand->getType()); + } +}; + #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ class StrongCopy##Name##ValueInst \ : public UnaryInstructionBase< \ diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index 513da24c7127c..a803896eed50d 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -453,6 +453,9 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction) // alone by OSSA optimizations. SINGLE_VALUE_INST(ExplicitCopyValueInst, explicit_copy_value, SingleValueInstruction, None, DoesNotRelease) + // Produce a @sil_unowned value from the specified value of reference type. + SINGLE_VALUE_INST(UnownedCopyValueInst, unowned_copy_value, + SingleValueInstruction, MayHaveSideEffects, DoesNotRelease) SINGLE_VALUE_INST(WeakCopyValueInst, weak_copy_value, SingleValueInstruction, MayHaveSideEffects, DoesNotRelease) #define REF_STORAGE(Name, name, ...) \ diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 1b87d3a716b55..6bec19b3d5c77 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -1504,6 +1504,7 @@ class IRGenSILFunction : void visitHasSymbolInst(HasSymbolInst *i); void visitWeakCopyValueInst(swift::WeakCopyValueInst *i); + void visitUnownedCopyValueInst(swift::UnownedCopyValueInst *i); #define LOADABLE_REF_STORAGE_HELPER(Name) \ void visitRefTo##Name##Inst(RefTo##Name##Inst *i); \ void visit##Name##ToRefInst(Name##ToRefInst *i); @@ -5361,6 +5362,12 @@ void IRGenSILFunction::visitWeakCopyValueInst(swift::WeakCopyValueInst *i) { llvm::report_fatal_error("weak_copy_value not lowered by AddressLowering!?"); } +void IRGenSILFunction::visitUnownedCopyValueInst( + swift::UnownedCopyValueInst *i) { + llvm::report_fatal_error( + "unowned_copy_value not lowered by AddressLowering!?"); +} + #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ void IRGenSILFunction::visitLoad##Name##Inst(swift::Load##Name##Inst *i) { \ Address source = getLoweredAddress(i->getOperand()); \ diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index a2fda4ecbe9fa..7fe14a6e059a4 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -220,6 +220,7 @@ OPERAND_OWNERSHIP(InstantaneousUse, ClassMethod) OPERAND_OWNERSHIP(InstantaneousUse, SuperMethod) OPERAND_OWNERSHIP(InstantaneousUse, ClassifyBridgeObject) OPERAND_OWNERSHIP(InstantaneousUse, SetDeallocating) +OPERAND_OWNERSHIP(InstantaneousUse, UnownedCopyValue) OPERAND_OWNERSHIP(InstantaneousUse, WeakCopyValue) #define REF_STORAGE(Name, ...) \ OPERAND_OWNERSHIP(InstantaneousUse, StrongCopy##Name##Value) diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 7ace113169b1b..3aeff49e23af5 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2141,6 +2141,10 @@ class SILPrinter : public SILInstructionVisitor { *this << getIDAndType(I->getOperand()); } + void visitUnownedCopyValueInst(UnownedCopyValueInst *I) { + *this << getIDAndType(I->getOperand()); + } + void visitWeakCopyValueInst(WeakCopyValueInst *I) { *this << getIDAndType(I->getOperand()); } diff --git a/lib/SIL/IR/ValueOwnership.cpp b/lib/SIL/IR/ValueOwnership.cpp index 08774ac6523cb..5cdc0b01c15e8 100644 --- a/lib/SIL/IR/ValueOwnership.cpp +++ b/lib/SIL/IR/ValueOwnership.cpp @@ -49,6 +49,7 @@ class ValueOwnershipKindClassifier return OwnershipKind::OWNERSHIP; \ } +CONSTANT_OWNERSHIP_INST(Owned, UnownedCopyValue) CONSTANT_OWNERSHIP_INST(Owned, WeakCopyValue) #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ CONSTANT_OWNERSHIP_INST(Owned, StrongCopy##Name##Value) \ diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 05daad56eb864..6f7d7f0c2afc9 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -3646,6 +3646,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, REFCOUNTING_INSTRUCTION(RetainValue) REFCOUNTING_INSTRUCTION(ReleaseValueAddr) REFCOUNTING_INSTRUCTION(RetainValueAddr) + UNARY_INSTRUCTION(UnownedCopyValue) UNARY_INSTRUCTION(WeakCopyValue) #define UNCHECKED_REF_STORAGE(Name, ...) \ UNARY_INSTRUCTION(StrongCopy##Name##Value) diff --git a/lib/SIL/Utils/InstructionUtils.cpp b/lib/SIL/Utils/InstructionUtils.cpp index 68eb65d7995b1..577b0fb3d6448 100644 --- a/lib/SIL/Utils/InstructionUtils.cpp +++ b/lib/SIL/Utils/InstructionUtils.cpp @@ -848,6 +848,7 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType) #include "swift/AST/ReferenceStorage.def" #undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE + case SILInstructionKind::UnownedCopyValueInst: case SILInstructionKind::WeakCopyValueInst: return RuntimeEffect::RefCounting; #define REF_STORAGE(Name, ...) \ diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index b4319e6da2779..1c45435eea961 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -2983,6 +2983,13 @@ class SILVerifier : public SILVerifierBase { "'MoveOnly' types can only be copied in Raw SIL?!"); } + void checkUnownedCopyValueInst(UnownedCopyValueInst *I) { + require(!F.getModule().useLoweredAddresses(), + "unowned_copy_value is only valid in opaque values"); + require(I->getType().isAddressOnly(F), + "unowned_copy_value must produce an address-only value"); + } + void checkWeakCopyValueInst(WeakCopyValueInst *I) { require(!F.getModule().useLoweredAddresses(), "weak_copy_value is only valid in opaque values"); diff --git a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp index 733f0957de399..11de478376585 100644 --- a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp +++ b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp @@ -210,6 +210,7 @@ static bool hasOpaqueArchetype(TypeExpansionContext context, case SILInstructionKind::MarkUnresolvedReferenceBindingInst: case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst: case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst: + case SILInstructionKind::UnownedCopyValueInst: case SILInstructionKind::WeakCopyValueInst: #define REF_STORAGE(Name, ...) \ case SILInstructionKind::StrongCopy##Name##ValueInst: diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp index 861adfd85988c..030852d275bf1 100644 --- a/lib/SILOptimizer/Utils/SILInliner.cpp +++ b/lib/SILOptimizer/Utils/SILInliner.cpp @@ -1122,6 +1122,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) { case SILInstructionKind::HopToExecutorInst: case SILInstructionKind::ExtractExecutorInst: case SILInstructionKind::HasSymbolInst: + case SILInstructionKind::UnownedCopyValueInst: case SILInstructionKind::WeakCopyValueInst: #define COMMON_ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name) \ case SILInstructionKind::Name##ToRefInst: \ diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index b2df776c4719d..419a1063b131f 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -2082,6 +2082,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, (Atomicity)Attr); \ break; + UNARY_INSTRUCTION(UnownedCopyValue) UNARY_INSTRUCTION(WeakCopyValue) #define UNCHECKED_REF_STORAGE(Name, ...) \ UNARY_INSTRUCTION(StrongCopy##Name##Value) diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 6d66abf9b5924..5de33709a5961 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 799; // added weak_copy_value +const uint16_t SWIFTMODULE_VERSION_MINOR = 800; // added unowned_copy_value /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 07187a76c453e..cc2602c289f25 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -1442,6 +1442,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { ListOfValues); break; } + case SILInstructionKind::UnownedCopyValueInst: case SILInstructionKind::WeakCopyValueInst: #define UNCHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::StrongCopy##Name##ValueInst: diff --git a/test/SIL/Parser/opaque_values_parse_objc.sil b/test/SIL/Parser/opaque_values_parse_objc.sil new file mode 100644 index 0000000000000..3582b7b0df5fa --- /dev/null +++ b/test/SIL/Parser/opaque_values_parse_objc.sil @@ -0,0 +1,22 @@ +// RUN: %target-sil-opt -enable-sil-opaque-values -enable-sil-verify-all -emit-sorted-sil %s | %FileCheck %s + +// REQUIRES: objc_interop + +import Builtin +import Swift + +struct UnownedBox { + unowned var value: T +} + +// CHECK-LABEL: sil [ossa] @test_unowned_copy_value : {{.*}} { +// CHECK: bb0([[VALUE:%[^,]+]] : +// CHECK: unowned_copy_value [[VALUE]] +// CHECK-LABEL: } // end sil function 'test_unowned_copy_value' +sil [ossa] @test_unowned_copy_value : $@convention(thin) (@owned T) -> @out UnownedBox { +bb0(%owned_value : @owned $T): + %unowned_value = unowned_copy_value %owned_value : $T + destroy_value %owned_value : $T + %instance = struct $UnownedBox (%unowned_value : $@sil_unowned T) + return %instance : $UnownedBox +} diff --git a/test/SIL/Serialization/opaque_values_serialize_objc.sil b/test/SIL/Serialization/opaque_values_serialize_objc.sil new file mode 100644 index 0000000000000..d18fff44feed4 --- /dev/null +++ b/test/SIL/Serialization/opaque_values_serialize_objc.sil @@ -0,0 +1,30 @@ +// First parse this and then emit a *.sib. Then read in the *.sib, then recreate +// RUN: %empty-directory(%t) +// FIXME: sil-opt -verify is broken +// RUN: %target-sil-opt %s -enable-sil-opaque-values -emit-sib -o %t/tmp.sib -module-name opaqueval +// RUN: %target-sil-opt %t/tmp.sib -enable-sil-opaque-values -verify -o %t/tmp.2.sib -module-name opaqueval +// RUN: %target-sil-opt %t/tmp.2.sib -enable-sil-opaque-values -emit-sorted-sil -verify -module-name opaqueval | %FileCheck %s + +// REQUIRES: objc_interop + +sil_stage raw + +import Builtin +import Swift + +struct UnownedBox { + unowned var value: T +} + +// CHECK-LABEL: sil [ossa] @test_unowned_copy_value : {{.*}} { +// CHECK: bb0([[VALUE:%[^,]+]] : +// CHECK: unowned_copy_value [[VALUE]] +// CHECK-LABEL: } // end sil function 'test_unowned_copy_value' +sil [ossa] @test_unowned_copy_value : $@convention(thin) (@owned T) -> @out UnownedBox { +bb0(%owned_value : @owned $T): + %unowned_value = unowned_copy_value %owned_value : $T + destroy_value %owned_value : $T + %instance = struct $UnownedBox (%unowned_value : $@sil_unowned T) + return %instance : $UnownedBox +} + diff --git a/test/SIL/cloning_opaque_values.sil b/test/SIL/cloning_opaque_values.sil index dc375f7c520a6..04f6f35f47ce3 100644 --- a/test/SIL/cloning_opaque_values.sil +++ b/test/SIL/cloning_opaque_values.sil @@ -8,7 +8,6 @@ struct WeakBox { weak var t: T? } - // CHECK-LABEL: sil [ossa] @strong_copy_weak_value_caller : {{.*}} { // CHECK: bb0([[INSTANCE:%[^,]+]] : // CHECK: [[WEAK_OPTIONAL:%[^,]+]] = struct_extract [[INSTANCE]] diff --git a/test/SIL/cloning_opaque_values_objc.sil b/test/SIL/cloning_opaque_values_objc.sil new file mode 100644 index 0000000000000..7c0edbf05474f --- /dev/null +++ b/test/SIL/cloning_opaque_values_objc.sil @@ -0,0 +1,33 @@ +// RUN: %target-sil-opt -enable-sil-verify-all -enable-sil-opaque-values -inline %s | %FileCheck %s + +// Check cloning of instructions that are only legal in opaque values mode. + +// REQUIRES: objc_interop + +import Swift + +struct UnownedBox { + unowned var value: T +} + +// CHECK-LABEL: sil [ossa] @unowned_copy_value_caller : {{.*}} { +// CHECK: bb0([[STRONG:%[^,]+]] : +// CHECK: [[UNOWNED:%[^,]+]] = unowned_copy_value [[STRONG]] +// CHECK: destroy_value [[STRONG]] +// CHECK: [[RETVAL:%[^,]+]] = struct $UnownedBox ([[UNOWNED]] : +// CHECK: return [[RETVAL]] +// CHECK-LABEL: } // end sil function 'unowned_copy_value_caller' +sil [ossa] @unowned_copy_value_caller : $@convention(thin) (@owned T) -> @out UnownedBox { +bb0(%value : @owned $T): + %callee = function_ref @unowned_copy_value : $@convention(thin) (@owned T) -> @out UnownedBox + %retval = apply %callee(%value) : $@convention(thin) (@owned T) -> @out UnownedBox + return %retval : $UnownedBox +} + +sil [always_inline] [ossa] @unowned_copy_value : $@convention(thin) (@owned T) -> @out UnownedBox { +bb0(%owned_value : @owned $T): + %unowned_value = unowned_copy_value %owned_value : $T + destroy_value %owned_value : $T + %instance = struct $UnownedBox (%unowned_value : $@sil_unowned T) + return %instance : $UnownedBox +} From 57c7c9e7303146f088c13a858770ea4dc2aa69ef Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 31 Jul 2023 15:04:26 -0700 Subject: [PATCH 09/10] [AddressLowering] Handle unowned copies. Lower the `strong_copy_unowned_value` and `unowned_copy_value` to `load_unowned` and `store_unowned` respectively. --- .../Mandatory/AddressLowering.cpp | 17 ++++++++ test/SILOptimizer/address_lowering.sil | 1 + test/SILOptimizer/address_lowering_objc.sil | 40 +++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 test/SILOptimizer/address_lowering_objc.sil diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.cpp b/lib/SILOptimizer/Mandatory/AddressLowering.cpp index 45d882a1ef85c..de248485a4bb7 100644 --- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp +++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp @@ -3483,6 +3483,14 @@ class UseRewriter : SILInstructionVisitor { pass.deleter.forceDelete(sei); } + void visitStrongCopyUnownedValueInst(StrongCopyUnownedValueInst *scuvi) { + auto sourceAddr = addrMat.materializeAddress(use->get()); + SILValue value = + builder.createLoadUnowned(scuvi->getLoc(), sourceAddr, IsNotTake); + scuvi->replaceAllUsesWith(value); + pass.deleter.forceDelete(scuvi); + } + void visitStrongCopyWeakValueInst(StrongCopyWeakValueInst *scwvi) { auto sourceAddr = addrMat.materializeAddress(use->get()); SILValue value = @@ -4103,6 +4111,15 @@ class DefRewriter : SILInstructionVisitor { rewriteUnconditionalCheckedCastInst(uncondCheckedCast, pass); } + void visitUnownedCopyValueInst(UnownedCopyValueInst *uci) { + auto &storage = pass.valueStorageMap.getStorage(uci); + auto destAddr = addrMat.recursivelyMaterializeStorage( + storage, /*intoPhiOperand=*/false); + + builder.createStoreUnowned(uci->getLoc(), uci->getOperand(), destAddr, + IsInitialization); + } + void visitWeakCopyValueInst(WeakCopyValueInst *wcsvi) { auto &storage = pass.valueStorageMap.getStorage(wcsvi); auto destAddr = addrMat.recursivelyMaterializeStorage( diff --git a/test/SILOptimizer/address_lowering.sil b/test/SILOptimizer/address_lowering.sil index efa3d18c273e3..ae4db1dbbf52b 100644 --- a/test/SILOptimizer/address_lowering.sil +++ b/test/SILOptimizer/address_lowering.sil @@ -2720,6 +2720,7 @@ bb0(%instance : @owned $T): %retval = tuple () return %retval : $() } + // CHECK-LABEL: sil [ossa] @test_yield_1_two_values : {{.*}} { // CHECK: tuple_element_addr // CHECK: tuple_element_addr diff --git a/test/SILOptimizer/address_lowering_objc.sil b/test/SILOptimizer/address_lowering_objc.sil new file mode 100644 index 0000000000000..6f405554075d8 --- /dev/null +++ b/test/SILOptimizer/address_lowering_objc.sil @@ -0,0 +1,40 @@ +// RUN: %target-sil-opt -address-lowering -enable-sil-opaque-values -emit-sorted-sil -module-name Swift -sil-verify-all %s | %FileCheck %s + +// REQUIRES: objc_interop + +import Builtin + +typealias AnyObject = Builtin.AnyObject + +// The module name must be Swift so that declarations like Error are parsed as the correct loadable type. + +struct UnownedBox { + unowned var value: T +} + +// CHECK-LABEL: sil [ossa] @test_strong_copy_unowned_value : {{.*}} { +// CHECK: bb0([[INSTANCE_ADDR:%[^,]+]] : +// CHECK: [[FIELD_ADDR:%[^,]+]] = struct_element_addr [[INSTANCE_ADDR]] +// CHECK: [[OWNED_VALUE:%[^,]+]] = load_unowned [[FIELD_ADDR]] +// CHECK: return [[OWNED_VALUE]] +// CHECK-LABEL: } // end sil function 'test_strong_copy_unowned_value' +sil [ossa] @test_strong_copy_unowned_value : $@convention(thin) (@in_guaranteed UnownedBox) -> @owned T { +bb0(%instance : @guaranteed $UnownedBox): + %unowned_value = struct_extract %instance : $UnownedBox, #UnownedBox.value + %owned_value = strong_copy_unowned_value %unowned_value : $@sil_unowned T + return %owned_value : $T +} + +// CHECK-LABEL: sil [ossa] @test_unowned_copy_value : {{.*}} { +// CHECK: bb0([[INSTANCE_OUT:%[^,]+]] : {{.*}}, [[OWNED_VALUE:%[^,]+]] : +// CHECK: [[FIELD_ADDR:%[^,]+]] = struct_element_addr [[INSTANCE_OUT]] +// CHECK: store_unowned [[OWNED_VALUE]] to [init] [[FIELD_ADDR]] +// CHECK: destroy_value [[OWNED_VALUE]] +// CHECK-LABEL: } // end sil function 'test_unowned_copy_value' +sil [ossa] @test_unowned_copy_value : $@convention(thin) (@owned T) -> @out UnownedBox { +bb0(%owned_value : @owned $T): + %unowned_value = unowned_copy_value %owned_value : $T + destroy_value %owned_value : $T + %instance = struct $UnownedBox (%unowned_value : $@sil_unowned T) + return %instance : $UnownedBox +} From ded4d32c71a42fd77d84f414e0df4674e7830c5a Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 31 Jul 2023 13:22:01 -0700 Subject: [PATCH 10/10] [OpaqueValues] Emit unowned copies. In opaque values mode, emit the unowned copy instructions to convert as follows: strong_copy_unowned_value: `@owned $sil_unowned T` -> `@owned $T` unowned_copy_value: `@owned T` -> `@owned $sil_unowned T` Doing so is necessary in opaque values mode where it is needed to deal with unowned values directly rather than indirectly via `load_unowned`s and `store_unowned`s. --- lib/SILGen/SILGenBuilder.cpp | 3 ++- lib/SILGen/SILGenLValue.cpp | 27 ++++++++++--------- .../SILGen/opaque_values_silgen_nonobjc.swift | 25 +++++++++++++++++ test/SILGen/opaque_values_silgen_objc.swift | 23 ++++++++++++++++ 4 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 test/SILGen/opaque_values_silgen_nonobjc.swift create mode 100644 test/SILGen/opaque_values_silgen_objc.swift diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp index 3781cd5c2efa5..d256963e236d6 100644 --- a/lib/SILGen/SILGenBuilder.cpp +++ b/lib/SILGen/SILGenBuilder.cpp @@ -191,7 +191,8 @@ ManagedValue SILGenBuilder::createCopyValue(SILLocation loc, ManagedValue SILGenBuilder::createStrongCopy##Name##Value( \ SILLocation loc, ManagedValue originalValue) { \ auto ty = originalValue.getType().castTo(); \ - assert(ty->isLoadable(ResilienceExpansion::Maximal)); \ + assert(ty->isLoadable(ResilienceExpansion::Maximal) || \ + !SGF.useLoweredAddresses()); \ (void)ty; \ SILValue result = \ createStrongCopy##Name##Value(loc, originalValue.getValue()); \ diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 6aeab1555944a..b3ed211e1685f 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -4847,8 +4847,11 @@ SILValue SILGenFunction::emitConversionFromSemanticValue(SILLocation loc, B.emitDestroyValueOperation(loc, semanticValue); return value; } - case ReferenceOwnership::Unowned: - llvm_unreachable("unimplemented"); + case ReferenceOwnership::Unowned: { + auto value = B.createUnownedCopyValue(loc, semanticValue); + B.emitDestroyValueOperation(loc, semanticValue); + return value; + } } } switch (swiftStorageType->getOwnership()) { @@ -4864,16 +4867,16 @@ SILValue SILGenFunction::emitConversionFromSemanticValue(SILLocation loc, B.emitDestroyValueOperation(loc, semanticValue); \ return value; \ } -#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - case ReferenceOwnership::Name: { \ - /* For loadable types, place into a box. */ \ - auto type = storageType.castTo(); \ - assert(type->isLoadable(ResilienceExpansion::Maximal)); \ - (void) type; \ - SILValue value = B.createRefTo##Name(loc, semanticValue, storageType); \ - value = B.createCopyValue(loc, value); \ - B.emitDestroyValueOperation(loc, semanticValue); \ - return value; \ +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case ReferenceOwnership::Name: { \ + /* For loadable types, place into a box. */ \ + auto type = storageType.castTo(); \ + assert(type->isLoadable(ResilienceExpansion::Maximal)); \ + (void)type; \ + SILValue value = B.createRefTo##Name(loc, semanticValue, storageType); \ + value = B.createCopyValue(loc, value); \ + B.emitDestroyValueOperation(loc, semanticValue); \ + return value; \ } #define UNCHECKED_REF_STORAGE(Name, ...) \ case ReferenceOwnership::Name: { \ diff --git a/test/SILGen/opaque_values_silgen_nonobjc.swift b/test/SILGen/opaque_values_silgen_nonobjc.swift new file mode 100644 index 0000000000000..3bba0ef315665 --- /dev/null +++ b/test/SILGen/opaque_values_silgen_nonobjc.swift @@ -0,0 +1,25 @@ +// RUN: %target-swift-emit-silgen -enable-sil-opaque-values -Xllvm -sil-full-demangle -disable-objc-interop -primary-file %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime + +// Test SILGen -enable-sil-opaque-values with tests that depend on the stdlib and objc interop. + +// REQUIRES: objc_interop + +// CHECK-LABEL: sil {{.*}}[ossa] @$s28opaque_values_silgen_nonobjc13UnownedVarBoxV5valuexvg : {{.*}} { +// CHECK: bb0([[INSTANCE:%[^,]+]] : +// CHECK: [[UNOWNED_VALUE:%[^,]+]] = struct_extract [[INSTANCE]] +// CHECK: [[STRONG_VALUE:%[^,]+]] = strong_copy_unowned_value [[UNOWNED_VALUE]] +// CHECK: return [[STRONG_VALUE]] +// CHECK-LABEL: } // end sil function '$s28opaque_values_silgen_nonobjc13UnownedVarBoxV5valuexvg' +// CHECK-LABEL: sil {{.*}}[ossa] @$s28opaque_values_silgen_nonobjc13UnownedVarBoxV5valueACyxGx_tcfC : {{.*}} { +// CHECK: bb0([[STRONG_VALUE:%[^,]+]] : +// CHECK: [[WRAPPED_IN_UNOWNED_TYPE:%[^,]+]] = ref_to_unowned [[STRONG_VALUE]] +// CHECK: [[UNOWNED_VALUE:%[^,]+]] = copy_value [[WRAPPED_IN_UNOWNED_TYPE]] +// CHECK: destroy_value [[STRONG_VALUE]] +// CHECK: [[RETVAL:%[^,]+]] = struct $UnownedVarBox ([[UNOWNED_VALUE]] : $@sil_unowned T) +// CHECK: return [[RETVAL]] +// CHECK-LABEL: } // end sil function '$s28opaque_values_silgen_nonobjc13UnownedVarBoxV5valueACyxGx_tcfC' +struct UnownedVarBox { + unowned var value: T +} + + diff --git a/test/SILGen/opaque_values_silgen_objc.swift b/test/SILGen/opaque_values_silgen_objc.swift new file mode 100644 index 0000000000000..49b02f2d05fdc --- /dev/null +++ b/test/SILGen/opaque_values_silgen_objc.swift @@ -0,0 +1,23 @@ +// RUN: %target-swift-emit-silgen -enable-sil-opaque-values -Xllvm -sil-full-demangle -primary-file %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime + +// Test SILGen -enable-sil-opaque-values with tests that depend on the stdlib and objc interop. + +// REQUIRES: objc_interop + +// CHECK-LABEL: sil {{.*}}[ossa] @$s25opaque_values_silgen_objc10UnownedBoxV5valuexvg : {{.*}} { +// CHECK: bb0([[INSTANCE:%[^,]+]] : +// CHECK: [[UNOWNED_VALUE:%[^,]+]] = struct_extract [[INSTANCE]] +// CHECK: [[STRONG_VALUE:%[^,]+]] = strong_copy_unowned_value [[UNOWNED_VALUE]] +// CHECK: return [[STRONG_VALUE]] +// CHECK-LABEL: } // end sil function '$s25opaque_values_silgen_objc10UnownedBoxV5valuexvg' +// CHECK-LABEL: sil {{.*}}[ossa] @$s25opaque_values_silgen_objc10UnownedBoxV5valueACyxGx_tcfC : {{.*}} { +// CHECK: bb0([[STRONG_VALUE:%[^,]+]] : +// CHECK: [[UNOWNED_VALUE:%[^,]+]] = unowned_copy_value [[STRONG_VALUE]] +// CHECK: destroy_value [[STRONG_VALUE]] +// CHECK: [[RETVAL:%[^,]+]] = struct $UnownedBox ([[UNOWNED_VALUE]] : $@sil_unowned T) +// CHECK: return [[RETVAL]] +// CHECK-LABEL: } // end sil function '$s25opaque_values_silgen_objc10UnownedBoxV5valueACyxGx_tcfC' +struct UnownedBox { + unowned var value: T +} +