| // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -sil-combine | %FileCheck %s |
| |
| sil_stage canonical |
| |
| import Builtin |
| import Swift |
| import SwiftShims |
| |
| public class Base {} |
| |
| @objc |
| public protocol ObjCProto {} |
| |
| public protocol NativeProto {} |
| |
| // CHECK-LABEL: sil @promote_super : $@convention(thin) <T where T : Base> (@owned AnyObject) -> @owned T { |
| // CHECK: bb0(%0 : $AnyObject): |
| // CHECK: unchecked_ref_cast %{{.*}} : $AnyObject to $T |
| sil @promote_super : $@convention(thin) <T where T : Base> (@owned AnyObject) -> @owned T { |
| bb0(%0 : $AnyObject): |
| %1 = alloc_stack $AnyObject |
| store %0 to %1 : $*AnyObject |
| %3 = unchecked_addr_cast %1 : $*AnyObject to $*T |
| %4 = load %3 : $*T |
| dealloc_stack %1 : $*AnyObject |
| return %4 : $T |
| } |
| |
| // CHECK-LABEL: sil @promote_anyobject : $@convention(thin) <T where T : AnyObject> (@owned AnyObject) -> @owned T { |
| // CHECK: bb0(%0 : $AnyObject): |
| // CHECK: unchecked_ref_cast %{{.*}} : $AnyObject to $T |
| sil @promote_anyobject : $@convention(thin) <T where T : AnyObject> (@owned AnyObject) -> @owned T { |
| bb0(%0 : $AnyObject): |
| %1 = alloc_stack $AnyObject |
| store %0 to %1 : $*AnyObject |
| %3 = unchecked_addr_cast %1 : $*AnyObject to $*T |
| %4 = load %3 : $*T |
| dealloc_stack %1 : $*AnyObject |
| return %4 : $T |
| } |
| |
| // CHECK-LABEL: sil @promote_objc : $@convention(thin) <T where T : ObjCProto> (@owned AnyObject) -> @owned T { |
| // CHECK: bb0(%0 : $AnyObject): |
| // CHECK: unchecked_ref_cast %{{.*}} : $AnyObject to $T |
| sil @promote_objc : $@convention(thin) <T where T : ObjCProto> (@owned AnyObject) -> @owned T { |
| bb0(%0 : $AnyObject): |
| %1 = alloc_stack $AnyObject |
| store %0 to %1 : $*AnyObject |
| %3 = unchecked_addr_cast %1 : $*AnyObject to $*T |
| %4 = load %3 : $*T |
| dealloc_stack %1 : $*AnyObject |
| return %4 : $T |
| } |
| |
| // CHECK-LABEL: sil @promote_objcproto : $@convention(thin) (@owned AnyObject) -> @owned ObjCProto { |
| // CHECK: bb0(%0 : $AnyObject): |
| // CHECK: unchecked_ref_cast %{{.*}} : $AnyObject to $ObjCProto |
| sil @promote_objcproto : $@convention(thin) (@owned AnyObject) -> @owned ObjCProto { |
| bb0(%0 : $AnyObject): |
| %1 = alloc_stack $AnyObject |
| store %0 to %1 : $*AnyObject |
| %3 = unchecked_addr_cast %1 : $*AnyObject to $*ObjCProto |
| %4 = load %3 : $*ObjCProto |
| dealloc_stack %1 : $*AnyObject |
| return %4 : $ObjCProto |
| } |
| |
| // CHECK-LABEL: sil @nopromote_nativeproto : $@convention(thin) (@owned AnyObject) -> @out NativeProto { |
| // CHECK: bb0(%0 : $*NativeProto, %1 : $AnyObject): |
| // CHECK: unchecked_addr_cast %{{.*}} : $*AnyObject to $*NativeProto |
| sil @nopromote_nativeproto : $@convention(thin) (@owned AnyObject) -> @out NativeProto { |
| bb0(%0 : $*NativeProto, %1 : $AnyObject): |
| %3 = alloc_stack $AnyObject |
| store %1 to %3 : $*AnyObject |
| %5 = unchecked_addr_cast %3 : $*AnyObject to $*NativeProto |
| copy_addr %5 to [initialization] %0 : $*NativeProto |
| dealloc_stack %3 : $*AnyObject |
| strong_release %1 : $AnyObject |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| class B {} |
| |
| // CHECK-LABEL: sil @load_uncheckedaddrcast_to_uncheckedrefcast_load : $@convention(thin) (@inout Optional<B>) -> (Builtin.NativeObject, Optional<Builtin.NativeObject>) { |
| // CHECK-NOT: unchecked_addr_cast |
| // CHECK: unchecked_ref_cast |
| // CHECK-NOT: unchecked_addr_cast |
| // CHECK: unchecked_ref_cast |
| // CHECK-NOT: unchecked_addr_cast |
| sil @load_uncheckedaddrcast_to_uncheckedrefcast_load : $@convention(thin) (@inout Optional<B>) -> (Builtin.NativeObject, Optional<Builtin.NativeObject>) { |
| bb0(%0 : $*Optional<B>): |
| %1 = unchecked_addr_cast %0 : $*Optional<B> to $*Builtin.NativeObject |
| %2 = unchecked_addr_cast %0 : $*Optional<B> to $*Optional<Builtin.NativeObject> |
| %3 = load %1 : $*Builtin.NativeObject |
| %4 = load %2 : $*Optional<Builtin.NativeObject> |
| %5 = tuple(%3 : $Builtin.NativeObject, %4 : $Optional<Builtin.NativeObject>) |
| return %5 : $(Builtin.NativeObject, Optional<Builtin.NativeObject>) |
| } |
| |
| struct rs_E { |
| var ptr : Builtin.NativeObject |
| var i : Int |
| } |
| struct rs_F { |
| var e : rs_E |
| } |
| struct rs_D { |
| var i : Int |
| } |
| struct rs_C { |
| var d : rs_D |
| } |
| |
| struct rs_B { |
| var ptr : Builtin.NativeObject |
| } |
| struct rs_A { |
| var b : rs_B |
| } |
| |
| enum TwoStateEnum { |
| case State1(rs_A) |
| case State2(rs_C) |
| } |
| |
| enum FakeOptional<T> { |
| case nOne |
| case some(T) |
| } |
| |
| // CHECK-LABEL: sil @reinterpretcast_simplification_unchecked_addr : $@convention(thin) (@inout FakeOptional<rs_A>, @inout FakeOptional<rs_C>, @inout FakeOptional<rs_F>, @inout TwoStateEnum, @inout TwoStateEnum) -> (Builtin.NativeObject, Int, Builtin.NativeObject, Builtin.NativeObject, Int) { |
| // CHECK: bb0( |
| // CHECK-NEXT: load |
| // CHECK-NEXT: unchecked_bitwise_cast |
| // CHECK-NEXT: load |
| // CHECK-NEXT: unchecked_trivial_bit_cast |
| // CHECK-NEXT: load |
| // CHECK-NEXT: unchecked_bitwise_cast |
| // CHECK-NEXT: load |
| // CHECK-NEXT: unchecked_bitwise_cast |
| // CHECK-NEXT: load |
| // CHECK-NEXT: unchecked_trivial_bit_cast |
| // CHECK-NEXT: tuple |
| // CHECK-NEXT: return |
| sil @reinterpretcast_simplification_unchecked_addr |
| : $@convention(thin) (@inout FakeOptional<rs_A>, @inout FakeOptional<rs_C>, @inout FakeOptional<rs_F>, @inout TwoStateEnum, |
| @inout TwoStateEnum) |
| -> (Builtin.NativeObject, Int, Builtin.NativeObject, Builtin.NativeObject, Int) { |
| bb0(%0 : $*FakeOptional<rs_A>, %1 : $*FakeOptional<rs_C>, %2 : $*FakeOptional<rs_F>, %3 : $*TwoStateEnum, %4 : $*TwoStateEnum): |
| %5 = unchecked_addr_cast %0 : $*FakeOptional<rs_A> to $*Builtin.NativeObject |
| %6 = unchecked_addr_cast %1 : $*FakeOptional<rs_C> to $*Int |
| %7 = unchecked_addr_cast %2 : $*FakeOptional<rs_F> to $*Builtin.NativeObject |
| %8 = unchecked_addr_cast %3 : $*TwoStateEnum to $*Builtin.NativeObject |
| %9 = unchecked_addr_cast %4 : $*TwoStateEnum to $*Int |
| %10 = load %5 : $*Builtin.NativeObject |
| %11 = load %6 : $*Int |
| %12 = load %7 : $*Builtin.NativeObject |
| %13 = load %8 : $*Builtin.NativeObject |
| %14 = load %9 : $*Int |
| %15 = tuple(%10 : $Builtin.NativeObject, %11 : $Int, %12 : $Builtin.NativeObject, %13 : $Builtin.NativeObject, %14 : $Int) |
| return %15 : $(Builtin.NativeObject, Int, Builtin.NativeObject, Builtin.NativeObject, Int) |
| } |
| |
| enum ValEnum {case X, Y, Z} |
| |
| struct PtrInt { |
| var Ptr: Builtin.RawPointer |
| var Val: Builtin.Int32 |
| } |
| struct PtrInt2 { |
| var Ptr: Builtin.RawPointer |
| var Val1: Builtin.Int32 |
| var Val2: ValEnum |
| } |
| struct Agg { |
| var pi: PtrInt |
| var Val: ValEnum |
| } |
| |
| // struct {A, B} -> A is safe |
| // struct {A, B, C} -> struct {A, B} is safe |
| // struct { struct {A, B}, C} -> struct {A, B} is safe |
| // struct { struct {A, B}, C} -> struct {A, B, C} is NOT safe |
| // CHECK-LABEL: sil @unchecked_addr_cast_struct_promote : $@convention(thin) (@inout PtrInt, @inout PtrInt2, @inout Agg) -> (Builtin.RawPointer, PtrInt, PtrInt, PtrInt2) { |
| // CHECK: bb0(%0 : $*PtrInt, %1 : $*PtrInt2, %2 : $*Agg): |
| // CHECK: load %0 : $*PtrInt |
| // CHECK: unchecked_trivial_bit_cast %{{.*}} : $PtrInt to $Builtin.RawPointer |
| // CHECK: load %1 : $*PtrInt2 |
| // CHECK: unchecked_trivial_bit_cast %{{.*}} : $PtrInt2 to $PtrInt |
| // CHECK: load %2 : $*Agg |
| // CHECK: unchecked_trivial_bit_cast %{{.*}} : $Agg to $PtrInt |
| // CHECK: [[LOCAL:%.*]] = alloc_stack $Agg |
| // CHECK: store %{{.*}} to [[LOCAL]] : $*Agg |
| // CHECK: [[CAST:%.*]] = unchecked_addr_cast [[LOCAL]] : $*Agg to $*PtrInt2 |
| // CHECK: load [[CAST]] : $*PtrInt2 |
| // CHECK: dealloc_stack |
| // CHECK: return |
| sil @unchecked_addr_cast_struct_promote : $@convention(thin) (@inout PtrInt, @inout PtrInt2, @inout Agg) -> (Builtin.RawPointer, PtrInt, PtrInt, PtrInt2) { |
| bb0(%0 : $*PtrInt, %1 : $*PtrInt2, %2 : $*Agg): |
| %3 = load %0 : $*PtrInt |
| %4 = alloc_stack $PtrInt |
| store %3 to %4 : $*PtrInt |
| %6 = unchecked_addr_cast %4 : $*PtrInt to $*Builtin.RawPointer |
| %7 = load %6 : $*Builtin.RawPointer |
| %8 = load %1 : $*PtrInt2 |
| %9 = alloc_stack $PtrInt2 |
| store %8 to %9 : $*PtrInt2 |
| %11 = unchecked_addr_cast %9 : $*PtrInt2 to $*PtrInt |
| %12 = load %11 : $*PtrInt |
| %13 = load %2 : $*Agg |
| %14 = alloc_stack $Agg |
| store %13 to %14 : $*Agg |
| %16 = unchecked_addr_cast %14 : $*Agg to $*PtrInt |
| %17 = load %16 : $*PtrInt |
| %18 = alloc_stack $Agg |
| store %13 to %18 : $*Agg |
| %20 = unchecked_addr_cast %18 : $*Agg to $*PtrInt2 |
| %21 = load %20 : $*PtrInt2 |
| %22 = tuple (%7 : $Builtin.RawPointer, %12 : $PtrInt, %17 : $PtrInt, %21 : $PtrInt2) |
| dealloc_stack %18 : $*Agg |
| dealloc_stack %14 : $*Agg |
| dealloc_stack %9 : $*PtrInt2 |
| dealloc_stack %4 : $*PtrInt |
| return %22 : $(Builtin.RawPointer, PtrInt, PtrInt, PtrInt2) |
| } |
| |
| public enum E0 {} |
| public enum E0_ {} |
| public enum E1 {case A} |
| public enum E2 {case A, B} |
| public enum E3 {case A, B, C} |
| |
| public enum PB2 {case A, B(Int)} |
| public enum PX2 {case X(Int), Y} |
| public enum PAB2 {case A(Int), B(Int)} |
| public enum PXY2 {case X(Int), Y(Int)} |
| public enum PX3 {case X(Int), Y, Z} |
| |
| // enum {} -> enum {} is safe |
| // enum {A, B} -> enum {X} is safe |
| // enum {A, B(Int)} -> Int is safe |
| // enum {A, B(Int)} -> enum {X(Int), Y} is safe |
| // enum {A, B(Int)} -> enum {X(Int), Y, Z} is NOT safe |
| // enum {A(Int), B(Int)} -> enum {X(Int), Y(Int)} is NOT safe |
| // CHECK-LABEL: sil @unchecked_addr_cast_enum_promote : $@convention(thin) (@inout E0, @inout E2, @inout PB2, @inout PAB2) -> (E0_, E1, Int, PX2, PX3, PXY2) |
| // CHECK: load %0 : $*E0 |
| // CHECK: unchecked_trivial_bit_cast %{{.*}} : $E0 to $E0_ |
| // CHECK: load %1 : $*E2 |
| // CHECK: unchecked_trivial_bit_cast %{{.*}} : $E2 to $E1 |
| // CHECK: load %2 : $*PB2 |
| // CHECK: unchecked_trivial_bit_cast %{{.*}} : $PB2 to $Int |
| // CHECK: unchecked_trivial_bit_cast %{{.*}} : $PB2 to $PX2 |
| // CHECK: alloc_stack $PB2 |
| // CHECK: store %{{.*}} to %{{.*}} : $*PB2 |
| // CHECK: unchecked_addr_cast %{{.*}} : $*PB2 to $*PX3 |
| // CHECK: load %{{.*}} : $*PX3 |
| // CHECK: load %3 : $*PAB2 |
| // CHECK: alloc_stack $PAB2 |
| // CHECK: store %{{.*}} to %{{.*}} : $*PAB2 |
| // CHECK: unchecked_addr_cast %{{.*}} : $*PAB2 to $*PXY2 |
| // CHECK: load %{{.*}} : $*PXY2 |
| // CHECK: dealloc_stack %{{.*}} : $*PAB2 |
| // CHECK: dealloc_stack %{{.*}} : $*PB2 |
| // CHECK: return %{{.*}} : $(E0_, E1, Int, PX2, PX3, PXY2) |
| sil @unchecked_addr_cast_enum_promote : $@convention(thin) (@inout E0, @inout E2, @inout PB2, @inout PAB2) -> (E0_, E1, Int, PX2, PX3, PXY2) { |
| bb0(%0 : $*E0, %1 : $*E2, %2 : $*PB2, %3 : $*PAB2): |
| %9 = load %0 : $*E0 // user: %11 |
| %10 = alloc_stack $E0 // users: %11, %12, %43 |
| store %9 to %10 : $*E0 // id: %11 |
| %12 = unchecked_addr_cast %10 : $*E0 to $*E0_ // user: %13 |
| %13 = load %12 : $*E0_ // user: %37 |
| %14 = load %1 : $*E2 // user: %16 |
| %15 = alloc_stack $E2 // users: %16, %17, %42 |
| store %14 to %15 : $*E2 // id: %16 |
| %17 = unchecked_addr_cast %15 : $*E2 to $*E1 // user: %18 |
| %18 = load %17 : $*E1 // user: %37 |
| %19 = load %2 : $*PB2 // users: %21, %25, %29 |
| %20 = alloc_stack $PB2 // users: %21, %22, %41 |
| store %19 to %20 : $*PB2 // id: %21 |
| %22 = unchecked_addr_cast %20 : $*PB2 to $*Int // user: %23 |
| %23 = load %22 : $*Int // user: %37 |
| %24 = alloc_stack $PB2 // users: %25, %26, %40 |
| store %19 to %24 : $*PB2 // id: %25 |
| %26 = unchecked_addr_cast %24 : $*PB2 to $*PX2 // user: %27 |
| %27 = load %26 : $*PX2 // user: %37 |
| %28 = alloc_stack $PB2 // users: %29, %30, %39 |
| store %19 to %28 : $*PB2 // id: %29 |
| %30 = unchecked_addr_cast %28 : $*PB2 to $*PX3 // user: %31 |
| %31 = load %30 : $*PX3 // user: %37 |
| %32 = load %3 : $*PAB2 // user: %34 |
| %33 = alloc_stack $PAB2 // users: %34, %35, %38 |
| store %32 to %33 : $*PAB2 // id: %34 |
| %35 = unchecked_addr_cast %33 : $*PAB2 to $*PXY2 // user: %36 |
| %36 = load %35 : $*PXY2 // user: %37 |
| %37 = tuple (%13 : $E0_, %18 : $E1, %23 : $Int, %27 : $PX2, %31 : $PX3, %36 : $PXY2) // user: %44 |
| dealloc_stack %33 : $*PAB2 // id: %38 |
| dealloc_stack %28 : $*PB2 // id: %39 |
| dealloc_stack %24 : $*PB2 // id: %40 |
| dealloc_stack %20 : $*PB2 // id: %41 |
| dealloc_stack %15 : $*E2 // id: %42 |
| dealloc_stack %10 : $*E0 // id: %43 |
| return %37 : $(E0_, E1, Int, PX2, PX3, PXY2) // id: %44 |
| } |