blob: f458a34d1f8f402810d73d38a264d77b5c867d4d [file] [log] [blame]
// RUN: %target-sil-opt -enable-objc-interop -enforce-exclusivity=none -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
// FIXME: Update for select_enum change.
// Declare this SIL to be canonical because some tests break raw SIL
// conventions. e.g. address-type block args. -enforce-exclusivity=none is also
// required to allow address-type block args in canonical SIL.
sil_stage canonical
import Builtin
import Swift
///////////////////////
// Type Declarations //
///////////////////////
class foo {
var a: Int
deinit
init()
}
sil @use_foo : $@convention(thin) (@owned foo) -> ()
///////////
// Tests //
///////////
// CHECK-LABEL: sil @test_dead_block
// CHECK-NEXT: bb0:
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
sil @test_dead_block : $() -> () {
bb0:
unreachable
bb1:
%4 = integer_literal $Builtin.Int64, 1
br bb2
bb2:
%5 = struct $Int64 (%4 : $Builtin.Int64)
unreachable
}
// CHECK-LABEL: @release_in_arcinert_termination_block
// CHECK: bb0
// CHECK: unreachable
// CHECK: }
sil @release_in_arcinert_termination_block : $(@owned foo) -> () {
bb0(%0 : $foo):
br bb1
bb1:
strong_release %0 : $foo
unreachable
}
// CHECK-LABEL: @release_in_nonarcinert_termination_block
// CHECK: bb0
// CHECK: strong_release
// CHECK: apply
// CHECK: unreachable
sil @release_in_nonarcinert_termination_block : $(@owned foo) -> () {
bb0(%0 : $foo):
br bb1
bb1:
strong_release %0 : $foo
%1 = function_ref @use_foo : $@convention(thin) (@owned foo) -> ()
apply %1(%0) : $@convention(thin) (@owned foo) -> ()
unreachable
}
// CHECK-LABEL: @test_single_pred_block
// CHECK: bb3([[ARG:%[0-9]+]] : $Builtin.Int64):
// CHECK: struct $Int64
// CHECK-NEXT: return
sil @test_single_pred_block : $@convention(thin) (Builtin.Int1) -> Int64 {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb3
bb1:
%4 = integer_literal $Builtin.Int64, 1
br bb2(%4 : $Builtin.Int64)
bb3:
%9 = integer_literal $Builtin.Int64, 2
br bb2(%9 : $Builtin.Int64)
bb2(%6 : $Builtin.Int64):
%7 = struct $Int64 (%6 : $Builtin.Int64)
br bb4(%7 : $Int64)
bb4(%8 : $Int64):
return %8 : $Int64
}
// CHECK-LABEL: sil @canonicalize_not_branch
// CHECK: bb0([[ARG:%.*]] : $Builtin.Int1):
// CHECK: cond_br [[ARG]], bb2, bb1
// CHECK: bb1:
// CHECK: integer_literal {{.*}} 2
// CHECK: br
// CHECK: bb2:
// CHECK: integer_literal {{.*}} 3
// CHECK: br
sil @canonicalize_not_branch : $@convention(thin) (Builtin.Int1) -> (Builtin.Int32) {
bb0(%0 : $Builtin.Int1):
%1 = integer_literal $Builtin.Int1, -1
%2 = builtin "xor_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
cond_br %2, bb1, bb2
bb1:
%4 = integer_literal $Builtin.Int32, 2
br bb3(%4 : $Builtin.Int32)
bb2:
%5 = integer_literal $Builtin.Int32, 3
br bb3(%5 : $Builtin.Int32)
bb3(%6 : $Builtin.Int32):
return %6 : $Builtin.Int32
}
// CHECK-LABEL: sil @canonicalize_not_branch_expect
// CHECK: bb0([[ARG:%.*]] : $Builtin.Int1):
// CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int1, 0
// CHECK: [[EXPECT:%.*]] = builtin "int_expect_Int1"([[ARG]] : $Builtin.Int1, [[ZERO]]
// CHECK cond_br [[EXPECT]], bb2, bb1
// CHECK: bb1:
// CHECK: integer_literal {{.*}} 2
// CHECK: br
// CHECK: bb2:
// CHECK: integer_literal {{.*}} 3
// CHECK: br
sil @canonicalize_not_branch_expect : $@convention(thin) (Builtin.Int1) -> (Builtin.Int32) {
bb0(%0 : $Builtin.Int1):
%1 = integer_literal $Builtin.Int1, -1
%2 = builtin "xor_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
%3 = builtin "int_expect_Int1"(%2 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
cond_br %3, bb1, bb2
bb1:
%4 = integer_literal $Builtin.Int32, 2
br bb3(%4 : $Builtin.Int32)
bb2:
%5 = integer_literal $Builtin.Int32, 3
br bb3(%5 : $Builtin.Int32)
bb3(%6 : $Builtin.Int32):
return %6 : $Builtin.Int32
}
enum BoolLike { case true_, false_ }
// func testThread(a : BoolLike) -> Int32 {
// if a { return 42 } else { return 17 } }
//
/// CHECK-LABEL: sil @testThread
sil @testThread : $@convention(thin) (@in BoolLike) -> Int64 {
bb0(%0 : $*BoolLike):
// CHECK: switch_enum_addr %0 : $*BoolLike, case #BoolLike.true_!enumelt: bb1, case #BoolLike.false_!enumelt: bb2
switch_enum_addr %0 : $*BoolLike, case #BoolLike.true_!enumelt: bb1, case #BoolLike.false_!enumelt: bb3 // 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 bb1
// CHECK: bb1
// CHECK-NEXT: br bb1
sil @infinite_loop : $@convention(thin) () -> () {
bb0:
br bb1
bb1:
br bb1
}
import Builtin
import Swift
// CHECK-LABEL: @dead_loop
// CHECK-NOT: br bb
sil @dead_loop : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Int1, 0 // 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: bb2
// 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: objc_method
// CHECK: switch_enum
// CHECK: return
sil @dont_jumpthread_switch_enum : $@convention(thin) (Int32) -> Int32 {
bb0(%0 : $Int32):
%100 = alloc_ref $Bar
%1 = integer_literal $Builtin.Int32, 0
%2 = integer_literal $Builtin.Int32, 1
%3 = struct_extract %0 : $Int32, #Int32._value
%5 = integer_literal $Builtin.Int1, -1
%6 = builtin "sadd_with_overflow_Int32"(%3 : $Builtin.Int32, %2 : $Builtin.Int32, %5 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%7 = tuple_extract %6 : $(Builtin.Int32, Builtin.Int1), 0
%8 = tuple_extract %6 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %8 : $Builtin.Int1
%11 = builtin "cmp_eq_Int32"(%2 : $Builtin.Int32, %7 : $Builtin.Int32) : $Builtin.Int1
cond_br %11, bb8(%1 : $Builtin.Int32), bb2
bb2:
%14 = integer_literal $Builtin.Int32, 2
%15 = struct $Int32 (%2 : $Builtin.Int32)
%16 = enum $Optional<Int32>, #Optional.some!enumelt.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 = objc_method %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 : $()
}
// CHECK-LABEL: sil @dont_crash_jump_threading_single_case_switch_enums
// CHECK-NOT: switch_enum
// CHECK: } // end sil function
sil @dont_crash_jump_threading_single_case_switch_enums : $@convention(thin) () -> () {
bb0:
br bb1(undef : $OneCase)
bb1(%19 : $OneCase):
switch_enum %19 : $OneCase, case #OneCase.First!enumelt.1: bb2
bb2:
switch_enum %19 : $OneCase, case #OneCase.First!enumelt.1: bb3
bb3:
%48 = enum $OneCase, #OneCase.First!enumelt.1
cond_br undef, bb6, bb7
bb6:
%72 = tuple ()
return %72 : $()
bb7:
br bb1(%48 : $OneCase)
}
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: objc_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 = objc_method %1 : $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] %1(%{{[0-9]+}}) : $@convention(thin) (@owned @callee_owned (Int) -> (Int, @error Error)) -> (Int, @error Error)
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: return [[R]] : $Int
sil @replace_try_apply_with_apply : $@convention(thin) () -> Int {
bb0:
%as = alloc_stack $Builtin.Int32
%0 = function_ref @rethrow_function : $@convention(thin) (@owned @callee_owned (Int) -> (Int, @error Error)) -> (Int, @error Error)
%1 = function_ref @non_throwing_closure : $@convention(thin) (Int) -> Int
%2 = thin_to_thick_function %1 : $@convention(thin) (Int) -> Int to $@callee_owned (Int) -> Int
%3 = convert_function %2 : $@callee_owned (Int) -> Int to $@callee_owned (Int) -> (Int, @error Error)
try_apply %0(%3) : $@convention(thin) (@owned @callee_owned (Int) -> (Int, @error Error)) -> (Int, @error Error), normal bb1, error bb2
bb1(%5 : $Int):
dealloc_stack %as: $*Builtin.Int32
return %5 : $Int
bb2(%8 : $Error):
dealloc_stack %as: $*Builtin.Int32
unreachable
}
public class EE {
init()
}
public class BB {
init()
}
public class CC : BB {
@inline(never) init(e: EE)
override init()
}
public protocol PP {
var prop1: BB? { get }
}
public class DD : PP {
public var prop1: BB? { get }
init()
}
// CHECK-LABEL: sil @replace_try_apply_with_apply_cast_return_type : $@convention(method) (@guaranteed DD) -> @owned Optional<BB>
// CHECK: bb0
// CHECK: apply %{{.*}}
// CHECK: convert_function
// CHECK-NOT: try_apply
// CHECK: apply
// Check that return value is properly casted
// CHECK-NEXT: enum $Optional<CC>, #Optional.some!enumelt.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:
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: jump_thread_retain_release
// CHECK: cond_br
// CHECK: cond_br %3, bb3, bb4
// CHECK: bb3:
// CHECK: strong_retain %1 : $foo
// CHECK: strong_release %1 : $foo
// CHECK: br bb5(%1 : $foo)
// CHECK: bb4:
// CHECK: strong_retain %2 : $foo
// CHECK: strong_release %2 : $foo
// CHECK: br bb5(%2 : $foo)
sil @jump_thread_retain_release : $@convention(thin) (Builtin.Int1, foo, foo, Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1, %1 : $foo, %2 : $foo, %3 : $Builtin.Int1):
cond_br %0, bb2, bb1
bb1:
br bb6(%2 : $foo)
bb2:
cond_br %3, bb3, bb4
bb3:
strong_retain %1 : $foo
br bb5(%1 : $foo)
bb4:
strong_retain %2 : $foo
br bb5(%2 : $foo)
bb5(%11 : $foo):
strong_release %11 : $foo
br bb6(%11 : $foo)
bb6(%14 : $foo):
strong_release %14 : $foo
%16 = tuple ()
return %16 : $()
}
protocol Q {}
class IsQ : Q {}
// checked_cast_br take_* should be replaced by a destroy in case it ever
// converts a managed object to an unmanaged value. Currently this doesn't
// happen at the language level because bridge (NSNumber->Int) casts aren't
// represented with checked_cast_br.
// ---
// CHECK-LABEL: sil @test_dead_checked_cast_br : $@convention(thin) (@in IsQ) -> () {
// CHECK: bb0(%0 : $*IsQ):
// CHECK: [[Q:%.*]] = alloc_stack $Q
// CHECK: [[LD:%.*]] = load %0 : $*IsQ
// CHECK: strong_release [[LD]] : $IsQ
// CHECK: dealloc_stack [[Q]] : $*Q
// CHECK: [[R:%.*]] = tuple ()
// CHECK: return [[R]] : $()
// CHECK-LABEL: } // end sil function 'test_dead_checked_cast_br'
sil @test_dead_checked_cast_br : $@convention(thin) (@in IsQ) -> () {
bb0(%0 : $*IsQ):
%p = alloc_stack $Q
checked_cast_addr_br take_always IsQ in %0 : $*IsQ to Q in %p : $*Q, bb1, bb3
bb1:
%m1 = integer_literal $Builtin.Int1, -1
br bb2(%m1 : $Builtin.Int1)
bb2(%5 : $Builtin.Int1):
// To avoid violating ownership, Q needs to be destroyed here. However, that
// would create a use of the checked_cast, defeating the test. In theory, Q
// could be some unmananged type with no destroy, but we don't have a way to
// express that in the type system, and bridged casts don't yet go through
// this optimization path.
dealloc_stack %p : $*Q
%r = tuple ()
return %r : $()
bb3:
%z = integer_literal $Builtin.Int1, 0
br bb2(%z : $Builtin.Int1)
}
// CHECK-LABEL: sil @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
}
// CHECK-LABEL: sil @test_constant_folding
// CHECK: [[R:%[0-9]+]] = integer_literal $Builtin.Int32, 30
// CHECK: return [[R]] : $Builtin.Int32
// CHECK-NEXT: }
sil @test_constant_folding : $@convention(thin) () -> Builtin.Int32 {
bb0:
%0 = integer_literal $Builtin.Int1, 0
%20 = integer_literal $Builtin.Int32, 20
%30 = integer_literal $Builtin.Int32, 30
cond_br %0, bb1, bb2
bb1:
br bb3(%20 : $Builtin.Int32)
bb2:
br bb3(%30 : $Builtin.Int32)
bb3(%2 : $Builtin.Int32):
%3 = builtin "cmp_slt_Int32"(%2 : $Builtin.Int32, %30 : $Builtin.Int32) : $Builtin.Int1
cond_br %3, bb4, bb5
bb4:
br bb6(%20 : $Builtin.Int32)
bb5:
br bb6(%30 : $Builtin.Int32)
bb6(%4 : $Builtin.Int32):
%5 = builtin "cmp_slt_Int32"(%4 : $Builtin.Int32, %30 : $Builtin.Int32) : $Builtin.Int1
cond_br %5, bb7, bb8
bb7:
br bb9(%20 : $Builtin.Int32)
bb8:
br bb9(%30 : $Builtin.Int32)
bb9(%6 : $Builtin.Int32):
return %6 : $Builtin.Int32
}
sil @adder : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> Builtin.Int32
// CHECK-LABEL: sil @test_noescape
// CHECK: [[FN:%.*]] = function_ref @adder
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[FN]](%0)
// CHECK-NOT: try_apply
// CHECK: apply [[PA]](%1)
// CHECK: return
sil @test_noescape : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> Builtin.Int32 {
bb0(%0 : $Builtin.Int32, %1 : $Builtin.Int32):
%f = function_ref @adder : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> Builtin.Int32
%pa = partial_apply [callee_guaranteed] %f(%0) : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> Builtin.Int32
%conv = convert_function %pa : $@callee_guaranteed (Builtin.Int32) -> (Builtin.Int32) to $@callee_guaranteed (Builtin.Int32) -> (Builtin.Int32, @error Error)
%ne = convert_escape_to_noescape %conv : $@callee_guaranteed (Builtin.Int32) -> (Builtin.Int32, @error Error) to $@noescape @callee_guaranteed (Builtin.Int32) -> (Builtin.Int32, @error Error)
try_apply %ne(%1) : $@noescape @callee_guaranteed (Builtin.Int32) -> (Builtin.Int32, @error Error), normal bb1, error bb2
bb1(%r : $Builtin.Int32):
br bb3(%r : $Builtin.Int32)
bb2(%e : $Error):
%r1 = integer_literal $Builtin.Int32, 0
br bb3(%r1 : $Builtin.Int32)
bb3(%res : $Builtin.Int32):
release_value %pa : $@callee_guaranteed (Builtin.Int32) -> (Builtin.Int32)
return %res : $Builtin.Int32
}
struct TestStr {
let a: Int32
let c: Int32
}
enum TestEnm {
case X
case Y(TestStr)
}
// CHECK-LABEL: sil @dont_crash
// CHECK: bb0(%0 : $TestEnm, %1 : $Int32):
// CHECK-NEXT: %2 = tuple ()
// CHECK-NEXT: return %2 : $()
sil @dont_crash : $@convention(method) (TestEnm, Int32) -> () {
bb0(%2 : $TestEnm, %3 : $Int32):
%98 = integer_literal $Builtin.Int1, -1
cond_br %98, bb2, bb3
bb2:
%18 = tuple()
return %18 : $()
bb3:
br bb8(%2 : $TestEnm)
bb8(%47 : $TestEnm):
%49 = unchecked_enum_data %47 : $TestEnm, #TestEnm.Y!enumelt.1
%57 = struct_extract %49 : $TestStr, #TestStr.c
cond_br undef, bb9, bb11
bb9:
br bb10
bb10:
%64 = struct $TestStr (%3 : $Int32, %57 : $Int32)
%65 = enum $TestEnm, #TestEnm.Y!enumelt.1, %64 : $TestStr
cond_br undef, bb2, bb16
bb11:
br bb10
bb16:
br bb8(%65 : $TestEnm)
}
sil @print : $@convention(thin) (@guaranteed String) -> ()
sil @yield_string : $@yield_once @convention(thin) () -> @yields @guaranteed String
sil @dont_clone_begin_apply : $(Builtin.Int1, @guaranteed String) -> () {
bb0(%condition : $Builtin.Int1, %arg : $String):
%print = function_ref @print : $@convention(thin) (@guaranteed String) -> ()
cond_br %condition, bb1, bb2
bb1:
apply %print(%arg) : $@convention(thin) (@guaranteed String) -> ()
br bb3
bb2:
br bb3
bb3:
%yield_string = function_ref @yield_string : $@yield_once @convention(thin) () -> @yields @guaranteed String
(%yield, %token) = begin_apply %yield_string() : $@yield_once @convention(thin) () -> @yields @guaranteed String
cond_br %condition, bb4, bb5
bb4:
apply %print(%yield) : $@convention(thin) (@guaranteed String) -> ()
br bb6
bb5:
br bb6
bb6:
end_apply %token
%rv = tuple ()
return %rv : $()
}
class X {
@objc func f() { }
}
sil @external_g : $@convention(thin) () -> ()
// Don't tail duplicate dynamic_method_br. IRGen cannot handle phi nodes of
// objc_methods.
// CHECK-LABEL: sil @dont_tail_duplicate_dynamic_method_br
// CHECK: dynamic_method_br
// CHECK-NOT: dynamic_method_br
// CHECK: return
sil @dont_tail_duplicate_dynamic_method_br : $@convention(thin) (@owned Builtin.UnknownObject, Builtin.Int1) -> () {
bb0(%x : $Builtin.UnknownObject, %b : $Builtin.Int1):
cond_br %b, bb1, bb2
bb1:
%f = function_ref @external_f : $@convention(thin) () -> ()
apply %f() : $@convention(thin) () -> ()
strong_retain %x : $Builtin.UnknownObject
br bb3(%x : $Builtin.UnknownObject)
bb2:
%g = function_ref @external_g : $@convention(thin) () -> ()
apply %g() : $@convention(thin) () -> ()
strong_retain %x : $Builtin.UnknownObject
br bb3(%x : $Builtin.UnknownObject)
bb3(%y: $Builtin.UnknownObject):
strong_release %y : $Builtin.UnknownObject
dynamic_method_br %x : $Builtin.UnknownObject, #X.f!1.foreign, bb4, bb5
bb4(%m : $@convention(objc_method) (Builtin.UnknownObject) -> ()):
br bb6
bb5:
br bb6
bb6:
%r = tuple()
return %r : $()
}