aboutsummaryrefslogtreecommitdiff
path: root/test/Transforms/ObjCARC/retain-block-escape-analysis.ll
blob: 2c1ddce32836bc24de349e50dca96194fa0885e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
; 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
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This test makes sure that we do not hang clang when visiting a use ;
; cycle caused by phi nodes during objc-arc analysis. *NOTE* This    ;
; test case looks a little convoluted since it was produced by	     ;
; bugpoint.							     ;
; 								     ;
; bugzilla://14551						     ;
; rdar://12851911						     ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

define void @phinode_use_cycle(i8* %block) uwtable optsize ssp {
; CHECK: define void @phinode_use_cycle(i8* %block)
entry:
  br label %for.body

for.body:                                         ; preds = %if.then, %for.body, %entry
  %block.05 = phi void (...)* [ null, %entry ], [ %1, %if.then ], [ %block.05, %for.body ]
  br i1 undef, label %for.body, label %if.then

if.then:                                          ; preds = %for.body
  %0 = call i8* @objc_retainBlock(i8* %block), !clang.arc.copy_on_escape !0
  %1 = bitcast i8* %0 to void (...)*
  %2 = bitcast void (...)* %block.05 to i8*
  call void @objc_release(i8* %2) nounwind, !clang.imprecise_release !0
  br label %for.body
}

!0 = metadata !{}