Revision 42e827e6e7247224c068a9dce8f6eabd2ab892ba authored by Devin Coughlin on 21 January 2016, 00:12:56 UTC, committed by Devin Coughlin on 21 January 2016, 01:22:15 UTC
1 parent ac1f5a6
Raw File
casts.sil
// RUN: %target-swift-frontend -Xllvm -sil-disable-pass="External Defs To Decls" %s -emit-ir -disable-objc-attr-requires-foundation-module | FileCheck %s

// REQUIRES: CPU=i386_or_x86_64
// XFAIL: linux

sil_stage canonical

import Builtin
import Swift

struct NotClass {}

class A {}
class B: A {}

sil_vtable A {}
sil_vtable B {}

// CHECK-LABEL: define %C5casts1B* @unchecked_addr_cast(%C5casts1A** noalias nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK:         bitcast %C5casts1A** %0 to %C5casts1B**
sil @unchecked_addr_cast : $(@in A) -> B {
entry(%a : $*A):
  %b = unchecked_addr_cast %a : $*A to $*B
  %x = load %b : $*B
  return %x : $B
}

protocol CP: class {}
protocol CP2: class {}
@objc protocol OP: class {}

// CHECK-LABEL: define i8* @ref_to_raw_pointer_existential(%objc_object*, i8**) {{.*}} {
// CHECK:         [[CAST:%.*]] = bitcast %objc_object* %0 to i8*
// CHECK:         ret i8* [[CAST]]
sil @ref_to_raw_pointer_existential : $@convention(thin) (@owned CP) -> Builtin.RawPointer {
entry(%p : $CP):
  %r = ref_to_raw_pointer %p : $CP to $Builtin.RawPointer
  return %r : $Builtin.RawPointer
}

// CHECK-LABEL: define %objc_object* @raw_pointer_to_ref_existential(i8*) {{.*}} {
// CHECK:         [[CAST:%.*]] = bitcast i8* %0 to %objc_object*
// CHECK:         ret %objc_object* [[CAST]]
sil @raw_pointer_to_ref_existential : $@convention(thin) (@owned Builtin.RawPointer) -> AnyObject {
entry(%p : $Builtin.RawPointer):
  %r = raw_pointer_to_ref %p : $Builtin.RawPointer to $AnyObject
  return %r : $AnyObject
}

sil @unchecked_ref_cast_to_existential : $@convention(thin) (@owned Builtin.NativeObject) -> @owned AnyObject {
entry(%n : $Builtin.NativeObject):
  %r = unchecked_ref_cast %n : $Builtin.NativeObject to $AnyObject
  return %r : $AnyObject
}

// CHECK-LABEL: define { %objc_object*, i8** } @u_cast_to_class_existential(%objc_object*)
// CHECK:         call { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* {{%.*}}, %swift.type* {{%.*}}, %swift.protocol* @_TMp5casts2CP)
// CHECK-LABEL: define private { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8*, %swift.type*, %swift.protocol*) {{.*}} {
// CHECK:         [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2)
// CHECK:         [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null
// CHECK:         br i1 [[IS_NULL]], label %fail, label %cont
// CHECK:       cont:
// CHECK:         [[FIRST:%.*]] = insertvalue { i8*, i8** } undef, i8* %0, 0
// CHECK:         [[SECOND:%.*]] = insertvalue { i8*, i8** } [[FIRST]], i8** [[WITNESS]], 1
// CHECK:         ret { i8*, i8** } [[SECOND]]
// CHECK:       fail:
// CHECK:         call void @llvm.trap()
sil @u_cast_to_class_existential : $@convention(thin) (@owned AnyObject) -> @owned CP {
entry(%a : $AnyObject):
  %p = unconditional_checked_cast %a : $AnyObject to $CP
  return %p : $CP
}

// CHECK-LABEL: define { %swift.type*, i8** } @u_cast_to_existential_metatype(%swift.type*)
// CHECK:         call { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* %1, %swift.type* %0, %swift.protocol* @_TMp5casts2CP)
sil @u_cast_to_existential_metatype : $@convention(thin) (@owned @thick Any.Type) -> @owned @thick CP.Type {
entry(%a : $@thick Any.Type):
  %p = unconditional_checked_cast %a : $@thick Any.Type to $@thick CP.Type
  return %p : $@thick CP.Type
}

// CHECK-LABEL: define { %objc_object*, i8**, i8** } @u_cast_to_class_existential_2(%objc_object*)
// CHECK:         call { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* {{%.*}}, %swift.type* {{%.*}}, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2)
// CHECK-LABEL: define private { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8*, %swift.type*, %swift.protocol*, %swift.protocol*)
// CHECK:         [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2)
// CHECK:         [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null
// CHECK:         br i1 [[IS_NULL]], label %fail, label %cont
// CHECK:       cont:
// CHECK:         [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %3)
// CHECK:         [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null
// CHECK:         br i1 [[IS_NULL]], label %fail, label %cont.1
// CHECK:       cont.1:
// CHECK:         ret { i8*, i8**, i8** }
// CHECK:       fail:
// CHECK:         call void @llvm.trap()
sil @u_cast_to_class_existential_2 : $@convention(thin) (@owned AnyObject) -> @owned protocol<CP, CP2> {
entry(%a : $AnyObject):
  %p = unconditional_checked_cast %a : $AnyObject to $protocol<CP, CP2>
  return %p : $protocol<CP, CP2>
}

// CHECK-LABEL: define { %objc_object*, i8**, i8** } @u_cast_to_class_existential_mixed(%objc_object*)
// CHECK:         call %objc_object* @swift_dynamicCastObjCProtocolUnconditional
// CHECK:         call { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* {{%.*}}, %swift.type* {{%.*}}, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2)
sil @u_cast_to_class_existential_mixed : $@convention(thin) (@owned AnyObject) -> @owned protocol<CP, OP, CP2> {
entry(%a : $AnyObject):
  %p = unconditional_checked_cast %a : $AnyObject to $protocol<CP, OP, CP2>
  return %p : $protocol<CP, OP, CP2>
}

// CHECK-LABEL: define { %swift.type*, i8**, i8** } @u_cast_to_existential_metatype_mixed(%swift.type*)
// CHECK:         call %swift.type* @swift_dynamicCastTypeToObjCProtocolUnconditional(%swift.type* %0, {{(i32|i64)}} 1, i8** {{%.*}})
// CHECK:         [[CAST:%.*]] = call { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* {{.*}}, %swift.type* %0, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2)
// CHECK:         [[OBJPTR:%.*]] = extractvalue { i8*, i8**, i8** } [[CAST]], 0
// CHECK:         [[OBJ:%.*]] = bitcast i8* [[OBJPTR]] to %swift.type*
// CHECK:         insertvalue {{.*}} [[OBJ]]
sil @u_cast_to_existential_metatype_mixed : $@convention(thin) (@owned @thick Any.Type) -> @owned @thick protocol<CP, OP, CP2>.Type {
entry(%a : $@thick Any.Type):
  %p = unconditional_checked_cast %a : $@thick Any.Type to $@thick protocol<CP, OP, CP2>.Type
  return %p : $@thick protocol<CP, OP, CP2>.Type
}


// CHECK-LABEL: define { %objc_object*, i8** } @c_cast_to_class_existential(%objc_object*)
// CHECK:         call { i8*, i8** } @dynamic_cast_existential_1_conditional(i8* {{.*}}, %swift.type* %.Type, %swift.protocol* @_TMp5casts2CP)
// CHECK-LABEL: define private { i8*, i8** } @dynamic_cast_existential_1_conditional(i8*, %swift.type*, %swift.protocol*)
// CHECK:         [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2)
// CHECK:         [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null
// CHECK:         br i1 [[IS_NULL]], label %fail, label %cont
// CHECK:       cont:
// CHECK:         ret { i8*, i8** }
// CHECK:       fail:
// CHECK:         ret { i8*, i8** } zeroinitializer
sil @c_cast_to_class_existential : $@convention(thin) (@owned AnyObject) -> @owned CP {
entry(%a : $AnyObject):
  checked_cast_br %a : $AnyObject to $CP, yea, nay
yea(%p : $CP):
  return %p : $CP
nay:
  unreachable
}

// CHECK-LABEL: define { %swift.type*, i8** } @c_cast_to_existential_metatype(%swift.type*) {{.*}} {
// CHECK:         call { i8*, i8** } @dynamic_cast_existential_1_conditional(i8* %1, %swift.type* %0, %swift.protocol* @_TMp5casts2CP)
sil @c_cast_to_existential_metatype : $@convention(thin) (@owned @thick Any.Type) -> @owned @thick CP.Type {
entry(%a : $@thick Any.Type):
  checked_cast_br %a : $@thick Any.Type to $@thick CP.Type, yea, nay
yea(%p : $@thick CP.Type):
  return %p : $@thick CP.Type
nay:
  unreachable
}

// CHECK-LABEL: define { %objc_object*, i8**, i8** } @c_cast_to_class_existential_2(%objc_object*)
// CHECK:         call { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* {{%.*}}, %swift.type* {{%.*}}, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2)
// CHECK-LABEL: define private { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8*, %swift.type*, %swift.protocol*, %swift.protocol*)
// CHECK:         [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2)
// CHECK:         [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null
// CHECK:         br i1 [[IS_NULL]], label %fail, label %cont
// CHECK:       cont:
// CHECK:         [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %3)
// CHECK:         [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null
// CHECK:         br i1 [[IS_NULL]], label %fail, label %cont.1
// CHECK:       cont.1:
// CHECK:         ret { i8*, i8**, i8** }
// CHECK:       fail:
// CHECK:         ret { i8*, i8**, i8** } zeroinitializer
sil @c_cast_to_class_existential_2 : $@convention(thin) (@owned AnyObject) -> @owned protocol<CP, CP2> {
entry(%a : $AnyObject):
  checked_cast_br %a : $AnyObject to $protocol<CP, CP2>, yea, nay
yea(%p : $protocol<CP, CP2>):
  return %p : $protocol<CP, CP2>
nay:
  unreachable
}

// CHECK-LABEL: define { %objc_object*, i8**, i8** } @c_cast_to_class_existential_mixed(%objc_object*)
// CHECK:         [[CAST:%.*]] = call %objc_object* @swift_dynamicCastObjCProtocolConditional
// CHECK:         [[IS_NULL:%.*]] = icmp eq %objc_object* [[CAST]], null
// CHECK:         br i1 [[IS_NULL]], label %cont, label %success
// CHECK:       success:
// CHECK:         call { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* {{%.*}}, %swift.type* {{%.*}}, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2)
// CHECK:         br label %cont
// CHECK:       cont:
// CHECK:         phi %objc_object* [ [[CAST:%.*]], %success ], [ null, %entry ]
sil @c_cast_to_class_existential_mixed : $@convention(thin) (@owned AnyObject) -> @owned protocol<CP, OP, CP2> {
entry(%a : $AnyObject):
  checked_cast_br %a : $AnyObject to $protocol<CP, OP, CP2>, yea, nay
yea(%p : $protocol<CP, OP, CP2>):
  return %p : $protocol<CP, OP, CP2>
nay:
  unreachable
}

// CHECK-LABEL: define { %swift.type*, i8**, i8** } @c_cast_to_existential_metatype_mixed(%swift.type*)
// CHECK:         [[OBJC_CAST:%.*]] = call %swift.type* @swift_dynamicCastTypeToObjCProtocolConditional(%swift.type* %0, {{(i32|i64)}} 1, i8** {{%.*}})
// CHECK:         [[IS_NULL:%.*]] = icmp eq %swift.type* [[OBJC_CAST]], null
// CHECK:         br i1 [[IS_NULL]], label %cont, label %success
// CHECK:       success:
// CHECK:         call { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* {{.*}}, %swift.type* %0, %swift.protocol* @_TMp5casts2CP, %swift.protocol* @_TMp5casts3CP2)
sil @c_cast_to_existential_metatype_mixed : $@convention(thin) (@owned @thick Any.Type) -> @owned @thick protocol<CP, OP, CP2>.Type {
entry(%a : $@thick Any.Type):
  checked_cast_br %a : $@thick Any.Type to $@thick protocol<CP, OP, CP2>.Type, yea, nay
yea(%p : $@thick protocol<CP, OP, CP2>.Type):
  return %p : $@thick protocol<CP, OP, CP2>.Type
nay:
  unreachable
}

// CHECK-LABEL: define %objc_object* @checked_upcast(%C5casts1A*) {{.*}} {
// -- Don't need to check conformance of an object to AnyObject.
// CHECK-NOT:     call %objc_object* @swift_dynamicCastObjCProtocolConditional
// CHECK:         phi %objc_object*
sil @checked_upcast : $@convention(thin) (@owned A) -> @owned AnyObject {
entry(%a : $A):
  checked_cast_br %a : $A to $AnyObject, yea, nay
yea(%o : $AnyObject):
  return %o : $AnyObject
nay:
  unreachable
}

// CHECK-LABEL: define %C5casts1A* @checked_downcast_optional({{(i32|i64)}}) {{.*}} {
// CHECK:         [[OBJ_PTR:%.*]] = inttoptr {{(i32|i64)}} %0 to i8*
// CHECK:         [[METADATA:%.*]] = call %swift.type* @_TMaC5casts1A()
// CHECK:         [[METADATA_PTR:%.*]] = bitcast %swift.type* [[METADATA]] to i8*
// CHECK:         [[RESULT_PTR:%.*]] = call i8* @swift_dynamicCastClass(i8* [[OBJ_PTR]], i8* [[METADATA_PTR]])
// CHECK:         [[RESULT:%.*]] = bitcast i8* [[RESULT_PTR]] to %C5casts1A*
// CHECK:         [[COND:%.*]] = icmp ne %C5casts1A* [[RESULT]], null
// CHECK:         br i1 [[COND]]
sil @checked_downcast_optional : $@convention(thin) (Optional<A>) -> @owned A {
entry(%a : $Optional<A>):
  checked_cast_br %a : $Optional<A> to $A, yea, nay
yea(%aa : $A):
  return %aa : $A
nay:
  unreachable
}

// CHECK-LABEL: define void @checked_metatype_to_object_casts
sil @checked_metatype_to_object_casts : $@convention(thin) <T> (@thick Any.Type) -> () {
entry(%e : $@thick Any.Type):
  %a = metatype $@thin NotClass.Type
  // CHECK: br i1 false
  checked_cast_br %a : $@thin NotClass.Type to $AnyObject, a_yea, a_nay
a_yea(%1 : $AnyObject):
  %b = metatype $@thick A.Type
  // CHECK: bitcast %swift.type* {{%.*}} to %objc_object*
  checked_cast_br %b : $@thick A.Type to $AnyObject, b_yea, b_nay
b_yea(%2 : $AnyObject):
  %c = metatype $@objc_metatype A.Type
  // CHECK: bitcast %objc_class* {{%.*}} to %objc_object*
  checked_cast_br %c : $@objc_metatype A.Type to $AnyObject, c_yea, c_nay
c_yea(%3 : $AnyObject):
  %d = metatype $@thick T.Type
  // CHECK: call %objc_object* @swift_dynamicCastMetatypeToObjectConditional(%swift.type* %T)
  checked_cast_br %d : $@thick T.Type to $AnyObject, d_yea, d_nay
d_yea(%4 : $AnyObject):
  // CHECK: call %objc_object* @swift_dynamicCastMetatypeToObjectConditional(%swift.type* %0)
  checked_cast_br %e : $@thick Any.Type to $AnyObject, e_yea, e_nay
e_yea(%5 : $AnyObject):
  return undef : $()
a_nay:
  unreachable
b_nay:
  unreachable
c_nay:
  unreachable
d_nay:
  unreachable
e_nay:
  unreachable
}

@objc class OA {}
sil_vtable OA {}
sil hidden @_TToFC5casts2OAcfT_S0_ : $@convention(thin) (OA) -> OA {
entry(%x : $OA):
  return %x : $OA
}

@objc class OB {}
sil_vtable OB {}
sil hidden_external @_TToFC5casts2OBcfT_S0_ : $@convention(thin) (OB) -> OB {
entry(%x : $OB):
  return %x : $OB
}

// CHECK-LABEL: define %C5casts1B* @checked_object_to_object_casts(%C5casts1A*)
// CHECK:         @swift_dynamicCastClassUnconditional
sil @checked_object_to_object_casts : $@convention(thin) (A) -> B {
entry(%a : $A):
  %b = unconditional_checked_cast %a : $A to $B
  return %b : $B
}

// CHECK-LABEL: define %C5casts2OB* @checked_objc_object_to_object_casts(%C5casts2OA*)
// CHECK:         @swift_dynamicCastClassUnconditional
sil @checked_objc_object_to_object_casts : $@convention(thin) (OA) -> OB {
entry(%a : $OA):
  %b = unconditional_checked_cast %a : $OA to $OB
  return %b : $OB
}
back to top