mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
StackAllocationPromoter::pruneAllocStackUsage substitutes loads/stores of alloc_stack with values. For some reason isLoadFromStack was bailing out for load_borrows with reborrows leaving them to be fixed up by fixBranchesAndUses which uses live in value from predecessors for substitution which is obviosly incorrect the block containing the load_borrow has a store before it. Fixes rdar://145834542
438 lines
14 KiB
Plaintext
438 lines
14 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 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_load_borrow_with_reborrow :
|
|
// CHECK-NOT: alloc_stack
|
|
// CHECK-LABEL: } // end sil function 'test_load_borrow_with_reborrow'
|
|
sil [ossa] @test_load_borrow_with_reborrow : $@convention(thin) () -> () {
|
|
bb0:
|
|
%owned = apply undef() : $@convention(thin) () -> (@owned Klass)
|
|
%stack = alloc_stack [lexical] $Klass
|
|
store %owned to [init] %stack : $*Klass
|
|
br bb1
|
|
|
|
bb1:
|
|
%ld = load [take] %stack : $*Klass
|
|
destroy_value %ld
|
|
%owned_other = apply undef() : $@convention(thin) () -> (@owned Klass)
|
|
store %owned_other to [init] %stack : $*Klass
|
|
%lb = load_borrow %stack
|
|
br bb2(%lb)
|
|
|
|
bb2(%reborrow : @reborrow $Klass):
|
|
end_borrow %reborrow : $Klass
|
|
destroy_addr %stack : $*Klass
|
|
dealloc_stack %stack : $*Klass
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|