mirror of
https://github.com/apple/swift.git
synced 2026-10-16 16:50:49 +02:00
For now, create a new ClassDestroyDevirtualizer pass, which is basically a copy of the old ReleaseDevirtualizer pass, just with support for OSSA. We still don't have OSSA in the pipeline where the pass runs. So we need to keep the old pass around. The new pass is a no-op until we extend OSSA to this part of the pipeline. Then we can delete the old pass. The new pass is named ClassDestroyDevirtualizer to distinguish the optimization from de-virtualizing value-type deinits.
283 lines
8.1 KiB
Plaintext
283 lines
8.1 KiB
Plaintext
// RUN: %target-sil-opt -enable-sil-verify-all %s -class-destroy-devirtualizer -module-name=test | %FileCheck %s
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
class B {
|
|
@_hasStorage var next: B
|
|
}
|
|
|
|
struct Str {
|
|
@_hasStorage var b: B
|
|
}
|
|
|
|
sil @unknown_func : $@convention(thin) () -> ()
|
|
sil @unknown_releaseing_func : $@convention(thin) (@owned B) -> ()
|
|
|
|
sil [ossa] @$s4test1BCfD : $@convention(method) (@owned B) -> () {
|
|
// Note that the destructor is not destroying, but it must block the optimization.
|
|
[global: ]
|
|
bb0(%0 : @owned $B):
|
|
dealloc_ref %0
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @devirtualize_object :
|
|
// CHECK: [[A:%[0-9]+]] = alloc_ref
|
|
// CHECK-NEXT: [[BD:%.*]] = begin_dealloc_ref [[A]] of [[A]]
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: [[D:%[0-9]+]] = function_ref @$s4test1BCfD
|
|
// CHECK-NEXT: apply [[D]]([[BD]])
|
|
// CHECK-NEXT: dealloc_stack_ref [[A]]
|
|
// CHECK: } // end sil function 'devirtualize_object'
|
|
sil [ossa] @devirtualize_object : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_ref [stack] $B
|
|
destroy_value %1
|
|
dealloc_stack_ref %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_devirtualize_heap_allocated :
|
|
// CHECK: alloc_ref
|
|
// CHECK-NEXT: destroy_value
|
|
// CHECK: } // end sil function 'dont_devirtualize_heap_allocated'
|
|
sil [ossa] @dont_devirtualize_heap_allocated : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_ref $B
|
|
destroy_value %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_devirtualize_devirtualized
|
|
// CHECK: alloc_ref
|
|
// CHECK-NEXT: copy_value
|
|
// CHECK-NEXT: destroy_value
|
|
// CHECK-NEXT: begin_dealloc_ref
|
|
// CHECK-NEXT: dealloc_ref
|
|
// CHECK-NEXT: dealloc_stack_ref
|
|
// CHECK-NEXT: tuple
|
|
// CHECK: } // end sil function 'dont_devirtualize_devirtualized'
|
|
sil [ossa] @dont_devirtualize_devirtualized : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_ref [stack] $B
|
|
%2 = copy_value %1
|
|
destroy_value %2
|
|
%4 = begin_dealloc_ref %1 of %1
|
|
dealloc_ref %4
|
|
dealloc_stack_ref %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_devirtualize_devirtualized_not_inlined :
|
|
// CHECK: alloc_ref
|
|
// CHECK-NEXT: copy_value
|
|
// CHECK-NEXT: destroy_value
|
|
// CHECK-NEXT: begin_dealloc_ref
|
|
// CHECK: } // end sil function 'dont_devirtualize_devirtualized_not_inlined'
|
|
sil [ossa] @dont_devirtualize_devirtualized_not_inlined : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_ref [stack] $B
|
|
%2 = copy_value %1
|
|
destroy_value %2
|
|
%4 = begin_dealloc_ref %1 of %1
|
|
%5 = function_ref @$s4test1BCfD : $@convention(method) (@owned B) -> ()
|
|
%6 = apply %5(%4) : $@convention(method) (@owned B) -> ()
|
|
dealloc_stack_ref %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @devirtualize_with_other_destroys_in_between :
|
|
// CHECK: %1 = alloc_ref [stack] $B
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: apply
|
|
// CHECK-NEXT: destroy_value %0
|
|
// CHECK-NEXT: dealloc_stack_ref %1
|
|
// CHECK: } // end sil function 'devirtualize_with_other_destroys_in_between'
|
|
sil [ossa] @devirtualize_with_other_destroys_in_between : $@convention(thin) (@owned B) -> () {
|
|
bb0(%0 : @owned $B):
|
|
%1 = alloc_ref [stack] $B
|
|
destroy_value %1
|
|
destroy_value %0
|
|
dealloc_stack_ref %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @devirtualize_with_apply_in_between :
|
|
// CHECK: alloc_ref
|
|
// CHECK-NEXT: begin_dealloc_ref
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: } // end sil function 'devirtualize_with_apply_in_between'
|
|
sil [ossa] @devirtualize_with_apply_in_between : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_ref [stack] $B
|
|
destroy_value %1 : $B
|
|
%f = function_ref @unknown_func : $@convention(thin) () -> ()
|
|
%a = apply %f() : $@convention(thin) () -> ()
|
|
dealloc_stack_ref %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_devirtualize_unknown_destroy :
|
|
// CHECK: alloc_ref
|
|
// CHECK-NEXT: copy_value
|
|
// CHECK-NEXT: destroy_value
|
|
// CHECK: } // end sil function 'dont_devirtualize_unknown_destroy'
|
|
sil [ossa] @dont_devirtualize_unknown_destroy : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_ref [stack] $B
|
|
%2 = copy_value %1
|
|
destroy_value %2
|
|
%f = function_ref @unknown_releaseing_func : $@convention(thin) (@owned B) -> ()
|
|
%a = apply %f(%1) : $@convention(thin) (@owned B) -> ()
|
|
dealloc_stack_ref %1
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_crash_with_missing_destroy
|
|
// CHECK: [[A:%[0-9]+]] = alloc_ref
|
|
// CHECK-NEXT: [[BD:%.*]] = begin_dealloc_ref [[A]] of [[A]]
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: [[D:%[0-9]+]] = function_ref @$s4test1BCfD
|
|
// CHECK-NEXT: apply [[D]]([[BD]])
|
|
// CHECK-NEXT: dealloc_stack_ref [[A]]
|
|
// CHECK: } // end sil function 'dont_crash_with_missing_destroy'
|
|
sil [ossa] @dont_crash_with_missing_destroy : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_ref [stack] $B
|
|
destroy_value %1 : $B
|
|
dealloc_stack_ref %1
|
|
%2 = alloc_ref [stack] $B
|
|
end_lifetime %2
|
|
dealloc_stack_ref %2
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @long_chain_from_alloc_to_destroy
|
|
// CHECK: bb3([[P:%.*]] : @owned $B):
|
|
// CHECK: [[T:%.*]] = tuple ({{.*}})
|
|
// CHECK: ([[S:%.*]], {{.*}}) = destructure_tuple [[T]]
|
|
// CHECK: [[A:%.*]] = destructure_struct [[S]]
|
|
// CHECK: begin_dealloc_ref [[A]]
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: } // end sil function 'long_chain_from_alloc_to_destroy'
|
|
sil [ossa] @long_chain_from_alloc_to_destroy : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_ref [stack] $B
|
|
%2 = struct $Str(%1)
|
|
%3 = destructure_struct %2
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3(%3)
|
|
|
|
bb2:
|
|
br bb3(%3)
|
|
|
|
bb3(%a : @owned $B):
|
|
%s = struct $Str (%a)
|
|
%i = integer_literal $Builtin.Int64, 0
|
|
%t = tuple (%s, %i)
|
|
destroy_value %t
|
|
dealloc_stack_ref %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_devirtualize_double_destroy
|
|
// CHECK-NOT: begin_dealloc_ref
|
|
// CHECK: destroy_value
|
|
// CHECK: } // end sil function 'dont_devirtualize_double_destroy'
|
|
sil [ossa] @dont_devirtualize_double_destroy : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_ref [stack] $B
|
|
%2 = copy_value %1
|
|
%t = tuple (%1, %2)
|
|
destroy_value %t : $(B, B)
|
|
dealloc_stack_ref %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_devirtualize_destroy_of_load
|
|
// CHECK: [[L:%.*]] = load
|
|
// CHECK: [[D:%[0-9]+]] = function_ref @$s4test1BCfD
|
|
// CHECK-NEXT: apply [[D]]
|
|
// CHECK-NEXT: destroy_value [[L]]
|
|
// CHECK: } // end sil function 'dont_devirtualize_destroy_of_load'
|
|
sil [ossa] @dont_devirtualize_destroy_of_load : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_ref [stack] $B
|
|
%2 = begin_borrow %1
|
|
%3 = ref_element_addr %2, #B.next
|
|
%4 = load [copy] %3
|
|
end_borrow %2
|
|
destroy_value %1
|
|
destroy_value %4
|
|
dealloc_stack_ref %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dont_devirtualize_destroy_of_different_allocations
|
|
// CHECK-NOT: begin_dealloc_ref
|
|
// CHECK: bb3([[P:%.*]] : @owned $B):
|
|
// CHECK: destroy_value [[P]]
|
|
// CHECK: } // end sil function 'dont_devirtualize_destroy_of_different_allocations'
|
|
sil [ossa] @dont_devirtualize_destroy_of_different_allocations : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_ref [stack] $B
|
|
%2 = alloc_ref [stack] $B
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
destroy_value %2
|
|
br bb3(%1)
|
|
|
|
bb2:
|
|
destroy_value %1
|
|
br bb3(%2)
|
|
|
|
bb3(%a : @owned $B):
|
|
destroy_value %a
|
|
dealloc_stack_ref %2
|
|
dealloc_stack_ref %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @devirtualize_double_destroy :
|
|
// CHECK-NOT: destroy_value
|
|
// CHECK: } // end sil function 'devirtualize_double_destroy'
|
|
sil [ossa] @devirtualize_double_destroy : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_ref [stack] $B
|
|
%1 = end_init_let_ref %0
|
|
%2 = alloc_ref [stack] $B
|
|
%3 = end_init_let_ref %2
|
|
destroy_value %1
|
|
destroy_value %3
|
|
%4 = function_ref @unknown_func : $@convention(thin) () -> ()
|
|
%5 = apply %4() : $@convention(thin) () -> ()
|
|
dealloc_stack_ref %2
|
|
dealloc_stack_ref %0
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
sil_vtable B {
|
|
#B.deinit!deallocator: @$s4test1BCfD
|
|
}
|
|
|