Skip to content

Commit e1006c6

Browse files
committed
[move-only] Add copyable_to_moveonlywrapper and moveonlywrapper_to_copyable instructions.
These instructions have the following attributes: 1. copyably_to_moveonlywrapper takes in a 'T' and maps it to a '@moveOnly T'. This is semantically used when initializing a new moveOnly binding from a copyable value. It semantically destroys its input @owned value and returns a brand new independent @owned @moveOnly value. It also is used to convert a trivial copyable value with type 'Trivial' into an owned non-trivial value of type '@moveOnly Trivial'. If one thinks of '@moveOnly' as a monad, this is how one injects a copyable value into the move only space. 2. moveonlywrapper_to_copyable takes in a '@moveOnly T' and produces a new 'T' value. This is a 'forwarding' instruction where at parse time, we only allow for one to choose it to be [owned] or [guaranteed]. * moveonlywrapper_to_copyable [owned] is used to signal the end of lifetime of the '@moveOnly' wrapper. SILGen inserts these when ever a move only value has its ownership passed to a situation where a copyable value is needed. Since it is consuming, we know that the no implicit copy checker will ensure that if we need a copy for it, the program will emit a diagnostic. * moveonlywrapper_to_copyable [guaranteed] is used to pass a @moveOnly T value as a copyable guaranteed parameter with type 'T' to a function. In the case of using no-implicit-copy checking this is always fine since no-implicit-copy is a local pattern. This would be an error when performing no escape checking. Importantly, this instruction also is where in the case of an @moveOnly trivial type, we convert from the non-trivial representation to the trivial representation. Some important notes: 1. In a forthcoming commit, I am going to rebase the no implicit copy checker on top of these instructions. By using '@moveOnly' in the type system, we can ensure that later in the SIL pipeline, we can have optimizations easily ignore the code. 2. Be aware of is that due to SILGen only emitting '@moveOnly T' along immediate accesses to the variable and always converts to a copyable representation when calling other code, we can simply eliminate from the IR all moveonly-ness from the IR using a lowering pass (that I am going to upstream). In the evil scheme we are accomplishing here, we perform lowering of trivial values right after ownership lowering and before diagnostics to simplify the pipeline. On another note, I also fixed a few things in SILParsing around getASTType() vs getRawASTType().
1 parent e1412a0 commit e1006c6

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)