Skip to content

[SIL] Represent copies to @sil_unowned values. #67722

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 73 additions & 4 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5191,7 +5191,30 @@ 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``
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
``````````````````````
::

sil-instruction ::= 'strong_copy_weak_value' sil-operand

%1 = strong_copy_weak_value %0 : $@sil_weak Optional<T>
// %1 will be a strong @owned value of type $Optional<T>.
// $T must be a reference type
// $@sil_weak Optional<T> 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``/``weak_copy_value`` or ``load_weak``/``strong_copy_weak_value``
operations on the same address.

store_weak
Expand All @@ -5218,7 +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`` 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<T>
// %1 will be an @owned value of type $@sil_weak Optional<T>.
// $T must be a reference type
// $@sil_weak Optional<T> 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
````````````
Expand All @@ -5239,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``/``unowned_copy_value`` or
``load_unowned``/``strong_copy_unowned_value`` operations on the same address.

store_unowned
`````````````
Expand All @@ -5259,8 +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`` 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
````````````
Expand Down
119 changes: 76 additions & 43 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1061,20 +1061,49 @@ 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)); \
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()
.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) { \
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) { \
Expand All @@ -1085,41 +1114,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,
Expand Down
61 changes: 46 additions & 15 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -1407,7 +1407,34 @@ SILCloner<ImplClass>::visitDebugStepInst(DebugStepInst *Inst) {
recordClonedInstruction(Inst, getBuilder().createDebugStep(Inst->getLoc()));
}

#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \
template <typename ImplClass>
void SILCloner<ImplClass>::visitUnownedCopyValueInst(
UnownedCopyValueInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(
Inst, getBuilder().createUnownedCopyValue(
getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand())));
}

template <typename ImplClass>
void SILCloner<ImplClass>::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 <typename ImplClass> \
void SILCloner<ImplClass>::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 <typename ImplClass> \
void SILCloner<ImplClass>::visitLoad##Name##Inst(Load##Name##Inst *Inst) { \
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); \
Expand Down Expand Up @@ -1441,17 +1468,8 @@ SILCloner<ImplClass>::visitDebugStepInst(DebugStepInst *Inst) {
Inst, getBuilder().create##Name##ToRef(getOpLocation(Inst->getLoc()), \
getOpValue(Inst->getOperand()), \
getOpType(Inst->getType()))); \
} \
template <typename ImplClass> \
void SILCloner<ImplClass>::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 <typename ImplClass> \
void SILCloner<ImplClass>::visitStrongRetain##Name##Inst( \
StrongRetain##Name##Inst *Inst) { \
Expand All @@ -1478,13 +1496,26 @@ SILCloner<ImplClass>::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<typename ImplClass>
void
Expand Down
Loading