Skip to content

Commit a5f8956

Browse files
eecksteinkavon
authored andcommitted
SIL: add the drop_deinit instruction
his instruction is a marker for a following destroy instruction to suppress the call of the move-only type's deinitializer.
1 parent a4b8af4 commit a5f8956

File tree

24 files changed

+144
-1
lines changed

24 files changed

+144
-1
lines changed

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,10 @@ final public class MoveValueInst : SingleValueInstruction, UnaryInstruction {
647647
public var fromValue: Value { operand.value }
648648
}
649649

650+
final public class DropDeinitInst : SingleValueInstruction, UnaryInstruction {
651+
public var fromValue: Value { operand.value }
652+
}
653+
650654
final public class StrongCopyUnownedValueInst : SingleValueInstruction, UnaryInstruction {}
651655

652656
final public class StrongCopyUnmanagedValueInst : SingleValueInstruction, UnaryInstruction {}

SwiftCompilerSources/Sources/SIL/Registration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ public func registerSILClasses() {
125125
register(ProjectBoxInst.self)
126126
register(CopyValueInst.self)
127127
register(MoveValueInst.self)
128+
register(DropDeinitInst.self)
128129
register(EndCOWMutationInst.self)
129130
register(ClassifyBridgeObjectInst.self)
130131
register(PartialApplyInst.self)

docs/SIL.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6117,6 +6117,29 @@ a type `T` into the move only value space.
61176117
The ``lexical`` attribute specifies that the value corresponds to a local
61186118
variable in the Swift source.
61196119

6120+
6121+
drop_deinit
6122+
```````````
6123+
6124+
::
6125+
6126+
sil-instruction ::= 'drop_deinit' sil-operand
6127+
6128+
%1 = drop_deinit %0 : $T
6129+
// T must be a move-only type
6130+
// %1 is an @owned T
6131+
%3 = drop_deinit %2 : $*T
6132+
// T must be a move-only type
6133+
// %2 has type *T
6134+
6135+
This instruction is a marker for a following destroy instruction to suppress
6136+
the call of the move-only type's deinitializer.
6137+
The instruction accepts an object or address type.
6138+
If its argument is an object type it takes in an `@owned T` and produces a new
6139+
`@owned T`. If its argument is an address type, it's an identity projection.
6140+
6141+
The instruction is only valid in ownership SIL.
6142+
61206143
release_value
61216144
`````````````
61226145

include/swift/SIL/MemAccessUtils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,7 @@ inline bool isAccessStorageIdentityCast(SingleValueInstruction *svi) {
16321632
// Simply pass-thru the incoming address.
16331633
case SILInstructionKind::MarkUninitializedInst:
16341634
case SILInstructionKind::MarkMustCheckInst:
1635+
case SILInstructionKind::DropDeinitInst:
16351636
case SILInstructionKind::MarkUnresolvedReferenceBindingInst:
16361637
case SILInstructionKind::MarkDependenceInst:
16371638
case SILInstructionKind::CopyValueInst:

include/swift/SIL/SILBuilder.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,14 @@ class SILBuilder {
13551355
operand, isLexical));
13561356
}
13571357

1358+
DropDeinitInst *createDropDeinit(SILLocation loc, SILValue operand) {
1359+
assert(getFunction().hasOwnership());
1360+
assert(!operand->getType().isTrivial(getFunction()) &&
1361+
"Should not be passing trivial values to this api.");
1362+
return insert(new (getModule()) DropDeinitInst(getSILDebugLocation(loc),
1363+
operand));
1364+
}
1365+
13581366
MarkUnresolvedMoveAddrInst *createMarkUnresolvedMoveAddr(SILLocation loc,
13591367
SILValue srcAddr,
13601368
SILValue takeAddr) {

include/swift/SIL/SILCloner.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1888,6 +1888,17 @@ void SILCloner<ImplClass>::visitMoveValueInst(MoveValueInst *Inst) {
18881888
recordClonedInstruction(Inst, MVI);
18891889
}
18901890

1891+
template <typename ImplClass>
1892+
void SILCloner<ImplClass>::visitDropDeinitInst(DropDeinitInst *Inst) {
1893+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1894+
if (!getBuilder().hasOwnership()) {
1895+
return recordFoldedValue(Inst, getOpValue(Inst->getOperand()));
1896+
}
1897+
auto *MVI = getBuilder().createDropDeinit(getOpLocation(Inst->getLoc()),
1898+
getOpValue(Inst->getOperand()));
1899+
recordClonedInstruction(Inst, MVI);
1900+
}
1901+
18911902
template <typename ImplClass>
18921903
void SILCloner<ImplClass>::visitMarkMustCheckInst(MarkMustCheckInst *Inst) {
18931904
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));

include/swift/SIL/SILInstruction.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8268,6 +8268,15 @@ class MoveValueInst
82688268
void removeIsLexical() { lexical = false; }
82698269
};
82708270

8271+
class DropDeinitInst
8272+
: public UnaryInstructionBase<SILInstructionKind::DropDeinitInst,
8273+
SingleValueInstruction> {
8274+
friend class SILBuilder;
8275+
8276+
DropDeinitInst(SILDebugLocation DebugLoc, SILValue operand)
8277+
: UnaryInstructionBase(DebugLoc, operand, operand->getType()) {}
8278+
};
8279+
82718280
/// Equivalent to a copy_addr to [init] except that it is used for diagnostics
82728281
/// and should not be pattern matched. During the diagnostic passes, the "move
82738282
/// function" checker for addresses always converts this to a copy_addr [init]

include/swift/SIL/SILNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,8 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
461461
// effects relative to other OSSA values like copy_value.
462462
SINGLE_VALUE_INST(MoveValueInst, move_value, SingleValueInstruction, None,
463463
DoesNotRelease)
464+
SINGLE_VALUE_INST(DropDeinitInst, drop_deinit, SingleValueInstruction, None,
465+
DoesNotRelease)
464466
// A canary value inserted by a SIL generating frontend to signal to the move
465467
// checker to check a specific value. Valid only in Raw SIL. The relevant
466468
// checkers should remove the mark_must_check instruction after successfully

lib/IRGen/IRGenSIL.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,10 @@ class IRGenSILFunction :
12221222
auto e = getLoweredExplosion(i->getOperand());
12231223
setLoweredExplosion(i, e);
12241224
}
1225+
void visitDropDeinitInst(DropDeinitInst *i) {
1226+
auto e = getLoweredExplosion(i->getOperand());
1227+
setLoweredExplosion(i, e);
1228+
}
12251229
void visitMarkMustCheckInst(MarkMustCheckInst *i) {
12261230
llvm_unreachable("Invalid in Lowered SIL");
12271231
}

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,12 @@ OperandOwnershipClassifier::visitStoreBorrowInst(StoreBorrowInst *i) {
455455
return OperandOwnership::TrivialUse;
456456
}
457457

458+
OperandOwnership
459+
OperandOwnershipClassifier::visitDropDeinitInst(DropDeinitInst *i) {
460+
return i->getType().isAddress() ? OperandOwnership::TrivialUse
461+
: OperandOwnership::ForwardingConsume;
462+
}
463+
458464
// Get the OperandOwnership for instantaneous apply, yield, and return uses.
459465
// This does not apply to uses that begin an explicit borrow scope in the
460466
// caller, such as begin_apply.

lib/SIL/IR/SILPrinter.cpp

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

1999+
void visitDropDeinitInst(DropDeinitInst *I) {
2000+
*this << getIDAndType(I->getOperand());
2001+
}
2002+
19992003
void visitMarkMustCheckInst(MarkMustCheckInst *I) {
20002004
using CheckKind = MarkMustCheckInst::CheckKind;
20012005
switch (I->getCheckKind()) {

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,10 @@ ValueOwnershipKind ValueOwnershipKindClassifier::visitLoadInst(LoadInst *LI) {
354354
llvm_unreachable("Unhandled LoadOwnershipQualifier in switch.");
355355
}
356356

357+
ValueOwnershipKind ValueOwnershipKindClassifier::visitDropDeinitInst(DropDeinitInst *ddi) {
358+
return ddi->getType().isAddress() ? OwnershipKind::None : OwnershipKind::Owned;
359+
}
360+
357361
ValueOwnershipKind
358362
ValueOwnershipKindClassifier::visitPartialApplyInst(PartialApplyInst *PA) {
359363
// partial_apply instructions are modeled as creating an owned value during

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3698,6 +3698,15 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
36983698
break;
36993699
}
37003700

3701+
case SILInstructionKind::DropDeinitInst: {
3702+
if (parseTypedValueRef(Val, B))
3703+
return true;
3704+
if (parseSILDebugLocation(InstLoc, B))
3705+
return true;
3706+
ResultVal = B.createDropDeinit(InstLoc, Val);
3707+
break;
3708+
}
3709+
37013710
case SILInstructionKind::MarkMustCheckInst: {
37023711
StringRef AttrName;
37033712
if (!parseSILOptional(AttrName, *this)) {

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
441441
case SILInstructionKind::ValueToBridgeObjectInst:
442442
case SILInstructionKind::MarkDependenceInst:
443443
case SILInstructionKind::MoveValueInst:
444+
case SILInstructionKind::DropDeinitInst:
444445
case SILInstructionKind::MarkMustCheckInst:
445446
case SILInstructionKind::MarkUnresolvedReferenceBindingInst:
446447
case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst:

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,6 +1866,7 @@ AccessPathDefUseTraversal::visitSingleValueUser(SingleValueInstruction *svi,
18661866
return IgnoredUse;
18671867
}
18681868

1869+
case SILInstructionKind::DropDeinitInst:
18691870
case SILInstructionKind::MarkMustCheckInst: {
18701871
// Mark must check goes on the project_box, so it isn't a ref.
18711872
assert(!dfs.isRef());

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5921,6 +5921,14 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
59215921
"Result and operand must have the same type, today.");
59225922
}
59235923

5924+
void checkDropDeinitInst(DropDeinitInst *ddi) {
5925+
require(ddi->getType() == ddi->getOperand()->getType(),
5926+
"Result and operand must have the same type.");
5927+
require(ddi->getType().isMoveOnlyNominalType(),
5928+
"drop_deinit only allowed for move-only types");
5929+
require(F.hasOwnership(), "drop_deinit only allowed in OSSA");
5930+
}
5931+
59245932
void checkMarkMustCheckInst(MarkMustCheckInst *i) {
59255933
require(i->getModule().getStage() == SILStage::Raw,
59265934
"Only valid in Raw SIL! Should have been eliminated by /some/ "

lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ struct OwnershipModelEliminatorVisitor
141141
eraseInstructionAndRAUW(mvi, mvi->getOperand());
142142
return true;
143143
}
144+
bool visitDropDeinitInst(DropDeinitInst *ddi) {
145+
eraseInstructionAndRAUW(ddi, ddi->getOperand());
146+
return true;
147+
}
144148
bool visitBeginBorrowInst(BeginBorrowInst *bbi) {
145149
eraseInstructionAndRAUW(bbi, bbi->getOperand());
146150
return true;

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::CopyValueInst:
205205
case SILInstructionKind::ExplicitCopyValueInst:
206206
case SILInstructionKind::MoveValueInst:
207+
case SILInstructionKind::DropDeinitInst:
207208
case SILInstructionKind::MarkMustCheckInst:
208209
case SILInstructionKind::MarkUnresolvedReferenceBindingInst:
209210
case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst:

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
876876
case SILInstructionKind::BindMemoryInst:
877877
case SILInstructionKind::RebindMemoryInst:
878878
case SILInstructionKind::MoveValueInst:
879+
case SILInstructionKind::DropDeinitInst:
879880
case SILInstructionKind::MarkMustCheckInst:
880881
case SILInstructionKind::MarkUnresolvedReferenceBindingInst:
881882
case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst:

lib/Serialization/DeserializeSIL.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,6 +2204,14 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
22042204
break;
22052205
}
22062206

2207+
case SILInstructionKind::DropDeinitInst: {
2208+
auto Ty = MF->getType(TyID);
2209+
ResultInst = Builder.createDropDeinit(
2210+
Loc,
2211+
getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)));
2212+
break;
2213+
}
2214+
22072215
case SILInstructionKind::MarkUnresolvedReferenceBindingInst: {
22082216
using Kind = MarkUnresolvedReferenceBindingInst::Kind;
22092217
auto ty = MF->getType(TyID);

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 781; // compound introduced names
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 782; // drop_deinit instruction
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///

lib/Serialization/SerializeSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
14821482
case SILInstructionKind::CopyValueInst:
14831483
case SILInstructionKind::ExplicitCopyValueInst:
14841484
case SILInstructionKind::MoveValueInst:
1485+
case SILInstructionKind::DropDeinitInst:
14851486
case SILInstructionKind::MarkUnresolvedReferenceBindingInst:
14861487
case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst:
14871488
case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst:

test/SIL/Parser/basic.sil

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ class Class2 {
4848
init()
4949
}
5050

51+
@_moveOnly struct MoveOnlyStruct {
52+
@_hasStorage var i: Int
53+
deinit
54+
}
55+
56+
5157
sil @type_ref1 : $(Class1, Int) -> () // CHECK-LABEL: sil @type_ref1 : $@convention(thin) (Class1, Int)
5258

5359
// Instructions
@@ -1659,6 +1665,16 @@ bb0(%0 : @guaranteed $Builtin.NativeObject):
16591665
return undef : $()
16601666
}
16611667

1668+
// CHECK-LABEL: sil [ossa] @test_drop_deinit :
1669+
sil [ossa] @test_drop_deinit : $@convention(thin) (@owned MoveOnlyStruct) -> () {
1670+
bb0(%0 : @owned $MoveOnlyStruct):
1671+
// CHECK: drop_deinit %0 : $MoveOnlyStruct
1672+
%1 = drop_deinit %0 : $MoveOnlyStruct
1673+
destroy_value %1 : $MoveOnlyStruct
1674+
%3 = tuple ()
1675+
return %3 : $()
1676+
}
1677+
16621678
sil @test_destructure_struct_tuple : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.Int32), @owned TestArray2) -> @owned (Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Int32, TestArrayStorage) {
16631679
bb0(%0 : $(Builtin.NativeObject, Builtin.Int32), %1 : $TestArray2):
16641680
(%2, %3) = destructure_tuple %0 : $(Builtin.NativeObject, Builtin.Int32)

test/SIL/Serialization/basic.sil

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ struct Int32 {
2323

2424
struct EmptyStruct {}
2525

26+
@_moveOnly struct MoveOnlyStruct {
27+
@_hasStorage var i: Int32
28+
deinit
29+
}
30+
2631
// CHECK-LABEL: sil @async_test : $@convention(thin) @async
2732
sil @async_test : $@async () -> () {
2833
bb0:
@@ -44,6 +49,17 @@ bb0(%0 : @owned $(Builtin.NativeObject, Builtin.Int32), %1 : @owned $TestArray2)
4449
return %7 : $(Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Int32, TestArrayStorage)
4550
}
4651

52+
// CHECK-LABEL: sil [ossa] @test_drop_deinit :
53+
// CHECK: %1 = drop_deinit %0 : $MoveOnlyStruct
54+
// CHECK-LABEL: } // end sil function 'test_drop_deinit'
55+
sil [ossa] @test_drop_deinit : $@convention(thin) (@owned MoveOnlyStruct) -> () {
56+
bb0(%0 : @owned $MoveOnlyStruct):
57+
%1 = drop_deinit %0 : $MoveOnlyStruct
58+
destroy_value %1 : $MoveOnlyStruct
59+
%3 = tuple ()
60+
return %3 : $()
61+
}
62+
4763
sil @test_empty_destructure : $@convention(thin) () -> () {
4864
bb0:
4965
%0 = struct $EmptyStruct()

0 commit comments

Comments
 (0)