342 changes: 168 additions & 174 deletions llvm/test/Transforms/ObjCARC/inlined-autorelease-return-value.ll

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions llvm/test/Transforms/ObjCARC/intrinsic-use-isolated.ll
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ declare void @llvm.objc.clang.arc.use(...) nounwind
; CHECK-LABEL: define void @test0(
; CHECK-NOT: clang.arc.use
; CHECK: }
define void @test0(i8* %a, i8* %b) {
call void (...) @llvm.objc.clang.arc.use(i8* %a, i8* %b) nounwind
define void @test0(ptr %a, ptr %b) {
call void (...) @llvm.objc.clang.arc.use(ptr %a, ptr %b) nounwind
ret void
}

176 changes: 88 additions & 88 deletions llvm/test/Transforms/ObjCARC/intrinsic-use.ll
Original file line number Diff line number Diff line change
Expand Up @@ -2,127 +2,127 @@

target datalayout = "e-p:64:64:64"

declare i8* @llvm.objc.retain(i8*)
declare i8* @llvm.objc.retainAutorelease(i8*)
declare void @llvm.objc.release(i8*)
declare i8* @llvm.objc.autorelease(i8*)
declare ptr @llvm.objc.retain(ptr)
declare ptr @llvm.objc.retainAutorelease(ptr)
declare void @llvm.objc.release(ptr)
declare ptr @llvm.objc.autorelease(ptr)

declare void @llvm.objc.clang.arc.use(...)
declare void @llvm.objc.clang.arc.noop.use(...)

declare void @test0_helper(i8*, i8**)
declare void @can_release(i8*)
declare void @test0_helper(ptr, ptr)
declare void @can_release(ptr)

; Ensure that we honor clang.arc.use as a use and don't miscompile
; the reduced test case from <rdar://13195034>.
;
; CHECK-LABEL: define void @test0(
; CHECK: @llvm.objc.retain(i8* %x)
; CHECK-NEXT: store i8* %y, i8** %temp0
; CHECK-NEXT: @llvm.objc.retain(i8* %y)
; CHECK: @llvm.objc.retain(ptr %x)
; CHECK-NEXT: store ptr %y, ptr %temp0
; CHECK-NEXT: @llvm.objc.retain(ptr %y)
; CHECK-NEXT: call void @test0_helper
; CHECK-NEXT: [[VAL1:%.*]] = load i8*, i8** %temp0
; CHECK-NEXT: @llvm.objc.retain(i8* [[VAL1]])
; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(i8* %y)
; CHECK-NEXT: @llvm.objc.release(i8* %y)
; CHECK-NEXT: store i8* [[VAL1]], i8** %temp1
; CHECK-NEXT: [[VAL1:%.*]] = load ptr, ptr %temp0
; CHECK-NEXT: @llvm.objc.retain(ptr [[VAL1]])
; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr %y)
; CHECK-NEXT: @llvm.objc.release(ptr %y)
; CHECK-NEXT: store ptr [[VAL1]], ptr %temp1
; CHECK-NEXT: call void @test0_helper
; CHECK-NEXT: [[VAL2:%.*]] = load i8*, i8** %temp1
; CHECK-NEXT: @llvm.objc.retain(i8* [[VAL2]])
; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(i8* [[VAL1]])
; CHECK-NEXT: @llvm.objc.release(i8* [[VAL1]])
; CHECK-NEXT: @llvm.objc.autorelease(i8* %x)
; CHECK-NEXT: store i8* %x, i8** %out
; CHECK-NEXT: @llvm.objc.retain(i8* %x)
; CHECK-NEXT: @llvm.objc.release(i8* [[VAL2]])
; CHECK-NEXT: @llvm.objc.release(i8* %x)
; CHECK-NEXT: [[VAL2:%.*]] = load ptr, ptr %temp1
; CHECK-NEXT: @llvm.objc.retain(ptr [[VAL2]])
; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[VAL1]])
; CHECK-NEXT: @llvm.objc.release(ptr [[VAL1]])
; CHECK-NEXT: @llvm.objc.autorelease(ptr %x)
; CHECK-NEXT: store ptr %x, ptr %out
; CHECK-NEXT: @llvm.objc.retain(ptr %x)
; CHECK-NEXT: @llvm.objc.release(ptr [[VAL2]])
; CHECK-NEXT: @llvm.objc.release(ptr %x)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test0(i8** %out, i8* %x, i8* %y) {
define void @test0(ptr %out, ptr %x, ptr %y) {
entry:
%temp0 = alloca i8*, align 8
%temp1 = alloca i8*, align 8
%0 = call i8* @llvm.objc.retain(i8* %x) nounwind
%1 = call i8* @llvm.objc.retain(i8* %y) nounwind
store i8* %y, i8** %temp0
call void @test0_helper(i8* %x, i8** %temp0)
%val1 = load i8*, i8** %temp0
%2 = call i8* @llvm.objc.retain(i8* %val1) nounwind
call void (...) @llvm.objc.clang.arc.use(i8* %y) nounwind
call void @llvm.objc.release(i8* %y) nounwind
store i8* %val1, i8** %temp1
call void @test0_helper(i8* %x, i8** %temp1)
%val2 = load i8*, i8** %temp1
%3 = call i8* @llvm.objc.retain(i8* %val2) nounwind
call void (...) @llvm.objc.clang.arc.use(i8* %val1) nounwind
call void @llvm.objc.release(i8* %val1) nounwind
%4 = call i8* @llvm.objc.retain(i8* %x) nounwind
%5 = call i8* @llvm.objc.autorelease(i8* %x) nounwind
store i8* %x, i8** %out
call void @llvm.objc.release(i8* %val2) nounwind
call void @llvm.objc.release(i8* %x) nounwind
%temp0 = alloca ptr, align 8
%temp1 = alloca ptr, align 8
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
%1 = call ptr @llvm.objc.retain(ptr %y) nounwind
store ptr %y, ptr %temp0
call void @test0_helper(ptr %x, ptr %temp0)
%val1 = load ptr, ptr %temp0
%2 = call ptr @llvm.objc.retain(ptr %val1) nounwind
call void (...) @llvm.objc.clang.arc.use(ptr %y) nounwind
call void @llvm.objc.release(ptr %y) nounwind
store ptr %val1, ptr %temp1
call void @test0_helper(ptr %x, ptr %temp1)
%val2 = load ptr, ptr %temp1
%3 = call ptr @llvm.objc.retain(ptr %val2) nounwind
call void (...) @llvm.objc.clang.arc.use(ptr %val1) nounwind
call void @llvm.objc.release(ptr %val1) nounwind
%4 = call ptr @llvm.objc.retain(ptr %x) nounwind
%5 = call ptr @llvm.objc.autorelease(ptr %x) nounwind
store ptr %x, ptr %out
call void @llvm.objc.release(ptr %val2) nounwind
call void @llvm.objc.release(ptr %x) nounwind
ret void
}

; CHECK-LABEL: define void @test0a(
; CHECK: @llvm.objc.retain(i8* %x)
; CHECK-NEXT: store i8* %y, i8** %temp0
; CHECK-NEXT: @llvm.objc.retain(i8* %y)
; CHECK: @llvm.objc.retain(ptr %x)
; CHECK-NEXT: store ptr %y, ptr %temp0
; CHECK-NEXT: @llvm.objc.retain(ptr %y)
; CHECK-NEXT: call void @test0_helper
; CHECK-NEXT: [[VAL1:%.*]] = load i8*, i8** %temp0
; CHECK-NEXT: @llvm.objc.retain(i8* [[VAL1]])
; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(i8* %y)
; CHECK-NEXT: @llvm.objc.release(i8* %y)
; CHECK-NEXT: store i8* [[VAL1]], i8** %temp1
; CHECK-NEXT: [[VAL1:%.*]] = load ptr, ptr %temp0
; CHECK-NEXT: @llvm.objc.retain(ptr [[VAL1]])
; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr %y)
; CHECK-NEXT: @llvm.objc.release(ptr %y)
; CHECK-NEXT: store ptr [[VAL1]], ptr %temp1
; CHECK-NEXT: call void @test0_helper
; CHECK-NEXT: [[VAL2:%.*]] = load i8*, i8** %temp1
; CHECK-NEXT: @llvm.objc.retain(i8* [[VAL2]])
; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(i8* [[VAL1]])
; CHECK-NEXT: @llvm.objc.release(i8* [[VAL1]])
; CHECK-NEXT: @llvm.objc.autorelease(i8* %x)
; CHECK-NEXT: @llvm.objc.release(i8* [[VAL2]])
; CHECK-NEXT: store i8* %x, i8** %out
; CHECK-NEXT: [[VAL2:%.*]] = load ptr, ptr %temp1
; CHECK-NEXT: @llvm.objc.retain(ptr [[VAL2]])
; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(ptr [[VAL1]])
; CHECK-NEXT: @llvm.objc.release(ptr [[VAL1]])
; CHECK-NEXT: @llvm.objc.autorelease(ptr %x)
; CHECK-NEXT: @llvm.objc.release(ptr [[VAL2]])
; CHECK-NEXT: store ptr %x, ptr %out
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test0a(i8** %out, i8* %x, i8* %y) {
define void @test0a(ptr %out, ptr %x, ptr %y) {
entry:
%temp0 = alloca i8*, align 8
%temp1 = alloca i8*, align 8
%0 = call i8* @llvm.objc.retain(i8* %x) nounwind
%1 = call i8* @llvm.objc.retain(i8* %y) nounwind
store i8* %y, i8** %temp0
call void @test0_helper(i8* %x, i8** %temp0)
%val1 = load i8*, i8** %temp0
%2 = call i8* @llvm.objc.retain(i8* %val1) nounwind
call void (...) @llvm.objc.clang.arc.use(i8* %y) nounwind
call void @llvm.objc.release(i8* %y) nounwind, !clang.imprecise_release !0
store i8* %val1, i8** %temp1
call void @test0_helper(i8* %x, i8** %temp1)
%val2 = load i8*, i8** %temp1
%3 = call i8* @llvm.objc.retain(i8* %val2) nounwind
call void (...) @llvm.objc.clang.arc.use(i8* %val1) nounwind
call void @llvm.objc.release(i8* %val1) nounwind, !clang.imprecise_release !0
%4 = call i8* @llvm.objc.retain(i8* %x) nounwind
%5 = call i8* @llvm.objc.autorelease(i8* %x) nounwind
store i8* %x, i8** %out
call void @llvm.objc.release(i8* %val2) nounwind, !clang.imprecise_release !0
call void @llvm.objc.release(i8* %x) nounwind, !clang.imprecise_release !0
%temp0 = alloca ptr, align 8
%temp1 = alloca ptr, align 8
%0 = call ptr @llvm.objc.retain(ptr %x) nounwind
%1 = call ptr @llvm.objc.retain(ptr %y) nounwind
store ptr %y, ptr %temp0
call void @test0_helper(ptr %x, ptr %temp0)
%val1 = load ptr, ptr %temp0
%2 = call ptr @llvm.objc.retain(ptr %val1) nounwind
call void (...) @llvm.objc.clang.arc.use(ptr %y) nounwind
call void @llvm.objc.release(ptr %y) nounwind, !clang.imprecise_release !0
store ptr %val1, ptr %temp1
call void @test0_helper(ptr %x, ptr %temp1)
%val2 = load ptr, ptr %temp1
%3 = call ptr @llvm.objc.retain(ptr %val2) nounwind
call void (...) @llvm.objc.clang.arc.use(ptr %val1) nounwind
call void @llvm.objc.release(ptr %val1) nounwind, !clang.imprecise_release !0
%4 = call ptr @llvm.objc.retain(ptr %x) nounwind
%5 = call ptr @llvm.objc.autorelease(ptr %x) nounwind
store ptr %x, ptr %out
call void @llvm.objc.release(ptr %val2) nounwind, !clang.imprecise_release !0
call void @llvm.objc.release(ptr %x) nounwind, !clang.imprecise_release !0
ret void
}

; ARC optimizer should be able to safely remove the retain/release pair as the
; call to @llvm.objc.clang.arc.noop.use is a no-op.

; CHECK-LABEL: define void @test_arc_noop_use(
; CHECK-NEXT: call void @can_release(i8* %x)
; CHECK-NEXT: call void @can_release(ptr %x)
; CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(
; CHECK-NEXT: ret void

define void @test_arc_noop_use(i8** %out, i8* %x) {
call i8* @llvm.objc.retain(i8* %x)
call void @can_release(i8* %x)
call void (...) @llvm.objc.clang.arc.noop.use(i8* %x)
call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
define void @test_arc_noop_use(ptr %out, ptr %x) {
call ptr @llvm.objc.retain(ptr %x)
call void @can_release(ptr %x)
call void (...) @llvm.objc.clang.arc.noop.use(ptr %x)
call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
ret void
}

Expand Down
36 changes: 18 additions & 18 deletions llvm/test/Transforms/ObjCARC/invoke-2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,51 @@ target triple = "x86_64-unknown-windows-msvc"

declare i32 @__CxxFrameHandler3(...)

declare dllimport i8* @objc_msgSend(i8*, i8*, ...) local_unnamed_addr
declare dllimport ptr @objc_msgSend(ptr, ptr, ...) local_unnamed_addr

declare dllimport i8* @llvm.objc.retain(i8* returned) local_unnamed_addr
declare dllimport void @llvm.objc.release(i8*) local_unnamed_addr
declare dllimport i8* @llvm.objc.retainAutoreleasedReturnValue(i8* returned) local_unnamed_addr
declare dllimport ptr @llvm.objc.retain(ptr returned) local_unnamed_addr
declare dllimport void @llvm.objc.release(ptr) local_unnamed_addr
declare dllimport ptr @llvm.objc.retainAutoreleasedReturnValue(ptr returned) local_unnamed_addr

declare dllimport i8* @llvm.objc.begin_catch(i8*) local_unnamed_addr
declare dllimport ptr @llvm.objc.begin_catch(ptr) local_unnamed_addr
declare dllimport void @llvm.objc.end_catch() local_unnamed_addr

@llvm.objc.METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"m\00", align 1
@llvm.objc.SELECTOR_REFERENCES_ = private externally_initialized global i8* getelementptr inbounds ([2 x i8], [2 x i8]* @llvm.objc.METH_VAR_NAME_, i64 0, i64 0), section ".objc_selrefs$B", align 8
@llvm.objc.SELECTOR_REFERENCES_ = private externally_initialized global ptr @llvm.objc.METH_VAR_NAME_, section ".objc_selrefs$B", align 8

define void @f(i8* %i) local_unnamed_addr personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
define void @f(ptr %i) local_unnamed_addr personality ptr @__CxxFrameHandler3 {
entry:
%0 = tail call i8* @llvm.objc.retain(i8* %i)
%1 = load i8*, i8** @llvm.objc.SELECTOR_REFERENCES_, align 8, !invariant.load !0
%call = invoke i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %0, i8* %1)
%0 = tail call ptr @llvm.objc.retain(ptr %i)
%1 = load ptr, ptr @llvm.objc.SELECTOR_REFERENCES_, align 8, !invariant.load !0
%call = invoke ptr @objc_msgSend(ptr %0, ptr %1)
to label %invoke.cont unwind label %catch.dispatch, !clang.arc.no_objc_arc_exceptions !0

catch.dispatch: ; preds = %entry
%2 = catchswitch within none [label %catch] unwind to caller

invoke.cont: ; preds = %entry
%3 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call)
tail call void @llvm.objc.release(i8* %3) #0, !clang.imprecise_release !0
%3 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call)
tail call void @llvm.objc.release(ptr %3) #0, !clang.imprecise_release !0
br label %eh.cont

eh.cont: ; preds = %invoke.cont, %catch
tail call void @llvm.objc.release(i8* %0) #0, !clang.imprecise_release !0
tail call void @llvm.objc.release(ptr %0) #0, !clang.imprecise_release !0
ret void

catch: ; preds = %catch.dispatch
%4 = catchpad within %2 [i8* null, i32 0, i8* null]
%exn.adjusted = tail call i8* @llvm.objc.begin_catch(i8* undef)
%4 = catchpad within %2 [ptr null, i32 0, ptr null]
%exn.adjusted = tail call ptr @llvm.objc.begin_catch(ptr undef)
tail call void @llvm.objc.end_catch(), !clang.arc.no_objc_arc_exceptions !0
br label %eh.cont
}

; CHECK-LABEL: @f

; CHECK-NOT: tail call i8* @llvm.objc.retain(i8* %i)
; CHECK: load i8*, i8** @llvm.objc.SELECTOR_REFERENCES_, align 8
; CHECK-NOT: tail call ptr @llvm.objc.retain(ptr %i)
; CHECK: load ptr, ptr @llvm.objc.SELECTOR_REFERENCES_, align 8

; CHECK: eh.cont:
; CHECK-NOT: call void @llvm.objc.release(i8*
; CHECK-NOT: call void @llvm.objc.release(ptr
; CHECK: ret void

attributes #0 = { nounwind }
Expand Down
120 changes: 60 additions & 60 deletions llvm/test/Transforms/ObjCARC/invoke.ll
Original file line number Diff line number Diff line change
@@ -1,218 +1,218 @@
; RUN: opt -S -passes=objc-arc < %s | FileCheck %s

declare i8* @llvm.objc.retain(i8*)
declare void @llvm.objc.release(i8*)
declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)
declare i8* @objc_msgSend(i8*, i8*, ...)
declare void @use_pointer(i8*)
declare ptr @llvm.objc.retain(ptr)
declare void @llvm.objc.release(ptr)
declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)
declare ptr @objc_msgSend(ptr, ptr, ...)
declare void @use_pointer(ptr)
declare void @callee()
declare i8* @returner()
declare ptr @returner()

; ARCOpt shouldn't try to move the releases to the block containing the invoke.

; CHECK-LABEL: define void @test0(
; CHECK: invoke.cont:
; CHECK: call void @llvm.objc.release(i8* %zipFile) [[NUW:#[0-9]+]], !clang.imprecise_release !0
; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW:#[0-9]+]], !clang.imprecise_release !0
; CHECK: ret void
; CHECK: lpad:
; CHECK: call void @llvm.objc.release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW]], !clang.imprecise_release !0
; CHECK: ret void
; CHECK-NEXT: }
define void @test0(i8* %zipFile) personality i32 (...)* @__gxx_personality_v0 {
define void @test0(ptr %zipFile) personality ptr @__gxx_personality_v0 {
entry:
call i8* @llvm.objc.retain(i8* %zipFile) nounwind
call void @use_pointer(i8* %zipFile)
invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*)*)(i8* %zipFile)
call ptr @llvm.objc.retain(ptr %zipFile) nounwind
call void @use_pointer(ptr %zipFile)
invoke void @objc_msgSend(ptr %zipFile)
to label %invoke.cont unwind label %lpad

invoke.cont: ; preds = %entry
call void @llvm.objc.release(i8* %zipFile) nounwind, !clang.imprecise_release !0
call void @llvm.objc.release(ptr %zipFile) nounwind, !clang.imprecise_release !0
ret void

lpad: ; preds = %entry
%exn = landingpad {i8*, i32}
%exn = landingpad {ptr, i32}
cleanup
call void @llvm.objc.release(i8* %zipFile) nounwind, !clang.imprecise_release !0
call void @llvm.objc.release(ptr %zipFile) nounwind, !clang.imprecise_release !0
ret void
}

; ARCOpt should move the release before the callee calls.

; CHECK-LABEL: define void @test1(
; CHECK: invoke.cont:
; CHECK: call void @llvm.objc.release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW]], !clang.imprecise_release !0
; CHECK: call void @callee()
; CHECK: br label %done
; CHECK: lpad:
; CHECK: call void @llvm.objc.release(i8* %zipFile) [[NUW]], !clang.imprecise_release !0
; CHECK: call void @llvm.objc.release(ptr %zipFile) [[NUW]], !clang.imprecise_release !0
; CHECK: call void @callee()
; CHECK: br label %done
; CHECK: done:
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test1(i8* %zipFile) personality i32 (...)* @__gxx_personality_v0 {
define void @test1(ptr %zipFile) personality ptr @__gxx_personality_v0 {
entry:
call i8* @llvm.objc.retain(i8* %zipFile) nounwind
call void @use_pointer(i8* %zipFile)
invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*)*)(i8* %zipFile)
call ptr @llvm.objc.retain(ptr %zipFile) nounwind
call void @use_pointer(ptr %zipFile)
invoke void @objc_msgSend(ptr %zipFile)
to label %invoke.cont unwind label %lpad

invoke.cont: ; preds = %entry
call void @callee()
br label %done

lpad: ; preds = %entry
%exn = landingpad {i8*, i32}
%exn = landingpad {ptr, i32}
cleanup
call void @callee()
br label %done

done:
call void @llvm.objc.release(i8* %zipFile) nounwind, !clang.imprecise_release !0
call void @llvm.objc.release(ptr %zipFile) nounwind, !clang.imprecise_release !0
ret void
}

; The optimizer should ignore invoke unwind paths consistently.
; PR12265

; CHECK: define void @test2() personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
; CHECK: define void @test2() personality ptr @__objc_personality_v0 {
; CHECK: invoke.cont:
; CHECK-NEXT: call i8* @llvm.objc.retain
; CHECK-NEXT: call ptr @llvm.objc.retain
; CHECK-NOT: @llvm.objc.r
; CHECK: finally.cont:
; CHECK-NEXT: call void @llvm.objc.release
; CHECK-NOT: @objc
; CHECK: finally.rethrow:
; CHECK-NOT: @objc
; CHECK: }
define void @test2() personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
define void @test2() personality ptr @__objc_personality_v0 {
entry:
%call = invoke i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* ()*)()
%call = invoke ptr @objc_msgSend()
to label %invoke.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0

invoke.cont: ; preds = %entry
%tmp1 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) nounwind
call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void ()*)(), !clang.arc.no_objc_arc_exceptions !0
invoke void @use_pointer(i8* %call)
%tmp1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
call void @objc_msgSend(), !clang.arc.no_objc_arc_exceptions !0
invoke void @use_pointer(ptr %call)
to label %finally.cont unwind label %finally.rethrow, !clang.arc.no_objc_arc_exceptions !0

finally.cont: ; preds = %invoke.cont
tail call void @llvm.objc.release(i8* %call) nounwind, !clang.imprecise_release !0
tail call void @llvm.objc.release(ptr %call) nounwind, !clang.imprecise_release !0
ret void

finally.rethrow: ; preds = %invoke.cont, %entry
%tmp2 = landingpad { i8*, i32 }
catch i8* null
%tmp2 = landingpad { ptr, i32 }
catch ptr null
unreachable
}

; Don't try to place code on invoke critical edges.

; CHECK-LABEL: define void @test3(
; CHECK: if.end:
; CHECK-NEXT: call void @llvm.objc.release(i8* %p) [[NUW]]
; CHECK-NEXT: call void @llvm.objc.release(ptr %p) [[NUW]]
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test3(i8* %p, i1 %b) personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
define void @test3(ptr %p, i1 %b) personality ptr @__objc_personality_v0 {
entry:
%0 = call i8* @llvm.objc.retain(i8* %p)
%0 = call ptr @llvm.objc.retain(ptr %p)
call void @callee()
br i1 %b, label %if.else, label %if.then

if.then:
invoke void @use_pointer(i8* %p)
invoke void @use_pointer(ptr %p)
to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0

if.else:
invoke void @use_pointer(i8* %p)
invoke void @use_pointer(ptr %p)
to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0

lpad:
%r = landingpad { i8*, i32 }
%r = landingpad { ptr, i32 }
cleanup
ret void

if.end:
call void @llvm.objc.release(i8* %p)
call void @llvm.objc.release(ptr %p)
ret void
}

; Like test3, but with ARC-relevant exception handling.

; CHECK-LABEL: define void @test4(
; CHECK: lpad:
; CHECK-NEXT: %r = landingpad { i8*, i32 }
; CHECK-NEXT: %r = landingpad { ptr, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: call void @llvm.objc.release(i8* %p) [[NUW]]
; CHECK-NEXT: call void @llvm.objc.release(ptr %p) [[NUW]]
; CHECK-NEXT: ret void
; CHECK: if.end:
; CHECK-NEXT: call void @llvm.objc.release(i8* %p) [[NUW]]
; CHECK-NEXT: call void @llvm.objc.release(ptr %p) [[NUW]]
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test4(i8* %p, i1 %b) personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
define void @test4(ptr %p, i1 %b) personality ptr @__objc_personality_v0 {
entry:
%0 = call i8* @llvm.objc.retain(i8* %p)
%0 = call ptr @llvm.objc.retain(ptr %p)
call void @callee()
br i1 %b, label %if.else, label %if.then

if.then:
invoke void @use_pointer(i8* %p)
invoke void @use_pointer(ptr %p)
to label %if.end unwind label %lpad

if.else:
invoke void @use_pointer(i8* %p)
invoke void @use_pointer(ptr %p)
to label %if.end unwind label %lpad

lpad:
%r = landingpad { i8*, i32 }
%r = landingpad { ptr, i32 }
cleanup
call void @llvm.objc.release(i8* %p)
call void @llvm.objc.release(ptr %p)
ret void

if.end:
call void @llvm.objc.release(i8* %p)
call void @llvm.objc.release(ptr %p)
ret void
}

; Don't turn the retainAutoreleaseReturnValue into retain, because it's
; for an invoke which we can assume codegen will put immediately prior.

; CHECK-LABEL: define void @test5(
; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %z)
; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z)
; CHECK: }
define void @test5() personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
define void @test5() personality ptr @__objc_personality_v0 {
entry:
%z = invoke i8* @returner()
%z = invoke ptr @returner()
to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0

lpad:
%r13 = landingpad { i8*, i32 }
%r13 = landingpad { ptr, i32 }
cleanup
ret void

if.end:
call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %z)
call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z)
ret void
}

; Like test5, but there's intervening code.

; CHECK-LABEL: define void @test6(
; CHECK: call i8* @llvm.objc.retain(i8* %z)
; CHECK: call ptr @llvm.objc.retain(ptr %z)
; CHECK: }
define void @test6() personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
define void @test6() personality ptr @__objc_personality_v0 {
entry:
%z = invoke i8* @returner()
%z = invoke ptr @returner()
to label %if.end unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0

lpad:
%r13 = landingpad { i8*, i32 }
%r13 = landingpad { ptr, i32 }
cleanup
ret void

if.end:
call void @callee()
call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %z)
call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z)
ret void
}

Expand Down
275 changes: 124 additions & 151 deletions llvm/test/Transforms/ObjCARC/move-and-form-retain-autorelease.ll

Large diffs are not rendered by default.

107 changes: 46 additions & 61 deletions llvm/test/Transforms/ObjCARC/move-and-merge-autorelease.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
; and fold it with the release in bb65.

; CHECK: bb65:
; CHECK: call i8* @llvm.objc.retainAutorelease
; CHECK: call ptr @llvm.objc.retainAutorelease
; CHECK: br label %bb76

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"
Expand All @@ -17,92 +17,77 @@ target triple = "x86_64-apple-darwin11.0.0"
%4 = type opaque
%5 = type opaque

@"\01L_OBJC_SELECTOR_REFERENCES_11" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_421455" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_598" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_620" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_622" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_624" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_626" = external hidden global i8*, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_11" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_421455" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_598" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_620" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_622" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_624" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
@"\01L_OBJC_SELECTOR_REFERENCES_626" = external hidden global ptr, section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"

declare i8* @objc_msgSend(i8*, i8*, ...)
declare ptr @objc_msgSend(ptr, ptr, ...)

declare i8* @llvm.objc.retain(i8*)
declare ptr @llvm.objc.retain(ptr)

declare void @llvm.objc.release(i8*)
declare void @llvm.objc.release(ptr)

declare i8* @llvm.objc.autorelease(i8*)
declare ptr @llvm.objc.autorelease(ptr)

define hidden %0* @foo(%1* %arg, %3* %arg3) {
define hidden ptr @foo(ptr %arg, ptr %arg3) {
bb:
%tmp16 = load i8*, i8** @"\01L_OBJC_SELECTOR_REFERENCES_620", align 8
%tmp17 = bitcast %3* %arg3 to i8*
%tmp18 = call %4* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %4* (i8*, i8*)*)(i8* %tmp17, i8* %tmp16)
%tmp19 = load i8*, i8** @"\01L_OBJC_SELECTOR_REFERENCES_622", align 8
%tmp20 = bitcast %4* %tmp18 to i8*
%tmp21 = call %5* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %5* (i8*, i8*)*)(i8* %tmp20, i8* %tmp19)
%tmp22 = bitcast %5* %tmp21 to i8*
%tmp23 = call i8* @llvm.objc.retain(i8* %tmp22) nounwind
%tmp24 = bitcast i8* %tmp23 to %5*
%tmp26 = icmp eq i8* %tmp23, null
%tmp16 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_620", align 8
%tmp18 = call ptr @objc_msgSend(ptr %arg3, ptr %tmp16)
%tmp19 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_622", align 8
%tmp21 = call ptr @objc_msgSend(ptr %tmp18, ptr %tmp19)
%tmp23 = call ptr @llvm.objc.retain(ptr %tmp21) nounwind
%tmp26 = icmp eq ptr %tmp23, null
br i1 %tmp26, label %bb81, label %bb27

bb27: ; preds = %bb
%tmp29 = load i8*, i8** @"\01L_OBJC_SELECTOR_REFERENCES_11", align 8
%tmp30 = bitcast %1* %arg to i8*
%tmp31 = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %tmp30, i8* %tmp29)
%tmp34 = call i8* @llvm.objc.retain(i8* %tmp31) nounwind
%tmp37 = load i8*, i8** @"\01L_OBJC_SELECTOR_REFERENCES_421455", align 8
%tmp39 = call %0* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %0* (i8*, i8*)*)(i8* %tmp34, i8* %tmp37)
%tmp40 = bitcast %0* %tmp39 to i8*
%tmp41 = call i8* @llvm.objc.retain(i8* %tmp40) nounwind
%tmp42 = bitcast i8* %tmp41 to %0*
%tmp44 = icmp eq i8* %tmp41, null
%tmp29 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_11", align 8
%tmp31 = call ptr @objc_msgSend(ptr %arg, ptr %tmp29)
%tmp34 = call ptr @llvm.objc.retain(ptr %tmp31) nounwind
%tmp37 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_421455", align 8
%tmp39 = call ptr @objc_msgSend(ptr %tmp34, ptr %tmp37)
%tmp41 = call ptr @llvm.objc.retain(ptr %tmp39) nounwind
%tmp44 = icmp eq ptr %tmp41, null
br i1 %tmp44, label %bb45, label %bb55

bb45: ; preds = %bb27
%tmp47 = load i8*, i8** @"\01L_OBJC_SELECTOR_REFERENCES_624", align 8
%tmp49 = call %0* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %0* (i8*, i8*)*)(i8* %tmp34, i8* %tmp47)
%tmp51 = bitcast %0* %tmp49 to i8*
%tmp52 = call i8* @llvm.objc.retain(i8* %tmp51) nounwind
call void @llvm.objc.release(i8* %tmp41) nounwind
%tmp47 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_624", align 8
%tmp49 = call ptr @objc_msgSend(ptr %tmp34, ptr %tmp47)
%tmp52 = call ptr @llvm.objc.retain(ptr %tmp49) nounwind
call void @llvm.objc.release(ptr %tmp41) nounwind
br label %bb55

bb55: ; preds = %bb27, %bb45
%tmp13.0 = phi %0* [ %tmp42, %bb27 ], [ %tmp49, %bb45 ]
%tmp57 = icmp eq %0* %tmp13.0, null
%tmp13.0 = phi ptr [ %tmp41, %bb27 ], [ %tmp49, %bb45 ]
%tmp57 = icmp eq ptr %tmp13.0, null
br i1 %tmp57, label %bb76, label %bb58

bb58: ; preds = %bb55
%tmp60 = load i8*, i8** @"\01L_OBJC_SELECTOR_REFERENCES_598", align 8
%tmp61 = bitcast %0* %tmp13.0 to i8*
%tmp62 = call signext i8 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8 (i8*, i8*)*)(i8* %tmp61, i8* %tmp60)
%tmp60 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_598", align 8
%tmp62 = call signext i8 @objc_msgSend(ptr %tmp13.0, ptr %tmp60)
%tmp64 = icmp eq i8 %tmp62, 0
br i1 %tmp64, label %bb76, label %bb65

bb65: ; preds = %bb58
%tmp68 = load i8*, i8** @"\01L_OBJC_SELECTOR_REFERENCES_626", align 8
%tmp69 = bitcast %0* %tmp13.0 to i8*
%tmp70 = call %0* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %0* (i8*, i8*, %5*)*)(i8* %tmp69, i8* %tmp68, %5* %tmp24)
%tmp72 = bitcast %0* %tmp70 to i8*
%tmp73 = call i8* @llvm.objc.retain(i8* %tmp72) nounwind
%tmp68 = load ptr, ptr @"\01L_OBJC_SELECTOR_REFERENCES_626", align 8
%tmp70 = call ptr @objc_msgSend(ptr %tmp13.0, ptr %tmp68, ptr %tmp23)
%tmp73 = call ptr @llvm.objc.retain(ptr %tmp70) nounwind
br label %bb76

bb76: ; preds = %bb58, %bb55, %bb65
%tmp10.0 = phi %0* [ %tmp70, %bb65 ], [ null, %bb58 ], [ null, %bb55 ]
%tmp78 = bitcast %0* %tmp13.0 to i8*
call void @llvm.objc.release(i8* %tmp78) nounwind
call void @llvm.objc.release(i8* %tmp34) nounwind
%tmp10.0 = phi ptr [ %tmp70, %bb65 ], [ null, %bb58 ], [ null, %bb55 ]
call void @llvm.objc.release(ptr %tmp13.0) nounwind
call void @llvm.objc.release(ptr %tmp34) nounwind
br label %bb81

bb81: ; preds = %bb, %bb76
%tmp10.1 = phi %0* [ %tmp10.0, %bb76 ], [ null, %bb ]
%tmp83 = bitcast %0* %tmp10.1 to i8*
%tmp84 = call i8* @llvm.objc.retain(i8* %tmp83) nounwind
call void @llvm.objc.release(i8* %tmp23) nounwind
%tmp87 = call i8* @llvm.objc.autorelease(i8* %tmp84) nounwind
%tmp88 = bitcast i8* %tmp87 to %0*
%tmp92 = bitcast %0* %tmp10.1 to i8*
call void @llvm.objc.release(i8* %tmp92) nounwind
ret %0* %tmp88
%tmp10.1 = phi ptr [ %tmp10.0, %bb76 ], [ null, %bb ]
%tmp84 = call ptr @llvm.objc.retain(ptr %tmp10.1) nounwind
call void @llvm.objc.release(ptr %tmp23) nounwind
%tmp87 = call ptr @llvm.objc.autorelease(ptr %tmp84) nounwind
call void @llvm.objc.release(ptr %tmp10.1) nounwind
ret ptr %tmp87
}
637 changes: 312 additions & 325 deletions llvm/test/Transforms/ObjCARC/nested.ll

Large diffs are not rendered by default.

52 changes: 26 additions & 26 deletions llvm/test/Transforms/ObjCARC/opt-catchswitch.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,62 @@
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686--windows-msvc"

declare i8* @f(i8*, i8*)
declare ptr @f(ptr, ptr)

declare i32 @__CxxFrameHandler3(...)

declare dllimport i8* @llvm.objc.autoreleaseReturnValue(i8* returned)
declare dllimport i8* @llvm.objc.retain(i8* returned)
declare dllimport i8* @llvm.objc.retainAutoreleasedReturnValue(i8* returned)
declare dllimport void @llvm.objc.release(i8*)
declare dllimport ptr @llvm.objc.autoreleaseReturnValue(ptr returned)
declare dllimport ptr @llvm.objc.retain(ptr returned)
declare dllimport ptr @llvm.objc.retainAutoreleasedReturnValue(ptr returned)
declare dllimport void @llvm.objc.release(ptr)

define i8* @g(i8* %p, i8* %q) local_unnamed_addr personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
define ptr @g(ptr %p, ptr %q) local_unnamed_addr personality ptr @__CxxFrameHandler3 {
; CHECK-LABEL: @g(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = tail call i8* @llvm.objc.retain(i8* [[P:%.*]]) #[[ATTR0:[0-9]+]]
; CHECK-NEXT: [[V1:%.*]] = call i8* @f(i8* null, i8* null)
; CHECK-NEXT: [[CALL:%.*]] = invoke i8* @f(i8* [[P]], i8* [[Q:%.*]])
; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @llvm.objc.retain(ptr [[P:%.*]]) #[[ATTR0:[0-9]+]]
; CHECK-NEXT: [[V1:%.*]] = call ptr @f(ptr null, ptr null)
; CHECK-NEXT: [[CALL:%.*]] = invoke ptr @f(ptr [[P]], ptr [[Q:%.*]])
; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[CATCH_DISPATCH:%.*]], !clang.arc.no_objc_arc_exceptions !0
; CHECK: catch.dispatch:
; CHECK-NEXT: [[TMP1:%.*]] = catchswitch within none [label %catch] unwind to caller
; CHECK: catch:
; CHECK-NEXT: [[TMP2:%.*]] = catchpad within [[TMP1]] [i8* null, i32 64, i8* null]
; CHECK-NEXT: [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 64, ptr null]
; CHECK-NEXT: catchret from [[TMP2]] to label [[CLEANUP:%.*]]
; CHECK: invoke.cont:
; CHECK-NEXT: [[TMP3:%.*]] = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* [[CALL]]) #[[ATTR0]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr [[CALL]]) #[[ATTR0]]
; CHECK-NEXT: br label [[CLEANUP]]
; CHECK: cleanup:
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i8* [ [[CALL]], [[INVOKE_CONT]] ], [ null, [[CATCH:%.*]] ]
; CHECK-NEXT: tail call void @llvm.objc.release(i8* [[P]]) #[[ATTR0]], !clang.imprecise_release !0
; CHECK-NEXT: [[TMP4:%.*]] = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* [[RETVAL_0]]) #[[ATTR0]]
; CHECK-NEXT: ret i8* [[RETVAL_0]]
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi ptr [ [[CALL]], [[INVOKE_CONT]] ], [ null, [[CATCH:%.*]] ]
; CHECK-NEXT: tail call void @llvm.objc.release(ptr [[P]]) #[[ATTR0]], !clang.imprecise_release !0
; CHECK-NEXT: [[TMP4:%.*]] = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr [[RETVAL_0]]) #[[ATTR0]]
; CHECK-NEXT: ret ptr [[RETVAL_0]]
;
entry:
%0 = tail call i8* @llvm.objc.retain(i8* %p) #0
%0 = tail call ptr @llvm.objc.retain(ptr %p) #0
; the following call prevents ARC optimizer from removing the retain/release
; pair on %p
%v1 = call i8* @f(i8* null, i8* null)
%1 = tail call i8* @llvm.objc.retain(i8* %q) #0
%call = invoke i8* @f(i8* %p, i8* %q)
%v1 = call ptr @f(ptr null, ptr null)
%1 = tail call ptr @llvm.objc.retain(ptr %q) #0
%call = invoke ptr @f(ptr %p, ptr %q)
to label %invoke.cont unwind label %catch.dispatch, !clang.arc.no_objc_arc_exceptions !0

catch.dispatch:
%2 = catchswitch within none [label %catch] unwind to caller

catch:
%3 = catchpad within %2 [i8* null, i32 64, i8* null]
%3 = catchpad within %2 [ptr null, i32 64, ptr null]
catchret from %3 to label %cleanup

invoke.cont:
%4 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) #0
%4 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) #0
br label %cleanup

cleanup:
%retval.0 = phi i8* [ %call, %invoke.cont ], [ null, %catch ]
tail call void @llvm.objc.release(i8* %q) #0, !clang.imprecise_release !0
tail call void @llvm.objc.release(i8* %p) #0, !clang.imprecise_release !0
%5 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %retval.0) #0
ret i8* %retval.0
%retval.0 = phi ptr [ %call, %invoke.cont ], [ null, %catch ]
tail call void @llvm.objc.release(ptr %q) #0, !clang.imprecise_release !0
tail call void @llvm.objc.release(ptr %p) #0, !clang.imprecise_release !0
%5 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %retval.0) #0
ret ptr %retval.0
}

attributes #0 = { nounwind }
Expand Down
26 changes: 13 additions & 13 deletions llvm/test/Transforms/ObjCARC/opt-max-ptr-states.ll
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
; RUN: opt -passes=objc-arc -S < %s | FileCheck -check-prefix=ENABLE -check-prefix=CHECK %s
; RUN: opt -passes=objc-arc -arc-opt-max-ptr-states=1 -S < %s | FileCheck -check-prefix=DISABLE -check-prefix=CHECK %s

@g0 = common global i8* null, align 8
@g0 = common global ptr null, align 8

; CHECK: call i8* @llvm.objc.retain
; ENABLE-NOT: call i8* @llvm.objc.retain
; DISABLE: call i8* @llvm.objc.retain
; CHECK: call ptr @llvm.objc.retain
; ENABLE-NOT: call ptr @llvm.objc.retain
; DISABLE: call ptr @llvm.objc.retain
; CHECK: call void @llvm.objc.release
; ENABLE-NOT: call void @llvm.objc.release
; DISABLE: call void @llvm.objc.release

define void @foo0(i8* %a) {
%1 = tail call i8* @llvm.objc.retain(i8* %a)
%2 = tail call i8* @llvm.objc.retain(i8* %a)
%3 = load i8*, i8** @g0, align 8
store i8* %a, i8** @g0, align 8
tail call void @llvm.objc.release(i8* %3)
tail call void @llvm.objc.release(i8* %a), !clang.imprecise_release !0
define void @foo0(ptr %a) {
%1 = tail call ptr @llvm.objc.retain(ptr %a)
%2 = tail call ptr @llvm.objc.retain(ptr %a)
%3 = load ptr, ptr @g0, align 8
store ptr %a, ptr @g0, align 8
tail call void @llvm.objc.release(ptr %3)
tail call void @llvm.objc.release(ptr %a), !clang.imprecise_release !0
ret void
}

declare i8* @llvm.objc.retain(i8*)
declare void @llvm.objc.release(i8*)
declare ptr @llvm.objc.retain(ptr)
declare void @llvm.objc.release(ptr)

!0 = !{}
439 changes: 219 additions & 220 deletions llvm/test/Transforms/ObjCARC/path-overflow.ll

Large diffs are not rendered by default.

20 changes: 9 additions & 11 deletions llvm/test/Transforms/ObjCARC/pointer-types.ll
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,24 @@
; rdar://10551239

; CHECK-LABEL: define void @test0(
; CHECK: %otherBlock = phi void ()* [ %b1, %if.then ], [ null, %entry ]
; CHECK-NEXT: call void @use_fptr(void ()* %otherBlock)
; CHECK-NEXT: %tmp11 = bitcast void ()* %otherBlock to i8*
; CHECK-NEXT: call void @llvm.objc.release(i8* %tmp11)
; CHECK: %otherBlock = phi ptr [ %b1, %if.then ], [ null, %entry ]
; CHECK-NEXT: call void @use_fptr(ptr %otherBlock)
; CHECK-NEXT: call void @llvm.objc.release(ptr %otherBlock)

define void @test0(i1 %tobool, void ()* %b1) {
define void @test0(i1 %tobool, ptr %b1) {
entry:
br i1 %tobool, label %if.end, label %if.then

if.then: ; preds = %entry
br label %if.end

if.end: ; preds = %if.then, %entry
%otherBlock = phi void ()* [ %b1, %if.then ], [ null, %entry ]
call void @use_fptr(void ()* %otherBlock)
%tmp11 = bitcast void ()* %otherBlock to i8*
call void @llvm.objc.release(i8* %tmp11) nounwind
%otherBlock = phi ptr [ %b1, %if.then ], [ null, %entry ]
call void @use_fptr(ptr %otherBlock)
call void @llvm.objc.release(ptr %otherBlock) nounwind
ret void
}

declare void @use_fptr(void ()*)
declare void @llvm.objc.release(i8*)
declare void @use_fptr(ptr)
declare void @llvm.objc.release(ptr)

96 changes: 46 additions & 50 deletions llvm/test/Transforms/ObjCARC/post-inlining.ll
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
; RUN: opt -S -passes=objc-arc < %s | FileCheck %s

declare void @use_pointer(i8*)
declare i8* @returner()
declare i8* @llvm.objc.retain(i8*)
declare i8* @llvm.objc.autoreleaseReturnValue(i8*)
declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)
declare void @use_pointer(ptr)
declare ptr @returner()
declare ptr @llvm.objc.retain(ptr)
declare ptr @llvm.objc.autoreleaseReturnValue(ptr)
declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)

; Clean up residue left behind after inlining.

; CHECK-LABEL: define void @test0(
; CHECK: entry:
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test0(i8* %call.i) {
define void @test0(ptr %call.i) {
entry:
%0 = tail call i8* @llvm.objc.retain(i8* %call.i) nounwind
%1 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind
%0 = tail call ptr @llvm.objc.retain(ptr %call.i) nounwind
%1 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %0) nounwind
ret void
}

Expand All @@ -25,25 +25,25 @@ entry:
; CHECK: entry:
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test1(i8* %call.i) {
define void @test1(ptr %call.i) {
entry:
%0 = tail call i8* @llvm.objc.retain(i8* %call.i) nounwind
%1 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call.i) nounwind
%0 = tail call ptr @llvm.objc.retain(ptr %call.i) nounwind
%1 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %call.i) nounwind
ret void
}

; Delete a retainRV+autoreleaseRV even if the pointer is used.

; CHECK-LABEL: define void @test24(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @use_pointer(i8* %p)
; CHECK-NEXT: call void @use_pointer(ptr %p)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test24(i8* %p) {
define void @test24(ptr %p) {
entry:
call i8* @llvm.objc.autoreleaseReturnValue(i8* %p) nounwind
call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p) nounwind
call void @use_pointer(i8* %p)
call ptr @llvm.objc.autoreleaseReturnValue(ptr %p) nounwind
call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p) nounwind
call void @use_pointer(ptr %p)
ret void
}

Expand All @@ -52,61 +52,57 @@ entry:

; 1) Noop instructions: bitcasts and zero-indices GEPs.

; CHECK-LABEL: define i8* @testNoop(
; CHECK-LABEL: define ptr @testNoop(
; CHECK: entry:
; CHECK-NEXT: %noop0 = bitcast i8* %call.i to i64*
; CHECK-NEXT: %noop1 = getelementptr i8, i8* %call.i, i32 0
; CHECK-NEXT: ret i8* %call.i
; CHECK-NEXT: ret ptr %call.i
; CHECK-NEXT: }
define i8* @testNoop(i8* %call.i) {
define ptr @testNoop(ptr %call.i) {
entry:
%0 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call.i) nounwind
%noop0 = bitcast i8* %call.i to i64*
%noop1 = getelementptr i8, i8* %call.i, i32 0
%1 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call.i) nounwind
ret i8* %call.i
%0 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %call.i) nounwind
%1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call.i) nounwind
ret ptr %call.i
}

; 2) Lifetime markers.

declare void @llvm.lifetime.start.p0i8(i64, i8*)
declare void @llvm.lifetime.end.p0i8(i64, i8*)
declare void @llvm.lifetime.start.p0(i64, ptr)
declare void @llvm.lifetime.end.p0(i64, ptr)

; CHECK-LABEL: define i8* @testLifetime(
; CHECK-LABEL: define ptr @testLifetime(
; CHECK: entry:
; CHECK-NEXT: %obj = alloca i8
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* %obj)
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* %obj)
; CHECK-NEXT: ret i8* %call.i
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr %obj)
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr %obj)
; CHECK-NEXT: ret ptr %call.i
; CHECK-NEXT: }
define i8* @testLifetime(i8* %call.i) {
define ptr @testLifetime(ptr %call.i) {
entry:
%obj = alloca i8
call void @llvm.lifetime.start.p0i8(i64 8, i8* %obj)
%0 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call.i) nounwind
call void @llvm.lifetime.end.p0i8(i64 8, i8* %obj)
%1 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call.i) nounwind
ret i8* %call.i
call void @llvm.lifetime.start.p0(i64 8, ptr %obj)
%0 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %call.i) nounwind
call void @llvm.lifetime.end.p0(i64 8, ptr %obj)
%1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call.i) nounwind
ret ptr %call.i
}

; 3) Dynamic alloca markers.

declare i8* @llvm.stacksave()
declare void @llvm.stackrestore(i8*)
declare ptr @llvm.stacksave()
declare void @llvm.stackrestore(ptr)

; CHECK-LABEL: define i8* @testStack(
; CHECK-LABEL: define ptr @testStack(
; CHECK: entry:
; CHECK-NEXT: %save = tail call i8* @llvm.stacksave()
; CHECK-NEXT: %save = tail call ptr @llvm.stacksave()
; CHECK-NEXT: %obj = alloca i8, i8 %arg
; CHECK-NEXT: call void @llvm.stackrestore(i8* %save)
; CHECK-NEXT: ret i8* %call.i
; CHECK-NEXT: call void @llvm.stackrestore(ptr %save)
; CHECK-NEXT: ret ptr %call.i
; CHECK-NEXT: }
define i8* @testStack(i8* %call.i, i8 %arg) {
define ptr @testStack(ptr %call.i, i8 %arg) {
entry:
%save = tail call i8* @llvm.stacksave()
%save = tail call ptr @llvm.stacksave()
%obj = alloca i8, i8 %arg
%0 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call.i) nounwind
call void @llvm.stackrestore(i8* %save)
%1 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call.i) nounwind
ret i8* %call.i
%0 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %call.i) nounwind
call void @llvm.stackrestore(ptr %save)
%1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call.i) nounwind
ret ptr %call.i
}
15 changes: 7 additions & 8 deletions llvm/test/Transforms/ObjCARC/pr12270.ll
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@
; test that we don't crash on unreachable code
%2 = type opaque

define void @_i_Test__foo(%2 *%x) {
define void @_i_Test__foo(ptr %x) {
entry:
unreachable

return: ; No predecessors!
%bar = bitcast %2* %x to i8*
%foo = call i8* @llvm.objc.autoreleaseReturnValue(i8* %bar) nounwind
%foo = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
call void @callee()
call void @use_pointer(i8* %foo)
call void @llvm.objc.release(i8* %foo) nounwind
call void @use_pointer(ptr %foo)
call void @llvm.objc.release(ptr %foo) nounwind
ret void
}

declare i8* @llvm.objc.autoreleaseReturnValue(i8*)
declare void @llvm.objc.release(i8*)
declare ptr @llvm.objc.autoreleaseReturnValue(ptr)
declare void @llvm.objc.release(ptr)
declare void @callee()
declare void @use_pointer(i8*)
declare void @use_pointer(ptr)
20 changes: 10 additions & 10 deletions llvm/test/Transforms/ObjCARC/provenance.ll
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,29 @@

declare void @g(i8)

define void @f(i8* %a, i8** %b, i8** %c) {
%y1 = load i8, i8* %a
define void @f(ptr %a, ptr %b, ptr %c) {
%y1 = load i8, ptr %a
call void @g(i8 %y1)

%y2 = load i8*, i8** %b
%y3 = load i8*, i8** %c
%y2 = load ptr, ptr %b
%y3 = load ptr, ptr %c

%x0 = load i8, i8* @"\01l_objc_msgSend_fixup_"
%x0 = load i8, ptr @"\01l_objc_msgSend_fixup_"
call void @g(i8 %x0)

%x1 = load i8, i8* @g1
%x1 = load i8, ptr @g1
call void @g(i8 %x1)

%x2 = load i8, i8* @g2
%x2 = load i8, ptr @g2
call void @g(i8 %x2)

%x3 = load i8, i8* @g3
%x3 = load i8, ptr @g3
call void @g(i8 %x3)

%x4 = load i8, i8* @g4
%x4 = load i8, ptr @g4
call void @g(i8 %x4)

%x5 = load i8, i8* @g5
%x5 = load i8, ptr @g5
call void @g(i8 %x5)
ret void
}
Expand Down
149 changes: 72 additions & 77 deletions llvm/test/Transforms/ObjCARC/related-check.ll
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,43 @@
; RUN: diff -u %t/out1.ll %t/out2.ll

%0 = type opaque
%struct._class_t = type { %struct._class_t*, %struct._class_t*, %struct._objc_cache*, i8* (i8*, i8*)**, %struct._class_ro_t* }
%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
%struct._objc_cache = type opaque
%struct._class_ro_t = type { i32, i32, i32, i8*, i8*, %struct.__method_list_t*, %struct._objc_protocol_list*, %struct._ivar_list_t*, i8*, %struct._prop_list_t* }
%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
%struct.__method_list_t = type { i32, i32, [0 x %struct._objc_method] }
%struct._objc_method = type { i8*, i8*, i8* }
%struct._objc_protocol_list = type { i64, [0 x %struct._protocol_t*] }
%struct._protocol_t = type { i8*, i8*, %struct._objc_protocol_list*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._prop_list_t*, i32, i32, i8**, i8*, %struct._prop_list_t* }
%struct._objc_method = type { ptr, ptr, ptr }
%struct._objc_protocol_list = type { i64, [0 x ptr] }
%struct._protocol_t = type { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, i32, i32, ptr, ptr, ptr }
%struct._ivar_list_t = type { i32, i32, [0 x %struct._ivar_t] }
%struct._ivar_t = type { i32*, i8*, i8*, i32, i32 }
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
%struct._prop_list_t = type { i32, i32, [0 x %struct._prop_t] }
%struct._prop_t = type { i8*, i8* }
%struct.__NSConstantString_tag = type { i32*, i32, i8*, i64 }
%struct._prop_t = type { ptr, ptr }
%struct.__NSConstantString_tag = type { ptr, i32, ptr, i64 }

@.str = private unnamed_addr constant [8 x i8] c"%s: %s\0A\00", align 1
@OBJC_METH_VAR_NAME_ = private unnamed_addr constant [25 x i8] c"fileSystemRepresentation\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@OBJC_SELECTOR_REFERENCES_ = internal externally_initialized global i8* getelementptr inbounds ([25 x i8], [25 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", align 8
@OBJC_SELECTOR_REFERENCES_ = internal externally_initialized global ptr @OBJC_METH_VAR_NAME_, section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", align 8
@"OBJC_CLASS_$_NSString" = external global %struct._class_t
@"OBJC_CLASSLIST_REFERENCES_$_" = internal global %struct._class_t* @"OBJC_CLASS_$_NSString", section "__DATA,__objc_classrefs,regular,no_dead_strip", align 8
@"OBJC_CLASSLIST_REFERENCES_$_" = internal global ptr @"OBJC_CLASS_$_NSString", section "__DATA,__objc_classrefs,regular,no_dead_strip", align 8
@__CFConstantStringClassReference = external global [0 x i32]
@.str.1 = private unnamed_addr constant [3 x i8] c"%@\00", section "__TEXT,__cstring,cstring_literals", align 1
@_unnamed_cfstring_ = private global %struct.__NSConstantString_tag { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i32 0, i32 0), i64 2 }, section "__DATA,__cfstring", align 8 #0
@_unnamed_cfstring_ = private global %struct.__NSConstantString_tag { ptr @__CFConstantStringClassReference, i32 1992, ptr @.str.1, i64 2 }, section "__DATA,__cfstring", align 8 #0
@OBJC_METH_VAR_NAME_.2 = private unnamed_addr constant [18 x i8] c"stringWithFormat:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@OBJC_SELECTOR_REFERENCES_.3 = internal externally_initialized global i8* getelementptr inbounds ([18 x i8], [18 x i8]* @OBJC_METH_VAR_NAME_.2, i32 0, i32 0), section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", align 8
@global1 = external local_unnamed_addr constant i8*, align 8
@llvm.compiler.used = appending global [5 x i8*] [i8* getelementptr inbounds ([25 x i8], [25 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* bitcast (i8** @OBJC_SELECTOR_REFERENCES_ to i8*), i8* bitcast (%struct._class_t** @"OBJC_CLASSLIST_REFERENCES_$_" to i8*), i8* getelementptr inbounds ([18 x i8], [18 x i8]* @OBJC_METH_VAR_NAME_.2, i32 0, i32 0), i8* bitcast (i8** @OBJC_SELECTOR_REFERENCES_.3 to i8*)], section "llvm.metadata"
@OBJC_SELECTOR_REFERENCES_.3 = internal externally_initialized global ptr @OBJC_METH_VAR_NAME_.2, section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", align 8
@global1 = external local_unnamed_addr constant ptr, align 8
@llvm.compiler.used = appending global [5 x ptr] [ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_SELECTOR_REFERENCES_, ptr @"OBJC_CLASSLIST_REFERENCES_$_", ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_SELECTOR_REFERENCES_.3], section "llvm.metadata"

; Function Attrs: optsize ssp uwtable(sync)
define i32 @main(i32 noundef %argc, i8** nocapture noundef readnone %argv) local_unnamed_addr #1 {
define i32 @main(i32 noundef %argc, ptr nocapture noundef readnone %argv) local_unnamed_addr #1 {
entry:
%persistent = alloca i32, align 4
%personalized = alloca i32, align 4
%cmp31 = icmp sgt i32 %argc, 1
br i1 %cmp31, label %for.body.lr.ph, label %for.cond.cleanup

for.body.lr.ph: ; preds = %entry
%0 = bitcast i32* %persistent to i8*
%1 = bitcast i32* %personalized to i8*
%2 = load i8*, i8** @OBJC_SELECTOR_REFERENCES_, align 8
%3 = load i8*, i8** @OBJC_SELECTOR_REFERENCES_.3, align 8
%0 = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8
%1 = load ptr, ptr @OBJC_SELECTOR_REFERENCES_.3, align 8
br label %for.body

for.cond.cleanup.loopexit: ; preds = %if.end19
Expand All @@ -54,116 +52,113 @@ for.cond.cleanup: ; preds = %for.cond.cleanup.lo

for.body: ; preds = %for.body.lr.ph, %if.end19
%i.032 = phi i32 [ 1, %for.body.lr.ph ], [ %inc, %if.end19 ]
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) #4
store i32 0, i32* %persistent, align 4
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %1) #4
store i32 0, i32* %personalized, align 4
%call = call zeroext i1 @lookupType(i32* noundef nonnull %persistent, i32* noundef nonnull %personalized) #8, !clang.arc.no_objc_arc_exceptions !15
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %persistent) #4
store i32 0, ptr %persistent, align 4
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %personalized) #4
store i32 0, ptr %personalized, align 4
%call = call zeroext i1 @lookupType(ptr noundef nonnull %persistent, ptr noundef nonnull %personalized) #8, !clang.arc.no_objc_arc_exceptions !15
br i1 %call, label %if.then, label %if.end19

if.then: ; preds = %for.body
%4 = load i32, i32* %persistent, align 4
%cmp1.not = icmp eq i32 %4, 0
%2 = load i32, ptr %persistent, align 4
%cmp1.not = icmp eq i32 %2, 0
br i1 %cmp1.not, label %if.end, label %if.then2

if.then2: ; preds = %if.then
%call34 = call %0* bitcast (%0* (...)* @getnsstr to %0* ()*)() #8 [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ], !clang.arc.no_objc_arc_exceptions !15
call void (...) @llvm.objc.clang.arc.noop.use(%0* %call34) #4
call void @llvm.objc.release(i8* null) #4, !clang.imprecise_release !15
%call56 = call %0* bitcast (%0* (...)* @getnsstr to %0* ()*)() #8 [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ], !clang.arc.no_objc_arc_exceptions !15
call void (...) @llvm.objc.clang.arc.noop.use(%0* %call56) #4
call void @llvm.objc.release(i8* null) #4, !clang.imprecise_release !15
%call34 = call ptr @getnsstr() #8 [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ], !clang.arc.no_objc_arc_exceptions !15
call void (...) @llvm.objc.clang.arc.noop.use(ptr %call34) #4
call void @llvm.objc.release(ptr null) #4, !clang.imprecise_release !15
%call56 = call ptr @getnsstr() #8 [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ], !clang.arc.no_objc_arc_exceptions !15
call void (...) @llvm.objc.clang.arc.noop.use(ptr %call56) #4
call void @llvm.objc.release(ptr null) #4, !clang.imprecise_release !15
br label %if.end

if.end: ; preds = %if.then2, %if.then
%path.0 = phi %0* [ %call34, %if.then2 ], [ null, %if.then ]
%name.0 = phi %0* [ %call56, %if.then2 ], [ null, %if.then ]
%5 = load i32, i32* %personalized, align 4
%cmp7.not = icmp eq i32 %5, 0
%path.0 = phi ptr [ %call34, %if.then2 ], [ null, %if.then ]
%name.0 = phi ptr [ %call56, %if.then2 ], [ null, %if.then ]
%3 = load i32, ptr %personalized, align 4
%cmp7.not = icmp eq i32 %3, 0
br i1 %cmp7.not, label %if.end11, label %if.then8

if.then8: ; preds = %if.end
%call910 = call %0* bitcast (%0* (...)* @getnsstr to %0* ()*)() #8 [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ], !clang.arc.no_objc_arc_exceptions !15
call void (...) @llvm.objc.clang.arc.noop.use(%0* %call910) #4
%6 = bitcast %0* %path.0 to i8*
call void @llvm.objc.release(i8* %6) #4, !clang.imprecise_release !15
%call910 = call ptr @getnsstr() #8 [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ], !clang.arc.no_objc_arc_exceptions !15
call void (...) @llvm.objc.clang.arc.noop.use(ptr %call910) #4
call void @llvm.objc.release(ptr %path.0) #4, !clang.imprecise_release !15
br label %if.end11

if.end11: ; preds = %if.then8, %if.end
%path.1 = phi %0* [ %call910, %if.then8 ], [ %path.0, %if.end ]
%cmp12.not = icmp eq %0* %path.1, null
%path.1 = phi ptr [ %call910, %if.then8 ], [ %path.0, %if.end ]
%cmp12.not = icmp eq ptr %path.1, null
br i1 %cmp12.not, label %if.else, label %if.then13

if.then13: ; preds = %if.end11
%7 = bitcast %0* %path.1 to i8*
%call14 = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* noundef nonnull %7, i8* noundef %2) #8, !clang.arc.no_objc_arc_exceptions !15
%call15 = call i32 (i8*, ...) @printf(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0), i8* noundef %call14) #8, !clang.arc.no_objc_arc_exceptions !15
%call14 = call ptr @objc_msgSend(ptr noundef nonnull %path.1, ptr noundef %0) #8, !clang.arc.no_objc_arc_exceptions !15
%call15 = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @.str, ptr noundef %call14) #8, !clang.arc.no_objc_arc_exceptions !15
br label %if.end18

if.else: ; preds = %if.end11
%8 = load i8*, i8** bitcast (%struct._class_t** @"OBJC_CLASSLIST_REFERENCES_$_" to i8**), align 8
%call1617 = call i8* (i8*, i8*, %0*, ...) bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, %0*, ...)*)(i8* noundef %8, i8* noundef %3, %0* noundef nonnull bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to %0*), %0* noundef null) #8 [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ], !clang.arc.no_objc_arc_exceptions !15
call void (...) @llvm.objc.clang.arc.noop.use(i8* %call1617) #4
call void @llvm.objc.release(i8* %call1617) #4, !clang.imprecise_release !15
%4 = load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_", align 8
%call1617 = call ptr (ptr, ptr, ptr, ...) @objc_msgSend(ptr noundef %4, ptr noundef %1, ptr noundef nonnull @_unnamed_cfstring_, ptr noundef null) #8 [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ], !clang.arc.no_objc_arc_exceptions !15
call void (...) @llvm.objc.clang.arc.noop.use(ptr %call1617) #4
call void @llvm.objc.release(ptr %call1617) #4, !clang.imprecise_release !15
br label %if.end18

if.end18: ; preds = %if.else, %if.then13
%.pre-phi = phi i8* [ null, %if.else ], [ %7, %if.then13 ]
%9 = bitcast %0* %name.0 to i8*
call void @llvm.objc.release(i8* %9) #4, !clang.imprecise_release !15
call void @llvm.objc.release(i8* %.pre-phi) #4, !clang.imprecise_release !15
%.pre-phi = phi ptr [ null, %if.else ], [ %path.1, %if.then13 ]
call void @llvm.objc.release(ptr %name.0) #4, !clang.imprecise_release !15
call void @llvm.objc.release(ptr %.pre-phi) #4, !clang.imprecise_release !15
br label %if.end19

if.end19: ; preds = %if.end18, %for.body
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %1) #4
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0) #4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %personalized) #4
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %persistent) #4
%inc = add nuw nsw i32 %i.032, 1
%exitcond.not = icmp eq i32 %inc, %argc
br i1 %exitcond.not, label %for.cond.cleanup.loopexit, label %for.body
}

; CHECK-LABEL: define i8* @foo() {
; CHECK-LABEL: define ptr @foo() {
; CHECK-NOT: @llvm.objc
; CHECK: ret i8* %

define i8* @foo() {
%t = alloca i8*, align 8
%v4 = load i8*, i8** @global1, align 8
%v5 = tail call i8* @llvm.objc.retain(i8* %v4)
store i8* %v4, i8** %t, align 8
%v13 = load i8*, i8** bitcast (%struct._class_t** @"OBJC_CLASSLIST_REFERENCES_$_" to i8**), align 8
%call78 = call i8* @bar(i8* %v13)
call void @llvm.objc.release(i8* %v4)
ret i8* %call78
; CHECK: ret ptr %

define ptr @foo() {
%t = alloca ptr, align 8
%v4 = load ptr, ptr @global1, align 8
%v5 = tail call ptr @llvm.objc.retain(ptr %v4)
store ptr %v4, ptr %t, align 8
%v13 = load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_", align 8
%call78 = call ptr @bar(ptr %v13)
call void @llvm.objc.release(ptr %v4)
ret ptr %call78
}

declare i8* @bar(i8*)
declare ptr @bar(ptr)

declare i8* @llvm.objc.retain(i8*)
declare ptr @llvm.objc.retain(ptr)

; Function Attrs: argmemonly mustprogress nocallback nofree nosync nounwind willreturn
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #2
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #2

; Function Attrs: argmemonly mustprogress nocallback nofree nosync nounwind willreturn
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #2
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #2

; Function Attrs: inaccessiblememonly mustprogress nocallback nofree nosync nounwind willreturn
declare void @llvm.objc.clang.arc.noop.use(...) #5

declare zeroext i1 @lookupType(i32* noundef, i32* noundef) #2
declare zeroext i1 @lookupType(ptr noundef, ptr noundef) #2

declare %0* @getnsstr(...) #2
declare ptr @getnsstr(...) #2

; Function Attrs: nounwind
declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*) #3
declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr) #3

; Function Attrs: nounwind
declare void @llvm.objc.release(i8*) #3
declare void @llvm.objc.release(ptr) #3

declare i32 @printf(i8* noundef, ...) #2
declare i32 @printf(ptr noundef, ...) #2

; Function Attrs: nonlazybind
declare i8* @objc_msgSend(i8*, i8*, ...) #4
declare ptr @objc_msgSend(ptr, ptr, ...) #4

attributes #0 = { "objc_arc_inert" }

Expand Down
38 changes: 17 additions & 21 deletions llvm/test/Transforms/ObjCARC/retain-block-side-effects.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,35 @@
; objc_retainBlock stores into %repeater so the load from after the
; call isn't forwardable from the store before the call.

; CHECK: %tmp16 = call i8* @llvm.objc.retainBlock(i8* %tmp15) [[NUW:#[0-9]+]]
; CHECK: %tmp17 = bitcast i8* %tmp16 to void ()*
; CHECK: %tmp18 = load %struct.__block_byref_repeater*, %struct.__block_byref_repeater** %byref.forwarding, align 8
; CHECK: %repeater12 = getelementptr inbounds %struct.__block_byref_repeater, %struct.__block_byref_repeater* %tmp18, i64 0, i32 6
; CHECK: store void ()* %tmp17, void ()** %repeater12, align 8
; CHECK: %tmp16 = call ptr @llvm.objc.retainBlock(ptr %block) [[NUW:#[0-9]+]]
; CHECK: %tmp18 = load ptr, ptr %byref.forwarding, align 8
; CHECK: %repeater12 = getelementptr inbounds %struct.__block_byref_repeater, ptr %tmp18, i64 0, i32 6
; CHECK: store ptr %tmp16, ptr %repeater12, align 8

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"

%0 = type opaque
%struct.__block_byref_repeater = type { i8*, %struct.__block_byref_repeater*, i32, i32, i8*, i8*, void ()* }
%struct.__block_byref_repeater = type { ptr, ptr, i32, i32, ptr, ptr, ptr }
%struct.__block_descriptor = type { i64, i64 }

define void @foo() noreturn {
entry:
%repeater = alloca %struct.__block_byref_repeater, align 8
%block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0*, i8* }>, align 8
%byref.forwarding = getelementptr inbounds %struct.__block_byref_repeater, %struct.__block_byref_repeater* %repeater, i64 0, i32 1
%tmp10 = getelementptr inbounds %struct.__block_byref_repeater, %struct.__block_byref_repeater* %repeater, i64 0, i32 6
store void ()* null, void ()** %tmp10, align 8
%block.captured11 = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0*, i8* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0*, i8* }>* %block, i64 0, i32 6
%tmp14 = bitcast %struct.__block_byref_repeater* %repeater to i8*
store i8* %tmp14, i8** %block.captured11, align 8
%tmp15 = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0*, i8* }>* %block to i8*
%tmp16 = call i8* @llvm.objc.retainBlock(i8* %tmp15) nounwind
%tmp17 = bitcast i8* %tmp16 to void ()*
%tmp18 = load %struct.__block_byref_repeater*, %struct.__block_byref_repeater** %byref.forwarding, align 8
%repeater12 = getelementptr inbounds %struct.__block_byref_repeater, %struct.__block_byref_repeater* %tmp18, i64 0, i32 6
%tmp13 = load void ()*, void ()** %repeater12, align 8
store void ()* %tmp17, void ()** %repeater12, align 8
%block = alloca <{ ptr, i32, i32, ptr, ptr, ptr, ptr }>, align 8
%byref.forwarding = getelementptr inbounds %struct.__block_byref_repeater, ptr %repeater, i64 0, i32 1
%tmp10 = getelementptr inbounds %struct.__block_byref_repeater, ptr %repeater, i64 0, i32 6
store ptr null, ptr %tmp10, align 8
%block.captured11 = getelementptr inbounds <{ ptr, i32, i32, ptr, ptr, ptr, ptr }>, ptr %block, i64 0, i32 6
store ptr %repeater, ptr %block.captured11, align 8
%tmp16 = call ptr @llvm.objc.retainBlock(ptr %block) nounwind
%tmp18 = load ptr, ptr %byref.forwarding, align 8
%repeater12 = getelementptr inbounds %struct.__block_byref_repeater, ptr %tmp18, i64 0, i32 6
%tmp13 = load ptr, ptr %repeater12, align 8
store ptr %tmp16, ptr %repeater12, align 8
ret void
}

declare i8* @llvm.objc.retainBlock(i8*)
declare ptr @llvm.objc.retainBlock(ptr)

; CHECK: attributes #0 = { noreturn }
; CHECK: attributes [[NUW]] = { nounwind }
46 changes: 23 additions & 23 deletions llvm/test/Transforms/ObjCARC/retain-not-declared.ll
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
; RUN: opt -S -passes=objc-arc,objc-arc-contract < %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"
declare i8* @llvm.objc.unretainedObject(i8*)
declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)
declare i8* @llvm.objc.autoreleaseReturnValue(i8*)
declare i8* @objc_msgSend(i8*, i8*, ...)
declare void @llvm.objc.release(i8*)
declare ptr @llvm.objc.unretainedObject(ptr)
declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)
declare ptr @llvm.objc.autoreleaseReturnValue(ptr)
declare ptr @objc_msgSend(ptr, ptr, ...)
declare void @llvm.objc.release(ptr)

; Test that the optimizer can create an objc_retainAutoreleaseReturnValue
; declaration even if no objc_retain declaration exists.
; rdar://9401303

; CHECK: define i8* @test0(i8* %p) {
; CHECK: define ptr @test0(ptr %p) {
; CHECK-NEXT: entry:
; CHECK-NEXT: %0 = tail call i8* @llvm.objc.retainAutoreleaseReturnValue(i8* %p) [[NUW:#[0-9]+]]
; CHECK-NEXT: ret i8* %0
; CHECK-NEXT: %0 = tail call ptr @llvm.objc.retainAutoreleaseReturnValue(ptr %p) [[NUW:#[0-9]+]]
; CHECK-NEXT: ret ptr %0
; CHECK-NEXT: }

define i8* @test0(i8* %p) {
define ptr @test0(ptr %p) {
entry:
%call = tail call i8* @llvm.objc.unretainedObject(i8* %p)
%0 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) nounwind
%1 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call) nounwind
ret i8* %call
%call = tail call ptr @llvm.objc.unretainedObject(ptr %p)
%0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
%1 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %call) nounwind
ret ptr %call
}

; Properly create the @llvm.objc.retain declaration when it doesn't already exist.
Expand All @@ -34,31 +34,31 @@ entry:
; CHECK: @llvm.objc.release
; CHECK: @llvm.objc.release
; CHECK: }
define void @test1(i8* %call88) nounwind personality i32 (...)* @__gxx_personality_v0 {
define void @test1(ptr %call88) nounwind personality ptr @__gxx_personality_v0 {
entry:
%tmp1 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call88) nounwind
%call94 = invoke i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*)*)(i8* %tmp1)
%tmp1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call88) nounwind
%call94 = invoke ptr @objc_msgSend(ptr %tmp1)
to label %invoke.cont93 unwind label %lpad91

invoke.cont93: ; preds = %entry
%tmp2 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call94) nounwind
call void @llvm.objc.release(i8* %tmp1) nounwind
invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*)*)(i8* %tmp2)
%tmp2 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call94) nounwind
call void @llvm.objc.release(ptr %tmp1) nounwind
invoke void @objc_msgSend(ptr %tmp2)
to label %invoke.cont102 unwind label %lpad100

invoke.cont102: ; preds = %invoke.cont93
call void @llvm.objc.release(i8* %tmp2) nounwind, !clang.imprecise_release !0
call void @llvm.objc.release(ptr %tmp2) nounwind, !clang.imprecise_release !0
unreachable

lpad91: ; preds = %entry
%exn91 = landingpad {i8*, i32}
%exn91 = landingpad {ptr, i32}
cleanup
unreachable

lpad100: ; preds = %invoke.cont93
%exn100 = landingpad {i8*, i32}
%exn100 = landingpad {ptr, i32}
cleanup
call void @llvm.objc.release(i8* %tmp2) nounwind, !clang.imprecise_release !0
call void @llvm.objc.release(ptr %tmp2) nounwind, !clang.imprecise_release !0
unreachable
}

Expand Down
146 changes: 73 additions & 73 deletions llvm/test/Transforms/ObjCARC/rle-s2l.ll
Original file line number Diff line number Diff line change
@@ -1,136 +1,136 @@
; RUN: opt -S -passes=objc-arc < %s | FileCheck %s

declare i8* @llvm.objc.loadWeak(i8**)
declare i8* @llvm.objc.loadWeakRetained(i8**)
declare i8* @llvm.objc.storeWeak(i8**, i8*)
declare i8* @llvm.objc.initWeak(i8**, i8*)
declare void @use_pointer(i8*)
declare ptr @llvm.objc.loadWeak(ptr)
declare ptr @llvm.objc.loadWeakRetained(ptr)
declare ptr @llvm.objc.storeWeak(ptr, ptr)
declare ptr @llvm.objc.initWeak(ptr, ptr)
declare void @use_pointer(ptr)
declare void @callee()

; Basic redundant @llvm.objc.loadWeak elimination.

; CHECK: define void @test0(i8** %p) {
; CHECK-NEXT: %y = call i8* @llvm.objc.loadWeak(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %y)
; CHECK: define void @test0(ptr %p) {
; CHECK-NEXT: %y = call ptr @llvm.objc.loadWeak(ptr %p)
; CHECK-NEXT: call void @use_pointer(ptr %y)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test0(i8** %p) {
%x = call i8* @llvm.objc.loadWeak(i8** %p)
%y = call i8* @llvm.objc.loadWeak(i8** %p)
call void @use_pointer(i8* %y)
define void @test0(ptr %p) {
%x = call ptr @llvm.objc.loadWeak(ptr %p)
%y = call ptr @llvm.objc.loadWeak(ptr %p)
call void @use_pointer(ptr %y)
ret void
}

; DCE the @llvm.objc.loadWeak.

; CHECK: define void @test1(i8** %p) {
; CHECK-NEXT: %y = call i8* @llvm.objc.loadWeakRetained(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %y)
; CHECK: define void @test1(ptr %p) {
; CHECK-NEXT: %y = call ptr @llvm.objc.loadWeakRetained(ptr %p)
; CHECK-NEXT: call void @use_pointer(ptr %y)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test1(i8** %p) {
%x = call i8* @llvm.objc.loadWeak(i8** %p)
%y = call i8* @llvm.objc.loadWeakRetained(i8** %p)
call void @use_pointer(i8* %y)
define void @test1(ptr %p) {
%x = call ptr @llvm.objc.loadWeak(ptr %p)
%y = call ptr @llvm.objc.loadWeakRetained(ptr %p)
call void @use_pointer(ptr %y)
ret void
}

; Basic redundant @llvm.objc.loadWeakRetained elimination.

; CHECK: define void @test2(i8** %p) {
; CHECK-NEXT: %x = call i8* @llvm.objc.loadWeak(i8** %p)
; CHECK-NEXT: store i8 3, i8* %x
; CHECK-NEXT: %1 = tail call i8* @llvm.objc.retain(i8* %x)
; CHECK-NEXT: call void @use_pointer(i8* %x)
; CHECK: define void @test2(ptr %p) {
; CHECK-NEXT: %x = call ptr @llvm.objc.loadWeak(ptr %p)
; CHECK-NEXT: store i8 3, ptr %x
; CHECK-NEXT: %1 = tail call ptr @llvm.objc.retain(ptr %x)
; CHECK-NEXT: call void @use_pointer(ptr %x)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test2(i8** %p) {
%x = call i8* @llvm.objc.loadWeak(i8** %p)
store i8 3, i8* %x
%y = call i8* @llvm.objc.loadWeakRetained(i8** %p)
call void @use_pointer(i8* %y)
define void @test2(ptr %p) {
%x = call ptr @llvm.objc.loadWeak(ptr %p)
store i8 3, ptr %x
%y = call ptr @llvm.objc.loadWeakRetained(ptr %p)
call void @use_pointer(ptr %y)
ret void
}

; Basic redundant @llvm.objc.loadWeakRetained elimination, this time
; with a readonly call instead of a store.

; CHECK: define void @test3(i8** %p) {
; CHECK-NEXT: %x = call i8* @llvm.objc.loadWeak(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %x) [[RO:#[0-9]+]]
; CHECK-NEXT: %1 = tail call i8* @llvm.objc.retain(i8* %x)
; CHECK-NEXT: call void @use_pointer(i8* %x)
; CHECK: define void @test3(ptr %p) {
; CHECK-NEXT: %x = call ptr @llvm.objc.loadWeak(ptr %p)
; CHECK-NEXT: call void @use_pointer(ptr %x) [[RO:#[0-9]+]]
; CHECK-NEXT: %1 = tail call ptr @llvm.objc.retain(ptr %x)
; CHECK-NEXT: call void @use_pointer(ptr %x)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test3(i8** %p) {
%x = call i8* @llvm.objc.loadWeak(i8** %p)
call void @use_pointer(i8* %x) readonly
%y = call i8* @llvm.objc.loadWeakRetained(i8** %p)
call void @use_pointer(i8* %y)
define void @test3(ptr %p) {
%x = call ptr @llvm.objc.loadWeak(ptr %p)
call void @use_pointer(ptr %x) readonly
%y = call ptr @llvm.objc.loadWeakRetained(ptr %p)
call void @use_pointer(ptr %y)
ret void
}

; A regular call blocks redundant weak load elimination.

; CHECK: define void @test4(i8** %p) {
; CHECK-NEXT: %x = call i8* @llvm.objc.loadWeak(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %x) [[RO]]
; CHECK: define void @test4(ptr %p) {
; CHECK-NEXT: %x = call ptr @llvm.objc.loadWeak(ptr %p)
; CHECK-NEXT: call void @use_pointer(ptr %x) [[RO]]
; CHECK-NEXT: call void @callee()
; CHECK-NEXT: %y = call i8* @llvm.objc.loadWeak(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %y)
; CHECK-NEXT: %y = call ptr @llvm.objc.loadWeak(ptr %p)
; CHECK-NEXT: call void @use_pointer(ptr %y)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test4(i8** %p) {
%x = call i8* @llvm.objc.loadWeak(i8** %p)
call void @use_pointer(i8* %x) readonly
define void @test4(ptr %p) {
%x = call ptr @llvm.objc.loadWeak(ptr %p)
call void @use_pointer(ptr %x) readonly
call void @callee()
%y = call i8* @llvm.objc.loadWeak(i8** %p)
call void @use_pointer(i8* %y)
%y = call ptr @llvm.objc.loadWeak(ptr %p)
call void @use_pointer(ptr %y)
ret void
}

; Store to load forwarding.

; CHECK: define void @test5(i8** %p, i8* %n) {
; CHECK-NEXT: %1 = call i8* @llvm.objc.storeWeak(i8** %p, i8* %n)
; CHECK-NEXT: call void @use_pointer(i8* %n)
; CHECK: define void @test5(ptr %p, ptr %n) {
; CHECK-NEXT: %1 = call ptr @llvm.objc.storeWeak(ptr %p, ptr %n)
; CHECK-NEXT: call void @use_pointer(ptr %n)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test5(i8** %p, i8* %n) {
call i8* @llvm.objc.storeWeak(i8** %p, i8* %n)
%y = call i8* @llvm.objc.loadWeak(i8** %p)
call void @use_pointer(i8* %y)
define void @test5(ptr %p, ptr %n) {
call ptr @llvm.objc.storeWeak(ptr %p, ptr %n)
%y = call ptr @llvm.objc.loadWeak(ptr %p)
call void @use_pointer(ptr %y)
ret void
}

; Store to load forwarding with objc_initWeak.

; CHECK: define void @test6(i8** %p, i8* %n) {
; CHECK-NEXT: %1 = call i8* @llvm.objc.initWeak(i8** %p, i8* %n)
; CHECK-NEXT: call void @use_pointer(i8* %n)
; CHECK: define void @test6(ptr %p, ptr %n) {
; CHECK-NEXT: %1 = call ptr @llvm.objc.initWeak(ptr %p, ptr %n)
; CHECK-NEXT: call void @use_pointer(ptr %n)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test6(i8** %p, i8* %n) {
call i8* @llvm.objc.initWeak(i8** %p, i8* %n)
%y = call i8* @llvm.objc.loadWeak(i8** %p)
call void @use_pointer(i8* %y)
define void @test6(ptr %p, ptr %n) {
call ptr @llvm.objc.initWeak(ptr %p, ptr %n)
%y = call ptr @llvm.objc.loadWeak(ptr %p)
call void @use_pointer(ptr %y)
ret void
}

; Don't forward if there's a may-alias store in the way.

; CHECK: define void @test7(i8** %p, i8* %n, i8** %q, i8* %m) {
; CHECK-NEXT: call i8* @llvm.objc.initWeak(i8** %p, i8* %n)
; CHECK-NEXT: call i8* @llvm.objc.storeWeak(i8** %q, i8* %m)
; CHECK-NEXT: %y = call i8* @llvm.objc.loadWeak(i8** %p)
; CHECK-NEXT: call void @use_pointer(i8* %y)
; CHECK: define void @test7(ptr %p, ptr %n, ptr %q, ptr %m) {
; CHECK-NEXT: call ptr @llvm.objc.initWeak(ptr %p, ptr %n)
; CHECK-NEXT: call ptr @llvm.objc.storeWeak(ptr %q, ptr %m)
; CHECK-NEXT: %y = call ptr @llvm.objc.loadWeak(ptr %p)
; CHECK-NEXT: call void @use_pointer(ptr %y)
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @test7(i8** %p, i8* %n, i8** %q, i8* %m) {
call i8* @llvm.objc.initWeak(i8** %p, i8* %n)
call i8* @llvm.objc.storeWeak(i8** %q, i8* %m)
%y = call i8* @llvm.objc.loadWeak(i8** %p)
call void @use_pointer(i8* %y)
define void @test7(ptr %p, ptr %n, ptr %q, ptr %m) {
call ptr @llvm.objc.initWeak(ptr %p, ptr %n)
call ptr @llvm.objc.storeWeak(ptr %q, ptr %m)
%y = call ptr @llvm.objc.loadWeak(ptr %p)
call void @use_pointer(ptr %y)
ret void
}

Expand Down
509 changes: 252 additions & 257 deletions llvm/test/Transforms/ObjCARC/rv.ll

Large diffs are not rendered by default.

46 changes: 23 additions & 23 deletions llvm/test/Transforms/ObjCARC/split-backedge.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,46 @@
; rdar://11256239

; CHECK-LABEL: define void @test0(
; CHECK: call i8* @llvm.objc.retain(i8* %call) [[NUW:#[0-9]+]]
; CHECK: call i8* @llvm.objc.retain(i8* %call) [[NUW]]
; CHECK: call i8* @llvm.objc.retain(i8* %cond) [[NUW]]
; CHECK: call void @llvm.objc.release(i8* %call) [[NUW]]
; CHECK: call void @llvm.objc.release(i8* %call) [[NUW]]
; CHECK: call void @llvm.objc.release(i8* %cond) [[NUW]]
define void @test0() personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
; CHECK: call ptr @llvm.objc.retain(ptr %call) [[NUW:#[0-9]+]]
; CHECK: call ptr @llvm.objc.retain(ptr %call) [[NUW]]
; CHECK: call ptr @llvm.objc.retain(ptr %cond) [[NUW]]
; CHECK: call void @llvm.objc.release(ptr %call) [[NUW]]
; CHECK: call void @llvm.objc.release(ptr %call) [[NUW]]
; CHECK: call void @llvm.objc.release(ptr %cond) [[NUW]]
define void @test0() personality ptr @__objc_personality_v0 {
entry:
br label %while.body

while.body: ; preds = %while.cond
%call = invoke i8* @returner()
%call = invoke ptr @returner()
to label %invoke.cont unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0

invoke.cont: ; preds = %while.body
%t0 = call i8* @llvm.objc.retain(i8* %call) nounwind
%t1 = call i8* @llvm.objc.retain(i8* %call) nounwind
%call.i1 = invoke i8* @returner()
%t0 = call ptr @llvm.objc.retain(ptr %call) nounwind
%t1 = call ptr @llvm.objc.retain(ptr %call) nounwind
%call.i1 = invoke ptr @returner()
to label %invoke.cont1 unwind label %lpad

invoke.cont1: ; preds = %invoke.cont
%cond = select i1 undef, i8* null, i8* %call
%t2 = call i8* @llvm.objc.retain(i8* %cond) nounwind
call void @llvm.objc.release(i8* %call) nounwind
call void @llvm.objc.release(i8* %call) nounwind
call void @use_pointer(i8* %cond)
call void @llvm.objc.release(i8* %cond) nounwind
%cond = select i1 undef, ptr null, ptr %call
%t2 = call ptr @llvm.objc.retain(ptr %cond) nounwind
call void @llvm.objc.release(ptr %call) nounwind
call void @llvm.objc.release(ptr %call) nounwind
call void @use_pointer(ptr %cond)
call void @llvm.objc.release(ptr %cond) nounwind
br label %while.body

lpad: ; preds = %invoke.cont, %while.body
%t4 = landingpad { i8*, i32 }
catch i8* null
%t4 = landingpad { ptr, i32 }
catch ptr null
ret void
}

declare i8* @returner()
declare ptr @returner()
declare i32 @__objc_personality_v0(...)
declare void @llvm.objc.release(i8*)
declare i8* @llvm.objc.retain(i8*)
declare void @use_pointer(i8*)
declare void @llvm.objc.release(ptr)
declare ptr @llvm.objc.retain(ptr)
declare void @use_pointer(ptr)

!0 = !{}

Expand Down
120 changes: 60 additions & 60 deletions llvm/test/Transforms/ObjCARC/tail-call-invariant-enforcement.ll
Original file line number Diff line number Diff line change
@@ -1,107 +1,107 @@
; RUN: opt -passes=objc-arc -S < %s | FileCheck %s

declare void @llvm.objc.release(i8* %x)
declare i8* @llvm.objc.retain(i8* %x)
declare i8* @llvm.objc.autorelease(i8* %x)
declare i8* @llvm.objc.autoreleaseReturnValue(i8* %x)
declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %x)
declare i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %x)
declare i8* @tmp(i8*)
declare void @llvm.objc.release(ptr %x)
declare ptr @llvm.objc.retain(ptr %x)
declare ptr @llvm.objc.autorelease(ptr %x)
declare ptr @llvm.objc.autoreleaseReturnValue(ptr %x)
declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %x)
declare ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %x)
declare ptr @tmp(ptr)

; Never tail call objc_autorelease.

; CHECK: define i8* @test0(i8* %x) [[NUW:#[0-9]+]] {
; CHECK: %tmp0 = call i8* @llvm.objc.autorelease(i8* %x) [[NUW]]
; CHECK: %tmp1 = call i8* @llvm.objc.autorelease(i8* %x) [[NUW]]
; CHECK: define ptr @test0(ptr %x) [[NUW:#[0-9]+]] {
; CHECK: %tmp0 = call ptr @llvm.objc.autorelease(ptr %x) [[NUW]]
; CHECK: %tmp1 = call ptr @llvm.objc.autorelease(ptr %x) [[NUW]]
; CHECK: }
define i8* @test0(i8* %x) nounwind {
define ptr @test0(ptr %x) nounwind {
entry:
%tmp0 = call i8* @llvm.objc.autorelease(i8* %x)
%tmp1 = tail call i8* @llvm.objc.autorelease(i8* %x)
%tmp0 = call ptr @llvm.objc.autorelease(ptr %x)
%tmp1 = tail call ptr @llvm.objc.autorelease(ptr %x)

ret i8* %x
ret ptr %x
}

; Always tail call autoreleaseReturnValue.

; CHECK: define i8* @test1(i8* %x) [[NUW]] {
; CHECK: %tmp0 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) [[NUW]]
; CHECK: %tmp1 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) [[NUW]]
; CHECK: define ptr @test1(ptr %x) [[NUW]] {
; CHECK: %tmp0 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) [[NUW]]
; CHECK: %tmp1 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) [[NUW]]
; CHECK: }
define i8* @test1(i8* %x) nounwind {
define ptr @test1(ptr %x) nounwind {
entry:
%tmp0 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x)
%tmp1 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %x)
ret i8* %x
%tmp0 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x)
%tmp1 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %x)
ret ptr %x
}

; Always tail call objc_retain.

; CHECK: define i8* @test2(i8* %x) [[NUW]] {
; CHECK: %tmp0 = tail call i8* @llvm.objc.retain(i8* %x) [[NUW]]
; CHECK: %tmp1 = tail call i8* @llvm.objc.retain(i8* %x) [[NUW]]
; CHECK: define ptr @test2(ptr %x) [[NUW]] {
; CHECK: %tmp0 = tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
; CHECK: %tmp1 = tail call ptr @llvm.objc.retain(ptr %x) [[NUW]]
; CHECK: }
define i8* @test2(i8* %x) nounwind {
define ptr @test2(ptr %x) nounwind {
entry:
%tmp0 = call i8* @llvm.objc.retain(i8* %x)
%tmp1 = tail call i8* @llvm.objc.retain(i8* %x)
ret i8* %x
%tmp0 = call ptr @llvm.objc.retain(ptr %x)
%tmp1 = tail call ptr @llvm.objc.retain(ptr %x)
ret ptr %x
}

; Always tail call objc_retainAutoreleasedReturnValue unless it's annotated with
; notail.
; CHECK: define i8* @test3(i8* %x) [[NUW]] {
; CHECK: %tmp0 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %y) [[NUW]]
; CHECK: %tmp1 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %z) [[NUW]]
; CHECK: %tmp2 = notail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %z2) [[NUW]]
; CHECK: define ptr @test3(ptr %x) [[NUW]] {
; CHECK: %tmp0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %y) [[NUW]]
; CHECK: %tmp1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z) [[NUW]]
; CHECK: %tmp2 = notail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z2) [[NUW]]
; CHECK: }
define i8* @test3(i8* %x) nounwind {
define ptr @test3(ptr %x) nounwind {
entry:
%y = call i8* @tmp(i8* %x)
%tmp0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %y)
%z = call i8* @tmp(i8* %x)
%tmp1 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %z)
%z2 = call i8* @tmp(i8* %x)
%tmp2 = notail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %z2)
ret i8* %x
%y = call ptr @tmp(ptr %x)
%tmp0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %y)
%z = call ptr @tmp(ptr %x)
%tmp1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z)
%z2 = call ptr @tmp(ptr %x)
%tmp2 = notail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %z2)
ret ptr %x
}

; By itself, we should never change whether or not objc_release is tail called.

; CHECK: define void @test4(i8* %x) [[NUW]] {
; CHECK: call void @llvm.objc.release(i8* %x) [[NUW]]
; CHECK: tail call void @llvm.objc.release(i8* %x) [[NUW]]
; CHECK: define void @test4(ptr %x) [[NUW]] {
; CHECK: call void @llvm.objc.release(ptr %x) [[NUW]]
; CHECK: tail call void @llvm.objc.release(ptr %x) [[NUW]]
; CHECK: }
define void @test4(i8* %x) nounwind {
define void @test4(ptr %x) nounwind {
entry:
call void @llvm.objc.release(i8* %x)
tail call void @llvm.objc.release(i8* %x)
call void @llvm.objc.release(ptr %x)
tail call void @llvm.objc.release(ptr %x)
ret void
}

; If we convert a tail called @llvm.objc.autoreleaseReturnValue to an
; @llvm.objc.autorelease, ensure that the tail call is removed.
; CHECK: define i8* @test5(i8* %x) [[NUW]] {
; CHECK: %tmp0 = call i8* @llvm.objc.autorelease(i8* %x) [[NUW]]
; CHECK: define ptr @test5(ptr %x) [[NUW]] {
; CHECK: %tmp0 = call ptr @llvm.objc.autorelease(ptr %x) [[NUW]]
; CHECK: }
define i8* @test5(i8* %x) nounwind {
define ptr @test5(ptr %x) nounwind {
entry:
%tmp0 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %x)
ret i8* %tmp0
%tmp0 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %x)
ret ptr %tmp0
}

; Always tail call llvm.objc.unsafeClaimAutoreleasedReturnValue.
; CHECK: define i8* @test6(i8* %x) [[NUW]] {
; CHECK: %tmp0 = tail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %y) [[NUW]]
; CHECK: %tmp1 = tail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %z) [[NUW]]
; CHECK: define ptr @test6(ptr %x) [[NUW]] {
; CHECK: %tmp0 = tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %y) [[NUW]]
; CHECK: %tmp1 = tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %z) [[NUW]]
; CHECK: }
define i8* @test6(i8* %x) nounwind {
define ptr @test6(ptr %x) nounwind {
entry:
%y = call i8* @tmp(i8* %x)
%tmp0 = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %y)
%z = call i8* @tmp(i8* %x)
%tmp1 = tail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %z)
ret i8* %x
%y = call ptr @tmp(ptr %x)
%tmp0 = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %y)
%z = call ptr @tmp(ptr %x)
%tmp1 = tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %z)
ret ptr %x
}

; CHECK: attributes [[NUW]] = { nounwind }
Expand Down
32 changes: 16 additions & 16 deletions llvm/test/Transforms/ObjCARC/unsafe-claim-rv.ll
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,44 @@

; Generated by compiling:
;
; id baz(void *X) { return (__bridge_transfer id)X; }
; id baz(ptr X) { return (__bridge_transfer id)X; }
;
; void foo(id X) {
; void *Y = 0;
; ptr Y = 0;
; if (X)
; Y = (__bridge_retained void *)X;
; Y = (__bridge_retained ptr)X;
; baz(Y);
; }
;
; clang -x objective-c -mllvm -enable-objc-arc-opts=0 -fobjc-arc -S -emit-llvm test.m
;
; And then hand-reduced further.

declare i8* @llvm.objc.autoreleaseReturnValue(i8*)
declare i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8*)
declare i8* @llvm.objc.retain(i8*)
declare void @llvm.objc.release(i8*)
declare ptr @llvm.objc.autoreleaseReturnValue(ptr)
declare ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr)
declare ptr @llvm.objc.retain(ptr)
declare void @llvm.objc.release(ptr)

define void @foo(i8* %X) {
define void @foo(ptr %X) {
entry:
%0 = tail call i8* @llvm.objc.retain(i8* %X)
%tobool = icmp eq i8* %0, null
%0 = tail call ptr @llvm.objc.retain(ptr %X)
%tobool = icmp eq ptr %0, null
br i1 %tobool, label %if.end, label %if.then

if.then: ; preds = %entry
%1 = tail call i8* @llvm.objc.retain(i8* nonnull %0)
%1 = tail call ptr @llvm.objc.retain(ptr nonnull %0)
br label %if.end

if.end: ; preds = %if.then, %entry
%Y.0 = phi i8* [ %1, %if.then ], [ null, %entry ]
%2 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %Y.0)
%3 = tail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %2)
tail call void @llvm.objc.release(i8* %0)
%Y.0 = phi ptr [ %1, %if.then ], [ null, %entry ]
%2 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %Y.0)
%3 = tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %2)
tail call void @llvm.objc.release(ptr %0)
ret void
}

; CHECK: if.then
; CHECK: tail call i8* @llvm.objc.retain
; CHECK: tail call ptr @llvm.objc.retain
; CHECK: %Y.0 = phi
; CHECK-NEXT: tail call void @llvm.objc.release
; CHECK-NEXT: tail call void @llvm.objc.release
Expand Down
14 changes: 7 additions & 7 deletions llvm/test/Transforms/ObjCARC/weak-contract.ll
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
; RUN: opt -passes=objc-arc-contract -S < %s | FileCheck %s

declare i8* @llvm.objc.initWeak(i8**, i8*)
declare ptr @llvm.objc.initWeak(ptr, ptr)

; Convert objc_initWeak(p, null) to *p = null.

; CHECK: define i8* @test0(i8** %p) {
; CHECK-NEXT: store i8* null, i8** %p
; CHECK-NEXT: ret i8* null
; CHECK: define ptr @test0(ptr %p) {
; CHECK-NEXT: store ptr null, ptr %p
; CHECK-NEXT: ret ptr null
; CHECK-NEXT: }
define i8* @test0(i8** %p) {
%t = call i8* @llvm.objc.initWeak(i8** %p, i8* null)
ret i8* %t
define ptr @test0(ptr %p) {
%t = call ptr @llvm.objc.initWeak(ptr %p, ptr null)
ret ptr %t
}
102 changes: 50 additions & 52 deletions llvm/test/Transforms/ObjCARC/weak-copies.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,86 +3,84 @@
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"
target triple = "x86_64-apple-darwin11.0.0"

%0 = type { i64, i64, i8*, i8*, i8*, i8* }
%1 = type <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>
%0 = type { i64, i64, ptr, ptr, ptr, ptr }
%1 = type <{ ptr, i32, i32, ptr, ptr, ptr }>
%struct.__block_descriptor = type { i64, i64 }

@_NSConcreteStackBlock = external global i8*
@_NSConcreteStackBlock = external global ptr
@.str = private unnamed_addr constant [6 x i8] c"v8@?0\00"
@"\01L_OBJC_CLASS_NAME_" = internal global [3 x i8] c"\01@\00", section "__TEXT,__objc_classname,cstring_literals", align 1
@__block_descriptor_tmp = internal constant %0 { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_ to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_ to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_OBJC_CLASS_NAME_", i32 0, i32 0) }
@__block_descriptor_tmp = internal constant %0 { i64 0, i64 40, ptr @__copy_helper_block_, ptr @__destroy_helper_block_, ptr @.str, ptr @"\01L_OBJC_CLASS_NAME_" }
@"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__DATA, __objc_imageinfo, regular, no_dead_strip"
@llvm.used = appending global [2 x i8*] [i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_OBJC_CLASS_NAME_", i32 0, i32 0), i8* bitcast ([2 x i32]* @"\01L_OBJC_IMAGE_INFO" to i8*)], section "llvm.metadata"
@llvm.used = appending global [2 x ptr] [ptr @"\01L_OBJC_CLASS_NAME_", ptr @"\01L_OBJC_IMAGE_INFO"], section "llvm.metadata"

; Eliminate unnecessary weak pointer copies.

; CHECK: define void @foo() {
; CHECK-NEXT: entry:
; CHECK-NEXT: %call = call i8* @bar()
; CHECK-NEXT: call void @use(i8* %call) [[NUW:#[0-9]+]]
; CHECK-NEXT: %call = call ptr @bar()
; CHECK-NEXT: call void @use(ptr %call) [[NUW:#[0-9]+]]
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @foo() {
entry:
%w = alloca i8*, align 8
%x = alloca i8*, align 8
%call = call i8* @bar()
%0 = call i8* @llvm.objc.initWeak(i8** %w, i8* %call) nounwind
%1 = call i8* @llvm.objc.loadWeak(i8** %w) nounwind
%2 = call i8* @llvm.objc.initWeak(i8** %x, i8* %1) nounwind
%3 = call i8* @llvm.objc.loadWeak(i8** %x) nounwind
call void @use(i8* %3) nounwind
call void @llvm.objc.destroyWeak(i8** %x) nounwind
call void @llvm.objc.destroyWeak(i8** %w) nounwind
%w = alloca ptr, align 8
%x = alloca ptr, align 8
%call = call ptr @bar()
%0 = call ptr @llvm.objc.initWeak(ptr %w, ptr %call) nounwind
%1 = call ptr @llvm.objc.loadWeak(ptr %w) nounwind
%2 = call ptr @llvm.objc.initWeak(ptr %x, ptr %1) nounwind
%3 = call ptr @llvm.objc.loadWeak(ptr %x) nounwind
call void @use(ptr %3) nounwind
call void @llvm.objc.destroyWeak(ptr %x) nounwind
call void @llvm.objc.destroyWeak(ptr %w) nounwind
ret void
}

; Eliminate unnecessary weak pointer copies in a block initialization.

; CHECK: define void @qux(i8* %me) #0 {
; CHECK: define void @qux(ptr %me) #0 {
; CHECK-NEXT: entry:
; CHECK-NEXT: %block = alloca %1, align 8
; CHECK-NOT: alloca
; CHECK: }
define void @qux(i8* %me) nounwind {
define void @qux(ptr %me) nounwind {
entry:
%w = alloca i8*, align 8
%w = alloca ptr, align 8
%block = alloca %1, align 8
%0 = call i8* @llvm.objc.retain(i8* %me) nounwind
%1 = call i8* @llvm.objc.initWeak(i8** %w, i8* %0) nounwind
%block.isa = getelementptr inbounds %1, %1* %block, i64 0, i32 0
store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %block.isa, align 8
%block.flags = getelementptr inbounds %1, %1* %block, i64 0, i32 1
store i32 1107296256, i32* %block.flags, align 8
%block.reserved = getelementptr inbounds %1, %1* %block, i64 0, i32 2
store i32 0, i32* %block.reserved, align 4
%block.invoke = getelementptr inbounds %1, %1* %block, i64 0, i32 3
store i8* bitcast (void (i8*)* @__qux_block_invoke_0 to i8*), i8** %block.invoke, align 8
%block.descriptor = getelementptr inbounds %1, %1* %block, i64 0, i32 4
store %struct.__block_descriptor* bitcast (%0* @__block_descriptor_tmp to %struct.__block_descriptor*), %struct.__block_descriptor** %block.descriptor, align 8
%block.captured = getelementptr inbounds %1, %1* %block, i64 0, i32 5
%2 = call i8* @llvm.objc.loadWeak(i8** %w) nounwind
%3 = call i8* @llvm.objc.initWeak(i8** %block.captured, i8* %2) nounwind
%4 = bitcast %1* %block to void ()*
call void @use_block(void ()* %4) nounwind
call void @llvm.objc.destroyWeak(i8** %block.captured) nounwind
call void @llvm.objc.destroyWeak(i8** %w) nounwind
call void @llvm.objc.release(i8* %0) nounwind, !clang.imprecise_release !0
%0 = call ptr @llvm.objc.retain(ptr %me) nounwind
%1 = call ptr @llvm.objc.initWeak(ptr %w, ptr %0) nounwind
store ptr @_NSConcreteStackBlock, ptr %block, align 8
%block.flags = getelementptr inbounds %1, ptr %block, i64 0, i32 1
store i32 1107296256, ptr %block.flags, align 8
%block.reserved = getelementptr inbounds %1, ptr %block, i64 0, i32 2
store i32 0, ptr %block.reserved, align 4
%block.invoke = getelementptr inbounds %1, ptr %block, i64 0, i32 3
store ptr @__qux_block_invoke_0, ptr %block.invoke, align 8
%block.descriptor = getelementptr inbounds %1, ptr %block, i64 0, i32 4
store ptr @__block_descriptor_tmp, ptr %block.descriptor, align 8
%block.captured = getelementptr inbounds %1, ptr %block, i64 0, i32 5
%2 = call ptr @llvm.objc.loadWeak(ptr %w) nounwind
%3 = call ptr @llvm.objc.initWeak(ptr %block.captured, ptr %2) nounwind
call void @use_block(ptr %block) nounwind
call void @llvm.objc.destroyWeak(ptr %block.captured) nounwind
call void @llvm.objc.destroyWeak(ptr %w) nounwind
call void @llvm.objc.release(ptr %0) nounwind, !clang.imprecise_release !0
ret void
}

declare i8* @llvm.objc.retain(i8*)
declare void @use_block(void ()*) nounwind
declare void @__qux_block_invoke_0(i8* %.block_descriptor) nounwind
declare void @__copy_helper_block_(i8*, i8*) nounwind
declare void @llvm.objc.copyWeak(i8**, i8**)
declare void @__destroy_helper_block_(i8*) nounwind
declare void @llvm.objc.release(i8*)
declare i8* @bar()
declare i8* @llvm.objc.initWeak(i8**, i8*)
declare i8* @llvm.objc.loadWeak(i8**)
declare void @use(i8*) nounwind
declare void @llvm.objc.destroyWeak(i8**)
declare ptr @llvm.objc.retain(ptr)
declare void @use_block(ptr) nounwind
declare void @__qux_block_invoke_0(ptr %.block_descriptor) nounwind
declare void @__copy_helper_block_(ptr, ptr) nounwind
declare void @llvm.objc.copyWeak(ptr, ptr)
declare void @__destroy_helper_block_(ptr) nounwind
declare void @llvm.objc.release(ptr)
declare ptr @bar()
declare ptr @llvm.objc.initWeak(ptr, ptr)
declare ptr @llvm.objc.loadWeak(ptr)
declare void @use(ptr) nounwind
declare void @llvm.objc.destroyWeak(ptr)

; CHECK: attributes [[NUW]] = { nounwind }

Expand Down
62 changes: 31 additions & 31 deletions llvm/test/Transforms/ObjCARC/weak-dce.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,44 @@

; Delete the weak calls and replace them with just the net retain.

; CHECK: define void @test0(i8* %p) {
; CHECK-NEXT: call i8* @llvm.objc.retain(i8* %p)
; CHECK: define void @test0(ptr %p) {
; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p)
; CHECK-NEXT: ret void

define void @test0(i8* %p) {
%weakBlock = alloca i8*, align 8
%tmp7 = call i8* @llvm.objc.initWeak(i8** %weakBlock, i8* %p) nounwind
%tmp26 = call i8* @llvm.objc.loadWeakRetained(i8** %weakBlock) nounwind
call void @llvm.objc.destroyWeak(i8** %weakBlock) nounwind
define void @test0(ptr %p) {
%weakBlock = alloca ptr, align 8
%tmp7 = call ptr @llvm.objc.initWeak(ptr %weakBlock, ptr %p) nounwind
%tmp26 = call ptr @llvm.objc.loadWeakRetained(ptr %weakBlock) nounwind
call void @llvm.objc.destroyWeak(ptr %weakBlock) nounwind
ret void
}

; CHECK: define i8* @test1(i8* %p) {
; CHECK-NEXT: call i8* @llvm.objc.retain(i8* %p)
; CHECK-NEXT: ret i8* %p
; CHECK: define ptr @test1(ptr %p) {
; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p)
; CHECK-NEXT: ret ptr %p

define i8* @test1(i8* %p) {
%weakBlock = alloca i8*, align 8
%tmp7 = call i8* @llvm.objc.initWeak(i8** %weakBlock, i8* %p) nounwind
%tmp26 = call i8* @llvm.objc.loadWeakRetained(i8** %weakBlock) nounwind
call void @llvm.objc.destroyWeak(i8** %weakBlock) nounwind
ret i8* %tmp26
define ptr @test1(ptr %p) {
%weakBlock = alloca ptr, align 8
%tmp7 = call ptr @llvm.objc.initWeak(ptr %weakBlock, ptr %p) nounwind
%tmp26 = call ptr @llvm.objc.loadWeakRetained(ptr %weakBlock) nounwind
call void @llvm.objc.destroyWeak(ptr %weakBlock) nounwind
ret ptr %tmp26
}

; CHECK: define i8* @test2(i8* %p, i8* %q) {
; CHECK-NEXT: call i8* @llvm.objc.retain(i8* %q)
; CHECK-NEXT: ret i8* %q

define i8* @test2(i8* %p, i8* %q) {
%weakBlock = alloca i8*, align 8
%tmp7 = call i8* @llvm.objc.initWeak(i8** %weakBlock, i8* %p) nounwind
%tmp19 = call i8* @llvm.objc.storeWeak(i8** %weakBlock, i8* %q) nounwind
%tmp26 = call i8* @llvm.objc.loadWeakRetained(i8** %weakBlock) nounwind
call void @llvm.objc.destroyWeak(i8** %weakBlock) nounwind
ret i8* %tmp26
; CHECK: define ptr @test2(ptr %p, ptr %q) {
; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %q)
; CHECK-NEXT: ret ptr %q

define ptr @test2(ptr %p, ptr %q) {
%weakBlock = alloca ptr, align 8
%tmp7 = call ptr @llvm.objc.initWeak(ptr %weakBlock, ptr %p) nounwind
%tmp19 = call ptr @llvm.objc.storeWeak(ptr %weakBlock, ptr %q) nounwind
%tmp26 = call ptr @llvm.objc.loadWeakRetained(ptr %weakBlock) nounwind
call void @llvm.objc.destroyWeak(ptr %weakBlock) nounwind
ret ptr %tmp26
}

declare i8* @llvm.objc.initWeak(i8**, i8*)
declare void @llvm.objc.destroyWeak(i8**)
declare i8* @llvm.objc.loadWeakRetained(i8**)
declare i8* @llvm.objc.storeWeak(i8** %weakBlock, i8* %q)
declare ptr @llvm.objc.initWeak(ptr, ptr)
declare void @llvm.objc.destroyWeak(ptr)
declare ptr @llvm.objc.loadWeakRetained(ptr)
declare ptr @llvm.objc.storeWeak(ptr %weakBlock, ptr %q)
Loading