Files
swift-mirror/test/SILOptimizer/mem2reg_borrows.sil
Meghana Gupta 0b835f0080 Fix ownership verification error due to multi block mem2reg with store_borrows
@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.
2023-04-21 12:29:18 -07:00

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