Skip to content

Commit c1bcb0b

Browse files
committed
SIL: add new instruction set_deallocating
It will be used by the ReleaseDevirtualizer before calling the deallocator. So far, this is NFC.
1 parent e1b9488 commit c1bcb0b

File tree

19 files changed

+134
-5
lines changed

19 files changed

+134
-5
lines changed

Diff for: docs/SIL.rst

+15
Original file line numberDiff line numberDiff line change
@@ -2300,6 +2300,21 @@ zero, the object is destroyed and ``@weak`` references are cleared. When both
23002300
its strong and unowned reference counts reach zero, the object's memory is
23012301
deallocated.
23022302

2303+
set_deallocating
2304+
````````````````
2305+
::
2306+
2307+
set_deallocating %0 : $T
2308+
// $T must be a reference type.
2309+
2310+
Explicitly sets the state of the object referenced by ``%0`` to deallocated.
2311+
This is the same operation what's done by a strong_release immediately before
2312+
it calls the deallocator of the object.
2313+
2314+
It is expected that the strong reference count of the object is one.
2315+
Furthermore, no other thread may increment the strong reference count during
2316+
execution of this instruction.
2317+
23032318
strong_retain_unowned
23042319
`````````````````````
23052320
::

Diff for: include/swift/Runtime/RuntimeFunctions.def

+7
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,13 @@ FUNCTION_WITH_GLOBAL_SYMBOL_AND_IMPL(NativeStrongReleaseN, swift_release_n,
167167
ARGS(RefCountedPtrTy, Int32Ty),
168168
ATTRS(NoUnwind))
169169

170+
// void swift_setDeallocating(void *ptr);
171+
FUNCTION(NativeSetDeallocating, swift_setDeallocating,
172+
DefaultCC,
173+
RETURNS(VoidTy),
174+
ARGS(RefCountedPtrTy),
175+
ATTRS(NoUnwind))
176+
170177
// void swift_unknownRetain_n(void *ptr, int32_t n);
171178
FUNCTION(UnknownRetainN, swift_unknownRetain_n,
172179
DefaultCC,

Diff for: include/swift/SIL/SILBuilder.h

+6
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,12 @@ class SILBuilder {
674674
getSILDebugLocation(Loc), operand));
675675
}
676676

677+
SetDeallocatingInst *createSetDeallocating(SILLocation Loc,
678+
SILValue operand) {
679+
return insert(new (F.getModule()) SetDeallocatingInst(
680+
getSILDebugLocation(Loc), operand));
681+
}
682+
677683
StructInst *createStruct(SILLocation Loc, SILType Ty,
678684
ArrayRef<SILValue> Elements) {
679685
return insert(

Diff for: include/swift/SIL/SILCloner.h

+9
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,15 @@ SILCloner<ImplClass>::visitAutoreleaseValueInst(AutoreleaseValueInst *Inst) {
10501050
getOpValue(Inst->getOperand())));
10511051
}
10521052

1053+
template<typename ImplClass>
1054+
void
1055+
SILCloner<ImplClass>::visitSetDeallocatingInst(SetDeallocatingInst *Inst) {
1056+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1057+
doPostProcess(Inst,
1058+
getBuilder().createSetDeallocating(getOpLocation(Inst->getLoc()),
1059+
getOpValue(Inst->getOperand())));
1060+
}
1061+
10531062
template<typename ImplClass>
10541063
void
10551064
SILCloner<ImplClass>::visitStructInst(StructInst *Inst) {

Diff for: include/swift/SIL/SILInstruction.h

+14
Original file line numberDiff line numberDiff line change
@@ -2322,6 +2322,20 @@ class AutoreleaseValueInst
23222322
: UnaryInstructionBase(DebugLoc, operand) {}
23232323
};
23242324

2325+
/// SetDeallocatingInst - Sets the operand in deallocating state.
2326+
///
2327+
/// This is the same operation what's done by a strong_release immediately
2328+
/// before it calls the deallocator of the object.
2329+
class SetDeallocatingInst
2330+
: public UnaryInstructionBase<ValueKind::SetDeallocatingInst,
2331+
RefCountingInst,
2332+
/*HasValue*/ false> {
2333+
friend class SILBuilder;
2334+
2335+
SetDeallocatingInst(SILDebugLocation DebugLoc, SILValue operand)
2336+
: UnaryInstructionBase(DebugLoc, operand) {}
2337+
};
2338+
23252339
/// StrongPinInst - Ensure that the operand is retained and pinned, if
23262340
/// not by this operation then by some enclosing pin.
23272341
///

Diff for: include/swift/SIL/SILNodes.def

+2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
123123
MayRelease)
124124
INST(RetainValueInst, RefCountingInst, MayHaveSideEffects, DoesNotRelease)
125125
INST(ReleaseValueInst, RefCountingInst, MayHaveSideEffects, MayRelease)
126+
INST(SetDeallocatingInst, RefCountingInst, MayHaveSideEffects,
127+
DoesNotRelease)
126128
INST(AutoreleaseValueInst, RefCountingInst, MayHaveSideEffects,
127129
DoesNotRelease)
128130
VALUE_RANGE(RefCountingInst, StrongRetainInst, AutoreleaseValueInst)

Diff for: include/swift/Serialization/ModuleFormat.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// describe what change you made. The content of this comment isn't important;
5555
/// it just ensures a conflict if two people change the module format.
5656
/// describe what change you made.
57-
const uint16_t VERSION_MINOR = 240; // Last change: @_cdecl
57+
const uint16_t VERSION_MINOR = 241; // Last change: set_deallocating instruction
5858

5959
using DeclID = PointerEmbeddedInt<unsigned, 31>;
6060
using DeclIDField = BCFixed<31>;

Diff for: lib/IRGen/GenHeap.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,11 @@ void IRGenFunction::emitNativeStrongRelease(llvm::Value *value) {
11121112
emitUnaryRefCountCall(*this, IGM.getNativeStrongReleaseFn(), value);
11131113
}
11141114

1115+
void IRGenFunction::emitNativeSetDeallocating(llvm::Value *value) {
1116+
if (doesNotRequireRefCounting(value)) return;
1117+
emitUnaryRefCountCall(*this, IGM.getNativeSetDeallocatingFn(), value);
1118+
}
1119+
11151120
void IRGenFunction::emitNativeUnownedInit(llvm::Value *value,
11161121
Address dest) {
11171122
dest = Builder.CreateStructGEP(dest, 0, Size(0));

Diff for: lib/IRGen/IRGenFunction.h

+1
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ class IRGenFunction {
274274
void emitNativeStrongInit(llvm::Value *value, Address addr);
275275
void emitNativeStrongRetain(llvm::Value *value);
276276
void emitNativeStrongRelease(llvm::Value *value);
277+
void emitNativeSetDeallocating(llvm::Value *value);
277278
// - unowned references
278279
void emitNativeUnownedRetain(llvm::Value *value);
279280
void emitNativeUnownedRelease(llvm::Value *value);

Diff for: lib/IRGen/IRGenSIL.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,7 @@ class IRGenSILFunction :
733733
void visitRetainValueInst(RetainValueInst *i);
734734
void visitReleaseValueInst(ReleaseValueInst *i);
735735
void visitAutoreleaseValueInst(AutoreleaseValueInst *i);
736+
void visitSetDeallocatingInst(SetDeallocatingInst *i);
736737
void visitStructInst(StructInst *i);
737738
void visitTupleInst(TupleInst *i);
738739
void visitEnumInst(EnumInst *i);
@@ -3030,6 +3031,40 @@ void IRGenSILFunction::visitAutoreleaseValueInst(swift::AutoreleaseValueInst *i)
30303031
emitObjCAutoreleaseCall(val);
30313032
}
30323033

3034+
void IRGenSILFunction::visitSetDeallocatingInst(SetDeallocatingInst *i) {
3035+
auto *ARI = dyn_cast<AllocRefInst>(i->getOperand());
3036+
if (ARI && StackAllocs.count(ARI)) {
3037+
// A small peep-hole optimization: If the operand is allocated on stack and
3038+
// there is no "significant" code between the set_deallocating and the final
3039+
// dealloc_ref, the set_deallocating is not required.
3040+
// %0 = alloc_ref [stack]
3041+
// ...
3042+
// set_deallocating %0 // not needed
3043+
// // code which does not depend on the RC_DEALLOCATING_FLAG flag.
3044+
// dealloc_ref %0 // not needed (stems from the inlined deallocator)
3045+
// ...
3046+
// dealloc_ref [stack] %0
3047+
SILBasicBlock::iterator Iter(i);
3048+
SILBasicBlock::iterator End = i->getParent()->end();
3049+
for (++Iter; Iter != End; ++Iter) {
3050+
SILInstruction *I = &*Iter;
3051+
if (auto *DRI = dyn_cast<DeallocRefInst>(I)) {
3052+
if (DRI->getOperand() == ARI) {
3053+
// The set_deallocating is followed by a dealloc_ref -> we can ignore
3054+
// it.
3055+
return;
3056+
}
3057+
}
3058+
// Assume that any instruction with side-effects may depend on the
3059+
// RC_DEALLOCATING_FLAG flag.
3060+
if (I->mayHaveSideEffects())
3061+
break;
3062+
}
3063+
}
3064+
Explosion lowered = getLoweredExplosion(i->getOperand());
3065+
emitNativeSetDeallocating(lowered.claimNext());
3066+
}
3067+
30333068
void IRGenSILFunction::visitReleaseValueInst(swift::ReleaseValueInst *i) {
30343069
Explosion in = getLoweredExplosion(i->getOperand());
30353070
cast<LoadableTypeInfo>(getTypeInfo(i->getOperand()->getType()))

Diff for: lib/Parse/ParseSIL.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,7 @@ bool SILParser::parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc,
11621162
.Case("select_enum", ValueKind::SelectEnumInst)
11631163
.Case("select_enum_addr", ValueKind::SelectEnumAddrInst)
11641164
.Case("select_value", ValueKind::SelectValueInst)
1165+
.Case("set_deallocating", ValueKind::SetDeallocatingInst)
11651166
.Case("store", ValueKind::StoreInst)
11661167
.Case("store_unowned", ValueKind::StoreUnownedInst)
11671168
.Case("store_weak", ValueKind::StoreWeakInst)
@@ -1877,6 +1878,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
18771878
UNARY_INSTRUCTION(IsUniqueOrPinned)
18781879
UNARY_INSTRUCTION(DestroyAddr)
18791880
UNARY_INSTRUCTION(AutoreleaseValue)
1881+
UNARY_INSTRUCTION(SetDeallocating)
18801882
UNARY_INSTRUCTION(ReleaseValue)
18811883
UNARY_INSTRUCTION(RetainValue)
18821884
UNARY_INSTRUCTION(Load)

Diff for: lib/SIL/SILPrinter.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,10 @@ class SILPrinter : public SILVisitor<SILPrinter> {
11761176
*this << "autorelease_value " << getIDAndType(I->getOperand());
11771177
}
11781178

1179+
void visitSetDeallocatingInst(SetDeallocatingInst *I) {
1180+
*this << "set_deallocating " << getIDAndType(I->getOperand());
1181+
}
1182+
11791183
void visitStructInst(StructInst *SI) {
11801184
*this << "struct " << SI->getType() << " (";
11811185
interleave(SI->getElements(),

Diff for: lib/SIL/SILVerifier.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,13 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
11631163
"Source value must be a reference type or optional thereof");
11641164
}
11651165

1166+
void checkSetDeallocatingInst(SetDeallocatingInst *I) {
1167+
require(I->getOperand()->getType().isObject(),
1168+
"Source value should be an object value");
1169+
require(I->getOperand()->getType().hasRetainablePointerRepresentation(),
1170+
"Source value must be a reference type");
1171+
}
1172+
11661173
void checkCopyBlockInst(CopyBlockInst *I) {
11671174
require(I->getOperand()->getType().isBlockPointerCompatible(),
11681175
"operand of copy_block should be a block");

Diff for: lib/SILOptimizer/Utils/SILInliner.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) {
368368
case ValueKind::StoreWeakInst:
369369
case ValueKind::StrongPinInst:
370370
case ValueKind::StrongReleaseInst:
371+
case ValueKind::SetDeallocatingInst:
371372
case ValueKind::StrongRetainInst:
372373
case ValueKind::StrongRetainUnownedInst:
373374
case ValueKind::StrongUnpinInst:

Diff for: lib/Serialization/DeserializeSIL.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
11711171
UNARY_INSTRUCTION(RetainValue)
11721172
UNARY_INSTRUCTION(ReleaseValue)
11731173
UNARY_INSTRUCTION(AutoreleaseValue)
1174+
UNARY_INSTRUCTION(SetDeallocating)
11741175
UNARY_INSTRUCTION(DeinitExistentialAddr)
11751176
UNARY_INSTRUCTION(DestroyAddr)
11761177
UNARY_INSTRUCTION(IsNonnull)

Diff for: lib/Serialization/SerializeSIL.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
876876
case ValueKind::RetainValueInst:
877877
case ValueKind::ReleaseValueInst:
878878
case ValueKind::AutoreleaseValueInst:
879+
case ValueKind::SetDeallocatingInst:
879880
case ValueKind::DeallocStackInst:
880881
case ValueKind::DeallocRefInst:
881882
case ValueKind::DeinitExistentialAddrInst:

Diff for: test/SIL/Parser/basic.sil

+9
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,15 @@ bb0(%0 : $X):
10631063
// CHECK-NEXT: return [[T0]] : $X
10641064
}
10651065

1066+
// CHECK-LABEL: sil @test_set_deallocating
1067+
sil @test_set_deallocating : $X -> X {
1068+
bb0(%0 : $X):
1069+
set_deallocating %0 : $X
1070+
return %0 : $X
1071+
// CHECK: set_deallocating [[T0]] : $X
1072+
// CHECK-NEXT: return [[T0]] : $X
1073+
}
1074+
10661075
struct GenericStruct<T> {
10671076
var x : T
10681077
}

Diff for: test/Serialization/Inputs/def_basic.sil

+13-3
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,15 @@ bb0(%0 : $X):
939939
// CHECK-NEXT: return [[T0]] : $X
940940
}
941941

942+
// CHECK-LABEL: sil public_external [fragile] @test_set_deallocating
943+
sil [fragile] @test_set_deallocating : $@convention(thin) (X) -> (X) {
944+
bb0(%0 : $X):
945+
set_deallocating %0 : $X
946+
return %0 : $X
947+
// CHECK: set_deallocating [[T0:%.*]] : $X
948+
// CHECK-NEXT: return [[T0]] : $X
949+
}
950+
942951
public func serialize_all() {
943952
}
944953

@@ -1337,7 +1346,8 @@ bb0:
13371346
%113 = function_ref @test_dynamic_lookup_br : $@convention(thin) (AnyObject) -> ()
13381347
%115 = function_ref @test_mark_fn_escape : $@convention(thin) () -> ()
13391348
%117 = function_ref @test_copy_release_value : $@convention(thin) (X) -> (X)
1340-
%118 = function_ref @cond_fail_test : $@convention(thin) Builtin.Int1 -> ()
1349+
%118 = function_ref @test_set_deallocating : $@convention(thin) (X) -> (X)
1350+
%119 = function_ref @cond_fail_test : $@convention(thin) Builtin.Int1 -> ()
13411351

13421352
%124 = function_ref @block_storage_type : $@convention(thin) Int -> @convention(block) () -> ()
13431353
%127 = function_ref @bitcasts : $@convention(thin) (@owned Class1) -> @owned (Class2, Int)
@@ -1354,7 +1364,7 @@ bb0:
13541364
%150 = function_ref @a_reabstraction_thunk: $@convention(thin) () -> ()
13551365
%151 = function_ref @a_regular_thunk: $@convention(thin) () -> ()
13561366

1357-
%119 = tuple ()
1358-
return %119 : $()
1367+
%r = tuple ()
1368+
return %r : $()
13591369
}
13601370

Diff for: utils/vim/syntax/sil.vim

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ syn keyword swiftKeyword getter setter allocator initializer enumelt destroyer g
2828
syn keyword swiftKeyword alloc_global alloc_stack alloc_ref alloc_ref_dynamic alloc_box alloc_existential_box alloc_value_buffer dealloc_stack dealloc_box dealloc_existential_box dealloc_ref dealloc_partial_ref dealloc_value_buffer skipwhite
2929
syn keyword swiftKeyword debug_value debug_value_addr skipwhite
3030
syn keyword swiftKeyword load load_unowned store assign mark_uninitialized mark_function_escape copy_addr destroy_addr index_addr index_raw_pointer to skipwhite
31-
syn keyword swiftKeyword strong_retain strong_release strong_retain_unowned ref_to_unowned unowned_to_ref unowned_retain unowned_release load_weak store_unowned store_weak fix_lifetime autorelease_value is_unique is_unique_or_pinned strong_pin strong_unpin skipwhite
31+
syn keyword swiftKeyword strong_retain strong_release strong_retain_unowned ref_to_unowned unowned_to_ref unowned_retain unowned_release load_weak store_unowned store_weak fix_lifetime autorelease_value set_deallocating is_unique is_unique_or_pinned strong_pin strong_unpin skipwhite
3232
syn keyword swiftKeyword function_ref integer_literal float_literal string_literal global_addr skipwhite
3333
syn keyword swiftKeyword class_method super_method witness_method dynamic_method skipwhite
3434
syn keyword swiftKeyword partial_apply builtin skipwhite

0 commit comments

Comments
 (0)