| // RUN: %target-sil-opt -enable-objc-interop -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -sil-combine | %FileCheck %s |
| |
| import Builtin |
| import Swift |
| |
| // Simplify arithmetic where one operand is a zero and the other is not a constant |
| sil @fold_add_with_overflow_zeros : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 { |
| bb0(%x : $Builtin.Int64): |
| %0 = integer_literal $Builtin.Int64, 0 |
| %18 = builtin "int_sadd_with_overflow_Int64"(%x : $Builtin.Int64, %0 : $Builtin.Int64) : $(Builtin.Int64, Builtin.Int1) |
| %19 = tuple_extract %18 : $(Builtin.Int64, Builtin.Int1), 0 |
| return %19 : $Builtin.Int64 |
| |
| // CHECK-LABEL: sil @fold_add_with_overflow_zeros |
| // CHECK-NOT: integer_literal $Builtin.Int64, 0 |
| // CHECK-NOT: builtin "int_sadd_with_overflow_Int64" |
| // CHECK: return %0 : $Builtin.Int64 |
| } |
| |
| // Simplify arithmetic where one operand is a zero and the other is not a constant |
| sil @fold_add_with_overflow_zeros2 : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 { |
| bb0(%x : $Builtin.Int64): |
| %0 = integer_literal $Builtin.Int64, 0 |
| %18 = builtin "int_sadd_with_overflow_Int64"(%0 : $Builtin.Int64, %x : $Builtin.Int64) : $(Builtin.Int64, Builtin.Int1) |
| %19 = tuple_extract %18 : $(Builtin.Int64, Builtin.Int1), 0 |
| return %19 : $Builtin.Int64 |
| |
| // CHECK-LABEL: sil @fold_add_with_overflow_zeros2 |
| // CHECK-NOT: integer_literal $Builtin.Int64, 0 |
| // CHECK-NOT: builtin "int_sadd_with_overflow_Int64" |
| // CHECK: return %0 : $Builtin.Int64 |
| } |
| |
| // Simplify arithmetic where one operand is a zero and the other is not a constant |
| sil @fold_sub_with_overflow_zeros : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 { |
| bb0(%x : $Builtin.Int64): |
| %0 = integer_literal $Builtin.Int64, 0 |
| %18 = builtin "int_ssub_with_overflow_Int64"(%x : $Builtin.Int64, %0 : $Builtin.Int64) : $(Builtin.Int64, Builtin.Int1) |
| %19 = tuple_extract %18 : $(Builtin.Int64, Builtin.Int1), 0 |
| return %19 : $Builtin.Int64 |
| |
| // CHECK-LABEL: sil @fold_sub_with_overflow_zeros |
| // CHECK-NOT: integer_literal $Builtin.Int64, 0 |
| // CHECK-NOT: builtin "int_ssub_with_overflow_Int64" |
| // CHECK: return %0 : $Builtin.Int64 |
| } |
| |
| // Simplify arithmetic where one operand is a zero and the other is not a constant |
| sil @fold_mul_with_overflow_zeros : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 { |
| bb0(%x : $Builtin.Int64): |
| %0 = integer_literal $Builtin.Int64, 0 |
| %18 = builtin "int_smul_with_overflow_Int64"(%x : $Builtin.Int64, %0 : $Builtin.Int64) : $(Builtin.Int64, Builtin.Int1) |
| %19 = tuple_extract %18 : $(Builtin.Int64, Builtin.Int1), 0 |
| return %19 : $Builtin.Int64 |
| |
| // CHECK-LABEL: sil @fold_mul_with_overflow_zeros |
| // CHECK-NOT: builtin "int_smul_with_overflow_Int64" |
| // CHECK: [[RES:%.*]] = integer_literal $Builtin.Int64, 0 |
| // CHECK-NEXT: return [[RES]] : $Builtin.Int64 |
| } |
| |
| // Simplify arithmetic where one operand is a one and the other is not a constant |
| sil @fold_mul_with_overflow_ones : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 { |
| bb0(%x : $Builtin.Int64): |
| %0 = integer_literal $Builtin.Int64, 1 |
| %18 = builtin "int_smul_with_overflow_Int64"(%x : $Builtin.Int64, %0 : $Builtin.Int64) : $(Builtin.Int64, Builtin.Int1) |
| %19 = tuple_extract %18 : $(Builtin.Int64, Builtin.Int1), 0 |
| return %19 : $Builtin.Int64 |
| |
| // CHECK-LABEL: sil @fold_mul_with_overflow_ones |
| // CHECK-NOT: builtin "int_smul_with_overflow_Int64" |
| // CHECK: return %0 : $Builtin.Int64 |
| } |
| |
| // Simplify trunc(zext(x)) -> x |
| sil @fold_trunc_zext : $@convention(thin) (Builtin.Word) -> Builtin.Word { |
| bb0(%x : $Builtin.Word): |
| %78 = builtin "zextOrBitCast_Word_Int64"(%x : $Builtin.Word) : $Builtin.Int64 // user: %80 |
| %80 = builtin "truncOrBitCast_Int64_Word"(%78 : $Builtin.Int64) : $Builtin.Word // users: %81, %85 |
| return %80 : $Builtin.Word |
| |
| // CHECK-LABEL: sil @fold_trunc_zext |
| // CHECK-NOT: builtin |
| // CHECK: return %0 : $Builtin.Word |
| } |
| |
| // Simplify trunc(sext(x)) -> x |
| sil @fold_trunc_sext : $@convention(thin) (Builtin.Word) -> Builtin.Word { |
| bb0(%x : $Builtin.Word): |
| %78 = builtin "sextOrBitCast_Word_Int64"(%x : $Builtin.Word) : $Builtin.Int64 // user: %80 |
| %80 = builtin "truncOrBitCast_Int64_Word"(%78 : $Builtin.Int64) : $Builtin.Word // users: %81, %85 |
| return %80 : $Builtin.Word |
| |
| // CHECK-LABEL: sil @fold_trunc_sext |
| // CHECK-NOT: builtin |
| // CHECK: return %0 : $Builtin.Word |
| } |
| |
| // Simplify trunc((x)) -> x with same type |
| sil @fold_trunc_n_to_n : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 { |
| bb0(%x : $Builtin.Int64): |
| %trunc = builtin "truncOrBitCast_Int64_Word"(%x : $Builtin.Int64) : $Builtin.Int64 |
| return %trunc : $Builtin.Int64 |
| |
| // CHECK-LABEL: sil @fold_trunc_n_to_n |
| // CHECK-NOT: builtin |
| // CHECK: return %0 : $Builtin.Int64 |
| } |
| |
| // Simplify sext((x)) -> x with same type |
| sil @fold_sext_n_to_n : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 { |
| bb0(%x : $Builtin.Int64): |
| %trunc = builtin "sextOrBitCast_Int64_Int64"(%x : $Builtin.Int64) : $Builtin.Int64 |
| return %trunc : $Builtin.Int64 |
| |
| // CHECK-LABEL: sil @fold_sext_n_to_n |
| // CHECK-NOT: builtin |
| // CHECK: return %0 : $Builtin.Int64 |
| } |
| |
| // Simplify zext((x)) -> x with same type |
| sil @fold_zext_n_to_n : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 { |
| bb0(%x : $Builtin.Int64): |
| %trunc = builtin "zextOrBitCast_Int64_Int64"(%x : $Builtin.Int64) : $Builtin.Int64 |
| return %trunc : $Builtin.Int64 |
| |
| // CHECK-LABEL: sil @fold_zext_n_to_n |
| // CHECK-NOT: builtin |
| // CHECK: return %0 : $Builtin.Int64 |
| } |
| |
| class IntClass { |
| @sil_stored var value: Builtin.Int32 { get set } |
| init(value: Builtin.Int32) |
| @objc deinit |
| } |
| |
| enum SortaOptional1 { |
| case Nope, Yup(IntClass) |
| } |
| |
| sil @rewrap_optional_1 : $@convention(thin) (@owned SortaOptional1) -> @owned SortaOptional1 { |
| bb0(%0 : $SortaOptional1): |
| switch_enum %0 : $SortaOptional1, case #SortaOptional1.Yup!enumelt.1: bb1, case #SortaOptional1.Nope!enumelt: bb2 |
| |
| bb1: |
| // CHECK-NOT: unchecked_enum_data |
| // CHECK: return %0 |
| %2 = unchecked_enum_data %0 : $SortaOptional1, #SortaOptional1.Yup!enumelt.1 |
| %3 = enum $SortaOptional1, #SortaOptional1.Yup!enumelt.1, %2 : $IntClass |
| return %3 : $SortaOptional1 |
| |
| bb2: |
| %5 = integer_literal $Builtin.Int1, -1 |
| cond_fail %5 : $Builtin.Int1 |
| unreachable |
| } |
| |
| enum SortaOptional2 { |
| case Nope, Yup(IntClass) |
| } |
| |
| sil @rewrap_optional_2 : $@convention(thin) (@owned SortaOptional1) -> @owned SortaOptional2 { |
| bb0(%0 : $SortaOptional1): |
| switch_enum %0 : $SortaOptional1, case #SortaOptional1.Yup!enumelt.1: bb1, case #SortaOptional1.Nope!enumelt: bb2 |
| |
| bb1: |
| // CHECK: [[DATA:%[0-9a-zA-Z]+]] = unchecked_enum_data %0 |
| // CHECK: [[RESULT:%[0-9a-zA-Z]+]] = enum $SortaOptional2, #SortaOptional2.Yup!enumelt.1, [[DATA]] : $IntClass |
| // CHECK: return [[RESULT]] |
| %2 = unchecked_enum_data %0 : $SortaOptional1, #SortaOptional1.Yup!enumelt.1 |
| %3 = enum $SortaOptional2, #SortaOptional2.Yup!enumelt.1, %2 : $IntClass // user: %4 |
| return %3 : $SortaOptional2 // id: %4 |
| |
| bb2: |
| %5 = integer_literal $Builtin.Int1, -1 |
| cond_fail %5 : $Builtin.Int1 |
| unreachable |
| } |
| |
| public enum GenericEnum<T> { |
| case A(T) |
| case B(Int) |
| } |
| |
| // CHECK-LABEL: sil @combine_enum_data_and_enum |
| // CHECK: [[RESULT:%[0-9]+]] = load %0 |
| // CHECK-NOT: unchecked_enum_data |
| // CHECK-NOT: enum $GenericEnum |
| // CHECK: return [[RESULT]] |
| sil @combine_enum_data_and_enum : $@convention(thin) (@in_guaranteed GenericEnum<Int>) -> GenericEnum<Int> { |
| bb0(%0 : $*GenericEnum<Int>): |
| %5 = load %0 : $*GenericEnum<Int> // users: %6, %7, %8, %23 |
| %23 = unchecked_enum_data %5 : $GenericEnum<Int>, #GenericEnum.B!enumelt.1 // user: %24 |
| %24 = enum $GenericEnum<Int>, #GenericEnum.B!enumelt.1, %23 : $Int |
| return %24 : $GenericEnum<Int> |
| } |
| |
| // CHECK-LABEL: sil @dont_combine_enum_data_and_enum |
| // CHECK: load |
| // CHECK-NEXT: unchecked_enum_data |
| // CHECK-NEXT: enum $GenericEnum |
| // CHECK-NEXT: return |
| sil @dont_combine_enum_data_and_enum : $@convention(thin) (@in_guaranteed GenericEnum<Int>) -> GenericEnum<Double> { |
| bb0(%0 : $*GenericEnum<Int>): |
| %5 = load %0 : $*GenericEnum<Int> // users: %6, %7, %8, %23 |
| %23 = unchecked_enum_data %5 : $GenericEnum<Int>, #GenericEnum.B!enumelt.1 // user: %24 |
| %24 = enum $GenericEnum<Double>, #GenericEnum.B!enumelt.1, %23 : $Int |
| return %24 : $GenericEnum<Double> |
| } |
| |
| public enum Ternary { |
| case First |
| case Second |
| case Third |
| |
| public subscript(_: Builtin.Word) -> Ternary {get} |
| } |
| |
| // CHECK-LABEL: sil @do_not_use_switch_enum_operand |
| sil @do_not_use_switch_enum_operand : $@convention(method) (Builtin.Word, Ternary) -> Ternary { |
| bb0(%0 : $Builtin.Word, %1 : $Ternary): |
| // CHECK: bb0 |
| // CHECK-NEXT: switch_enum %1 : $Ternary, case #Ternary.Second!enumelt: [[FIRST:bb[0-9a-zA-Z]+]], default [[SECOND:bb[0-9a-zA-Z]+]] |
| switch_enum %1 : $Ternary, case #Ternary.Second!enumelt: bb1, default bb2 |
| |
| bb1: |
| // CHECK: [[FIRST]] |
| // CHECK: enum $Ternary, #Ternary.Third!enumelt |
| %5 = enum $Ternary, #Ternary.Third!enumelt |
| br bb3(%5 : $Ternary) |
| |
| bb2: |
| // CHECK: [[SECOND]] |
| // CHECK: [[RESULT:%[0-9a-zA-Z]+]] = enum $Ternary, #Ternary.First!enumelt |
| %9 = enum $Ternary, #Ternary.First!enumelt |
| // CHECK: br bb3([[RESULT]] : $Ternary) |
| br bb3(%9 : $Ternary) |
| |
| bb3(%11 : $Ternary): |
| return %11 : $Ternary |
| } |
| |
| // xor(xor (a, b), b) -> a |
| // CHECK-LABEL: sil @simplify_xor1 |
| // CHECK: bb0 |
| // CHECK-NEXT: return %0 : $Builtin.Int32 |
| sil @simplify_xor1 : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> Builtin.Int32 { |
| bb0(%0 : $Builtin.Int32, %1 : $Builtin.Int32): |
| %2 = builtin "xor_Int32"(%0 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int32 |
| %3 = builtin "xor_Int32"(%2 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int32 |
| return %3 : $Builtin.Int32 |
| } |
| |
| // xor(xor (a, b), a) -> b |
| // CHECK-LABEL: sil @simplify_xor2 |
| // CHECK: bb0 |
| // CHECK-NEXT: return %1 : $Builtin.Int32 |
| sil @simplify_xor2 : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> Builtin.Int32 { |
| bb0(%0 : $Builtin.Int32, %1 : $Builtin.Int32): |
| %2 = builtin "xor_Int32"(%0 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int32 |
| %3 = builtin "xor_Int32"(%2 : $Builtin.Int32, %0 : $Builtin.Int32) : $Builtin.Int32 |
| return %3 : $Builtin.Int32 |
| } |
| |
| |
| // CHECK-LABEL: sil @simplify_xor3 |
| // CHECK: bb0 |
| // xor(b, xor (a, b)) -> a |
| // CHECK-NEXT: return %0 : $Builtin.Int32 |
| sil @simplify_xor3 : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> Builtin.Int32 { |
| bb0(%0 : $Builtin.Int32, %1 : $Builtin.Int32): |
| %2 = builtin "xor_Int32"(%0 : $Builtin.Int32, %1 : $Builtin.Int32) : $Builtin.Int32 |
| %3 = builtin "xor_Int32"(%1 : $Builtin.Int32, %2 : $Builtin.Int32) : $Builtin.Int32 |
| return %3 : $Builtin.Int32 |
| } |
| |
| struct BitwiseStruct1 { |
| var a: Int64 |
| var b: Int32 |
| } |
| struct BitwiseStruct2 { |
| var a: Int64 |
| var b: Int32 |
| } |
| |
| // CHECK-LABEL: sil @simplify_unchecked_bitwise_cast |
| // CHECK: bb0 |
| // CHECK-NEXT: tuple |
| // CHECK-NEXT: return |
| sil @simplify_unchecked_bitwise_cast : $@convention(thin) (BitwiseStruct1) -> (BitwiseStruct1, BitwiseStruct1) { |
| bb0(%0 : $BitwiseStruct1): |
| %1 = unchecked_bitwise_cast %0 : $BitwiseStruct1 to $BitwiseStruct1 |
| %2 = unchecked_bitwise_cast %0 : $BitwiseStruct1 to $BitwiseStruct2 |
| %3 = unchecked_bitwise_cast %2 : $BitwiseStruct2 to $BitwiseStruct1 |
| %4 = tuple (%1 : $BitwiseStruct1, %3 : $BitwiseStruct1) |
| return %4 : $(BitwiseStruct1, BitwiseStruct1) |
| } |
| |
| // simplify_shifts_by_zero |
| sil @simplify_shifts_by_zero : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64, Builtin.Int64, Builtin.Int64) { |
| bb0(%0 : $Builtin.Int64): |
| %1 = integer_literal $Builtin.Int64, 0 |
| %2 = builtin "ashr_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int64 |
| %3 = builtin "lshr_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int64 |
| %4 = builtin "shl_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int64 |
| %5 = tuple (%2 : $Builtin.Int64, %3 : $Builtin.Int64, %4 : $Builtin.Int64) |
| return %5 : $(Builtin.Int64, Builtin.Int64, Builtin.Int64) |
| |
| // CHECK-LABEL: sil @simplify_shifts_by_zero |
| // CHECK: bb0 |
| // CHECK-NEXT: %1 = tuple (%0 : $Builtin.Int64, %0 : $Builtin.Int64, %0 : $Builtin.Int64) |
| // CHECK-NEXT: return %1 : $(Builtin.Int64, Builtin.Int64, Builtin.Int64) |
| } |
| |
| public class A { |
| var b: B |
| init(b: B) |
| deinit |
| } |
| |
| public class B { |
| var x: Int |
| init(x: Int) |
| deinit |
| } |
| |
| // simplify access markers |
| sil @simplify_accesssil : $@convention(method) (@guaranteed A) -> () { |
| bb0(%0 : $A): |
| %badr = ref_element_addr %0 : $A, #A.b |
| %ba1 = begin_access [read] [dynamic] %badr : $*B |
| end_access %ba1 : $*B |
| %ba2 = begin_access [read] [dynamic] %badr : $*B |
| fix_lifetime %ba2 : $*B |
| end_access %ba2 : $*B |
| %ba3 = begin_access [read] [dynamic] %badr : $*B |
| %b = load %ba3 : $*B |
| end_access %ba3 : $*B |
| %xadr = ref_element_addr %b : $B, #B.x |
| %xaccess = begin_access [read] [dynamic] %xadr : $*Int |
| end_access %xaccess : $*Int |
| |
| %r = tuple () |
| return %r : $() |
| } |
| |
| // CHECK-LABEL: sil @simplify_accesssil : $@convention(method) (@guaranteed A) -> () { |
| // CHECK: bb0(%0 : $A): |
| // CHECK-NEXT: [[ADR:%.*]] = ref_element_addr %0 : $A, #A.b |
| // CHECK-NEXT: fix_lifetime [[ADR]] : $*B |
| // CHECK-NEXT: %{{.*}} = tuple () |
| // CHECK-NEXT: return %{{.*}} : $() |
| // CHECK-LABEL: } // end sil function 'simplify_accesssil' |