blob: d1ad2212f99ba541408d7c29ea013afc5d41b824 [file] [log] [blame]
// RUN: %target-sil-opt -enable-sil-verify-all -mandatory-combine -sil-mandatory-combine-enable-canon-and-simple-dce -semantic-arc-opts %s | %FileCheck %s
// Make sure that we can perform all of these RAUW without producing ARC traffic
// that semantic arc opts can't eliminate.
sil_stage canonical
import Builtin
// Trivial declarations
struct MyInt {
var value: Builtin.Int64
}
// Generic declarations
protocol Addable {
static var an: Self { get }
}
// Class declarations
class Klass {
init()
deinit
}
class SubKlass : Klass {}
sil @use_klass_unowned : $@convention(thin) (Klass) -> ()
// Existential declarations
protocol Proto {
static var an: Proto { get }
}
// Trivial support
sil @first_of_three_ints : $@convention(thin) (MyInt, MyInt, MyInt) -> MyInt
sil @constant_zero : $@convention(thin) () -> MyInt
sil @identity_int : $@convention(thin) (MyInt) -> MyInt
// Generic support
sil @first_of_three_addables : $@convention(thin) <A where A : Addable> (@in_guaranteed A, @guaranteed _0_0 where τ_0_0 : Addable> { var τ_0_0 } <A>, @guaranteed _0_0 where τ_0_0 : Addable> { var τ_0_0 } <A>) -> @
out A
// Class support
sil [exact_self_class] @klass_alloc_init : $@convention(method) (@thick Klass.Type) -> @owned Klass
// Klass.init()
sil @klass_init : $@convention(method) (@owned Klass) -> @owned Klass
// Klass.deinit
sil @klass_deinit : $@convention(method) (@guaranteed Klass) -> @owned Builtin.NativeObject
// Klass.__deallocating_deinit
sil @klass_dealloc_deinit : $@convention(method) (@owned Klass) -> ()
sil_vtable Klass {
#Klass.init!allocator: (Klass.Type) -> () -> Klass : @klass_alloc_init
#Klass.deinit!deallocator: @klass_dealloc_deinit
}
sil @first_of_three_klasses : $@convention(thin) (@guaranteed Klass, @guaranteed Klass, @guaranteed Klass) -> @owned Klass
sil @use_klass_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
// Existential support
sil @first_of_three_protos : $@convention(thin) (@in_guaranteed Proto, @guaranteed { var Proto }, @guaranteed { var Proto }) -> @out Proto
sil @get_proto : $@convention(thin) () -> @out Proto
// Mixed support
sil @proto_from_proto_and_myint : $@convention(thin) (@in_guaranteed Proto, MyInt) -> @out Proto
sil @myint_from_myint_and_proto : $@convention(thin) (MyInt, @guaranteed { var Proto }) -> MyInt
sil @myint_from_proto_and_myint : $@convention(thin) (@guaranteed { var Proto }, MyInt) -> MyInt
// Enum support
enum FakeOptional<T> {
case none
case some(T)
}
sil @use_fakeoptional_klass_guaranteed : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
///////////
// Tests //
///////////
//===---
// None Tests
//
// CHECK-LABEL: sil [ossa] @none_to_none_rauw : $@convention(thin) (MyInt) -> MyInt {
// CHECK: bb0
// CHECK: return %0
// CHECK: } // end sil function 'none_to_none_rauw'
sil [ossa] @none_to_none_rauw : $@convention(thin) (MyInt) -> MyInt {
bb0(%0 : $MyInt):
%1 = unchecked_bitwise_cast %0 : $MyInt to $Builtin.Int64
%2 = unchecked_bitwise_cast %1 : $Builtin.Int64 to $MyInt
return %2 : $MyInt
}
// We do not support replacing .none with non-trivial ownerships. This can only
// occur with enum cases without payloads or with trivial payload. That requires
// more infrastructure than we have currently.
//===---
// Owned Tests
//
// CHECK-LABEL: sil [ossa] @owned_to_owned_rauw : $@convention(thin) (@owned Klass) -> @owned Klass {
// CHECK: bb0(
// CHECK-NEXT: return
// CHECK: } // end sil function 'owned_to_owned_rauw'
sil [ossa] @owned_to_owned_rauw : $@convention(thin) (@owned Klass) -> @owned Klass {
bb0(%0 : @owned $Klass):
%1 = unchecked_ref_cast %0 : $Klass to $SubKlass
%2 = upcast %1 : $SubKlass to $Klass
return %2 : $Klass
}
// We get ARC traffic here today since we do not get rid of PhiArguments kept
// alive only by destroys/end_borrows. We will eventually though.
//
// CHECK-LABEL: sil [ossa] @owned_to_owned_consuming : $@convention(thin) (@owned FakeOptional<Klass>) -> () {
// CHECK: copy_value
// CHECK-NOT: enum $FakeOptional<Klass>, #FakeOptional.some!enumelt
// CHECK: } // end sil function 'owned_to_owned_consuming'
sil [ossa] @owned_to_owned_consuming : $@convention(thin) (@owned FakeOptional<Klass>) -> () {
bb0(%0 : @owned $FakeOptional<Klass>):
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some: bb1, case #FakeOptional.none: bb2
bb1(%0a : @owned $Klass):
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0a : $Klass
br bb3(%1 : $FakeOptional<Klass>)
bb2:
%3 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%3 : $FakeOptional<Klass>)
bb3(%4 : @owned $FakeOptional<Klass>):
destroy_value %4 : $FakeOptional<Klass>
%9999 = tuple()
return %9999 : $()
}
//===---
// Unowned Tests
//
// CHECK-LABEL: sil [ossa] @unowned_to_owned_rauw : $@convention(thin) (@owned Klass) -> @owned Klass {
// CHECK: bb0(
// CHECK-NEXT: return
// CHECK: } // end sil function 'unowned_to_owned_rauw'
sil [ossa] @unowned_to_owned_rauw : $@convention(thin) (@owned Klass) -> @owned Klass {
bb0(%0 : @owned $Klass):
%1 = unchecked_bitwise_cast %0 : $Klass to $SubKlass
%2 = unchecked_bitwise_cast %1 : $SubKlass to $Klass
%3 = copy_value %2 : $Klass
destroy_value %0 : $Klass
return %3 : $Klass
}
// CHECK-LABEL: sil [ossa] @unowned_to_owned_rauw_loop : $@convention(thin) (@owned Klass) -> @owned FakeOptional<Klass> {
// CHECK: bb0([[ARG:%.*]] : @owned $Klass):
// CHECK-NOT: unchecked_bitwise_cast
// CHECK-NOT: copy_value
// CHECK-NOT: destroy_value
//
// CHECK: bb2:
// CHECK-NEXT: [[COPY:%.*]] = copy_value [[ARG]]
// CHECK-NEXT: cond_br undef, bb3, bb4
//
// CHECK: bb3:
// CHECK-NEXT: destroy_value [[COPY]]
// CHECK-NEXT: br bb2
//
// CHECK: bb4:
// CHECK-NEXT: [[ENUM_SOME_RESULT:%.*]] = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, [[COPY]]
// CHECK-NEXT: br bb6([[ENUM_SOME_RESULT]] : $FakeOptional<Klass>)
//
// CHECK: bb5:
// CHECK-NEXT: [[ENUM_NONE_RESULT:%.*]] = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
// CHECK-NEXT: br bb6([[ENUM_NONE_RESULT]] :
//
// CHECK: bb6([[RESULT:%.*]] : @owned $FakeOptional<Klass>):
// CHECK-NEXT: destroy_value [[ARG]]
// CHECK-NEXT: return [[RESULT]]
// CHECK: } // end sil function 'unowned_to_owned_rauw_loop'
sil [ossa] @unowned_to_owned_rauw_loop : $@convention(thin) (@owned Klass) -> @owned FakeOptional<Klass> {
bb0(%0 : @owned $Klass):
cond_br undef, bbLoopPreHeader, bbEarlyExit
bbLoopPreHeader:
br bbLoopHeader
bbLoopHeader:
%1 = unchecked_bitwise_cast %0 : $Klass to $SubKlass
%2 = unchecked_bitwise_cast %1 : $SubKlass to $Klass
%3 = copy_value %2 : $Klass
cond_br undef, bbBackEdge, bbExitingBlock
bbBackEdge:
destroy_value %3 : $Klass
br bbLoopHeader
bbExitingBlock:
%4 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %3 : $Klass
br bbExitBlock(%4 : $FakeOptional<Klass>)
bbEarlyExit:
%5 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bbExitBlock(%5 : $FakeOptional<Klass>)
bbExitBlock(%result : @owned $FakeOptional<Klass>):
destroy_value %0 : $Klass
return %result : $FakeOptional<Klass>
}
// CHECK-LABEL: sil [ossa] @unowned_to_guaranteed_rauw : $@convention(thin) (@guaranteed Klass) -> @owned Klass {
// CHECK: bb0(
// CHECK-NEXT: copy_value
// CHECK-NEXT: return
// CHECK: } // end sil function 'unowned_to_guaranteed_rauw'
sil [ossa] @unowned_to_guaranteed_rauw : $@convention(thin) (@guaranteed Klass) -> @owned Klass {
bb0(%0 : @guaranteed $Klass):
%1 = unchecked_bitwise_cast %0 : $Klass to $SubKlass
%2 = unchecked_bitwise_cast %1 : $SubKlass to $Klass
%3 = copy_value %2 : $Klass
return %3 : $Klass
}
// CHECK-LABEL: sil [ossa] @unowned_to_guaranteed_rauw_loop : $@convention(thin) (@guaranteed Klass) -> @owned FakeOptional<Klass> {
// CHECK: bb0([[ARG:%.*]] : @guaranteed $Klass):
// CHECK-NOT: unchecked_bitwise_cast
// CHECK-NOT: copy_value
// CHECK-NOT: destroy_value
//
// CHECK: bb2:
// CHECK-NEXT: [[COPY:%.*]] = copy_value [[ARG]]
// CHECK-NEXT: cond_br undef, bb3, bb4
//
// CHECK: bb3:
// CHECK-NEXT: destroy_value [[COPY]]
// CHECK-NEXT: br bb2
//
// CHECK: bb4:
// CHECK-NEXT: [[ENUM_SOME_RESULT:%.*]] = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, [[COPY]]
// CHECK-NEXT: br bb6([[ENUM_SOME_RESULT]] : $FakeOptional<Klass>)
//
// CHECK: bb5:
// CHECK-NEXT: [[ENUM_NONE_RESULT:%.*]] = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt // user: %10
// CHECK-NEXT: br bb6([[ENUM_NONE_RESULT]] :
//
// CHECK: bb6([[RESULT:%.*]] : @owned $FakeOptional<Klass>):
// CHECK-NEXT: return [[RESULT]]
// CHECK: } // end sil function 'unowned_to_guaranteed_rauw_loop'
sil [ossa] @unowned_to_guaranteed_rauw_loop : $@convention(thin) (@guaranteed Klass) -> @owned FakeOptional<Klass> {
bb0(%0 : @guaranteed $Klass):
cond_br undef, bbLoopPreHeader, bbEarlyExit
bbLoopPreHeader:
br bbLoopHeader
bbLoopHeader:
%1 = unchecked_bitwise_cast %0 : $Klass to $SubKlass
%2 = unchecked_bitwise_cast %1 : $SubKlass to $Klass
%3 = copy_value %2 : $Klass
cond_br undef, bbBackEdge, bbExitingBlock
bbBackEdge:
destroy_value %3 : $Klass
br bbLoopHeader
bbExitingBlock:
%4 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %3 : $Klass
br bbExitBlock(%4 : $FakeOptional<Klass>)
bbEarlyExit:
%5 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bbExitBlock(%5 : $FakeOptional<Klass>)
bbExitBlock(%result : @owned $FakeOptional<Klass>):
return %result : $FakeOptional<Klass>
}
// CHECK-LABEL: sil [ossa] @unowned_to_guaranteed_rauw_2 : $@convention(thin) (@guaranteed Klass) -> (Klass, Klass) {
// CHECK: bb0(
// CHECK-NEXT: unchecked_ownership_conversion
// CHECK-NEXT: tuple
// CHECK-NEXT: return
// CHECK: } // end sil function 'unowned_to_guaranteed_rauw_2'
sil [ossa] @unowned_to_guaranteed_rauw_2 : $@convention(thin) (@guaranteed Klass) -> (Klass, Klass) {
bb0(%0 : @guaranteed $Klass):
%1 = unchecked_bitwise_cast %0 : $Klass to $SubKlass
%2 = unchecked_bitwise_cast %1 : $SubKlass to $Klass
%3 = tuple(%2 : $Klass, %2 : $Klass)
return %3 : $(Klass, Klass)
}
// CHECK-LABEL: sil [ossa] @unowned_to_guaranteed_rauw_2_loop : $@convention(thin) (@guaranteed Klass) -> @owned FakeOptional<(Klass, Klass)> {
// CHECK: bb0([[ARG:%.*]] : @guaranteed $Klass):
// CHECK-NOT: unchecked_bitwise_cast
// CHECK-NOT: copy_value
// CHECK-NOT: destroy_value
//
// CHECK: bb2:
// CHECK-NEXT: [[ARG_CONVERT:%.*]] = unchecked_ownership_conversion [[ARG]]
// CHECK-NEXT: [[TUP:%.*]] = tuple ([[ARG_CONVERT]] : $Klass, [[ARG_CONVERT]] : $Klass)
// CHECK-NEXT: [[COPY:%.*]] = copy_value [[TUP]]
// CHECK-NEXT: cond_br undef, bb3, bb4
//
// CHECK: bb3:
// CHECK-NEXT: destroy_value [[COPY]]
// CHECK-NEXT: br bb2
//
// CHECK: bb4:
// CHECK-NEXT: [[ENUM_SOME_RESULT:%.*]] = enum $FakeOptional<{{.*}}>, #FakeOptional.some!enumelt, [[COPY]]
// CHECK-NEXT: br bb6([[ENUM_SOME_RESULT]] : $FakeOptional<{{.*}}>)
//
// CHECK: bb5:
// CHECK-NEXT: [[ENUM_NONE_RESULT:%.*]] = enum $FakeOptional<{{.*}}>, #FakeOptional.none!enumelt
// CHECK-NEXT: br bb6([[ENUM_NONE_RESULT]] :
//
// CHECK: bb6([[RESULT:%.*]] : @owned $FakeOptional<{{.*}}>):
// CHECK-NEXT: return [[RESULT]]
// CHECK: } // end sil function 'unowned_to_guaranteed_rauw_2_loop'
sil [ossa] @unowned_to_guaranteed_rauw_2_loop : $@convention(thin) (@guaranteed Klass) -> @owned FakeOptional<(Klass, Klass)> {
bb0(%0 : @guaranteed $Klass):
cond_br undef, bbLoopPreHeader, bbEarlyExit
bbLoopPreHeader:
br bbLoopHeader
bbLoopHeader:
%1 = unchecked_bitwise_cast %0 : $Klass to $SubKlass
%2 = unchecked_bitwise_cast %1 : $SubKlass to $Klass
%3 = tuple(%2 : $Klass, %2 : $Klass)
%4 = copy_value %3 : $(Klass, Klass)
cond_br undef, bbBackEdge, bbExitingBlock
bbBackEdge:
destroy_value %4 : $(Klass, Klass)
br bbLoopHeader
bbExitingBlock:
%5 = enum $FakeOptional<(Klass, Klass)>, #FakeOptional.some!enumelt, %4 : $(Klass, Klass)
br bbExitBlock(%5 : $FakeOptional<(Klass, Klass)>)
bbEarlyExit:
%6 = enum $FakeOptional<(Klass, Klass)>, #FakeOptional.none!enumelt
br bbExitBlock(%6 : $FakeOptional<(Klass, Klass)>)
bbExitBlock(%result : @owned $FakeOptional<(Klass, Klass)>):
return %result : $FakeOptional<(Klass, Klass)>
}
// CHECK-LABEL: sil [ossa] @unowned_to_guaranteed_rauw_3 : $@convention(thin) (@guaranteed Klass) -> Klass {
// CHECK: bb0(
// CHECK-NEXT: unchecked_ownership_conversion
// CHECK-NEXT: return
// CHECK: } // end sil function 'unowned_to_guaranteed_rauw_3'
sil [ossa] @unowned_to_guaranteed_rauw_3 : $@convention(thin) (@guaranteed Klass) -> Klass {
bb0(%0 : @guaranteed $Klass):
%1 = unchecked_bitwise_cast %0 : $Klass to $SubKlass
%2 = unchecked_bitwise_cast %1 : $SubKlass to $Klass
return %2 : $Klass
}
//===---
// Guaranteed Tests
//
// CHECK-LABEL: sil [ossa] @guaranteed_to_guaranteed : $@convention(thin) (@guaranteed Klass) -> () {
// CHECK-NOT: unchecked_ref_cast
// CHECK: } // end sil function 'guaranteed_to_guaranteed'
sil [ossa] @guaranteed_to_guaranteed : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
%1 = unchecked_ref_cast %0 : $Klass to $SubKlass
%2 = unchecked_ref_cast %1 : $SubKlass to $Klass
%f = function_ref @use_klass_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
apply %f(%2) : $@convention(thin) (@guaranteed Klass) -> ()
%9999 = tuple()
return %9999 : $()
}
// We should have no ARC traffic despite having a loop here.
//
// CHECK-LABEL: sil [ossa] @guaranteed_to_guaranteed_loop : $@convention(thin) (@guaranteed Klass) -> () {
// CHECK-NOT: unchecked_ref_cast
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'guaranteed_to_guaranteed_loop'
sil [ossa] @guaranteed_to_guaranteed_loop : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
cond_br undef, bb1, bbSkipLoop
bb1:
br bb1a
bb1a:
br bb2
bb2:
%1 = unchecked_ref_cast %0 : $Klass to $SubKlass
%2 = unchecked_ref_cast %1 : $SubKlass to $Klass
%f = function_ref @use_klass_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
apply %f(%2) : $@convention(thin) (@guaranteed Klass) -> ()
cond_br undef, bbBackEdge, bbExitingBlock
bbBackEdge:
br bb1a
bbSkipLoop:
br bbExit
bbExitingBlock:
br bbExit
bbExit:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @guaranteed_to_unowned : $@convention(thin) (@guaranteed Klass) -> () {
// CHECK-NOT: unchecked_ref_cast
// CHECK: } // end sil function 'guaranteed_to_unowned'
sil [ossa] @guaranteed_to_unowned : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
%1 = unchecked_ref_cast %0 : $Klass to $SubKlass
%2 = unchecked_ref_cast %1 : $SubKlass to $Klass
%f = function_ref @use_klass_unowned : $@convention(thin) (Klass) -> ()
apply %f(%2) : $@convention(thin) (Klass) -> ()
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @guaranteed_to_unowned_loop : $@convention(thin) (@guaranteed Klass) -> () {
// CHECK-NOT: unchecked_ref_cast
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'guaranteed_to_unowned_loop'
sil [ossa] @guaranteed_to_unowned_loop : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
cond_br undef, bb1, bbSkipLoop
bb1:
br bb1a
bb1a:
br bb2
bb2:
%1 = unchecked_ref_cast %0 : $Klass to $SubKlass
%2 = unchecked_ref_cast %1 : $SubKlass to $Klass
%f = function_ref @use_klass_unowned : $@convention(thin) (Klass) -> ()
apply %f(%2) : $@convention(thin) (Klass) -> ()
cond_br undef, bbBackEdge, bbExitingBlock
bbBackEdge:
br bb1a
bbSkipLoop:
br bbExit
bbExitingBlock:
br bbExit
bbExit:
%9999 = tuple()
return %9999 : $()
}
// Lifetime extend borrow to %3 and insert a copy.
//
// We should have no copies in this function when we are done.
//
// Just make sure we eliminated the FakeOptional.some.
//
// CHECK-LABEL: sil [ossa] @guaranteed_to_owned_consuming : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
// CHECK-NOT: enum $FakeOptional<Klass>, #FakeOptional.some!enumelt
// CHECK-NOT: copy_value
// CHECK-NOT: destroy_value
// CHECK: } // end sil function 'guaranteed_to_owned_consuming'
sil [ossa] @guaranteed_to_owned_consuming : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Klass>):
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some: bb1, case #FakeOptional.none: bb2
bb1(%0a : @guaranteed $Klass):
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0a : $Klass
%2 = copy_value %1 : $FakeOptional<Klass>
br bb3(%2 : $FakeOptional<Klass>)
bb2:
%3 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%3 : $FakeOptional<Klass>)
bb3(%4 : @owned $FakeOptional<Klass>):
destroy_value %4 : $FakeOptional<Klass>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @guaranteed_to_owned_consuming_loop : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
// CHECK-NOT: enum $FakeOptional<Klass>, #FakeOptional.some!enumelt
// CHECK-NOT: copy_value
// CHECK-NOT: destroy_value
// CHECK: } // end sil function 'guaranteed_to_owned_consuming_loop'
sil [ossa] @guaranteed_to_owned_consuming_loop : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Klass>):
cond_br undef, bbPreLoopHeader, bbEarlyExit
bbPreLoopHeader:
br bbLoopHeader
bbLoopHeader:
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some: bb1, case #FakeOptional.none: bb2
bb1(%0a : @guaranteed $Klass):
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0a : $Klass
%2 = copy_value %1 : $FakeOptional<Klass>
br bb3(%2 : $FakeOptional<Klass>)
bb2:
%3 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%3 : $FakeOptional<Klass>)
bb3(%4 : @owned $FakeOptional<Klass>):
destroy_value %4 : $FakeOptional<Klass>
cond_br undef, bbBackEdge, bbLoopExitingBlock
bbBackEdge:
br bbLoopHeader
bbLoopExitingBlock:
br bbExit
bbEarlyExit:
br bbExit
bbExit:
%9999 = tuple()
return %9999 : $()
}
// For the normal check, make sure we performed the optimization. In this case
// it means eliminating the enum instruction in bb1.
//
// Then after cleaning up show that we do not have any copy_value or
// begin_borrows left.
//
// CHECK-LABEL: sil [ossa] @guaranteed_to_guaranteed_consuming : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
// CHECK-NOT: copy_value
// CHECK: begin_borrow
// CHECK-NOT: enum $FakeOptional<Klass>, #FakeOptional.some!enumelt
// CHECK: } // end sil function 'guaranteed_to_guaranteed_consuming'
//
// We eliminate all begin borrows from this example with semantic-arc.
sil [ossa] @guaranteed_to_guaranteed_consuming : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Klass>):
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some: bb1, case #FakeOptional.none: bb2
bb1(%0a : @guaranteed $Klass):
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0a : $Klass
%2 = begin_borrow %1 : $FakeOptional<Klass>
br bb3(%2 : $FakeOptional<Klass>)
bb2:
%3 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%3 : $FakeOptional<Klass>)
bb3(%4 : @guaranteed $FakeOptional<Klass>):
end_borrow %4 : $FakeOptional<Klass>
%9999 = tuple()
return %9999 : $()
}
// Make sure we performed the optimization.
//
// CHECK-LABEL: sil [ossa] @guaranteed_to_guaranteed_non_consuming_deadend : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
// CHECK-NOT: copy_value
// CHECK-NOT: begin_borrow
// CHECK-NOT: enum $FakeOptional<Klass>, #FakeOptional.some!enumelt
// CHECK: } // end sil function 'guaranteed_to_guaranteed_non_consuming_deadend'
sil [ossa] @guaranteed_to_guaranteed_non_consuming_deadend : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Klass>):
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some: bb1, case #FakeOptional.none: bb2
bb1(%0a : @guaranteed $Klass):
// We are going to replace %1 with %0.
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0a : $Klass
%f2 = function_ref @use_fakeoptional_klass_guaranteed : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
apply %f2(%1) : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
unreachable
bb2:
%3 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
%f = function_ref @use_fakeoptional_klass_guaranteed : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
apply %f(%3) : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
unreachable
}
// In this example we are replacing %1 with %0 inserting fix up copies. Make
// sure that we do not end up with any arc traffic!
//
// Make sure we actually eliminated the FakeOptional.some in bb1. We are
// replacing it with %0.
//
// CHECK-LABEL: sil [ossa] @guaranteed_to_guaranteed_nonconsuming_2 : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
// CHECK-NOT: copy_value
// CHECK-NOT: enum $FakeOptional<Klass>, #FakeOptional.some!enumelt
// CHECK-NOT: begin_borrow
// CHECK: } // end sil function 'guaranteed_to_guaranteed_nonconsuming_2'
sil [ossa] @guaranteed_to_guaranteed_nonconsuming_2 : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Klass>):
switch_enum %0 : $FakeOptional<Klass>, case #FakeOptional.some: bb1, case #FakeOptional.none: bb2
bb1(%0a : @guaranteed $Klass):
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0a : $Klass
%f2 = function_ref @use_fakeoptional_klass_guaranteed : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
apply %f2(%1) : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
br bb3
bb2:
%3 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
%f = function_ref @use_fakeoptional_klass_guaranteed : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
apply %f(%3) : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// We do eliminate the copy_value here, but we do not eliminate the begin_borrow
// since we do not in semantic arc opts eliminate args kept alive just by
// borrows.
//
// CHECK-LABEL: sil [ossa] @guaranteed_copy_rauw_owned : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
// CHECK-NOT: copy_value
// CHECK: begin_borrow
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'guaranteed_copy_rauw_owned'
sil [ossa] @guaranteed_copy_rauw_owned : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Klass>):
%0c = copy_value %0 : $FakeOptional<Klass>
switch_enum %0c : $FakeOptional<Klass>, case #FakeOptional.some: bb1, case #FakeOptional.none: bb2
bb1(%0a : @owned $Klass):
%1 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0a : $Klass
br bb3(%1 : $FakeOptional<Klass>)
bb2:
%3 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%3 : $FakeOptional<Klass>)
bb3(%4 : @owned $FakeOptional<Klass>):
destroy_value %4 : $FakeOptional<Klass>
%9999 = tuple()
return %9999 : $()
}