Files
swift-mirror/test/IRGen/objc_dealloc.sil
Erik Eckstein 18063707b5 Optimizer: enable complete OSSA lifetimes throughout the pass pipeline
This new OSSA invariant simplifies many optimizations because they don't have to take care of the corner case of incomplete lifetimes in dead-end blocks.

The implementation basically consists of these changes:
* add the lifetime completion utility
* add a flag in SILFunction which tells optimization that they need to run the lifetime completion utility
* let all optimizations complete lifetimes if necessary
* enable the ownership verifier to check complete lifetimes
2026-01-22 17:41:48 +01:00

129 lines
5.6 KiB
Plaintext

// RUN: %empty-directory(%t)
// RUN: %build-irgen-test-overlays
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) %s -emit-ir | %FileCheck %s
// REQUIRES: CPU=arm64 || CPU=arm64e || CPU=x86_64
// REQUIRES: objc_interop
sil_stage raw
import Builtin
import Swift
import gizmo
class X { }
sil_vtable X {}
sil @$s12objc_dealloc1XCfD : $@convention(method) (X) -> ()
func onDestruct() { }
class SwiftGizmo : Gizmo {
var x : X
override init()
deinit
}
sil_vtable SwiftGizmo {}
sil @$s12objc_dealloc10SwiftGizmoCfD : $@convention(method) (SwiftGizmo) -> ()
sil @$s12objc_dealloc10onDestructyyF : $@convention(thin) () -> () {
bb0:
%0 = tuple ()
%1 = tuple () // user: %2
return %1 : $() // id: %2
}
sil [ossa] @$s12objc_dealloc10SwiftGizmoCfd : $@convention(thin) (@owned SwiftGizmo) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $SwiftGizmo):
// function_ref objc_dealloc.onDestruct () -> ()
%1 = function_ref @$s12objc_dealloc10onDestructyyF : $@convention(thin) () -> () // user: %2
%2 = apply %1() : $@convention(thin) () -> ()
%3 = begin_borrow %0 : $SwiftGizmo
%4 = ref_element_addr %3 : $SwiftGizmo, #SwiftGizmo.x // user: %4
destroy_addr %4 : $*X // id: %4
end_borrow %3 : $SwiftGizmo
%5 = unchecked_ref_cast %0 : $SwiftGizmo to $Builtin.NativeObject // user: %6
return %5 : $Builtin.NativeObject // id: %6
}
sil private [ossa] @$s12objc_dealloc10SwiftGizmoC1xAA1XCfgTo : $@convention(objc_method) (SwiftGizmo) -> @autoreleased X {
bb0(%0 : @unowned $SwiftGizmo):
%1 = unchecked_ownership_conversion %0 : $SwiftGizmo, @unowned to @guaranteed
%2 = ref_element_addr %1 : $SwiftGizmo, #SwiftGizmo.x // user: %2
%3 = load [copy] %2 : $*X // users: %4, %3
end_borrow %1 : $SwiftGizmo
return %3 : $X // id: %4
}
sil private [ossa] @$s12objc_dealloc10SwiftGizmoC1xAA1XCfsTo : $@convention(objc_method) (X, SwiftGizmo) -> () {
bb0(%0 : @unowned $X, %1 : @unowned $SwiftGizmo):
%2 = copy_value %0 : $X
%3 = copy_value %1 : $SwiftGizmo
%4 = begin_borrow %3 : $SwiftGizmo
%5 = ref_element_addr %4 : $SwiftGizmo, #SwiftGizmo.x // user: %5
assign %2 to %5 : $*X // id: %5
end_borrow %4 : $SwiftGizmo
destroy_value %3 : $SwiftGizmo // id: %6
%7 = tuple () // user: %8
return %7 : $() // id: %8
}
// CHECK: define internal void @"$s12objc_dealloc10SwiftGizmoCfDTo"(ptr %0, ptr %1) {{[#0-9]*}} {
sil private [ossa] @$s12objc_dealloc10SwiftGizmoCfDTo : $@convention(objc_method) (SwiftGizmo) -> () {
bb0(%0 : @unowned $SwiftGizmo):
// CHECK-NEXT: entry
// CHECK-NEXT: [[OBJC_SUPER:%[a-zA-Z0-9_]+]] = alloca %objc_super, align 8
// Call to onDestruct()
// CHECK: call swiftcc void @"$s12objc_dealloc10onDestructyyF"()
// function_ref objc_dealloc.onDestruct () -> ()
%1 = function_ref @$s12objc_dealloc10onDestructyyF : $@convention(thin) () -> () // user: %2
%2 = apply %1() : $@convention(thin) () -> ()
// Destroy instance variables
// FIXME: This should move to .cxx_destruct
// CHECK: [[XOFFSET:%[a-zA-Z0-9]+]] = load i64, ptr @"$s12objc_dealloc10SwiftGizmoC1xAA1XCvpWvd", align 8
// CHECK-NEXT: [[IVAR_ADDR:%[a-zA-Z0-9]+]] = getelementptr inbounds i8, ptr {{.*}}, i64 [[XOFFSET]]
// CHECK-NEXT: [[X:%[a-zA-Z0-9]+]] = load ptr, ptr [[IVAR_ADDR]], align 8
// CHECK-NEXT: call void @swift_release(ptr [[X]])
%3 = unchecked_ownership_conversion %0 : $SwiftGizmo, @unowned to @guaranteed
%4 = ref_element_addr %3 : $SwiftGizmo, #SwiftGizmo.x // user: %4
destroy_addr %4 : $*X // id: %4
end_borrow %3 : $SwiftGizmo
// Call super -dealloc.
// CHECK: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$s12objc_dealloc10SwiftGizmoCMa"(i64 0)
// CHECK-NEXT: [[T0:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
// CHECK-NEXT: [[OBJC_SUPER_RECEIVER:%[a-zA-Z0-9]+]] = getelementptr inbounds{{.*}} %objc_super, ptr [[OBJC_SUPER]], i32 0, i32 0
// CHECK-NEXT: store ptr %0, ptr [[OBJC_SUPER_RECEIVER]], align 8
// CHECK-NEXT: [[OBJC_SUPER_CLASS:%[a-zA-Z0-9]+]] = getelementptr inbounds{{.*}} %objc_super, ptr [[OBJC_SUPER]], i32 0, i32 1
// CHECK-NEXT: store ptr [[T0]], ptr [[OBJC_SUPER_CLASS]], align 8
// CHECK-NEXT: [[DEALLOC_SEL:%[a-zA-Z0-9]+]] = load ptr, ptr @"\01L_selector(dealloc)", align 8
// CHECK-NEXT: call void @objc_msgSendSuper2(ptr [[OBJC_SUPER]], ptr [[DEALLOC_SEL]])
%5 = objc_super_method %0 : $SwiftGizmo, #Gizmo.deinit!deallocator.foreign : (Gizmo) -> () -> (), $@convention(objc_method) (Gizmo) -> () // user: %7
%6 = upcast %0 : $SwiftGizmo to $Gizmo // user: %7
%7 = apply %5(%6) : $@convention(objc_method) (Gizmo) -> ()
// CHECK-NEXT: ret void
%8 = tuple () // user: %9
return %8 : $() // id: %9
}
// @objc ObjectiveC.SwiftGizmo.__ivar_destroyer
sil [ossa] @$s12objc_dealloc10SwiftGizmoCfETo : $@convention(objc_method) (SwiftGizmo) -> () {
bb0(%0 : @unowned $SwiftGizmo):
%3 = tuple ()
return %3 : $() // id: %4
}
sil [ossa] @$s12objc_dealloc10SwiftGizmoCACycfcTo : $@convention(objc_method) (@owned SwiftGizmo) -> @owned SwiftGizmo {
bb0(%0 : @owned $SwiftGizmo):
return %0 : $SwiftGizmo
}
sil [ossa] @$s12objc_dealloc10SwiftGizmoC7bellsOnACSgSi_tcfcTo : $@convention(objc_method) (Int, @owned SwiftGizmo) -> @owned SwiftGizmo? {
bb0(%0 : $Int, %1 : @owned $SwiftGizmo):
destroy_value [dead_end] %1
unreachable
}