|
| 1 | +; RUN: opt -S -objc-arc < %s | FileCheck %s |
| 2 | + |
| 3 | +declare i8* @objc_retain(i8*) nonlazybind |
| 4 | +declare void @objc_release(i8*) nonlazybind |
| 5 | +declare i8* @objc_retainBlock(i8*) |
| 6 | + |
| 7 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 8 | +; Use by an instruction which copies the value is an escape if the ; |
| 9 | +; result is an escape. The current instructions with this property are: ; |
| 10 | +; ; |
| 11 | +; 1. BitCast. ; |
| 12 | +; 2. GEP. ; |
| 13 | +; 3. PhiNode. ; |
| 14 | +; 4. SelectInst. ; |
| 15 | +; ; |
| 16 | +; Make sure that such instructions do not confuse the optimizer into removing ; |
| 17 | +; an objc_retainBlock that is needed. ; |
| 18 | +; ; |
| 19 | +; rdar://13273675. (With extra test cases to handle bitcast, phi, and select. ; |
| 20 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 21 | + |
| 22 | +define void @bitcasttest(i8* %storage, void (...)* %block) { |
| 23 | +; CHECK: define void @bitcasttest |
| 24 | +entry: |
| 25 | + %t1 = bitcast void (...)* %block to i8* |
| 26 | +; CHECK-NOT: tail call i8* @objc_retain |
| 27 | + %t2 = tail call i8* @objc_retain(i8* %t1) |
| 28 | +; CHECK: tail call i8* @objc_retainBlock |
| 29 | + %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0 |
| 30 | + %t4 = bitcast i8* %storage to void (...)** |
| 31 | + %t5 = bitcast i8* %t3 to void (...)* |
| 32 | + store void (...)* %t5, void (...)** %t4, align 8 |
| 33 | +; CHECK-NOT: call void @objc_release |
| 34 | + call void @objc_release(i8* %t1) |
| 35 | + ret void |
| 36 | +} |
| 37 | + |
| 38 | +define void @geptest(void (...)** %storage_array, void (...)* %block) { |
| 39 | +; CHECK: define void @geptest |
| 40 | +entry: |
| 41 | + %t1 = bitcast void (...)* %block to i8* |
| 42 | +; CHECK-NOT: tail call i8* @objc_retain |
| 43 | + %t2 = tail call i8* @objc_retain(i8* %t1) |
| 44 | +; CHECK: tail call i8* @objc_retainBlock |
| 45 | + %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0 |
| 46 | + %t4 = bitcast i8* %t3 to void (...)* |
| 47 | + |
| 48 | + %storage = getelementptr inbounds void (...)** %storage_array, i64 0 |
| 49 | + |
| 50 | + store void (...)* %t4, void (...)** %storage, align 8 |
| 51 | +; CHECK-NOT: call void @objc_release |
| 52 | + call void @objc_release(i8* %t1) |
| 53 | + ret void |
| 54 | +} |
| 55 | + |
| 56 | +define void @selecttest(void (...)** %store1, void (...)** %store2, |
| 57 | + void (...)* %block) { |
| 58 | +; CHECK: define void @selecttest |
| 59 | +entry: |
| 60 | + %t1 = bitcast void (...)* %block to i8* |
| 61 | +; CHECK-NOT: tail call i8* @objc_retain |
| 62 | + %t2 = tail call i8* @objc_retain(i8* %t1) |
| 63 | +; CHECK: tail call i8* @objc_retainBlock |
| 64 | + %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0 |
| 65 | + %t4 = bitcast i8* %t3 to void (...)* |
| 66 | + %store = select i1 undef, void (...)** %store1, void (...)** %store2 |
| 67 | + store void (...)* %t4, void (...)** %store, align 8 |
| 68 | +; CHECK-NOT: call void @objc_release |
| 69 | + call void @objc_release(i8* %t1) |
| 70 | + ret void |
| 71 | +} |
| 72 | + |
| 73 | +define void @phinodetest(void (...)** %storage1, |
| 74 | + void (...)** %storage2, |
| 75 | + void (...)* %block) { |
| 76 | +; CHECK: define void @phinodetest |
| 77 | +entry: |
| 78 | + %t1 = bitcast void (...)* %block to i8* |
| 79 | +; CHECK-NOT: tail call i8* @objc_retain |
| 80 | + %t2 = tail call i8* @objc_retain(i8* %t1) |
| 81 | +; CHECK: tail call i8* @objc_retainBlock |
| 82 | + %t3 = tail call i8* @objc_retainBlock(i8* %t1), !clang.arc.copy_on_escape !0 |
| 83 | + %t4 = bitcast i8* %t3 to void (...)* |
| 84 | + br i1 undef, label %store1_set, label %store2_set |
| 85 | + |
| 86 | +store1_set: |
| 87 | + br label %end |
| 88 | + |
| 89 | +store2_set: |
| 90 | + br label %end |
| 91 | + |
| 92 | +end: |
| 93 | + %storage = phi void (...)** [ %storage1, %store1_set ], [ %storage2, %store2_set] |
| 94 | + store void (...)* %t4, void (...)** %storage, align 8 |
| 95 | +; CHECK-NOT: call void @objc_release |
| 96 | + call void @objc_release(i8* %t1) |
| 97 | + ret void |
| 98 | +} |
| 99 | + |
| 100 | +!0 = metadata !{} |
0 commit comments