| // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s |
| // FIXME: Update for select_enum change. |
| |
| import Builtin |
| import Swift |
| |
| sil_stage canonical |
| |
| /////////////////////// |
| // 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 // id: %3 |
| |
| bb1: // Preds: bb0 |
| %4 = integer_literal $Builtin.Int1, -1 // user: %5 |
| br bb2(%4 : $Builtin.Int1) // id: %5 |
| |
| bb2(%6 : $Builtin.Int1): // Preds: bb3 bb1 |
| br bb4 // id: %7 |
| |
| bb3: // Preds: bb0 |
| %8 = integer_literal $Builtin.Int1, 0 // user: %9 |
| br bb2(%8 : $Builtin.Int1) // id: %9 |
| |
| bb4: // Preds: bb2 |
| cond_br %6, bb5, bb6 // id: %10 |
| |
| bb5: // Preds: bb4 |
| %11 = metatype $@thin Int64.Type |
| %12 = integer_literal $Builtin.Int64, 42 // user: %13 |
| %13 = struct $Int64 (%12 : $Builtin.Int64) // user: %14 |
| br bb7(%13 : $Int64) // id: %14 |
| |
| bb6: // Preds: bb4 |
| %15 = metatype $@thin Int64.Type |
| %16 = integer_literal $Builtin.Int64, 17 // user: %17 |
| %17 = struct $Int64 (%16 : $Builtin.Int64) // user: %18 |
| br bb7(%17 : $Int64) // id: %18 |
| |
| bb7(%19 : $Int64): // Preds: bb6 bb5 |
| return %19 : $Int64 // id: %21 |
| } |
| |
| // 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: // Preds: bb0 |
| %4 = enum $BoolLike, #BoolLike.true_!enumelt // user: %5 |
| br bb3(%4 : $BoolLike) // id: %5 |
| |
| bb2: // Preds: bb0 |
| %8 = enum $BoolLike, #BoolLike.false_!enumelt // user: %9 |
| br bb3(%8 : $BoolLike) // id: %9 |
| |
| bb3(%6 : $BoolLike): // Preds: bb3 bb1 |
| %100 = select_enum %6 : $BoolLike, case #BoolLike.true_!enumelt: %t, case #BoolLike.false_!enumelt: %f : $Builtin.Int1 |
| br bb4 // id: %7 |
| |
| bb4: // Preds: bb2 |
| cond_br %100, bb5, bb6 // id: %10 |
| |
| bb5: // Preds: bb4 |
| %11 = metatype $@thin Int64.Type |
| %12 = integer_literal $Builtin.Int64, 42 // user: %13 |
| %13 = struct $Int64 (%12 : $Builtin.Int64) // user: %14 |
| br bb7(%13 : $Int64) // id: %14 |
| |
| bb6: // Preds: bb4 |
| %15 = metatype $@thin Int64.Type |
| %16 = integer_literal $Builtin.Int64, 17 // user: %17 |
| %17 = struct $Int64 (%16 : $Builtin.Int64) // user: %18 |
| br bb7(%17 : $Int64) // id: %18 |
| |
| bb7(%19 : $Int64): // Preds: bb6 bb5 |
| return %19 : $Int64 // id: %21 |
| } |
| |
| // 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: // Preds: bb0 |
| %4 = enum $BoolLike, #BoolLike.true_!enumelt // user: %5 |
| %40 = integer_literal $Builtin.Int64, 16 |
| br bb3(%4 : $BoolLike, %40 : $Builtin.Int64) // id: %5 |
| |
| bb2: // Preds: bb0 |
| %8 = enum $BoolLike, #BoolLike.false_!enumelt // user: %9 |
| %80 = integer_literal $Builtin.Int64, 17 |
| br bb3(%8 : $BoolLike, %80 : $Builtin.Int64) // id: %9 |
| |
| bb3(%6 : $BoolLike, %60 : $Builtin.Int64): // Preds: bb3 bb1 |
| %100 = select_enum %6 : $BoolLike, case #BoolLike.true_!enumelt: %t, case #BoolLike.false_!enumelt: %f : $Builtin.Int1 |
| br bb4 // id: %7 |
| |
| bb4: // Preds: bb2 |
| cond_br %100, bb5, bb6 // id: %10 |
| |
| bb5: // Preds: bb4 |
| %11 = metatype $@thin Int64.Type |
| %12 = integer_literal $Builtin.Int64, 42 // user: %13 |
| %13 = struct $Int64 (%12 : $Builtin.Int64) // user: %14 |
| br bb7(%13 : $Int64) // id: %14 |
| |
| bb6: // Preds: bb4 |
| %15 = metatype $@thin Int64.Type |
| %17 = struct $Int64 (%60 : $Builtin.Int64) // user: %18 |
| br bb7(%17 : $Int64) // id: %18 |
| |
| bb7(%19 : $Int64): // Preds: bb6 bb5 |
| return %19 : $Int64 // id: %21 |
| } |
| |
| |
| |
| /// 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, bb1, bb2 |
| // CHECK: bb1: |
| // CHECK-NEXT: br bb3 |
| // CHECK: bb2: |
| // CHECK: 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 |
| } |
| |
| // Make sure that a conditional branch to a trampoline without parameters |
| // gets eliminated by branching to a target of this trampoline. |
| // CHECK-LABEL: @elim_trampoline5 |
| // CHECK: cond_br |
| // CHECK: bb3: |
| // CHECK: cond_br |
| // CHECK: bb4{{.*}}: |
| // Last cond_br should branch directly to the target of a trampoline |
| // instead of the original bb3 |
| // CHECK: cond_br {{.*}}, bb3, bb5 |
| // CHECK: bb5: |
| // CHECK-NEXT: br bb4 |
| // 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 bb0 |
| sil @infinite_loop : $@convention(thin) () -> () { |
| bb0: |
| br bb0 |
| } |
| |
| import Builtin |
| import Swift |
| |
| // CHECK-LABEL: @dead_loop |
| // CHECK-NOT: br bb |
| sil @dead_loop : $@convention(thin) () -> () { |
| bb0: |
| %0 = integer_literal $Builtin.Int1, 0 // users: %1, %4 |
| %2 = integer_literal $Builtin.Int1, -1 // user: %11 |
| cond_br %0, bb1, bb3 // id: %4 |
| |
| bb1: // Preds: bb0 |
| %5 = integer_literal $Builtin.Int32, 0 // users: %6, %7 |
| %6 = struct $Int32 (%5 : $Builtin.Int32) |
| br bb2(%5 : $Builtin.Int32) // id: %7 |
| |
| bb2(%8 : $Builtin.Int32): // Preds: bb1 bb2 |
| %9 = integer_literal $Builtin.Int32, 1 // user: %11 |
| %11 = builtin "sadd_with_overflow_Int32"(%8 : $Builtin.Int32, %9 : $Builtin.Int32, %2 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %12, %13 |
| %12 = tuple_extract %11 : $(Builtin.Int32, Builtin.Int1), 0 // users: %15, %16 |
| %13 = tuple_extract %11 : $(Builtin.Int32, Builtin.Int1), 1 // user: %14 |
| cond_fail %13 : $Builtin.Int1 // id: %14 |
| %15 = struct $Int32 (%12 : $Builtin.Int32) |
| br bb2(%12 : $Builtin.Int32) // id: %16 |
| |
| bb3: // Preds: bb0 |
| %17 = tuple () // user: %18 |
| return %17 : $() // id: %18 |
| } |
| |
| // 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, [[TRUE:[a-zA-Z0-9]+]], [[FALSE:[a-zA-Z0-9]+]] |
| cond_br %1, bb1, bb2 |
| |
| // CHECK: [[TRUE]]: |
| bb1: |
| %3 = integer_literal $Builtin.Int1, 0 |
| %4 = struct $Bool (%3 : $Builtin.Int1) |
| // CHECK: br [[RETURN:[a-zA-Z0-9]+]] |
| br bb3(%4 : $Bool) |
| |
| // CHECK: [[FALSE]]: |
| bb2: |
| %6 = integer_literal $Builtin.Int1, -1 // user: %7 |
| %7 = struct $Bool (%6 : $Builtin.Int1) // user: %8 |
| // CHECK: br [[RETURN]] |
| br bb3(%7 : $Bool) // id: %8 |
| |
| // CHECK: [[RETURN]] |
| bb3(%9 : $Bool): // Preds: bb1 bb2 |
| // CHECK-NOT: struct_extract |
| %10 = struct_extract %9 : $Bool, #Bool._value // user: %11 |
| // CHECK: return |
| cond_br %10, bb4, bb5 // id: %11 |
| |
| // CHECK-NOT: bb4 |
| bb4: // Preds: bb3 |
| %12 = integer_literal $Builtin.Int1, 0 // user: %13 |
| %13 = struct $Bool (%12 : $Builtin.Int1) // user: %14 |
| br bb6(%13 : $Bool) // id: %14 |
| |
| // CHECK-NOT: bb5 |
| bb5: // Preds: bb3 |
| %15 = integer_literal $Builtin.Int1, -1 // user: %16 |
| %16 = struct $Bool (%15 : $Builtin.Int1) // user: %17 |
| br bb6(%16 : $Bool) // id: %17 |
| |
| bb6(%18 : $Bool): // Preds: bb4 bb5 |
| return %18 : $Bool // id: %19 |
| } |
| |
| 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.1: 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.1: bb5, case #Optional.none!enumelt: bb6 |
| |
| bb5: |
| %25 = unchecked_take_enum_data_addr %21 : $*Optional<C>, #Optional.some!enumelt.1 |
| %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.1, %11 : $Int32 |
| br bb3(%12 : $Optional<Int32>) |
| |
| bb2: |
| %22 = enum $Optional<Int32>, #Optional.some!enumelt.1, %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.1: 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.1 |
| // 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.1: bb2 |
| |
| bb1: |
| %12 = enum $Optional<Int32>, #Optional.some!enumelt.1, %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.1: 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.1: 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.1: 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.1: 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.1: 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.1: 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.1: 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.1: 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.1: 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 {{.*}}, bb2, bb3 |
| // CHECK: bb2: |
| // CHECK: return |
| // CHECK: bb3: |
| // CHECK: enum $Optional<Int32>, #Optional.some |
| // CHECK: br bb1( |
| |
| 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.1, %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.1: 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.1 |
| 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!1 : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> () |
| %1 = class_method %0 : $Base, #Base.middle!1 : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> () |
| // CHECK: checked_cast_br [exact] %0 : $Base to $Base, [[SUCCESS:bb[0-9]+]], [[FAIL:bb[0-9]+]] |
| checked_cast_br [exact] %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!1 : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> () |
| // CHECK-NOT: checked_cast_br |
| checked_cast_br [exact] %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!1 : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> () |
| %1 = class_method %0 : $Base, #Base.middle!1 : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> () |
| // CHECK: checked_cast_br [exact] %0 : $Base to $Base, [[SUCCESS:bb[0-9]+]], [[FAIL:bb[0-9]+]] |
| checked_cast_br [exact] %0 : $Base to $Base, bb2, bb7 |
| |
| bb1: |
| %3 = tuple () |
| return %3 : $() |
| |
| bb2(%5 : $Base): |
| // CHECK: [[SUCCESS]] |
| // CHECK: [[METHOD2:%.*]] = class_method %0 : $Base, #Base.inner!1 : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> () |
| %7 = class_method %0 : $Base, #Base.inner!1 : (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!1 : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> () |
| %15 = apply %14(%0) : $@convention(method) (@guaranteed Base) -> () |
| br bb4 |
| |
| bb6(%17 : $()): |
| br bb1 |
| |
| // CHECK: bb4: |
| // CHECK: tuple () |
| // CHECK: return |
| |
| bb7: |
| // CHECK: checked_cast_br [exact] %0 : $Base to $Derived |
| checked_cast_br [exact] %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!1 : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> () |
| %1 = class_method %0 : $Base, #Base.middle!1 : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> () |
| // CHECK: checked_cast_br [exact] %0 : $Base to $Base, [[SUCCESS:bb[0-9]+]], [[FAIL:bb[0-9]+]] |
| checked_cast_br [exact] %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!1 : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> () |
| %7 = class_method %0 : $Base, #Base.inner!1 : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> () |
| // CHECK-NOT: checked_cast_br [exact] %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] %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] %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] %0 : $Base to $Base, bb4, bb5 |
| |
| bb4(%2 : $Base): |
| apply %fu() : $@convention(thin) () -> () |
| br bb6 |
| |
| bb5: |
| apply %fu2() : $@convention(thin) () -> () |
| br bb6 |
| |
| bb6: |
| dealloc_ref [stack] %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.1, %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.1: bb4, case #Optional.none!enumelt: bb5 |
| |
| bb4: |
| %22 = unchecked_enum_data %20 : $Optional<Int32>, #Optional.some!enumelt.1 |
| %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.1, %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.1, %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.1: bb2, case #Optional.none!enumelt: bb3 |
| |
| bb2: |
| %9 = unchecked_enum_data %7 : $Optional<Int32>, #Optional.some!enumelt.1 |
| %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: switch_enum %0 : $Optional<Int32>, case #Optional.none!enumelt: bb1, case #Optional.some!enumelt.1: bb3 |
| // CHECK: bb1: |
| // CHECK-NEXT: switch_enum |
| // CHECK: bb2: |
| // CHECK-NEXT: br bb5 |
| // CHECK: bb3: |
| // CHECK-NEXT: br bb5 |
| // CHECK: bb4: |
| // CHECK-NEXT: br bb6 |
| // CHECK: bb5: |
| // CHECK-NEXT: br bb6 |
| // CHECK: bb6({{.*}}): |
| // 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.1: 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.1: 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-NEXT: cond_br undef, bb3, bb4 |
| // CHECK: bb2: |
| // CHECK: integer_literal {{.*}}, 27 |
| // CHECK: br bb5 |
| // CHECK: bb3: |
| // CHECK: br bb4 |
| // CHECK: bb4: |
| // CHECK: integer_literal {{.*}}, 28 |
| // CHECK: br bb5 |
| // CHECK: bb5({{.*}}): |
| // CHECK-NEXT: return |
| sil @jumpthread_switch_enum4 : $@convention(thin) () -> Builtin.Int32 { |
| bb0: |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %4 = enum $Optional<Int32>, #Optional.none!enumelt |
| cond_br undef, bb3(%4 : $Optional<Int32>), bb4(%4 : $Optional<Int32>) |
| |
| bb2: |
| %6 = integer_literal $Builtin.Int32, 0 |
| %7 = struct $Int32 (%6 : $Builtin.Int32) |
| %8 = enum $Optional<Int32>, #Optional.some!enumelt.1, %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>) |
| |
| |
| bb4(%13 : $Optional<Int32>): |
| switch_enum %13 : $Optional<Int32>, case #Optional.some!enumelt.1: bb5, case #Optional.none!enumelt: bb6 |
| |
| bb5: |
| %r1 = integer_literal $Builtin.Int32, 27 |
| %c2 = builtin "assert_configuration"() : $Builtin.Int32 |
| br bb7(%r1 : $Builtin.Int32) |
| |
| bb6: |
| %r2 = integer_literal $Builtin.Int32, 28 |
| %c3 = builtin "assert_configuration"() : $Builtin.Int32 |
| br bb7(%r2 : $Builtin.Int32) |
| |
| bb7(%r : $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.1, %7 : $Int32 |
| br bb1(%8 : $Optional<Int32>) |
| |
| bb1(%13 : $Optional<Int32>): |
| switch_enum %13 : $Optional<Int32>, case #Optional.some!enumelt.1: 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: class_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.1, %15 : $Int32 |
| br bb3(%1 : $Builtin.Int32, %14 : $Builtin.Int32, %16 : $Optional<Int32>) |
| |
| bb3(%18 : $Builtin.Int32, %19 : $Builtin.Int32, %20 : $Optional<Int32>): |
| %101 = class_method [volatile] %100 : $Bar, #Bar.foo!1.foreign : (Bar) -> () -> (), $@convention(objc_method) (Bar) -> () |
| switch_enum %20 : $Optional<Int32>, case #Optional.some!enumelt.1: 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.1 |
| %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 : $() |
| } |
| |
| enum IntEnum : Int32 { |
| case E0 |
| case E1 |
| case E2 |
| } |
| |
| // CHECK-LABEL: sil @create_select_value : $@convention(thin) (Builtin.Int32) -> Optional<IntEnum> { |
| // CHECK-DAG: [[X2:%[0-9]+]] = integer_literal $Builtin.Int32, 0 |
| // CHECK-DAG: [[X5:%[0-9]+]] = enum $Optional<IntEnum>, #Optional.none!enumelt |
| // CHECK-DAG: [[X6:%[0-9]+]] = integer_literal $Builtin.Int32, 2 |
| // CHECK-DAG: [[X7:%[0-9]+]] = enum $IntEnum, #IntEnum.E2!enumelt |
| // CHECK-DAG: [[X8:%[0-9]+]] = enum $Optional<IntEnum>, #Optional.some!enumelt.1, [[X7]] : $IntEnum |
| // CHECK-DAG: [[X9:%[0-9]+]] = integer_literal $Builtin.Int32, 1 |
| // CHECK-DAG: [[X10:%[0-9]+]] = enum $IntEnum, #IntEnum.E1!enumelt |
| // CHECK-DAG: [[X11:%[0-9]+]] = enum $Optional<IntEnum>, #Optional.some!enumelt.1, [[X10]] : $IntEnum |
| // CHECK-DAG: [[X12:%[0-9]+]] = enum $IntEnum, #IntEnum.E0!enumelt |
| // CHECK-DAG: [[X13:%[0-9]+]] = enum $Optional<IntEnum>, #Optional.some!enumelt.1, [[X12]] : $IntEnum |
| // CHECK-DAG: [[X14:%[0-9]+]] = select_value %0 : $Builtin.Int32, case [[X6]]: [[X8]], case [[X9]]: [[X11]], case [[X2]]: [[X13]], default [[X5]] : $Optional<IntEnum> |
| // CHECK-DAG: return [[X14]] : $Optional<IntEnum> |
| sil @create_select_value : $@convention(thin) (Builtin.Int32) -> Optional<IntEnum> { |
| bb0(%0 : $Builtin.Int32): |
| %2 = integer_literal $Builtin.Int32, 0 |
| %4 = builtin "cmp_eq_Int32"(%2 : $Builtin.Int32, %0 : $Builtin.Int32) : $Builtin.Int1 |
| cond_br %4, bb1, bb2 |
| |
| bb1: |
| %6 = enum $IntEnum, #IntEnum.E0!enumelt |
| %7 = enum $Optional<IntEnum>, #Optional.some!enumelt.1, %6 : $IntEnum |
| br bb7(%7 : $Optional<IntEnum>) |
| |
| bb2: |
| %9 = integer_literal $Builtin.Int32, 1 |
| %10 = builtin "cmp_eq_Int32"(%9 : $Builtin.Int32, %0 : $Builtin.Int32) : $Builtin.Int1 |
| cond_br %10, bb3, bb4 |
| |
| bb3: |
| %12 = enum $IntEnum, #IntEnum.E1!enumelt |
| %13 = enum $Optional<IntEnum>, #Optional.some!enumelt.1, %12 : $IntEnum |
| br bb7(%13 : $Optional<IntEnum>) |
| |
| bb4: |
| %15 = integer_literal $Builtin.Int32, 2 |
| %16 = builtin "cmp_eq_Int32"(%15 : $Builtin.Int32, %0 : $Builtin.Int32) : $Builtin.Int1 |
| cond_br %16, bb5, bb6 |
| |
| bb5: |
| %18 = enum $IntEnum, #IntEnum.E2!enumelt |
| %19 = enum $Optional<IntEnum>, #Optional.some!enumelt.1, %18 : $IntEnum |
| br bb7(%19 : $Optional<IntEnum>) |
| |
| bb6: |
| %21 = enum $Optional<IntEnum>, #Optional.none!enumelt |
| br bb7(%21 : $Optional<IntEnum>) |
| |
| bb7(%23 : $Optional<IntEnum>): |
| return %23 : $Optional<IntEnum> |
| } |
| |
| |
| 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 %0 : $@thick AnyObject.Protocol to $@thick 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, bb1, bb2 |
| 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: bb1: |
| // 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 bb4 |
| // CHECK: bb2: |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: cond_br |
| // CHECK: bb3: |
| // CHECK: br bb4 |
| // CHECK: bb4({{.*}}): |
| // 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] %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] %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, bb2 |
| // CHECK: bb1 |
| // CHECK: witness_method |
| // CHECK: apply |
| // CHECK: strong_release |
| // CHECK: cond_br {{.*}}, bb3, bb4 |
| // CHECK: bb2 |
| // CHECK: strong_release |
| // CHECK: cond_br {{.*}}, bb3, bb4 |
| // CHECK: bb3 |
| // CHECK: cond_fail |
| // CHECK: br bb4 |
| // CHECK: bb4: |
| // 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 = witness_method [volatile] $T, #ObjcProto.foo!1.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.1: bb3 |
| |
| // CHECK: bb3{{.*}} |
| // CHECK: br bb4({{.*}} : $Builtin.Int32, %2 : $Builtin.Int32, [[EXT]] |
| |
| // CHECK: bb4({{.*}} : $Builtin.Int32, [[CUR:%.*]] : $Builtin.Int32, [[NEXT:%.*]] : $Builtin.Int32 |
| // CHECK: [[F:%.*]] = function_ref @f |
| // CHECK: apply [[F]]([[CUR]]) |
| // CHECK: cond_br {{.*}}, bb5, bb6 |
| |
| // CHECK: bb5: |
| // CHECK: [[VARADD:%.*]] = builtin "sadd_with_overflow_Int32"([[NEXT]] : $Builtin.Int32 |
| // CHECK: [[NEXT2:%.*]] = tuple_extract [[VARADD]] |
| // CHECK: br bb4({{.*}} : $Builtin.Int32, [[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.1: 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.1, %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.1: bb1, case #AnEnum.C!enumelt.1: bb2 |
| |
| // CHECK: bb1([[ARG2:%.*]] : $Builtin.Int32): |
| // CHECK: apply [[F]]([[ARG2]]) |
| // CHECK: [[UED:%.*]] = unchecked_enum_data [[ARG]] : $AnEnum, #AnEnum.B!enumelt.1 |
| // CHECK: apply [[F]]([[UED]]) |
| // CHECK: br bb3 |
| |
| // CHECK: bb2([[ARG3:%.*]] : $Builtin.Int16): |
| // CHECK: apply [[F2]]([[ARG3]]) |
| // CHECK: [[UED2:%.*]] = unchecked_enum_data [[ARG]] : $AnEnum, #AnEnum.C!enumelt.1 |
| // CHECK: apply [[F2]]([[UED2]]) |
| // 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.1: bb1, case #AnEnum.C!enumelt.1: 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.1: bb6, case #AnEnum.B!enumelt.1: 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.1: bb1 |
| // CHECK: bb1: |
| // CHECK: [[F:%.*]] = select_enum [[ENUM]] : $AnEnum, case #AnEnum.B!enumelt.1: [[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.1: bb4, case #AnEnum.C!enumelt.1: bb5 |
| |
| bb4: |
| br bb1 |
| |
| bb5: |
| %8 = select_enum %0 : $AnEnum, case #AnEnum.B!enumelt.1: %f, case #AnEnum.C!enumelt.1: %t : $Builtin.Int1 |
| cond_br %8, bb10, bb1 |
| |
| bb1: |
| %3 = select_enum %0 : $AnEnum, case #AnEnum.B!enumelt.1: %f, case #AnEnum.C!enumelt.1: %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] %0(%{{[0-9]+}}) : $@convention(thin) (@owned @callee_owned (Int) -> (Int, @error Error)) -> (Int, @error Error) |
| // CHECK-NEXT: return [[R]] : $Int |
| sil @replace_try_apply_with_apply : $@convention(thin) () -> Int { |
| bb0: |
| %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): |
| return %5 : $Int |
| |
| bb2(%8 : $Error): |
| 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.1, %{{.*}} : $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 that we don't crash on this. |
| |
| // CHECK-LABEL: @simplified_branch_arg_has_result_value_1 |
| // CHECK: [[B:%[0-9]+]] = alloc_box |
| // CHECK: [[PB:%[0-9]+]] = project_box [[B]] |
| // CHECK: br bb1([[PB]] : $*Builtin.Int32) |
| sil @simplified_branch_arg_has_result_value_1 : $@convention(thin) (@in Builtin.Int32) -> Builtin.Int32 { |
| entry(%0 : $*Builtin.Int32): |
| %b = alloc_box $<τ_0_0> { var τ_0_0 } <Builtin.Int32> |
| %p = project_box %b : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>, 0 |
| %i = integer_literal $Builtin.Int32, 0 |
| store %i to %p : $*Builtin.Int32 |
| br bb1(%p : $*Builtin.Int32) |
| |
| bb1(%a : $*Builtin.Int32): |
| %r = load %a : $*Builtin.Int32 |
| cond_br undef, bb1(%0 : $*Builtin.Int32), bb2 |
| |
| bb2: |
| return %r : $Builtin.Int32 |
| } |
| |
| // 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.1, %0 : $Int |
| br bb3(%2 : $Optional<Int>) |
| |
| bb2: |
| %3 = enum $Optional<Int>, #Optional.some!enumelt.1, %1 : $Int |
| br bb3(%3 : $Optional<Int>) |
| |
| bb3(%4 : $Optional<Int>): |
| %5 = unchecked_enum_data %4 : $Optional<Int>, #Optional.some!enumelt.1 |
| 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.1, %0 : $TwoCase |
| br bb1(%x : $Optional<TwoCase>) |
| |
| bb1(%10 : $Optional<TwoCase>): |
| switch_enum %10 : $Optional<TwoCase>, case #Optional.some!enumelt.1: 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.1: 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: |
| %60 = 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.1: bb7, case #TestEnum.string!enumelt.1: bb10 |
| |
| bbnone: |
| %tn = enum $TestEnum, #TestEnum.none!enumelt |
| %en = enum $MyError, #MyError.c!enumelt.1, %tn : $TestEnum |
| br bb5(%en : $MyError) |
| |
| bb7(%50 : $Builtin.Int64): |
| %t = enum $TestEnum, #TestEnum.int64!enumelt.1, %50 : $Builtin.Int64 |
| %e1 = enum $MyError, #MyError.c!enumelt.1, %t : $TestEnum |
| br bb5(%e1 : $MyError) |
| |
| bb10(%53 : $Base): |
| %t4 = enum $TestEnum, #TestEnum.string!enumelt.1, %53 : $Base |
| %e4 = enum $MyError, #MyError.c!enumelt.1, %t4 : $TestEnum |
| br bb5(%e4 : $MyError) |
| |
| bb5(%e : $MyError): |
| %89 = enum $Optional<MyError>, #Optional.some!enumelt.1, %e : $MyError |
| %e5 = enum $MyError2, #MyError2.o!enumelt.1, %89 : $Optional<MyError> |
| store %e5 to %23 : $*MyError2 |
| throw %22 : $Error |
| |
| bb6(%44 : $Builtin.Int8): |
| return %44 : $Builtin.Int8 |
| } |
| |
| // CHECK-LABEL: sil @dont_hang |
| // CHECK: bb6: |
| // CHECK: integer_literal $Builtin.Int64, 1 |
| // CHECK-NEXT: br bb5 |
| // 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 |
| } |
| |