Skip to content

Commit 5590c7b

Browse files
committed
[sil] Add a move_value instruction.
This is a new instruction that can be used by SILGen to perform a semantic move in between two entities that are considered separate variables at the AST level. I am going to use it to implement an experimental borrow checker. This PR contains the following: 1. I define move_value, setup parsing, printing, serializing, deserializing, cloning, and filled in all of the visitors as appropriate. 2. I added createMoveValue and emitMoveValueOperation SILBuilder APIs. createMoveValue always creates a move and asserts is passed a trivial type. emitMoveValueOperation in contrast, will short circuit if passed a trivial value and just return the trivial value. 3. I added IRGen tests to show that we can push this through the entire system. This is all just scaffolding for the instruction to live in SIL land and as of this PR doesn't actually do anything.
1 parent 03e32c4 commit 5590c7b

File tree

20 files changed

+155
-2
lines changed

20 files changed

+155
-2
lines changed

docs/SIL.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5245,6 +5245,34 @@ independent of the operand. In terms of specific types:
52455245
In ownership qualified functions, a ``copy_value`` produces a +1 value that must
52465246
be consumed at most once along any path through the program.
52475247

5248+
move_value
5249+
``````````
5250+
5251+
::
5252+
5253+
sil-instruction ::= 'move_value' sil-operand
5254+
5255+
%1 = move_value %0 : $@_moveOnly A
5256+
5257+
Performs a move of the operand, ending its lifetime. When ownership is enabled,
5258+
it always takes in an `@owned T` and produces a new `@owned @_moveOnly T`.
5259+
5260+
1. For trivial types, this is equivalent to just propagating through the trivial
5261+
value.
5262+
2. For reference types, this is equivalent to ending the lifetime of the
5263+
operand, beginning a new lifetime for the result and setting the result to
5264+
the value of the operand.
5265+
3. For aggregates, the operation is equivalent to performing a move_value on
5266+
each of its fields recursively.
5267+
5268+
After ownership is lowered, we leave in the move_value to provide a place for
5269+
IRGenSIL to know to store a potentially new variable (in case the move was
5270+
associated with a let binding).
5271+
5272+
NOTE: This instruction is used in an experimental feature called 'move only
5273+
values'. A move_value instruction is an instruction that introduces (or injects)
5274+
a type `T` into the move only value space.
5275+
52485276
release_value
52495277
`````````````
52505278

include/swift/SIL/SILBuilder.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,14 @@ class SILBuilder {
12321232
operand, poisonRefs));
12331233
}
12341234

1235+
MoveValueInst *createMoveValue(SILLocation loc, SILValue operand) {
1236+
assert(!operand->getType().isTrivial(getFunction()) &&
1237+
"Should not be passing trivial values to this api. Use instead "
1238+
"emitMoveValueOperation");
1239+
return insert(new (getModule())
1240+
MoveValueInst(getSILDebugLocation(loc), operand));
1241+
}
1242+
12351243
UnconditionalCheckedCastInst *
12361244
createUnconditionalCheckedCast(SILLocation Loc, SILValue op,
12371245
SILType destLoweredTy,
@@ -2466,6 +2474,17 @@ class SILBuilder {
24662474
createDestroyAddr(loc, v);
24672475
}
24682476

2477+
/// Convenience function that is a no-op for trivial values and inserts a
2478+
/// move_value on non-trivial instructions.
2479+
SILValue emitMoveValueOperation(SILLocation Loc, SILValue v) {
2480+
assert(!v->getType().isAddress());
2481+
if (v->getType().isTrivial(*getInsertionBB()->getParent()))
2482+
return v;
2483+
assert(v.getOwnershipKind() == OwnershipKind::Owned &&
2484+
"move_value consumes its argument");
2485+
return createMoveValue(Loc, v);
2486+
}
2487+
24692488
SILValue emitTupleExtract(SILLocation Loc, SILValue Operand, unsigned FieldNo,
24702489
SILType ResultTy) {
24712490
// Fold tuple_extract(tuple(x,y,z),2)

include/swift/SIL/SILCloner.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,6 +1717,14 @@ void SILCloner<ImplClass>::visitCopyValueInst(CopyValueInst *Inst) {
17171717
getOpValue(Inst->getOperand())));
17181718
}
17191719

1720+
template <typename ImplClass>
1721+
void SILCloner<ImplClass>::visitMoveValueInst(MoveValueInst *Inst) {
1722+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1723+
recordClonedInstruction(
1724+
Inst, getBuilder().createMoveValue(getOpLocation(Inst->getLoc()),
1725+
getOpValue(Inst->getOperand())));
1726+
}
1727+
17201728
template <typename ImplClass>
17211729
void SILCloner<ImplClass>::visitReleaseValueInst(ReleaseValueInst *Inst) {
17221730
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));

include/swift/SIL/SILInstruction.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7321,6 +7321,15 @@ class DestroyValueInst
73217321
}
73227322
};
73237323

7324+
class MoveValueInst
7325+
: public UnaryInstructionBase<SILInstructionKind::MoveValueInst,
7326+
SingleValueInstruction> {
7327+
friend class SILBuilder;
7328+
7329+
MoveValueInst(SILDebugLocation DebugLoc, SILValue operand)
7330+
: UnaryInstructionBase(DebugLoc, operand, operand->getType()) {}
7331+
};
7332+
73247333
/// Given an object reference, return true iff it is non-nil and refers
73257334
/// to a native swift object with strong reference count of 1.
73267335
class IsUniqueInst

include/swift/SIL/SILNodes.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,10 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
587587
#include "swift/AST/ReferenceStorage.def"
588588
SINGLE_VALUE_INST(UncheckedOwnershipConversionInst, unchecked_ownership_conversion,
589589
SingleValueInstruction, None, MayRelease)
590+
// A move_value is an OSSA only instruction. Its result does not have any side
591+
// effects relative to other OSSA values like copy_value.
592+
SINGLE_VALUE_INST(MoveValueInst, move_value,
593+
SingleValueInstruction, None, DoesNotRelease)
590594

591595
// IsUnique does not actually write to memory but should be modeled
592596
// as such. Its operand is a pointer to an object reference. The

lib/IRGen/IRGenSIL.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,10 @@ class IRGenSILFunction :
11491149
void visitRetainValueInst(RetainValueInst *i);
11501150
void visitRetainValueAddrInst(RetainValueAddrInst *i);
11511151
void visitCopyValueInst(CopyValueInst *i);
1152+
void visitMoveValueInst(MoveValueInst *i) {
1153+
auto e = getLoweredExplosion(i->getOperand());
1154+
setLoweredExplosion(i, e);
1155+
}
11521156
void visitReleaseValueInst(ReleaseValueInst *i);
11531157
void visitReleaseValueAddrInst(ReleaseValueAddrInst *i);
11541158
void visitDestroyValueInst(DestroyValueInst *i);

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,9 @@ OPERAND_OWNERSHIP(DestroyingConsume, EndLifetime)
249249
OPERAND_OWNERSHIP(DestroyingConsume, BeginCOWMutation)
250250
OPERAND_OWNERSHIP(DestroyingConsume, EndCOWMutation)
251251

252+
// TODO: Should this be a forwarding consume.
253+
OPERAND_OWNERSHIP(DestroyingConsume, MoveValue)
254+
252255
// Instructions that move an owned value.
253256
OPERAND_OWNERSHIP(ForwardingConsume, CheckedCastValueBranch)
254257
OPERAND_OWNERSHIP(ForwardingConsume, UnconditionalCheckedCastValue)

lib/SIL/IR/SILPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,6 +1826,10 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
18261826
*this << getIDAndType(I->getOperand());
18271827
}
18281828

1829+
void visitMoveValueInst(MoveValueInst *I) {
1830+
*this << getIDAndType(I->getOperand());
1831+
}
1832+
18291833
#define UNCHECKED_REF_STORAGE(Name, ...) \
18301834
void visitStrongCopy##Name##ValueInst(StrongCopy##Name##ValueInst *I) { \
18311835
*this << getIDAndType(I->getOperand()); \

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ CONSTANT_OWNERSHIP_INST(None, AllocValueBuffer)
7474
CONSTANT_OWNERSHIP_INST(Owned, CopyBlock)
7575
CONSTANT_OWNERSHIP_INST(Owned, CopyBlockWithoutEscaping)
7676
CONSTANT_OWNERSHIP_INST(Owned, CopyValue)
77+
CONSTANT_OWNERSHIP_INST(Owned, MoveValue)
7778
CONSTANT_OWNERSHIP_INST(Owned, EndCOWMutation)
7879
CONSTANT_OWNERSHIP_INST(Owned, KeyPath)
7980
CONSTANT_OWNERSHIP_INST(Owned, InitExistentialValue)

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3113,6 +3113,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
31133113
UNARY_INSTRUCTION(IsUnique)
31143114
UNARY_INSTRUCTION(DestroyAddr)
31153115
UNARY_INSTRUCTION(CopyValue)
3116+
UNARY_INSTRUCTION(MoveValue)
31163117
UNARY_INSTRUCTION(EndBorrow)
31173118
UNARY_INSTRUCTION(DestructureStruct)
31183119
UNARY_INSTRUCTION(DestructureTuple)

0 commit comments

Comments
 (0)