Files
swift-mirror/test/SILOptimizer/simplify_cfg_checkcast.sil
2024-07-06 13:28:07 +02:00

745 lines
27 KiB
Plaintext

// RUN: %target-sil-opt -enable-sil-verify-all %s -update-borrowed-from -jumpthread-simplify-cfg
// RUN: %target-sil-opt -enable-sil-verify-all %s -update-borrowed-from -jumpthread-simplify-cfg -debug-only=sil-simplify-cfg
//
// REQUIRES: asserts
// FIXME: which of these tests actually require -jumpthread-simplify-cfg instead of -simplify-cfg?
// FIXME_rauw: revisit these fixme's after the OwnershipRAUW utility is rewritten in terms of OwnershipLiveness.
sil_stage canonical
import Builtin
import Swift
class Klass {
var a: Int
deinit
init()
}
protocol OtherKlass : AnyObject {}
sil [ossa] @consume_klass : $@convention(thin) (@owned Klass) -> ()
sil [ossa] @get_klass : $@convention(thin) () -> @owned Klass
sil [ossa] @unknown : $@convention(thin) () -> ()
struct KlassWrapper {
var k: Klass
}
class Base {
@inline(never) func inner()
func middle()
func outer()
}
class Derived : Base {
override func inner()
@inline(never) final override func middle()
}
class Final : Derived {
}
sil [ossa] @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
sil [ossa] @_TFC3ccb4Base6middlefS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
sil @get_base : $@convention(thin) () -> @owned Base
// TODO-CHECK-LABEL: sil [ossa] @redundant_checked_cast_br
sil [ossa] @redundant_checked_cast_br : $@convention(method) (@guaranteed Base) -> () {
bb0(%0 : @guaranteed $Base):
// TODO-CHECK: [[METHOD:%.*]] = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%1 = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: checked_cast_br [exact] Base in %0 : $Base to Base, [[SUCCESS:bb[0-9]+]], [[FAIL:bb[0-9]+]]
checked_cast_br [exact] Base in %0 : $Base to Base, bb2, bb7
// TODO-CHECK: bb1
bb1:
%3 = tuple ()
return %3 : $()
bb2(%5 : @guaranteed $Base):
// TODO-CHECK: [[SUCCESS]]
%7 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK-NOT: checked_cast_br
checked_cast_br [exact] Base in %0 : $Base to Base, bb3, bb5
// TODO-CHECK: [[INNER:%.*]] = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: apply [[INNER]]
// TODO-CHECK: br bb1
bb3(%9 : @guaranteed $Base):
// TODO-CHECK: [[FAIL]]
// TODO-CHECK-NOT: function-ref
// TODO-CHECK: apply [[METHOD]]
%10 = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
%11 = apply %10(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb4:
%13 = tuple ()
br bb6(%13 : $())
bb5(%defaultBB2 : @guaranteed $Base):
%15 = apply %7(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb6(%17 : $()):
br bb1
bb7(%defaultBB0 : @guaranteed $Base):
%19 = apply %1(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb1
}
// TODO-CHECK-LABEL: sil [ossa] @redundant_checked_cast_br_owned
sil [ossa] @redundant_checked_cast_br_owned : $@convention(method) (@guaranteed Base) -> () {
// TODO-CHECK: [[COPY:%.*]] = copy_value %0
// TODO-CHECK: [[METHOD:%.*]] = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: checked_cast_br [exact] Base in [[COPY]] : $Base to Base, [[SUCCESS:bb[0-9]+]], [[FAIL:bb[0-9]+]]
bb0(%0 : @guaranteed $Base):
%copy = copy_value %0 : $Base
%1 = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
checked_cast_br [exact] Base in %copy : $Base to Base, bb2, bb7
// TODO-CHECK: bb1
bb1:
%3 = tuple ()
return %3 : $()
// TODO-CHECK: [[SUCCESS]]([[SUCCESSARG:%.*]] : @owned $Base)
// TODO-CHECK-NOT: checked_cast_br
//
// FIXME_rauw: RAUW should not create this copy!
// TODO-CHECK: [[SUCCESSCOPY:%.*]] = copy_value [[SUCCESSARG]] : $Base
// TODO-CHECK: [[INNER:%.*]] = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: apply [[INNER]]([[SUCCESSCOPY]])
// TODO-CHECK: br bb1
bb2(%5 : @owned $Base):
%7 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
checked_cast_br [exact] Base in %5 : $Base to Base, bb3, bb5
// TODO-CHECK: [[FAIL]]([[FAILARG:%.*]] : @owned $Base)
// TODO-CHECK-NOT: function-ref
// TODO-CHECK: apply [[METHOD]]([[FAILARG]])
bb3(%9 : @owned $Base):
%10 = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
%11 = apply %10(%9) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %9 : $Base
br bb4
bb4:
%13 = tuple ()
br bb6(%13 : $())
bb5(%defaultBB2 : @owned $Base):
%15 = apply %7(%defaultBB2) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %defaultBB2 : $Base
br bb4
bb6(%17 : $()):
br bb1
bb7(%defaultBB0 : @owned $Base):
%19 = apply %1(%defaultBB0) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %defaultBB0 : $Base
br bb1
}
// TODO-CHECK-LABEL: sil [ossa] @not_redundant_checked_cast_br : $@convention(method) (@guaranteed Base) -> () {
sil [ossa] @not_redundant_checked_cast_br : $@convention(method) (@guaranteed Base) -> () {
bb0(%0 : @guaranteed $Base):
// TODO-CHECK: [[METHOD:%.*]] = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%1 = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: checked_cast_br [exact] Base in %0 : $Base to Base, [[SUCCESS:bb[0-9]+]], [[FAIL:bb[0-9]+]]
checked_cast_br [exact] Base in %0 : $Base to Base, bb2, bb7
// TODO-CHECK: bb1:
// TODO-CHECK: tuple ()
// TODO-CHECK: return
bb1:
%3 = tuple ()
return %3 : $()
bb2(%5 : @guaranteed $Base):
// TODO-CHECK: [[SUCCESS]]
// TODO-CHECK: [[METHOD2:%.*]] = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%7 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%8 = apply %7(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb3(%9 : @guaranteed $Derived):
%10 = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
%11 = apply %10(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb4:
%13 = tuple ()
br bb6(%13 : $())
bb5(%9a : @guaranteed $Base):
%14 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%15 = apply %14(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb6(%17 : $()):
br bb1
bb7(%10a : @guaranteed $Base):
// TODO-CHECK: checked_cast_br [exact] Base in %0 : $Base to Derived
checked_cast_br [exact] Base in %0 : $Base to Derived, bb3, bb5
}
// TODO-CHECK-LABEL: sil [ossa] @failing_checked_cast_br
sil [ossa] @failing_checked_cast_br : $@convention(method) (@guaranteed Base) -> () {
bb0(%0 : @guaranteed $Base):
// TODO-CHECK: [[METHOD:%.*]] = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%1 = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: checked_cast_br [exact] Base in %0 : $Base to Base, [[SUCCESS:bb[0-9]+]], [[FAIL:bb[0-9]+]]
checked_cast_br [exact] Base in %0 : $Base to Base, bb2, bb7
// TODO-CHECK-LABEL: bb1
bb1:
%3 = tuple ()
return %3 : $()
bb2(%5 : @guaranteed $Base):
// TODO-CHECK: [[SUCCESS]]([[SUCCESSARG:%.*]] : @guaranteed $Base)
// TODO-CHECK: [[METHOD2:%.*]] = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%7 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK-NOT: checked_cast_br [exact] Base in %0 : $Base to Derived
// TODO-CHECK: apply [[METHOD2]]([[SUCCESSARG]])
// Check that checked_cast_br [exact] was replaced by a branch to the failure BB of the checked_cast_br.
// This is because bb2 is reached via the success branch of the checked_cast_br [exact] from bb0.
// It means that the exact dynamic type of %0 is $Base. Thus it cannot be $Derived.
// TODO-CHECK: br bb1
checked_cast_br [exact] Base in %5 : $Base to Derived, bb3, bb5
bb3(%9 : @guaranteed $Derived):
%10 = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
%11 = apply %10(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb4:
%13 = tuple ()
br bb6(%13 : $())
bb5(%9o : @guaranteed $Base):
%15 = apply %7(%9o) : $@convention(method) (@guaranteed Base) -> ()
br bb4
bb6(%17 : $()):
br bb1
bb7(%anotherDefaultPayload : @guaranteed $Base):
%19 = apply %1(%0) : $@convention(method) (@guaranteed Base) -> ()
br bb1
}
// TODO-CHECK-LABEL: sil [ossa] @failing_checked_cast_br_owned
sil [ossa] @failing_checked_cast_br_owned : $@convention(method) (@guaranteed Base) -> () {
// TODO-CHECK: [[COPY:%.*]] = copy_value %0
// TODO-CHECK: [[METHOD:%.*]] = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: checked_cast_br [exact] Base in [[COPY]] : $Base to Base, [[SUCCESS:bb[0-9]+]], [[FAIL:bb[0-9]+]]
bb0(%0 : @guaranteed $Base):
%copy = copy_value %0 : $Base
%1 = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
checked_cast_br [exact] Base in %copy : $Base to Base, bb2, bb7
// TODO-CHECK-LABEL: bb1
bb1:
%3 = tuple ()
return %3 : $()
// TODO-CHECK: [[SUCCESS]]([[SUCCESSARG:%.*]] : @owned $Base)
// TODO-CHECK: [[METHOD2:%.*]] = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK-NOT: checked_cast_br [exact] Base in %0 : $Base to Derived
// TODO-CHECK: apply [[METHOD2]]([[SUCCESSARG]])
// Check that checked_cast_br [exact] was replaced by a branch to the failure BB of the checked_cast_br.
// This is because bb2 is reached via the success branch of the checked_cast_br [exact] from bb0.
// It means that the exact dynamic type of %0 is $Base. Thus it cannot be $Derived.
// TODO-CHECK: br bb1
bb2(%5 : @owned $Base):
%7 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
checked_cast_br [exact] Base in %5 : $Base to Derived, bb3, bb5
bb3(%9 : @owned $Derived):
%upcast = upcast %9 : $Derived to $Base
%10 = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
%11 = apply %10(%upcast) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %upcast : $Base
br bb4
bb4:
%13 = tuple ()
br bb6(%13 : $())
bb5(%9o : @owned $Base):
%15 = apply %7(%9o) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %9o : $Base
br bb4
bb6(%17 : $()):
br bb1
bb7(%anotherDefaultPayload : @owned $Base):
%19 = apply %1(%0) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %anotherDefaultPayload : $Base
br bb1
}
sil [ossa] @unknown2 : $@convention(thin) () -> ()
// TODO-CHECK-LABEL: no_checked_cast_br_threading_with_alloc_ref_stack
// TODO-CHECK: checked_cast_br
// TODO-CHECK: apply
// TODO-CHECK: apply
// TODO-CHECK: checked_cast_br
// TODO-CHECK: apply
// TODO-CHECK: apply
// TODO-CHECK: return
sil [ossa] @no_checked_cast_br_threading_with_alloc_ref_stack : $@convention(method) (@guaranteed Base) -> () {
bb0(%0 : @guaranteed $Base):
%fu = function_ref @unknown : $@convention(thin) () -> ()
%fu2 = function_ref @unknown2 : $@convention(thin) () -> ()
checked_cast_br [exact] Base in %0 : $Base to Base, bb1, bb2
bb1(%1 : @guaranteed $Base):
apply %fu() : $@convention(thin) () -> ()
br bb3
bb2(%1a : @guaranteed $Base):
apply %fu2() : $@convention(thin) () -> ()
br bb3
bb3:
%a = alloc_ref [stack] $Base
checked_cast_br [exact] Base in %0 : $Base to Base, bb4, bb5
bb4(%2 : @guaranteed $Base):
apply %fu() : $@convention(thin) () -> ()
br bb6
bb5(%2a : @guaranteed $Base):
apply %fu2() : $@convention(thin) () -> ()
br bb6
bb6:
dealloc_ref %a : $Base
dealloc_stack_ref %a : $Base
%r = tuple()
return %r : $()
}
// Test a redundant checked_cast_br that has success, failure paths, and unknown paths.
//
// TODO: this is currently a bailout because the CFG transform can't handle it:
// (!SuccessPreds.empty() && !FailurePreds.empty() && numUnknownPreds > 0)
sil [ossa] @redundant_checked_cast_br_joined_success_fail_unknown : $@convention(method) (@guaranteed Base) -> () {
bb0(%0 : @guaranteed $Base):
%middle = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
checked_cast_br [exact] Base in %0 : $Base to Base, bb1, bb4
bb1(%successBB0 : @guaranteed $Base):
cond_br undef, bb2, bb3
bb2:
%successBB0call2 = apply %middle(%successBB0) : $@convention(method) (@guaranteed Base) -> ()
br bb8(%successBB0 : $Base)
bb3:
%successBB0call3 = apply %middle(%successBB0) : $@convention(method) (@guaranteed Base) -> ()
br bb7(%successBB0 : $Base)
bb4(%failBB0 : @guaranteed $Base):
cond_br undef, bb5, bb6
bb5:
%failBB0call5 = apply %middle(%failBB0) : $@convention(method) (@guaranteed Base) -> ()
br bb7(%failBB0 : $Base)
bb6:
%failBB0call6 = apply %middle(%failBB0) : $@convention(method) (@guaranteed Base) -> ()
br bb8(%failBB0 : $Base)
bb7(%unknown : @guaranteed $Base):
%unknownCall = apply %middle(%unknown) : $@convention(method) (@guaranteed Base) -> ()
br bb8(%unknown : $Base)
bb8(%joined : @guaranteed $Base):
%joinedCall = apply %middle(%joined) : $@convention(method) (@guaranteed Base) -> ()
checked_cast_br [exact] Base in %joined : $Base to Base, bb9, bb10
bb9(%successBB7 : @guaranteed $Base):
%successBB7call8 = apply %middle(%successBB7) : $@convention(method) (@guaranteed Base) -> ()
br bb11
bb10(%failBB7 : @guaranteed $Base):
%failBB7call8 = apply %middle(%failBB7) : $@convention(method) (@guaranteed Base) -> ()
br bb11
bb11:
%20 = tuple ()
return %20 : $()
}
// Verify that checked-cast jump-threading kicks in and generates verifiable SIL.
//
// TODO-CHECK-TRACE-LABEL: ### Run SimplifyCFG on $testCheckCastJumpThread
// TODO-CHECK-TRACE: Condition is the same if reached over {{.*}} parent @$testCheckCastJumpThread : $@convention(thin) (@guaranteed Klass) -> @owned any OtherKlass }
// TODO-CHECK-TRACE-NEXT: // %{{.*}} user:
// TODO-CHECK-TRACE-NEXT: bb1(%{{.*}} : @owned $any OtherKlass):
// TODO-CHECK-TRACE-NEXT: destroy_value
// TODO-CHECK-TRACE-NEXT: br bb5(%{{.*}} : $Klass)
sil shared [ossa] @$testCheckCastJumpThread : $@convention(thin) (@guaranteed Klass) -> @owned OtherKlass {
bb0(%0 : @guaranteed $Klass):
%1 = function_ref @get_klass : $@convention(thin) () -> @owned Klass
%2 = integer_literal $Builtin.Int64, 1
%3 = apply %1() : $@convention(thin) () -> @owned Klass
%4 = copy_value %3 : $Klass
checked_cast_br Klass in %3 : $Klass to OtherKlass, bb1, bb2
bb1(%5 : @owned $OtherKlass):
destroy_value %5 : $OtherKlass
%6 = integer_literal $Builtin.Int1, -1
br bb3(%6 : $Builtin.Int1)
bb2(%7 : @owned $Klass):
destroy_value %7 : $Klass
%8 = integer_literal $Builtin.Int1, 0
br bb3(%8 : $Builtin.Int1)
bb3(%10 : $Builtin.Int1):
cond_br %10, bb5, bb6
bb4:
unreachable
bb5:
br bb7(%4 : $Klass)
bb6:
destroy_value %4 : $Klass
br bb10(%2 : $Builtin.Int64)
bb7(%16 : @owned $Klass):
checked_cast_br Klass in %16 : $Klass to OtherKlass, bb9, bb8
bb8(%18 : @owned $Klass):
destroy_value %18 : $Klass
br bb4
bb9(%20 : @owned $OtherKlass):
return %20 : $OtherKlass
bb10(%22 : $Builtin.Int64):
%23 = apply %1() : $@convention(thin) () -> @owned Klass
%24 = copy_value %23 : $Klass
checked_cast_br Klass in %23 : $Klass to OtherKlass, bb11, bb12
bb11(%25 : @owned $OtherKlass):
destroy_value %25 : $OtherKlass
%26 = integer_literal $Builtin.Int1, -1
br bb13(%26 : $Builtin.Int1)
bb12(%27 : @owned $Klass):
destroy_value %27 : $Klass
%28 = integer_literal $Builtin.Int1, 0
br bb13(%28 : $Builtin.Int1)
bb13(%30 : $Builtin.Int1):
cond_br %30, bb14, bb15
bb14:
br bb7(%24 : $Klass)
bb15:
destroy_value %24 : $Klass
cond_br undef, bb16, bb17
bb16:
br bb4
bb17:
br bb10(undef : $Builtin.Int64)
}
// =============================================================================
// Test OSSA lifetime fixup after removing redundant checked_cast_br
// Replace an owned result with a guaranteed value on the success path.
// Introduce a copy for the new lifetime.
//
// TODO-CHECK-LABEL: sil [ossa] @redundant_checked_cast_br_rauw_guaranteed_to_owned_success : $@convention(method) (@owned Base) -> () {
// TODO-CHECK: bb0(%0 : @owned $Base):
// TODO-CHECK: [[BORROW:%.*]] = begin_borrow %0 : $Base
// TODO-CHECK: checked_cast_br [exact] Base in [[BORROW]] : $Base to Base, bb1, bb2
// TODO-CHECK: bb1([[EXACT:%.*]] : @guaranteed $Base):
// TODO-CHECK-NEXT: [[NEWCP:%.*]] = copy_value [[EXACT]] : $Base
// TODO-CHECK-NEXT: [[OLDCP:%.*]] = copy_value [[EXACT]] : $Base
// TODO-CHECK-NEXT: end_borrow
// TODO-CHECK: destroy_value [[OLDCP]] : $Base
// TODO-CHECK: apply %{{.*}}([[NEWCP]]) : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: destroy_value [[NEWCP]] : $Base
// TODO-CHECK: br bb3
// TODO-CHECK: bb2([[INEXACT:%.*]] : @guaranteed $Base):
// TODO-CHECK: apply %{{.*}}([[INEXACT]]) : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: end_borrow %1 : $Base
// TODO-CHECK: br bb3
// TODO-CHECK: bb3:
// TODO-CHECK: destroy_value %0 : $Base
// TODO-CHECK-LABEL: } // end sil function 'redundant_checked_cast_br_rauw_guaranteed_to_owned_success'
sil [ossa] @redundant_checked_cast_br_rauw_guaranteed_to_owned_success : $@convention(method) (@owned Base) -> () {
bb0(%0 : @owned $Base):
%borrow = begin_borrow %0 : $Base
%1 = class_method %0 : $Base, #Base.middle : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
checked_cast_br [exact] Base in %borrow : $Base to Base, bb1, bb6
bb1(%5 : @guaranteed $Base):
%6 = copy_value %5 : $Base
end_borrow %borrow : $Base
%7 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
checked_cast_br [exact] Base in %6 : $Base to Base, bb2, bb4
bb2(%9 : @owned $Base):
%10 = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
%11 = apply %10(%9) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %9 : $Base
br bb3
bb3:
%13 = tuple ()
br bb5(%13 : $())
bb4(%defaultBB2 : @owned $Base):
%15 = apply %7(%defaultBB2) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %defaultBB2 : $Base
br bb3
bb5(%17 : $()):
br bb7
bb6(%defaultBB0 : @guaranteed $Base):
%19 = apply %1(%defaultBB0) : $@convention(method) (@guaranteed Base) -> ()
end_borrow %borrow : $Base
br bb7
bb7:
destroy_value %0 : $Base
%3 = tuple ()
return %3 : $()
}
// Replace an owned result with a guaranteed value on the merged path.
// Introduce a copy for the new lifetime.
// Simplify down to a single diamond.
//
// TODO: Simplify some of the obviously dead copy/destroy/borrows
// on-the-fly after each simplify-cfg. Possible using CanonicalizeOSSALifetime.
//
// TODO-CHECK-LABEL: sil [ossa] @redundant_checked_cast_br_rauw_guaranteed_to_owned_merge : $@convention(method) (@owned Base) -> () {
// TODO-CHECK: bb0(%0 : @owned $Base):
// TODO-CHECK: [[BORROW:%.*]] = begin_borrow %0 : $Base
// TODO-CHECK: checked_cast_br [exact] Base in [[BORROW]] : $Base to Base, bb1, bb3
// TODO-CHECK: bb1([[ARG1:%.*]] : @guaranteed $Base):
// TODO-CHECK: [[NEWCOPY1:%.*]] = copy_value [[ARG1]] : $Base
// TODO-CHECK: apply %{{.*}}([[ARG1]]) : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: [[OLDCOPY:%.*]] = copy_value [[BORROW]] : $Base
// TODO-CHECK: end_borrow [[BORROW]] : $Base
// TODO-CHECK: destroy_value [[OLDCOPY]] : $Base
// TODO-CHECK: apply %{{.*}}([[NEWCOPY1]]) : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: destroy_value [[NEWCOPY1]] : $Base
// TODO-CHECK: br bb2
// TODO-CHECK: bb2:
// TODO-CHECK: destroy_value %0 : $Base
// TODO-CHECK: return
// TODO-CHECK: bb3([[ARG3:%.*]] : @guaranteed $Base):
// TODO-CHECK: apply %1([[ARG3]]) : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: [[NEWCOPY3:%.*]] = copy_value [[BORROW]] : $Base
// TODO-CHECK: end_borrow [[BORROW]] : $Base
// TODO-CHECK: apply %{{.*}}([[NEWCOPY3]]) : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: destroy_value [[NEWCOPY3]] : $Base
// TODO-CHECK: br bb2
// TODO-CHECK-LABEL: } // end sil function 'redundant_checked_cast_br_rauw_guaranteed_to_owned_merge'
sil [ossa] @redundant_checked_cast_br_rauw_guaranteed_to_owned_merge : $@convention(method) (@owned Base) -> () {
bb0(%0 : @owned $Base):
%m = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%f = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
%1 = begin_borrow %0 : $Base
checked_cast_br [exact] Base in %1 : $Base to Base, bb1, bb2
bb1(%4 : @guaranteed $Base):
%5 = apply %f(%4) : $@convention(method) (@guaranteed Base) -> ()
br bb3
bb2(%7 : @guaranteed $Base):
%8 = apply %m(%7) : $@convention(method) (@guaranteed Base) -> ()
br bb3
bb3:
%11 = copy_value %1 : $Base
end_borrow %1 : $Base
checked_cast_br [exact] Base in %11 : $Base to Base, bb4, bb5
bb4(%14 : @owned $Base):
%15 = apply %f(%14) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %14 : $Base
br bb6
bb5(%20 : @owned $Base):
%21 = apply %m(%20) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %20 : $Base
br bb6
bb6:
destroy_value %0 : $Base
%27 = tuple ()
return %27 : $()
}
// Replace an owned result with a guaranteed value on the merged path.
//
// The merged path has an unknown predecessor, where the merged value
// is produced by an apply.
//
// Clone the success path, introducing a copy on it.
//
// TODO-CHECK-LABEL: sil [ossa] @redundant_checked_cast_br_rauw_guaranteed_to_owned_mergecopy : $@convention(method) (@owned Base) -> () {
// TODO-CHECK: bb0(%0 : @owned $Base):
// TODO-CHECK: [[BORROW:%.*]] = begin_borrow %0 : $Base
// TODO-CHECK: checked_cast_br [exact] Base in [[BORROW]] : $Base to Base, bb1, bb2
// TODO-CHECK: bb1([[ARG1:%.*]] : @guaranteed $Base):
// TODO-CHECK: [[CP1:%.*]] = copy_value [[ARG1]] : $Base
// TODO-CHECK: apply %2([[ARG1]]) : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: end_borrow [[BORROW]] : $Base
// TODO-CHECK: br bb4([[CP1]] : $Base)
// TODO-CHECK: bb2([[ARG2:%.*]] : @guaranteed $Base):
// TODO-CHECK: apply %{{.*}}([[ARG2]]) : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: [[RESULT:%.*]] = apply %{{.*}}() : $@convention(thin) () -> @owned Base
// TODO-CHECK: end_borrow [[BORROW]] : $Base
// TODO-CHECK: checked_cast_br [exact] Base in %13 : $Base to Base, bb3, bb5
// TODO-CHECK: bb3([[ARG3:%.*]] : @owned $Base):
// TODO-CHECK: br bb4(%16 : $Base)
// TODO-CHECK: bb4([[ARG4:%.*]] : @owned $Base):
// TODO-CHECK: apply %{{.*}}([[ARG4]]) : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: destroy_value [[ARG4]] : $Base
// TODO-CHECK: br bb6
// TODO-CHECK: bb5([[ARG5:%.*]] : @owned $Base):
// TODO-CHECK: apply %{{.*}}([[ARG5]]) : $@convention(method) (@guaranteed Base) -> ()
// TODO-CHECK: destroy_value [[ARG5]] : $Base
// TODO-CHECK: br bb6
// TODO-CHECK: bb6:
// TODO-CHECK: destroy_value %0 : $Base
// TODO-CHECK: return
// TODO-CHECK-LABEL: } // end sil function 'redundant_checked_cast_br_rauw_guaranteed_to_owned_mergecopy'
sil [ossa] @redundant_checked_cast_br_rauw_guaranteed_to_owned_mergecopy : $@convention(method) (@owned Base) -> () {
bb0(%0 : @owned $Base):
%1 = class_method %0 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
%2 = function_ref @_TFC3ccb4Base5innerfS0_FT_T_ : $@convention(method) (@guaranteed Base) -> ()
%f = function_ref @get_base : $@convention(thin) () -> @owned Base
%3 = begin_borrow %0 : $Base
checked_cast_br [exact] Base in %3 : $Base to Base, bb1, bb2
bb1(%6 : @guaranteed $Base):
%7 = apply %2(%6) : $@convention(method) (@guaranteed Base) -> ()
%8 = copy_value %6 : $Base
br bb3(%8 : $Base)
bb2(%9 : @guaranteed $Base):
%10 = apply %1(%9) : $@convention(method) (@guaranteed Base) -> ()
%11 = apply %f() : $@convention(thin) () -> @owned Base
br bb3(%11 : $Base)
bb3(%12 : @owned $Base):
end_borrow %3 : $Base
checked_cast_br [exact] Base in %12 : $Base to Base, bb6, bb7
bb6(%16 : @owned $Base):
%17 = apply %2(%16) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %16 : $Base
br bb8
bb7(%20 : @owned $Base):
%21 = apply %1(%20) : $@convention(method) (@guaranteed Base) -> ()
destroy_value %20 : $Base
br bb8
bb8:
destroy_value %0 : $Base
%25 = tuple ()
return %25 : $()
}
// TODO-CHECK-LABEL: sil [ossa] @redundant_checked_cast_failure_path :
// TODO-CHECK: checked_cast_br
// TODO-CHECK-NOT: checked_cast_br
// TODO-CHECK-LABEL: } // end sil function 'redundant_checked_cast_failure_path'
sil [ossa] @redundant_checked_cast_failure_path : $@convention(method) (@owned Base) -> () {
bb0(%0 : @owned $Base):
%borrow = begin_borrow %0 : $Base
checked_cast_br Base in %borrow : $Base to Derived, bb1, bb2
bb1(%succ1 : @guaranteed $Derived):
br bbexit
bb2(%5 : @guaranteed $Base):
checked_cast_br Base in %5 : $Base to Derived, bb3, bb4
bb3(%9 : @guaranteed $Derived):
br bbexit
bb4(%10 : @guaranteed $Base):
%m = class_method %10 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
apply %m(%10) : $@convention(method) (@guaranteed Base) -> ()
br bbexit
bbexit:
end_borrow %borrow : $Base
destroy_value %0 : $Base
%t = tuple ()
return %t : $()
}
// TODO-CHECK-LABEL: sil [ossa] @redundant_checked_cast_failure_path_not_idom :
// TODO-CHECK: checked_cast_br
// TODO-CHECK-NOT: checked_cast_br
// TODO-CHECK-LABEL: } // end sil function 'redundant_checked_cast_failure_path_not_idom'
sil [ossa] @redundant_checked_cast_failure_path_not_idom : $@convention(method) (@owned Base) -> () {
bb0(%0 : @owned $Base):
%borrow = begin_borrow %0 : $Base
checked_cast_br Base in %borrow : $Base to Derived, bb1, bb2
bb1(%succ1 : @guaranteed $Derived):
br bbexit
bb2(%5 : @guaranteed $Base):
br bb3(%5 : $Base)
bb3(%6 : @guaranteed $Base):
checked_cast_br Base in %6 : $Base to Derived, bb4, bb5
bb4(%9 : @guaranteed $Derived):
br bbexit
bb5(%10 : @guaranteed $Base):
%m = class_method %10 : $Base, #Base.inner : (Base) -> () -> (), $@convention(method) (@guaranteed Base) -> ()
apply %m(%10) : $@convention(method) (@guaranteed Base) -> ()
br bbexit
bbexit:
end_borrow %borrow : $Base
destroy_value %0 : $Base
%t = tuple ()
return %t : $()
}
//!!!TODO: test replacing a guaranteed value with an ownedvalue
// test borrowOverValue->borrowCopyOverScope path
//!!!TODO: test prepareUnowned paths