Skip to content

Commit c841858

Browse files
authored
Merge pull request #70444 from eeckstein/deinit-devirt-part2
deinit-devirtualization: completely de-compose non-copyable destroys
2 parents f113eaa + 60baf11 commit c841858

File tree

10 files changed

+39
-32
lines changed

10 files changed

+39
-32
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/Devirtualization.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func devirtualizeDeinits(of destroy: DestroyAddrInst, _ context: some MutatingCo
3030

3131
private func devirtualize(destroy: some DevirtualizableDestroy, _ context: some MutatingContext) -> Bool {
3232
let type = destroy.type
33-
guard type.isMoveOnly && type.selfOrAnyFieldHasValueDeinit(in: destroy.parentFunction) else {
33+
if !type.isMoveOnly {
3434
return true
3535
}
3636
precondition(type.isNominal, "non-copyable non-nominal types not supported, yet")
@@ -47,9 +47,12 @@ private func devirtualize(destroy: some DevirtualizableDestroy, _ context: some
4747
// the struct fields or enum cases.
4848
if type.isStruct {
4949
result = destroy.devirtualizeStructFields(context)
50-
} else {
51-
precondition(type.isEnum, "unknown nominal value type")
50+
} else if type.isEnum {
5251
result = destroy.devirtualizeEnumPayloads(context)
52+
} else {
53+
precondition(type.isClass, "unknown non-copyable type")
54+
// A class reference cannot be further de-composed.
55+
return true
5356
}
5457
}
5558
context.erase(instruction: destroy)

SwiftCompilerSources/Sources/SIL/Type.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
4343
return bridged.isReferenceCounted(function.bridged)
4444
}
4545

46-
public func selfOrAnyFieldHasValueDeinit(in function: Function) -> Bool {
47-
return bridged.selfOrAnyFieldHasValueDeinit(function.bridged)
48-
}
49-
5046
public var isUnownedStorageType: Bool {
5147
return bridged.isUnownedStorageType()
5248
}

include/swift/SIL/SILBridging.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ struct BridgedType {
115115
BRIDGED_INLINE bool isValueTypeWithDeinit() const;
116116
BRIDGED_INLINE bool isLoadable(BridgedFunction f) const;
117117
BRIDGED_INLINE bool isReferenceCounted(BridgedFunction f) const;
118-
BRIDGED_INLINE bool selfOrAnyFieldHasValueDeinit(BridgedFunction f) const;
119118
BRIDGED_INLINE bool isUnownedStorageType() const;
120119
BRIDGED_INLINE bool hasArchetype() const;
121120
BRIDGED_INLINE bool isNominalOrBoundGenericNominal() const;

include/swift/SIL/SILBridgingImpl.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,6 @@ bool BridgedType::isReferenceCounted(BridgedFunction f) const {
8888
return unbridged().isReferenceCounted(f.getFunction());
8989
}
9090

91-
bool BridgedType::selfOrAnyFieldHasValueDeinit(BridgedFunction f) const {
92-
swift::SILType contextType = unbridged().hasTypeParameter() ? f.getFunction()->mapTypeIntoContext(unbridged())
93-
: unbridged();
94-
return f.getFunction()->getTypeLowering(contextType).selfOrAnyFieldHasValueDeinit();
95-
}
96-
9791
bool BridgedType::isUnownedStorageType() const {
9892
return unbridged().isUnownedStorageType();
9993
}

include/swift/SIL/TypeLowering.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,10 @@ class TypeLowering {
192192
InfiniteFlag = 1 << 5,
193193
HasRawPointerFlag = 1 << 6,
194194
LexicalFlag = 1 << 7,
195-
HasValueDeinitFlag = 1 << 8,
196195
};
197196
// clang-format on
198197

199-
uint16_t Flags;
198+
uint8_t Flags;
200199
public:
201200
/// Construct a default RecursiveProperties, which corresponds to
202201
/// a trivial, loadable, fixed-layout type.
@@ -273,9 +272,6 @@ class TypeLowering {
273272
IsLexical_t isLexical() const {
274273
return IsLexical_t((Flags & LexicalFlag) != 0);
275274
}
276-
bool hasValueDeinit() const {
277-
return (Flags & HasValueDeinitFlag) != 0;
278-
}
279275

280276
void setNonTrivial() { Flags |= NonTrivialFlag; }
281277
void setNonFixedABI() { Flags |= NonFixedABIFlag; }
@@ -289,7 +285,6 @@ class TypeLowering {
289285
void setLexical(IsLexical_t isLexical) {
290286
Flags = (Flags & ~LexicalFlag) | (isLexical ? LexicalFlag : 0);
291287
}
292-
void setHasValueDeinit() { Flags |= HasValueDeinitFlag; }
293288
};
294289

295290
private:
@@ -368,10 +363,6 @@ class TypeLowering {
368363
return Properties.isOrContainsRawPointer();
369364
}
370365

371-
bool selfOrAnyFieldHasValueDeinit() const {
372-
return Properties.hasValueDeinit();
373-
}
374-
375366
/// Returns true if the type is a scalar reference-counted reference, which
376367
/// can be retained and released.
377368
bool isReferenceCounted() const {

lib/SIL/IR/TypeLowering.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,9 +2369,6 @@ namespace {
23692369
properties.setLexical(IsLexical);
23702370
return handleMoveOnlyAddressOnly(structType, properties);
23712371
}
2372-
if (D->getValueTypeDestructor()) {
2373-
properties.setHasValueDeinit();
2374-
}
23752372

23762373
auto subMap = structType->getContextSubstitutionMap(&TC.M, D);
23772374

@@ -2454,9 +2451,6 @@ namespace {
24542451
return new (TC) LoadableEnumTypeLowering(enumType, properties,
24552452
Expansion);
24562453
}
2457-
if (D->getValueTypeDestructor()) {
2458-
properties.setHasValueDeinit();
2459-
}
24602454

24612455
auto subMap = enumType->getContextSubstitutionMap(&TC.M, D);
24622456

test/SILOptimizer/devirt_deinits.sil

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ import SwiftShims
4747
deinit
4848
}
4949

50+
@_moveOnly struct S5 {
51+
@_hasStorage let a: Int
52+
@_hasStorage let b: AnyObject
53+
}
54+
5055
// CHECK-LABEL: sil [ossa] @test_simple_struct :
5156
// CHECK: [[D:%.*]] = function_ref @s1_deinit
5257
// CHECK: apply [[D]](%0) : $@convention(method) (@owned S1) -> ()
@@ -72,6 +77,17 @@ bb0(%0 : @owned $StrWithoutDeinit):
7277
return %r : $()
7378
}
7479

80+
// CHECK-LABEL: sil [ossa] @test_no_deinit :
81+
// CHECK: ({{%.*}}, [[S2:%.*]]) = destructure_struct %0
82+
// CHECK-NEXT: destroy_value [[S2]]
83+
// CHECK-NEXT: tuple ()
84+
// CHECK: } // end sil function 'test_no_deinit'
85+
sil [ossa] @test_no_deinit : $@convention(thin) (@owned S5) -> () {
86+
bb0(%0 : @owned $S5):
87+
destroy_value %0 : $S5
88+
%r = tuple()
89+
return %r : $()
90+
}
7591
// CHECK-LABEL: sil [ossa] @test_indirect_deinit_arg :
7692
// CHECK: [[D:%.*]] = function_ref @s3_deinit
7793
// CHECK: [[S:%.*]] = alloc_stack $S3<Int>

test/SILOptimizer/moveonly_deinit_devirtualization.sil

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,9 @@ bb2(%4 : $Builtin.Int32):
284284

285285

286286
bb3(%6 : @owned $(Klass, Klass)):
287-
destroy_value %6 : $(Klass, Klass)
287+
(%7, %8) = destructure_tuple %6 : $(Klass, Klass)
288+
destroy_value %7 : $Klass
289+
destroy_value %8 : $Klass
288290
br bb6
289291

290292
bb4(%9 : $(Builtin.Int64, Builtin.Int64)):

test/SILOptimizer/moveonly_deinit_devirtualization_library_evolution.sil

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,10 @@ bb2:
285285

286286
bb3:
287287
%6 = unchecked_take_enum_data_addr %0 : $*NonTrivialMoveOnlyEnum, #NonTrivialMoveOnlyEnum.third
288-
destroy_addr %6 : $*(Klass, Klass)
288+
%7 = tuple_element_addr %6 : $*(Klass, Klass), 0
289+
%8 = tuple_element_addr %6 : $*(Klass, Klass), 1
290+
destroy_addr %7 : $*Klass
291+
destroy_addr %8 : $*Klass
289292
br bb6
290293

291294
bb4:

test/SILOptimizer/performance-annotations.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,3 +471,12 @@ func useOfExistentialNoRuntime() -> P {
471471
Str(x: 1) // expected-error {{Using type 'any P' can cause metadata allocation or locks}}
472472
}
473473

474+
public struct NonCopyable: ~Copyable {
475+
var value: Int
476+
}
477+
478+
@_noAllocation
479+
public func testNonCopyable(_ foo: consuming NonCopyable) {
480+
let _ = foo.value
481+
}
482+

0 commit comments

Comments
 (0)