blob: 7998c764af44bdf0c2fede81409fa1bc8f1480cc [file] [log] [blame]
// RUN: %target-sil-opt -sil-print-debuginfo -enable-sil-verify-all %s -condition-forwarding | %FileCheck %s
import Builtin
import Swift
sil_stage canonical
enum E { case A, B }
enum E3 { case A, B, C }
class C {
@_hasStorage var x : Builtin.Int64
init()
}
sil @callee : $@convention(thin) () -> ()
sil @use_enum : $@convention(thin) (E) -> ()
sil @use_int : $@convention(thin) (Builtin.Int64) -> ()
// CHECK-LABEL: sil @simple_forwarding
// CHECK: bb0({{.*}}):
// CHECK-NEXT: br bb3
// CHECK: bb1:
// CHECK: br bb4,
// CHECK: bb2:
// CHECK: br bb5,
// CHECK: bb3:
// CHECK: apply
// CHECK: cond_br %0, bb1, bb2
// CHECK: bb4:
// CHECK: br bb6
// CHECK: bb5:
// CHECK: br bb6
// CHECK: bb6:
// CHECK: return
sil @simple_forwarding : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb2
bb1:
%1 = enum $E, #E.A!enumelt
br bb3(%1 : $E)
bb2:
%2 = enum $E, #E.B!enumelt
br bb3(%2 : $E)
bb3(%14 : $E):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4:
br bb6
bb5:
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @closed_range_iterator_example
// CHECK: bb0({{.*}}):
// CHECK-NEXT: br bb3
// CHECK: bb1:
// CHECK: [[PL:%[0-9]+]] = struct $Int64
// CHECK: br bb4([[PL]] : $Int64)
// CHECK: bb2:
// CHECK: [[O:%[0-9]+]] = enum $Optional<Int64>
// CHECK: br bb5([[O]] : $Optional<Int64>)
// CHECK: bb3:
// CHECK: apply
// CHECK: cond_br %0, bb1, bb2
// CHECK: bb4({{%[0-9]+}} : $Int64):
// CHECK: br bb6
// CHECK: bb5([[O2:%[0-9]+]] : $Optional<Int64>):
// CHECK: br bb6([[O2]] : $Optional<Int64>)
// CHECK: bb6
// CHECK: return
sil @closed_range_iterator_example : $@convention(thin) (Builtin.Int1, Builtin.Int64) -> Optional<Int64> {
bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int64):
cond_br %0, bb1, bb2
bb1:
%3 = integer_literal $Builtin.Int64, 1
%4 = integer_literal $Builtin.Int1, -1
%5 = builtin "sadd_with_overflow_Int64"(%1 : $Builtin.Int64, %3 : $Builtin.Int64, %4 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%6 = tuple_extract %5 : $(Builtin.Int64, Builtin.Int1), 0
%7 = tuple_extract %5 : $(Builtin.Int64, Builtin.Int1), 1
cond_fail %7 : $Builtin.Int1
%9 = struct $Int64 (%6 : $Builtin.Int64)
%10 = enum $Optional<Int64>, #Optional.some!enumelt.1, %9 : $Int64
br bb3(%10 : $Optional<Int64>)
bb2:
%12 = enum $Optional<Int64>, #Optional.none!enumelt
br bb3(%12 : $Optional<Int64>)
bb3(%14 : $Optional<Int64>):
debug_value %14 : $Optional<Int64>
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
switch_enum %14 : $Optional<Int64>, case #Optional.some!enumelt.1: bb4, case #Optional.none!enumelt: bb5
bb4(%18 : $Int64):
%19 = enum $Optional<Int64>, #Optional.some!enumelt.1, %18 : $Int64
br bb6(%19 : $Optional<Int64>)
bb5:
br bb6(%14 : $Optional<Int64>)
bb6(%22 : $Optional<Int64>):
return %22 : $Optional<Int64>
}
// CHECK-LABEL: sil @simple_switch_enum_forwarding
// CHECK: bb0({{.*}}):
// CHECK-NEXT: br bb3
// CHECK: bb1:
// CHECK: br bb4,
// CHECK: bb2:
// CHECK: br bb5,
// CHECK: bb3:
// CHECK: apply
// CHECK: switch_enum %0 : $E3, case #E3.A!enumelt: bb1, default bb2
// CHECK: bb4:
// CHECK: br bb6
// CHECK: bb5:
// CHECK: br bb6
// CHECK: bb6:
// CHECK: return
sil @simple_switch_enum_forwarding : $@convention(thin) (E3) -> () {
bb0(%0 : $E3):
switch_enum %0 : $E3, case #E3.A!enumelt: bb1, default bb2
bb1:
%1 = enum $E, #E.A!enumelt
br bb3(%1 : $E)
bb2:
%2 = enum $E, #E.B!enumelt
br bb3(%2 : $E)
bb3(%14 : $E):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4:
br bb6
bb5:
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @no_forwarding_side_effect_inst
// CHECK: bb0({{.*}}):
// CHECK: cond_br %0
// CHECK: bb3({{.*}}):
// CHECK: switch_enum
// CHECK: bb6
// CHECK: return
sil @no_forwarding_side_effect_inst : $@convention(thin) (Builtin.Int1, C) -> () {
bb0(%0 : $Builtin.Int1, %1 : $C):
%e = ref_element_addr %1 : $C, #C.x
cond_br %0, bb1, bb2
bb1:
%2 = enum $E, #E.A!enumelt
br bb3(%2 : $E)
bb2:
%3 = enum $E, #E.B!enumelt
%4 = load %e : $*Builtin.Int64
br bb3(%3 : $E)
bb3(%14 : $E):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4:
br bb6
bb5:
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @no_forwarding_second_enum_use
// CHECK: bb0({{.*}}):
// CHECK: cond_br %0
// CHECK: bb3({{.*}}):
// CHECK: switch_enum
// CHECK: bb6
// CHECK: return
sil @no_forwarding_second_enum_use : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb2
bb1:
%1 = enum $E, #E.A!enumelt
br bb3(%1 : $E)
bb2:
%2 = enum $E, #E.B!enumelt
br bb3(%2 : $E)
bb3(%14 : $E):
%15 = function_ref @use_enum : $@convention(thin) (E) -> ()
%16 = apply %15(%14) : $@convention(thin) (E) -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4:
br bb6
bb5:
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @no_forwarding_bad_control_flow
// CHECK: bb0({{.*}}):
// CHECK: cond_br %0
// CHECK: bb3({{.*}}):
// CHECK: switch_enum
// CHECK: bb6
// CHECK: return
sil @no_forwarding_bad_control_flow : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb2
bb1:
%1 = enum $E, #E.A!enumelt
br bb3(%1 : $E)
bb2:
%2 = enum $E, #E.B!enumelt
br bb3(%2 : $E)
bb3(%14 : $E):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4:
br bb6
bb5:
cond_br undef, bb1, bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @no_forwarding_multiple_block_args
// CHECK: bb0({{.*}}):
// CHECK: cond_br %0
// CHECK: bb3({{.*}}):
// CHECK: switch_enum
// CHECK: bb6
// CHECK: return
sil @no_forwarding_multiple_block_args : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb2
bb1:
%i1 = integer_literal $Builtin.Int64, 1
%1 = enum $E, #E.A!enumelt
br bb3(%1 : $E, %i1 : $Builtin.Int64)
bb2:
%i2 = integer_literal $Builtin.Int64, 2
%2 = enum $E, #E.B!enumelt
br bb3(%2 : $E, %i2 : $Builtin.Int64)
bb3(%14 : $E, %i3 : $Builtin.Int64):
%15 = function_ref @use_int : $@convention(thin) (Builtin.Int64) -> ()
%16 = apply %15(%i3) : $@convention(thin) (Builtin.Int64) -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4:
br bb6
bb5:
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @no_forwarding_additional_successor
// CHECK: bb0({{.*}}):
// CHECK: switch_enum %0
// CHECK: bb3({{.*}}):
// CHECK: switch_enum
// CHECK: bb6
// CHECK: return
sil @no_forwarding_additional_successor : $@convention(thin) (E3) -> () {
bb0(%0 : $E3):
switch_enum %0 : $E3, case #E3.A!enumelt: bb1, case #E3.B!enumelt: bb2, case #E3.C!enumelt: bb6
bb1:
%1 = enum $E, #E.A!enumelt
br bb3(%1 : $E)
bb2:
%2 = enum $E, #E.B!enumelt
br bb3(%2 : $E)
bb3(%14 : $E):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4:
br bb7
bb5:
br bb7
bb6:
br bb7
bb7:
%r = tuple ()
return %r : $()
}