Skip to content

Commit 7c7fb47

Browse files
authored
Merge pull request #59355 from gottesmm/pr-20b996075d28e099e1c791eb80e78022f940f91e
[move-only] Add copyable_to_moveonlywrapper and moveonlywrapper_to_copyable instructions.
2 parents d00c0f5 + e1006c6 commit 7c7fb47

22 files changed

+391
-21
lines changed

docs/SIL.rst

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7443,6 +7443,68 @@ The remaining components identify the SIL differentiability witness:
74437443
witness generic parameter clause is combined with the original function's
74447444
generic signature to form the full witness generic signature.
74457445

7446+
Optimizer Dataflow Marker Instructions
7447+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7448+
7449+
mark_must_check
7450+
```````````````
7451+
::
7452+
7453+
sil-instruction ::= 'mark_must_check'
7454+
'[' sil-optimizer-analysis-marker ']'
7455+
7456+
sil-optimizer-analysis-marker ::= 'no_implicit_copy'
7457+
7458+
A canary value inserted by a SIL generating frontend to signal to the move
7459+
checker to check a specific value. Valid only in Raw SIL. The relevant checkers
7460+
should remove the `mark_must_check`_ instruction after successfully running the
7461+
relevant diagnostic. The idea here is that instead of needing to introduce
7462+
multiple "flaging" instructions for the optimizer, we can just reuse this one
7463+
instruction by varying the kind.
7464+
7465+
No Implicit Copy and No Escape Value Instructions
7466+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7467+
7468+
copyable_to_moveonlywrapper
7469+
```````````````````````````
7470+
::
7471+
7472+
sil-instruction ::= 'copyable_to_moveonlywrapper'
7473+
7474+
`copyably_to_moveonlywrapper`_ takes in a 'T' and maps it to a move only wrapped
7475+
'@moveOnly T'. This is semantically used by a code generator initializing a new
7476+
moveOnly binding from a copyable value. It semantically destroys its input
7477+
@owned value and returns a brand new independent @owned @moveOnly value. It also
7478+
is used to convert a trivial copyable value with type 'Trivial' into an owned
7479+
non-trivial value of type '@moveOnly Trivial'. If one thinks of '@moveOnly' as a
7480+
monad, this is how one injects a copyable value into the move only space.
7481+
7482+
moveonlywrapper_to_copyable
7483+
```````````````````````````
7484+
::
7485+
7486+
sil-instruction ::= 'moveonlywrapper_to_copyable [owned]'
7487+
sil-instruction ::= 'moveonlywrapper_to_copyable [guaranteed]'
7488+
7489+
`moveonlywrapper_to_copyable`_ takes in a '@moveOnly T' and produces a new 'T'
7490+
value. This is a 'forwarding' instruction where at parse time, we only allow for
7491+
one to choose it to be [owned] or [guaranteed]. With time, we may eliminate the
7492+
need for the guaranteed form in the future.
7493+
7494+
* `moveonlywrapper_to_copyable [owned]` is used to signal the end of lifetime of
7495+
the '@moveOnly' wrapper. SILGen inserts these when ever a move only value has
7496+
its ownership passed to a situation where a copyable value is needed. Since it
7497+
is consuming, we know that the no implicit copy or no-escape checker will ensure
7498+
that if we need a copy for it, the program will emit a diagnostic.
7499+
7500+
* `moveonlywrapper_to_copyable [guaranteed]` is used to pass a @moveOnly T value
7501+
as a copyable guaranteed parameter with type 'T' to a function. In the case of
7502+
using no-implicit-copy checking this is always fine since no-implicit-copy is a
7503+
local pattern. This would be an error when performing no escape
7504+
checking. Importantly, this instruction also is where in the case of an
7505+
@moveOnly trivial type, we convert from the non-trivial representation to the
7506+
trivial representation.
7507+
74467508
Assertion configuration
74477509
~~~~~~~~~~~~~~~~~~~~~~~
74487510

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,10 @@ ERROR(sil_markmustcheck_invalid_attribute,none,
655655
"Attribute '[%0]' can not be applied to mark_value_as_moveonly", (StringRef))
656656
ERROR(sil_markmustcheck_requires_attribute,none,
657657
"mark_must_check requires an attribute like 'noImplicitCopy'", ())
658+
ERROR(sil_moveonlytocopyable_invalid_attribute,none,
659+
"Attribute '[%0]' can not be applied to moveonlywrapper_to_copyable", (StringRef))
660+
ERROR(sil_moveonlytocopyable_requires_attribute,none,
661+
"moveonlywrapper_to_copyable requires either a [guaranteed] or [owned] attribute", ())
658662

659663
// SIL Basic Blocks
660664
ERROR(expected_sil_block_name,none,

include/swift/SIL/SILBuilder.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/SIL/SILArgument.h"
1818
#include "swift/SIL/SILDebugScope.h"
1919
#include "swift/SIL/SILFunction.h"
20+
#include "swift/SIL/SILInstruction.h"
2021
#include "swift/SIL/SILModule.h"
2122
#include "swift/SIL/SILUndef.h"
2223
#include "llvm/ADT/PointerUnion.h"
@@ -1289,6 +1290,25 @@ class SILBuilder {
12891290
MarkMustCheckInst(getSILDebugLocation(loc), src, kind));
12901291
}
12911292

1293+
CopyableToMoveOnlyWrapperValueInst *
1294+
createCopyableToMoveOnlyWrapperValue(SILLocation loc, SILValue src) {
1295+
return insert(new (getModule()) CopyableToMoveOnlyWrapperValueInst(
1296+
getSILDebugLocation(loc), src));
1297+
}
1298+
1299+
MoveOnlyWrapperToCopyableValueInst *
1300+
createOwnedMoveOnlyWrapperToCopyableValue(SILLocation loc, SILValue src) {
1301+
return insert(new (getModule()) MoveOnlyWrapperToCopyableValueInst(
1302+
*F, getSILDebugLocation(loc), src, OwnershipKind::Owned));
1303+
}
1304+
1305+
MoveOnlyWrapperToCopyableValueInst *
1306+
createGuaranteedMoveOnlyWrapperToCopyableValue(SILLocation loc,
1307+
SILValue src) {
1308+
return insert(new (getModule()) MoveOnlyWrapperToCopyableValueInst(
1309+
*F, getSILDebugLocation(loc), src, OwnershipKind::Guaranteed));
1310+
}
1311+
12921312
UnconditionalCheckedCastInst *
12931313
createUnconditionalCheckedCast(SILLocation Loc, SILValue op,
12941314
SILType destLoweredTy,

include/swift/SIL/SILCloner.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/SIL/Dominance.h"
2525
#include "swift/SIL/SILBuilder.h"
2626
#include "swift/SIL/SILDebugScope.h"
27+
#include "swift/SIL/SILInstruction.h"
2728
#include "swift/SIL/SILVisitor.h"
2829

2930
namespace swift {
@@ -1769,6 +1770,31 @@ void SILCloner<ImplClass>::visitMarkMustCheckInst(MarkMustCheckInst *Inst) {
17691770
recordClonedInstruction(Inst, MVI);
17701771
}
17711772

1773+
template <typename ImplClass>
1774+
void SILCloner<ImplClass>::visitMoveOnlyWrapperToCopyableValueInst(
1775+
MoveOnlyWrapperToCopyableValueInst *inst) {
1776+
getBuilder().setCurrentDebugScope(getOpScope(inst->getDebugScope()));
1777+
MoveOnlyWrapperToCopyableValueInst *cvt;
1778+
if (inst->getOwnershipKind() == OwnershipKind::Owned) {
1779+
cvt = getBuilder().createOwnedMoveOnlyWrapperToCopyableValue(
1780+
getOpLocation(inst->getLoc()), getOpValue(inst->getOperand()));
1781+
} else {
1782+
assert(inst->getOwnershipKind() == OwnershipKind::Guaranteed);
1783+
cvt = getBuilder().createGuaranteedMoveOnlyWrapperToCopyableValue(
1784+
getOpLocation(inst->getLoc()), getOpValue(inst->getOperand()));
1785+
}
1786+
recordClonedInstruction(inst, cvt);
1787+
}
1788+
1789+
template <typename ImplClass>
1790+
void SILCloner<ImplClass>::visitCopyableToMoveOnlyWrapperValueInst(
1791+
CopyableToMoveOnlyWrapperValueInst *Inst) {
1792+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1793+
auto *MVI = getBuilder().createCopyableToMoveOnlyWrapperValue(
1794+
getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand()));
1795+
recordClonedInstruction(Inst, MVI);
1796+
}
1797+
17721798
template <typename ImplClass>
17731799
void SILCloner<ImplClass>::visitReleaseValueInst(ReleaseValueInst *Inst) {
17741800
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));

include/swift/SIL/SILInstruction.h

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1316,6 +1316,7 @@ FirstArgOwnershipForwardingSingleValueInst::classof(SILInstructionKind kind) {
13161316
case SILInstructionKind::OpenExistentialRefInst:
13171317
case SILInstructionKind::InitExistentialRefInst:
13181318
case SILInstructionKind::MarkDependenceInst:
1319+
case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst:
13191320
return true;
13201321
default:
13211322
return false;
@@ -7587,6 +7588,60 @@ class MarkMustCheckInst
75877588
bool isNoImplicitCopy() const { return kind == CheckKind::NoImplicitCopy; }
75887589
};
75897590

7591+
class CopyableToMoveOnlyWrapperValueInst
7592+
: public UnaryInstructionBase<
7593+
SILInstructionKind::CopyableToMoveOnlyWrapperValueInst,
7594+
SingleValueInstruction> {
7595+
friend class SILBuilder;
7596+
7597+
CopyableToMoveOnlyWrapperValueInst(SILDebugLocation DebugLoc,
7598+
SILValue operand)
7599+
: UnaryInstructionBase(DebugLoc, operand,
7600+
operand->getType().addingMoveOnlyWrapper()) {}
7601+
};
7602+
7603+
/// Convert from an @moveOnly wrapper type to the underlying copyable type. Can
7604+
/// be either owned or guaranteed.
7605+
///
7606+
/// IMPORTANT: Unlike other forwarding instructions, the ownership of moveonly
7607+
/// to copyable is not forwarded from the operand. Instead in SILBuilder one
7608+
/// must select the specific type of ownership one wishes by using the following
7609+
/// APIs:
7610+
///
7611+
/// * SILBuilder::createOwnedMoveOnlyWrapperToCopyableValueInst
7612+
/// * SILBuilder::createGuaranteedMoveOnlyWrapperToCopyableValueInst
7613+
///
7614+
/// The reason why this instruction was designed in this manner is that a
7615+
/// frontend chooses the ownership form of this instruction based off of the
7616+
/// semantic place that the value is used. As an example:
7617+
///
7618+
/// 1. When calling a function semantically with guaranteed ownership, the
7619+
/// frontend would use the "guaranteed variant".
7620+
///
7621+
/// 2. When returning a value or assigning into another binding, a frontend
7622+
/// would want to use the owned variant so that the move only checker will
7623+
/// enforce the end of the moved value's lifetime.
7624+
///
7625+
/// NOTE: With time, we are going to eliminate the guaranteed form of this
7626+
/// instruction in favor of a function conversion instruction.
7627+
class MoveOnlyWrapperToCopyableValueInst
7628+
: public UnaryInstructionBase<
7629+
SILInstructionKind::MoveOnlyWrapperToCopyableValueInst,
7630+
SingleValueInstruction>,
7631+
public OwnershipForwardingMixin {
7632+
friend class SILBuilder;
7633+
7634+
MoveOnlyWrapperToCopyableValueInst(const SILFunction &fn,
7635+
SILDebugLocation DebugLoc,
7636+
SILValue operand,
7637+
OwnershipKind forwardingOwnershipKind)
7638+
: UnaryInstructionBase(DebugLoc, operand,
7639+
operand->getType().removingMoveOnlyWrapper()),
7640+
OwnershipForwardingMixin(
7641+
SILInstructionKind::MoveOnlyWrapperToCopyableValueInst,
7642+
forwardingOwnershipKind) {}
7643+
};
7644+
75907645
/// Given an object reference, return true iff it is non-nil and refers
75917646
/// to a native swift object with strong reference count of 1.
75927647
class IsUniqueInst
@@ -9728,7 +9783,8 @@ inline bool OwnershipForwardingMixin::isa(SILInstructionKind kind) {
97289783
OwnershipForwardingConversionInst::classof(kind) ||
97299784
OwnershipForwardingSelectEnumInstBase::classof(kind) ||
97309785
OwnershipForwardingMultipleValueInstruction::classof(kind) ||
9731-
kind == SILInstructionKind::MarkMustCheckInst;
9786+
kind == SILInstructionKind::MarkMustCheckInst ||
9787+
kind == SILInstructionKind::MoveOnlyWrapperToCopyableValueInst;
97329788
}
97339789

97349790
inline OwnershipForwardingMixin *
@@ -9752,6 +9808,8 @@ OwnershipForwardingMixin::get(SILInstruction *inst) {
97529808
return result;
97539809
if (auto *result = dyn_cast<MarkMustCheckInst>(inst))
97549810
return result;
9811+
if (auto *result = dyn_cast<MoveOnlyWrapperToCopyableValueInst>(inst))
9812+
return result;
97559813
return nullptr;
97569814
}
97579815

include/swift/SIL/SILNodes.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,15 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
473473
// running the relevant diagnostic.
474474
SINGLE_VALUE_INST(MarkMustCheckInst, mark_must_check,
475475
SingleValueInstruction, None, DoesNotRelease)
476+
// Convert a $T to $@moveOnly T. This is the method that one uses to convert a
477+
// trivial value to a non-trivial move only value.
478+
SINGLE_VALUE_INST(CopyableToMoveOnlyWrapperValueInst, copyable_to_moveonlywrapper,
479+
SingleValueInstruction, None, DoesNotRelease)
480+
// Convert a $@moveOnly T to $T. Ownership is fixed at construction by
481+
// frontend to express specific semantics: guaranteed for function arguments
482+
// and owned for assignment/return values.
483+
SINGLE_VALUE_INST(MoveOnlyWrapperToCopyableValueInst, moveonlywrapper_to_copyable,
484+
SingleValueInstruction, None, DoesNotRelease)
476485
// A move_addr is a Raw SIL only instruction that is equivalent to a copy_addr
477486
// [init]. It is lowered during the diagnostic passes to a copy_addr [init] if
478487
// the move checker found uses that prevented us from converting this to a

include/swift/SIL/SILType.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ enum class SILValueCategory : uint8_t {
8787
};
8888

8989
class SILPrinter;
90+
class SILParser;
9091

9192
/// SILType - A Swift type that has been lowered to a SIL representation type.
9293
/// In addition to the Swift type system, SIL adds "address" types that can
@@ -116,6 +117,7 @@ class SILType {
116117
friend class Lowering::TypeConverter;
117118
friend struct llvm::DenseMapInfo<SILType>;
118119
friend class SILPrinter;
120+
friend class SILParser;
119121

120122
public:
121123
SILType() = default;
@@ -160,13 +162,13 @@ class SILType {
160162
/// Returns the address variant of this type. Instructions which
161163
/// manipulate memory will generally work with object addresses.
162164
SILType getAddressType() const {
163-
return SILType(getASTType(), SILValueCategory::Address);
165+
return SILType(getRawASTType(), SILValueCategory::Address);
164166
}
165167

166168
/// Returns the object variant of this type. Note that address-only
167169
/// types are not legal to manipulate directly as objects in SIL.
168170
SILType getObjectType() const {
169-
return SILType(getASTType(), SILValueCategory::Object);
171+
return SILType(getRawASTType(), SILValueCategory::Object);
170172
}
171173

172174
/// Returns the canonical AST type referenced by this SIL type.

lib/IRGen/IRGenSIL.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@
2929
#include "swift/Basic/STLExtras.h"
3030
#include "swift/IRGen/Linking.h"
3131
#include "swift/SIL/ApplySite.h"
32+
#include "swift/SIL/BasicBlockDatastructures.h"
3233
#include "swift/SIL/Dominance.h"
3334
#include "swift/SIL/InstructionUtils.h"
3435
#include "swift/SIL/MemAccessUtils.h"
3536
#include "swift/SIL/PrettyStackTrace.h"
36-
#include "swift/SIL/BasicBlockDatastructures.h"
3737
#include "swift/SIL/SILDebugScope.h"
3838
#include "swift/SIL/SILDeclRef.h"
39+
#include "swift/SIL/SILInstruction.h"
3940
#include "swift/SIL/SILLinkage.h"
4041
#include "swift/SIL/SILModule.h"
4142
#include "swift/SIL/SILType.h"
@@ -1190,6 +1191,16 @@ class IRGenSILFunction :
11901191
void visitMarkMustCheckInst(MarkMustCheckInst *i) {
11911192
llvm_unreachable("Invalid in Lowered SIL");
11921193
}
1194+
void visitCopyableToMoveOnlyWrapperValueInst(
1195+
CopyableToMoveOnlyWrapperValueInst *i) {
1196+
auto e = getLoweredExplosion(i->getOperand());
1197+
setLoweredExplosion(i, e);
1198+
}
1199+
void visitMoveOnlyWrapperToCopyableValueInst(
1200+
MoveOnlyWrapperToCopyableValueInst *i) {
1201+
auto e = getLoweredExplosion(i->getOperand());
1202+
setLoweredExplosion(i, e);
1203+
}
11931204
void visitReleaseValueInst(ReleaseValueInst *i);
11941205
void visitReleaseValueAddrInst(ReleaseValueAddrInst *i);
11951206
void visitDestroyValueInst(DestroyValueInst *i);

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ OPERAND_OWNERSHIP(DestroyingConsume, EndCOWMutation)
256256

257257
// TODO: Should this be a forwarding consume.
258258
OPERAND_OWNERSHIP(DestroyingConsume, MoveValue)
259+
OPERAND_OWNERSHIP(DestroyingConsume, CopyableToMoveOnlyWrapperValue)
259260

260261
// Instructions that move an owned value.
261262
OPERAND_OWNERSHIP(ForwardingConsume, InitExistentialValue)
@@ -328,6 +329,7 @@ FORWARDING_OWNERSHIP(InitExistentialRef)
328329
FORWARDING_OWNERSHIP(DifferentiableFunction)
329330
FORWARDING_OWNERSHIP(LinearFunction)
330331
FORWARDING_OWNERSHIP(MarkMustCheck)
332+
FORWARDING_OWNERSHIP(MoveOnlyWrapperToCopyableValue)
331333
#undef FORWARDING_OWNERSHIP
332334

333335
// Arbitrary value casts are forwarding instructions that are also allowed to

lib/SIL/IR/SILPrinter.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@
2323
#include "swift/AST/ProtocolConformance.h"
2424
#include "swift/AST/Types.h"
2525
#include "swift/Basic/QuotedString.h"
26-
#include "swift/Basic/SourceManager.h"
2726
#include "swift/Basic/STLExtras.h"
27+
#include "swift/Basic/SourceManager.h"
2828
#include "swift/Demangling/Demangle.h"
2929
#include "swift/SIL/ApplySite.h"
3030
#include "swift/SIL/CFG.h"
3131
#include "swift/SIL/SILCoverageMap.h"
3232
#include "swift/SIL/SILDebugScope.h"
3333
#include "swift/SIL/SILDeclRef.h"
3434
#include "swift/SIL/SILFunction.h"
35+
#include "swift/SIL/SILInstruction.h"
3536
#include "swift/SIL/SILModule.h"
3637
#include "swift/SIL/SILPrintContext.h"
3738
#include "swift/SIL/SILVTable.h"
@@ -1913,6 +1914,28 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
19131914
*this << getIDAndType(I->getOperand());
19141915
}
19151916

1917+
void visitCopyableToMoveOnlyWrapperValueInst(
1918+
CopyableToMoveOnlyWrapperValueInst *I) {
1919+
*this << getIDAndType(I->getOperand());
1920+
}
1921+
1922+
void visitMoveOnlyWrapperToCopyableValueInst(
1923+
MoveOnlyWrapperToCopyableValueInst *I) {
1924+
switch (I->getForwardingOwnershipKind()) {
1925+
case OwnershipKind::None:
1926+
case OwnershipKind::Any:
1927+
case OwnershipKind::Unowned:
1928+
llvm_unreachable("Move only values are always non-trivial");
1929+
case OwnershipKind::Owned:
1930+
*this << "[owned] ";
1931+
break;
1932+
case OwnershipKind::Guaranteed:
1933+
*this << "[guaranteed] ";
1934+
break;
1935+
}
1936+
*this << getIDAndType(I->getOperand());
1937+
}
1938+
19161939
#define UNCHECKED_REF_STORAGE(Name, ...) \
19171940
void visitStrongCopy##Name##ValueInst(StrongCopy##Name##ValueInst *I) { \
19181941
*this << getIDAndType(I->getOperand()); \

0 commit comments

Comments
 (0)