Files
swift-mirror/test/SILOptimizer/simplify_cfg_args.sil
Nate Chandler e5d87f75a8 [SIL] Add source formal type to checked_cast_br.
It is necessary for opaque values where for casts that will newly start
out as checked_cast_brs and be lowered to checked_cast_addr_brs, since
the latter has the source formal type, IRGen relies on being able to
access it, and there's no way in general to obtain the source formal
type from the source lowered type.
2023-07-27 15:04:15 -07:00

812 lines
20 KiB
Plaintext

// RUN: %target-sil-opt -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
// RUN: %target-sil-opt -enable-sil-verify-all %s -late-codemotion -jumpthread-simplify-cfg | %FileCheck %s --check-prefix=CHECK_WITH_CODEMOTION
sil_stage raw
import Builtin
import Swift
sil_global private @globalinit_token11 : $Builtin.Word
sil_global private @globalinit_token120 : $Builtin.Word
sil @globalinit_func11 : $@convention(thin) () -> ()
// CHECK: sil @a_method_to_simplify
sil @a_method_to_simplify : $@convention(thin) (Builtin.RawPointer, @owned Builtin.NativeObject, Builtin.Int32) -> Builtin.RawPointer {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.NativeObject, %2 : $Builtin.Int32):
%4 = struct $UnsafeMutablePointer<UInt8> (%0 : $Builtin.RawPointer)
strong_retain %1 : $Builtin.NativeObject
strong_retain %1 : $Builtin.NativeObject
strong_release %1 : $Builtin.NativeObject
%8 = integer_literal $Builtin.Int1, 0
%10 = global_addr @globalinit_token11 : $*Builtin.Word
%11 = address_to_pointer %10 : $*Builtin.Word to $Builtin.RawPointer
%12 = function_ref @globalinit_func11 : $@convention(thin) () -> ()
%14 = builtin "once"(%11 : $Builtin.RawPointer, %12 : $@convention(thin) () -> ()) : $()
%15 = alloc_stack $Int32
%16 = struct_element_addr %15 : $*Int32, #Int32._value
%17 = load %16 : $*Builtin.Int32
%18 = integer_literal $Builtin.Int32, -1
%20 = builtin "xor_Int32"(%17 : $Builtin.Int32, %18 : $Builtin.Int32) : $Builtin.Int32
%22 = builtin "and_Int32"(%2 : $Builtin.Int32, %20 : $Builtin.Int32) : $Builtin.Int32
// CHECK-NOT: cond_br
cond_br %8, bb1, bb2(%22 : $Builtin.Int32)
bb1:
%24 = global_addr @globalinit_token11 : $*Builtin.Word
%25 = address_to_pointer %24 : $*Builtin.Word to $Builtin.RawPointer
%27 = builtin "once"(%25 : $Builtin.RawPointer, %12 : $@convention(thin) () -> ()) : $()
%28 = load %16 : $*Builtin.Int32
// CHECK: [[VAR_21:%[0-9]+]] = builtin "and_Int32"
%30 = builtin "or_Int32"(%22 : $Builtin.Int32, %28 : $Builtin.Int32) : $Builtin.Int32
br bb2(%30 : $Builtin.Int32)
bb2(%32 : $Builtin.Int32):
// CHECK-NOT: tuple
%33 = tuple ()
br bb3(%33 : $())
bb3(%35 : $()):
// CHECK-NEXT: struct $Int32 ([[VAR_21]] : $Builtin.Int32)
%36 = struct $Int32 (%32 : $Builtin.Int32)
strong_retain %1 : $Builtin.NativeObject
strong_release %1 : $Builtin.NativeObject
strong_release %1 : $Builtin.NativeObject
dealloc_stack %15 : $*Int32
// CHECK: return
return %0 : $Builtin.RawPointer
}
//CHECK-LABEL: remove_dead_args
//CHECK-NOT: br bb2([[VAR_21:%[0-9]+]] : $Bool)
//CHECK: bb3:
//CHECK-NEXT: tuple ()
//CHECK-NEXT: return
sil @remove_dead_args: $@convention(thin) (Int32) -> () {
bb0(%0 : $Int32):
%1 = integer_literal $Builtin.Int32, 37
%3 = struct_extract %0 : $Int32, #Int32._value
%4 = builtin "cmp_ne_Int32"(%3 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int1
%5 = struct $Bool (%4 : $Builtin.Int1)
cond_br %4, bb1, bb3
bb1:
%7 = integer_literal $Builtin.Int32, 42
%8 = builtin "cmp_ne_Int32"(%3 : $Builtin.Int32, %7 : $Builtin.Int32) : $Builtin.Int1
%9 = struct $Bool (%8 : $Builtin.Int1)
br bb2(%9 : $Bool)
bb3:
%13 = tuple()
br bb2(%5 : $Bool)
// Remove this ARG.
bb2(%11 : $Bool):
%12 = tuple ()
return %12 : $()
}
class A {}
//CHECK-LABEL: no_remove_mandatory_dead_args
//CHECK: checked_cast_br AnyObject in {{%.*}} : $AnyObject to A, bb1
//CHECK-NOT: bb1
//CHECK: bb1([[VAR:%[0-9]+]] : $A)
//CHECK-NOT: [[VAR]]
//CHECK: return
sil @no_remove_mandatory_dead_args : $@convention(thin) (@owned AnyObject) -> Int32 {
bb0(%0 : $AnyObject):
checked_cast_br AnyObject in %0 : $AnyObject to A, bb1, bb2
bb1(%1 : $A):
%2 = integer_literal $Builtin.Int32, 1
br bb3(%2 : $Builtin.Int32)
bb2:
%3 = integer_literal $Builtin.Int32, 0
br bb3(%3 : $Builtin.Int32)
bb3(%4 : $Builtin.Int32):
%5 = struct $Int32 (%4 : $Builtin.Int32)
strong_release %0 : $AnyObject
return %5 : $Int32
}
enum X {
case A
case B((Int32, Int32))
case C(Int32)
}
// CHECK-LABEL: simplify_switch_include_args
sil @simplify_switch_include_args : $@convention(thin) (Int32, Int32) -> Int32 {
bb0(%0 : $Int32, %1 : $Int32):
// CHECK: return %0 : $Int32
%2 = tuple (%0 : $Int32, %1 : $Int32)
%3 = enum $X, #X.B!enumelt, %2 : $(Int32, Int32)
switch_enum %3 : $X, case #X.A!enumelt: bb1, case #X.B!enumelt: bb3, case #X.C!enumelt: bb5
bb1:
br bb2
bb2:
%6 = integer_literal $Builtin.Int32, 0
%7 = struct $Int32 (%6 : $Builtin.Int32)
br bb7(%7 : $Int32)
bb3(%9 : $(Int32, Int32)):
%10 = tuple_extract %9 : $(Int32, Int32), 0
br bb4
bb4:
br bb7(%10 : $Int32)
bb5(%13 : $Int32):
br bb6
bb6:
br bb7(%13 : $Int32)
bb7(%16 : $Int32):
return %16 : $Int32
}
// CHECK-LABEL: simplify_switch_dont_include_args
sil @simplify_switch_dont_include_args : $@convention(thin) (Int32, Int32) -> Int32 {
bb0(%0 : $Int32, %1 : $Int32):
%2 = tuple (%0 : $Int32, %1 : $Int32)
%3 = enum $X, #X.B!enumelt, %2 : $(Int32, Int32)
switch_enum %3 : $X, case #X.A!enumelt: bb1, case #X.B!enumelt: bb3, case #X.C!enumelt: bb5
bb1:
br bb2
bb2:
%6 = integer_literal $Builtin.Int32, 0
%7 = struct $Int32 (%6 : $Builtin.Int32)
br bb6
bb3(%9 : $(Int32, Int32)):
%10 = tuple_extract %9 : $(Int32, Int32), 0
br bb4
bb4:
br bb6
bb5:
br bb6
bb6:
return %0 : $Int32
}
// CHECK-LABEL: simplify_switch_dont_include_args_nested
sil @simplify_switch_dont_include_args_nested : $@convention(thin) (Int32, Int32, X) -> Int32 {
// CHECK: bb0
// CHECK: switch_enum %2
bb0(%0 : $Int32, %1 : $Int32, %2 : $X):
switch_enum %2 : $X, case #X.A!enumelt: bb3, case #X.B!enumelt: bb1, case #X.C!enumelt: bb5
// CHECK: bb1
// CHECK-NOT: switch_enum
bb1(%12: $(Int32, Int32)):
switch_enum %2 : $X, case #X.A!enumelt: bb6, case #X.B!enumelt: bb7, case #X.C!enumelt: bb8
bb2:
%6 = integer_literal $Builtin.Int32, 0
%7 = struct $Int32 (%6 : $Builtin.Int32)
br bb9(%7 : $Int32)
bb3:
%9 = integer_literal $Builtin.Int32, 1
%10 = struct $Int32 (%9 : $Builtin.Int32)
br bb4(%10 : $Int32)
bb4(%16 : $Int32):
br bb9(%16 : $Int32)
bb5(%18 : $Int32):
br bb9(%18 : $Int32)
bb6:
%20 = integer_literal $Builtin.Int32, 2
%21 = struct $Int32 (%20 : $Builtin.Int32)
br bb9(%21 : $Int32)
bb7:
%22 = integer_literal $Builtin.Int32, 3
%23 = struct $Int32 (%22 : $Builtin.Int32)
br bb9(%23 : $Int32)
bb8(%25 : $Int32):
br bb9(%25 : $Int32)
bb9(%27 : $Int32):
return %27 : $Int32
}
// CHECK-LABEL: simplify_switch_wrong_args
sil @simplify_switch_wrong_args : $@convention(thin) (Int32, Int32, X, Builtin.Int1) -> Int32 {
// CHECK: bb0
// CHECK: switch_enum %2
bb0(%0 : $Int32, %1 : $Int32, %2 : $X, %24 : $Builtin.Int1):
switch_enum %2 : $X, case #X.A!enumelt: bb3, case #X.B!enumelt: bb9, case #X.C!enumelt: bb10
bb9(%21 : $(Int32, Int32)):
%22 = tuple_extract %21 : $(Int32, Int32), 1
cond_br %24, bb1(%22 : $Int32), bb5(%22 : $Int32)
// CHECK: bb1
// CHECK-NOT: switch_enum
bb1(%12: $Int32):
switch_enum %2 : $X, case #X.A!enumelt: bb6, case #X.B!enumelt: bb7, case #X.C!enumelt: bb8
bb2:
%6 = integer_literal $Builtin.Int32, 0
%7 = struct $Int32 (%6 : $Builtin.Int32)
br bb5(%7 : $Int32)
bb3:
%9 = integer_literal $Builtin.Int32, 1
%10 = struct $Int32 (%9 : $Builtin.Int32)
br bb4(%10 : $Int32)
bb4(%16 : $Int32):
br bb5(%16 : $Int32)
bb10(%18 : $Int32):
br bb5(%18 : $Int32)
bb5(%19 : $Int32):
return %19 : $Int32
bb6:
%14 = integer_literal $Builtin.Int32, 2
%15 = struct $Int32 (%14 : $Builtin.Int32)
br bb5(%15 : $Int32)
bb7(%23 : $(Int32, Int32)):
%17 = tuple_extract %21 : $(Int32, Int32), 0
br bb5(%17 : $Int32)
bb8(%20 : $Int32):
br bb5(%20 : $Int32)
}
enum EA {
case cA
case cB(Int32)
case cC(Float)
}
// CHECK-LABEL: fold_unreachable_terminators1
sil @fold_unreachable_terminators1 : $@convention(thin) (EA) -> () {
// CHECK: bb0
// CHECK-NEXT: [[VAL:%[a-zA-Z0-9]+]] = tuple ()
// CHECK-NEXT: return [[VAL]]
bb0(%0 : $EA):
switch_enum %0 : $EA, case #EA.cA!enumelt: bb1, case #EA.cB!enumelt: bb3, case #EA.cC!enumelt: bb5
bb1:
br bb2
bb2:
br bb7
bb3(%6 : $Int32):
br bb4
bb4:
unreachable
bb5(%10 : $Float):
br bb6
bb6:
unreachable
bb7:
%14 = tuple ()
return %14 : $()
}
// CHECK-LABEL: fold_unreachable_terminators2
sil @fold_unreachable_terminators2 : $@convention(thin) (EA) -> Int32 {
// CHECK: bb0
bb0(%0 : $EA):
// CHECK-NEXT: [[VAL:%[a-zA-Z0-9]+]] = unchecked_enum_data %0 : $EA, #EA.cB!enumelt{{.*}}
// CHECK-NEXT: return [[VAL]] : $Int32
switch_enum %0 : $EA, case #EA.cA!enumelt: bb1, case #EA.cB!enumelt: bb3, case #EA.cC!enumelt: bb5
bb1:
br bb2
bb2:
unreachable
bb3(%6 : $Int32):
br bb4
bb4:
return %6 : $Int32
bb5(%10 : $Float):
br bb6
bb6:
unreachable
}
// CHECK-LABEL: simplify_switch_to_select_enum
sil @simplify_switch_to_select_enum : $@convention(thin) (X) -> Bool {
bb0(%0 : $X):
// CHECK: bb0
// CHECK: [[TRUE:%.*]] = integer_literal {{.*}} -1
// CHECK: integer_literal {{.*}} 0
// CHECK: [[FALSE:%.*]] = integer_literal {{.*}} 0
// CHECK: [[VAL:%[a-zA-Z0-9]+]] = select_enum %0 : $X, case #X.A!enumelt: [[TRUE]], default [[FALSE]]
// CHECK-NOT: switch_enum
// CHECK-NOT: bb2
// CHECK: [[RETVAL:%[a-zA-Z0-9]+]] = struct $Bool ([[VAL]] : $Builtin.Int1)
// CHECK-NEXT: return [[RETVAL]] : $Bool
%2 = integer_literal $Builtin.Int1, 0
switch_enum %0 : $X, case #X.A!enumelt: bb1, case #X.B!enumelt: bb2, case #X.C!enumelt: bb3
bb1:
%10 = integer_literal $Builtin.Int1, -1
br bb4(%10 : $Builtin.Int1)
bb2:
br bb4(%2 : $Builtin.Int1)
bb3:
br bb4(%2 : $Builtin.Int1)
bb4(%20 : $Builtin.Int1):
%11 = struct $Bool (%20 : $Builtin.Int1)
return %11 : $Bool
}
sil @external_f : $@convention(thin) () -> ()
// Check that switch_enum to select_enum conversion does not
// take place in a presence of side-effects.
// CHECK-LABEL: simplify_switch_to_select_enum_with_side_effects
sil @simplify_switch_to_select_enum_with_side_effects : $@convention(thin) (X) -> Int32 {
bb0(%0 : $X):
// CHECK: bb0
// CHECK-NOT: select_enum
// CHECK: switch_enum
switch_enum %0 : $X, case #X.A!enumelt: bb1, case #X.B!enumelt: bb2, case #X.C!enumelt: bb3
// CHECK: bb1:
bb1:
%10 = integer_literal $Builtin.Int32, 1
br bb4(%10 : $Builtin.Int32)
bb2:
// This BB contains a side-effect. Therefore switch_enum cannot be eliminated.
%11 = function_ref @external_f : $@convention(thin) () -> ()
%12 = apply %11() : $@convention(thin) () -> ()
%13 = integer_literal $Builtin.Int32, 2
br bb4(%13 : $Builtin.Int32)
// CHECK: bb3:
// CHECK: br bb4
bb3:
%14 = integer_literal $Builtin.Int32, 3
br bb4(%14 : $Builtin.Int32)
bb4(%20 : $Builtin.Int32):
// CHECK: bb4([[VAL:%[a-zA-Z0-9]+]]{{.*}}):
// CHECK: [[RETVAL:%[a-zA-Z0-9]+]] = struct $Int32 ([[VAL]] : $Builtin.Int32)
// CHECK-NEXT: return [[RETVAL]] : $Int32
%21 = struct $Int32 (%20 : $Builtin.Int32)
return %21 : $Int32
}
enum TwoCases {
case A
case B
}
struct S {
var x: Builtin.Int32
}
sil @useSandInt : $@convention(thin) (S, Builtin.Int32) -> ()
// CHECK-LABEL: sil @dont_opt_switch_enum_with_arg_bb
sil @dont_opt_switch_enum_with_arg_bb : $@convention(thin) (TwoCases, S, S) -> Builtin.Int32 {
bb0(%0 : $TwoCases, %1 : $S, %2 : $S):
%3 = integer_literal $Builtin.Int32, 3
%4 = integer_literal $Builtin.Int32, 4
// CHECK: switch_enum
switch_enum %0 : $TwoCases, case #TwoCases.A!enumelt: bb1, case #TwoCases.B!enumelt: bb2
bb1:
br bb3(%1 : $S)
bb2:
br bb3(%2 : $S)
bb3(%10 : $S):
br bb4(%3 : $Builtin.Int32)
bb4(%20 : $Builtin.Int32):
%11 = function_ref @useSandInt : $@convention(thin) (S, Builtin.Int32) -> ()
%12 = apply %11(%10, %20) : $@convention(thin) (S, Builtin.Int32) -> ()
cond_br undef, bb5, bb6
bb5:
br bb4(%4 : $Builtin.Int32)
bb6:
// CHECK: return
return %20 : $Builtin.Int32
}
enum E {
case Nope, Yup(Builtin.Int1)
}
// CHECK-LABEL: sil @simplify_switch_enum_pred_no_arg
sil @simplify_switch_enum_pred_no_arg : $@convention(thin) (E) -> Builtin.Int1 {
bb0(%0 : $E):
// CHECK-LABEL: bb0
// CHECK: switch_enum %0 : $E, case #E.Nope!enumelt: bb1, case #E.Yup!enumelt: bb2
switch_enum %0 : $E, case #E.Nope!enumelt: bb1, case #E.Yup!enumelt: bb2
bb1:
%1 = integer_literal $Builtin.Int1, -1
br bb5(%1 : $Builtin.Int1)
bb2:
// CHECK: unchecked_enum_data %0 : $E, #E.Yup!enumelt
// CHECK-NOT: switch_enum
// CHECK: return
switch_enum %0 : $E, case #E.Yup!enumelt: bb4, case #E.Nope!enumelt: bb3
bb3:
%2 = integer_literal $Builtin.Int1, 0
br bb5(%2 : $Builtin.Int1)
bb4(%3 : $Builtin.Int1):
br bb5(%3 : $Builtin.Int1)
bb5(%4 : $Builtin.Int1):
return %4 : $Builtin.Int1
}
// CHECK-LABEL: sil @same_destination_unused_arg
sil @same_destination_unused_arg : $@convention(thin) (Optional<Int32>) -> Optional<Int32> {
bb0(%0 : $Optional<Int32>):
%t = integer_literal $Builtin.Int1, 1
%f = integer_literal $Builtin.Int1, 0
// CHECK: select_enum
// CHECK-NEXT: return
%1 = select_enum %0 : $Optional<Int32>, case #Optional.some!enumelt: %t, default %f : $Builtin.Int1
cond_br %1, bb1(%0 : $Optional<Int32>), bb2(%0 : $Optional<Int32>)
bb1(%2 : $Optional<Int32>):
br bb2(%2 : $Optional<Int32>)
bb2(%3 : $Optional<Int32>):
return %0 : $Optional<Int32>
}
public enum Numbers {
case First, Second, Third, Fourth, Fifth
//var hashValue: Int32 { get }
}
// Check that one of the switch_enum instructions can be
// converted into select_enum instructions, even though
// the destination block is used as a target also by
// another switch_enum instruction
// CHECK_WITH_CODEMOTION-LABEL: sil @FormSelectEnumFromTwoSelectSwitches
// CHECK_WITH_CODEMOTION: switch_enum %0 : $Numbers
// CHECK_WITH_CODEMOTION-NOT: switch_enum
// CHECK_WITH_CODEMOTION: select_enum
// CHECK_WITH_CODEMOTION: return
sil @FormSelectEnumFromTwoSelectSwitches : $@convention(thin) (Numbers) -> Int32 {
bb0(%0 : $Numbers):
debug_value %0 : $Numbers, let, name "e"
switch_enum %0 : $Numbers, case #Numbers.First!enumelt: bb1, case #Numbers.Second!enumelt: bb3, case #Numbers.Third!enumelt: bb4, default bb6
bb1:
br bb2
bb2:
%4 = integer_literal $Builtin.Int32, 42
br bb20(%4 : $Builtin.Int32)
bb3:
br bb5
bb4:
br bb5
bb5:
%9 = integer_literal $Builtin.Int32, 24
br bb20(%9 : $Builtin.Int32)
bb6:
br bb7
bb7:
br bb8
bb8:
br bb9
bb9:
switch_enum %0 : $Numbers, case #Numbers.First!enumelt: bb10, case #Numbers.Second!enumelt: bb12, case #Numbers.Third!enumelt: bb13, case #Numbers.Fourth!enumelt: bb15, default bb17
bb10:
br bb11
bb11:
%17 = integer_literal $Builtin.Int32, 42
br bb20(%17 : $Builtin.Int32)
bb12:
br bb14
bb13:
br bb14
bb14:
%22 = integer_literal $Builtin.Int32, 24
br bb20(%22 : $Builtin.Int32)
bb15:
br bb16
bb16:
%26 = integer_literal $Builtin.Int32, 100
br bb20(%26 : $Builtin.Int32)
bb17:
br bb18
bb18:
br bb19
bb19:
%31 = integer_literal $Builtin.Int32, 100
br bb20(%31 : $Builtin.Int32)
bb20(%34 : $Builtin.Int32):
%35 = struct $Int32 (%34 : $Builtin.Int32)
return %35 : $Int32
}
// CHECK_WITH_CODEMOTION-LABEL: sil @FormSelectEnumIntResult
// CHECK_WITH_CODEMOTION-NOT: switch_enum
// CHECK_WITH_CODEMOTION: select_enum
// CHECK_WITH_CODEMOTION: return
sil @FormSelectEnumIntResult : $@convention(thin) (Numbers) -> Int32 {
bb0(%0 : $Numbers):
debug_value %0 : $Numbers, let, name "e"
switch_enum %0 : $Numbers, case #Numbers.First!enumelt: bb1, case #Numbers.Second!enumelt: bb3, case #Numbers.Third!enumelt: bb4, case #Numbers.Fourth!enumelt: bb6, default bb8
bb1:
br bb2
bb2:
%4 = integer_literal $Builtin.Int32, 42
br bb11(%4 : $Builtin.Int32)
bb3:
br bb5
bb4:
br bb5
bb5:
%9 = integer_literal $Builtin.Int32, 24
br bb11(%9 : $Builtin.Int32)
bb6:
br bb7
bb7:
%13 = integer_literal $Builtin.Int32, 100
br bb11(%13 : $Builtin.Int32)
bb8:
br bb9
bb9:
br bb10
bb10:
%18 = integer_literal $Builtin.Int32, 100
br bb11(%18 : $Builtin.Int32)
bb11(%21 : $Builtin.Int32):
%22 = struct $Int32 (%21: $Builtin.Int32)
return %22 : $Int32
}
// CHECK_WITH_CODEMOTION-LABEL: sil @FormSelectEnumBoolResult
// CHECK_WITH_CODEMOTION-NOT: switch_enum
// CHECK_WITH_CODEMOTION: select_enum
// CHECK_WITH_CODEMOTION: return
sil @FormSelectEnumBoolResult : $@convention(thin) (Numbers) -> Bool {
bb0(%0 : $Numbers):
debug_value %0 : $Numbers, let, name "e"
switch_enum %0 : $Numbers, case #Numbers.First!enumelt: bb1, case #Numbers.Second!enumelt: bb3, case #Numbers.Third!enumelt: bb4, default bb6
bb1:
br bb2
bb2:
%4 = integer_literal $Builtin.Int1, -1
br bb9(%4 : $Builtin.Int1)
bb3:
br bb5
bb4:
br bb5
bb5:
%9 = integer_literal $Builtin.Int1, 0
br bb9(%9 : $Builtin.Int1)
bb6:
br bb7
bb7:
br bb8
bb8:
%14 = integer_literal $Builtin.Int1, -1
br bb9(%14 : $Builtin.Int1)
bb9(%17 : $Builtin.Int1):
%18 = struct $Bool (%17 : $Builtin.Int1)
return %18 : $Bool
}
// CHECK_WITH_CODEMOTION-LABEL: sil @DontFormSelectEnumBoolResult
// CHECK_WITH_CODEMOTION: switch_enum
// CHECK_WITH_CODEMOTION-NOT: select_enum
// CHECK_WITH_CODEMOTION: return
sil @DontFormSelectEnumBoolResult : $@convention(thin) (Numbers, Bool) -> Bool {
bb0(%0 : $Numbers, %1 : $Bool):
debug_value %0 : $Numbers, let, name "e"
%2 = struct_extract %1 : $Bool, #Bool._value
switch_enum %0 : $Numbers, case #Numbers.First!enumelt: bb1, case #Numbers.Second!enumelt: bb3, case #Numbers.Third!enumelt: bb4, default bb6
bb1:
br bb2
bb2:
%6 = integer_literal $Builtin.Int1, -1
br bb10(%6 : $Builtin.Int1)
bb3:
br bb5
bb4:
br bb5
bb5:
%11 = integer_literal $Builtin.Int1, 0
br bb10(%11 : $Builtin.Int1)
bb6:
br bb7
bb7:
br bb8
bb8:
br bb9
bb9:
br bb10(%2 : $Builtin.Int1)
bb10(%18 : $Builtin.Int1):
%19 = struct $Bool (%18 : $Builtin.Int1)
return %19 : $Bool
}
// --- Test simplifyArguments; unwrap enum argument
// This optimization should not be defeated by the existence of other
// (unrelated) block arguments
struct Payload {
init()
}
enum MyEnum {
case payload(Payload)
}
enum ThreeWay {
case one
case two
case three
@_implements(Equatable, ==(_:_:)) static func __derived_enum_equals(_ a: ThreeWay, _ b: ThreeWay) -> Bool
var hashValue: Int { get }
func hash(into hasher: inout Hasher)
}
// CHECK-LABEL: sil hidden [noinline] @testUnwrapEnumArg : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: br bb1(undef : $Builtin.Int64, %{{.*}} : $Payload)
// CHECK: bb1(%{{.*}} : $Builtin.Int64, %{{.*}} : $Payload):
// CHECK: alloc_stack $Payload
// CHECK: switch_enum undef : $ThreeWay, case #ThreeWay.one!enumelt: bb4, case #ThreeWay.two!enumelt: bb2, case #ThreeWay.three!enumelt: bb3
// CHECK: bb2:
// CHECK: [[P2:%.*]] = load %{{.*}} : $*Payload
// CHECK: dealloc_stack %{{.*}} : $*Payload
// CHECK: br bb1(undef : $Builtin.Int64, [[P2]] : $Payload)
// CHECK: bb3:
// CHECK: [[P3:%.*]] = load %{{.*}} : $*Payload
// CHECK: dealloc_stack %{{.*}} : $*Payload
// CHECK: br bb7
// CHECK: bb4:
// CHECK: [[P4:%.*]] = load %{{.*}} : $*Payload
// CHECK: dealloc_stack %{{.*}} : $*Payload
// CHECK: cond_br undef, bb5, bb6
// CHECK: bb5:
// CHECK: br bb7
// CHECK: bb6:
// CHECK: br bb1(undef : $Builtin.Int64, [[P4]] : $Payload)
// CHECK: bb7:
// CHECK: return %{{.*}} : $()
// CHECK-LABEL: } // end sil function 'testUnwrapEnumArg'
sil hidden [noinline] @testUnwrapEnumArg : $@convention(thin) () -> () {
bb0:
%0 = struct $Payload (undef : $_UIntBuffer<UInt8>)
%1 = enum $MyEnum, #MyEnum.payload!enumelt, %0 : $Payload
br bb1(undef : $Builtin.Int64, %1 : $MyEnum)
bb1(%3 : $Builtin.Int64, %4 : $MyEnum):
%5 = alloc_stack $Payload
%6 = unchecked_enum_data %4 : $MyEnum, #MyEnum.payload!enumelt
store %6 to %5 : $*Payload
%8 = builtin "cmp_eq_Int64"(%3 : $Builtin.Int64, undef : $Builtin.Int64) : $Builtin.Int1
switch_enum undef : $ThreeWay, case #ThreeWay.one!enumelt: bb4, case #ThreeWay.two!enumelt: bb2, case #ThreeWay.three!enumelt: bb3
bb2:
%10 = load %5 : $*Payload
%11 = enum $MyEnum, #MyEnum.payload!enumelt, %10 : $Payload
dealloc_stack %5 : $*Payload
br bb6(%11 : $MyEnum)
bb3:
%14 = load %5 : $*Payload
%15 = enum $MyEnum, #MyEnum.payload!enumelt, %14 : $Payload
dealloc_stack %5 : $*Payload
br bb7
bb4:
%18 = load %5 : $*Payload
%19 = enum $MyEnum, #MyEnum.payload!enumelt, %18 : $Payload
dealloc_stack %5 : $*Payload
cond_br undef, bb7, bb5
bb5:
br bb6(%19 : $MyEnum)
bb6(%23 : $MyEnum):
br bb1(undef : $Builtin.Int64, %23 : $MyEnum)
bb7:
%25 = tuple ()
return %25 : $()
}