[llvm] r189869 - [objc-arc] Turn off the objc_retainBlock -> objc_retain optimization.

David Blaikie dblaikie at gmail.com
Wed Sep 4 12:44:31 PDT 2013


On Wed, Sep 4, 2013 at 11:31 AM, Bob Wilson <bob.wilson at apple.com> wrote:
>
> On Sep 4, 2013, at 11:03 AM, David Blaikie <dblaikie at gmail.com> wrote:
>
>> On Wed, Sep 4, 2013 at 10:31 AM, Bob Wilson <bob.wilson at apple.com> wrote:
>>> I already mentioned this to Michael off-line, but for the benefit of others reading the list, this is not the right way to temporarily disable something. It would be much better to make small changes to prevent the code from being run, e.g., "if (0) ….", and then change the RUN lines from the tests to disable them.  Removing all the code like this and then adding it back once you have a fix creates a lot of unnecessary churn in the sources.
>>
>> One standalone block of code, though? Hardly seems like major churn -
>> I assume it was all committed by one person, not a lot of complicated
>> blame - and assigning "ownership" to Michael when he commits it with a
>> fix to the new issue doesn't seem too problematic.
>
> Look at the follow-on commit: 189870 -- it wasn't just one block of code.

Alrighty, thanks for the context - so this code is large enough that
this change will hurt the blame history, but it shouldn't really hurt
out-of-tree/branches any more than usual upstream churn (since it's
just dead functions, not picking bits & pieces out of other functions,
etc).

>>> That makes it harder to search through the source history, increases the chances of merge conflicts for other branches, and makes it hard to cherry-pick fixes elsewhere.
>>
>> Depends how long the code's expected to be dead. Generally we back out
>> broken patches when we find them to be broken, work on a repro for the
>> issue, and then commit the patch again along with the fix & tests.
>> Leaving dead code in the codebase is generally frowned upon.
>
> We couldn't back this out.  It is a very longstanding issue in the ARC optimizer.

Right - but looks like it's still a fairly specific point at which
this feature is exposed & can be (& was) cleanly excised.

> We're actively working on a proper fix and simply wanted to temporarily disable it in the meantime.

Just out of curiosity - how temporary are we talking?

> Personally I would have preferred that this change only went on one of Apple's internal branches, but I think you can make a reasonable case for putting it  on trunk, since the bug will affect anyone using clang from trunk.

Agreed - seems quite correct to make this change in trunk. Known bug
that's affecting users, if it's going to be disabled, disabling it
upstream seems like a nice/right thing to do.

Anyway - just my thoughts,
- David

>
>>
>> See, for example, my recent revert to Clang in r189906 of a patch I
>> submitted a few weeks ago. There's certainly some leeway in
>> distance/time/complexity & ownership (if it was committed a long time
>> ago, by someone else, and is complicated/entwined in existing code...
>> maybe?), but if a patch (or even a piece of code) is broken & can be
>> easily removed - I say remove the broken code.
>>
>> Also, if you have a test case that demonstrates why code is broken, it
>> may be worth committing that with the revert (rather than in a
>> comment/commit message), or shortly thereafter - so that even if some
>> other person comes along with the same optimization/idea, they'll know
>> it's broken when they try to run the tests.
>>
>> (I could probably be OK with leaving the test cases in & XFAILed as
>> "TODO" reminders that this functionality would be nice to have at some
>> point)
>>
>>>
>>> Since this is already done, there's no point in re-doing it now, though.
>>>
>>> On Sep 3, 2013, at 3:40 PM, Michael Gottesman <mgottesman at apple.com> wrote:
>>>
>>>> Author: mgottesman
>>>> Date: Tue Sep  3 17:40:54 2013
>>>> New Revision: 189869
>>>>
>>>> URL: http://llvm.org/viewvc/llvm-project?rev=189869&view=rev
>>>> Log:
>>>> [objc-arc] Turn off the objc_retainBlock -> objc_retain optimization.
>>>>
>>>> The reason that I am turning off this optimization is that there is an
>>>> additional case where a block can escape that has come up. Specifically, this
>>>> occurs when a block is used in a scope outside of its current scope.
>>>>
>>>> This can cause a captured retainable object pointer whose life is preserved by
>>>> the objc_retainBlock to be deallocated before the block is invoked.
>>>>
>>>> An example of the code needed to trigger the bug is:
>>>>
>>>> ----
>>>> \#import <Foundation/Foundation.h>
>>>> int main(int argc, const char * argv[]) {
>>>> void (^somethingToDoLater)();
>>>>
>>>> {
>>>>   NSObject *obj = [NSObject new];
>>>>
>>>>   somethingToDoLater = ^{
>>>>     [obj self]; // Crashes here
>>>>   };
>>>> }
>>>>
>>>> NSLog(@"test.");
>>>>
>>>> somethingToDoLater();
>>>> return 0;
>>>> }
>>>> ----
>>>>
>>>> In the next commit, I remove all the dead code that results from this.
>>>>
>>>> Once I put in the fixing commit I will bring back the tests that I deleted in
>>>> this commit.
>>>>
>>>> rdar://14802782.
>>>> rdar://14868830.
>>>>
>>>> Removed:
>>>>   llvm/trunk/test/Transforms/ObjCARC/no-objc-arc-exceptions.ll
>>>>   llvm/trunk/test/Transforms/ObjCARC/retain-block-alloca.ll
>>>>   llvm/trunk/test/Transforms/ObjCARC/retain-block-escape-analysis.ll
>>>>   llvm/trunk/test/Transforms/ObjCARC/retain-block-load.ll
>>>>   llvm/trunk/test/Transforms/ObjCARC/retain-block.ll
>>>> Modified:
>>>>   llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
>>>>
>>>> Modified: llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp?rev=189869&r1=189868&r2=189869&view=diff
>>>> ==============================================================================
>>>> --- llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp (original)
>>>> +++ llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp Tue Sep  3 17:40:54 2013
>>>> @@ -1510,11 +1510,6 @@ void ObjCARCOpt::OptimizeIndividualCalls
>>>>      }
>>>>      break;
>>>>    }
>>>> -    case IC_RetainBlock:
>>>> -      // If we strength reduce an objc_retainBlock to an objc_retain, continue
>>>> -      // onto the objc_retain peephole optimizations. Otherwise break.
>>>> -      OptimizeRetainBlockCall(F, Inst, Class);
>>>> -      break;
>>>>    case IC_RetainRV:
>>>>      if (OptimizeRetainRVCall(F, Inst))
>>>>        continue;
>>>>
>>>> Removed: llvm/trunk/test/Transforms/ObjCARC/no-objc-arc-exceptions.ll
>>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/no-objc-arc-exceptions.ll?rev=189868&view=auto
>>>> ==============================================================================
>>>> --- llvm/trunk/test/Transforms/ObjCARC/no-objc-arc-exceptions.ll (original)
>>>> +++ llvm/trunk/test/Transforms/ObjCARC/no-objc-arc-exceptions.ll (removed)
>>>> @@ -1,123 +0,0 @@
>>>> -; RUN: opt -S -objc-arc < %s | FileCheck %s
>>>> -
>>>> -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
>>>> -%struct.__block_byref_x = type { i8*, %struct.__block_byref_x*, i32, i32, i32 }
>>>> -%struct.__block_descriptor = type { i64, i64 }
>>>> - at _NSConcreteStackBlock = external global i8*
>>>> - at __block_descriptor_tmp = external hidden constant { i64, i64, i8*, i8*, i8*, i8* }
>>>> -
>>>> -; The optimizer should make use of the !clang.arc.no_objc_arc_exceptions
>>>> -; metadata and eliminate the retainBlock+release pair here.
>>>> -; rdar://10803830.
>>>> -
>>>> -; CHECK-LABEL: define void @test0(
>>>> -; CHECK-NOT: @objc
>>>> -; CHECK: }
>>>> -define void @test0() {
>>>> -entry:
>>>> -  %x = alloca %struct.__block_byref_x, align 8
>>>> -  %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
>>>> -  %byref.isa = getelementptr inbounds %struct.__block_byref_x* %x, i64 0, i32 0
>>>> -  store i8* null, i8** %byref.isa, align 8
>>>> -  %byref.forwarding = getelementptr inbounds %struct.__block_byref_x* %x, i64 0, i32 1
>>>> -  store %struct.__block_byref_x* %x, %struct.__block_byref_x** %byref.forwarding, align 8
>>>> -  %byref.flags = getelementptr inbounds %struct.__block_byref_x* %x, i64 0, i32 2
>>>> -  store i32 0, i32* %byref.flags, align 8
>>>> -  %byref.size = getelementptr inbounds %struct.__block_byref_x* %x, i64 0, i32 3
>>>> -  store i32 32, i32* %byref.size, align 4
>>>> -  %block.isa = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 0
>>>> -  store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %block.isa, align 8
>>>> -  %block.flags = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 1
>>>> -  store i32 1107296256, i32* %block.flags, align 8
>>>> -  %block.reserved = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 2
>>>> -  store i32 0, i32* %block.reserved, align 4
>>>> -  %block.invoke = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 3
>>>> -  store i8* bitcast (void (i8*)* @__foo_block_invoke_0 to i8*), i8** %block.invoke, align 8
>>>> -  %block.descriptor = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 4
>>>> -  store %struct.__block_descriptor* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @__block_descriptor_tmp to %struct.__block_descriptor*), %struct.__block_descriptor** %block.descriptor, align 8
>>>> -  %block.captured = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 5
>>>> -  %t1 = bitcast %struct.__block_byref_x* %x to i8*
>>>> -  store i8* %t1, i8** %block.captured, align 8
>>>> -  %t2 = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block to i8*
>>>> -  %t3 = call i8* @objc_retainBlock(i8* %t2) nounwind, !clang.arc.copy_on_escape !4
>>>> -  %t4 = getelementptr inbounds i8* %t3, i64 16
>>>> -  %t5 = bitcast i8* %t4 to i8**
>>>> -  %t6 = load i8** %t5, align 8
>>>> -  %t7 = bitcast i8* %t6 to void (i8*)*
>>>> -  invoke void %t7(i8* %t3)
>>>> -          to label %invoke.cont unwind label %lpad, !clang.arc.no_objc_arc_exceptions !4
>>>> -
>>>> -invoke.cont:                                      ; preds = %entry
>>>> -  call void @objc_release(i8* %t3) nounwind, !clang.imprecise_release !4
>>>> -  call void @_Block_object_dispose(i8* %t1, i32 8)
>>>> -  ret void
>>>> -
>>>> -lpad:                                             ; preds = %entry
>>>> -  %t8 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
>>>> -          cleanup
>>>> -  call void @_Block_object_dispose(i8* %t1, i32 8)
>>>> -  resume { i8*, i32 } %t8
>>>> -}
>>>> -
>>>> -; There is no !clang.arc.no_objc_arc_exceptions metadata here, so the optimizer
>>>> -; shouldn't eliminate anything, but *CAN* strength reduce the objc_retainBlock
>>>> -; to an objc_retain.
>>>> -
>>>> -; CHECK-LABEL: define void @test0_no_metadata(
>>>> -; CHECK: call i8* @objc_retain(
>>>> -; CHECK: invoke
>>>> -; CHECK: call void @objc_release(
>>>> -; CHECK: }
>>>> -define void @test0_no_metadata() {
>>>> -entry:
>>>> -  %x = alloca %struct.__block_byref_x, align 8
>>>> -  %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
>>>> -  %byref.isa = getelementptr inbounds %struct.__block_byref_x* %x, i64 0, i32 0
>>>> -  store i8* null, i8** %byref.isa, align 8
>>>> -  %byref.forwarding = getelementptr inbounds %struct.__block_byref_x* %x, i64 0, i32 1
>>>> -  store %struct.__block_byref_x* %x, %struct.__block_byref_x** %byref.forwarding, align 8
>>>> -  %byref.flags = getelementptr inbounds %struct.__block_byref_x* %x, i64 0, i32 2
>>>> -  store i32 0, i32* %byref.flags, align 8
>>>> -  %byref.size = getelementptr inbounds %struct.__block_byref_x* %x, i64 0, i32 3
>>>> -  store i32 32, i32* %byref.size, align 4
>>>> -  %block.isa = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 0
>>>> -  store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %block.isa, align 8
>>>> -  %block.flags = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 1
>>>> -  store i32 1107296256, i32* %block.flags, align 8
>>>> -  %block.reserved = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 2
>>>> -  store i32 0, i32* %block.reserved, align 4
>>>> -  %block.invoke = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 3
>>>> -  store i8* bitcast (void (i8*)* @__foo_block_invoke_0 to i8*), i8** %block.invoke, align 8
>>>> -  %block.descriptor = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 4
>>>> -  store %struct.__block_descriptor* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @__block_descriptor_tmp to %struct.__block_descriptor*), %struct.__block_descriptor** %block.descriptor, align 8
>>>> -  %block.captured = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block, i64 0, i32 5
>>>> -  %t1 = bitcast %struct.__block_byref_x* %x to i8*
>>>> -  store i8* %t1, i8** %block.captured, align 8
>>>> -  %t2 = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>* %block to i8*
>>>> -  %t3 = call i8* @objc_retainBlock(i8* %t2) nounwind, !clang.arc.copy_on_escape !4
>>>> -  %t4 = getelementptr inbounds i8* %t3, i64 16
>>>> -  %t5 = bitcast i8* %t4 to i8**
>>>> -  %t6 = load i8** %t5, align 8
>>>> -  %t7 = bitcast i8* %t6 to void (i8*)*
>>>> -  invoke void %t7(i8* %t3)
>>>> -          to label %invoke.cont unwind label %lpad
>>>> -
>>>> -invoke.cont:                                      ; preds = %entry
>>>> -  call void @objc_release(i8* %t3) nounwind, !clang.imprecise_release !4
>>>> -  call void @_Block_object_dispose(i8* %t1, i32 8)
>>>> -  ret void
>>>> -
>>>> -lpad:                                             ; preds = %entry
>>>> -  %t8 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*)
>>>> -          cleanup
>>>> -  call void @_Block_object_dispose(i8* %t1, i32 8)
>>>> -  resume { i8*, i32 } %t8
>>>> -}
>>>> -
>>>> -declare i8* @objc_retainBlock(i8*)
>>>> -declare void @objc_release(i8*)
>>>> -declare void @_Block_object_dispose(i8*, i32)
>>>> -declare i32 @__objc_personality_v0(...)
>>>> -declare void @__foo_block_invoke_0(i8* nocapture) uwtable ssp
>>>> -
>>>> -!4 = metadata !{}
>>>>
>>>> Removed: llvm/trunk/test/Transforms/ObjCARC/retain-block-alloca.ll
>>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/retain-block-alloca.ll?rev=189868&view=auto
>>>> ==============================================================================
>>>> --- llvm/trunk/test/Transforms/ObjCARC/retain-block-alloca.ll (original)
>>>> +++ llvm/trunk/test/Transforms/ObjCARC/retain-block-alloca.ll (removed)
>>>> @@ -1,94 +0,0 @@
>>>> -; RUN: opt -S -objc-arc < %s | FileCheck %s
>>>> -; rdar://10209613
>>>> -
>>>> -%0 = type opaque
>>>> -%struct.__block_descriptor = type { i64, i64 }
>>>> -
>>>> - at _NSConcreteStackBlock = external global i8*
>>>> - at __block_descriptor_tmp = external hidden constant { i64, i64, i8*, i8*, i8*, i8* }
>>>> -@"\01L_OBJC_SELECTOR_REFERENCES_" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
>>>> -
>>>> -; CHECK-LABEL: define void @test(
>>>> -; CHECK: %3 = call i8* @objc_retainBlock(i8* %2) [[NUW:#[0-9]+]]
>>>> -; CHECK: @objc_msgSend
>>>> -; CHECK-NEXT: @objc_release(i8* %3)
>>>> -define void @test(%0* %array) uwtable {
>>>> -entry:
>>>> -  %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>, align 8
>>>> -  %0 = bitcast %0* %array to i8*
>>>> -  %1 = tail call i8* @objc_retain(i8* %0) nounwind
>>>> -  %block.isa = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 0
>>>> -  store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %block.isa, align 8
>>>> -  %block.flags = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 1
>>>> -  store i32 1107296256, i32* %block.flags, align 8
>>>> -  %block.reserved = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 2
>>>> -  store i32 0, i32* %block.reserved, align 4
>>>> -  %block.invoke = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 3
>>>> -  store i8* bitcast (void (i8*)* @__test_block_invoke_0 to i8*), i8** %block.invoke, align 8
>>>> -  %block.descriptor = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 4
>>>> -  store %struct.__block_descriptor* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @__block_descriptor_tmp to %struct.__block_descriptor*), %struct.__block_descriptor** %block.descriptor, align 8
>>>> -  %block.captured = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 5
>>>> -  store %0* %array, %0** %block.captured, align 8
>>>> -  %2 = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block to i8*
>>>> -  %3 = call i8* @objc_retainBlock(i8* %2) nounwind
>>>> -  %tmp2 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
>>>> -  call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* %0, i8* %tmp2, i8* %3)
>>>> -  call void @objc_release(i8* %3) nounwind
>>>> -  %strongdestroy = load %0** %block.captured, align 8
>>>> -  %4 = bitcast %0* %strongdestroy to i8*
>>>> -  call void @objc_release(i8* %4) nounwind, !clang.imprecise_release !0
>>>> -  ret void
>>>> -}
>>>> -
>>>> -; Same as test, but the objc_retainBlock has a clang.arc.copy_on_escape
>>>> -; tag so it's safe to delete.
>>>> -
>>>> -; CHECK-LABEL: define void @test_with_COE(
>>>> -; CHECK-NOT: @objc_retainBlock
>>>> -; CHECK: @objc_msgSend
>>>> -; CHECK: @objc_release
>>>> -; CHECK-NOT: @objc_release
>>>> -; CHECK: }
>>>> -define void @test_with_COE(%0* %array) uwtable {
>>>> -entry:
>>>> -  %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>, align 8
>>>> -  %0 = bitcast %0* %array to i8*
>>>> -  %1 = tail call i8* @objc_retain(i8* %0) nounwind
>>>> -  %block.isa = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 0
>>>> -  store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %block.isa, align 8
>>>> -  %block.flags = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 1
>>>> -  store i32 1107296256, i32* %block.flags, align 8
>>>> -  %block.reserved = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 2
>>>> -  store i32 0, i32* %block.reserved, align 4
>>>> -  %block.invoke = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 3
>>>> -  store i8* bitcast (void (i8*)* @__test_block_invoke_0 to i8*), i8** %block.invoke, align 8
>>>> -  %block.descriptor = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 4
>>>> -  store %struct.__block_descriptor* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @__block_descriptor_tmp to %struct.__block_descriptor*), %struct.__block_descriptor** %block.descriptor, align 8
>>>> -  %block.captured = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block, i64 0, i32 5
>>>> -  store %0* %array, %0** %block.captured, align 8
>>>> -  %2 = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %block to i8*
>>>> -  %3 = call i8* @objc_retainBlock(i8* %2) nounwind, !clang.arc.copy_on_escape !0
>>>> -  %tmp2 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", align 8
>>>> -  call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* %0, i8* %tmp2, i8* %3)
>>>> -  call void @objc_release(i8* %3) nounwind
>>>> -  %strongdestroy = load %0** %block.captured, align 8
>>>> -  %4 = bitcast %0* %strongdestroy to i8*
>>>> -  call void @objc_release(i8* %4) nounwind, !clang.imprecise_release !0
>>>> -  ret void
>>>> -}
>>>> -
>>>> -declare i8* @objc_retain(i8*)
>>>> -
>>>> -declare void @__test_block_invoke_0(i8* nocapture) uwtable
>>>> -
>>>> -declare i8* @objc_retainBlock(i8*)
>>>> -
>>>> -declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind
>>>> -
>>>> -declare void @objc_release(i8*)
>>>> -
>>>> -; CHECK: attributes #0 = { uwtable }
>>>> -; CHECK: attributes #1 = { nonlazybind }
>>>> -; CHECK: attributes [[NUW]] = { nounwind }
>>>> -
>>>> -!0 = metadata !{}
>>>>
>>>> Removed: llvm/trunk/test/Transforms/ObjCARC/retain-block-escape-analysis.ll
>>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/retain-block-escape-analysis.ll?rev=189868&view=auto
>>>> ==============================================================================
>>>> --- llvm/trunk/test/Transforms/ObjCARC/retain-block-escape-analysis.ll (original)
>>>> +++ llvm/trunk/test/Transforms/ObjCARC/retain-block-escape-analysis.ll (removed)
>>>> @@ -1,215 +0,0 @@
>>>> -; 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-LABEL: define void @bitcasttest(
>>>> -entry:
>>>> -  %t1 = bitcast void (...)* %block to i8*
>>>> -; CHECK: 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: call void @objc_release
>>>> -  call void @objc_release(i8* %t1)
>>>> -  ret void
>>>> -; CHECK: }
>>>> -}
>>>> -
>>>> -define void @bitcasttest_a(i8* %storage, void (...)* %block)  {
>>>> -; CHECK-LABEL: define void @bitcasttest_a(
>>>> -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), !clang.imprecise_release !0
>>>> -  ret void
>>>> -; CHECK: }
>>>> -}
>>>> -
>>>> -define void @geptest(void (...)** %storage_array, void (...)* %block)  {
>>>> -; CHECK-LABEL: define void @geptest(
>>>> -entry:
>>>> -  %t1 = bitcast void (...)* %block to i8*
>>>> -; CHECK: 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: call void @objc_release
>>>> -  call void @objc_release(i8* %t1)
>>>> -  ret void
>>>> -; CHECK: }
>>>> -}
>>>> -
>>>> -define void @geptest_a(void (...)** %storage_array, void (...)* %block)  {
>>>> -; CHECK-LABEL: define void @geptest_a(
>>>> -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), !clang.imprecise_release !0
>>>> -  ret void
>>>> -; CHECK: }
>>>> -}
>>>> -
>>>> -define void @selecttest(void (...)** %store1, void (...)** %store2,
>>>> -                        void (...)* %block) {
>>>> -; CHECK-LABEL: define void @selecttest(
>>>> -entry:
>>>> -  %t1 = bitcast void (...)* %block to i8*
>>>> -; CHECK: 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: call void @objc_release
>>>> -  call void @objc_release(i8* %t1)
>>>> -  ret void
>>>> -; CHECK: }
>>>> -}
>>>> -
>>>> -define void @selecttest_a(void (...)** %store1, void (...)** %store2,
>>>> -                          void (...)* %block) {
>>>> -; CHECK-LABEL: define void @selecttest_a(
>>>> -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), !clang.imprecise_release !0
>>>> -  ret void
>>>> -; CHECK: }
>>>> -}
>>>> -
>>>> -define void @phinodetest(void (...)** %storage1,
>>>> -                         void (...)** %storage2,
>>>> -                         void (...)* %block) {
>>>> -; CHECK-LABEL: define void @phinodetest(
>>>> -entry:
>>>> -  %t1 = bitcast void (...)* %block to i8*
>>>> -; CHECK: 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
>>>> -; CHECK: store1_set:
>>>> -
>>>> -store1_set:
>>>> -  br label %end
>>>> -
>>>> -store2_set:
>>>> -  br label %end
>>>> -
>>>> -end:
>>>> -; CHECK: end:
>>>> -  %storage = phi void (...)** [ %storage1, %store1_set ], [ %storage2, %store2_set]
>>>> -  store void (...)* %t4, void (...)** %storage, align 8
>>>> -; CHECK: call void @objc_release
>>>> -  call void @objc_release(i8* %t1)
>>>> -  ret void
>>>> -; CHECK: }
>>>> -}
>>>> -
>>>> -define void @phinodetest_a(void (...)** %storage1,
>>>> -                           void (...)** %storage2,
>>>> -                           void (...)* %block) {
>>>> -; CHECK-LABEL: define void @phinodetest_a(
>>>> -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), !clang.imprecise_release !0
>>>> -  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-LABEL: 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 !{}
>>>>
>>>> Removed: llvm/trunk/test/Transforms/ObjCARC/retain-block-load.ll
>>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/retain-block-load.ll?rev=189868&view=auto
>>>> ==============================================================================
>>>> --- llvm/trunk/test/Transforms/ObjCARC/retain-block-load.ll (original)
>>>> +++ llvm/trunk/test/Transforms/ObjCARC/retain-block-load.ll (removed)
>>>> @@ -1,51 +0,0 @@
>>>> -; RUN: opt -objc-arc -S < %s | FileCheck %s
>>>> -
>>>> -; rdar://10803830
>>>> -; The optimizer should be able to prove that the block does not
>>>> -; "escape", so the retainBlock+release pair can be eliminated.
>>>> -
>>>> -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
>>>> -
>>>> -%struct.__block_descriptor = type { i64, i64 }
>>>> -
>>>> - at _NSConcreteStackBlock = external global i8*
>>>> - at __block_descriptor_tmp = external global { i64, i64, i8*, i8* }
>>>> -
>>>> -; CHECK: define void @test() {
>>>> -; CHECK-NOT: @objc
>>>> -; CHECK: declare i8* @objc_retainBlock(i8*)
>>>> -; CHECK: declare void @objc_release(i8*)
>>>> -
>>>> -define void @test() {
>>>> -entry:
>>>> -  %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>, align 8
>>>> -  %block.isa = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %block, i64 0, i32 0
>>>> -  store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %block.isa, align 8
>>>> -  %block.flags = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %block, i64 0, i32 1
>>>> -  store i32 1073741824, i32* %block.flags, align 8
>>>> -  %block.reserved = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %block, i64 0, i32 2
>>>> -  store i32 0, i32* %block.reserved, align 4
>>>> -  %block.invoke = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %block, i64 0, i32 3
>>>> -  store i8* bitcast (i32 (i8*)* @__test_block_invoke_0 to i8*), i8** %block.invoke, align 8
>>>> -  %block.descriptor = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %block, i64 0, i32 4
>>>> -  store %struct.__block_descriptor* bitcast ({ i64, i64, i8*, i8* }* @__block_descriptor_tmp to %struct.__block_descriptor*), %struct.__block_descriptor** %block.descriptor, align 8
>>>> -  %block.captured = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %block, i64 0, i32 5
>>>> -  store i32 4, i32* %block.captured, align 8
>>>> -  %tmp = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %block to i8*
>>>> -  %tmp1 = call i8* @objc_retainBlock(i8* %tmp) nounwind, !clang.arc.copy_on_escape !0
>>>> -  %tmp2 = getelementptr inbounds i8* %tmp1, i64 16
>>>> -  %tmp3 = bitcast i8* %tmp2 to i8**
>>>> -  %tmp4 = load i8** %tmp3, align 8
>>>> -  %tmp5 = bitcast i8* %tmp4 to i32 (i8*)*
>>>> -  %call = call i32 %tmp5(i8* %tmp1)
>>>> -  call void @objc_release(i8* %tmp1) nounwind, !clang.imprecise_release !0
>>>> -  ret void
>>>> -}
>>>> -
>>>> -declare i32 @__test_block_invoke_0(i8* nocapture %.block_descriptor) nounwind readonly
>>>> -
>>>> -declare i8* @objc_retainBlock(i8*)
>>>> -
>>>> -declare void @objc_release(i8*)
>>>> -
>>>> -!0 = metadata !{}
>>>>
>>>> Removed: llvm/trunk/test/Transforms/ObjCARC/retain-block.ll
>>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/retain-block.ll?rev=189868&view=auto
>>>> ==============================================================================
>>>> --- llvm/trunk/test/Transforms/ObjCARC/retain-block.ll (original)
>>>> +++ llvm/trunk/test/Transforms/ObjCARC/retain-block.ll (removed)
>>>> @@ -1,189 +0,0 @@
>>>> -; RUN: opt -objc-arc -S < %s | FileCheck %s
>>>> -
>>>> -target datalayout = "e-p:64:64:64"
>>>> -
>>>> -!0 = metadata !{}
>>>> -
>>>> -declare i8* @objc_retain(i8*)
>>>> -declare void @callee(i8)
>>>> -declare void @use_pointer(i8*)
>>>> -declare void @objc_release(i8*)
>>>> -declare i8* @objc_retainBlock(i8*)
>>>> -declare i8* @objc_autorelease(i8*)
>>>> -
>>>> -; Basic retainBlock+release elimination.
>>>> -
>>>> -; CHECK-LABEL: define void @test0(i8* %tmp) {
>>>> -; CHECK-NOT: @objc
>>>> -; CHECK: }
>>>> -define void @test0(i8* %tmp) {
>>>> -entry:
>>>> -  %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind, !clang.arc.copy_on_escape !0
>>>> -  tail call void @use_pointer(i8* %tmp2)
>>>> -  tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
>>>> -  ret void
>>>> -}
>>>> -
>>>> -; Same as test0, but there's no copy_on_escape metadata, so there's no
>>>> -; optimization possible.
>>>> -
>>>> -; CHECK-LABEL: define void @test0_no_metadata(i8* %tmp) {
>>>> -; CHECK: %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) [[NUW:#[0-9]+]]
>>>> -; CHECK: tail call void @objc_release(i8* %tmp2) [[NUW]], !clang.imprecise_release !0
>>>> -; CHECK: }
>>>> -define void @test0_no_metadata(i8* %tmp) {
>>>> -entry:
>>>> -  %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind
>>>> -  tail call void @use_pointer(i8* %tmp2)
>>>> -  tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
>>>> -  ret void
>>>> -}
>>>> -
>>>> -; Same as test0, but the pointer escapes, so there's no
>>>> -; optimization possible.
>>>> -
>>>> -; CHECK-LABEL: define void @test0_escape(i8* %tmp, i8** %z) {
>>>> -; CHECK: %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) [[NUW]], !clang.arc.copy_on_escape !0
>>>> -; CHECK: tail call void @objc_release(i8* %tmp2) [[NUW]], !clang.imprecise_release !0
>>>> -; CHECK: }
>>>> -define void @test0_escape(i8* %tmp, i8** %z) {
>>>> -entry:
>>>> -  %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind, !clang.arc.copy_on_escape !0
>>>> -  store i8* %tmp2, i8** %z
>>>> -  tail call void @use_pointer(i8* %tmp2)
>>>> -  tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
>>>> -  ret void
>>>> -}
>>>> -
>>>> -; Same as test0_escape, but there's no intervening call.
>>>> -
>>>> -; CHECK-LABEL: define void @test0_just_escape(i8* %tmp, i8** %z) {
>>>> -; CHECK: %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) [[NUW]], !clang.arc.copy_on_escape !0
>>>> -; CHECK: tail call void @objc_release(i8* %tmp2) [[NUW]], !clang.imprecise_release !0
>>>> -; CHECK: }
>>>> -define void @test0_just_escape(i8* %tmp, i8** %z) {
>>>> -entry:
>>>> -  %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind, !clang.arc.copy_on_escape !0
>>>> -  store i8* %tmp2, i8** %z
>>>> -  tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
>>>> -  ret void
>>>> -}
>>>> -
>>>> -; Basic nested retainBlock+release elimination.
>>>> -
>>>> -; CHECK: define void @test1(i8* %tmp) {
>>>> -; CHECK-NOT: @objc
>>>> -; CHECK: tail call i8* @objc_retain(i8* %tmp) [[NUW]]
>>>> -; CHECK-NOT: @objc
>>>> -; CHECK: tail call void @objc_release(i8* %tmp) [[NUW]], !clang.imprecise_release !0
>>>> -; CHECK-NOT: @objc
>>>> -; CHECK: }
>>>> -define void @test1(i8* %tmp) {
>>>> -entry:
>>>> -  %tmp1 = tail call i8* @objc_retain(i8* %tmp) nounwind
>>>> -  %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind, !clang.arc.copy_on_escape !0
>>>> -  tail call void @use_pointer(i8* %tmp2)
>>>> -  tail call void @use_pointer(i8* %tmp2)
>>>> -  tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
>>>> -  tail call void @objc_release(i8* %tmp) nounwind, !clang.imprecise_release !0
>>>> -  ret void
>>>> -}
>>>> -
>>>> -; Same as test1, but there's no copy_on_escape metadata, so there's no
>>>> -; retainBlock+release optimization possible. But we can still eliminate
>>>> -; the outer retain+release.
>>>> -
>>>> -; CHECK-LABEL: define void @test1_no_metadata(i8* %tmp) {
>>>> -; CHECK-NEXT: entry:
>>>> -; CHECK-NEXT: tail call i8* @objc_retainBlock(i8* %tmp) [[NUW]]
>>>> -; CHECK-NEXT: @use_pointer(i8* %tmp2)
>>>> -; CHECK-NEXT: @use_pointer(i8* %tmp2)
>>>> -; CHECK-NEXT: tail call void @objc_release(i8* %tmp2) [[NUW]], !clang.imprecise_release !0
>>>> -; CHECK-NOT: @objc
>>>> -; CHECK: }
>>>> -define void @test1_no_metadata(i8* %tmp) {
>>>> -entry:
>>>> -  %tmp1 = tail call i8* @objc_retain(i8* %tmp) nounwind
>>>> -  %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind
>>>> -  tail call void @use_pointer(i8* %tmp2)
>>>> -  tail call void @use_pointer(i8* %tmp2)
>>>> -  tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
>>>> -  tail call void @objc_release(i8* %tmp) nounwind, !clang.imprecise_release !0
>>>> -  ret void
>>>> -}
>>>> -
>>>> -; Same as test1, but the pointer escapes, so there's no
>>>> -; retainBlock+release optimization possible. But we can still eliminate
>>>> -; the outer retain+release
>>>> -
>>>> -; CHECK: define void @test1_escape(i8* %tmp, i8** %z) {
>>>> -; CHECK-NEXT: entry:
>>>> -; CHECK-NEXT: %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) [[NUW]], !clang.arc.copy_on_escape !0
>>>> -; CHECK-NEXT: store i8* %tmp2, i8** %z
>>>> -; CHECK-NEXT: @use_pointer(i8* %tmp2)
>>>> -; CHECK-NEXT: @use_pointer(i8* %tmp2)
>>>> -; CHECK-NEXT: tail call void @objc_release(i8* %tmp2) [[NUW]], !clang.imprecise_release !0
>>>> -; CHECK-NOT: @objc
>>>> -; CHECK: }
>>>> -define void @test1_escape(i8* %tmp, i8** %z) {
>>>> -entry:
>>>> -  %tmp1 = tail call i8* @objc_retain(i8* %tmp) nounwind
>>>> -  %tmp2 = tail call i8* @objc_retainBlock(i8* %tmp) nounwind, !clang.arc.copy_on_escape !0
>>>> -  store i8* %tmp2, i8** %z
>>>> -  tail call void @use_pointer(i8* %tmp2)
>>>> -  tail call void @use_pointer(i8* %tmp2)
>>>> -  tail call void @objc_release(i8* %tmp2) nounwind, !clang.imprecise_release !0
>>>> -  tail call void @objc_release(i8* %tmp) nounwind, !clang.imprecise_release !0
>>>> -  ret void
>>>> -}
>>>> -
>>>> -; Optimize objc_retainBlock.
>>>> -
>>>> -; CHECK-LABEL: define void @test23(
>>>> -; CHECK-NOT: @objc_
>>>> -; CHECK: }
>>>> -%block0 = type { i64, i64, i8*, i8* }
>>>> -%block1 = type { i8**, i32, i32, i32 (%struct.__block_literal_1*)*, %block0* }
>>>> -%struct.__block_descriptor = type { i64, i64 }
>>>> -%struct.__block_literal_1 = type { i8**, i32, i32, i8**, %struct.__block_descriptor* }
>>>> - at __block_holder_tmp_1 = external constant %block1
>>>> -define void @test23() {
>>>> -entry:
>>>> -  %0 = call i8* @objc_retainBlock(i8* bitcast (%block1* @__block_holder_tmp_1 to i8*)) nounwind, !clang.arc.copy_on_escape !0
>>>> -  call void @bar(i32 ()* bitcast (%block1* @__block_holder_tmp_1 to i32 ()*))
>>>> -  call void @bar(i32 ()* bitcast (%block1* @__block_holder_tmp_1 to i32 ()*))
>>>> -  call void @objc_release(i8* bitcast (%block1* @__block_holder_tmp_1 to i8*)) nounwind
>>>> -  ret void
>>>> -}
>>>> -
>>>> -; Don't optimize objc_retainBlock, but do strength reduce it.
>>>> -
>>>> -; CHECK-LABEL: define void @test3a(i8* %p) {
>>>> -; CHECK: @objc_retain
>>>> -; CHECK: @objc_release
>>>> -; CHECK: }
>>>> -define void @test3a(i8* %p) {
>>>> -entry:
>>>> -  %0 = call i8* @objc_retainBlock(i8* %p) nounwind, !clang.arc.copy_on_escape !0
>>>> -  call void @callee()
>>>> -  call void @use_pointer(i8* %p)
>>>> -  call void @objc_release(i8* %p) nounwind
>>>> -  ret void
>>>> -}
>>>> -
>>>> -; Don't optimize objc_retainBlock, because there's no copy_on_escape metadata.
>>>> -
>>>> -; CHECK-LABEL: define void @test3b(
>>>> -; CHECK: @objc_retainBlock
>>>> -; CHECK: @objc_release
>>>> -; CHECK: }
>>>> -define void @test3b() {
>>>> -entry:
>>>> -  %0 = call i8* @objc_retainBlock(i8* bitcast (%block1* @__block_holder_tmp_1 to i8*)) nounwind
>>>> -  call void @bar(i32 ()* bitcast (%block1* @__block_holder_tmp_1 to i32 ()*))
>>>> -  call void @bar(i32 ()* bitcast (%block1* @__block_holder_tmp_1 to i32 ()*))
>>>> -  call void @objc_release(i8* bitcast (%block1* @__block_holder_tmp_1 to i8*)) nounwind
>>>> -  ret void
>>>> -}
>>>> -
>>>> -; CHECK: attributes [[NUW]] = { nounwind }
>>>>
>>>>
>>>> _______________________________________________
>>>> llvm-commits mailing list
>>>> llvm-commits at cs.uiuc.edu
>>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>>
>>>
>>> _______________________________________________
>>> llvm-commits mailing list
>>> llvm-commits at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>




More information about the llvm-commits mailing list