Files
swift-mirror/test/SILOptimizer/simplify_cfg.sil
Meghana Gupta 5bfa560b35 Update SimplifyCFG's replacement of phi with its incoming value
Previously we replaced phi with its incoming values when all incoming values were the same.
If the phi had itself as incoming value, it wasn't optimized. This PR handles such cases.
2024-04-03 10:46:05 -07:00

3262 lines
95 KiB
Plaintext

// RUN: %target-sil-opt -enable-objc-interop -enforce-exclusivity=none -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
// Declare this SIL to be canonical because some tests break raw SIL
// conventions. e.g. address-type block args. -enforce-exclusivity=none is also
// required to allow address-type block args in canonical SIL.
sil_stage canonical
import Builtin
import Swift
///////////////////////
// Type Declarations //
///////////////////////
class foo {
var a: Int
deinit
init()
}
sil @use_foo : $@convention(thin) (@owned foo) -> ()
///////////
// Tests //
///////////
// CHECK-LABEL: sil @test_dead_block
// CHECK-NEXT: bb0:
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
sil @test_dead_block : $() -> () {
bb0:
unreachable
bb1:
%4 = integer_literal $Builtin.Int64, 1
br bb2
bb2:
%5 = struct $Int64 (%4 : $Builtin.Int64)
unreachable
}
// CHECK-LABEL: @release_in_arcinert_termination_block
// CHECK: bb0
// CHECK: unreachable
// CHECK: }
sil @release_in_arcinert_termination_block : $(@owned foo) -> () {
bb0(%0 : $foo):
br bb1
bb1:
strong_release %0 : $foo
unreachable
}
// CHECK-LABEL: @release_in_nonarcinert_termination_block
// CHECK: bb0
// CHECK: strong_release
// CHECK: apply
// CHECK: unreachable
sil @release_in_nonarcinert_termination_block : $(@owned foo) -> () {
bb0(%0 : $foo):
br bb1
bb1:
strong_release %0 : $foo
%1 = function_ref @use_foo : $@convention(thin) (@owned foo) -> ()
apply %1(%0) : $@convention(thin) (@owned foo) -> ()
unreachable
}
// CHECK-LABEL: @test_single_pred_block
// CHECK: bb3([[ARG:%[0-9]+]] : $Builtin.Int64):
// CHECK: struct $Int64
// CHECK-NEXT: return
sil @test_single_pred_block : $@convention(thin) (Builtin.Int1) -> Int64 {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb3
bb1:
%4 = integer_literal $Builtin.Int64, 1
br bb2(%4 : $Builtin.Int64)
bb3:
%9 = integer_literal $Builtin.Int64, 2
br bb2(%9 : $Builtin.Int64)
bb2(%6 : $Builtin.Int64):
%7 = struct $Int64 (%6 : $Builtin.Int64)
br bb4(%7 : $Int64)
bb4(%8 : $Int64):
return %8 : $Int64
}
// CHECK-LABEL: sil @canonicalize_not_branch
// CHECK: bb0([[ARG:%.*]] : $Builtin.Int1):
// CHECK: cond_br [[ARG]], bb2, bb1
// CHECK: bb1:
// CHECK: integer_literal {{.*}} 2
// CHECK: br
// CHECK: bb2:
// CHECK: integer_literal {{.*}} 3
// CHECK: br
sil @canonicalize_not_branch : $@convention(thin) (Builtin.Int1) -> (Builtin.Int32) {
bb0(%0 : $Builtin.Int1):
%1 = integer_literal $Builtin.Int1, -1
%2 = builtin "xor_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
cond_br %2, bb1, bb2
bb1:
%4 = integer_literal $Builtin.Int32, 2
br bb3(%4 : $Builtin.Int32)
bb2:
%5 = integer_literal $Builtin.Int32, 3
br bb3(%5 : $Builtin.Int32)
bb3(%6 : $Builtin.Int32):
return %6 : $Builtin.Int32
}
// CHECK-LABEL: sil @canonicalize_not_branch_expect
// CHECK: bb0([[ARG:%.*]] : $Builtin.Int1):
// CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int1, 0
// CHECK: [[EXPECT:%.*]] = builtin "int_expect_Int1"([[ARG]] : $Builtin.Int1, [[ZERO]]
// CHECK: cond_br [[EXPECT]], bb2, bb1
// CHECK: bb1:
// CHECK: integer_literal {{.*}} 2
// CHECK: br
// CHECK: bb2:
// CHECK: integer_literal {{.*}} 3
// CHECK: br
sil @canonicalize_not_branch_expect : $@convention(thin) (Builtin.Int1) -> (Builtin.Int32) {
bb0(%0 : $Builtin.Int1):
%1 = integer_literal $Builtin.Int1, -1
%2 = builtin "xor_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
%3 = builtin "int_expect_Int1"(%2 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
cond_br %3, bb1, bb2
bb1:
%4 = integer_literal $Builtin.Int32, 2
br bb3(%4 : $Builtin.Int32)
bb2:
%5 = integer_literal $Builtin.Int32, 3
br bb3(%5 : $Builtin.Int32)
bb3(%6 : $Builtin.Int32):
return %6 : $Builtin.Int32
}
enum BoolLike { case true_, false_ }
// func testThread(a : BoolLike) -> Int32 {
// if a { return 42 } else { return 17 } }
//
/// CHECK-LABEL: sil @testThread
sil @testThread : $@convention(thin) (@in BoolLike) -> Int64 {
bb0(%0 : $*BoolLike):
// CHECK: switch_enum_addr %0 : $*BoolLike, case #BoolLike.true_!enumelt: bb1, case #BoolLike.false_!enumelt: bb2
switch_enum_addr %0 : $*BoolLike, case #BoolLike.true_!enumelt: bb1, case #BoolLike.false_!enumelt: bb3
bb1:
%4 = integer_literal $Builtin.Int1, -1
br bb2(%4 : $Builtin.Int1)
bb2(%6 : $Builtin.Int1):
br bb4
bb3:
%8 = integer_literal $Builtin.Int1, 0
br bb2(%8 : $Builtin.Int1)
bb4:
cond_br %6, bb5, bb6
bb5:
%11 = metatype $@thin Int64.Type
%12 = integer_literal $Builtin.Int64, 42
%13 = struct $Int64 (%12 : $Builtin.Int64)
br bb7(%13 : $Int64)
bb6:
%15 = metatype $@thin Int64.Type
%16 = integer_literal $Builtin.Int64, 17
%17 = struct $Int64 (%16 : $Builtin.Int64)
br bb7(%17 : $Int64)
bb7(%19 : $Int64):
return %19 : $Int64
}
// func testThread2(a : Int32) -> Int32 {
// enum b = (a ? _true : _false)
// if b == _true { return 42 } else { return 17 }
//
/// CHECK-LABEL: sil @testThread2
/// CHECK: bb0([[COND:%.*]] : {{.*}}):
/// CHECK: cond_br [[COND]], bb1, bb2
/// CHECK: bb1:
/// CHECK: integer_literal $Builtin.Int64, 42
/// CHeCK: br bb3
/// CHECK: bb2:
/// CHECK: integer_literal $Builtin.Int64, 17
/// CHECK: br bb3
/// CHECK: bb3
/// CHECK: return
sil @testThread2 : $@convention(thin) (Builtin.Int1) -> Int64 {
bb0(%0 : $Builtin.Int1):
%t = integer_literal $Builtin.Int1, 1
%f = integer_literal $Builtin.Int1, 0
cond_br %0, bb1, bb2
bb1:
%4 = enum $BoolLike, #BoolLike.true_!enumelt
br bb3(%4 : $BoolLike)
bb2:
%8 = enum $BoolLike, #BoolLike.false_!enumelt
br bb3(%8 : $BoolLike)
bb3(%6 : $BoolLike):
%100 = select_enum %6 : $BoolLike, case #BoolLike.true_!enumelt: %t, case #BoolLike.false_!enumelt: %f : $Builtin.Int1
br bb4
bb4:
cond_br %100, bb5, bb6
bb5:
%11 = metatype $@thin Int64.Type
%12 = integer_literal $Builtin.Int64, 42
%13 = struct $Int64 (%12 : $Builtin.Int64)
br bb7(%13 : $Int64)
bb6:
%15 = metatype $@thin Int64.Type
%16 = integer_literal $Builtin.Int64, 17
%17 = struct $Int64 (%16 : $Builtin.Int64)
br bb7(%17 : $Int64)
bb7(%19 : $Int64):
return %19 : $Int64
}
// func testThread3(a : Int32) -> Int32 {
// (enum b, val) = (a ? (_true, 16) : (_false, 17))
// if b == true { return 42 } else { return v } }
//
/// CHECK-LABEL: sil @testThread3
/// CHECK: bb0([[COND:%.*]] : {{.*}}):
/// CHECK: cond_br [[COND]], bb1, bb2
/// CHECK: bb1:
/// CHECK: integer_literal $Builtin.Int64, 42
/// CHeCK: br bb3
/// CHECK: bb2:
/// CHECK: integer_literal $Builtin.Int64, 17
/// CHECK: br bb3
/// CHECK: bb3
/// CHECK: return
sil @testThread3 : $@convention(thin) (Builtin.Int1) -> Int64 {
bb0(%0 : $Builtin.Int1):
%t = integer_literal $Builtin.Int1, 1
%f = integer_literal $Builtin.Int1, 0
cond_br %0, bb1, bb2
bb1:
%4 = enum $BoolLike, #BoolLike.true_!enumelt
%40 = integer_literal $Builtin.Int64, 16
br bb3(%4 : $BoolLike, %40 : $Builtin.Int64)
bb2:
%8 = enum $BoolLike, #BoolLike.false_!enumelt
%80 = integer_literal $Builtin.Int64, 17
br bb3(%8 : $BoolLike, %80 : $Builtin.Int64)
bb3(%6 : $BoolLike, %60 : $Builtin.Int64):
%100 = select_enum %6 : $BoolLike, case #BoolLike.true_!enumelt: %t, case #BoolLike.false_!enumelt: %f : $Builtin.Int1
br bb4
bb4:
cond_br %100, bb5, bb6
bb5:
%11 = metatype $@thin Int64.Type
%12 = integer_literal $Builtin.Int64, 42
%13 = struct $Int64 (%12 : $Builtin.Int64)
br bb7(%13 : $Int64)
bb6:
%15 = metatype $@thin Int64.Type
%17 = struct $Int64 (%60 : $Builtin.Int64)
br bb7(%17 : $Int64)
bb7(%19 : $Int64):
return %19 : $Int64
}
/// CHECK-LABEL: sil @testCondBrFold
/// CHECK: bb0(
/// CHECK-NEXT: return %1 : $Int64
sil @testCondBrFold : $@convention(thin) (Int64, Int64) -> Int64 {
bb0(%0 : $Int64, %1 : $Int64):
%8 = integer_literal $Builtin.Int1, 0
cond_br %8, bb1, bb2
bb1:
unreachable
bb2:
return %1 : $Int64
}
/// CHECK-LABEL: sil @testSwitchEnumFold
/// CHECK: bb0(
/// CHECK-NEXT: return %0 : $Int64
sil @testSwitchEnumFold : $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = enum $BoolLike, #BoolLike.true_!enumelt
switch_enum %1 : $BoolLike, case #BoolLike.true_!enumelt: bb2, case #BoolLike.false_!enumelt: bb1
bb1:
unreachable
bb2:
return %0 : $Int64
}
// CHECK-LABEL: @elim_trampoline
// CHECK: bb0
// CHECK: cond_br {{.*}}, bb1, bb2
// CHECK:bb1:
// CHECK: br bb3(%1
// CHECK:bb2:
// CHECK: br bb3(%2
// CHECK:bb3({{.*}}):
// CHECK: return
sil @elim_trampoline : $@convention(thin) (Builtin.Int1, Int64, Int64) -> Int64 {
bb0(%0 : $Builtin.Int1, %1 : $Int64, %2 : $Int64):
cond_br %0, bb1(%1 : $Int64), bb2(%2 : $Int64)
bb1(%3 : $Int64):
br bb3(%3 : $Int64)
bb2(%4 : $Int64):
br bb3(%4 : $Int64)
bb3(%5 : $Int64):
return %5 : $Int64
}
// CHECK-LABEL: @elim_trampoline2
// CHECK-NOT: cond_br %0, bb1(%1 : $Int64), bb1(%1 : $Int64)
// CHECK: return
sil @elim_trampoline2 : $@convention(thin) (Builtin.Int1, Int64) -> Int64 {
bb0(%0 : $Builtin.Int1, %1 : $Int64):
cond_br %0, bb1(%1 : $Int64), bb2(%1 : $Int64)
bb1(%2 : $Int64):
br bb3(%2 : $Int64)
bb2(%3 : $Int64):
br bb3(%3 : $Int64)
bb3(%4 : $Int64):
return %4 : $Int64
}
// CHECK-LABEL: @elim_trampoline_debug
// CHECK-NOT: cond_br %0, bb1(%1 : $Int64), bb1(%1 : $Int64)
// CHECK: return
sil @elim_trampoline_debug : $@convention(thin) (Builtin.Int1, Int64) -> Int64 {
bb0(%0 : $Builtin.Int1, %1 : $Int64):
cond_br %0, bb1(%1 : $Int64), bb2(%1 : $Int64)
bb1(%2 : $Int64):
debug_value %0 : $Builtin.Int1
br bb3(%2 : $Int64)
bb2(%3 : $Int64):
br bb3(%3 : $Int64)
bb3(%4 : $Int64):
return %4 : $Int64
}
// CHECK-LABEL: @elim_trampoline3
// CHECK: cond_br %0, bb1, bb2
// CHECK:bb1:
// CHECK: br bb3(%1
// CHECK:bb2:
// CHECK: br bb3(%2
// CHECK:bb3({{.*}}):
// CHECK: return
sil @elim_trampoline3 : $@convention(thin) (Builtin.Int1, Int64, Int64) -> Int64 {
bb0(%0 : $Builtin.Int1, %1 : $Int64, %2 : $Int64):
cond_br %0, bb1(%1 : $Int64), bb2(%2 : $Int64)
bb1(%3 : $Int64):
br bb3(%3 : $Int64)
bb2(%4 : $Int64):
br bb3(%4 : $Int64)
bb3(%5 : $Int64):
br bb4(%5 : $Int64)
bb4(%6 : $Int64):
return %6 : $Int64
}
// Make sure the cond_br is not simplified as it would create
// a critical edge.
// CHECK-LABEL: @elim_trampoline4
// CHECK: cond_br %0, bb2, bb1
// CHECK: bb1:
// CHECK: br bb3
// CHECK: bb2:
// CHECK-NEXT: br bb3
// CHECK: bb3
// CHECK: return
// CHECK: }
sil @external_f : $@convention(thin) () -> ()
sil @elim_trampoline4 : $@convention(thin) (Builtin.Int1, Int64, Int64) -> Int64 {
bb0(%0 : $Builtin.Int1, %1 : $Int64, %2 : $Int64):
cond_br %0, bb1, bb2
bb1:
br bb3(%1 : $Int64)
bb2:
br bb4(%2 : $Int64)
bb4(%4 : $Int64):
%55 = function_ref @external_f : $@convention(thin) () -> ()
apply %55() : $@convention(thin) () -> ()
br bb5(%4: $Int64)
bb3(%5 : $Int64):
br bb5(%5 : $Int64)
bb5(%6 : $Int64):
return %6 : $Int64
}
// Eliminate the trampoline from a cond_br at bb5->bb3->bb4/
// This becomes a cond_br at bb8->bb5
// CHECK-LABEL: @elim_trampoline5
// CHECK: cond_br
// CHECK: bb5:
// CHECK: cond_br
// CHECK: bb8{{.*}}:
// CHECK: cond_br {{.*}}, bb5, bb9
// CHECK: bb9:
// CHECK-NEXT: br bb8
// CHECK: }
sil @elim_trampoline5 : $@convention(thin) (Int32) -> () {
bb0(%0 : $Int32):
%1 = integer_literal $Builtin.Int32, 0
%2 = struct_extract %0 : $Int32, #Int32._value
%3 = builtin "cmp_eq_Int32"(%1 : $Builtin.Int32, %2 : $Builtin.Int32) : $Builtin.Int1
cond_br %3, bb1, bb2(%1 : $Builtin.Int32)
bb1:
%5 = tuple ()
return %5 : $()
bb2(%7 : $Builtin.Int32):
%8 = integer_literal $Builtin.Int32, 1
%9 = integer_literal $Builtin.Int1, 0
%10 = integer_literal $Builtin.Int32, 2
br bb5(%1 : $Builtin.Int32)
bb3:
br bb4(%8 : $Builtin.Int32)
bb4(%13 : $Builtin.Int32):
%14 = builtin "cmp_eq_Int32"(%13 : $Builtin.Int32, %2 : $Builtin.Int32) : $Builtin.Int1
cond_br %14, bb1, bb2(%13 : $Builtin.Int32)
bb5(%16 : $Builtin.Int32):
%17 = builtin "sadd_with_overflow_Int32"(%16 : $Builtin.Int32, %8 : $Builtin.Int32, %9 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%18 = tuple_extract %17 : $(Builtin.Int32, Builtin.Int1), 0
%19 = builtin "cmp_eq_Int32"(%18 : $Builtin.Int32, %10 : $Builtin.Int32) : $Builtin.Int1
cond_br %19, bb3, bb5(%18 : $Builtin.Int32)
}
// CHECK-LABEL: @elim_trampoline_loop
// Make sure we are not crashing on this one.
// CHECK: return
sil @elim_trampoline_loop : $@convention(thin) (Builtin.Int1, Int64, Int64) -> Int64 {
bb0(%0 : $Builtin.Int1, %1 : $Int64, %2 : $Int64):
cond_br %0, bb1(%1 : $Int64), bb2(%2 : $Int64)
bb1(%3 : $Int64):
br bb3(%3 : $Int64)
bb2(%4 : $Int64):
br bb2(%4 : $Int64)
bb3(%5 : $Int64):
br bb4(%5 : $Int64)
bb4(%6 : $Int64):
return %6 : $Int64
}
// CHECK-LABEL: @elim_common_arg
// CHECK: bb3:
// CHECK-NEXT: return %1
sil @elim_common_arg : $@convention(thin) (Builtin.Int1, Int64) -> Int64 {
bb0(%0 : $Builtin.Int1, %1 : $Int64):
%f1 = function_ref @external_f : $@convention(thin) () -> ()
cond_br %0, bb1, bb2
bb1:
apply %f1() : $@convention(thin) () -> ()
br bb3(%1 : $Int64)
bb2:
apply %f1() : $@convention(thin) () -> ()
br bb3(%1 : $Int64)
bb3(%a1 : $Int64):
return %a1 : $Int64
}
// CHECK-LABEL: @elim_diamonds
// CHECK: bb0
// CHECK-NEXT: return %1
sil @elim_diamonds : $@convention(thin) (Builtin.Int1, Int64, Int64) -> Int64 {
bb0(%0 : $Builtin.Int1, %1 : $Int64, %2 : $Int64):
cond_br %0, bb1(%1 : $Int64), bb2(%1 : $Int64)
bb1(%3 : $Int64):
br bb3(%3 : $Int64)
bb2(%4 : $Int64):
br bb3(%4 : $Int64)
bb3(%5 : $Int64):
cond_br %0, bb4(%5 : $Int64), bb5(%5 : $Int64)
bb4(%6 : $Int64):
br bb6(%6 : $Int64)
bb5(%7 : $Int64):
br bb6(%7 : $Int64)
bb6(%8 : $Int64):
return %8 : $Int64
}
// CHECK-LABEL: @infinite_loop
// CHECK: bb0
// CHECK-NEXT: br bb1
// CHECK: bb1
// CHECK-NEXT: br bb1
sil @infinite_loop : $@convention(thin) () -> () {
bb0:
br bb1
bb1:
br bb1
}
import Builtin
import Swift
// CHECK-LABEL: @dead_loop
// CHECK-NOT: br bb
sil @dead_loop : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Int1, 0
%2 = integer_literal $Builtin.Int1, -1
cond_br %0, bb1, bb3
bb1:
%5 = integer_literal $Builtin.Int32, 0
%6 = struct $Int32 (%5 : $Builtin.Int32)
br bb2(%5 : $Builtin.Int32)
bb2(%8 : $Builtin.Int32):
%9 = integer_literal $Builtin.Int32, 1
%11 = builtin "sadd_with_overflow_Int32"(%8 : $Builtin.Int32, %9 : $Builtin.Int32, %2 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%12 = tuple_extract %11 : $(Builtin.Int32, Builtin.Int1), 0
%13 = tuple_extract %11 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %13 : $Builtin.Int1
%15 = struct $Int32 (%12 : $Builtin.Int32)
br bb2(%12 : $Builtin.Int32)
bb3:
%17 = tuple ()
return %17 : $()
}
// We should be able to compile this down to returning the parameter
// but we're not quite there yet.
// CHECK-LABEL: @nop
sil @nop : $@convention(thin) (Bool) -> Bool {
bb0(%0 : $Bool):
%1 = struct_extract %0 : $Bool, #Bool._value
// CHECK: cond_br %1, bb2, bb1
cond_br %1, bb1, bb2
// CHECK: bb1:
// CHECK: br bb3
// CHECK: bb2:
// CHECK: br bb3
bb1:
%3 = integer_literal $Builtin.Int1, 0
%4 = struct $Bool (%3 : $Builtin.Int1)
br bb3(%4 : $Bool)
bb2:
%6 = integer_literal $Builtin.Int1, -1
%7 = struct $Bool (%6 : $Builtin.Int1)
br bb3(%7 : $Bool)
// CHECK: bb3
bb3(%9 : $Bool):
// CHECK-NOT: struct_extract
%10 = struct_extract %9 : $Bool, #Bool._value
// CHECK: return
cond_br %10, bb4, bb5
// CHECK-NOT: bb4
bb4:
%12 = integer_literal $Builtin.Int1, 0
%13 = struct $Bool (%12 : $Builtin.Int1)
br bb6(%13 : $Bool)
// CHECK-NOT: bb5
bb5:
%15 = integer_literal $Builtin.Int1, -1
%16 = struct $Bool (%15 : $Builtin.Int1)
br bb6(%16 : $Bool)
bb6(%18 : $Bool):
return %18 : $Bool
}
class C {
final var value: Int32
init(v: Int32)
}
// CHECK-LABEL: @redundant_switchenum
sil @redundant_switchenum : $@convention(thin) (@owned Optional<C>) -> Int32 {
bb0(%0 : $Optional<C>):
switch_enum %0 : $Optional<C>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
// CHECK: bb1:
bb1:
%9 = integer_literal $Builtin.Int1, -1
%10 = struct $Bool (%9 : $Builtin.Int1)
// CHECK: br [[DEST:[a-zA-Z0-9]+]]
br bb3(%10 : $Bool)
// CHECK: bb2:
bb2:
%17 = integer_literal $Builtin.Int1, 0
%18 = struct $Bool (%17 : $Builtin.Int1)
// CHECK: br [[DEST]]
br bb3(%18 : $Bool)
// CHECK: [[DEST]]({{.*}}):
bb3(%12 : $Bool):
%15 = struct_extract %12 : $Bool, #Bool._value
// CHECK-NOT: cond_br
// CHECK: return
cond_br %15, bb4, bb7
// CHECK-NOT: bb4:
bb4:
%21 = alloc_stack $Optional<C>
store %0 to %21 : $*Optional<C>
// CHECK-NOT: switch_enum
switch_enum %0 : $Optional<C>, case #Optional.some!enumelt: bb5, case #Optional.none!enumelt: bb6
bb5:
%25 = unchecked_take_enum_data_addr %21 : $*Optional<C>, #Optional.some!enumelt
%26 = load %25 : $*C
dealloc_stack %21 : $*Optional<C>
%29 = ref_element_addr %26 : $C, #C.value
%30 = load %29 : $*Int32
br bb8(%30 : $Int32)
bb6:
%34 = builtin "int_trap"() : $()
unreachable
bb7:
%36 = integer_literal $Builtin.Int32, 0
%37 = struct $Int32 (%36 : $Builtin.Int32)
br bb8(%37 : $Int32)
bb8(%39 : $Int32):
release_value %0 : $Optional<C>
return %39 : $Int32
}
enum A {
case B, C, D
}
// CHECK-LABEL: cannot_optimize_switch_enum
sil @cannot_optimize_switch_enum : $@convention(thin) (A) -> () {
// CHECK: bb0
bb0(%0 : $A):
// CHECK: %1 = function_ref
// CHECK-NEXT: switch_enum %0 : $A, case #A.B!enumelt: bb1, default [[BB:bb[0-9a-zA-Z]+]]
%f1 = function_ref @external_f : $@convention(thin) () -> ()
switch_enum %0 : $A, case #A.B!enumelt: bb1, default bb2
bb1:
apply %f1() : $@convention(thin) () -> ()
br bb5
// CHECK: [[BB]]
bb2:
// CHECK-NEXT: switch_enum %0
switch_enum %0 : $A, case #A.C!enumelt: bb3, default bb4
bb3:
apply %f1() : $@convention(thin) () -> ()
br bb5
bb4:
apply %f1() : $@convention(thin) () -> ()
br bb5
bb5:
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: sil @simplify_switch_enum1
// CHECK: bb0:
// CHECK-NOT: bb[0-9]
// CHECK: apply
// CHECK-NEXT: return
sil @simplify_switch_enum1 : $@convention(thin) () -> Int32 {
bb0:
%10 = integer_literal $Builtin.Int32, 2
%11 = struct $Int32 (%10 : $Builtin.Int32)
%20 = integer_literal $Builtin.Int32, 3
%21 = struct $Int32 (%20 : $Builtin.Int32)
cond_br undef, bb1, bb2
bb1:
%12 = enum $Optional<Int32>, #Optional.some!enumelt, %11 : $Int32
br bb3(%12 : $Optional<Int32>)
bb2:
%22 = enum $Optional<Int32>, #Optional.some!enumelt, %21 : $Int32
br bb3(%22 : $Optional<Int32>)
bb3(%30 : $Optional<Int32>):
%u = function_ref @unknown : $@convention(thin) () -> ()
apply %u() : $@convention(thin) () -> ()
switch_enum %30 : $Optional<Int32>, case #Optional.none!enumelt: bb4, case #Optional.some!enumelt: bb5
bb4:
br bb6(%11 : $Int32)
bb5:
br bb6(%21 : $Int32)
bb6(%r : $Int32):
return %r : $Int32
}
// CHECK-LABEL: sil @simplify_switch_enum2
// CHECK: bb3([[A:%[0-9]+]] : $Optional<Int32>):
// CHECK: apply
// CHECK: [[R:%[0-9]+]] = unchecked_enum_data [[A]] : $Optional<Int32>, #Optional.some!enumelt
// CHECK: return [[R]]
sil @simplify_switch_enum2 : $@convention(thin) (Optional<Int32>) -> Int32 {
bb0(%0 : $Optional<Int32>):
%10 = integer_literal $Builtin.Int32, 2
%11 = struct $Int32 (%10 : $Builtin.Int32)
%20 = integer_literal $Builtin.Int32, 3
%21 = struct $Int32 (%20 : $Builtin.Int32)
switch_enum %0 : $Optional<Int32>, case #Optional.none!enumelt: bb1, case #Optional.some!enumelt: bb2
bb1:
%12 = enum $Optional<Int32>, #Optional.some!enumelt, %11 : $Int32
br bb3(%12 : $Optional<Int32>)
bb2:
br bb3(%0 : $Optional<Int32>)
bb3(%30 : $Optional<Int32>):
%u = function_ref @unknown : $@convention(thin) () -> ()
apply %u() : $@convention(thin) () -> ()
switch_enum %30 : $Optional<Int32>, case #Optional.none!enumelt: bb4, case #Optional.some!enumelt: bb5
bb4:
br bb6(%21 : $Int32)
bb5(%p : $Int32):
br bb6(%p : $Int32)
bb6(%r : $Int32):
return %r : $Int32
}
// CHECK-LABEL: sil @identical_switch_enum_dests : $@convention(thin) (Optional<Int32>) -> () {
// CHECK: bb0(%0 : $Optional<Int32>):
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @identical_switch_enum_dests : $@convention(thin) (Optional<Int32>) -> () {
bb0(%0 : $Optional<Int32>):
switch_enum %0 : $Optional<Int32>, case #Optional.none!enumelt: bb1, case #Optional.some!enumelt: bb2
bb1:
br bb3
bb2:
br bb3
bb3:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @identical_switch_enum_addr_dests : $@convention(thin) (@in Optional<Int32>) -> () {
// CHECK: bb0(%0 : $*Optional<Int32>):
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @identical_switch_enum_addr_dests : $@convention(thin) (@in Optional<Int32>) -> () {
bb0(%0 : $*Optional<Int32>):
switch_enum_addr %0 : $*Optional<Int32>, case #Optional.none!enumelt: bb1, case #Optional.some!enumelt: bb2
bb1:
br bb3
bb2:
br bb3
bb3:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @identical_switch_value_dests : $@convention(thin) (Builtin.Int32) -> () {
// CHECK: bb0(%0 : $Builtin.Int32):
// CHECK-NEXT: integer_literal
// CHECK-NEXT: integer_literal
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @identical_switch_value_dests : $@convention(thin) (Builtin.Int32) -> () {
bb0(%0 : $Builtin.Int32):
%1 = integer_literal $Builtin.Int32, 24
%2 = integer_literal $Builtin.Int32, 25
switch_value %0 : $Builtin.Int32, case %1: bb1, case %2: bb2
bb1:
br bb3
bb2:
br bb3
bb3:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @fold_switch_value : $@convention(thin) () -> Int32 {
// CHECK: bb0:
// CHECK-NOT: bb1
// CHECK: integer_literal $Builtin.Int32, 100
// CHECK-NEXT: struct
// CHECK-NEXT: return
sil @fold_switch_value : $@convention(thin) () -> Int32 {
bb0:
%1 = integer_literal $Builtin.Int32, 24
%2 = integer_literal $Builtin.Int32, 25
switch_value %1 : $Builtin.Int32, case %1: bb1, case %2: bb2
bb1:
%3 = integer_literal $Builtin.Int32, 100
br bb3(%3 : $Builtin.Int32)
bb2:
%4 = integer_literal $Builtin.Int32, 200
br bb3(%4 : $Builtin.Int32)
bb3(%5 : $Builtin.Int32):
%r = struct $Int32 (%5 : $Builtin.Int32)
return %r : $Int32
}
// CHECK-LABEL: @dominator_based_simplify_condbr
// CHECK: integer_literal $Builtin.Int64, 1
// CHECK-NOT: integer_literal $Builtin.Int64, 2
// CHECK-NOT: integer_literal $Builtin.Int64, 3
// CHECK: integer_literal $Builtin.Int64, 4
// CHECK: return
sil @dominator_based_simplify_condbr : $@convention(thin) (Builtin.Int1) -> Int64 {
bb0(%0 : $Builtin.Int1):
%l1 = integer_literal $Builtin.Int1, -1
cond_br %0, bb1, bb4
bb1:
cond_br %0, bb2, bb3
bb2:
%1 = integer_literal $Builtin.Int64, 1
br bb7(%1 : $Builtin.Int64)
bb3:
%2 = integer_literal $Builtin.Int64, 2
br bb7(%2 : $Builtin.Int64)
bb4:
// expect-intrinsics should be transparent for checking the condition.
%x1 = builtin "int_expect_Int1"(%0 : $Builtin.Int1, %l1 : $Builtin.Int1) : $Builtin.Int1
cond_br %x1, bb5, bb6
bb5:
%3 = integer_literal $Builtin.Int64, 3
br bb7(%3 : $Builtin.Int64)
bb6:
%4 = integer_literal $Builtin.Int64, 4
br bb7(%4 : $Builtin.Int64)
bb7(%6 : $Builtin.Int64):
%7 = struct $Int64 (%6 : $Builtin.Int64)
return %7 : $Int64
}
// CHECK-LABEL: @dominator_based_simplify_condbr_with_inverts
// CHECK-NOT: integer_literal $Builtin.Int64, 1
// CHECK: [[I2:%[0-9]+]] = integer_literal $Builtin.Int64, 2
// CHECK: br bb3([[I2]] : $Builtin.Int64)
// CHECK-NOT: integer_literal $Builtin.Int64, 3
// CHECK: [[I4:%[0-9]+]] = integer_literal $Builtin.Int64, 4
// CHECK: br bb3([[I4]] : $Builtin.Int64)
// CHECK: bb3([[R:%[0-9]+]] : $Builtin.Int64):
// CHECK-NEXT: return [[R]]
sil @dominator_based_simplify_condbr_with_inverts : $@convention(thin) (Builtin.Int1) -> Builtin.Int64 {
bb0(%0 : $Builtin.Int1):
%l1 = integer_literal $Builtin.Int1, -1
%x1 = builtin "xor_Int1"(%0 : $Builtin.Int1, %l1 : $Builtin.Int1) : $Builtin.Int1
cond_br %x1, bb1, bb4
bb1:
cond_br %0, bb2, bb3
bb2:
%1 = integer_literal $Builtin.Int64, 1
br bb7(%1 : $Builtin.Int64)
bb3:
%2 = integer_literal $Builtin.Int64, 2
br bb7(%2 : $Builtin.Int64)
bb4:
// expect-intrinsics should be transparent for checking the condition.
%x2 = builtin "int_expect_Int1"(%0 : $Builtin.Int1, %l1 : $Builtin.Int1) : $Builtin.Int1
%x3 = builtin "xor_Int1"(%0 : $Builtin.Int1, %l1 : $Builtin.Int1) : $Builtin.Int1
cond_br %x3, bb5, bb6
bb5:
%3 = integer_literal $Builtin.Int64, 3
br bb7(%3 : $Builtin.Int64)
bb6:
%4 = integer_literal $Builtin.Int64, 4
br bb7(%4 : $Builtin.Int64)
bb7(%6 : $Builtin.Int64):
return %6 : $Builtin.Int64
}
// CHECK-LABEL: @switch_enum_dominates_switch_enum_arg
// CHECK: bb0(%0 : $Optional<Builtin.Int32>):
// CHECK-NEXT: switch_enum %0 {{.*}} case #Optional.some!enumelt: bb2
// CHECK: bb2:
// CHECK-NEXT: [[D:%[0-9]+]] = unchecked_enum_data %0
// CHECK-NEXT: br bb3([[D]] : $Builtin.Int32)
// CHECK: bb3([[R:%[0-9]+]] : $Builtin.Int32):
// CHECK-NEXT: return [[R]]
sil @switch_enum_dominates_switch_enum_arg : $@convention(thin) (Optional<Builtin.Int32>) -> Builtin.Int32 {
bb0(%0 : $Optional<Builtin.Int32>):
switch_enum %0 : $Optional<Builtin.Int32>, case #Optional.none!enumelt: bb1, case #Optional.some!enumelt: bb2
bb1:
%i1 = integer_literal $Builtin.Int32, 1
br bb5(%i1 : $Builtin.Int32)
bb2:
switch_enum %0 : $Optional<Builtin.Int32>, case #Optional.none!enumelt: bb3, case #Optional.some!enumelt: bb4
bb3:
%i2 = integer_literal $Builtin.Int32, 2
br bb5(%i2 : $Builtin.Int32)
bb4(%e : $Builtin.Int32):
br bb5(%e : $Builtin.Int32)
bb5(%r : $Builtin.Int32):
return %r : $Builtin.Int32
}
// CHECK-LABEL: @switch_enum_dominates_switch_enum_arg_reuse
// CHECK: bb0(%0 : $Optional<Builtin.Int32>):
// CHECK-NEXT: switch_enum %0 {{.*}} case #Optional.some!enumelt: bb2
// CHECK: bb2({{.*}} : $Builtin.Int32):
// CHECK-NEXT: [[A:%[0-9]+]] = unchecked_enum_data %0
// CHECK-NEXT: br bb3([[A]] : $Builtin.Int32)
// CHECK: bb3([[R:%[0-9]+]] : $Builtin.Int32):
// CHECK-NEXT: return [[R]]
sil @switch_enum_dominates_switch_enum_arg_reuse : $@convention(thin) (Optional<Builtin.Int32>) -> Builtin.Int32 {
bb0(%0 : $Optional<Builtin.Int32>):
switch_enum %0 : $Optional<Builtin.Int32>, case #Optional.none!enumelt: bb1, case #Optional.some!enumelt: bb2
bb1:
%i1 = integer_literal $Builtin.Int32, 1
br bb5(%i1 : $Builtin.Int32)
bb2(%d : $Builtin.Int32):
switch_enum %0 : $Optional<Builtin.Int32>, case #Optional.none!enumelt: bb3, case #Optional.some!enumelt: bb4
bb3:
%i2 = integer_literal $Builtin.Int32, 2
br bb5(%i2 : $Builtin.Int32)
bb4(%e : $Builtin.Int32):
br bb5(%e : $Builtin.Int32)
bb5(%r : $Builtin.Int32):
return %r : $Builtin.Int32
}
// CHECK-LABEL: sil @simplify_loop_header
// CHECK: bb1(
// CHECK: cond_br {{.*}}, bb3, bb2
// CHECK: bb2:
// CHECK: br bb1(
// CHECK: bb3:
// CHECK: return
sil @simplify_loop_header : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Int32, 0
%1 = integer_literal $Builtin.Int32, 1000
br bb1(%0 : $Builtin.Int32)
bb1(%3 : $Builtin.Int32):
%4 = struct $Int32 (%3 : $Builtin.Int32)
%6 = builtin "cmp_eq_Int32"(%3 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int1
cond_br %6, bb2, bb3
bb2:
%8 = enum $Optional<Int32>, #Optional.none!enumelt
br bb4(%3 : $Builtin.Int32, %8 : $Optional<Int32>)
bb3:
%10 = integer_literal $Builtin.Int32, 1
%12 = integer_literal $Builtin.Int1, -1
%13 = builtin "sadd_with_overflow_Int32"(%3 : $Builtin.Int32, %10 : $Builtin.Int32, %12 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0
%15 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %15 : $Builtin.Int1
%17 = enum $Optional<Int32>, #Optional.some!enumelt, %4 : $Int32
br bb4(%14 : $Builtin.Int32, %17 : $Optional<Int32>)
bb4(%19 : $Builtin.Int32, %20 : $Optional<Int32>):
switch_enum %20 : $Optional<Int32>, case #Optional.some!enumelt: bb5, case #Optional.none!enumelt: bb6
bb5:
// This could be a use like we generate for a loop with an induction
// variable use like in:
// for i in 1..10 { a[i] = i }
%9 = unchecked_enum_data %20 : $Optional<Int32>, #Optional.some!enumelt
br bb1(%19 : $Builtin.Int32)
bb6:
%23 = tuple ()
return %23 : $()
}
class Base {
@inline(never) func inner()
func middle()
func outer()
}
class Derived : Base {
override func inner()
@inline(never) final override func middle()
}
class Final : Derived {
}
sil @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
sil @_TFC3ccb4Base6middlefS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
// CHECK-LABEL: sil @redundant_checked_cast_br
sil @redundant_checked_cast_br : $@convention(method) (@guaranteed Base) -> () {
bb0(%0 : $Base):
// CHECK: [[METHOD:%.*]] = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%1 = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// CHECK: checked_cast_br [exact] Base in %0 : $Base to Base, [[SUCCESS:bb[0-9]+]], [[FAIL:bb[0-9]+]]
checked_cast_br [exact] Base in %0 : $Base to Base, bb2, bb7
// CHECK: bb1
bb1:
%3 = tuple ()
return %3 : $()
bb2(%5 : $Base):
// CHECK: [[SUCCESS]]
%7 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// CHECK-NOT: checked_cast_br
checked_cast_br [exact] Base in %0 : $Base to Base, bb3, bb5
// CHECK: [[INNER:%.*]] = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
// CHECK: apply [[INNER]]
// CHECK: br bb1
bb3(%9 : $Base):
// CHECK: [[FAIL]]
// CHECK-NOT: function-ref
// CHECK: apply [[METHOD]]
%10 = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
%11 = apply %10(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb4:
%13 = tuple ()
br bb6(%13 : $())
bb5:
%15 = apply %7(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb6(%17 : $()):
br bb1
bb7:
%19 = apply %1(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb1
}
// CHECK-LABEL: sil @not_redundant_checked_cast_br : $@convention(method) (@guaranteed Base) -> () {
sil @not_redundant_checked_cast_br : $@convention(method) (@guaranteed Base) -> () {
bb0(%0 : $Base):
// CHECK: [[METHOD:%.*]] = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%1 = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// CHECK: checked_cast_br [exact] Base in %0 : $Base to Base, [[SUCCESS:bb[0-9]+]], [[FAIL:bb[0-9]+]]
checked_cast_br [exact] Base in %0 : $Base to Base, bb2, bb7
// CHECK: bb1:
// CHECK: tuple ()
// CHECK: return
bb1:
%3 = tuple ()
return %3 : $()
bb2(%5 : $Base):
// CHECK: [[SUCCESS]]
// CHECK: [[METHOD2:%.*]] = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%7 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%8 = apply %7(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb3(%9 : $Derived):
%10 = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
%11 = apply %10(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb4:
%13 = tuple ()
br bb6(%13 : $())
bb5:
%14 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%15 = apply %14(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb6(%17 : $()):
br bb1
bb7:
// CHECK: checked_cast_br [exact] Base in %0 : $Base to Derived
checked_cast_br [exact] Base in %0 : $Base to Derived, bb3, bb5
}
// CHECK-LABEL: sil @failing_checked_cast_br
sil @failing_checked_cast_br : $@convention(method) (@guaranteed Base) -> () {
bb0(%0 : $Base):
// CHECK: [[METHOD:%.*]] = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%1 = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// CHECK: checked_cast_br [exact] Base in %0 : $Base to Base, [[SUCCESS:bb[0-9]+]], [[FAIL:bb[0-9]+]]
checked_cast_br [exact] Base in %0 : $Base to Base, bb2, bb7
// CHECK-LABEL: bb1
bb1:
%3 = tuple ()
return %3 : $()
bb2(%5 : $Base):
// CHECK: [[SUCCESS]]
// CHECK: [[METHOD2:%.*]] = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%7 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// CHECK-NOT: checked_cast_br [exact] Base in %0 : $Base to Derived
// CHECK: apply [[METHOD2]]
// Check that checked_cast_br [exact] was replaced by a branch to the failure BB of the checked_cast_br.
// This is because bb2 is reached via the success branch of the checked_cast_br [exact] from bb0.
// It means that the exact dynamic type of %0 is $Base. Thus it cannot be $Derived.
// CHECK: br bb1
checked_cast_br [exact] Base in %5 : $Base to Derived, bb3, bb5
bb3(%9 : $Derived):
%10 = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
%11 = apply %10(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb4:
%13 = tuple ()
br bb6(%13 : $())
bb5:
%15 = apply %7(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb6(%17 : $()):
br bb1
bb7:
%19 = apply %1(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb1
}
sil @unknown2 : $@convention(thin) () -> ()
// CHECK-LABEL: no_checked_cast_br_threading_with_alloc_ref_stack
// CHECK: checked_cast_br
// CHECK: apply
// CHECK: apply
// CHECK: checked_cast_br
// CHECK: apply
// CHECK: apply
// CHECK: return
sil @no_checked_cast_br_threading_with_alloc_ref_stack : $@convention(method) (@guaranteed Base) -> () {
bb0(%0 : $Base):
%fu = function_ref @unknown : $@convention(thin) () -> ()
%fu2 = function_ref @unknown2 : $@convention(thin) () -> ()
checked_cast_br [exact] Base in %0 : $Base to Base, bb1, bb2
bb1(%1 : $Base):
apply %fu() : $@convention(thin) () -> ()
br bb3
bb2:
apply %fu2() : $@convention(thin) () -> ()
br bb3
bb3:
%a = alloc_ref [stack] $Base
checked_cast_br [exact] Base in %0 : $Base to Base, bb4, bb5
bb4(%2 : $Base):
apply %fu() : $@convention(thin) () -> ()
br bb6
bb5:
apply %fu2() : $@convention(thin) () -> ()
br bb6
bb6:
dealloc_stack_ref %a : $Base
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @jumpthread_switch_enum
// CHECK-NOT: switch_enum
// CHECK: return
sil @jumpthread_switch_enum : $@convention(thin) (Int32) -> Int32 {
bb0(%0 : $Int32):
%1 = integer_literal $Builtin.Int32, 0
%2 = integer_literal $Builtin.Int32, 1
%3 = struct_extract %0 : $Int32, #Int32._value
%5 = integer_literal $Builtin.Int1, -1
%6 = builtin "sadd_with_overflow_Int32"(%3 : $Builtin.Int32, %2 : $Builtin.Int32, %5 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%7 = tuple_extract %6 : $(Builtin.Int32, Builtin.Int1), 0
%8 = tuple_extract %6 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %8 : $Builtin.Int1
%11 = builtin "cmp_eq_Int32"(%2 : $Builtin.Int32, %7 : $Builtin.Int32) : $Builtin.Int1
cond_br %11, bb8(%1 : $Builtin.Int32), bb2
bb2:
%14 = integer_literal $Builtin.Int32, 2
%15 = struct $Int32 (%2 : $Builtin.Int32)
%16 = enum $Optional<Int32>, #Optional.some!enumelt, %15 : $Int32
br bb3(%1 : $Builtin.Int32, %14 : $Builtin.Int32, %16 : $Optional<Int32>)
bb3(%18 : $Builtin.Int32, %19 : $Builtin.Int32, %20 : $Optional<Int32>):
switch_enum %20 : $Optional<Int32>, case #Optional.some!enumelt: bb4, case #Optional.none!enumelt: bb5
bb4:
%22 = unchecked_enum_data %20 : $Optional<Int32>, #Optional.some!enumelt
%23 = struct_extract %22 : $Int32, #Int32._value
%24 = builtin "sadd_with_overflow_Int32"(%18 : $Builtin.Int32, %23 : $Builtin.Int32, %5 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%25 = tuple_extract %24 : $(Builtin.Int32, Builtin.Int1), 0
%26 = tuple_extract %24 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %26 : $Builtin.Int1
%28 = struct $Int32 (%19 : $Builtin.Int32)
%29 = builtin "cmp_eq_Int32"(%19 : $Builtin.Int32, %7 : $Builtin.Int32) : $Builtin.Int1
cond_br %29, bb6, bb7
bb5:
cond_fail %5 : $Builtin.Int1
unreachable
bb6:
br bb8(%25 : $Builtin.Int32)
bb7:
%34 = builtin "sadd_with_overflow_Int32"(%19 : $Builtin.Int32, %2 : $Builtin.Int32, %5 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%35 = tuple_extract %34 : $(Builtin.Int32, Builtin.Int1), 0
%36 = tuple_extract %34 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %36 : $Builtin.Int1
%38 = enum $Optional<Int32>, #Optional.some!enumelt, %28 : $Int32
br bb3(%25 : $Builtin.Int32, %35 : $Builtin.Int32, %38 : $Optional<Int32>)
bb8(%40 : $Builtin.Int32):
%41 = struct $Int32 (%40 : $Builtin.Int32)
return %41 : $Int32
}
// CHECK-LABEL: sil @jumpthread_switch_enum2
// CHECK-NOT: switch_enum
// CHECK: return
sil @jumpthread_switch_enum2 : $@convention(thin) (Int32) -> Int32 {
bb0(%0 : $Int32):
%1 = integer_literal $Builtin.Int32, 0
%3 = enum $Optional<Int32>, #Optional.some!enumelt, %0 : $Int32
%4 = enum $Optional<Int32>, #Optional.none!enumelt
br bb1(%1 : $Builtin.Int32, %3 : $Optional<Int32>)
bb1(%6 : $Builtin.Int32, %7 : $Optional<Int32>):
switch_enum %7 : $Optional<Int32>, case #Optional.some!enumelt: bb2, case #Optional.none!enumelt: bb3
bb2:
%9 = unchecked_enum_data %7 : $Optional<Int32>, #Optional.some!enumelt
%10 = struct_extract %9 : $Int32, #Int32._value
%11 = integer_literal $Builtin.Int1, 0
%12 = builtin "sadd_with_overflow_Int32"(%6 : $Builtin.Int32, %10 : $Builtin.Int32, %11 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%13 = tuple_extract %12 : $(Builtin.Int32, Builtin.Int1), 0
br bb1(%13 : $Builtin.Int32, %4 : $Optional<Int32>)
bb3:
%17 = struct $Int32 (%6 : $Builtin.Int32)
return %17 : $Int32
}
// CHECK-LABEL: sil @jumpthread_switch_enum3
// CHECK: [[ONE:%.*]] = integer_literal $Builtin.Int32, 2
// CHECK: [[ONEVAL:%.*]] = struct $Int32 ([[ONE]] : $Builtin.Int32)
// CHECK: [[THREE:%.*]] = integer_literal $Builtin.Int32, 3
// CHECK: [[THREEVAL:%.*]] = struct $Int32 ([[THREE]] : $Builtin.Int32)
// CHECK: switch_enum %0 : $Optional<Int32>, case #Optional.none!enumelt: bb2, case #Optional.some!enumelt: bb1
// CHECK: bb1:
// CHECK-NEXT: br bb5([[ONEVAL]]
// CHECK: bb2:
// CHECK-NEXT: switch_enum undef : $Optional<Int32>, case #Optional.none!enumelt: bb3, case #Optional.some!enumelt: bb4
// CHECK: bb3:
// CHECK-NEXT: br bb5([[THREEVAL]]
// CHECK: bb4:
// CHECK-NEXT: br bb5([[ONEVAL]]
// CHECK: bb5
// CHECK-NEXT: return
sil @jumpthread_switch_enum3 : $@convention(thin) (Optional<Int32>) -> Int32 {
bb0(%0 : $Optional<Int32>):
%10 = integer_literal $Builtin.Int32, 2
%11 = struct $Int32 (%10 : $Builtin.Int32)
%20 = integer_literal $Builtin.Int32, 3
%21 = struct $Int32 (%20 : $Builtin.Int32)
switch_enum %0 : $Optional<Int32>, case #Optional.none!enumelt: bb1, case #Optional.some!enumelt: bb2
bb1:
br bb3(undef : $Optional<Int32>)
bb2:
br bb3(%0 : $Optional<Int32>)
bb3(%30 : $Optional<Int32>):
switch_enum %30 : $Optional<Int32>, case #Optional.none!enumelt: bb4, case #Optional.some!enumelt: bb5
bb4:
br bb6(%21 : $Int32)
bb5:
br bb6(%11 : $Int32)
bb6(%r : $Int32):
return %r : $Int32
}
// CHECK-LABEL: sil @jumpthread_switch_enum4
// CHECK: bb0:
// CHECK-NEXT: cond_br undef, bb1, bb2
// CHECK: bb1:
// CHECK: enum $Optional<Int32>, #Optional.none!enumelt
// CHECK: br bb3
// CHECK: bb2:
// CHECK: integer_literal $Builtin.Int32, 0
// CHECK: enum $Optional<Int32>, #Optional.some!enumelt
// CHECK: br bb3
// CHECK: bb3
// CHECK: integer_literal {{.*}}, 27
// CHECK: integer_literal {{.*}}, 28
// CHECK: return
sil @jumpthread_switch_enum4 : $@convention(thin) () -> Builtin.Int32 {
bb0:
%c0 = builtin "assert_configuration"() : $Builtin.Int32
cond_br undef, bb1, bb2
bb1:
%4 = enum $Optional<Int32>, #Optional.none!enumelt
cond_br undef, bb3(%4 : $Optional<Int32>), bb4(%4 : $Optional<Int32>, %c0 : $Builtin.Int32)
bb2:
%6 = integer_literal $Builtin.Int32, 0
%7 = struct $Int32 (%6 : $Builtin.Int32)
%8 = enum $Optional<Int32>, #Optional.some!enumelt, %7 : $Int32
br bb3(%8 : $Optional<Int32>)
bb3(%10 : $Optional<Int32>):
// Some instruction which is not "trivial"
%c1 = builtin "assert_configuration"() : $Builtin.Int32
br bb4(%10 : $Optional<Int32>, %c1 : $Builtin.Int32)
bb4(%13 : $Optional<Int32>, %carg1 : $Builtin.Int32):
switch_enum %13 : $Optional<Int32>, case #Optional.some!enumelt: bb5, case #Optional.none!enumelt: bb6
bb5:
%r1 = integer_literal $Builtin.Int32, 27
%c2 = builtin "assert_configuration"() : $Builtin.Int32
br bb7(%r1 : $Builtin.Int32, %c2 : $Builtin.Int32)
bb6:
%r2 = integer_literal $Builtin.Int32, 28
%c3 = builtin "assert_configuration"() : $Builtin.Int32
br bb7(%r2 : $Builtin.Int32, %c3 : $Builtin.Int32)
bb7(%r : $Builtin.Int32, %carg2 : $Builtin.Int32):
return %r : $Builtin.Int32
}
// CHECK-LABEL: sil @jumpthread_switch_enum5
// CHECK: bb0:
// CHECK: br bb1
// CHECK: bb1:
// CHECK-NEXT: cond_br undef, bb2, bb3
// CHECK: bb2:
// CHECK: br bb1
// CHECK: bb3:
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @jumpthread_switch_enum5 : $@convention(thin) () -> () {
bb0:
%6 = integer_literal $Builtin.Int32, 0
%7 = struct $Int32 (%6 : $Builtin.Int32)
%8 = enum $Optional<Int32>, #Optional.some!enumelt, %7 : $Int32
br bb1(%8 : $Optional<Int32>)
bb1(%13 : $Optional<Int32>):
switch_enum %13 : $Optional<Int32>, case #Optional.some!enumelt: bb2, case #Optional.none!enumelt: bb3
bb2:
br bb4
bb3:
%55 = function_ref @external_f : $@convention(thin) () -> ()
apply %55() : $@convention(thin) () -> ()
br bb4
bb4:
cond_br undef, bb1(%13 : $Optional<Int32>), bb5
bb5:
%r = tuple ()
return %r : $()
}
/// Don't jumpthread blocks that contain objc method instructions. We don't
/// support building phis with objc method values.
class Bar {
init()
@objc func foo()
}
// CHECK-LABEL: @dont_jumpthread_switch_enum
// CHECK: objc_method
// CHECK: switch_enum
// CHECK: return
sil @dont_jumpthread_switch_enum : $@convention(thin) (Int32) -> Int32 {
bb0(%0 : $Int32):
%100 = alloc_ref $Bar
%1 = integer_literal $Builtin.Int32, 0
%2 = integer_literal $Builtin.Int32, 1
%3 = struct_extract %0 : $Int32, #Int32._value
%5 = integer_literal $Builtin.Int1, -1
%6 = builtin "sadd_with_overflow_Int32"(%3 : $Builtin.Int32, %2 : $Builtin.Int32, %5 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%7 = tuple_extract %6 : $(Builtin.Int32, Builtin.Int1), 0
%8 = tuple_extract %6 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %8 : $Builtin.Int1
%11 = builtin "cmp_eq_Int32"(%2 : $Builtin.Int32, %7 : $Builtin.Int32) : $Builtin.Int1
cond_br %11, bb8(%1 : $Builtin.Int32), bb2
bb2:
%14 = integer_literal $Builtin.Int32, 2
%15 = struct $Int32 (%2 : $Builtin.Int32)
%16 = enum $Optional<Int32>, #Optional.some!enumelt, %15 : $Int32
br bb3(%1 : $Builtin.Int32, %14 : $Builtin.Int32, %16 : $Optional<Int32>)
bb3(%18 : $Builtin.Int32, %19 : $Builtin.Int32, %20 : $Optional<Int32>):
%101 = objc_method %100 : $Bar, #Bar.foo!foreign : (Bar) -> () -> (), $@convention(objc_method) (Bar) -> ()
switch_enum %20 : $Optional<Int32>, case #Optional.some!enumelt: bb4, case #Optional.none!enumelt: bb5
bb4:
%102 = apply %101(%100) : $@convention(objc_method) (Bar) -> ()
%22 = unchecked_enum_data %20 : $Optional<Int32>, #Optional.some!enumelt
%23 = struct_extract %22 : $Int32, #Int32._value
%24 = builtin "sadd_with_overflow_Int32"(%18 : $Builtin.Int32, %23 : $Builtin.Int32, %5 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%25 = tuple_extract %24 : $(Builtin.Int32, Builtin.Int1), 0
%26 = tuple_extract %24 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %26 : $Builtin.Int1
%28 = struct $Int32 (%19 : $Builtin.Int32)
%29 = builtin "cmp_eq_Int32"(%19 : $Builtin.Int32, %7 : $Builtin.Int32) : $Builtin.Int1
cond_br %29, bb6, bb7
bb5:
cond_fail %5 : $Builtin.Int1
unreachable
bb6:
br bb8(%25 : $Builtin.Int32)
bb7:
%34 = builtin "sadd_with_overflow_Int32"(%19 : $Builtin.Int32, %2 : $Builtin.Int32, %5 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%35 = tuple_extract %34 : $(Builtin.Int32, Builtin.Int1), 0
%36 = tuple_extract %34 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %36 : $Builtin.Int1
%38 = enum $Optional<Int32>, #Optional.none!enumelt
br bb3(%25 : $Builtin.Int32, %35 : $Builtin.Int32, %38 : $Optional<Int32>)
bb8(%40 : $Builtin.Int32):
%41 = struct $Int32 (%40 : $Builtin.Int32)
return %41 : $Int32
}
enum OneCase {
case First
}
enum TwoCase {
case First
case Second
}
enum ThreeCase {
case First
case Second
case Third
}
sil @unknown : $@convention(thin) () -> ()
sil @int1_user : $@convention(thin) (Builtin.Int1) -> ()
// CHECK-LABEL: sil @select_enum_case_canonicalization : $@convention(thin) (OneCase, TwoCase, TwoCase, ThreeCase, ThreeCase, ThreeCase) -> () {
// CHECK: bb0([[ONE_1:%.*]] : $OneCase, [[TWO_1:%.*]] : $TwoCase, [[TWO_2:%.*]] : $TwoCase, [[THREE_1:%.*]] : $ThreeCase, [[THREE_2:%.*]] : $ThreeCase, [[THREE_3:%.*]] : $ThreeCase):
// CHECK: [[TAG1:%.*]] = select_enum [[ONE_1]] : $OneCase, case #OneCase.First!enumelt: [[TRUE:%[0-9]+]]
// CHECK: [[TAG2:%.*]] = select_enum [[TWO_1]] : $TwoCase, case #TwoCase.First!enumelt: [[TRUE:%[0-9]+]]
// CHECK: [[TAG3:%.*]] = select_enum [[TWO_2]] : $TwoCase, case #TwoCase.First!enumelt: [[TRUE:%[0-9]+]]
// CHECK: [[TAG3_OLD:%.*]] = select_enum [[TWO_2]] : $TwoCase, case #TwoCase.Second!enumelt: [[TRUE:%[0-9]+]]
// CHECK: [[TAG4:%.*]] = select_enum [[THREE_1]] : $ThreeCase, case #ThreeCase.First!enumelt: [[TRUE:%[0-9]+]]
// CHECK: [[TAG5:%.*]] = select_enum [[THREE_2]] : $ThreeCase, case #ThreeCase.Second!enumelt: [[TRUE:%[0-9]+]]
// CHECK: [[TAG6:%.*]] = select_enum [[THREE_3]] : $ThreeCase, case #ThreeCase.Third!enumelt: [[TRUE:%[0-9]+]]
// CHECK: cond_br [[TAG1]], bb1, bb6
// CHECK: cond_br [[TAG2]], bb2, bb3
// CHECK: [[INT1_USER_FUN:%.*]] = function_ref @int1_user : $@convention(thin) (Builtin.Int1) -> ()
// CHECK: apply [[INT1_USER_FUN]]([[TAG3_OLD]])
// CHECK: cond_br [[TAG3]], bb5, bb4
// CHECK: cond_br [[TAG4]], bb7, bb8
// CHECK: cond_br [[TAG5]], bb9, bb10
// CHECK: cond_br [[TAG6]], bb11, bb12
sil @select_enum_case_canonicalization : $@convention(thin) (OneCase, TwoCase, TwoCase, ThreeCase, ThreeCase, ThreeCase) -> () {
bb0(%0 : $OneCase, %1 : $TwoCase, %2 : $TwoCase, %3 : $ThreeCase, %4 : $ThreeCase, %5 : $ThreeCase):
%t = integer_literal $Builtin.Int1, 1
%f = integer_literal $Builtin.Int1, 0
%6 = select_enum %0 : $OneCase, case #OneCase.First!enumelt: %t, default %f : $Builtin.Int1
%7 = select_enum %1 : $TwoCase, case #TwoCase.First!enumelt: %t, default %f : $Builtin.Int1
%8 = select_enum %2 : $TwoCase, case #TwoCase.Second!enumelt: %t, default %f : $Builtin.Int1
%9 = select_enum %3 : $ThreeCase, case #ThreeCase.First!enumelt: %t, default %f : $Builtin.Int1
%10 = select_enum %4 : $ThreeCase, case #ThreeCase.Second!enumelt: %t, default %f : $Builtin.Int1
%11 = select_enum %5 : $ThreeCase, case #ThreeCase.Third!enumelt: %t, default %f : $Builtin.Int1
%12 = function_ref @unknown : $@convention(thin) () -> ()
cond_br %6, bb1a, bb1b
bb1a:
apply %12() : $@convention(thin) () -> ()
cond_br %7, bb2a, bb3a
bb2a:
apply %12() : $@convention(thin) () -> ()
%13 = function_ref @int1_user : $@convention(thin) (Builtin.Int1) -> ()
apply %13(%8) : $@convention(thin) (Builtin.Int1) -> ()
cond_br %8, bb4a, bb5a
bb3a:
apply %12() : $@convention(thin) () -> ()
br exit
bb4a:
apply %12() : $@convention(thin) () -> ()
br exit
bb5a:
apply %12() : $@convention(thin) () -> ()
br exit
bb1b:
apply %12() : $@convention(thin) () -> ()
cond_br %9, bb2b, bb3b
bb2b:
apply %12() : $@convention(thin) () -> ()
cond_br %10, bb4b, bb5b
bb3b:
apply %12() : $@convention(thin) () -> ()
cond_br %11, bb6b, bb7b
bb4b:
apply %12() : $@convention(thin) () -> ()
br exit
bb5b:
apply %12() : $@convention(thin) () -> ()
br exit
bb6b:
apply %12() : $@convention(thin) () -> ()
br exit
bb7b:
apply %12() : $@convention(thin) () -> ()
br exit
exit:
apply %12() : $@convention(thin) () -> ()
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @dont_crash_jump_threading_single_case_switch_enums
// CHECK-NOT: switch_enum
// CHECK: } // end sil function
sil @dont_crash_jump_threading_single_case_switch_enums : $@convention(thin) () -> () {
bb0:
br bb1(undef : $OneCase)
bb1(%19 : $OneCase):
switch_enum %19 : $OneCase, case #OneCase.First!enumelt: bb2
bb2:
switch_enum %19 : $OneCase, case #OneCase.First!enumelt: bb3
bb3:
%48 = enum $OneCase, #OneCase.First!enumelt
cond_br undef, bb6, bb7
bb6:
%72 = tuple ()
return %72 : $()
bb7:
br bb1(%48 : $OneCase)
}
class B {}
class E : B {}
// CHECK-LABEL: sil @checked_cast_anyobject_metatypeinst_to_class
// CHECK: bb0
// CHECK-NOT: checked_cast
// CHECK-NOT: bb1
// CHECK: [[RET:%.*]] = tuple ()
// CHECK: return [[RET]] : $()
sil @checked_cast_anyobject_metatypeinst_to_class : $@convention(thin)() -> () {
bb0:
%0 = metatype $@thick AnyObject.Protocol
checked_cast_br AnyObject.Protocol in %0 : $@thick AnyObject.Protocol to B.Type, bb1, bb2
bb1(%3 : $@thick B.Type):
br bb3
bb2:
br bb3
bb3:
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @remove_cond_fail_trueblock
// CHECK: bb0([[COND:%.*]] :
// CHECK-NOT: bb
// CHECK: cond_fail [[COND]]
// CHECK-NOT: bb
// CHECK: return
sil @remove_cond_fail_trueblock : $@convention(thin)(Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb2
bb1:
%1 = integer_literal $Builtin.Int1, -1
cond_fail %1 : $Builtin.Int1
unreachable
bb2:
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @remove_cond_fail_falseblock
// CHECK: bb0([[COND:%.*]] :
// CHECK-NOT: bb
// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
// CHECK-NOT: bb
// CHECK: [[NOTCOND:%.*]] = builtin "xor_Int1"([[COND]]{{.*}}, [[TRUE]]
// CHECK: cond_fail [[NOTCOND]]
// CHECK-NOT: bb
// CHECK: return
sil @remove_cond_fail_falseblock : $@convention(thin)(Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb2, bb1
bb1:
%1 = integer_literal $Builtin.Int1, -1
cond_fail %1 : $Builtin.Int1
unreachable
bb2:
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @dont_remove_cond_fail_wrong_const
// CHECK: bb0(%0 : $Builtin.Int1):
// CHECK-NEXT: cond_br %0, bb2, bb1
sil @dont_remove_cond_fail_wrong_const : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb2
bb1:
%i1 = integer_literal $Builtin.Int1, 0
cond_fail %i1 : $Builtin.Int1
br bb2
bb2:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @remove_cond_fail_same_cond_in_true
// CHECK: bb0([[COND:%[0-9]*]]
// CHECK-NOT: bb
// CHECK: cond_fail [[COND]]
// CHECK: bb1:
// CHECK: return
sil @remove_cond_fail_same_cond_in_true : $@convention(thin)(Builtin.Int1, Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1):
cond_br %0, bb1, bb2
bb1:
cond_fail %0 : $Builtin.Int1
unreachable
bb2:
// Make bb1 not dominated from bb0 to prevent that dominator based
// simplification does the same thing.
%55 = function_ref @external_f : $@convention(thin) () -> ()
apply %55() : $@convention(thin) () -> ()
cond_br %1, bb1, bb3
bb3:
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @remove_cond_fail_same_cond_in_false
// CHECK: bb0([[COND:%[0-9]*]]
// CHECK-NOT: bb
// CHECK: [[INV:%[0-9]*]] = builtin "xor_Int1"([[COND]]
// CHECK-NOT: bb
// CHECK: cond_fail [[INV]]
// CHECK: bb1:
// CHECK: return
sil @remove_cond_fail_same_cond_in_false : $@convention(thin)(Builtin.Int1, Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1):
cond_br %0, bb2, bb1
bb1:
%i1 = integer_literal $Builtin.Int1, -1
%i2 = builtin "xor_Int1"(%0 : $Builtin.Int1, %i1 : $Builtin.Int1) : $Builtin.Int1
cond_fail %i2 : $Builtin.Int1
unreachable
bb2:
// Make bb1 not dominated from bb0 to prevent that dominator based
// simplification does the same thing.
%55 = function_ref @external_f : $@convention(thin) () -> ()
apply %55() : $@convention(thin) () -> ()
cond_br %1, bb1, bb3
bb3:
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @remove_cond_fail_same_cond_in_false2
// CHECK: bb0([[COND:%[0-9]*]]
// CHECK-NOT: bb
// CHECK: cond_fail [[COND]]
// CHECK: bb1:
// CHECK: return
sil @remove_cond_fail_same_cond_in_false2 : $@convention(thin)(Builtin.Int1, Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1):
%i1 = integer_literal $Builtin.Int1, -1
%i2 = builtin "xor_Int1"(%0 : $Builtin.Int1, %i1 : $Builtin.Int1) : $Builtin.Int1
cond_br %i2, bb2, bb1
bb1:
cond_fail %0 : $Builtin.Int1
unreachable
bb2:
// Make bb1 not dominated from bb0 to prevent that dominator based
// simplification does the same thing.
%55 = function_ref @external_f : $@convention(thin) () -> ()
apply %55() : $@convention(thin) () -> ()
cond_br %1, bb1, bb3
bb3:
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @dont_remove_cond_fail_same_cond_in_false
// CHECK: bb0([[COND:%[0-9]*]]
// CHECK-NEXT: cond_br
// CHECK: bb2:
// CHECK-NEXT: cond_fail [[COND]]
// CHECK: return
sil @dont_remove_cond_fail_same_cond_in_false : $@convention(thin)(Builtin.Int1, Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1):
cond_br %0, bb2, bb1
bb1:
cond_fail %0 : $Builtin.Int1
unreachable
bb2:
// Make bb1 not dominated from bb0.
%55 = function_ref @external_f : $@convention(thin) () -> ()
apply %55() : $@convention(thin) () -> ()
cond_br %1, bb1, bb3
bb3:
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @move_cond_fail
// CHECK: bb1:
// CHECK-NEXT: apply
// CHECK-NEXT: [[X:%[0-9]*]] = integer_literal $Builtin.Int1, -1
// CHECK-NEXT: cond_fail [[X]]
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: apply
// CHECK-NEXT: cond_fail %1
// CHECK-NEXT: br bb3
// CHECK: bb3:
// CHECK-NOT: cond_fail
// CHECK: return
sil @move_cond_fail : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1):
%f1 = function_ref @external_f : $@convention(thin) () -> ()
cond_br %0, bb2, bb1
bb1:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
%i1 = integer_literal $Builtin.Int1, -1
br bb3(%i1 : $Builtin.Int1)
bb2:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
br bb3(%1 : $Builtin.Int1)
bb3(%a3 : $Builtin.Int1):
cond_fail %a3 : $Builtin.Int1
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @move_cond_fail_inverted
// CHECK: bb1:
// CHECK-NEXT: apply
// CHECK-NEXT: [[X:%[0-9]*]] = integer_literal $Builtin.Int1, -1
// CHECK-NEXT: [[Y:%[0-9]*]] = builtin "xor_Int1"(%2 : $Builtin.Int1, [[X]] : $Builtin.Int1)
// CHECK-NEXT: cond_fail [[Y]]
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: apply
// CHECK-NEXT: [[R:%[0-9]*]] = integer_literal $Builtin.Int1, -1
// CHECK-NEXT: [[S:%[0-9]*]] = builtin "xor_Int1"(%1 : $Builtin.Int1, [[R]] : $Builtin.Int1)
// CHECK-NEXT: cond_fail [[S]]
// CHECK-NEXT: br bb3
// CHECK: bb3({{.*}}):
// CHECK-NOT: cond_fail
// CHECK: return
sil @move_cond_fail_inverted : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1):
%2 = integer_literal $Builtin.Int1, -1
%f1 = function_ref @external_f : $@convention(thin) () -> ()
cond_br %0, bb2, bb1
bb1:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
br bb3(%2 : $Builtin.Int1)
bb2:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
br bb3(%1 : $Builtin.Int1)
bb3(%a3 : $Builtin.Int1):
%v1 = builtin "xor_Int1"(%a3 : $Builtin.Int1, %2 : $Builtin.Int1) : $Builtin.Int1
cond_fail %v1 : $Builtin.Int1
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @dont_move_cond_fail_no_const
// CHECK: bb1:
// CHECK-NEXT: apply
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: apply
// CHECK-NEXT: br bb3
// CHECK: bb3({{.*}}):
// CHECK-NEXT: cond_fail
sil @dont_move_cond_fail_no_const : $@convention(thin) (Builtin.Int1, Builtin.Int1, Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1, %2 : $Builtin.Int1):
%f1 = function_ref @external_f : $@convention(thin) () -> ()
cond_br %0, bb2, bb1
bb1:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
br bb3(%1 : $Builtin.Int1)
bb2:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
br bb3(%2 : $Builtin.Int1)
bb3(%a3 : $Builtin.Int1):
cond_fail %a3 : $Builtin.Int1
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @dont_move_cond_fail_no_postdom
// CHECK: bb1:
// CHECK-NEXT: apply
// CHECK-NEXT: integer_literal
// CHECK-NEXT: br bb5
// CHECK: bb2:
// CHECK-NEXT: apply
// CHECK-NEXT: cond_br
// CHECK: bb3:
// CHECK: br bb6
// CHECK: bb5({{.*}}):
// CHECK-NEXT: apply
// CHECK-NEXT: cond_fail
sil @dont_move_cond_fail_no_postdom : $@convention(thin) (Builtin.Int1, Builtin.Int1, Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1, %2 : $Builtin.Int1):
%f1 = function_ref @external_f : $@convention(thin) () -> ()
cond_br %0, bb2, bb1
bb1:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
%i1 = integer_literal $Builtin.Int1, -1
br bb3(%i1 : $Builtin.Int1)
bb2:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
cond_br %2, bb3(%1 : $Builtin.Int1), bb4
bb3(%a3 : $Builtin.Int1):
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
cond_fail %a3 : $Builtin.Int1
br bb4
bb4:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @dont_move_cond_fail_multiple_uses
// CHECK: bb1:
// CHECK-NEXT: apply
// CHECK-NEXT: integer_literal
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: apply
// CHECK-NEXT: br bb3
// CHECK: bb3({{.*}}):
// CHECK-NEXT: cond_fail
sil @dont_move_cond_fail_multiple_uses : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 {
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1):
%f1 = function_ref @external_f : $@convention(thin) () -> ()
cond_br %0, bb2, bb1
bb1:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
%i1 = integer_literal $Builtin.Int1, -1
br bb3(%i1 : $Builtin.Int1)
bb2:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
br bb3(%1 : $Builtin.Int1)
bb3(%a3 : $Builtin.Int1):
cond_fail %a3 : $Builtin.Int1
return %a3 : $Builtin.Int1
}
// CHECK-LABEL: sil @dont_move_cond_fail_multiple_uses2
// CHECK: bb1:
// CHECK-NEXT: apply
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: apply
// CHECK-NEXT: br bb3
// CHECK: bb3({{.*}}):
// CHECK-NEXT: builtin "xor_Int1"
// CHECK-NEXT: cond_fail
// CHECK-NEXT: return
sil @dont_move_cond_fail_multiple_uses2 : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> Builtin.Int1 {
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1):
%f1 = function_ref @external_f : $@convention(thin) () -> ()
%i1 = integer_literal $Builtin.Int1, -1
cond_br %0, bb2, bb1
bb1:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
br bb3(%i1 : $Builtin.Int1)
bb2:
apply %f1() : $@convention(thin) () -> () // prevent other CFG optimizations
br bb3(%1 : $Builtin.Int1)
bb3(%a3 : $Builtin.Int1):
%v1 = builtin "xor_Int1"(%a3 : $Builtin.Int1, %i1 : $Builtin.Int1) : $Builtin.Int1
cond_fail %v1 : $Builtin.Int1
return %v1 : $Builtin.Int1
}
// CHECK-LABEL: sil @successful_checked_cast_br_on_alloc_ref
// CHECK: bb0
// CHECK-NEXT: alloc_ref
// CHECK-NOT: checked_cast_br
// CHECK-NOT: bb1
// CHECK: integer_literal $Builtin.Int32, 1
// CHECK: strong_release
// CHECK: return
sil @successful_checked_cast_br_on_alloc_ref : $() -> Builtin.Int32 {
bb0:
%1 = alloc_ref $B
checked_cast_br [exact] B in %1 : $B to B, bb1, bb2
bb1(%2 : $B):
%3 = integer_literal $Builtin.Int32, 1
br bb3 (%3 : $Builtin.Int32)
bb2:
%5 = integer_literal $Builtin.Int32, 2
br bb3 (%5 : $Builtin.Int32)
bb3 (%10: $Builtin.Int32):
strong_release %1 : $B
return %10 : $Builtin.Int32
}
// CHECK-LABEL: sil @failing_checked_cast_br_on_alloc_ref
// CHECK: bb0
// CHECK-NEXT: alloc_ref
// CHECK-NOT: checked_cast_br
// CHECK-NOT: bb1
// CHECK: integer_literal $Builtin.Int32, 2
// CHECK: strong_release
// CHECK: return
sil @failing_checked_cast_br_on_alloc_ref : $() -> Builtin.Int32 {
bb0:
%1 = alloc_ref $E
%2 = upcast %1 : $E to $B
checked_cast_br [exact] B in %2 : $B to B, bb1, bb2
bb1(%3 : $B):
%4 = integer_literal $Builtin.Int32, 1
br bb3 (%4 : $Builtin.Int32)
bb2:
%5 = integer_literal $Builtin.Int32, 2
br bb3 (%5 : $Builtin.Int32)
bb3 (%10: $Builtin.Int32):
strong_release %1 : $E
return %10 : $Builtin.Int32
}
@objc protocol ObjcProto { func foo() }
// CHECK-LABEL: sil @thread_objc_method_call_succ_block
// CHECK: bb0
// CHECK: cond_br {{.*}}, bb1, bb3
// CHECK: bb1
// CHECK: objc_method
// CHECK: apply
// CHECK: strong_release
// CHECK: cond_br {{.*}}, bb2, bb6
// CHECK: bb3
// CHECK: strong_release
// CHECK: cond_br {{.*}}, bb5, bb4
// CHECK: bb7
// CHECK: cond_fail
// CHECK: br bb8
// CHECK: bb8:
// CHECK: strong_release
// CHECK: return
sil @thread_objc_method_call_succ_block : $@convention(thin) <T where T : ObjcProto> (Builtin.Int1, @owned T, Builtin.Int1) -> () {
bb0(%0: $Builtin.Int1, %1 : $T, %2 : $Builtin.Int1):
strong_retain %1 : $T
cond_br %0, bb1 , bb2
bb1:
%3 = objc_method %1 : $T, #ObjcProto.foo!foreign, $@convention(objc_method) <τ_0_0 where τ_0_0 : ObjcProto> (τ_0_0) -> ()
%4 = apply %3<T>(%1) : $@convention(objc_method) <τ_0_0 where τ_0_0 : ObjcProto> (τ_0_0) -> ()
br bb2
bb2:
strong_release %1 : $T
cond_br %2, bb3, bb4
bb3:
cond_fail %0 : $Builtin.Int1
br bb4
bb4:
strong_release %1 : $T
%41 = tuple ()
return %41 : $()
}
sil @f_use : $@convention(thin) (Builtin.Int32) -> ()
// CHECK-LABEL: sil @switch_enum_jumpthreading_bug
// CHECK: bb1:
// CHECK: [[INVADD:%.*]] = builtin "sadd
// CHECK: [[EXT:%.*]] = tuple_extract [[INVADD]]
// CHECK: switch_enum {{.*}} case #Optional.some!enumelt: bb3
// CHECK: bb3{{.*}}
// CHECK: br bb5(%2 : $Builtin.Int32, [[EXT]]
// CHECK: bb5([[CUR:%.*]] : $Builtin.Int32, [[NEXT:%.*]] : $Builtin.Int32
// CHECK: [[F:%.*]] = function_ref @f
// CHECK: apply [[F]]([[CUR]])
// CHECK: cond_br {{.*}}, bb7, bb6
// CHECK: bb7:
// CHECK: [[VARADD:%.*]] = builtin "sadd_with_overflow_Int32"([[NEXT]] : $Builtin.Int32
// CHECK: [[NEXT2:%.*]] = tuple_extract [[VARADD]]
// CHECK: br bb5([[NEXT]] : $Builtin.Int32, [[NEXT2]]
sil @switch_enum_jumpthreading_bug : $@convention(thin) (Optional<Builtin.Int32>, Builtin.Int1, Builtin.Int32, Builtin.Int1) -> Builtin.Int32 {
bb0(%0 : $Optional<Builtin.Int32>, %1 : $Builtin.Int1, %2: $Builtin.Int32, %3 : $Builtin.Int1):
cond_br %1, bb2, bb10
bb2:
br bb3(%2 : $Builtin.Int32, %0 : $Optional<Builtin.Int32>)
bb3(%10 : $Builtin.Int32, %7 : $Optional<Builtin.Int32>):
%4 = integer_literal $Builtin.Int32, 1
%5 = integer_literal $Builtin.Int1, -1
%6 = builtin "sadd_with_overflow_Int32"(%10 : $Builtin.Int32, %4 : $Builtin.Int32, %5 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%16 = tuple_extract %6 : $(Builtin.Int32, Builtin.Int1), 0
switch_enum %7 : $Optional<Builtin.Int32>, case #Optional.some!enumelt: bb5, case #Optional.none!enumelt: bb4
bb4:
cond_fail %5 : $Builtin.Int1
unreachable
bb5(%9 : $Builtin.Int32):
%f = function_ref @f_use : $@convention(thin) (Builtin.Int32) -> ()
%a = apply %f(%10) : $@convention(thin) (Builtin.Int32) -> ()
cond_br %3, bb6, bb10
bb6:
%8 = enum $Optional<Builtin.Int32>, #Optional.some!enumelt, %9 : $Builtin.Int32
br bb3(%16 : $Builtin.Int32, %8 : $Optional<Builtin.Int32>)
bb10:
br bb11(%2: $Builtin.Int32)
bb11(%100 : $Builtin.Int32):
return %100 : $Builtin.Int32
}
sil @a : $@convention(thin) () -> ()
sil @b : $@convention(thin) () -> ()
sil @c : $@convention(thin) () -> ()
sil @d : $@convention(thin) () -> ()
// CHECK-LABEL: sil @jump_thread_diamond
// CHECK: bb1:
// CHECK: [[A:%.*]] = function_ref @a
// CHECK: apply [[A]]
// CHECK: [[C:%.*]] = function_ref @c
// CHECK: apply [[C]]
// CHECK: br bb3
// CHECK: bb2:
// CHECK: [[B:%.*]] = function_ref @b
// CHECK: apply [[B]]
// CHECK: [[D:%.*]] = function_ref @d
// CHECK: apply [[D]]
// CHECK: br bb3
// CHECK: return
sil @jump_thread_diamond : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
%1 = integer_literal $Builtin.Int1, -1
%2 = builtin "int_expect_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
%8 = builtin "int_expect_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
%9 = builtin "int_expect_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
cond_br %8, bb1, bb2
bb1:
%10 = function_ref @a : $@convention(thin) () -> ()
%11 = apply %10() : $@convention(thin) () -> ()
br bb3
bb2:
%13 = function_ref @b : $@convention(thin) () -> ()
%14 = apply %13() : $@convention(thin) () -> ()
br bb3
bb3:
%19 = builtin "int_expect_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
%20 = builtin "int_expect_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
%21 = builtin "int_expect_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
cond_br %21, bb4, bb5
bb4:
%23 = function_ref @c : $@convention(thin) () -> ()
%24 = apply %23() : $@convention(thin) () -> ()
br bb6
bb5:
%26 = function_ref @d : $@convention(thin) () -> ()
%27 = apply %26() : $@convention(thin) () -> ()
br bb6
bb6:
%29 = tuple ()
return %29 : $()
}
enum AnEnum {
case B(Builtin.Int32), C(Builtin.Int16)
}
sil @f : $@convention(thin) (Builtin.Int32) -> ()
sil @f2 : $@convention(thin) (Builtin.Int16) -> ()
// CHECK-LABEL: sil @jump_thread_switch_enum
// CHECK: bb0([[ARG:%.*]] : $AnEnum):
// CHECK: [[F:%.*]] = function_ref @f : $@convention(thin) (Builtin.Int32) -> ()
// CHECK: [[F2:%.*]] = function_ref @f2 : $@convention(thin) (Builtin.Int16) -> ()
// CHECK: switch_enum [[ARG]] : $AnEnum, case #AnEnum.B!enumelt: bb2, case #AnEnum.C!enumelt: bb1
// CHECK: bb1([[ARG3:%.*]] : $Builtin.Int16):
// CHECK: apply [[F2]]([[ARG3]])
// CHECK: [[UED2:%.*]] = unchecked_enum_data [[ARG]] : $AnEnum, #AnEnum.C!enumelt
// CHECK: apply [[F2]]([[UED2]])
// CHECK: br bb3
// CHECK: bb2([[ARG2:%.*]] : $Builtin.Int32):
// CHECK: apply [[F]]([[ARG2]])
// CHECK: [[UED:%.*]] = unchecked_enum_data [[ARG]] : $AnEnum, #AnEnum.B!enumelt
// CHECK: apply [[F]]([[UED]])
// CHECK: br bb3
sil @jump_thread_switch_enum : $@convention(thin) (AnEnum) -> () {
bb0(%0 : $AnEnum):
%1 = function_ref @f : $@convention(thin) (Builtin.Int32) -> ()
%2 = function_ref @f2 : $@convention(thin) (Builtin.Int16) -> ()
switch_enum %0 : $AnEnum, case #AnEnum.B!enumelt: bb1, case #AnEnum.C!enumelt: bb3
bb1(%4 : $Builtin.Int32):
br bb2
bb2:
%6 = apply %1(%4) : $@convention(thin) (Builtin.Int32) -> ()
br bb5
bb3(%8 : $Builtin.Int16):
br bb4
bb4:
%10 = apply %2(%8) : $@convention(thin) (Builtin.Int16) -> ()
br bb5
bb5:
switch_enum %0 : $AnEnum, case #AnEnum.C!enumelt: bb6, case #AnEnum.B!enumelt: bb8
bb6(%13 : $Builtin.Int16):
br bb7
bb7:
%15 = apply %2(%13) : $@convention(thin) (Builtin.Int16) -> ()
br bb10
bb8(%17 : $Builtin.Int32):
br bb9
bb9:
%19 = apply %1(%17) : $@convention(thin) (Builtin.Int32) -> ()
br bb10
bb10:
%21 = tuple ()
return %21 : $()
}
sil @fB : $@convention(thin) () -> ()
sil @fC : $@convention(thin) () -> ()
// Make sure that we correctly thread such that we end up calling @fB on the
// AnEnum.B path.
// CHECK-LABEL: sil @dont_jump_thread_switch_enum_to_cond_br
// CHECK: [[BFUN:%.*]] = function_ref @fB : $@convention(thin) () -> ()
// CHECK: [[FALSE:%.*]] = integer_literal $Builtin.Int1, 0
// CHECK: switch_enum [[ENUM:%.*]] : $AnEnum, case #AnEnum.B!enumelt: bb2
// CHECK: bb2:
// CHECK: [[F:%.*]] = select_enum [[ENUM]] : $AnEnum, case #AnEnum.B!enumelt: [[FALSE]]
// CHECK: cond_br [[F]], bb3, bb4
// CHECK: bb4:
// CHECK-NOT: br
// CHECK: apply [[BFUN]]
// CHECK: br
sil @dont_jump_thread_switch_enum_to_cond_br : $@convention(thin) (AnEnum) -> () {
bb0(%0 : $AnEnum):
%1 = function_ref @fB : $@convention(thin) () -> ()
%2 = function_ref @fC : $@convention(thin) () -> ()
%t = integer_literal $Builtin.Int1, 1
%f = integer_literal $Builtin.Int1, 0
switch_enum %0 : $AnEnum, case #AnEnum.B!enumelt: bb4, case #AnEnum.C!enumelt: bb5
bb4:
br bb1
bb5:
%8 = select_enum %0 : $AnEnum, case #AnEnum.B!enumelt: %f, case #AnEnum.C!enumelt: %t : $Builtin.Int1
cond_br %8, bb10, bb1
bb1:
%3 = select_enum %0 : $AnEnum, case #AnEnum.B!enumelt: %f, case #AnEnum.C!enumelt: %t : $Builtin.Int1
cond_br %3, bb2, bb3
bb2:
%6 = apply %2() : $@convention(thin) () -> ()
br bb10
bb3:
%7 = apply %1() : $@convention(thin) () -> ()
br bb10
bb10:
%21 = tuple ()
return %21 : $()
}
sil @rethrow_function : $@convention(thin) (@owned @callee_owned (Int) -> (Int, @error Error)) -> (Int, @error Error)
sil @non_throwing_closure : $@convention(thin) (Int) -> Int
// CHECK-LABEL: sil @replace_try_apply_with_apply
// CHECK: [[R:%[0-9]+]] = apply [nothrow] %1(%{{[0-9]+}}) : $@convention(thin) (@owned @callee_owned (Int) -> (Int, @error any Error)) -> (Int, @error any Error)
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: return [[R]] : $Int
sil @replace_try_apply_with_apply : $@convention(thin) () -> Int {
bb0:
%as = alloc_stack $Builtin.Int32
%0 = function_ref @rethrow_function : $@convention(thin) (@owned @callee_owned (Int) -> (Int, @error Error)) -> (Int, @error Error)
%1 = function_ref @non_throwing_closure : $@convention(thin) (Int) -> Int
%2 = thin_to_thick_function %1 : $@convention(thin) (Int) -> Int to $@callee_owned (Int) -> Int
%3 = convert_function %2 : $@callee_owned (Int) -> Int to $@callee_owned (Int) -> (Int, @error Error)
try_apply %0(%3) : $@convention(thin) (@owned @callee_owned (Int) -> (Int, @error Error)) -> (Int, @error Error), normal bb1, error bb2
bb1(%5 : $Int):
dealloc_stack %as: $*Builtin.Int32
return %5 : $Int
bb2(%8 : $Error):
dealloc_stack %as: $*Builtin.Int32
unreachable
}
public class EE {
init()
}
public class BB {
init()
}
public class CC : BB {
@inline(never) init(e: EE)
override init()
}
public protocol PP {
var prop1: BB? { get }
}
public class DD : PP {
public var prop1: BB? { get }
init()
}
// CHECK-LABEL: sil @replace_try_apply_with_apply_cast_return_type : $@convention(method) (@guaranteed DD) -> @owned Optional<BB>
// CHECK: bb0
// CHECK: apply %{{.*}}
// CHECK: convert_function
// CHECK-NOT: try_apply
// CHECK: apply
// Check that return value is properly casted
// CHECK-NEXT: enum $Optional<CC>, #Optional.some!enumelt, %{{.*}} : $CC
// CHECK-NEXT: upcast %{{.*}} : $Optional<CC> to $Optional<BB>
// CHECK-NEXT: return
sil @replace_try_apply_with_apply_cast_return_type: $@convention(method) (@guaranteed DD) -> @owned Optional<BB> {
bb0(%0 : $DD):
%1 = alloc_ref $EE
debug_value %1 : $EE
%3 = function_ref @initCC : $@convention(thin) (@thick CC.Type) -> @owned @callee_owned (@owned EE) -> @owned CC
%4 = metatype $@thick CC.Type
%5 = apply %3(%4) : $@convention(thin) (@thick CC.Type) -> @owned @callee_owned (@owned EE) -> @owned CC
%6 = convert_function %5 : $@callee_owned (@owned EE) -> @owned CC to $@callee_owned (@owned EE) -> (@owned Optional<BB>, @error Error)
try_apply %6(%1) : $@callee_owned (@owned EE) -> (@owned Optional<BB>, @error Error), normal bb1, error bb2
bb1(%8 : $Optional<BB>):
return %8 : $Optional<BB>
bb2(%10 : $Error):
unreachable
}
// Check that we don't crash on this, because we perform casting
// if the argument types of the converted function types do not match.
// CHECK-LABEL: try_apply_with_apply_of_cast_argument
// CHECK-NOT: try_apply {{%[0-9]+}}
// CHECK: convert_function
// CHECK: upcast
// CHECK: apply
// CHECK-NOT: try_apply
// CHECK: return
sil @try_apply_with_apply_of_cast_argument: $@convention(method) (@owned CC) -> @owned BB {
bb0(%0 : $CC):
%3 = function_ref @takeBB : $@convention(thin) (@owned BB) -> @owned BB
%6 = convert_function %3 : $@convention(thin) (@owned BB) -> @owned BB to $@convention(thin) (@owned CC) -> (@owned BB, @error Error)
try_apply %6(%0) : $@convention(thin) (@owned CC) -> (@owned BB, @error Error), normal bb1, error bb2
bb1(%8 : $BB):
return %8 : $BB
bb2(%10 : $Error):
// Prevent that the conversion is done because the error block is empty and unreachable.
%12 = function_ref @unknown : $@convention(thin) () -> ()
apply %12() : $@convention(thin) () -> ()
unreachable
}
sil [noinline] @initCC : $@convention(thin) (@thick CC.Type) -> @owned @callee_owned (@owned EE) -> @owned CC
sil [noinline] @takeBB : $@convention(thin) (@owned BB) -> @owned BB
// Check that we don't crash on this.
// The compiler should be able to cast between the labeled and unlabeled return tuple types.
// CHECK-LABEL: @try_apply_with_convert_function_returning_casted_unlabeled_tuple
// CHECK: [[T0:%.*]] = apply {{%[0-9]+}}
// CHECK: return [[T0]]
sil @try_apply_with_convert_function_returning_casted_unlabeled_tuple: $@convention(thin) () -> (Int32, Int32) {
bb0:
%3 = function_ref @returnLabeledTuple : $@convention(thin) () -> (Int32, Int32)
%6 = convert_function %3 : $@convention(thin) () -> (Int32, Int32) to $@convention(thin) () -> (Int32, Int32, @error Error)
try_apply %6() : $@convention(thin) () -> (Int32, Int32, @error Error), normal bb1, error bb2
bb1(%8 : $(Int32, Int32)):
return %8 : $(Int32, Int32)
bb2(%10 : $Error):
// Prevent that the conversion is done because the error block is empty and unreachable.
%12 = function_ref @unknown : $@convention(thin) () -> ()
apply %12() : $@convention(thin) () -> ()
unreachable
}
// Check that we don't crash on this.
// The compiler should be able to cast between the labeled and unlabeled return tuple types.
// CHECK-LABEL: @try_apply_with_convert_function_returning_casted_labeled_tuple
// CHECK: apply {{%[0-9]+}}
// Proper tuple is created by deconstructing the old one and creating a new one using its elements.
// CHECK: tuple_extract
// CHECK: tuple_extract
// CHECK: tuple
// CHECK: return
sil @try_apply_with_convert_function_returning_casted_labeled_tuple: $@convention(thin) () -> (Int32, Int32) {
bb0:
%3 = function_ref @returnUnlabeledTuple : $@convention(thin) () -> (Int32, Int32)
%6 = convert_function %3 : $@convention(thin) () -> (Int32, Int32) to $@convention(thin) () -> (Int32, Int32, @error Error)
try_apply %6() : $@convention(thin) () -> (Int32, Int32, @error Error), normal bb1, error bb2
bb1(%8 : $(Int32, Int32)):
return %8 : $(Int32, Int32)
bb2(%10 : $Error):
// Prevent that the conversion is done because the error block is empty and unreachable.
%12 = function_ref @unknown : $@convention(thin) () -> ()
apply %12() : $@convention(thin) () -> ()
unreachable
}
sil [noinline] @returnLabeledTuple: $@convention(thin) () -> (Int32, Int32)
sil [noinline] @returnUnlabeledTuple : $@convention(thin) () -> (Int32, Int32)
public class AAA {
}
public class BBB : AAA {
}
@inline(never) func returnUnlabeledTuple(b: BBB) -> (BBB, BBB)
func testit(f: (BBB) throws -> (AAA, AAA), _ b: BBB) throws -> (AAA, AAA)
func callit(b: BBB) throws -> (AAA, AAA)
sil [noinline] @returnUnlabeledTupleOfClasses : $@convention(thin) (@owned BBB) -> @owned (BBB, BBB) {
bb0(%0 : $BBB):
debug_value %0 : $BBB
strong_retain %0 : $BBB
%3 = tuple (%0 : $BBB, %0 : $BBB)
return %3 : $(BBB, BBB)
}
sil @testFunctorReturningUnlabeledTuple : $@convention(thin) (@owned @callee_owned (@owned BBB) -> (@owned (AAA, AAA), @error Error), @owned BBB) -> (@owned (AAA, AAA), @error Error) {
bb0(%0 : $@callee_owned (@owned BBB) -> (@owned (AAA, AAA), @error Error), %1 : $BBB):
debug_value %0 : $@callee_owned (@owned BBB) -> (@owned (AAA, AAA), @error Error)
debug_value %1 : $BBB
strong_retain %0 : $@callee_owned (@owned BBB) -> (@owned (AAA, AAA), @error Error)
strong_retain %1 : $BBB
try_apply %0(%1) : $@callee_owned (@owned BBB) -> (@owned (AAA, AAA), @error Error), normal bb1, error bb2
bb1(%7 : $(AAA, AAA)):
%8 = tuple_extract %7 : $(AAA, AAA), 0
%9 = tuple_extract %7 : $(AAA, AAA), 1
%10 = tuple (%8 : $AAA, %9 : $AAA)
strong_release %1 : $BBB
strong_release %0 : $@callee_owned (@owned BBB) -> (@owned (AAA, AAA), @error Error)
return %10 : $(AAA, AAA)
bb2(%14 : $Error):
strong_release %1 : $BBB
strong_release %0 : $@callee_owned (@owned BBB) -> (@owned (AAA, AAA), @error Error)
throw %14 : $Error
}
// Check that we don't crash on this. Currently we just do not optimize try_apply if
// we cannot cast the actual return type into expected return type.
// TODO: Change the checks when we support more complex casts of return types.
// CHECK-LABEL: @testCallingFunctionWithFunctorReturningUnlabeledTuple
// CHECK: try_apply {{%[0-9]+}}
// CHECK: return
sil @testCallingFunctionWithFunctorReturningUnlabeledTuple : $@convention(thin) (@owned BBB) -> (@owned (AAA, AAA), @error Error) {
bb0(%0 : $BBB):
debug_value %0 : $BBB
%2 = function_ref @testFunctorReturningUnlabeledTuple : $@convention(thin) (@owned @callee_owned (@owned BBB) -> (@owned (AAA, AAA), @error Error), @owned BBB) -> (@owned (AAA, AAA), @error Error)
%3 = function_ref @returnUnlabeledTupleOfClasses : $@convention(thin) (@owned BBB) -> @owned (BBB, BBB)
%4 = thin_to_thick_function %3 : $@convention(thin) (@owned BBB) -> @owned (BBB, BBB) to $@callee_owned (@owned BBB) -> @owned (BBB, BBB)
%5 = convert_function %4 : $@callee_owned (@owned BBB) -> @owned (BBB, BBB) to $@callee_owned (@owned BBB) -> (@owned (AAA, AAA), @error Error)
strong_retain %0 : $BBB
try_apply %2(%5, %0) : $@convention(thin) (@owned @callee_owned (@owned BBB) -> (@owned (AAA, AAA), @error Error), @owned BBB) -> (@owned (AAA, AAA), @error Error), normal bb1, error bb2
bb1(%8 : $(AAA, AAA)):
%9 = tuple_extract %8 : $(AAA, AAA), 0
%10 = tuple_extract %8 : $(AAA, AAA), 1
%11 = tuple (%9 : $AAA, %10 : $AAA)
strong_release %0 : $BBB
return %11 : $(AAA, AAA)
bb2(%14 : $Error):
strong_release %0 : $BBB
throw %14 : $Error
}
struct UP<T> {
}
struct UBP<A> {
}
struct CAB<A> {
}
sil @CABIdentityGetter : $@convention(thin) <τ_0_0> (UBP<τ_0_0>) -> UP<()>
sil @CABwithUnsafeBufferPointer : $@convention(method) <τ_0_0><τ_1_0> (@owned @callee_owned (UBP<τ_0_0>) -> (@out τ_1_0, @error Error), @guaranteed CAB<τ_0_0>) -> (@out τ_1_0, @error Error)
sil @thunk_helper : $@convention(thin) <τ_0_0> (UBP<τ_0_0>, @owned @callee_owned (UBP<τ_0_0>) -> (UP<()>, @error Error)) -> (@out UP<()>, @error Error)
// CHECK-LABEL: sil @check_parameters_casting_with_generics
// CHECK-NOT: try_apply
// CHECK: apply [nothrow] %{{.*}}<Element, UP<()>>
// CHECK: return
sil @check_parameters_casting_with_generics : $@convention(method) <Element> (@guaranteed CAB<Element>) -> UP<()> {
bb0(%0 : $CAB<Element>):
// function_ref Swift._ContiguousArrayBuffer.withUnsafeBufferPointer <A><B> (CAB<A>)((Swift.UBP<A>) throws -> B) throws -> B
%2 = function_ref @CABwithUnsafeBufferPointer : $@convention(method) <τ_0_0><τ_1_0> (@owned @callee_owned (UBP<τ_0_0>) -> (@out τ_1_0, @error Error), @guaranteed CAB<τ_0_0>) -> (@out τ_1_0, @error Error)
// function_ref Swift._ContiguousArrayBuffer.(identity.getter : UP<()>).(closure #1)
%3 = function_ref @CABIdentityGetter : $@convention(thin) <τ_0_0> (UBP<τ_0_0>) -> UP<()>
%4 = partial_apply %3<Element>() : $@convention(thin) <τ_0_0> (UBP<τ_0_0>) -> UP<()>
%5 = convert_function %4 : $@callee_owned (UBP<Element>) -> UP<()> to $@callee_owned (UBP<Element>) -> (UP<()>, @error Error)
// function_ref reabstraction thunk helper <A> from @callee_owned (@unowned UBP<A>) -> (@unowned UP<()>, @error @owned Swift.Error) to @callee_owned (@unowned UBP<A>) -> (@out UP<()>, @error @owned Swift.Error)
%6 = function_ref @thunk_helper : $@convention(thin) <τ_0_0> (UBP<τ_0_0>, @owned @callee_owned (UBP<τ_0_0>) -> (UP<()>, @error Error)) -> (@out UP<()>, @error Error)
%7 = partial_apply %6<Element>(%5) : $@convention(thin) <τ_0_0> (UBP<τ_0_0>, @owned @callee_owned (UBP<τ_0_0>) -> (UP<()>, @error Error)) -> (@out UP<()>, @error Error)
%8 = alloc_stack $UP<()>
%9 = unchecked_addr_cast %8 : $*UP<()> to $*UP<()>
%10 = convert_function %7 : $@callee_owned (UBP<Element>) -> (@out UP<()>, @error Error) to $@callee_owned (UBP<Element>) -> (@out UP<()>, @error Error)
try_apply %2<Element, UP<()>>(%8, %7, %0) : $@convention(method) <τ_0_0><τ_1_0> (@owned @callee_owned (UBP<τ_0_0>) -> (@out τ_1_0, @error Error), @guaranteed CAB<τ_0_0>) -> (@out τ_1_0, @error Error), normal bb1, error bb2
bb1(%12 : $()):
%13 = load %8 : $*UP<()>
dealloc_stack %8 : $*UP<()>
return %13 : $UP<()>
bb2(%16 : $Error):
unreachable
}
// CHECK-LABEL: sil @unpack_enum_arg
// CHECK: bb1:
// CHECK: br bb3(%0 : $Int)
// CHECK: bb2:
// CHECK: br bb3(%1 : $Int)
// CHECK: bb3([[A:%[0-9]+]] : $Int):
// CHECK: return [[A]]
sil @unpack_enum_arg : $@convention(thin) (Int, Int) -> Int {
bb0(%0 : $Int, %1 : $Int):
cond_br undef, bb1, bb2
bb1:
%2 = enum $Optional<Int>, #Optional.some!enumelt, %0 : $Int
br bb3(%2 : $Optional<Int>)
bb2:
%3 = enum $Optional<Int>, #Optional.some!enumelt, %1 : $Int
br bb3(%3 : $Optional<Int>)
bb3(%4 : $Optional<Int>):
%5 = unchecked_enum_data %4 : $Optional<Int>, #Optional.some!enumelt
return %5 : $Int
}
// CHECK-LABEL: sil @dont_crash_on_enum_payload_is_enum
// CHECK: bb0(%0 : $TwoCase):
// CHECK: switch_enum %0
// CHECK: bb1:
// CHECK: return
sil @dont_crash_on_enum_payload_is_enum : $@convention(thin) (TwoCase) -> () {
bb0(%0 : $TwoCase):
%x = enum $Optional<TwoCase>, #Optional.some!enumelt, %0 : $TwoCase
br bb1(%x : $Optional<TwoCase>)
bb1(%10 : $Optional<TwoCase>):
switch_enum %10 : $Optional<TwoCase>, case #Optional.some!enumelt: bb2, case #Optional.none!enumelt: bb5
bb2(%1 : $TwoCase):
// Simplification of that switch_enum crashed the compiler because
// SILArgument::getIncomingValues returns %10 ($Optional<TwoCase>) as the
// incoming value for %1 ($TwoCase).
// rdar://problem/26251856
switch_enum %1 : $TwoCase, case #TwoCase.First!enumelt: bb3, case #TwoCase.Second!enumelt: bb4
bb3:
%f1 = function_ref @unknown : $@convention(thin) () -> ()
%n1 = apply %f1() : $@convention(thin) () -> ()
br bb6
bb4:
br bb6
bb5:
br bb6
bb6:
%6 = tuple ()
return %6 : $()
}
enum TestEnum {
case int64(Builtin.Int64)
case string (Base)
case none
}
enum MyError : Error {
case a
case b
case c(TestEnum)
}
enum MyError2 : Error {
case o(Optional<MyError>)
}
sil @foo : $@convention(thin) (Builtin.Int64) -> Builtin.Int8
sil @foo2 : $@convention(thin) (Builtin.Int32) -> Builtin.Int8
sil @dont_thread_throw_block : $@convention(thin) (@guaranteed TestEnum) -> (Builtin.Int8, @error Error) {
bb0(%0 : $TestEnum):
switch_enum %0 : $TestEnum, case #TestEnum.int64!enumelt: bb1, default bb4
bb1(%5 : $Builtin.Int64):
%7 = function_ref @foo : $@convention(thin) (Builtin.Int64) -> Builtin.Int8
%9 = apply %7(%5) : $@convention(thin) (Builtin.Int64) -> Builtin.Int8
br bb6(%9 : $Builtin.Int8)
bb2(%11 : $Builtin.Int32):
%13 = function_ref @foo2 : $@convention(thin) (Builtin.Int32) -> Builtin.Int8
%15 = apply %13(%11) : $@convention(thin) (Builtin.Int32) -> Builtin.Int8
br bb6(%15 : $Builtin.Int8)
bb4:
debug_value %0 : $TestEnum
%22 = alloc_existential_box $Error, $MyError2
%23 = project_existential_box $MyError2 in %22 : $Error
switch_enum %0 : $TestEnum, case #TestEnum.none!enumelt: bbnone, case #TestEnum.int64!enumelt: bb7, case #TestEnum.string!enumelt: bb10
bbnone:
%tn = enum $TestEnum, #TestEnum.none!enumelt
%en = enum $MyError, #MyError.c!enumelt, %tn : $TestEnum
br bb5(%en : $MyError)
bb7(%50 : $Builtin.Int64):
%t = enum $TestEnum, #TestEnum.int64!enumelt, %50 : $Builtin.Int64
%e1 = enum $MyError, #MyError.c!enumelt, %t : $TestEnum
br bb5(%e1 : $MyError)
bb10(%53 : $Base):
%t4 = enum $TestEnum, #TestEnum.string!enumelt, %53 : $Base
%e4 = enum $MyError, #MyError.c!enumelt, %t4 : $TestEnum
br bb5(%e4 : $MyError)
bb5(%e : $MyError):
%89 = enum $Optional<MyError>, #Optional.some!enumelt, %e : $MyError
%e5 = enum $MyError2, #MyError2.o!enumelt, %89 : $Optional<MyError>
store %e5 to %23 : $*MyError2
throw %22 : $Error
bb6(%44 : $Builtin.Int8):
return %44 : $Builtin.Int8
}
// CHECK-LABEL: jump_thread_retain_release
// CHECK: cond_br
// CHECK: cond_br %3, bb4, bb3
// CHECK: bb3:
// CHECK: strong_retain %2 : $foo
// CHECK: strong_release %2 : $foo
// CHECK: br bb5(%2 : $foo)
// CHECK: bb4:
// CHECK: strong_retain %1 : $foo
// CHECK: strong_release %1 : $foo
// CHECK: br bb5(%1 : $foo)
sil @jump_thread_retain_release : $@convention(thin) (Builtin.Int1, foo, foo, Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1, %1 : $foo, %2 : $foo, %3 : $Builtin.Int1):
cond_br %0, bb2, bb1
bb1:
br bb6(%2 : $foo)
bb2:
cond_br %3, bb3, bb4
bb3:
strong_retain %1 : $foo
br bb5(%1 : $foo)
bb4:
strong_retain %2 : $foo
br bb5(%2 : $foo)
bb5(%11 : $foo):
strong_release %11 : $foo
br bb6(%11 : $foo)
bb6(%14 : $foo):
strong_release %14 : $foo
%16 = tuple ()
return %16 : $()
}
protocol Q {}
class IsQ : Q {}
// checked_cast_br take_* should be replaced by a destroy in case it ever
// converts a managed object to an unmanaged value. Currently this doesn't
// happen at the language level because bridge (NSNumber->Int) casts aren't
// represented with checked_cast_br.
// ---
// CHECK-LABEL: sil @test_dead_checked_cast_br : $@convention(thin) (@in IsQ) -> () {
// CHECK: bb0(%0 : $*IsQ):
// CHECK: [[Q:%.*]] = alloc_stack $any Q
// CHECK: [[LD:%.*]] = load %0 : $*IsQ
// CHECK: strong_release [[LD]] : $IsQ
// CHECK: dealloc_stack [[Q]] : $*any Q
// CHECK: [[R:%.*]] = tuple ()
// CHECK: return [[R]] : $()
// CHECK-LABEL: } // end sil function 'test_dead_checked_cast_br'
sil @test_dead_checked_cast_br : $@convention(thin) (@in IsQ) -> () {
bb0(%0 : $*IsQ):
%p = alloc_stack $Q
checked_cast_addr_br take_always IsQ in %0 : $*IsQ to Q in %p : $*Q, bb1, bb3
bb1:
%m1 = integer_literal $Builtin.Int1, -1
br bb2(%m1 : $Builtin.Int1)
bb2(%5 : $Builtin.Int1):
// To avoid violating ownership, Q needs to be destroyed here. However, that
// would create a use of the checked_cast, defeating the test. In theory, Q
// could be some unmanaged type with no destroy, but we don't have a way to
// express that in the type system, and bridged casts don't yet go through
// this optimization path.
dealloc_stack %p : $*Q
%r = tuple ()
return %r : $()
bb3:
%z = integer_literal $Builtin.Int1, 0
br bb2(%z : $Builtin.Int1)
}
// CHECK-LABEL: sil @trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed Int, @guaranteed Int) -> @owned Int
// CHECK: [[SRC:%.*]] = alloc_stack $Int
// CHECK: store %0 to [[SRC]]
// CHECK: [[DST:%.*]] = alloc_stack $Int
// CHECK: [[LD1:%.*]] = load [[SRC]]
// CHECK: store [[LD1]] to [[DST]]
// CHECK: [[LD2:%.*]] = load [[DST]]
// CHECK: return [[LD2]]
// CHECK: } // end sil function 'trivial_checked_cast_addr_br'
sil @trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed Int, @guaranteed Int) -> @owned Int {
bb0(%0 : $Int, %1 : $Int):
%6 = alloc_stack $Int
store %0 to %6 : $*Int
%8 = alloc_stack $Int
checked_cast_addr_br copy_on_success Int in %6 : $*Int to Int in %8 : $*Int, bb1, bb2
bb1:
%10 = load %8 : $*Int
dealloc_stack %8 : $*Int
br bb3(%10 : $Int)
bb2:
retain_value %1: $Int
dealloc_stack %8 : $*Int
br bb3(%1 : $Int)
bb3(%11 : $Int):
dealloc_stack %6 : $*Int
return %11 : $Int
}
// CHECK-LABEL: sil @non_trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed String, @guaranteed String) -> @owned String
// CHECK: [[SRC:%.*]] = alloc_stack $String
// CHECK: store %0 to [[SRC]]
// CHECK: [[DST:%.*]] = alloc_stack $String
// CHECK: [[TEMP:%.*]] = alloc_stack $String
// CHECK: copy_addr [[SRC]] to [init] [[TEMP]]
// CHECK: [[LD1:%.*]] = load [[TEMP]]
// CHECK: store [[LD1]] to [[DST]]
// CHECK: [[LD2:%.*]] = load [[DST]]
// CHECK: return [[LD2]]
// CHECK: } // end sil function 'non_trivial_checked_cast_addr_br'
sil @non_trivial_checked_cast_addr_br : $@convention(thin) (@guaranteed String, @guaranteed String) -> @owned String {
bb0(%0 : $String, %1 : $String):
%6 = alloc_stack $String
store %0 to %6 : $*String
%8 = alloc_stack $String
checked_cast_addr_br copy_on_success String in %6 : $*String to String in %8 : $*String, bb1, bb2
bb1:
%10 = load %8 : $*String
dealloc_stack %8 : $*String
br bb3(%10 : $String)
bb2:
retain_value %1: $String
dealloc_stack %8 : $*String
br bb3(%1 : $String)
bb3(%11 : $String):
dealloc_stack %6 : $*String
return %11 : $String
}
// CHECK-LABEL: sil @dont_hang
// CHECK: bb6:
// CHECK: integer_literal $Builtin.Int64, 1
// CHECK-NEXT: br bb6
// CHECK-NEXT: }
sil @dont_hang : $@convention(thin) () -> () {
bb0:
cond_br undef, bb1, bb4
bb1:
%0 = integer_literal $Builtin.Int64, 1
cond_br undef, bb2, bb6
bb2:
br bb3
bb3:
br bb5
bb4:
%1 = integer_literal $Builtin.Int64, 1
br bb3
bb5:
br bb2
bb6:
%2 = integer_literal $Builtin.Int64, 1
br bb7
bb7:
br bb5
}
// CHECK-LABEL: sil @test_constant_folding
// CHECK: [[R:%[0-9]+]] = integer_literal $Builtin.Int32, 30
// CHECK: return [[R]] : $Builtin.Int32
// CHECK-NEXT: }
sil @test_constant_folding : $@convention(thin) () -> Builtin.Int32 {
bb0:
%0 = integer_literal $Builtin.Int1, 0
%20 = integer_literal $Builtin.Int32, 20
%30 = integer_literal $Builtin.Int32, 30
cond_br %0, bb1, bb2
bb1:
br bb3(%20 : $Builtin.Int32)
bb2:
br bb3(%30 : $Builtin.Int32)
bb3(%2 : $Builtin.Int32):
%3 = builtin "cmp_slt_Int32"(%2 : $Builtin.Int32, %30 : $Builtin.Int32) : $Builtin.Int1
cond_br %3, bb4, bb5
bb4:
br bb6(%20 : $Builtin.Int32)
bb5:
br bb6(%30 : $Builtin.Int32)
bb6(%4 : $Builtin.Int32):
%5 = builtin "cmp_slt_Int32"(%4 : $Builtin.Int32, %30 : $Builtin.Int32) : $Builtin.Int1
cond_br %5, bb7, bb8
bb7:
br bb9(%20 : $Builtin.Int32)
bb8:
br bb9(%30 : $Builtin.Int32)
bb9(%6 : $Builtin.Int32):
return %6 : $Builtin.Int32
}
sil @adder : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> Builtin.Int32
// CHECK-LABEL: sil @test_noescape
// CHECK: [[FN:%.*]] = function_ref @adder
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[FN]](%0)
// CHECK-NOT: try_apply
// CHECK: apply [[PA]](%1)
// CHECK: return
sil @test_noescape : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> Builtin.Int32 {
bb0(%0 : $Builtin.Int32, %1 : $Builtin.Int32):
%f = function_ref @adder : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> Builtin.Int32
%pa = partial_apply [callee_guaranteed] %f(%0) : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> Builtin.Int32
%conv = convert_function %pa : $@callee_guaranteed (Builtin.Int32) -> (Builtin.Int32) to $@callee_guaranteed (Builtin.Int32) -> (Builtin.Int32, @error Error)
%ne = convert_escape_to_noescape %conv : $@callee_guaranteed (Builtin.Int32) -> (Builtin.Int32, @error Error) to $@noescape @callee_guaranteed (Builtin.Int32) -> (Builtin.Int32, @error Error)
try_apply %ne(%1) : $@noescape @callee_guaranteed (Builtin.Int32) -> (Builtin.Int32, @error Error), normal bb1, error bb2
bb1(%r : $Builtin.Int32):
br bb3(%r : $Builtin.Int32)
bb2(%e : $Error):
%r1 = integer_literal $Builtin.Int32, 0
br bb3(%r1 : $Builtin.Int32)
bb3(%res : $Builtin.Int32):
release_value %pa : $@callee_guaranteed (Builtin.Int32) -> (Builtin.Int32)
return %res : $Builtin.Int32
}
struct TestStr {
let a: Int32
let c: Int32
}
enum TestEnm {
case X
case Y(TestStr)
}
// CHECK-LABEL: sil @dont_crash
// CHECK: bb0(%0 : $TestEnm, %1 : $Int32):
// CHECK-NEXT: %2 = tuple ()
// CHECK-NEXT: return %2 : $()
sil @dont_crash : $@convention(method) (TestEnm, Int32) -> () {
bb0(%2 : $TestEnm, %3 : $Int32):
%98 = integer_literal $Builtin.Int1, -1
cond_br %98, bb2, bb3
bb2:
%18 = tuple()
return %18 : $()
bb3:
br bb8(%2 : $TestEnm)
bb8(%47 : $TestEnm):
%49 = unchecked_enum_data %47 : $TestEnm, #TestEnm.Y!enumelt
%57 = struct_extract %49 : $TestStr, #TestStr.c
cond_br undef, bb9, bb11
bb9:
br bb10
bb10:
%64 = struct $TestStr (%3 : $Int32, %57 : $Int32)
%65 = enum $TestEnm, #TestEnm.Y!enumelt, %64 : $TestStr
cond_br undef, bb2, bb16
bb11:
br bb10
bb16:
br bb8(%65 : $TestEnm)
}
sil @print : $@convention(thin) (@guaranteed String) -> ()
sil @yield_string : $@yield_once @convention(thin) () -> @yields @guaranteed String
sil @dont_clone_begin_apply : $(Builtin.Int1, @guaranteed String) -> () {
bb0(%condition : $Builtin.Int1, %arg : $String):
%print = function_ref @print : $@convention(thin) (@guaranteed String) -> ()
cond_br %condition, bb1, bb2
bb1:
apply %print(%arg) : $@convention(thin) (@guaranteed String) -> ()
br bb3
bb2:
br bb3
bb3:
%yield_string = function_ref @yield_string : $@yield_once @convention(thin) () -> @yields @guaranteed String
(%yield, %token) = begin_apply %yield_string() : $@yield_once @convention(thin) () -> @yields @guaranteed String
cond_br %condition, bb4, bb5
bb4:
apply %print(%yield) : $@convention(thin) (@guaranteed String) -> ()
br bb6
bb5:
br bb6
bb6:
end_apply %token as $()
%rv = tuple ()
return %rv : $()
}
class X {
@objc func f() { }
}
sil @external_g : $@convention(thin) () -> ()
// Don't tail duplicate dynamic_method_br. IRGen cannot handle phi nodes of
// objc_methods.
// CHECK-LABEL: sil @dont_tail_duplicate_dynamic_method_br
// CHECK: dynamic_method_br
// CHECK-NOT: dynamic_method_br
// CHECK: return
sil @dont_tail_duplicate_dynamic_method_br : $@convention(thin) (@owned Builtin.AnyObject, Builtin.Int1) -> () {
bb0(%x : $Builtin.AnyObject, %b : $Builtin.Int1):
cond_br %b, bb1, bb2
bb1:
%f = function_ref @external_f : $@convention(thin) () -> ()
apply %f() : $@convention(thin) () -> ()
strong_retain %x : $Builtin.AnyObject
br bb3(%x : $Builtin.AnyObject)
bb2:
%g = function_ref @external_g : $@convention(thin) () -> ()
apply %g() : $@convention(thin) () -> ()
strong_retain %x : $Builtin.AnyObject
br bb3(%x : $Builtin.AnyObject)
bb3(%y: $Builtin.AnyObject):
strong_release %y : $Builtin.AnyObject
dynamic_method_br %x : $Builtin.AnyObject, #X.f!foreign, bb4, bb5
bb4(%m : $@convention(objc_method) (Builtin.AnyObject) -> ()):
br bb6
bb5:
br bb6
bb6:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @dont_crash_in_cast_jump_threading
// CHECK: checked_cast_br
// CHECK: } // end sil function 'dont_crash_in_cast_jump_threading'
sil @dont_crash_in_cast_jump_threading : $@convention(thin) (Optional<Base>) -> () {
bb0(%0 : $Optional<Base>):
br bb1
bb1:
switch_enum %0 : $Optional<Base>, case #Optional.some!enumelt: bb2, case #Optional.none!enumelt: bb21
bb2(%18 : $Base):
checked_cast_br Base in %18 : $Base to Derived, bb3, bb4
bb3(%21 : $Derived):
%22 = integer_literal $Builtin.Int1, -1
br bb5(%22 : $Builtin.Int1)
bb4:
%24 = integer_literal $Builtin.Int1, 0
br bb5(%24 : $Builtin.Int1)
bb5(%26 : $Builtin.Int1):
cond_br %26, bb6, bb19
bb6:
checked_cast_br Base in %18 : $Base to Derived, bb7, bb8
bb7(%29 : $Derived):
%30 = enum $Optional<Derived>, #Optional.some!enumelt, %29 : $Derived
br bb9(%30 : $Optional<Derived>)
bb8:
%32 = enum $Optional<Derived>, #Optional.none!enumelt
br bb9(%32 : $Optional<Derived>)
bb9(%34 : $Optional<Derived>):
switch_enum %34 : $Optional<Derived>, case #Optional.some!enumelt: bb10, case #Optional.none!enumelt: bb18
bb10(%36 : $Derived):
br bb11
bb11:
checked_cast_br Base in %18 : $Base to Derived, bb12, bb13
bb12(%43 : $Derived):
%44 = enum $Optional<Derived>, #Optional.some!enumelt, %43 : $Derived
br bb14(%44 : $Optional<Derived>)
bb13:
%46 = enum $Optional<Derived>, #Optional.none!enumelt
br bb14(%46 : $Optional<Derived>)
bb14(%48 : $Optional<Derived>):
switch_enum %48 : $Optional<Derived>, case #Optional.some!enumelt: bb15, case #Optional.none!enumelt: bb17
bb15(%50 : $Derived):
br bb16
bb16:
br bb20
bb17:
br bb16
bb18:
br bb11
bb19:
br bb20
bb20:
br bb1
bb21:
%75 = tuple ()
return %75 : $()
}