mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
If stores of empty values to the address don't dominate the inject_enum_addr, the inject_enum_addr can't be eliminated--it's the only indication of the case that's in the address.
720 lines
24 KiB
Plaintext
720 lines
24 KiB
Plaintext
// RUN: %empty-directory(%t)
|
|
// RUN: %target-swift-frontend -emit-module -enable-library-evolution \
|
|
// RUN: -emit-module-path=%t/resilient_struct.swiftmodule \
|
|
// RUN: -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
|
|
|
|
// RUN: %target-sil-opt -sdk %clang-importer-sdk-path -enable-sil-verify-all %s -sil-combine -jumpthread-simplify-cfg -I %t | %FileCheck %s
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
import resilient_struct
|
|
import ctypes
|
|
|
|
// CHECK-LABEL: sil @convert_inject_enum_addr_select_enum_addr_into_cond_br : $@convention(thin) (@in Int, @inout _Stdout) -> ()
|
|
// CHECK-NOT: init_existential_addr
|
|
// CHECK-NOT: inject_enum_addr
|
|
// CHECK-NOT: select_enum_addr
|
|
// CHECK-NOT: bb1
|
|
// CHECK-NOT: unchecked_take_enum_data_addr
|
|
// CHECK: return
|
|
sil @convert_inject_enum_addr_select_enum_addr_into_cond_br : $@convention(thin) (@in Int, @inout _Stdout) -> () {
|
|
bb0(%0 : $*Int, %1 : $*_Stdout):
|
|
%2 = alloc_stack $CustomStringConvertible
|
|
%3 = alloc_stack $Optional<CustomStringConvertible>
|
|
%4 = init_enum_data_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
%5 = alloc_stack $Int
|
|
%6 = load %0 : $*Int
|
|
store %6 to %5 : $*Int
|
|
unconditional_checked_cast_addr Int in %5 : $*Int to CustomStringConvertible in %4 : $*CustomStringConvertible
|
|
inject_enum_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
dealloc_stack %5 : $*Int
|
|
%11 = integer_literal $Builtin.Int1, -1
|
|
%12 = integer_literal $Builtin.Int1, 0
|
|
%13 = select_enum_addr %3 : $*Optional<CustomStringConvertible>, case #Optional.some!enumelt: %11, case #Optional.none!enumelt: %12 : $Builtin.Int1
|
|
cond_br %13, bb2, bb1
|
|
|
|
bb1:
|
|
%15 = tuple ()
|
|
dealloc_stack %3 : $*Optional<CustomStringConvertible>
|
|
dealloc_stack %2 : $*CustomStringConvertible
|
|
return %15 : $()
|
|
|
|
bb2:
|
|
%19 = unchecked_take_enum_data_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
copy_addr [take] %19 to [init] %2 : $*CustomStringConvertible
|
|
br bb1
|
|
}
|
|
|
|
// CHECK-LABEL: sil @convert_inject_enum_addr_switch_enum_addr_into_cond_br : $@convention(thin) (@in Int, @inout _Stdout) -> ()
|
|
// CHECK-NOT: init_existential_addr
|
|
// CHECK-NOT: inject_enum_addr
|
|
// CHECK-NOT: switch_enum_addr
|
|
// CHECK-NOT: bb1
|
|
// CHECK-NOT: unchecked_take_enum_data_addr
|
|
// CHECK: return
|
|
sil @convert_inject_enum_addr_switch_enum_addr_into_cond_br : $@convention(thin) (@in Int, @inout _Stdout) -> () {
|
|
bb0(%0 : $*Int, %1 : $*_Stdout):
|
|
%2 = alloc_stack $CustomStringConvertible
|
|
%3 = alloc_stack $Optional<CustomStringConvertible>
|
|
%4 = init_enum_data_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
%5 = alloc_stack $Int
|
|
%6 = load %0 : $*Int
|
|
store %6 to %5 : $*Int
|
|
unconditional_checked_cast_addr Int in %5 : $*Int to CustomStringConvertible in %4 : $*CustomStringConvertible
|
|
inject_enum_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
dealloc_stack %5 : $*Int
|
|
switch_enum_addr %3 : $*Optional<CustomStringConvertible>, case #Optional.some!enumelt: bb3, case #Optional.none!enumelt: bb2
|
|
|
|
bb1:
|
|
%15 = tuple ()
|
|
dealloc_stack %3 : $*Optional<CustomStringConvertible>
|
|
dealloc_stack %2 : $*CustomStringConvertible
|
|
return %15 : $()
|
|
|
|
bb2:
|
|
br bb1
|
|
|
|
bb3:
|
|
%19 = unchecked_take_enum_data_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
copy_addr [take] %19 to [init] %2 : $*CustomStringConvertible
|
|
br bb1
|
|
}
|
|
|
|
|
|
// Check that a checked_cast_addr_br converting a known type into a protocol type
|
|
// is performed at the compile-time if protocol conformances are statically known.
|
|
//
|
|
// CHECK-LABEL: sil @convert_checked_cast_addr_br_into_unconditional_checked_cast_addr_cond_br : $@convention(thin) (@in Int, @inout _Stdout) -> ()
|
|
// CHECK: store
|
|
// CHECK-NOT: checked_cast_addr_br
|
|
// CHECK-NOT: bb1
|
|
// CHECK: inject_enum_addr %{{.*}} : $*Optional<any CustomStringConvertible>, #Optional.some!enumelt
|
|
// CHECK: dealloc_stack
|
|
// CHECK: return
|
|
sil @convert_checked_cast_addr_br_into_unconditional_checked_cast_addr_cond_br : $@convention(thin) (@in Int, @inout _Stdout) -> () {
|
|
bb0(%0 : $*Int, %1 : $*_Stdout):
|
|
%2 = alloc_stack $CustomStringConvertible
|
|
%3 = alloc_stack $Optional<CustomStringConvertible>
|
|
%4 = init_enum_data_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
%5 = alloc_stack $Int
|
|
%6 = load %0 : $*Int
|
|
store %6 to %5 : $*Int
|
|
checked_cast_addr_br take_always Int in %5 : $*Int to CustomStringConvertible in %4 : $*CustomStringConvertible, bb1, bb22
|
|
|
|
bb1:
|
|
inject_enum_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
br bb2
|
|
|
|
bb2:
|
|
dealloc_stack %5 : $*Int
|
|
dealloc_stack %3 : $*Optional<CustomStringConvertible>
|
|
%12 = integer_literal $Builtin.Int1, -1
|
|
%13 = integer_literal $Builtin.Int1, 0
|
|
%26 = tuple ()
|
|
dealloc_stack %2 : $*CustomStringConvertible
|
|
return %26 : $()
|
|
|
|
bb22:
|
|
inject_enum_addr %3 : $*Optional<CustomStringConvertible>, #Optional.none!enumelt
|
|
br bb2
|
|
}
|
|
|
|
class A {
|
|
|
|
}
|
|
|
|
private final class B {
|
|
}
|
|
|
|
public class C {
|
|
}
|
|
|
|
// D cannot be extended elsewhere, but C can!
|
|
private class D : C {
|
|
}
|
|
|
|
// Check that a checked_cast_addr_br converting a known type into a protocol type
|
|
// is performed at the compile-time if protocol conformances are statically known.
|
|
// In a negative case, take care that check for internal types are not folded (unless
|
|
// a whole module optimization is used), because an extension implementing a conformance
|
|
// could be defined elsewhere.
|
|
//
|
|
// CHECK-LABEL: sil @convert_checked_cast_addr_br_with_internal_type : $@convention(thin) (@in A, @inout _Stdout) -> ()
|
|
// CHECK: checked_cast_addr_br
|
|
// CHECK: inject_enum_addr %{{.*}} : $*Optional<any CustomStringConvertible>, #Optional.some!enumelt
|
|
// CHECK: dealloc_stack
|
|
// CHECK: return
|
|
// CHECK: inject_enum_addr %{{.*}} : $*Optional<any CustomStringConvertible>, #Optional.none!enumelt
|
|
// CHECK: }
|
|
sil @convert_checked_cast_addr_br_with_internal_type : $@convention(thin) (@in A, @inout _Stdout) -> () {
|
|
bb0(%0 : $*A, %1 : $*_Stdout):
|
|
%2 = alloc_stack $CustomStringConvertible
|
|
%3 = alloc_stack $Optional<CustomStringConvertible>
|
|
%4 = init_enum_data_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
%5 = alloc_stack $A
|
|
%6 = load %0 : $*A
|
|
store %6 to %5 : $*A
|
|
checked_cast_addr_br take_always A in %5 : $*A to CustomStringConvertible in %4 : $*CustomStringConvertible, bb1, bb22
|
|
|
|
bb1:
|
|
inject_enum_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
br bb2
|
|
|
|
bb2:
|
|
dealloc_stack %5 : $*A
|
|
dealloc_stack %3 : $*Optional<CustomStringConvertible>
|
|
%12 = integer_literal $Builtin.Int1, -1
|
|
%13 = integer_literal $Builtin.Int1, 0
|
|
%26 = tuple ()
|
|
dealloc_stack %2 : $*CustomStringConvertible
|
|
return %26 : $()
|
|
|
|
bb22:
|
|
inject_enum_addr %3 : $*Optional<CustomStringConvertible>, #Optional.none!enumelt
|
|
br bb2
|
|
}
|
|
|
|
// Check that a checked_cast_addr_br converting a known type into a protocol type
|
|
// is performed at the compile-time if protocol conformances are statically known.
|
|
// In a negative case, if the source type is private, it is safe to fold the check,
|
|
// because a conformance for this type cannot be defined elsewhere.
|
|
//
|
|
// CHECK-LABEL: sil @convert_checked_cast_addr_br_with_private_type : $@convention(thin) (@in B, @inout _Stdout) -> ()
|
|
// CHECK: store
|
|
// CHECK-NOT: checked_cast_addr_br
|
|
// CHECK-NOT: bb1
|
|
// CHECK: inject_enum_addr %{{.*}} : $*Optional<any CustomStringConvertible>, #Optional.none!enumelt
|
|
// CHECK: dealloc_stack
|
|
// CHECK: return
|
|
sil @convert_checked_cast_addr_br_with_private_type : $@convention(thin) (@in B, @inout _Stdout) -> () {
|
|
bb0(%0 : $*B, %1 : $*_Stdout):
|
|
%2 = alloc_stack $CustomStringConvertible
|
|
%3 = alloc_stack $Optional<CustomStringConvertible>
|
|
%4 = init_enum_data_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
%5 = alloc_stack $B
|
|
%6 = load %0 : $*B
|
|
store %6 to %5 : $*B
|
|
checked_cast_addr_br take_always B in %5 : $*B to CustomStringConvertible in %4 : $*CustomStringConvertible, bb1, bb22
|
|
|
|
bb1:
|
|
inject_enum_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
br bb2
|
|
|
|
bb2:
|
|
dealloc_stack %5 : $*B
|
|
dealloc_stack %3 : $*Optional<CustomStringConvertible>
|
|
%12 = integer_literal $Builtin.Int1, -1
|
|
%13 = integer_literal $Builtin.Int1, 0
|
|
%26 = tuple ()
|
|
dealloc_stack %2 : $*CustomStringConvertible
|
|
return %26 : $()
|
|
|
|
bb22:
|
|
inject_enum_addr %3 : $*Optional<CustomStringConvertible>, #Optional.none!enumelt
|
|
br bb2
|
|
}
|
|
|
|
// Check that a checked_cast_addr_br converting a known type into a protocol type
|
|
// is performed at the compile-time if protocol conformances are statically known.
|
|
// In a negative case, take care that cast for private types are not folded if one
|
|
// of its superclasses could have a conformance extension defined elsewhere.
|
|
//
|
|
// CHECK-LABEL: sil @convert_checked_cast_addr_br_with_non_private_superclass : $@convention(thin) (@in D, @inout _Stdout) -> ()
|
|
// CHECK: checked_cast_addr_br
|
|
// CHECK: inject_enum_addr %{{.*}} : $*Optional<any CustomStringConvertible>, #Optional.some!enumelt
|
|
// CHECK: dealloc_stack
|
|
// CHECK: return
|
|
// CHECK: inject_enum_addr %{{.*}} : $*Optional<any CustomStringConvertible>, #Optional.none!enumelt
|
|
// CHECK: }
|
|
sil @convert_checked_cast_addr_br_with_non_private_superclass : $@convention(thin) (@in D, @inout _Stdout) -> () {
|
|
bb0(%0 : $*D, %1 : $*_Stdout):
|
|
%2 = alloc_stack $CustomStringConvertible
|
|
%3 = alloc_stack $Optional<CustomStringConvertible>
|
|
%4 = init_enum_data_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
%5 = alloc_stack $D
|
|
%6 = load %0 : $*D
|
|
store %6 to %5 : $*D
|
|
checked_cast_addr_br take_always D in %5 : $*D to CustomStringConvertible in %4 : $*CustomStringConvertible, bb1, bb22
|
|
|
|
bb1:
|
|
inject_enum_addr %3 : $*Optional<CustomStringConvertible>, #Optional.some!enumelt
|
|
br bb2
|
|
|
|
bb2:
|
|
dealloc_stack %5 : $*D
|
|
dealloc_stack %3 : $*Optional<CustomStringConvertible>
|
|
%12 = integer_literal $Builtin.Int1, -1
|
|
%13 = integer_literal $Builtin.Int1, 0
|
|
%26 = tuple ()
|
|
dealloc_stack %2 : $*CustomStringConvertible
|
|
return %26 : $()
|
|
|
|
bb22:
|
|
inject_enum_addr %3 : $*Optional<CustomStringConvertible>, #Optional.none!enumelt
|
|
br bb2
|
|
}
|
|
|
|
sil @no_init : $@convention(thin) () -> (@out ())
|
|
|
|
// CHECK-LABEL: sil @test_empty_tuple_uninintialized : $@convention(thin) () -> () {
|
|
// CHECK-NOT: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'test_empty_tuple_uninintialized'
|
|
sil @test_empty_tuple_uninintialized : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_stack $Optional<()>
|
|
%1 = init_enum_data_addr %0 : $*Optional<()>, #Optional.some!enumelt
|
|
%f = function_ref @no_init : $@convention(thin) () -> (@out ())
|
|
apply %f(%1) : $@convention(thin) () -> (@out ())
|
|
inject_enum_addr %0 : $*Optional<()>, #Optional.some!enumelt
|
|
%2 = load %0 : $*Optional<()>
|
|
switch_enum %2 : $Optional<()>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
|
|
|
|
bb1(%4 : $()):
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
dealloc_stack %0 : $*Optional<()>
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
sil @no_init_nested_tuple : $@convention(thin) () -> (@out ((), ()))
|
|
|
|
// CHECK-LABEL: sil @test_empty_nested_tuple_uninintialized : $@convention(thin) () -> () {
|
|
// CHECK-NOT: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'test_empty_nested_tuple_uninintialized'
|
|
sil @test_empty_nested_tuple_uninintialized : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_stack $Optional<((), ())>
|
|
%1 = init_enum_data_addr %0 : $*Optional<((), ())>, #Optional.some!enumelt
|
|
%f = function_ref @no_init_nested_tuple : $@convention(thin) () -> (@out ((), ()))
|
|
apply %f(%1) : $@convention(thin) () -> (@out ((), ()))
|
|
inject_enum_addr %0 : $*Optional<((), ())>, #Optional.some!enumelt
|
|
%2 = load %0 : $*Optional<((), ())>
|
|
switch_enum %2 : $Optional<((), ())>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
|
|
|
|
bb1(%4 : $((), ())):
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
dealloc_stack %0 : $*Optional<((), ())>
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
sil @no_init_struct : $@convention(thin) () -> (@out ResilientEmptyStruct)
|
|
|
|
// CHECK-LABEL: sil @test_empty_struct_uninitialized : $@convention(thin) () -> () {
|
|
// CHECK-NOT: switch_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'test_empty_struct_uninitialized'
|
|
sil @test_empty_struct_uninitialized : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_stack $Optional<ResilientEmptyStruct>
|
|
%1 = init_enum_data_addr %0 : $*Optional<ResilientEmptyStruct>, #Optional.some!enumelt
|
|
%f = function_ref @no_init_struct : $@convention(thin) () -> (@out ResilientEmptyStruct)
|
|
apply %f(%1) : $@convention(thin) () -> (@out ResilientEmptyStruct)
|
|
inject_enum_addr %0 : $*Optional<ResilientEmptyStruct>, #Optional.some!enumelt
|
|
switch_enum_addr %0 : $*Optional<ResilientEmptyStruct>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
dealloc_stack %0 : $*Optional<ResilientEmptyStruct>
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
sil @no_init_c_union : $@convention(thin) () -> (@out EmptyCUnion)
|
|
|
|
// CHECK-LABEL: sil @test_empty_c_union : $@convention(thin) () -> () {
|
|
// CHECK: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'test_empty_c_union'
|
|
sil @test_empty_c_union : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_stack $Optional<EmptyCUnion>
|
|
%1 = init_enum_data_addr %0 : $*Optional<EmptyCUnion>, #Optional.some!enumelt
|
|
%f = function_ref @no_init_c_union : $@convention(thin) () -> (@out EmptyCUnion)
|
|
apply %f(%1) : $@convention(thin) () -> (@out EmptyCUnion)
|
|
inject_enum_addr %0 : $*Optional<EmptyCUnion>, #Optional.some!enumelt
|
|
switch_enum_addr %0 : $*Optional<EmptyCUnion>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
dealloc_stack %0 : $*Optional<EmptyCUnion>
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
struct NestedUnreferenceableStorage {
|
|
let e: EmptyCUnion
|
|
}
|
|
|
|
sil @no_init_nested_c_union : $@convention(thin) () -> (@out NestedUnreferenceableStorage)
|
|
|
|
// CHECK-LABEL: sil @test_empty_nested_c_union : $@convention(thin) () -> () {
|
|
// CHECK: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'test_empty_nested_c_union'
|
|
sil @test_empty_nested_c_union : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_stack $Optional<NestedUnreferenceableStorage>
|
|
%1 = init_enum_data_addr %0 : $*Optional<NestedUnreferenceableStorage>, #Optional.some!enumelt
|
|
%f = function_ref @no_init_nested_c_union : $@convention(thin) () -> (@out NestedUnreferenceableStorage)
|
|
apply %f(%1) : $@convention(thin) () -> (@out NestedUnreferenceableStorage)
|
|
inject_enum_addr %0 : $*Optional<NestedUnreferenceableStorage>, #Optional.some!enumelt
|
|
switch_enum_addr %0 : $*Optional<NestedUnreferenceableStorage>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
dealloc_stack %0 : $*Optional<NestedUnreferenceableStorage>
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
sil @getVoidOut : $@convention(thin) () -> @out ()
|
|
sil @getIntOut : $@convention(thin) () -> @out Int
|
|
|
|
// CHECK-LABEL: sil @empty_nondominating_apply : {{.*}} {
|
|
// CHECK: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'empty_nondominating_apply'
|
|
sil @empty_nondominating_apply : $@convention(thin) (Builtin.Int1) -> () {
|
|
entry(%cond : $Builtin.Int1):
|
|
%addr = alloc_stack $Optional<()>
|
|
%some_addr = init_enum_data_addr %addr : $*Optional<()>, #Optional.some!enumelt
|
|
cond_br %cond, left, right
|
|
|
|
left:
|
|
br middle
|
|
|
|
right:
|
|
%get = function_ref @getVoidOut : $@convention(thin) () -> @out ()
|
|
apply %get(%some_addr) : $@convention(thin) () -> @out ()
|
|
br middle
|
|
|
|
middle:
|
|
inject_enum_addr %addr : $*Optional<()>, #Optional.some!enumelt
|
|
%o = load %addr : $*Optional<()>
|
|
switch_enum %o : $Optional<()>, case #Optional.some!enumelt: some_block, case #Optional.none!enumelt: none_block
|
|
|
|
some_block(%avoid : $()):
|
|
br exit
|
|
|
|
none_block:
|
|
br exit
|
|
|
|
exit:
|
|
dealloc_stack %addr : $*Optional<()>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @check_dominating_apply_unreachable : {{.*}} {
|
|
// CHECK-NOT: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'check_dominating_apply_unreachable'
|
|
sil @check_dominating_apply_unreachable : $@convention(thin) (Builtin.Int1) -> () {
|
|
entry(%cond : $Builtin.Int1):
|
|
%addr = alloc_stack $Optional<()>
|
|
%some_addr = init_enum_data_addr %addr : $*Optional<()>, #Optional.some!enumelt
|
|
cond_br %cond, left, right
|
|
|
|
left:
|
|
%get = function_ref @getVoidOut : $@convention(thin) () -> @out ()
|
|
apply %get(%some_addr) : $@convention(thin) () -> @out ()
|
|
br middle
|
|
|
|
right:
|
|
unreachable
|
|
|
|
middle:
|
|
inject_enum_addr %addr : $*Optional<()>, #Optional.some!enumelt
|
|
%o = load %addr : $*Optional<()>
|
|
switch_enum %o : $Optional<()>, case #Optional.some!enumelt: some_block, case #Optional.none!enumelt: none_block
|
|
|
|
some_block(%avoid : $()):
|
|
br exit
|
|
|
|
none_block:
|
|
br exit
|
|
|
|
exit:
|
|
dealloc_stack %addr : $*Optional<()>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @check_dominating_apply_unreachable_nonempty : {{.*}} {
|
|
// CHECK-NOT: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'check_dominating_apply_unreachable_nonempty'
|
|
sil @check_dominating_apply_unreachable_nonempty : $@convention(thin) (Builtin.Int1) -> () {
|
|
entry(%cond : $Builtin.Int1):
|
|
%addr = alloc_stack $Optional<Int>
|
|
%some_addr = init_enum_data_addr %addr : $*Optional<Int>, #Optional.some!enumelt
|
|
cond_br %cond, left, right
|
|
|
|
left:
|
|
%get = function_ref @getIntOut : $@convention(thin) () -> @out Int
|
|
apply %get(%some_addr) : $@convention(thin) () -> @out Int
|
|
br middle
|
|
|
|
right:
|
|
unreachable
|
|
|
|
middle:
|
|
inject_enum_addr %addr : $*Optional<Int>, #Optional.some!enumelt
|
|
%o = load %addr : $*Optional<Int>
|
|
switch_enum %o : $Optional<Int>, case #Optional.some!enumelt: some_block, case #Optional.none!enumelt: none_block
|
|
|
|
some_block(%avoid : $Int):
|
|
br exit
|
|
|
|
none_block:
|
|
br exit
|
|
|
|
exit:
|
|
dealloc_stack %addr : $*Optional<Int>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @empty_nondominating_store : {{.*}} {
|
|
// CHECK: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'empty_nondominating_store'
|
|
sil @empty_nondominating_store : $@convention(thin) (Builtin.Int1) -> () {
|
|
entry(%cond : $Builtin.Int1):
|
|
%addr = alloc_stack $Optional<()>
|
|
%some_addr = init_enum_data_addr %addr : $*Optional<()>, #Optional.some!enumelt
|
|
cond_br %cond, left, right
|
|
|
|
left:
|
|
br middle
|
|
|
|
right:
|
|
%void = tuple ()
|
|
store %void to %some_addr : $*()
|
|
br middle
|
|
|
|
middle:
|
|
inject_enum_addr %addr : $*Optional<()>, #Optional.some!enumelt
|
|
%o = load %addr : $*Optional<()>
|
|
switch_enum %o : $Optional<()>, case #Optional.some!enumelt: some_block, case #Optional.none!enumelt: none_block
|
|
|
|
some_block(%avoid : $()):
|
|
br exit
|
|
|
|
none_block:
|
|
br exit
|
|
|
|
exit:
|
|
dealloc_stack %addr : $*Optional<()>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @empty_nondominating_tuple_store_neither : {{.*}} {
|
|
// CHECK: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'empty_nondominating_tuple_store_neither'
|
|
sil @empty_nondominating_tuple_store_neither : $@convention(thin) (Builtin.Int1) -> () {
|
|
entry(%cond : $Builtin.Int1):
|
|
%addr = alloc_stack $Optional<((), ())>
|
|
%some_addr = init_enum_data_addr %addr : $*Optional<((), ())>, #Optional.some!enumelt
|
|
%left_addr = tuple_element_addr %some_addr : $*((), ()), 0
|
|
%right_addr = tuple_element_addr %some_addr : $*((), ()), 1
|
|
cond_br %cond, left, right
|
|
|
|
left:
|
|
br middle
|
|
|
|
right:
|
|
%void = tuple ()
|
|
store %void to %left_addr : $*()
|
|
store %void to %right_addr : $*()
|
|
br middle
|
|
|
|
middle:
|
|
inject_enum_addr %addr : $*Optional<((), ())>, #Optional.some!enumelt
|
|
%o = load %addr : $*Optional<((), ())>
|
|
switch_enum %o : $Optional<((), ())>, case #Optional.some!enumelt: some_block, case #Optional.none!enumelt: none_block
|
|
|
|
some_block(%avoid : $((), ())):
|
|
br exit
|
|
|
|
none_block:
|
|
br exit
|
|
|
|
exit:
|
|
dealloc_stack %addr : $*Optional<((), ())>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @empty_nondominating_tuple_store_left : {{.*}} {
|
|
// CHECK: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'empty_nondominating_tuple_store_left'
|
|
sil @empty_nondominating_tuple_store_left : $@convention(thin) (Builtin.Int1) -> () {
|
|
entry(%cond : $Builtin.Int1):
|
|
%addr = alloc_stack $Optional<((), ())>
|
|
%some_addr = init_enum_data_addr %addr : $*Optional<((), ())>, #Optional.some!enumelt
|
|
%left_addr = tuple_element_addr %some_addr : $*((), ()), 0
|
|
%right_addr = tuple_element_addr %some_addr : $*((), ()), 1
|
|
%void = tuple ()
|
|
cond_br %cond, left, right
|
|
|
|
left:
|
|
br middle
|
|
|
|
right:
|
|
store %void to %left_addr : $*()
|
|
br middle
|
|
|
|
middle:
|
|
store %void to %right_addr : $*()
|
|
inject_enum_addr %addr : $*Optional<((), ())>, #Optional.some!enumelt
|
|
%o = load %addr : $*Optional<((), ())>
|
|
switch_enum %o : $Optional<((), ())>, case #Optional.some!enumelt: some_block, case #Optional.none!enumelt: none_block
|
|
|
|
some_block(%avoid : $((), ())):
|
|
br exit
|
|
|
|
none_block:
|
|
br exit
|
|
|
|
exit:
|
|
dealloc_stack %addr : $*Optional<((), ())>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @empty_nondominating_tuple_store_right : {{.*}} {
|
|
// CHECK: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'empty_nondominating_tuple_store_right'
|
|
sil @empty_nondominating_tuple_store_right : $@convention(thin) (Builtin.Int1) -> () {
|
|
entry(%cond : $Builtin.Int1):
|
|
%addr = alloc_stack $Optional<((), ())>
|
|
%some_addr = init_enum_data_addr %addr : $*Optional<((), ())>, #Optional.some!enumelt
|
|
%left_addr = tuple_element_addr %some_addr : $*((), ()), 0
|
|
%right_addr = tuple_element_addr %some_addr : $*((), ()), 1
|
|
%void = tuple ()
|
|
cond_br %cond, left, right
|
|
|
|
left:
|
|
br middle
|
|
|
|
right:
|
|
store %void to %right_addr : $*()
|
|
br middle
|
|
|
|
middle:
|
|
store %void to %left_addr : $*()
|
|
inject_enum_addr %addr : $*Optional<((), ())>, #Optional.some!enumelt
|
|
%o = load %addr : $*Optional<((), ())>
|
|
switch_enum %o : $Optional<((), ())>, case #Optional.some!enumelt: some_block, case #Optional.none!enumelt: none_block
|
|
|
|
some_block(%avoid : $((), ())):
|
|
br exit
|
|
|
|
none_block:
|
|
br exit
|
|
|
|
exit:
|
|
dealloc_stack %addr : $*Optional<((), ())>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @check_partially_dominating_tuple_stores : {{.*}} {
|
|
// CHECK: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'check_partially_dominating_tuple_stores'
|
|
sil @check_partially_dominating_tuple_stores : $@convention(thin) (Builtin.Int1) -> () {
|
|
entry(%cond : $Builtin.Int1):
|
|
%addr = alloc_stack $Optional<(Builtin.Int1, ())>
|
|
%some_addr = init_enum_data_addr %addr : $*Optional<(Builtin.Int1, ())>, #Optional.some!enumelt
|
|
%left_addr = tuple_element_addr %some_addr : $*(Builtin.Int1, ()), 0
|
|
%false = integer_literal $Builtin.Int1, 0
|
|
store %false to %left_addr : $*Builtin.Int1
|
|
%right_addr = tuple_element_addr %some_addr : $*(Builtin.Int1, ()), 1
|
|
cond_br %cond, left, right
|
|
|
|
left:
|
|
br middle
|
|
|
|
right:
|
|
%void = tuple ()
|
|
store %void to %right_addr : $*()
|
|
br middle
|
|
|
|
middle:
|
|
inject_enum_addr %addr : $*Optional<(Builtin.Int1, ())>, #Optional.some!enumelt
|
|
%o = load %addr : $*Optional<(Builtin.Int1, ())>
|
|
switch_enum %o : $Optional<(Builtin.Int1, ())>, case #Optional.some!enumelt: some_block, case #Optional.none!enumelt: none_block
|
|
|
|
some_block(%avoid : $(Builtin.Int1, ())):
|
|
br exit
|
|
|
|
none_block:
|
|
br exit
|
|
|
|
exit:
|
|
dealloc_stack %addr : $*Optional<(Builtin.Int1, ())>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @empty_dominating_tuple_stores : {{.*}} {
|
|
// CHECK-NOT: inject_enum_addr
|
|
// CHECK-LABEL: } // end sil function 'empty_dominating_tuple_stores'
|
|
sil @empty_dominating_tuple_stores : $@convention(thin) (Builtin.Int1) -> () {
|
|
entry(%cond : $Builtin.Int1):
|
|
%addr = alloc_stack $Optional<((), ())>
|
|
%some_addr = init_enum_data_addr %addr : $*Optional<((), ())>, #Optional.some!enumelt
|
|
%left_addr = tuple_element_addr %some_addr : $*((), ()), 0
|
|
%right_addr = tuple_element_addr %some_addr : $*((), ()), 1
|
|
%void = tuple ()
|
|
cond_br %cond, left, right
|
|
|
|
left:
|
|
br middle
|
|
|
|
right:
|
|
br middle
|
|
|
|
middle:
|
|
store %void to %right_addr : $*()
|
|
store %void to %left_addr : $*()
|
|
inject_enum_addr %addr : $*Optional<((), ())>, #Optional.some!enumelt
|
|
%o = load %addr : $*Optional<((), ())>
|
|
switch_enum %o : $Optional<((), ())>, case #Optional.some!enumelt: some_block, case #Optional.none!enumelt: none_block
|
|
|
|
some_block(%avoid : $((), ())):
|
|
br exit
|
|
|
|
none_block:
|
|
br exit
|
|
|
|
exit:
|
|
dealloc_stack %addr : $*Optional<((), ())>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|