mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
452 lines
11 KiB
Plaintext
452 lines
11 KiB
Plaintext
// RUN: %target-sil-opt -destroy-hoisting %s | %FileCheck %s
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
import SwiftShims
|
|
|
|
class X {
|
|
}
|
|
|
|
enum TwoCases {
|
|
case A(X)
|
|
case B
|
|
}
|
|
|
|
struct S {
|
|
var x: X
|
|
}
|
|
|
|
struct Outer {
|
|
var s: S
|
|
var ox: X
|
|
}
|
|
|
|
struct Mixed {
|
|
var x: X
|
|
var i: Int
|
|
}
|
|
|
|
public struct S2 {
|
|
let s: S
|
|
}
|
|
|
|
|
|
public enum E {
|
|
case A
|
|
case B
|
|
}
|
|
|
|
sil @unknown : $@convention(thin) () -> ()
|
|
sil @use_S : $@convention(thin) (@in_guaranteed S) -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_simple
|
|
// CHECK: bb0(%0 : $*S):
|
|
// CHECK-NEXT: destroy_addr %0
|
|
// CHECK-NEXT: br bb1
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil [ossa] @test_simple : $@convention(thin) (@in S) -> () {
|
|
bb0(%0 : $*S):
|
|
br bb1
|
|
bb1:
|
|
destroy_addr %0 : $*S
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_move_over_pure_insts
|
|
// CHECK: bb0(%0 : $*S):
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: destroy_addr %0
|
|
// CHECK-NEXT: return
|
|
sil [ossa] @dont_move_over_pure_insts : $@convention(thin) (@in S) -> () {
|
|
bb0(%0 : $*S):
|
|
%r = tuple ()
|
|
destroy_addr %0 : $*S
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @combine_load
|
|
// CHECK: bb0(%0 : $*S):
|
|
// CHECK-NEXT: load [take] %0
|
|
// CHECK-NEXT: br bb1
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: return
|
|
sil [ossa] @combine_load : $@convention(thin) (@in S) -> @owned S {
|
|
bb0(%0 : $*S):
|
|
%v = load [copy] %0 : $*S
|
|
br bb1
|
|
bb1:
|
|
destroy_addr %0 : $*S
|
|
return %v : $S
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @combine_copy_addr
|
|
// CHECK: bb0(%0 : $*S, %1 : $*S):
|
|
// CHECK-NEXT: copy_addr [take] %1 to [init] %0
|
|
// CHECK-NEXT: br bb1
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil [ossa] @combine_copy_addr : $@convention(thin) (@in S) -> @out S {
|
|
bb0(%0 : $*S, %1 : $*S):
|
|
copy_addr %1 to [init] %0 : $*S
|
|
br bb1
|
|
bb1:
|
|
destroy_addr %1 : $*S
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @tail_merging
|
|
// CHECK: bb1:
|
|
// CHECK: apply
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: destroy_addr %0
|
|
// CHECK-NEXT: br bb4
|
|
// CHECK: bb4:
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil [ossa] @tail_merging : $@convention(thin) (@in S) -> () {
|
|
bb0(%0 : $*S):
|
|
cond_br undef, bb1, bb2
|
|
bb1:
|
|
%f = function_ref @use_S : $@convention(thin) (@in_guaranteed S) -> ()
|
|
%a = apply %f(%0) : $@convention(thin) (@in_guaranteed S) -> ()
|
|
br bb3
|
|
bb2:
|
|
br bb3
|
|
bb3:
|
|
br bb4
|
|
bb4:
|
|
destroy_addr %0 : $*S
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @store_splitting
|
|
// CHECK: destroy_addr %0
|
|
// CHECK-NEXT: store %1 to [init] %0
|
|
// CHECK: return
|
|
sil [ossa] @store_splitting : $@convention(thin) (@inout S, @owned S, @guaranteed TwoCases) -> () {
|
|
bb0(%0 : $*S, %1 : @owned $S, %2 : @guaranteed $TwoCases):
|
|
switch_enum %2 : $TwoCases, case #TwoCases.A!enumelt: bb1, case #TwoCases.B!enumelt: bb2
|
|
|
|
bb1(%4 : @guaranteed $X):
|
|
%5 = enum $TwoCases, #TwoCases.B!enumelt
|
|
store %1 to [assign] %0 : $*S
|
|
br bb3
|
|
|
|
bb2:
|
|
destroy_value %1 : $S
|
|
br bb3
|
|
|
|
bb3:
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// Check several things: critical edge splitting, handling of sub-locations, complex control flow
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_complex
|
|
// CHECK: bb0(%0 : $*Outer, %1 : $*Outer):
|
|
// CHECK: [[OOX:%[0-9]+]] = struct_element_addr %0 : $*Outer, #Outer.ox
|
|
// CHECK-NEXT: destroy_addr [[OOX]]
|
|
// CHECK: [[OS:%[0-9]+]] = struct_element_addr %0 : $*Outer, #Outer.s
|
|
// CHECK: cond_br undef, bb1, bb2
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: destroy_addr [[OS]]
|
|
// CHECK-NEXT: br bb4
|
|
// CHECK: bb4:
|
|
// CHECK: apply
|
|
// CHECK: cond_br undef, bb5, bb6
|
|
// CHECK: bb5:
|
|
// CHECK-NEXT: br bb4
|
|
// CHECK: bb6:
|
|
// CHECK-NEXT: destroy_addr %1
|
|
// CHECK: br bb7
|
|
// CHECK: bb7:
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil [ossa] @test_complex : $@convention(thin) (@in Outer, @in Outer) -> () {
|
|
bb0(%0 : $*Outer, %1 : $*Outer):
|
|
%f = function_ref @use_S : $@convention(thin) (@in_guaranteed S) -> ()
|
|
%2 = struct_element_addr %0 : $*Outer, #Outer.s
|
|
cond_br undef, bb1, bb2
|
|
bb1:
|
|
%a1 = apply %f(%2) : $@convention(thin) (@in_guaranteed S) -> ()
|
|
br bb3
|
|
bb2:
|
|
br bb3
|
|
bb3:
|
|
br bb4
|
|
bb4:
|
|
%4 = struct_element_addr %1 : $*Outer, #Outer.s
|
|
%a2 = apply %f(%4) : $@convention(thin) (@in_guaranteed S) -> ()
|
|
cond_br undef, bb5, bb6
|
|
bb5:
|
|
br bb4
|
|
bb6:
|
|
destroy_addr %2 : $*S
|
|
%3 = struct_element_addr %0 : $*Outer, #Outer.ox
|
|
destroy_addr %3 : $*X
|
|
br bb7
|
|
bb7:
|
|
destroy_addr %1 : $*Outer
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_mixed
|
|
// CHECK: load
|
|
// CHECK: destroy_addr %0
|
|
// CHECK: br bb1
|
|
// CHECK: return
|
|
sil [ossa] @test_mixed : $@convention(thin) (@in Mixed) -> Int {
|
|
bb0(%0 : $*Mixed):
|
|
%2 = struct_element_addr %0 : $*Mixed, #Mixed.i
|
|
%v = load [trivial] %2 : $*Int
|
|
br bb1
|
|
bb1:
|
|
destroy_addr %0 : $*Mixed
|
|
return %v : $Int
|
|
}
|
|
|
|
sil @coro : $@yield_once @convention(thin) (@in S) -> @yields @inout Int
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_begin_apply
|
|
// CHECK: end_apply
|
|
// CHECK-NEXT: destroy_addr %0
|
|
// CHECK-NEXT: br bb1
|
|
// CHECK: bb1:
|
|
// CHECK: return
|
|
sil [ossa] @test_begin_apply : $@convention(thin) (@in S, Int) -> () {
|
|
bb0(%0 : $*S, %1 : $Int):
|
|
%f = function_ref @coro : $@yield_once @convention(thin) (@in S) -> @yields @inout Int
|
|
(%i, %t) = begin_apply %f(%0) : $@yield_once @convention(thin) (@in S) -> @yields @inout Int
|
|
store %1 to [trivial] %i : $*Int
|
|
end_apply %t
|
|
br bb1
|
|
bb1:
|
|
destroy_addr %0 : $*S
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_abort_apply
|
|
// CHECK: abort_apply
|
|
// CHECK-NEXT: destroy_addr %0
|
|
// CHECK-NEXT: br bb1
|
|
// CHECK: bb1:
|
|
// CHECK: return
|
|
sil [ossa] @test_abort_apply : $@convention(thin) (@in S, Int) -> () {
|
|
bb0(%0 : $*S, %1 : $Int):
|
|
%f = function_ref @coro : $@yield_once @convention(thin) (@in S) -> @yields @inout Int
|
|
(%i, %t) = begin_apply %f(%0) : $@yield_once @convention(thin) (@in S) -> @yields @inout Int
|
|
abort_apply %t
|
|
br bb1
|
|
bb1:
|
|
destroy_addr %0 : $*S
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_simple_infinite_loop
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: } // end sil function 'test_simple_infinite_loop'
|
|
sil [ossa] @test_simple_infinite_loop : $@convention(thin) (@in_guaranteed S) -> () {
|
|
bb0(%0 : $*S):
|
|
br bb1
|
|
bb1:
|
|
br bb1
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_infinite_loop
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: bb4:
|
|
// CHECK-NEXT: destroy_addr %1
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: } // end sil function 'test_infinite_loop'
|
|
sil [ossa] @test_infinite_loop : $@convention(thin) (@in_guaranteed S, @in S) -> () {
|
|
bb0(%0 : $*S, %1 : $*S):
|
|
cond_br undef, bb1, bb4
|
|
bb1:
|
|
br bb2
|
|
bb2:
|
|
br bb3
|
|
bb3:
|
|
br bb2
|
|
bb4:
|
|
br bb5
|
|
bb5:
|
|
destroy_addr %1 : $*S
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_debug_value
|
|
// CHECK: bb0({{.*}}):
|
|
// CHECK-NEXT: struct_element_addr
|
|
// CHECK-NEXT: destroy_addr
|
|
// CHECK-NEXT: br bb1
|
|
// CHECK: } // end sil function 'test_debug_value'
|
|
sil [ossa] @test_debug_value : $@convention(method) (@inout S2, @owned X, @owned S, @inout E) -> () {
|
|
bb0(%0 : $*S2, %1 : @owned $X, %2 : @owned $S, %3 : $*E):
|
|
debug_value %0 : $*S2, var, name "self", argno 1, expr op_deref
|
|
br bb1
|
|
|
|
bb1:
|
|
%60 = struct_element_addr %0 : $*S2, #S2.s
|
|
destroy_addr %60 : $*S
|
|
store %2 to [init] %60 : $*S
|
|
%71 = struct_element_addr %60 : $*S, #S.x
|
|
store %1 to [assign] %71 : $*X
|
|
|
|
%75 = tuple ()
|
|
return %75 : $()
|
|
}
|
|
|
|
sil [ossa] @closure_inout : $@convention(thin) (@inout X) -> ()
|
|
sil [ossa] @closure_inout_aliasable : $@convention(thin) (@inout_aliasable X) -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_closure_inout :
|
|
// CHECK: partial_apply
|
|
// CHECK-NEXT: = apply
|
|
// CHECK-NEXT: destroy_addr %0
|
|
// CHECK: } // end sil function 'test_closure_inout'
|
|
sil [ossa] @test_closure_inout : $@convention(thin) (@in X) -> () {
|
|
bb0(%0 : $*X):
|
|
%func = function_ref @closure_inout : $@convention(thin) (@inout X) -> ()
|
|
%pa = partial_apply %func(%0) : $@convention(thin) (@inout X) -> ()
|
|
apply %pa() : $@callee_owned () -> ()
|
|
destroy_addr %0 : $*X
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_closure_inout_aliasable :
|
|
// CHECK: partial_apply
|
|
// CHECK-NEXT: = apply
|
|
// CHECK-NEXT: destroy_addr %0
|
|
// CHECK: } // end sil function 'test_closure_inout_aliasable'
|
|
sil [ossa] @test_closure_inout_aliasable : $@convention(thin) (@in X) -> () {
|
|
bb0(%0 : $*X):
|
|
%func = function_ref @closure_inout_aliasable : $@convention(thin) (@inout_aliasable X) -> ()
|
|
%pa = partial_apply %func(%0) : $@convention(thin) (@inout_aliasable X) -> ()
|
|
apply %pa() : $@callee_owned () -> ()
|
|
destroy_addr %0 : $*X
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_switch_enum_addr :
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: switch_enum_addr
|
|
// CHECK: } // end sil function 'test_switch_enum_addr'
|
|
sil [ossa] @test_switch_enum_addr : $@convention(thin) (@in TwoCases) -> () {
|
|
bb0(%0 : $*TwoCases):
|
|
%2 = alloc_stack $TwoCases
|
|
copy_addr %0 to [init] %2 : $*TwoCases
|
|
switch_enum_addr %2 : $*TwoCases, case #TwoCases.A!enumelt: bb1, case #TwoCases.B!enumelt: bb2
|
|
|
|
bb1:
|
|
destroy_addr %2 : $*TwoCases
|
|
dealloc_stack %2 : $*TwoCases
|
|
br bb3
|
|
|
|
bb2:
|
|
destroy_addr %2 : $*TwoCases
|
|
dealloc_stack %2 : $*TwoCases
|
|
br bb3
|
|
|
|
bb3:
|
|
destroy_addr %0 : $*TwoCases
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_load_borrow1 :
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: load_borrow
|
|
// CHECK-LABEL: } // end sil function 'test_load_borrow1'
|
|
sil [ossa] @test_load_borrow1 : $@convention(thin) (@in TwoCases) -> () {
|
|
bb0(%0 : $*TwoCases):
|
|
%2 = alloc_stack $TwoCases
|
|
copy_addr %0 to [init] %2 : $*TwoCases
|
|
%ld = load_borrow %2 : $*TwoCases
|
|
br bb1(%ld : $TwoCases)
|
|
|
|
bb1(%newld : @guaranteed $TwoCases):
|
|
end_borrow %newld : $TwoCases
|
|
br bb2
|
|
|
|
bb2:
|
|
destroy_addr %2 : $*TwoCases
|
|
dealloc_stack %2 : $*TwoCases
|
|
br bb3
|
|
|
|
bb3:
|
|
destroy_addr %0 : $*TwoCases
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_load_borrow2 :
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: load_borrow
|
|
// CHECK-LABEL: } // end sil function 'test_load_borrow2'
|
|
sil [ossa] @test_load_borrow2 : $@convention(thin) (@in TwoCases) -> () {
|
|
bb0(%0 : $*TwoCases):
|
|
%2 = alloc_stack $TwoCases
|
|
copy_addr %0 to [init] %2 : $*TwoCases
|
|
%ld = load_borrow %2 : $*TwoCases
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
end_borrow %ld : $TwoCases
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb2a(%ld : $TwoCases)
|
|
|
|
bb2a(%newld : @guaranteed $TwoCases):
|
|
end_borrow %newld : $TwoCases
|
|
br bb3
|
|
|
|
bb3:
|
|
destroy_addr %2 : $*TwoCases
|
|
dealloc_stack %2 : $*TwoCases
|
|
br bb3
|
|
|
|
bb4:
|
|
destroy_addr %0 : $*TwoCases
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_begin_access :
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: begin_access
|
|
// CHECK-LABEL: } // end sil function 'test_begin_access'
|
|
sil [ossa] @test_begin_access : $@convention(thin) (@in X) -> () {
|
|
bb0(%0 : $*X):
|
|
%a = begin_access [read] [dynamic] %0 : $*X
|
|
br bb1
|
|
|
|
bb1:
|
|
end_access %a : $*X
|
|
destroy_addr %0 : $*X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|