Skip to content

Commit efe4883

Browse files
committed
SILOptimizer: Fix to deal with casts involving dynamic Self
The cast optimizer was too eager to fold casts where the source and target lowered types were the same, even though the formal types might be different. Move the classifyFeasibility() check to deal with this case. Also in dead code elimination we have to mark all operands of a cast branch instruction as live, not just the first operand, otherwise we miss the special 'type dependent' self metadata operand and replace it with 'undef'.
1 parent b9c1def commit efe4883

File tree

3 files changed

+54
-15
lines changed

3 files changed

+54
-15
lines changed

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -400,22 +400,18 @@ void DCE::propagateLiveness(SILInstruction *I) {
400400
case TermKind::SwitchEnumInst:
401401
case TermKind::SwitchEnumAddrInst:
402402
case TermKind::DynamicMethodBranchInst:
403-
case TermKind::CheckedCastBranchInst:
404-
case TermKind::CheckedCastValueBranchInst:
405403
markValueLive(I->getOperand(0));
406404
return;
407405

406+
case TermKind::CheckedCastBranchInst:
407+
case TermKind::CheckedCastValueBranchInst:
408+
case TermKind::CheckedCastAddrBranchInst:
408409
case TermKind::TryApplyInst:
409410
case TermKind::SwitchValueInst:
410411
case TermKind::YieldInst:
411412
for (auto &O : I->getAllOperands())
412413
markValueLive(O.get());
413414
return;
414-
415-
case TermKind::CheckedCastAddrBranchInst:
416-
markValueLive(I->getOperand(0));
417-
markValueLive(I->getOperand(1));
418-
return;
419415
}
420416
llvm_unreachable("corrupt instruction!");
421417
}

lib/SILOptimizer/Utils/CastOptimizer.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,9 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) {
997997
// Check if we can statically predict the outcome of the cast.
998998
auto Feasibility =
999999
dynamicCast.classifyFeasibility(false /*allow whole module*/);
1000+
if (Feasibility == DynamicCastFeasibility::MaySucceed) {
1001+
return nullptr;
1002+
}
10001003

10011004
SILBuilderWithScope Builder(Inst, builderContext);
10021005
if (Feasibility == DynamicCastFeasibility::WillFail) {
@@ -1009,6 +1012,8 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) {
10091012
return NewI;
10101013
}
10111014

1015+
assert(Feasibility == DynamicCastFeasibility::WillSucceed);
1016+
10121017
bool ResultNotUsed = SuccessBB->getArgument(0)->use_empty();
10131018
SILValue CastedValue;
10141019
if (Op->getType() != TargetLoweredType) {
@@ -1022,14 +1027,6 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) {
10221027
llvm_unreachable(
10231028
"Bridged casts cannot be expressed by checked_cast_br yet");
10241029
} else {
1025-
// If the cast may succeed or fail and can't be turned into a bridging
1026-
// call, then let it be.
1027-
if (Feasibility == DynamicCastFeasibility::MaySucceed) {
1028-
return nullptr;
1029-
}
1030-
1031-
assert(Feasibility == DynamicCastFeasibility::WillSucceed);
1032-
10331030
// Replace by unconditional_cast, followed by a branch.
10341031
// The unconditional_cast can be skipped, if the result of a cast
10351032
// is not used afterwards.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all -O %s | %FileCheck %s
2+
3+
sil_stage raw
4+
5+
import Swift
6+
7+
public class SelfCasts {
8+
}
9+
10+
// CHECK-LABEL: sil @$dynamic_self_cast_1 : $@convention(method) (@guaranteed SelfCasts, @thick SelfCasts.Type) -> @owned Optional<SelfCasts>
11+
sil @$dynamic_self_cast_1 : $@convention(method) (@guaranteed SelfCasts, @thick SelfCasts.Type) -> @owned Optional<SelfCasts> {
12+
bb0(%0 : $SelfCasts, %1 : $@thick SelfCasts.Type):
13+
strong_retain %0 : $SelfCasts
14+
// CHECK: checked_cast_br
15+
checked_cast_br %0 : $SelfCasts to @dynamic_self SelfCasts, bb1, bb2
16+
bb1(%7 : $SelfCasts):
17+
%8 = enum $Optional<SelfCasts>, #Optional.some!enumelt.1, %7 : $SelfCasts
18+
br bb3(%8 : $Optional<SelfCasts>)
19+
20+
bb2:
21+
strong_release %0 : $SelfCasts
22+
%11 = enum $Optional<SelfCasts>, #Optional.none!enumelt
23+
br bb3(%11 : $Optional<SelfCasts>)
24+
25+
bb3(%13 : $Optional<SelfCasts>):
26+
return %13 : $Optional<SelfCasts>
27+
}
28+
29+
// CHECK-LABEL: sil @$dynamic_self_cast_2 : $@convention(method) (@guaranteed SelfCasts, @thick SelfCasts.Type) -> @owned Optional<SelfCasts>
30+
sil @$dynamic_self_cast_2 : $@convention(method) (@guaranteed SelfCasts, @thick SelfCasts.Type) -> @owned Optional<SelfCasts> {
31+
bb0(%0 : $SelfCasts, %1 : $@thick SelfCasts.Type):
32+
strong_retain %0 : $SelfCasts
33+
// CHECK-NOT: checked_cast_br
34+
checked_cast_br %0 : $SelfCasts to SelfCasts, bb1, bb2
35+
bb1(%7 : $SelfCasts):
36+
%8 = enum $Optional<SelfCasts>, #Optional.some!enumelt.1, %7 : $SelfCasts
37+
br bb3(%8 : $Optional<SelfCasts>)
38+
39+
bb2:
40+
strong_release %0 : $SelfCasts
41+
%11 = enum $Optional<SelfCasts>, #Optional.none!enumelt
42+
br bb3(%11 : $Optional<SelfCasts>)
43+
44+
bb3(%13 : $Optional<SelfCasts>):
45+
return %13 : $Optional<SelfCasts>
46+
}

0 commit comments

Comments
 (0)