blob: 9f296987ae77f84cd28cd5a841772ce3f1a43833 [file] [log] [blame]
// RUN: %target-sil-opt -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_unchecked_addr_cast_to_unchecked_ref_cast_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_unchecked_addr_cast_to_unchecked_ref_cast_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
}