mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
@guaranteed stored values will never be added to a phi in mem2reg because any uses of store borrowed locations have to be accessed via the store borrow return address and since we ban address phis altogether we will never have input sil which necessitates this. But, the DJ-edges based algorithm for inserting phi blocks in mem2reg can insert unnecessary phis which are removed later. Ensure fixPhiPredBlock handles both owned and guaranteed stored values correctly for this reason.
411 lines
13 KiB
Plaintext
411 lines
13 KiB
Plaintext
// RUN: %target-sil-opt -enable-sil-verify-all -enable-lexical-lifetimes %s -mem2reg | %FileCheck %s
|
|
import Builtin
|
|
|
|
class Klass {}
|
|
|
|
struct WrapperStruct {
|
|
var val:Klass
|
|
}
|
|
|
|
sil [ossa] @use_inguaranteed : $@convention(thin) (@in_guaranteed Klass) -> ()
|
|
sil [ossa] @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
sil [ossa] @use_owned : $@convention(thin) (@owned Klass) -> ()
|
|
sil [ossa] @get_owned : $@convention(thin) () -> @owned Klass
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_no_storeborrow1 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test_no_storeborrow1'
|
|
sil [ossa] @test_no_storeborrow1 : $@convention(thin) (@owned Klass) -> () {
|
|
bb0(%0 : @owned $Klass):
|
|
%stk = alloc_stack $Klass
|
|
store %0 to [init] %stk : $*Klass
|
|
%ld = load_borrow %stk : $*Klass
|
|
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%4 = apply %3(%ld) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %ld : $Klass
|
|
destroy_addr %stk : $*Klass
|
|
dealloc_stack %stk : $*Klass
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_no_storeborrow2 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test_no_storeborrow2'
|
|
sil [ossa] @test_no_storeborrow2 : $@convention(method) (@owned Klass) -> () {
|
|
bb0(%0 : @owned $Klass):
|
|
%stk = alloc_stack $Klass
|
|
store %0 to [init] %stk : $*Klass
|
|
%ld1 = load_borrow %stk : $*Klass
|
|
%f = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %f(%ld1) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %ld1 : $Klass
|
|
cond_br undef, bb3, bb1
|
|
|
|
bb1:
|
|
%ld2 = load_borrow %stk : $*Klass
|
|
apply %f(%ld2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %ld2 : $Klass
|
|
%tk1 = load [take] %stk : $*Klass
|
|
destroy_value %tk1 : $Klass
|
|
dealloc_stack %stk : $*Klass
|
|
br bb4
|
|
|
|
bb3:
|
|
%tk2 = load [take] %stk : $*Klass
|
|
destroy_value %tk2 : $Klass
|
|
dealloc_stack %stk : $*Klass
|
|
br bb4
|
|
|
|
bb4:
|
|
%ret = tuple ()
|
|
return %ret : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_no_storeborrow3 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test_no_storeborrow3'
|
|
sil [ossa] @test_no_storeborrow3 : $@convention(thin) (@owned Klass) -> () {
|
|
bb0(%0 : @owned $Klass):
|
|
%1 = alloc_stack $Klass
|
|
store %0 to [init] %1 : $*Klass
|
|
%2 = load_borrow %1 : $*Klass
|
|
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %2 : $Klass
|
|
destroy_addr %1 : $*Klass
|
|
dealloc_stack %1 : $*Klass
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// load_borrow of projections are not optimized
|
|
// CHECK-LABEL: sil [ossa] @test_with_structs_and_borrows1 :
|
|
// CHECK: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test_with_structs_and_borrows1'
|
|
sil [ossa] @test_with_structs_and_borrows1 : $@convention(thin) (@guaranteed WrapperStruct) -> () {
|
|
bb0(%0 : @guaranteed $WrapperStruct):
|
|
%stk = alloc_stack $WrapperStruct
|
|
%sb = store_borrow %0 to %stk : $*WrapperStruct
|
|
%ele = struct_element_addr %sb : $*WrapperStruct, #WrapperStruct.val
|
|
%ld = load_borrow %ele : $*Klass
|
|
%f = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %f(%ld) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %ld : $Klass
|
|
end_borrow %sb : $*WrapperStruct
|
|
dealloc_stack %stk : $*WrapperStruct
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
// CHECK-LABEL: sil [ossa] @storeborrow_only_allocas :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'storeborrow_only_allocas'
|
|
sil [ossa] @storeborrow_only_allocas : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = alloc_stack $Klass
|
|
%2 = store_borrow %0 to %1 : $*Klass
|
|
end_borrow %2 : $*Klass
|
|
dealloc_stack %1 : $*Klass
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test1 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test1'
|
|
sil [ossa] @test1 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = alloc_stack $Klass
|
|
%sb = store_borrow %0 to %1 : $*Klass
|
|
%2 = load_borrow %sb : $*Klass
|
|
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %2 : $Klass
|
|
end_borrow %sb : $*Klass
|
|
dealloc_stack %1 : $*Klass
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test1_lexical :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test1_lexical'
|
|
sil [ossa] @test1_lexical : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = alloc_stack [lexical] $Klass
|
|
%sb = store_borrow %0 to %1 : $*Klass
|
|
%2 = load_borrow %sb : $*Klass
|
|
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %2 : $Klass
|
|
end_borrow %sb : $*Klass
|
|
dealloc_stack %1 : $*Klass
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test2 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test2'
|
|
sil [ossa] @test2 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = alloc_stack $Klass
|
|
%sb = store_borrow %0 to %1 : $*Klass
|
|
%2 = load_borrow %sb : $*Klass
|
|
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %2 : $Klass
|
|
%5 = load_borrow %sb : $*Klass
|
|
%6 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%7 = apply %3(%5) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %5 : $Klass
|
|
end_borrow %sb : $*Klass
|
|
dealloc_stack %1 : $*Klass
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test3 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test3'
|
|
sil [ossa] @test3 : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass):
|
|
%2 = alloc_stack $Klass
|
|
%sb1 = store_borrow %0 to %2 : $*Klass
|
|
%3 = load_borrow %sb1 : $*Klass
|
|
%4 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%5 = apply %4(%3) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %3 : $Klass
|
|
end_borrow %sb1 : $*Klass
|
|
%sb2 = store_borrow %1 to %2 : $*Klass
|
|
%6 = load_borrow %sb2 : $*Klass
|
|
%7 = apply %4(%6) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %6 : $Klass
|
|
end_borrow %sb2 : $*Klass
|
|
dealloc_stack %2 : $*Klass
|
|
%9 = tuple ()
|
|
return %9 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test4 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test4'
|
|
sil [ossa] @test4 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = alloc_stack $Klass
|
|
%sb = store_borrow %0 to %1 : $*Klass
|
|
%2 = load_borrow %sb: $*Klass
|
|
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %2 : $Klass
|
|
%5 = load [copy] %sb : $*Klass
|
|
%6 = function_ref @use_owned : $@convention(thin) (@owned Klass) -> ()
|
|
%7 = apply %6(%5) : $@convention(thin) (@owned Klass) -> ()
|
|
end_borrow %sb : $*Klass
|
|
dealloc_stack %1 : $*Klass
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test6 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test6'
|
|
sil [ossa] @test6 : $@convention(thin) (@owned Klass) -> () {
|
|
bb0(%0 : @owned $Klass):
|
|
%1 = alloc_stack $Klass
|
|
%b = begin_borrow %0 : $Klass
|
|
%sb = store_borrow %b to %1 : $*Klass
|
|
%2 = load_borrow %sb : $*Klass
|
|
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %2 : $Klass
|
|
end_borrow %sb : $*Klass
|
|
end_borrow %b : $Klass
|
|
destroy_value %0 : $Klass
|
|
dealloc_stack %1 : $*Klass
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
sil [ossa] @test_control_flow1 : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%stk = alloc_stack $Klass
|
|
%sb = store_borrow %0 to %stk : $*Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%ld1 = load_borrow %sb : $*Klass
|
|
fix_lifetime %ld1 : $Klass
|
|
end_borrow %ld1 : $Klass
|
|
end_borrow %sb : $*Klass
|
|
dealloc_stack %stk : $*Klass
|
|
%r = tuple ()
|
|
return %r : $()
|
|
|
|
bb2:
|
|
%ld2 = load_borrow %sb : $*Klass
|
|
fix_lifetime %ld2 : $Klass
|
|
end_borrow %ld2 : $Klass
|
|
end_borrow %sb : $*Klass
|
|
dealloc_stack %stk : $*Klass
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_control_flow2 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test_control_flow2'
|
|
sil [ossa] @test_control_flow2 : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass):
|
|
%stk = alloc_stack $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%copy1 = copy_value %0 : $Klass
|
|
store %copy1 to [init] %stk : $*Klass
|
|
br bb3
|
|
|
|
bb2:
|
|
%copy2 = copy_value %1 : $Klass
|
|
store %copy2 to [init] %stk : $*Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
%2 = load_borrow %stk : $*Klass
|
|
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %2 : $Klass
|
|
destroy_addr %stk : $*Klass
|
|
dealloc_stack %stk : $*Klass
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_control_flow3 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test_control_flow3'
|
|
sil [ossa] @test_control_flow3 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%4 = alloc_stack [lexical] $Klass
|
|
%f = function_ref @get_owned : $@convention(thin) () -> @owned Klass
|
|
%5 = apply %f() : $@convention(thin) () -> @owned Klass
|
|
store %5 to [init] %4 : $*Klass
|
|
%7 = load_borrow %4 : $*Klass
|
|
end_borrow %7 : $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb2:
|
|
%28 = load_borrow %4 : $*Klass
|
|
end_borrow %28 : $Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
destroy_addr %4 : $*Klass
|
|
dealloc_stack %4 : $*Klass
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_control_flow4 :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test_control_flow4'
|
|
sil [ossa] @test_control_flow4 : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass):
|
|
%stk = alloc_stack [lexical] $Klass
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%copy1 = copy_value %0 : $Klass
|
|
store %copy1 to [init] %stk : $*Klass
|
|
br bb3
|
|
|
|
bb2:
|
|
%copy2 = copy_value %1 : $Klass
|
|
store %copy2 to [init] %stk : $*Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
%2 = load_borrow %stk : $*Klass
|
|
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %2 : $Klass
|
|
destroy_addr %stk : $*Klass
|
|
dealloc_stack %stk : $*Klass
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_store_borrow_use_in_block_without_alloc_stack_use : {{.*}} {
|
|
// CHECK: [[OWNED:%[^,]+]] = apply
|
|
// CHECK: [[GUARANTEED:%[^,]+]] = begin_borrow [[OWNED]]
|
|
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[GUARANTEED]]
|
|
// CHECK: apply undef([[LIFETIME]]) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
// CHECK: br [[MIDDLE:bb[0-9]+]]
|
|
// CHECK: [[MIDDLE]]:
|
|
// CHECK: end_borrow [[LIFETIME]]
|
|
// CHECK: br [[EXIT:bb[0-9]+]]
|
|
// CHECK: [[EXIT]]:
|
|
// CHECK: end_borrow [[GUARANTEED]]
|
|
// CHECK: destroy_value [[OWNED]]
|
|
// CHECK-LABEL: } // end sil function 'test_store_borrow_use_in_block_without_alloc_stack_use'
|
|
sil [ossa] @test_store_borrow_use_in_block_without_alloc_stack_use : $@convention(thin) () -> () {
|
|
bb0:
|
|
%owned = apply undef() : $@convention(thin) () -> (@owned Klass)
|
|
%guaranteed = begin_borrow %owned : $Klass
|
|
%stack = alloc_stack [lexical] $Klass
|
|
%stored = store_borrow %guaranteed to %stack : $*Klass
|
|
%load = load_borrow %stored : $*Klass
|
|
apply undef(%load) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %load : $Klass
|
|
br bb1
|
|
|
|
bb1:
|
|
end_borrow %stored : $*Klass
|
|
br bb3
|
|
|
|
bb3:
|
|
dealloc_stack %stack : $*Klass
|
|
end_borrow %guaranteed : $Klass
|
|
destroy_value %owned : $Klass
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Ensure we don't have an ownership verification error
|
|
sil [ossa] @test_store_borrow_phi : $@convention(thin) () -> () {
|
|
bb0:
|
|
br bb1
|
|
|
|
bb1:
|
|
%1 = apply undef() : $@convention(thin) () -> @owned Klass
|
|
%2 = begin_borrow %1 : $Klass
|
|
%3 = alloc_stack $Klass
|
|
%4 = store_borrow %2 to %3 : $*Klass
|
|
%5 = load_borrow %4 : $*Klass
|
|
%6 = apply undef(%5) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %5 : $Klass
|
|
end_borrow %4 : $*Klass
|
|
cond_br undef, bb2, bb3
|
|
|
|
bb2:
|
|
br bb4
|
|
|
|
bb3:
|
|
br bb4
|
|
|
|
bb4:
|
|
dealloc_stack %3 : $*Klass
|
|
end_borrow %2 : $Klass
|
|
destroy_value %1 : $Klass
|
|
cond_br undef, bb5, bb6
|
|
|
|
bb5:
|
|
br bb1
|
|
|
|
bb6:
|
|
%17 = tuple ()
|
|
return %17 : $()
|
|
}
|