Skip to content

Commit b90cd31

Browse files
committed
Fix optimization of checked_cast_addr_br to checked_cast_br
1 parent 2e8f74f commit b90cd31

File tree

5 files changed

+96
-7
lines changed

5 files changed

+96
-7
lines changed

include/swift/SIL/DynamicCasts.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ bool canSILUseScalarCheckedCastInstructions(SILModule &M,
9797
CanType sourceType,
9898
CanType targetType);
9999

100+
/// Can the given cast be performed by the scalar checked-cast instructions in
101+
/// the current SIL stage, or do we need to use the indirect instructions?
102+
bool canOptimizeToScalarCheckedCastInstructions(
103+
SILFunction *func, CanType sourceType, CanType targetType,
104+
CastConsumptionKind consumption);
105+
100106
/// Can the given cast be performed by the scalar checked-cast
101107
/// instructions at IRGen, or do we need to use the indirect instructions?
102108
bool canIRGenUseScalarCheckedCastInstructions(SILModule &M,

include/swift/SIL/TypeSubstCloner.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,9 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
244244
auto FalseCount = inst->getFalseBBCount();
245245

246246
// Try to use the scalar cast instruction.
247-
if (canSILUseScalarCheckedCastInstructions(B.getModule(),
248-
sourceType, targetType)) {
247+
if (canOptimizeToScalarCheckedCastInstructions(
248+
&B.getFunction(), sourceType, targetType,
249+
inst->getConsumptionKind())) {
249250
emitIndirectConditionalCastWithScalar(
250251
B, SwiftMod, loc, inst->getCheckedCastOptions(),
251252
inst->getConsumptionKind(), src, sourceType, dest,

lib/SIL/Utils/DynamicCasts.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,27 @@ bool swift::canSILUseScalarCheckedCastInstructions(SILModule &M,
13551355
targetFormalType);
13561356
}
13571357

1358+
bool swift::canOptimizeToScalarCheckedCastInstructions(
1359+
SILFunction *func, CanType sourceType, CanType targetType,
1360+
CastConsumptionKind consumption) {
1361+
if (!canSILUseScalarCheckedCastInstructions(func->getModule(), sourceType,
1362+
targetType)) {
1363+
return false;
1364+
}
1365+
1366+
if (consumption == CastConsumptionKind::CopyOnSuccess) {
1367+
// If it's a copy-on-success cast, check whether the cast preserves
1368+
// ownership in ossa. This is needed because the optimization creates a
1369+
// scalar cast which is a guaranteed forwarding instruction and is valid
1370+
// only when ownership can be preserved.
1371+
return !func->hasOwnership() ||
1372+
doesCastPreserveOwnershipForTypes(func->getModule(), sourceType,
1373+
targetType);
1374+
}
1375+
1376+
return true;
1377+
}
1378+
13581379
/// Can the given cast be performed by the scalar checked-cast
13591380
/// instructions?
13601381
bool swift::canIRGenUseScalarCheckedCastInstructions(SILModule &M,

lib/SILOptimizer/Utils/CastOptimizer.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,8 +1064,7 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) {
10641064
// The unconditional_cast can be skipped, if the result of a cast
10651065
// is not used afterwards.
10661066
if (!ResultNotUsed) {
1067-
if (!dynamicCast.canSILUseScalarCheckedCastInstructions())
1068-
return nullptr;
1067+
ASSERT(dynamicCast.canSILUseScalarCheckedCastInstructions());
10691068

10701069
CastedValue =
10711070
emitSuccessfulScalarUnconditionalCast(Builder, Loc, dynamicCast);
@@ -1160,9 +1159,9 @@ SILInstruction *CastOptimizer::optimizeCheckedCastAddrBranchInst(
11601159

11611160
if (MI) {
11621161
if (SuccessBB->getSinglePredecessorBlock() &&
1163-
canSILUseScalarCheckedCastInstructions(
1164-
Inst->getModule(), MI->getType().getASTType(),
1165-
Inst->getTargetFormalType())) {
1162+
canOptimizeToScalarCheckedCastInstructions(
1163+
Inst->getFunction(), MI->getType().getASTType(),
1164+
Inst->getTargetFormalType(), Inst->getConsumptionKind())) {
11661165
SILBuilderWithScope B(Inst, builderContext);
11671166
auto NewI = B.createCheckedCastBranch(
11681167
Loc, false /*isExact*/,
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all -generic-specializer %s | %FileCheck %s
2+
3+
// REQUIRES: objc_interop
4+
5+
sil_stage canonical
6+
7+
import Builtin
8+
import Swift
9+
import SwiftShims
10+
11+
import Foundation
12+
13+
public enum ResultType : Equatable {
14+
case object(NSObject)
15+
case undefined
16+
internal init<T>(metatypeOf value: T)
17+
}
18+
19+
// CHECK-LABEL: // specialized callee_anyobject
20+
// CHECK-LABEL: sil shared [ossa] @$s16callee_anyobjectyXl_Tt0g5 :
21+
// CHECK: checked_cast_addr_br
22+
// CHECK-LABEL: } // end sil function '$s16callee_anyobjectyXl_Tt0g5'
23+
sil hidden [ossa] @callee_anyobject : $@convention(method) <T> (@in T, @thin ResultType.Type) -> @owned ResultType {
24+
bb0(%0 : $*T, %1 : $@thin ResultType.Type):
25+
%3 = alloc_stack $T
26+
copy_addr %0 to [init] %3
27+
%5 = alloc_stack $NSObject
28+
checked_cast_addr_br copy_on_success T in %3 to NSObject in %5, bb1, bb2
29+
30+
bb1:
31+
destroy_addr %0
32+
%8 = enum $ResultType, #ResultType.undefined!enumelt
33+
destroy_addr %5
34+
dealloc_stack %5
35+
br bb5(%8)
36+
37+
bb2:
38+
destroy_addr %0
39+
dealloc_stack %5
40+
%28 = enum $ResultType, #ResultType.undefined!enumelt
41+
br bb5(%28)
42+
43+
bb5(%30 : @owned $ResultType):
44+
destroy_addr %3
45+
dealloc_stack %3
46+
%34 = move_value [lexical] %30
47+
return %34
48+
}
49+
50+
sil hidden [ossa] @caller_anyobject : $@convention(thin) (@owned AnyObject) -> () {
51+
bb0(%0 : @owned $AnyObject):
52+
%1 = metatype $@thin ResultType.Type
53+
%2 = alloc_stack $AnyObject
54+
store %0 to [init] %2
55+
%4 = function_ref @callee_anyobject : $@convention(method) <τ_0_0> (@in τ_0_0, @thin ResultType.Type) -> @owned ResultType
56+
%5 = apply %4<AnyObject>(%2, %1) : $@convention(method) <τ_0_0> (@in τ_0_0, @thin ResultType.Type) -> @owned ResultType
57+
dealloc_stack %2
58+
destroy_value %5
59+
%8 = tuple ()
60+
return %8
61+
}
62+

0 commit comments

Comments
 (0)