Skip to content

Commit a3c6f8f

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 a3c6f8f

21 files changed

+311
-16
lines changed

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 moveonly_to_copyable", (StringRef))
660+
ERROR(sil_moveonlytocopyable_requires_attribute,none,
661+
"moveonly_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: 19 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,24 @@ class SILBuilder {
12891290
MarkMustCheckInst(getSILDebugLocation(loc), src, kind));
12901291
}
12911292

1293+
CopyableToMoveOnlyValueInst *createCopyableToMoveOnlyValue(SILLocation loc,
1294+
SILValue src) {
1295+
return insert(new (getModule()) CopyableToMoveOnlyValueInst(
1296+
getSILDebugLocation(loc), src));
1297+
}
1298+
1299+
MoveOnlyToCopyableValueInst *
1300+
createOwnedMoveOnlyToCopyableValue(SILLocation loc, SILValue src) {
1301+
return insert(new (getModule()) MoveOnlyToCopyableValueInst(
1302+
*F, getSILDebugLocation(loc), src, OwnershipKind::Owned));
1303+
}
1304+
1305+
MoveOnlyToCopyableValueInst *
1306+
createGuaranteedMoveOnlyToCopyableValue(SILLocation loc, SILValue src) {
1307+
return insert(new (getModule()) MoveOnlyToCopyableValueInst(
1308+
*F, getSILDebugLocation(loc), src, OwnershipKind::Guaranteed));
1309+
}
1310+
12921311
UnconditionalCheckedCastInst *
12931312
createUnconditionalCheckedCast(SILLocation Loc, SILValue op,
12941313
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>::visitMoveOnlyToCopyableValueInst(
1775+
MoveOnlyToCopyableValueInst *inst) {
1776+
getBuilder().setCurrentDebugScope(getOpScope(inst->getDebugScope()));
1777+
MoveOnlyToCopyableValueInst *cvt;
1778+
if (inst->getOwnershipKind() == OwnershipKind::Owned) {
1779+
cvt = getBuilder().createOwnedMoveOnlyToCopyableValue(
1780+
getOpLocation(inst->getLoc()), getOpValue(inst->getOperand()));
1781+
} else {
1782+
assert(inst->getOwnershipKind() == OwnershipKind::Guaranteed);
1783+
cvt = getBuilder().createGuaranteedMoveOnlyToCopyableValue(
1784+
getOpLocation(inst->getLoc()), getOpValue(inst->getOperand()));
1785+
}
1786+
recordClonedInstruction(inst, cvt);
1787+
}
1788+
1789+
template <typename ImplClass>
1790+
void SILCloner<ImplClass>::visitCopyableToMoveOnlyValueInst(
1791+
CopyableToMoveOnlyValueInst *Inst) {
1792+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1793+
auto *MVI = getBuilder().createCopyableToMoveOnlyValue(
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: 57 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::MoveOnlyToCopyableValueInst:
13191320
return true;
13201321
default:
13211322
return false;
@@ -7587,6 +7588,58 @@ class MarkMustCheckInst
75877588
bool isNoImplicitCopy() const { return kind == CheckKind::NoImplicitCopy; }
75887589
};
75897590

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

97349788
inline OwnershipForwardingMixin *
@@ -9752,6 +9806,8 @@ OwnershipForwardingMixin::get(SILInstruction *inst) {
97529806
return result;
97539807
if (auto *result = dyn_cast<MarkMustCheckInst>(inst))
97549808
return result;
9809+
if (auto *result = dyn_cast<MoveOnlyToCopyableValueInst>(inst))
9810+
return result;
97559811
return nullptr;
97569812
}
97579813

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(CopyableToMoveOnlyValueInst, copyable_to_moveonly,
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(MoveOnlyToCopyableValueInst, moveonly_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: 10 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,14 @@ class IRGenSILFunction :
11901191
void visitMarkMustCheckInst(MarkMustCheckInst *i) {
11911192
llvm_unreachable("Invalid in Lowered SIL");
11921193
}
1194+
void visitCopyableToMoveOnlyValueInst(CopyableToMoveOnlyValueInst *i) {
1195+
auto e = getLoweredExplosion(i->getOperand());
1196+
setLoweredExplosion(i, e);
1197+
}
1198+
void visitMoveOnlyToCopyableValueInst(MoveOnlyToCopyableValueInst *i) {
1199+
auto e = getLoweredExplosion(i->getOperand());
1200+
setLoweredExplosion(i, e);
1201+
}
11931202
void visitReleaseValueInst(ReleaseValueInst *i);
11941203
void visitReleaseValueAddrInst(ReleaseValueAddrInst *i);
11951204
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, CopyableToMoveOnlyValue)
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(MoveOnlyToCopyableValue)
331333
#undef FORWARDING_OWNERSHIP
332334

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

lib/SIL/IR/SILPrinter.cpp

Lines changed: 22 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,26 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
19131914
*this << getIDAndType(I->getOperand());
19141915
}
19151916

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

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ CONSTANT_OWNERSHIP_INST(Owned, CopyBlockWithoutEscaping)
7575
CONSTANT_OWNERSHIP_INST(Owned, CopyValue)
7676
CONSTANT_OWNERSHIP_INST(Owned, ExplicitCopyValue)
7777
CONSTANT_OWNERSHIP_INST(Owned, MoveValue)
78+
CONSTANT_OWNERSHIP_INST(Owned, CopyableToMoveOnlyValue)
7879
CONSTANT_OWNERSHIP_INST(Owned, EndCOWMutation)
7980
CONSTANT_OWNERSHIP_INST(Owned, KeyPath)
8081
CONSTANT_OWNERSHIP_INST(Owned, InitExistentialValue)
@@ -275,6 +276,7 @@ FORWARDING_OWNERSHIP_INST(InitExistentialRef)
275276
FORWARDING_OWNERSHIP_INST(DifferentiableFunction)
276277
FORWARDING_OWNERSHIP_INST(LinearFunction)
277278
FORWARDING_OWNERSHIP_INST(MarkMustCheck)
279+
FORWARDING_OWNERSHIP_INST(MoveOnlyToCopyableValue)
278280
#undef FORWARDING_OWNERSHIP_INST
279281

280282
ValueOwnershipKind

0 commit comments

Comments
 (0)