Files
swift-mirror/test/SILOptimizer/mem2reg_borrows.sil
Meghana Gupta 4c46faad26 Fix mem2reg for load_borrows with reborrows
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
2025-03-04 10:18:08 -08:00

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