mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-24 08:33:39 +00:00
a98729b10e
This test makes sure that the ObjCARC escape analysis looks at the uses of instructions which copy the block pointer value by checking all four cases where that can occur. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@177232 91177308-0d34-0410-b5e6-96231b3b80d8
101 lines
3.9 KiB
LLVM
101 lines
3.9 KiB
LLVM
; RUN: opt -S -objc-arc < %s | FileCheck %s
|
|
|
|
declare i8* @objc_retain(i8*) nonlazybind
|
|
declare void @objc_release(i8*) nonlazybind
|
|
declare i8* @objc_retainBlock(i8*)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
; Use by an instruction which copies the value is an escape if the ;
|
|
; result is an escape. The current instructions with this property are: ;
|
|
; ;
|
|
; 1. BitCast. ;
|
|
; 2. GEP. ;
|
|
; 3. PhiNode. ;
|
|
; 4. SelectInst. ;
|
|
; ;
|
|
; Make sure that such instructions do not confuse the optimizer into removing ;
|
|
; an objc_retainBlock that is needed. ;
|
|
; ;
|
|
; rdar://13273675. (With extra test cases to handle bitcast, phi, and select. ;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
define void @bitcasttest(i8* %storage, void (...)* %block) {
|
|
; CHECK: define void @bitcasttest
|
|
entry:
|
|
%t1 = bitcast void (...)* %block to i8*
|
|
; CHECK-NOT: tail call i8* @objc_retain
|
|
%t2 = tail call i8* @objc_retain(i8* %t1)
|
|
; CHECK: tail call i8* @objc_retainBlock
|
|
%t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
|
|
%t4 = bitcast i8* %storage to void (...)**
|
|
%t5 = bitcast i8* %t3 to void (...)*
|
|
store void (...)* %t5, void (...)** %t4, align 8
|
|
; CHECK-NOT: call void @objc_release
|
|
call void @objc_release(i8* %t1)
|
|
ret void
|
|
}
|
|
|
|
define void @geptest(void (...)** %storage_array, void (...)* %block) {
|
|
; CHECK: define void @geptest
|
|
entry:
|
|
%t1 = bitcast void (...)* %block to i8*
|
|
; CHECK-NOT: tail call i8* @objc_retain
|
|
%t2 = tail call i8* @objc_retain(i8* %t1)
|
|
; CHECK: tail call i8* @objc_retainBlock
|
|
%t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
|
|
%t4 = bitcast i8* %t3 to void (...)*
|
|
|
|
%storage = getelementptr inbounds void (...)** %storage_array, i64 0
|
|
|
|
store void (...)* %t4, void (...)** %storage, align 8
|
|
; CHECK-NOT: call void @objc_release
|
|
call void @objc_release(i8* %t1)
|
|
ret void
|
|
}
|
|
|
|
define void @selecttest(void (...)** %store1, void (...)** %store2,
|
|
void (...)* %block) {
|
|
; CHECK: define void @selecttest
|
|
entry:
|
|
%t1 = bitcast void (...)* %block to i8*
|
|
; CHECK-NOT: tail call i8* @objc_retain
|
|
%t2 = tail call i8* @objc_retain(i8* %t1)
|
|
; CHECK: tail call i8* @objc_retainBlock
|
|
%t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
|
|
%t4 = bitcast i8* %t3 to void (...)*
|
|
%store = select i1 undef, void (...)** %store1, void (...)** %store2
|
|
store void (...)* %t4, void (...)** %store, align 8
|
|
; CHECK-NOT: call void @objc_release
|
|
call void @objc_release(i8* %t1)
|
|
ret void
|
|
}
|
|
|
|
define void @phinodetest(void (...)** %storage1,
|
|
void (...)** %storage2,
|
|
void (...)* %block) {
|
|
; CHECK: define void @phinodetest
|
|
entry:
|
|
%t1 = bitcast void (...)* %block to i8*
|
|
; CHECK-NOT: tail call i8* @objc_retain
|
|
%t2 = tail call i8* @objc_retain(i8* %t1)
|
|
; CHECK: tail call i8* @objc_retainBlock
|
|
%t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0
|
|
%t4 = bitcast i8* %t3 to void (...)*
|
|
br i1 undef, label %store1_set, label %store2_set
|
|
|
|
store1_set:
|
|
br label %end
|
|
|
|
store2_set:
|
|
br label %end
|
|
|
|
end:
|
|
%storage = phi void (...)** [ %storage1, %store1_set ], [ %storage2, %store2_set]
|
|
store void (...)* %t4, void (...)** %storage, align 8
|
|
; CHECK-NOT: call void @objc_release
|
|
call void @objc_release(i8* %t1)
|
|
ret void
|
|
}
|
|
|
|
!0 = metadata !{}
|