Files
swift-mirror/test/SILOptimizer/conditionforwarding_nontrivial_ossa.sil
Meghana Gupta 01d4f11cf5 Fix condition forwarding for switch_enum with default in ossa
In ossa, switch_enum's destination accepts an argument. Fixup
condition forwarding to correctly forward the enum in this case.

Fixes rdar://143042093
2025-01-17 11:01:12 -08:00

432 lines
11 KiB
Plaintext

// RUN: %target-sil-opt -sil-print-types -sil-print-debuginfo -update-borrowed-from -enable-sil-verify-all %s -condition-forwarding | %FileCheck %s
import Builtin
import Swift
sil_stage canonical
class Klass {}
enum E { case A(Klass), B(Klass) }
enum E3 { case A(Klass), B(Klass), C(Klass) }
class C {
@_hasStorage var x : Builtin.Int64
init()
}
enum FakeOptional<T> {
case none
case some(T)
}
enum PrimaryColor : Int {
case red = 0
case blue = 1
case green = 2
}
sil [ossa] @use_color : $@convention(thin) (PrimaryColor) -> ()
sil [ossa] @callee : $@convention(thin) () -> ()
sil [ossa] @use_enum : $@convention(thin) (@guaranteed E) -> ()
sil [ossa] @use_int : $@convention(thin) (Builtin.Int64) -> ()
// CHECK-LABEL: sil [ossa] @simple_forwarding1 :
// CHECK: bb0(%0 : $Builtin.Int1, %1 : @owned $Klass):
// CHECK-NEXT: br bb3
// CHECK: bb1:
// CHECK: br bb4(%1 : $Klass)
// CHECK: bb2:
// CHECK: br bb5(%1 : $Klass)
// CHECK: bb3:
// CHECK: apply
// CHECK: cond_br %0, bb1, bb2
// CHECK: bb4({{.*}}):
// CHECK: br bb6
// CHECK: bb5({{.*}}):
// CHECK: br bb6
// CHECK: bb6:
// CHECK-LABEL: } // end sil function 'simple_forwarding1'
sil [ossa] @simple_forwarding1 : $@convention(thin) (Builtin.Int1, @owned Klass) -> () {
bb0(%0 : $Builtin.Int1, %1 : @owned $Klass):
cond_br %0, bb1, bb2
bb1:
%2 = enum $E, #E.A!enumelt, %1 : $Klass
br bb3(%2 : $E)
bb2:
%3 = enum $E, #E.B!enumelt, %1 : $Klass
br bb3(%3 : $E)
bb3(%14 : @owned $E):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4(%17 : @owned $Klass):
destroy_value %17 : $Klass
br bb6
bb5(%18 : @owned $Klass):
destroy_value %18 : $Klass
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @simple_forwarding2 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'simple_forwarding2'
sil [ossa] @simple_forwarding2 : $@convention(thin) (Builtin.Int1, @guaranteed Klass) -> () {
bb0(%0 : $Builtin.Int1, %1 : @guaranteed $Klass):
cond_br %0, bb1, bb2
bb1:
%2 = enum $E, #E.A!enumelt, %1 : $Klass
br bb3(%2 : $E)
bb2:
%3 = enum $E, #E.B!enumelt, %1 : $Klass
br bb3(%3 : $E)
bb3(%14 : @guaranteed $E):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4(%17 : @guaranteed $Klass):
br bb6
bb5(%18 : @guaranteed $Klass):
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @simple_forwarding3 :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'simple_forwarding3'
sil [ossa] @simple_forwarding3 : $@convention(thin) (Builtin.Int1, @owned Klass) -> () {
bb0(%0 : $Builtin.Int1, %1 : @owned $Klass):
cond_br %0, bb1, bb2
bb1:
%2 = enum $E, #E.A!enumelt, %1 : $Klass
debug_value %2 : $E
br bb3(%2 : $E)
bb2:
%3 = enum $E, #E.B!enumelt, %1 : $Klass
br bb3(%3 : $E)
bb3(%14 : @owned $E):
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4(%17 : @owned $Klass):
destroy_value %17 : $Klass
br bb6
bb5(%18 : @owned $Klass):
destroy_value %18 : $Klass
br bb6
bb6:
%r = tuple ()
return %r : $()
}
sil [ossa] @simple_forwarding4 : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb2
bb1:
%2 = enum $PrimaryColor, #PrimaryColor.red!enumelt
br bb3(%2 : $PrimaryColor)
bb2:
%3 = enum $PrimaryColor, #PrimaryColor.blue!enumelt
br bb3(%3 : $PrimaryColor)
bb3(%14 : $PrimaryColor):
switch_enum %14 : $PrimaryColor, case #PrimaryColor.red!enumelt: bb4, default bb5
bb4:
br bb6
bb5(%18 : $PrimaryColor):
%15 = function_ref @use_color : $@convention(thin) (PrimaryColor) -> ()
%16 = apply %15(%18) : $@convention(thin) (PrimaryColor) -> ()
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @simple_switch_enum_forwarding1 :
// CHECK: bb0({{.*}}):
// CHECK-NEXT: br bb3
// CHECK: bb1({{.*}}):
// CHECK: br bb4({{.*}})
// CHECK: bb2({{.*}}):
// CHECK: br bb5({{.*}})
// CHECK: bb3:
// CHECK: apply
// CHECK: switch_enum %0 : $E3, case #E3.A!enumelt: bb1, default bb2
// CHECK: bb4({{.*}}):
// CHECK: br bb6
// CHECK: bb5({{.*}}):
// CHECK: br bb6
// CHECK: bb6:
// CHECK-LABEL: } // end sil function 'simple_switch_enum_forwarding1'
sil [ossa] @simple_switch_enum_forwarding1 : $@convention(thin) (@owned E3) -> () {
bb0(%0 : @owned $E3):
switch_enum %0 : $E3, case #E3.A!enumelt: bb1, default bb2
bb1(%1 : @owned $Klass):
%2 = enum $E, #E.A!enumelt, %1 : $Klass
br bb3(%2 : $E)
bb2(%defaultenum : @owned $E3):
%defaultklass = unchecked_enum_data %defaultenum : $E3, #E3.B!enumelt
%3 = enum $E, #E.B!enumelt, %defaultklass : $Klass
br bb3(%3 : $E)
bb3(%14 : @owned $E):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4(%4 : @owned $Klass):
destroy_value %4 : $Klass
br bb6
bb5(%5 : @owned $Klass):
destroy_value %5 : $Klass
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @simple_switch_enum_forwarding2 :
// CHECK: switch_enum
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'simple_switch_enum_forwarding2'
sil [ossa] @simple_switch_enum_forwarding2 : $@convention(thin) (@guaranteed E3) -> () {
bb0(%0 : @guaranteed $E3):
switch_enum %0 : $E3, case #E3.A!enumelt: bb1, default bb2
bb1(%1 : @guaranteed $Klass):
%2 = enum $E, #E.A!enumelt, %1 : $Klass
br bb3(%2 : $E)
bb2(%defaultenum : @guaranteed $E3):
%defaultklass = unchecked_enum_data %defaultenum : $E3, #E3.B!enumelt
%3 = enum $E, #E.B!enumelt, %defaultklass : $Klass
br bb3(%3 : $E)
bb3(%14 : @guaranteed $E):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4(%4 : @guaranteed $Klass):
br bb6
bb5(%5 : @guaranteed $Klass):
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// TODO : This is not optimized today, it needs lifetime extension
// CHECK-LABEL: sil [ossa] @simple_switch_enum_forwarding3 :
// CHECK: switch_enum
// CHECK: switch_enum
// CHECK-LABEL: } // end sil function 'simple_switch_enum_forwarding3'
sil [ossa] @simple_switch_enum_forwarding3 : $@convention(thin) (@in_guaranteed E3) -> () {
bb0(%0 : $*E3):
%ldb = load_borrow %0 : $*E3
switch_enum %ldb : $E3, case #E3.A!enumelt: bb1, default bb2
bb1(%1 : @guaranteed $Klass):
%2 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%2 : $FakeOptional<Klass>)
bb2(%defaultenum : @guaranteed $E3):
%3 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%3 : $FakeOptional<Klass>)
bb3(%14 : $FakeOptional<Klass>):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
end_borrow %ldb : $E3
switch_enum %14 : $FakeOptional<Klass>, case #FakeOptional.some: bb4, case #FakeOptional.none: bb5
bb4(%4 : $Klass):
br bb6
bb5:
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// TODO : This is not optimized today, it needs lifetime extension
// CHECK-LABEL: sil [ossa] @simple_switch_enum_forwarding4 :
// CHECK: switch_enum
// CHECK: switch_enum
// CHECK-LABEL: } // end sil function 'simple_switch_enum_forwarding4'
sil [ossa] @simple_switch_enum_forwarding4 : $@convention(thin) (@in_guaranteed E3) -> () {
bb0(%0 : $*E3):
%ld = load [copy] %0 : $*E3
%borrow = begin_borrow %ld : $E3
switch_enum %borrow : $E3, case #E3.A!enumelt: bb1, default bb2
bb1(%1 : @guaranteed $Klass):
%2 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%2 : $FakeOptional<Klass>)
bb2(%defaultenum : @guaranteed $E3):
%3 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%3 : $FakeOptional<Klass>)
bb3(%14 : $FakeOptional<Klass>):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
end_borrow %borrow : $E3
destroy_value %ld : $E3
switch_enum %14 : $FakeOptional<Klass>, case #FakeOptional.some: bb4, case #FakeOptional.none: bb5
bb4(%4 : $Klass):
br bb6
bb5:
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// TODO : This is not optimized today, it needs lifetime extension
// CHECK-LABEL: sil [ossa] @simple_switch_enum_forwarding5 :
// CHECK: switch_enum
// CHECK: switch_enum
// CHECK-LABEL: } // end sil function 'simple_switch_enum_forwarding5'
sil [ossa] @simple_switch_enum_forwarding5 : $@convention(thin) (@in_guaranteed E3) -> () {
bb0(%0 : $*E3):
%ld = load [copy] %0 : $*E3
%borrow = begin_borrow %ld : $E3
switch_enum %borrow : $E3, case #E3.A!enumelt: bb1, default bb2
bb1(%1 : @guaranteed $Klass):
%2 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
end_borrow %borrow : $E3
destroy_value %ld : $E3
br bb3(%2 : $FakeOptional<Klass>)
bb2(%defaultenum : @guaranteed $E3):
%3 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
end_borrow %borrow : $E3
destroy_value %ld : $E3
br bb3(%3 : $FakeOptional<Klass>)
bb3(%14 : $FakeOptional<Klass>):
%15 = function_ref @callee : $@convention(thin) () -> ()
%16 = apply %15() : $@convention(thin) () -> ()
switch_enum %14 : $FakeOptional<Klass>, case #FakeOptional.some: bb4, case #FakeOptional.none: bb5
bb4(%4 : $Klass):
br bb6
bb5:
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @no_forwarding_second_enum_use :
// CHECK: bb0({{.*}}):
// CHECK: cond_br %0
// CHECK: bb3({{.*}}):
// CHECK: switch_enum
// CHECK: bb6
// CHECK-LABEL: } // end sil function 'no_forwarding_second_enum_use'
sil [ossa] @no_forwarding_second_enum_use : $@convention(thin) (Builtin.Int1, @owned Klass) -> () {
bb0(%0 : $Builtin.Int1, %1 : @owned $Klass):
cond_br %0, bb1, bb2
bb1:
%2 = enum $E, #E.A!enumelt, %1 : $Klass
br bb3(%2 : $E)
bb2:
%3 = enum $E, #E.B!enumelt, %1 : $Klass
br bb3(%3 : $E)
bb3(%14 : @owned $E):
%15 = function_ref @use_enum : $@convention(thin) (@guaranteed E) -> ()
%16 = apply %15(%14) : $@convention(thin) (@guaranteed E) -> ()
switch_enum %14 : $E, case #E.A!enumelt: bb4, case #E.B!enumelt: bb5
bb4(%17 : @owned $Klass):
destroy_value %17 : $Klass
br bb6
bb5(%18 : @owned $Klass):
destroy_value %18 : $Klass
br bb6
bb6:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @nontrivialenumarg :
// CHECK-NOT: switch_enum
// CHECK-LABEL: } // end sil function 'nontrivialenumarg'
sil [ossa] @nontrivialenumarg : $@convention(thin) (@guaranteed Klass) -> @owned Optional<Klass> {
bb0(%0 : @guaranteed $Klass):
cond_br undef, bb1, bb2
bb1:
%2 = enum $Optional<Klass>, #Optional.some!enumelt, %0
br bb3(%2)
bb2:
%3 = enum $Optional<Klass>, #Optional.some!enumelt, %0
br bb3(%3)
bb3(%7 : @guaranteed $Optional<Klass>):
switch_enum %7, case #Optional.some!enumelt: bb4, case #Optional.none!enumelt: bb5
bb4(%9 : @guaranteed $Klass):
apply undef(%7) : $@convention(thin) (@guaranteed Optional<Klass>) -> ()
%10 = enum $Optional<Klass>, #Optional.some!enumelt, %9
br bb6(%10)
bb5:
%12 = enum $Optional<Klass>, #Optional.none!enumelt
br bb6(%12)
bb6(%14 : @guaranteed $Optional<Klass>):
%15 = copy_value %14
return %15
}