Skip to content

Commit fe321ca

Browse files
authored
Merge pull request #39267 from gottesmm/pr-c8321c6af93e6ad619f35474eb2a74f181c17384
[sil] Add a move_value instruction.
2 parents 03e32c4 + 5590c7b commit fe321ca

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)

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5271,6 +5271,13 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
52715271
"convention");
52725272
}
52735273

5274+
void checkMoveValueInst(MoveValueInst *mvi) {
5275+
require(mvi->getOperand()->getType().isObject(),
5276+
"Operand value should be an object");
5277+
require(mvi->getType() == mvi->getOperand()->getType(),
5278+
"Result and operand must have the same type, today.");
5279+
}
5280+
52745281
void verifyEpilogBlocks(SILFunction *F) {
52755282
bool FoundReturnBlock = false;
52765283
bool FoundThrowBlock = false;

lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ static bool hasOpaqueArchetype(TypeExpansionContext context,
204204
case SILInstructionKind::CopyBlockInst:
205205
case SILInstructionKind::CopyBlockWithoutEscapingInst:
206206
case SILInstructionKind::CopyValueInst:
207+
case SILInstructionKind::MoveValueInst:
207208
#define UNCHECKED_REF_STORAGE(Name, ...) \
208209
case SILInstructionKind::StrongCopy##Name##ValueInst:
209210
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
687687
case SILInstructionKind::EndLifetimeInst:
688688
case SILInstructionKind::UncheckedOwnershipConversionInst:
689689
case SILInstructionKind::BindMemoryInst:
690+
case SILInstructionKind::MoveValueInst:
690691
return InlineCost::Free;
691692

692693
// Typed GEPs are free.

lib/Serialization/DeserializeSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,6 +1846,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
18461846
REFCOUNTING_INSTRUCTION(RetainValueAddr)
18471847
REFCOUNTING_INSTRUCTION(UnmanagedRetainValue)
18481848
UNARY_INSTRUCTION(CopyValue)
1849+
UNARY_INSTRUCTION(MoveValue)
18491850
REFCOUNTING_INSTRUCTION(ReleaseValue)
18501851
REFCOUNTING_INSTRUCTION(ReleaseValueAddr)
18511852
REFCOUNTING_INSTRUCTION(UnmanagedReleaseValue)

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5656
/// describe what change you made. The content of this comment isn't important;
5757
/// it just ensures a conflict if two people change the module format.
5858
/// Don't worry about adhering to the 80-column limit for this line.
59-
const uint16_t SWIFTMODULE_VERSION_MINOR = 626; // switch & checkcast ownership
59+
const uint16_t SWIFTMODULE_VERSION_MINOR = 627; // move_value inst
6060

6161
/// A standard hash seed used for all string hashes in a serialized module.
6262
///

lib/Serialization/SerializeSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,6 +1388,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
13881388
case SILInstructionKind::UnmanagedRetainValueInst:
13891389
case SILInstructionKind::EndBorrowInst:
13901390
case SILInstructionKind::CopyValueInst:
1391+
case SILInstructionKind::MoveValueInst:
13911392
case SILInstructionKind::DestroyValueInst:
13921393
case SILInstructionKind::ReleaseValueInst:
13931394
case SILInstructionKind::ReleaseValueAddrInst:

test/IRGen/move_value.sil

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %swift -disable-legacy-type-info -target x86_64-apple-macosx10.9 -module-name main %s -emit-ir -o - | %FileCheck %s
2+
3+
// REQUIRES: CODEGENERATOR=X86
4+
5+
sil_stage canonical
6+
7+
import Builtin
8+
9+
// CHECK-LABEL: define swiftcc %swift.refcounted* @move_value_test(
10+
// CHECK-NEXT: entry:
11+
// CHECK-NEXT: ret
12+
// CHECK-NEXT: }
13+
sil @move_value_test : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
14+
bb0(%0 : $Builtin.NativeObject):
15+
%1 = move_value %0 : $Builtin.NativeObject
16+
return %1 : $Builtin.NativeObject
17+
}

test/SIL/Parser/basic2.sil

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,25 @@ bb0(%0 : @owned $Builtin.NativeObject):
4343
%2 = tuple ()
4444
return %2 : $()
4545
}
46+
47+
// CHECK-LABEL: sil [ossa] @test_movevalue_parsing : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
48+
// CHECK: bb0(%0 :
49+
// CHECK-NEXT: %1 = move_value %0 : $Builtin.NativeObject
50+
// CHECK-NEXT: return
51+
// CHECK-NEXT: } // end sil function 'test_movevalue_parsing'
52+
sil [ossa] @test_movevalue_parsing : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
53+
bb0(%0 : @owned $Builtin.NativeObject):
54+
%1 = move_value %0 : $Builtin.NativeObject
55+
return %1 : $Builtin.NativeObject
56+
}
57+
58+
// CHECK-LABEL: sil @test_movevalue_parsing_non_ossa : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
59+
// CHECK: bb0(%0 :
60+
// CHECK-NEXT: %1 = move_value %0 : $Builtin.NativeObject
61+
// CHECK-NEXT: return
62+
// CHECK-NEXT: } // end sil function 'test_movevalue_parsing_non_ossa'
63+
sil @test_movevalue_parsing_non_ossa : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
64+
bb0(%0 : $Builtin.NativeObject):
65+
%1 = move_value %0 : $Builtin.NativeObject
66+
return %1 : $Builtin.NativeObject
67+
}

test/SIL/Serialization/basic.sil

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ bb0(%0 : @owned $Builtin.NativeObject):
3030
return undef : $()
3131
}
3232

33+
// CHECK-LABEL: sil @test_movevalue_parsing_non_ossa : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
34+
// CHECK: bb0(%0 :
35+
// CHECK-NEXT: %1 = move_value %0 : $Builtin.NativeObject
36+
// CHECK-NEXT: return
37+
// CHECK-NEXT: } // end sil function 'test_movevalue_parsing_non_ossa'
38+
sil @test_movevalue_parsing_non_ossa : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
39+
bb0(%0 : $Builtin.NativeObject):
40+
%1 = move_value %0 : $Builtin.NativeObject
41+
return %1 : $Builtin.NativeObject
42+
}
43+
3344
class TestArrayStorage {
3445
@_hasStorage var count: Int32
3546
init()
@@ -59,6 +70,17 @@ bb0(%0 : @owned $(Builtin.NativeObject, Builtin.Int32), %1 : @owned $TestArray2)
5970
return %7 : $(Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Int32, TestArrayStorage)
6071
}
6172

73+
// CHECK-LABEL: sil [ossa] @test_movevalue_parsing : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
74+
// CHECK: bb0(%0 :
75+
// CHECK-NEXT: %1 = move_value %0 : $Builtin.NativeObject
76+
// CHECK-NEXT: return
77+
// CHECK-NEXT: } // end sil function 'test_movevalue_parsing'
78+
sil [ossa] @test_movevalue_parsing : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
79+
bb0(%0 : @owned $Builtin.NativeObject):
80+
%1 = move_value %0 : $Builtin.NativeObject
81+
return %1 : $Builtin.NativeObject
82+
}
83+
6284
// CHECK-LABEL: sil [serialized] [ossa] @test_subst_function_type_generic_context : $@convention(thin) <X, Y> (@guaranteed @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_1) -> () for <X, Y>) -> ()
6385
sil [serialized] [ossa] @test_subst_function_type_generic_context : $@convention(thin) <X, Y> (@guaranteed @callee_guaranteed @substituted <A, B> (@in A, @in B) -> () for <X, Y>) -> () {
6486
entry(%0 : @guaranteed $@callee_guaranteed @substituted <C, D> (@in C, @in D) -> () for <X, Y>):

utils/sil-mode.el

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@
124124
"unmanaged_retain_value" "unmanaged_release_value"
125125
"unmanaged_autorelease_value"
126126
"strong_copy_unowned_value" "strong_copy_unmanaged_value"
127-
"destructure_struct" "destructure_tuple")
127+
"destructure_struct" "destructure_tuple" "move_value")
128128
'words) . font-lock-keyword-face)
129129
;; Enums. *NOTE* We do not include enum itself here since enum is a
130130
;; swift declaration as well handled at the top.

0 commit comments

Comments
 (0)