mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Type annotations for instruction operands are omitted, e.g. ``` %3 = struct $S(%1, %2) ``` Operand types are redundant anyway and were only used for sanity checking in the SIL parser. But: operand types _are_ printed if the definition of the operand value was not printed yet. This happens: * if the block with the definition appears after the block where the operand's instruction is located * if a block or instruction is printed in isolation, e.g. in a debugger The old behavior can be restored with `-Xllvm -sil-print-types`. This option is added to many existing test files which check for operand types in their check-lines.
817 lines
20 KiB
Plaintext
817 lines
20 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
|
|
// RUN: %target-sil-opt -sil-print-types -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: sil @simplify_switch_include_args :
|
|
// CHECK: tuple
|
|
// CHECK-NEXT: enum $X
|
|
// CHECK-NEXT: unchecked_enum_data
|
|
// CHECK-NEXT: tuple_extract
|
|
// CHECK-NEXT: return
|
|
// CHECK: } // end sil function 'simplify_switch_include_args'
|
|
sil @simplify_switch_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 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(%{{.*}} : $Payload)
|
|
// CHECK: bb1(%{{.*}} : $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([[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([[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 : $()
|
|
}
|