Files
swift-mirror/test/SILOptimizer/destroy_hoisting.sil
Nate Chandler ed623d7b64 [NFC] Shortened SIL [init] flag.
Instead of writing out [initalization] for some instructions, use [init]
everywhere.
2022-10-27 10:38:54 -07:00

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 : $()
}