; RUN: llc -mtriple=x86_64-apple-macosx -verify-machineinstrs -o - %s | FileCheck --check-prefix=CHECK %s ; TODO: support marker generation with GlobalISel target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" declare ptr @foo0(i32) declare ptr @foo1() declare void @llvm.objc.release(ptr) declare void @objc_object(ptr) declare void @foo2(ptr) declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) declare ptr @_ZN1SD1Ev(ptr nonnull dereferenceable(1)) declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) %struct.S = type { i8 } @g = global ptr null, align 8 @fptr = global ptr null, align 8 define ptr @rv_marker_1_retain() { ; CHECK-LABEL: rv_marker_1_retain: ; CHECK: pushq %rax ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: callq _foo1 ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue ; CHECK-NEXT: popq %rcx ; CHECK-NEXT: retq ; entry: %call = call ptr @foo1() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] ret ptr %call } define ptr @rv_marker_1_unsafeClaim() { ; CHECK-LABEL: rv_marker_1_unsafeClaim: ; CHECK: pushq %rax ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: callq _foo1 ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: callq _objc_unsafeClaimAutoreleasedReturnValue ; CHECK-NEXT: popq %rcx ; CHECK-NEXT: retq ; entry: %call = call ptr @foo1() [ "clang.arc.attachedcall"(ptr @objc_unsafeClaimAutoreleasedReturnValue) ] ret ptr %call } define void @rv_marker_2_select(i32 %c) { ; CHECK-LABEL: rv_marker_2_select: ; CHECK: pushq %rax ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: cmpl $1, %edi ; CHECK-NEXT: adcl $1, %eax ; CHECK-NEXT: movl %eax, %edi ; CHECK-NEXT: callq _foo0 ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: popq %rax ; CHECK-NEXT: jmp _foo2 ; entry: %tobool.not = icmp eq i32 %c, 0 %.sink = select i1 %tobool.not, i32 2, i32 1 %call1 = call ptr @foo0(i32 %.sink) [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] tail call void @foo2(ptr %call1) ret void } define void @rv_marker_3() personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: rv_marker_3 ; CHECK: pushq %r14 ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: pushq %rbx ; CHECK-NEXT: .cfi_def_cfa_offset 24 ; CHECK-NEXT: pushq %rax ; CHECK-NEXT: .cfi_def_cfa_offset 32 ; CHECK-NEXT: .cfi_offset %rbx, -24 ; CHECK-NEXT: .cfi_offset %r14, -16 ; CHECK-NEXT: callq _foo1 ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue ; CHECK-NEXT: movq %rax, %rbx ; CHECK-NEXT: Ltmp0: ; entry: %call = call ptr @foo1() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] invoke void @objc_object(ptr %call) #5 to label %invoke.cont unwind label %lpad invoke.cont: ; preds = %entry tail call void @llvm.objc.release(ptr %call) ret void lpad: ; preds = %entry %0 = landingpad { ptr, i32 } cleanup tail call void @llvm.objc.release(ptr %call) resume { ptr, i32 } %0 } define void @rv_marker_4() personality ptr @__gxx_personality_v0 { ; CHECK-LABEL: rv_marker_4 ; CHECK: pushq %r14 ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: pushq %rbx ; CHECK-NEXT: .cfi_def_cfa_offset 24 ; CHECK-NEXT: pushq %rax ; CHECK-NEXT: .cfi_def_cfa_offset 32 ; CHECK-NEXT: .cfi_offset %rbx, -24 ; CHECK-NEXT: .cfi_offset %r14, -16 ; CHECK-NEXT: Ltmp3: ; CHECK-NEXT: callq _foo1 ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue ; CHECK-NEXT: Ltmp4: ; entry: %s = alloca %struct.S, align 1 call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %s) #2 %call = invoke ptr @foo1() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] to label %invoke.cont unwind label %lpad invoke.cont: ; preds = %entry invoke void @objc_object(ptr %call) #5 to label %invoke.cont2 unwind label %lpad1 invoke.cont2: ; preds = %invoke.cont tail call void @llvm.objc.release(ptr %call) %call3 = call ptr @_ZN1SD1Ev(ptr nonnull dereferenceable(1) %s) call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %s) ret void lpad: ; preds = %entry %0 = landingpad { ptr, i32 } cleanup br label %ehcleanup lpad1: ; preds = %invoke.cont %1 = landingpad { ptr, i32 } cleanup tail call void @llvm.objc.release(ptr %call) br label %ehcleanup ehcleanup: ; preds = %lpad1, %lpad %.pn = phi { ptr, i32 } [ %1, %lpad1 ], [ %0, %lpad ] %call4 = call ptr @_ZN1SD1Ev(ptr nonnull dereferenceable(1) %s) call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %s) resume { ptr, i32 } %.pn } ; TODO: This should use "callq *_fptr(%rip)". define ptr @rv_marker_5_indirect_call() { ; CHECK-LABEL: rv_marker_5_indirect_call ; CHECK: pushq %rbx ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: .cfi_offset %rbx, -16 ; CHECK-NEXT: movq _fptr(%rip), %rax ; CHECK-NEXT: callq *%rax ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue ; CHECK-NEXT: movq %rax, %rbx ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: callq _foo2 ; CHECK-NEXT: movq %rbx, %rax ; CHECK-NEXT: popq %rbx ; CHECK-NEXT: retq ; entry: %lv = load ptr, ptr @fptr, align 8 %call = call ptr %lv() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] tail call void @foo2(ptr %call) ret ptr %call } declare ptr @foo(i64, i64, i64) define void @rv_marker_multiarg(i64 %a, i64 %b, i64 %c) { ; CHECK-LABEL: rv_marker_multiarg ; CHECK: pushq %rax ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: movq %rdi, %rax ; CHECK-NEXT: movq %rdx, %rdi ; CHECK-NEXT: movq %rax, %rdx ; CHECK-NEXT: callq _foo ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue ; CHECK-NEXT: popq %rax ; CHECK-NEXT: retq ; %r = call ptr @foo(i64 %c, i64 %b, i64 %a) [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] ret void } define void @test_nonlazybind() { ; CHECK-LABEL: _test_nonlazybind: ; CHECK: bb.0: ; CHECK-NEXT: pushq %rax ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: callq *_foo_nonlazybind@GOTPCREL(%rip) ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue ; %call1 = notail call ptr @foo_nonlazybind() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] ret void } declare ptr @foo_nonlazybind() nonlazybind declare ptr @objc_retainAutoreleasedReturnValue(ptr) declare ptr @objc_unsafeClaimAutoreleasedReturnValue(ptr) declare i32 @__gxx_personality_v0(...) declare ptr @fn1() declare ptr @fn2() define ptr @rv_marker_block_placement(i1 %c.0) { ; CHECK-LABEL: _rv_marker_block_placement: ; CHECK: pushq %rax ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: testb $1, %dil ; CHECK-NEXT: je LBB8_2 ; CHECK-NEXT: ## %bb.1: ; CHECK-NEXT: callq _fn1 ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue ; CHECK-NEXT: jmp LBB8_3 ; CHECK-NEXT: LBB8_2: ; CHECK-NEXT: callq _fn2 ; CHECK-NEXT: movq %rax, %rdi ; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue ; CHECK-NEXT: LBB8_3: ; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: popq %rcx ; CHECK-NEXT: retq ; entry: br i1 %c.0, label %then, label %else then: %call.0 = notail call ptr @fn1() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] br label %exit else: %call.1 = notail call ptr @fn2() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] br label %exit exit: ret ptr null }