; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -verify-machineinstrs < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-APPLE %s ; RUN: llc -verify-machineinstrs -O0 < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-O0 %s ; RUN: llc -verify-machineinstrs < %s -mtriple=armv7-linux-androideabi | FileCheck --check-prefix=CHECK-ANDROID %s declare i8* @malloc(i64) declare void @free(i8*) %swift_error = type { i64, i8 } %struct.S = type { i32, i32, i32, i32, i32, i32 } ; This tests the basic usage of a swifterror parameter. "foo" is the function ; that takes a swifterror parameter and "caller" is the caller of "foo". define float @foo(%swift_error** swifterror %error_ptr_ref) { ; CHECK-APPLE-LABEL: foo: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {lr} ; CHECK-APPLE-NEXT: mov r0, #16 ; CHECK-APPLE-NEXT: mov r1, #0 ; CHECK-APPLE-NEXT: bl _malloc ; CHECK-APPLE-NEXT: mov r8, r0 ; CHECK-APPLE-NEXT: mov r0, #1 ; CHECK-APPLE-NEXT: strb r0, [r8, #8] ; CHECK-APPLE-NEXT: mov r0, #1065353216 ; CHECK-APPLE-NEXT: pop {lr} ; CHECK-APPLE-NEXT: bx lr ; ; CHECK-O0-LABEL: foo: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: mov r0, #16 ; CHECK-O0-NEXT: mov r1, #0 ; CHECK-O0-NEXT: bl _malloc ; CHECK-O0-NEXT: mov r1, r0 ; CHECK-O0-NEXT: mov r8, r1 ; CHECK-O0-NEXT: mov r0, #1 ; CHECK-O0-NEXT: strb r0, [r1, #8] ; CHECK-O0-NEXT: mov r0, #1065353216 ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: foo: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r11, lr} ; CHECK-ANDROID-NEXT: push {r11, lr} ; CHECK-ANDROID-NEXT: mov r0, #16 ; CHECK-ANDROID-NEXT: mov r1, #0 ; CHECK-ANDROID-NEXT: bl malloc ; CHECK-ANDROID-NEXT: mov r8, r0 ; CHECK-ANDROID-NEXT: mov r0, #1 ; CHECK-ANDROID-NEXT: strb r0, [r8, #8] ; CHECK-ANDROID-NEXT: mov r0, #1065353216 ; CHECK-ANDROID-NEXT: pop {r11, pc} entry: %call = call i8* @malloc(i64 16) %call.0 = bitcast i8* %call to %swift_error* store %swift_error* %call.0, %swift_error** %error_ptr_ref %tmp = getelementptr inbounds i8, i8* %call, i64 8 store i8 1, i8* %tmp ret float 1.0 } ; "caller" calls "foo" that takes a swifterror parameter. define float @caller(i8* %error_ref) { ; CHECK-APPLE-LABEL: caller: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {r4, r8, lr} ; CHECK-APPLE-NEXT: sub sp, sp, #4 ; CHECK-APPLE-NEXT: mov r8, #0 ; CHECK-APPLE-NEXT: mov r4, r0 ; CHECK-APPLE-NEXT: bl _foo ; CHECK-APPLE-NEXT: mov r0, r8 ; CHECK-APPLE-NEXT: cmp r8, #0 ; CHECK-APPLE-NEXT: ldrbeq r1, [r0, #8] ; CHECK-APPLE-NEXT: strbeq r1, [r4] ; CHECK-APPLE-NEXT: bl _free ; CHECK-APPLE-NEXT: mov r0, #1065353216 ; CHECK-APPLE-NEXT: add sp, sp, #4 ; CHECK-APPLE-NEXT: pop {r4, r8, pc} ; ; CHECK-O0-LABEL: caller: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: push {r8} ; CHECK-O0-NEXT: sub sp, sp, #12 ; CHECK-O0-NEXT: @ implicit-def: $r1 ; CHECK-O0-NEXT: str r0, [sp] @ 4-byte Spill ; CHECK-O0-NEXT: mov r8, #0 ; CHECK-O0-NEXT: bl _foo ; CHECK-O0-NEXT: str r8, [sp, #4] @ 4-byte Spill ; CHECK-O0-NEXT: movw r0, #0 ; CHECK-O0-NEXT: cmp r8, r0 ; CHECK-O0-NEXT: bne LBB1_2 ; CHECK-O0-NEXT: @ %bb.1: @ %cont ; CHECK-O0-NEXT: ldr r1, [sp] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r0, [sp, #4] @ 4-byte Reload ; CHECK-O0-NEXT: ldrb r0, [r0, #8] ; CHECK-O0-NEXT: strb r0, [r1] ; CHECK-O0-NEXT: LBB1_2: @ %handler ; CHECK-O0-NEXT: ldr r0, [sp, #4] @ 4-byte Reload ; CHECK-O0-NEXT: bl _free ; CHECK-O0-NEXT: mov r0, #1065353216 ; CHECK-O0-NEXT: sub sp, r7, #4 ; CHECK-O0-NEXT: pop {r8} ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: caller: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r4, r8, r11, lr} ; CHECK-ANDROID-NEXT: push {r4, r8, r11, lr} ; CHECK-ANDROID-NEXT: .pad #8 ; CHECK-ANDROID-NEXT: sub sp, sp, #8 ; CHECK-ANDROID-NEXT: mov r8, #0 ; CHECK-ANDROID-NEXT: mov r4, r0 ; CHECK-ANDROID-NEXT: bl foo ; CHECK-ANDROID-NEXT: mov r0, r8 ; CHECK-ANDROID-NEXT: cmp r8, #0 ; CHECK-ANDROID-NEXT: ldrbeq r1, [r0, #8] ; CHECK-ANDROID-NEXT: strbeq r1, [r4] ; CHECK-ANDROID-NEXT: bl free ; CHECK-ANDROID-NEXT: mov r0, #1065353216 ; CHECK-ANDROID-NEXT: add sp, sp, #8 ; CHECK-ANDROID-NEXT: pop {r4, r8, r11, pc} ; Access part of the error object and save it to error_ref ; spill r0 ; reload r0 entry: %error_ptr_ref = alloca swifterror %swift_error* store %swift_error* null, %swift_error** %error_ptr_ref %call = call float @foo(%swift_error** swifterror %error_ptr_ref) %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null %tmp = bitcast %swift_error* %error_from_foo to i8* br i1 %had_error_from_foo, label %handler, label %cont cont: %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 %t = load i8, i8* %v1 store i8 %t, i8* %error_ref br label %handler handler: call void @free(i8* %tmp) ret float 1.0 } ; "caller2" is the caller of "foo", it calls "foo" inside a loop. define float @caller2(i8* %error_ref) { ; CHECK-APPLE-LABEL: caller2: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {r4, r8, lr} ; CHECK-APPLE-NEXT: vpush {d8} ; CHECK-APPLE-NEXT: sub sp, sp, #4 ; CHECK-APPLE-NEXT: vmov.f32 s16, #1.000000e+00 ; CHECK-APPLE-NEXT: mov r4, r0 ; CHECK-APPLE-NEXT: LBB2_1: @ %bb_loop ; CHECK-APPLE-NEXT: @ =>This Inner Loop Header: Depth=1 ; CHECK-APPLE-NEXT: mov r8, #0 ; CHECK-APPLE-NEXT: bl _foo ; CHECK-APPLE-NEXT: cmp r8, #0 ; CHECK-APPLE-NEXT: bne LBB2_4 ; CHECK-APPLE-NEXT: @ %bb.2: @ %cont ; CHECK-APPLE-NEXT: @ in Loop: Header=BB2_1 Depth=1 ; CHECK-APPLE-NEXT: vmov s0, r0 ; CHECK-APPLE-NEXT: vcmp.f32 s0, s16 ; CHECK-APPLE-NEXT: vmrs APSR_nzcv, fpscr ; CHECK-APPLE-NEXT: ble LBB2_1 ; CHECK-APPLE-NEXT: @ %bb.3: @ %bb_end ; CHECK-APPLE-NEXT: ldrb r0, [r8, #8] ; CHECK-APPLE-NEXT: strb r0, [r4] ; CHECK-APPLE-NEXT: LBB2_4: @ %handler ; CHECK-APPLE-NEXT: mov r0, r8 ; CHECK-APPLE-NEXT: bl _free ; CHECK-APPLE-NEXT: mov r0, #1065353216 ; CHECK-APPLE-NEXT: add sp, sp, #4 ; CHECK-APPLE-NEXT: vpop {d8} ; CHECK-APPLE-NEXT: pop {r4, r8, pc} ; ; CHECK-O0-LABEL: caller2: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: push {r8} ; CHECK-O0-NEXT: sub sp, sp, #16 ; CHECK-O0-NEXT: @ implicit-def: $r1 ; CHECK-O0-NEXT: str r0, [sp, #8] @ 4-byte Spill ; CHECK-O0-NEXT: LBB2_1: @ %bb_loop ; CHECK-O0-NEXT: @ =>This Inner Loop Header: Depth=1 ; CHECK-O0-NEXT: mov r8, #0 ; CHECK-O0-NEXT: bl _foo ; CHECK-O0-NEXT: vmov s0, r0 ; CHECK-O0-NEXT: vstr s0, [sp] @ 4-byte Spill ; CHECK-O0-NEXT: str r8, [sp, #4] @ 4-byte Spill ; CHECK-O0-NEXT: movw r0, #0 ; CHECK-O0-NEXT: cmp r8, r0 ; CHECK-O0-NEXT: bne LBB2_4 ; CHECK-O0-NEXT: @ %bb.2: @ %cont ; CHECK-O0-NEXT: @ in Loop: Header=BB2_1 Depth=1 ; CHECK-O0-NEXT: vldr s0, [sp] @ 4-byte Reload ; CHECK-O0-NEXT: vmov.f32 s2, #1.000000e+00 ; CHECK-O0-NEXT: vcmp.f32 s0, s2 ; CHECK-O0-NEXT: vmrs APSR_nzcv, fpscr ; CHECK-O0-NEXT: ble LBB2_1 ; CHECK-O0-NEXT: @ %bb.3: @ %bb_end ; CHECK-O0-NEXT: ldr r1, [sp, #8] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r0, [sp, #4] @ 4-byte Reload ; CHECK-O0-NEXT: ldrb r0, [r0, #8] ; CHECK-O0-NEXT: strb r0, [r1] ; CHECK-O0-NEXT: LBB2_4: @ %handler ; CHECK-O0-NEXT: ldr r0, [sp, #4] @ 4-byte Reload ; CHECK-O0-NEXT: bl _free ; CHECK-O0-NEXT: mov r0, #1065353216 ; CHECK-O0-NEXT: sub sp, r7, #4 ; CHECK-O0-NEXT: pop {r8} ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: caller2: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r4, r8, r11, lr} ; CHECK-ANDROID-NEXT: push {r4, r8, r11, lr} ; CHECK-ANDROID-NEXT: .vsave {d8} ; CHECK-ANDROID-NEXT: vpush {d8} ; CHECK-ANDROID-NEXT: .pad #8 ; CHECK-ANDROID-NEXT: sub sp, sp, #8 ; CHECK-ANDROID-NEXT: vmov.f32 s16, #1.000000e+00 ; CHECK-ANDROID-NEXT: mov r4, r0 ; CHECK-ANDROID-NEXT: .LBB2_1: @ %bb_loop ; CHECK-ANDROID-NEXT: @ =>This Inner Loop Header: Depth=1 ; CHECK-ANDROID-NEXT: mov r8, #0 ; CHECK-ANDROID-NEXT: bl foo ; CHECK-ANDROID-NEXT: cmp r8, #0 ; CHECK-ANDROID-NEXT: bne .LBB2_4 ; CHECK-ANDROID-NEXT: @ %bb.2: @ %cont ; CHECK-ANDROID-NEXT: @ in Loop: Header=BB2_1 Depth=1 ; CHECK-ANDROID-NEXT: vmov s0, r0 ; CHECK-ANDROID-NEXT: vcmp.f32 s0, s16 ; CHECK-ANDROID-NEXT: vmrs APSR_nzcv, fpscr ; CHECK-ANDROID-NEXT: ble .LBB2_1 ; CHECK-ANDROID-NEXT: @ %bb.3: @ %bb_end ; CHECK-ANDROID-NEXT: ldrb r0, [r8, #8] ; CHECK-ANDROID-NEXT: strb r0, [r4] ; CHECK-ANDROID-NEXT: .LBB2_4: @ %handler ; CHECK-ANDROID-NEXT: mov r0, r8 ; CHECK-ANDROID-NEXT: bl free ; CHECK-ANDROID-NEXT: mov r0, #1065353216 ; CHECK-ANDROID-NEXT: add sp, sp, #8 ; CHECK-ANDROID-NEXT: vpop {d8} ; CHECK-ANDROID-NEXT: pop {r4, r8, r11, pc} ; Access part of the error object and save it to error_ref ; spill r0 ; reload r0 entry: %error_ptr_ref = alloca swifterror %swift_error* br label %bb_loop bb_loop: store %swift_error* null, %swift_error** %error_ptr_ref %call = call float @foo(%swift_error** swifterror %error_ptr_ref) %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null %tmp = bitcast %swift_error* %error_from_foo to i8* br i1 %had_error_from_foo, label %handler, label %cont cont: %cmp = fcmp ogt float %call, 1.000000e+00 br i1 %cmp, label %bb_end, label %bb_loop bb_end: %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 %t = load i8, i8* %v1 store i8 %t, i8* %error_ref br label %handler handler: call void @free(i8* %tmp) ret float 1.0 } ; "foo_if" is a function that takes a swifterror parameter, it sets swifterror ; under a certain condition. define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) { ; CHECK-APPLE-LABEL: foo_if: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {lr} ; CHECK-APPLE-NEXT: cmp r0, #0 ; CHECK-APPLE-NEXT: beq LBB3_2 ; CHECK-APPLE-NEXT: @ %bb.1: @ %gen_error ; CHECK-APPLE-NEXT: mov r0, #16 ; CHECK-APPLE-NEXT: mov r1, #0 ; CHECK-APPLE-NEXT: bl _malloc ; CHECK-APPLE-NEXT: mov r8, r0 ; CHECK-APPLE-NEXT: mov r0, #1 ; CHECK-APPLE-NEXT: vmov.f32 s0, #1.000000e+00 ; CHECK-APPLE-NEXT: strb r0, [r8, #8] ; CHECK-APPLE-NEXT: b LBB3_3 ; CHECK-APPLE-NEXT: LBB3_2: ; CHECK-APPLE-NEXT: vldr s0, LCPI3_0 ; CHECK-APPLE-NEXT: LBB3_3: @ %common.ret ; CHECK-APPLE-NEXT: vmov r0, s0 ; CHECK-APPLE-NEXT: pop {lr} ; CHECK-APPLE-NEXT: bx lr ; CHECK-APPLE-NEXT: .p2align 2 ; CHECK-APPLE-NEXT: @ %bb.4: ; CHECK-APPLE-NEXT: .data_region ; CHECK-APPLE-NEXT: LCPI3_0: ; CHECK-APPLE-NEXT: .long 0x00000000 @ float 0 ; CHECK-APPLE-NEXT: .end_data_region ; ; CHECK-O0-LABEL: foo_if: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: sub sp, sp, #4 ; CHECK-O0-NEXT: str r8, [sp] @ 4-byte Spill ; CHECK-O0-NEXT: cmp r0, #0 ; CHECK-O0-NEXT: beq LBB3_2 ; CHECK-O0-NEXT: @ %bb.1: @ %gen_error ; CHECK-O0-NEXT: mov r0, #16 ; CHECK-O0-NEXT: mov r1, #0 ; CHECK-O0-NEXT: bl _malloc ; CHECK-O0-NEXT: mov r1, r0 ; CHECK-O0-NEXT: mov r8, r1 ; CHECK-O0-NEXT: mov r0, #1 ; CHECK-O0-NEXT: strb r0, [r1, #8] ; CHECK-O0-NEXT: mov r0, #1065353216 ; CHECK-O0-NEXT: mov sp, r7 ; CHECK-O0-NEXT: pop {r7, pc} ; CHECK-O0-NEXT: LBB3_2: @ %normal ; CHECK-O0-NEXT: ldr r8, [sp] @ 4-byte Reload ; CHECK-O0-NEXT: mov r0, #0 ; CHECK-O0-NEXT: mov sp, r7 ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: foo_if: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r11, lr} ; CHECK-ANDROID-NEXT: push {r11, lr} ; CHECK-ANDROID-NEXT: cmp r0, #0 ; CHECK-ANDROID-NEXT: beq .LBB3_2 ; CHECK-ANDROID-NEXT: @ %bb.1: @ %gen_error ; CHECK-ANDROID-NEXT: mov r0, #16 ; CHECK-ANDROID-NEXT: mov r1, #0 ; CHECK-ANDROID-NEXT: bl malloc ; CHECK-ANDROID-NEXT: vmov.f32 s0, #1.000000e+00 ; CHECK-ANDROID-NEXT: mov r8, r0 ; CHECK-ANDROID-NEXT: mov r0, #1 ; CHECK-ANDROID-NEXT: strb r0, [r8, #8] ; CHECK-ANDROID-NEXT: vmov r0, s0 ; CHECK-ANDROID-NEXT: pop {r11, pc} ; CHECK-ANDROID-NEXT: .LBB3_2: ; CHECK-ANDROID-NEXT: vldr s0, .LCPI3_0 ; CHECK-ANDROID-NEXT: vmov r0, s0 ; CHECK-ANDROID-NEXT: pop {r11, pc} ; CHECK-ANDROID-NEXT: .p2align 2 ; CHECK-ANDROID-NEXT: @ %bb.3: ; CHECK-ANDROID-NEXT: .LCPI3_0: ; CHECK-ANDROID-NEXT: .long 0x00000000 @ float 0 ; spill to stack ; reload from stack entry: %cond = icmp ne i32 %cc, 0 br i1 %cond, label %gen_error, label %normal gen_error: %call = call i8* @malloc(i64 16) %call.0 = bitcast i8* %call to %swift_error* store %swift_error* %call.0, %swift_error** %error_ptr_ref %tmp = getelementptr inbounds i8, i8* %call, i64 8 store i8 1, i8* %tmp ret float 1.0 normal: ret float 0.0 } ; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror ; under a certain condition inside a loop. define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) { ; CHECK-APPLE-LABEL: foo_loop: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {r4, r5, lr} ; CHECK-APPLE-NEXT: vpush {d8, d9} ; CHECK-APPLE-NEXT: vmov.f32 s18, #1.000000e+00 ; CHECK-APPLE-NEXT: mov r4, r0 ; CHECK-APPLE-NEXT: vmov s16, r1 ; CHECK-APPLE-NEXT: mov r5, #1 ; CHECK-APPLE-NEXT: b LBB4_2 ; CHECK-APPLE-NEXT: LBB4_1: @ %bb_cont ; CHECK-APPLE-NEXT: @ in Loop: Header=BB4_2 Depth=1 ; CHECK-APPLE-NEXT: vcmp.f32 s16, s18 ; CHECK-APPLE-NEXT: vmrs APSR_nzcv, fpscr ; CHECK-APPLE-NEXT: bgt LBB4_4 ; CHECK-APPLE-NEXT: LBB4_2: @ %bb_loop ; CHECK-APPLE-NEXT: @ =>This Inner Loop Header: Depth=1 ; CHECK-APPLE-NEXT: cmp r4, #0 ; CHECK-APPLE-NEXT: beq LBB4_1 ; CHECK-APPLE-NEXT: @ %bb.3: @ %gen_error ; CHECK-APPLE-NEXT: @ in Loop: Header=BB4_2 Depth=1 ; CHECK-APPLE-NEXT: mov r0, #16 ; CHECK-APPLE-NEXT: mov r1, #0 ; CHECK-APPLE-NEXT: bl _malloc ; CHECK-APPLE-NEXT: mov r8, r0 ; CHECK-APPLE-NEXT: strb r5, [r0, #8] ; CHECK-APPLE-NEXT: b LBB4_1 ; CHECK-APPLE-NEXT: LBB4_4: @ %bb_end ; CHECK-APPLE-NEXT: mov r0, #0 ; CHECK-APPLE-NEXT: vpop {d8, d9} ; CHECK-APPLE-NEXT: pop {r4, r5, pc} ; ; CHECK-O0-LABEL: foo_loop: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: sub sp, sp, #20 ; CHECK-O0-NEXT: str r0, [sp, #8] @ 4-byte Spill ; CHECK-O0-NEXT: vmov s0, r1 ; CHECK-O0-NEXT: vstr s0, [r7, #-8] @ 4-byte Spill ; CHECK-O0-NEXT: str r8, [r7, #-4] @ 4-byte Spill ; CHECK-O0-NEXT: b LBB4_1 ; CHECK-O0-NEXT: LBB4_1: @ %bb_loop ; CHECK-O0-NEXT: @ =>This Inner Loop Header: Depth=1 ; CHECK-O0-NEXT: ldr r1, [sp, #8] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r0, [r7, #-4] @ 4-byte Reload ; CHECK-O0-NEXT: cmp r1, #0 ; CHECK-O0-NEXT: str r0, [sp, #4] @ 4-byte Spill ; CHECK-O0-NEXT: beq LBB4_3 ; CHECK-O0-NEXT: @ %bb.2: @ %gen_error ; CHECK-O0-NEXT: @ in Loop: Header=BB4_1 Depth=1 ; CHECK-O0-NEXT: mov r0, #16 ; CHECK-O0-NEXT: mov r1, #0 ; CHECK-O0-NEXT: bl _malloc ; CHECK-O0-NEXT: mov r2, r0 ; CHECK-O0-NEXT: movw r1, #1 ; CHECK-O0-NEXT: strb r1, [r2, #8] ; CHECK-O0-NEXT: str r0, [sp, #4] @ 4-byte Spill ; CHECK-O0-NEXT: LBB4_3: @ %bb_cont ; CHECK-O0-NEXT: @ in Loop: Header=BB4_1 Depth=1 ; CHECK-O0-NEXT: vldr s0, [r7, #-8] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r0, [sp, #4] @ 4-byte Reload ; CHECK-O0-NEXT: str r0, [sp] @ 4-byte Spill ; CHECK-O0-NEXT: vmov.f32 s2, #1.000000e+00 ; CHECK-O0-NEXT: vcmp.f32 s0, s2 ; CHECK-O0-NEXT: vmrs APSR_nzcv, fpscr ; CHECK-O0-NEXT: str r0, [r7, #-4] @ 4-byte Spill ; CHECK-O0-NEXT: ble LBB4_1 ; CHECK-O0-NEXT: @ %bb.4: @ %bb_end ; CHECK-O0-NEXT: ldr r8, [sp] @ 4-byte Reload ; CHECK-O0-NEXT: mov r0, #0 ; CHECK-O0-NEXT: mov sp, r7 ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: foo_loop: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r4, r5, r11, lr} ; CHECK-ANDROID-NEXT: push {r4, r5, r11, lr} ; CHECK-ANDROID-NEXT: .vsave {d8, d9} ; CHECK-ANDROID-NEXT: vpush {d8, d9} ; CHECK-ANDROID-NEXT: vmov.f32 s18, #1.000000e+00 ; CHECK-ANDROID-NEXT: mov r4, r0 ; CHECK-ANDROID-NEXT: vmov s16, r1 ; CHECK-ANDROID-NEXT: mov r5, #1 ; CHECK-ANDROID-NEXT: b .LBB4_2 ; CHECK-ANDROID-NEXT: .LBB4_1: @ %bb_cont ; CHECK-ANDROID-NEXT: @ in Loop: Header=BB4_2 Depth=1 ; CHECK-ANDROID-NEXT: vcmp.f32 s16, s18 ; CHECK-ANDROID-NEXT: vmrs APSR_nzcv, fpscr ; CHECK-ANDROID-NEXT: bgt .LBB4_4 ; CHECK-ANDROID-NEXT: .LBB4_2: @ %bb_loop ; CHECK-ANDROID-NEXT: @ =>This Inner Loop Header: Depth=1 ; CHECK-ANDROID-NEXT: cmp r4, #0 ; CHECK-ANDROID-NEXT: beq .LBB4_1 ; CHECK-ANDROID-NEXT: @ %bb.3: @ %gen_error ; CHECK-ANDROID-NEXT: @ in Loop: Header=BB4_2 Depth=1 ; CHECK-ANDROID-NEXT: mov r0, #16 ; CHECK-ANDROID-NEXT: mov r1, #0 ; CHECK-ANDROID-NEXT: bl malloc ; CHECK-ANDROID-NEXT: mov r8, r0 ; CHECK-ANDROID-NEXT: strb r5, [r0, #8] ; CHECK-ANDROID-NEXT: b .LBB4_1 ; CHECK-ANDROID-NEXT: .LBB4_4: @ %bb_end ; CHECK-ANDROID-NEXT: mov r0, #0 ; CHECK-ANDROID-NEXT: vpop {d8, d9} ; CHECK-ANDROID-NEXT: pop {r4, r5, r11, pc} ; swifterror is kept in a register ; spill r0 ; reload from stack entry: br label %bb_loop bb_loop: %cond = icmp ne i32 %cc, 0 br i1 %cond, label %gen_error, label %bb_cont gen_error: %call = call i8* @malloc(i64 16) %call.0 = bitcast i8* %call to %swift_error* store %swift_error* %call.0, %swift_error** %error_ptr_ref %tmp = getelementptr inbounds i8, i8* %call, i64 8 store i8 1, i8* %tmp br label %bb_cont bb_cont: %cmp = fcmp ogt float %cc2, 1.000000e+00 br i1 %cmp, label %bb_end, label %bb_loop bb_end: ret float 0.0 } ; "foo_sret" is a function that takes a swifterror parameter, it also has a sret ; parameter. define void @foo_sret(%struct.S* sret(%struct.S) %agg.result, i32 %val1, %swift_error** swifterror %error_ptr_ref) { ; CHECK-APPLE-LABEL: foo_sret: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {r4, r5, lr} ; CHECK-APPLE-NEXT: mov r4, r1 ; CHECK-APPLE-NEXT: mov r5, r0 ; CHECK-APPLE-NEXT: mov r0, #16 ; CHECK-APPLE-NEXT: mov r1, #0 ; CHECK-APPLE-NEXT: bl _malloc ; CHECK-APPLE-NEXT: mov r1, #1 ; CHECK-APPLE-NEXT: mov r8, r0 ; CHECK-APPLE-NEXT: strb r1, [r0, #8] ; CHECK-APPLE-NEXT: str r4, [r5, #4] ; CHECK-APPLE-NEXT: pop {r4, r5, pc} ; ; CHECK-O0-LABEL: foo_sret: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: sub sp, sp, #8 ; CHECK-O0-NEXT: str r1, [sp] @ 4-byte Spill ; CHECK-O0-NEXT: str r0, [sp, #4] @ 4-byte Spill ; CHECK-O0-NEXT: mov r0, #16 ; CHECK-O0-NEXT: mov r1, #0 ; CHECK-O0-NEXT: bl _malloc ; CHECK-O0-NEXT: ldr r1, [sp] @ 4-byte Reload ; CHECK-O0-NEXT: mov r3, r0 ; CHECK-O0-NEXT: ldr r0, [sp, #4] @ 4-byte Reload ; CHECK-O0-NEXT: mov r8, r3 ; CHECK-O0-NEXT: mov r2, #1 ; CHECK-O0-NEXT: strb r2, [r3, #8] ; CHECK-O0-NEXT: str r1, [r0, #4] ; CHECK-O0-NEXT: mov sp, r7 ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: foo_sret: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r4, r5, r11, lr} ; CHECK-ANDROID-NEXT: push {r4, r5, r11, lr} ; CHECK-ANDROID-NEXT: mov r4, r1 ; CHECK-ANDROID-NEXT: mov r5, r0 ; CHECK-ANDROID-NEXT: mov r0, #16 ; CHECK-ANDROID-NEXT: mov r1, #0 ; CHECK-ANDROID-NEXT: bl malloc ; CHECK-ANDROID-NEXT: mov r1, #1 ; CHECK-ANDROID-NEXT: mov r8, r0 ; CHECK-ANDROID-NEXT: strb r1, [r0, #8] ; CHECK-ANDROID-NEXT: str r4, [r5, #4] ; CHECK-ANDROID-NEXT: pop {r4, r5, r11, pc} ; spill to stack: sret and val1 ; reload from stack: sret and val1 entry: %call = call i8* @malloc(i64 16) %call.0 = bitcast i8* %call to %swift_error* store %swift_error* %call.0, %swift_error** %error_ptr_ref %tmp = getelementptr inbounds i8, i8* %call, i64 8 store i8 1, i8* %tmp %v2 = getelementptr inbounds %struct.S, %struct.S* %agg.result, i32 0, i32 1 store i32 %val1, i32* %v2 ret void } ; "caller3" calls "foo_sret" that takes a swifterror parameter. define float @caller3(i8* %error_ref) { ; CHECK-APPLE-LABEL: caller3: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {r4, r7, r8, lr} ; CHECK-APPLE-NEXT: add r7, sp, #8 ; CHECK-APPLE-NEXT: sub sp, sp, #32 ; CHECK-APPLE-NEXT: bfc sp, #0, #3 ; CHECK-APPLE-NEXT: mov r4, r0 ; CHECK-APPLE-NEXT: add r0, sp, #8 ; CHECK-APPLE-NEXT: mov r1, #1 ; CHECK-APPLE-NEXT: mov r8, #0 ; CHECK-APPLE-NEXT: bl _foo_sret ; CHECK-APPLE-NEXT: mov r0, r8 ; CHECK-APPLE-NEXT: cmp r8, #0 ; CHECK-APPLE-NEXT: ldrbeq r1, [r0, #8] ; CHECK-APPLE-NEXT: strbeq r1, [r4] ; CHECK-APPLE-NEXT: bl _free ; CHECK-APPLE-NEXT: mov r0, #1065353216 ; CHECK-APPLE-NEXT: sub sp, r7, #8 ; CHECK-APPLE-NEXT: pop {r4, r7, r8, pc} ; ; CHECK-O0-LABEL: caller3: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: push {r8} ; CHECK-O0-NEXT: sub sp, sp, #44 ; CHECK-O0-NEXT: bfc sp, #0, #3 ; CHECK-O0-NEXT: @ implicit-def: $r1 ; CHECK-O0-NEXT: str r0, [sp, #4] @ 4-byte Spill ; CHECK-O0-NEXT: mov r8, #0 ; CHECK-O0-NEXT: add r0, sp, #16 ; CHECK-O0-NEXT: mov r1, #1 ; CHECK-O0-NEXT: bl _foo_sret ; CHECK-O0-NEXT: str r8, [sp, #8] @ 4-byte Spill ; CHECK-O0-NEXT: movw r0, #0 ; CHECK-O0-NEXT: cmp r8, r0 ; CHECK-O0-NEXT: bne LBB6_2 ; CHECK-O0-NEXT: @ %bb.1: @ %cont ; CHECK-O0-NEXT: ldr r1, [sp, #4] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r0, [sp, #8] @ 4-byte Reload ; CHECK-O0-NEXT: ldrb r0, [r0, #8] ; CHECK-O0-NEXT: strb r0, [r1] ; CHECK-O0-NEXT: LBB6_2: @ %handler ; CHECK-O0-NEXT: ldr r0, [sp, #8] @ 4-byte Reload ; CHECK-O0-NEXT: bl _free ; CHECK-O0-NEXT: mov r0, #1065353216 ; CHECK-O0-NEXT: sub sp, r7, #4 ; CHECK-O0-NEXT: pop {r8} ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: caller3: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r4, r8, r11, lr} ; CHECK-ANDROID-NEXT: push {r4, r8, r11, lr} ; CHECK-ANDROID-NEXT: .pad #32 ; CHECK-ANDROID-NEXT: sub sp, sp, #32 ; CHECK-ANDROID-NEXT: mov r4, r0 ; CHECK-ANDROID-NEXT: add r0, sp, #8 ; CHECK-ANDROID-NEXT: mov r1, #1 ; CHECK-ANDROID-NEXT: mov r8, #0 ; CHECK-ANDROID-NEXT: bl foo_sret ; CHECK-ANDROID-NEXT: mov r0, r8 ; CHECK-ANDROID-NEXT: cmp r8, #0 ; CHECK-ANDROID-NEXT: ldrbeq r1, [r0, #8] ; CHECK-ANDROID-NEXT: strbeq r1, [r4] ; CHECK-ANDROID-NEXT: bl free ; CHECK-ANDROID-NEXT: mov r0, #1065353216 ; CHECK-ANDROID-NEXT: add sp, sp, #32 ; CHECK-ANDROID-NEXT: pop {r4, r8, r11, pc} ; Access part of the error object and save it to error_ref ; Access part of the error object and save it to error_ref entry: %s = alloca %struct.S, align 8 %error_ptr_ref = alloca swifterror %swift_error* store %swift_error* null, %swift_error** %error_ptr_ref call void @foo_sret(%struct.S* sret(%struct.S) %s, i32 1, %swift_error** swifterror %error_ptr_ref) %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null %tmp = bitcast %swift_error* %error_from_foo to i8* br i1 %had_error_from_foo, label %handler, label %cont cont: %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 %t = load i8, i8* %v1 store i8 %t, i8* %error_ref br label %handler handler: call void @free(i8* %tmp) ret float 1.0 } ; "foo_vararg" is a function that takes a swifterror parameter, it also has ; variable number of arguments. declare void @llvm.va_start(i8*) nounwind define float @foo_vararg(%swift_error** swifterror %error_ptr_ref, ...) { ; CHECK-APPLE-LABEL: foo_vararg: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: sub sp, sp, #16 ; CHECK-APPLE-NEXT: push {r7, lr} ; CHECK-APPLE-NEXT: mov r7, sp ; CHECK-APPLE-NEXT: sub sp, sp, #24 ; CHECK-APPLE-NEXT: bfc sp, #0, #3 ; CHECK-APPLE-NEXT: add r8, r7, #8 ; CHECK-APPLE-NEXT: stm r8, {r0, r1, r2, r3} ; CHECK-APPLE-NEXT: mov r0, #16 ; CHECK-APPLE-NEXT: mov r1, #0 ; CHECK-APPLE-NEXT: bl _malloc ; CHECK-APPLE-NEXT: mov r8, r0 ; CHECK-APPLE-NEXT: mov r0, #1 ; CHECK-APPLE-NEXT: strb r0, [r8, #8] ; CHECK-APPLE-NEXT: add r0, r7, #8 ; CHECK-APPLE-NEXT: add r0, r0, #4 ; CHECK-APPLE-NEXT: ldr r2, [r7, #8] ; CHECK-APPLE-NEXT: ldr r1, [r0], #4 ; CHECK-APPLE-NEXT: ldr r3, [r0], #4 ; CHECK-APPLE-NEXT: str r0, [sp, #16] ; CHECK-APPLE-NEXT: mov r0, #1065353216 ; CHECK-APPLE-NEXT: str r2, [sp, #12] ; CHECK-APPLE-NEXT: str r1, [sp, #8] ; CHECK-APPLE-NEXT: str r3, [sp, #4] ; CHECK-APPLE-NEXT: mov sp, r7 ; CHECK-APPLE-NEXT: pop {r7, lr} ; CHECK-APPLE-NEXT: add sp, sp, #16 ; CHECK-APPLE-NEXT: bx lr ; ; CHECK-O0-LABEL: foo_vararg: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: sub sp, sp, #16 ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: sub sp, sp, #24 ; CHECK-O0-NEXT: bfc sp, #0, #3 ; CHECK-O0-NEXT: str r3, [r7, #20] ; CHECK-O0-NEXT: str r2, [r7, #16] ; CHECK-O0-NEXT: str r1, [r7, #12] ; CHECK-O0-NEXT: str r0, [r7, #8] ; CHECK-O0-NEXT: mov r0, #16 ; CHECK-O0-NEXT: mov r1, #0 ; CHECK-O0-NEXT: bl _malloc ; CHECK-O0-NEXT: mov r1, r0 ; CHECK-O0-NEXT: mov r8, r1 ; CHECK-O0-NEXT: mov r0, #1 ; CHECK-O0-NEXT: strb r0, [r1, #8] ; CHECK-O0-NEXT: add r0, r7, #8 ; CHECK-O0-NEXT: str r0, [sp, #16] ; CHECK-O0-NEXT: ldr r0, [sp, #16] ; CHECK-O0-NEXT: add r1, r0, #4 ; CHECK-O0-NEXT: str r1, [sp, #16] ; CHECK-O0-NEXT: ldr r0, [r0] ; CHECK-O0-NEXT: str r0, [sp, #12] ; CHECK-O0-NEXT: ldr r0, [sp, #16] ; CHECK-O0-NEXT: add r1, r0, #4 ; CHECK-O0-NEXT: str r1, [sp, #16] ; CHECK-O0-NEXT: ldr r0, [r0] ; CHECK-O0-NEXT: str r0, [sp, #8] ; CHECK-O0-NEXT: ldr r0, [sp, #16] ; CHECK-O0-NEXT: add r1, r0, #4 ; CHECK-O0-NEXT: str r1, [sp, #16] ; CHECK-O0-NEXT: ldr r0, [r0] ; CHECK-O0-NEXT: str r0, [sp, #4] ; CHECK-O0-NEXT: mov r0, #1065353216 ; CHECK-O0-NEXT: mov sp, r7 ; CHECK-O0-NEXT: pop {r7, lr} ; CHECK-O0-NEXT: add sp, sp, #16 ; CHECK-O0-NEXT: bx lr ; ; CHECK-ANDROID-LABEL: foo_vararg: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .pad #16 ; CHECK-ANDROID-NEXT: sub sp, sp, #16 ; CHECK-ANDROID-NEXT: .save {r11, lr} ; CHECK-ANDROID-NEXT: push {r11, lr} ; CHECK-ANDROID-NEXT: .pad #24 ; CHECK-ANDROID-NEXT: sub sp, sp, #24 ; CHECK-ANDROID-NEXT: add r8, sp, #32 ; CHECK-ANDROID-NEXT: stm r8, {r0, r1, r2, r3} ; CHECK-ANDROID-NEXT: mov r0, #16 ; CHECK-ANDROID-NEXT: mov r1, #0 ; CHECK-ANDROID-NEXT: bl malloc ; CHECK-ANDROID-NEXT: mov r8, r0 ; CHECK-ANDROID-NEXT: mov r0, #1 ; CHECK-ANDROID-NEXT: strb r0, [r8, #8] ; CHECK-ANDROID-NEXT: add r0, sp, #32 ; CHECK-ANDROID-NEXT: orr r0, r0, #4 ; CHECK-ANDROID-NEXT: ldr r2, [sp, #32] ; CHECK-ANDROID-NEXT: ldr r1, [r0], #4 ; CHECK-ANDROID-NEXT: ldr r3, [r0], #4 ; CHECK-ANDROID-NEXT: str r0, [sp, #16] ; CHECK-ANDROID-NEXT: mov r0, #1065353216 ; CHECK-ANDROID-NEXT: str r2, [sp, #12] ; CHECK-ANDROID-NEXT: str r1, [sp, #8] ; CHECK-ANDROID-NEXT: str r3, [sp, #4] ; CHECK-ANDROID-NEXT: add sp, sp, #24 ; CHECK-ANDROID-NEXT: pop {r11, lr} ; CHECK-ANDROID-NEXT: add sp, sp, #16 ; CHECK-ANDROID-NEXT: bx lr entry: %call = call i8* @malloc(i64 16) %call.0 = bitcast i8* %call to %swift_error* store %swift_error* %call.0, %swift_error** %error_ptr_ref %tmp = getelementptr inbounds i8, i8* %call, i64 8 store i8 1, i8* %tmp %args = alloca i8*, align 8 %a10 = alloca i32, align 4 %a11 = alloca i32, align 4 %a12 = alloca i32, align 4 %v10 = bitcast i8** %args to i8* call void @llvm.va_start(i8* %v10) %v11 = va_arg i8** %args, i32 store i32 %v11, i32* %a10, align 4 %v12 = va_arg i8** %args, i32 store i32 %v12, i32* %a11, align 4 %v13 = va_arg i8** %args, i32 store i32 %v13, i32* %a12, align 4 ret float 1.0 } ; "caller4" calls "foo_vararg" that takes a swifterror parameter. define float @caller4(i8* %error_ref) { ; CHECK-APPLE-LABEL: caller4: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {r4, r8, lr} ; CHECK-APPLE-NEXT: sub sp, sp, #16 ; CHECK-APPLE-NEXT: mov r4, r0 ; CHECK-APPLE-NEXT: mov r0, #11 ; CHECK-APPLE-NEXT: str r0, [sp, #4] ; CHECK-APPLE-NEXT: mov r0, #10 ; CHECK-APPLE-NEXT: str r0, [sp, #8] ; CHECK-APPLE-NEXT: mov r0, #12 ; CHECK-APPLE-NEXT: str r0, [sp] ; CHECK-APPLE-NEXT: mov r8, #0 ; CHECK-APPLE-NEXT: mov r0, #10 ; CHECK-APPLE-NEXT: mov r1, #11 ; CHECK-APPLE-NEXT: mov r2, #12 ; CHECK-APPLE-NEXT: bl _foo_vararg ; CHECK-APPLE-NEXT: mov r0, r8 ; CHECK-APPLE-NEXT: cmp r8, #0 ; CHECK-APPLE-NEXT: ldrbeq r1, [r0, #8] ; CHECK-APPLE-NEXT: strbeq r1, [r4] ; CHECK-APPLE-NEXT: bl _free ; CHECK-APPLE-NEXT: mov r0, #1065353216 ; CHECK-APPLE-NEXT: add sp, sp, #16 ; CHECK-APPLE-NEXT: pop {r4, r8, pc} ; ; CHECK-O0-LABEL: caller4: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: push {r8} ; CHECK-O0-NEXT: sub sp, sp, #24 ; CHECK-O0-NEXT: @ implicit-def: $r1 ; CHECK-O0-NEXT: str r0, [sp] @ 4-byte Spill ; CHECK-O0-NEXT: mov r8, #0 ; CHECK-O0-NEXT: mov r0, #10 ; CHECK-O0-NEXT: str r0, [r7, #-12] ; CHECK-O0-NEXT: mov r0, #11 ; CHECK-O0-NEXT: str r0, [sp, #12] ; CHECK-O0-NEXT: mov r0, #12 ; CHECK-O0-NEXT: str r0, [sp, #8] ; CHECK-O0-NEXT: ldr r0, [r7, #-12] ; CHECK-O0-NEXT: ldr r1, [sp, #12] ; CHECK-O0-NEXT: ldr r2, [sp, #8] ; CHECK-O0-NEXT: bl _foo_vararg ; CHECK-O0-NEXT: str r8, [sp, #4] @ 4-byte Spill ; CHECK-O0-NEXT: movw r0, #0 ; CHECK-O0-NEXT: cmp r8, r0 ; CHECK-O0-NEXT: bne LBB8_2 ; CHECK-O0-NEXT: @ %bb.1: @ %cont ; CHECK-O0-NEXT: ldr r1, [sp] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r0, [sp, #4] @ 4-byte Reload ; CHECK-O0-NEXT: ldrb r0, [r0, #8] ; CHECK-O0-NEXT: strb r0, [r1] ; CHECK-O0-NEXT: LBB8_2: @ %handler ; CHECK-O0-NEXT: ldr r0, [sp, #4] @ 4-byte Reload ; CHECK-O0-NEXT: bl _free ; CHECK-O0-NEXT: mov r0, #1065353216 ; CHECK-O0-NEXT: sub sp, r7, #4 ; CHECK-O0-NEXT: pop {r8} ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: caller4: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r4, r8, r11, lr} ; CHECK-ANDROID-NEXT: push {r4, r8, r11, lr} ; CHECK-ANDROID-NEXT: .pad #16 ; CHECK-ANDROID-NEXT: sub sp, sp, #16 ; CHECK-ANDROID-NEXT: mov r4, r0 ; CHECK-ANDROID-NEXT: mov r0, #11 ; CHECK-ANDROID-NEXT: str r0, [sp, #4] ; CHECK-ANDROID-NEXT: mov r0, #10 ; CHECK-ANDROID-NEXT: str r0, [sp, #8] ; CHECK-ANDROID-NEXT: mov r0, #12 ; CHECK-ANDROID-NEXT: str r0, [sp] ; CHECK-ANDROID-NEXT: mov r8, #0 ; CHECK-ANDROID-NEXT: mov r0, #10 ; CHECK-ANDROID-NEXT: mov r1, #11 ; CHECK-ANDROID-NEXT: mov r2, #12 ; CHECK-ANDROID-NEXT: bl foo_vararg ; CHECK-ANDROID-NEXT: mov r0, r8 ; CHECK-ANDROID-NEXT: cmp r8, #0 ; CHECK-ANDROID-NEXT: ldrbeq r1, [r0, #8] ; CHECK-ANDROID-NEXT: strbeq r1, [r4] ; CHECK-ANDROID-NEXT: bl free ; CHECK-ANDROID-NEXT: mov r0, #1065353216 ; CHECK-ANDROID-NEXT: add sp, sp, #16 ; CHECK-ANDROID-NEXT: pop {r4, r8, r11, pc} ; Access part of the error object and save it to error_ref entry: %error_ptr_ref = alloca swifterror %swift_error* store %swift_error* null, %swift_error** %error_ptr_ref %a10 = alloca i32, align 4 %a11 = alloca i32, align 4 %a12 = alloca i32, align 4 store i32 10, i32* %a10, align 4 store i32 11, i32* %a11, align 4 store i32 12, i32* %a12, align 4 %v10 = load i32, i32* %a10, align 4 %v11 = load i32, i32* %a11, align 4 %v12 = load i32, i32* %a12, align 4 %call = call float (%swift_error**, ...) @foo_vararg(%swift_error** swifterror %error_ptr_ref, i32 %v10, i32 %v11, i32 %v12) %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null %tmp = bitcast %swift_error* %error_from_foo to i8* br i1 %had_error_from_foo, label %handler, label %cont cont: %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 %t = load i8, i8* %v1 store i8 %t, i8* %error_ref br label %handler handler: call void @free(i8* %tmp) ret float 1.0 } ; Check that we don't blow up on tail calling swifterror argument functions. define float @tailcallswifterror(%swift_error** swifterror %error_ptr_ref) { ; CHECK-APPLE-LABEL: tailcallswifterror: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {lr} ; CHECK-APPLE-NEXT: bl _tailcallswifterror ; CHECK-APPLE-NEXT: pop {lr} ; CHECK-APPLE-NEXT: bx lr ; ; CHECK-O0-LABEL: tailcallswifterror: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: bl _tailcallswifterror ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: tailcallswifterror: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r11, lr} ; CHECK-ANDROID-NEXT: push {r11, lr} ; CHECK-ANDROID-NEXT: bl tailcallswifterror ; CHECK-ANDROID-NEXT: pop {r11, pc} entry: %0 = tail call float @tailcallswifterror(%swift_error** swifterror %error_ptr_ref) ret float %0 } define swiftcc float @tailcallswifterror_swiftcc(%swift_error** swifterror %error_ptr_ref) { ; CHECK-APPLE-LABEL: tailcallswifterror_swiftcc: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {lr} ; CHECK-APPLE-NEXT: bl _tailcallswifterror_swiftcc ; CHECK-APPLE-NEXT: pop {lr} ; CHECK-APPLE-NEXT: bx lr ; ; CHECK-O0-LABEL: tailcallswifterror_swiftcc: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: bl _tailcallswifterror_swiftcc ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: tailcallswifterror_swiftcc: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r11, lr} ; CHECK-ANDROID-NEXT: push {r11, lr} ; CHECK-ANDROID-NEXT: bl tailcallswifterror_swiftcc ; CHECK-ANDROID-NEXT: pop {r11, pc} entry: %0 = tail call swiftcc float @tailcallswifterror_swiftcc(%swift_error** swifterror %error_ptr_ref) ret float %0 } define swiftcc void @swifterror_clobber(%swift_error** nocapture swifterror %err) { ; CHECK-APPLE-LABEL: swifterror_clobber: ; CHECK-APPLE: @ %bb.0: ; CHECK-APPLE-NEXT: mov r0, r8 ; CHECK-APPLE-NEXT: @ InlineAsm Start ; CHECK-APPLE-NEXT: nop ; CHECK-APPLE-NEXT: @ InlineAsm End ; CHECK-APPLE-NEXT: mov r8, r0 ; CHECK-APPLE-NEXT: bx lr ; ; CHECK-O0-LABEL: swifterror_clobber: ; CHECK-O0: @ %bb.0: ; CHECK-O0-NEXT: sub sp, sp, #4 ; CHECK-O0-NEXT: str r8, [sp] @ 4-byte Spill ; CHECK-O0-NEXT: @ InlineAsm Start ; CHECK-O0-NEXT: nop ; CHECK-O0-NEXT: @ InlineAsm End ; CHECK-O0-NEXT: ldr r8, [sp] @ 4-byte Reload ; CHECK-O0-NEXT: add sp, sp, #4 ; CHECK-O0-NEXT: bx lr ; ; CHECK-ANDROID-LABEL: swifterror_clobber: ; CHECK-ANDROID: @ %bb.0: ; CHECK-ANDROID-NEXT: mov r0, r8 ; CHECK-ANDROID-NEXT: @APP ; CHECK-ANDROID-NEXT: nop ; CHECK-ANDROID-NEXT: @NO_APP ; CHECK-ANDROID-NEXT: mov r8, r0 ; CHECK-ANDROID-NEXT: bx lr call void asm sideeffect "nop", "~{r8}"() ret void } define swiftcc void @swifterror_reg_clobber(%swift_error** nocapture %err) { ; CHECK-APPLE-LABEL: swifterror_reg_clobber: ; CHECK-APPLE: @ %bb.0: ; CHECK-APPLE-NEXT: push {r8, lr} ; CHECK-APPLE-NEXT: @ InlineAsm Start ; CHECK-APPLE-NEXT: nop ; CHECK-APPLE-NEXT: @ InlineAsm End ; CHECK-APPLE-NEXT: pop {r8, pc} ; ; CHECK-O0-LABEL: swifterror_reg_clobber: ; CHECK-O0: @ %bb.0: ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: push {r8} ; CHECK-O0-NEXT: @ InlineAsm Start ; CHECK-O0-NEXT: nop ; CHECK-O0-NEXT: @ InlineAsm End ; CHECK-O0-NEXT: pop {r8} ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: swifterror_reg_clobber: ; CHECK-ANDROID: @ %bb.0: ; CHECK-ANDROID-NEXT: .save {r8, lr} ; CHECK-ANDROID-NEXT: push {r8, lr} ; CHECK-ANDROID-NEXT: @APP ; CHECK-ANDROID-NEXT: nop ; CHECK-ANDROID-NEXT: @NO_APP ; CHECK-ANDROID-NEXT: pop {r8, pc} call void asm sideeffect "nop", "~{r8}"() ret void } define swiftcc void @params_in_reg(i32, i32, i32, i32, i8* swiftself, %swift_error** nocapture swifterror %err) { ; CHECK-APPLE-LABEL: params_in_reg: ; CHECK-APPLE: @ %bb.0: ; CHECK-APPLE-NEXT: push {r4, r5, r6, r7, r10, r11, lr} ; CHECK-APPLE-NEXT: add r7, sp, #20 ; CHECK-APPLE-NEXT: sub sp, sp, #12 ; CHECK-APPLE-NEXT: bfc sp, #0, #3 ; CHECK-APPLE-NEXT: str r8, [sp, #4] @ 4-byte Spill ; CHECK-APPLE-NEXT: mov r6, r3 ; CHECK-APPLE-NEXT: str r10, [sp] @ 4-byte Spill ; CHECK-APPLE-NEXT: mov r4, r2 ; CHECK-APPLE-NEXT: mov r11, r1 ; CHECK-APPLE-NEXT: mov r5, r0 ; CHECK-APPLE-NEXT: mov r0, #1 ; CHECK-APPLE-NEXT: mov r1, #2 ; CHECK-APPLE-NEXT: mov r2, #3 ; CHECK-APPLE-NEXT: mov r3, #4 ; CHECK-APPLE-NEXT: mov r10, #0 ; CHECK-APPLE-NEXT: mov r8, #0 ; CHECK-APPLE-NEXT: bl _params_in_reg2 ; CHECK-APPLE-NEXT: ldr r10, [sp] @ 4-byte Reload ; CHECK-APPLE-NEXT: mov r0, r5 ; CHECK-APPLE-NEXT: ldr r8, [sp, #4] @ 4-byte Reload ; CHECK-APPLE-NEXT: mov r1, r11 ; CHECK-APPLE-NEXT: mov r2, r4 ; CHECK-APPLE-NEXT: mov r3, r6 ; CHECK-APPLE-NEXT: bl _params_in_reg2 ; CHECK-APPLE-NEXT: sub sp, r7, #20 ; CHECK-APPLE-NEXT: pop {r4, r5, r6, r7, r10, r11, pc} ; ; CHECK-O0-LABEL: params_in_reg: ; CHECK-O0: @ %bb.0: ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: push {r10} ; CHECK-O0-NEXT: sub sp, sp, #28 ; CHECK-O0-NEXT: bfc sp, #0, #3 ; CHECK-O0-NEXT: str r8, [sp, #20] @ 4-byte Spill ; CHECK-O0-NEXT: str r10, [sp] @ 4-byte Spill ; CHECK-O0-NEXT: str r3, [sp, #16] @ 4-byte Spill ; CHECK-O0-NEXT: str r2, [sp, #12] @ 4-byte Spill ; CHECK-O0-NEXT: str r1, [sp, #8] @ 4-byte Spill ; CHECK-O0-NEXT: str r0, [sp, #4] @ 4-byte Spill ; CHECK-O0-NEXT: @ implicit-def: $r0 ; CHECK-O0-NEXT: mov r8, #0 ; CHECK-O0-NEXT: mov r0, #1 ; CHECK-O0-NEXT: mov r1, #2 ; CHECK-O0-NEXT: mov r2, #3 ; CHECK-O0-NEXT: mov r3, #4 ; CHECK-O0-NEXT: mov r10, r8 ; CHECK-O0-NEXT: bl _params_in_reg2 ; CHECK-O0-NEXT: ldr r10, [sp] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r0, [sp, #4] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r1, [sp, #8] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r2, [sp, #12] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r3, [sp, #16] @ 4-byte Reload ; CHECK-O0-NEXT: mov r9, r8 ; CHECK-O0-NEXT: ldr r8, [sp, #20] @ 4-byte Reload ; CHECK-O0-NEXT: bl _params_in_reg2 ; CHECK-O0-NEXT: sub sp, r7, #4 ; CHECK-O0-NEXT: pop {r10} ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: params_in_reg: ; CHECK-ANDROID: @ %bb.0: ; CHECK-ANDROID-NEXT: .save {r4, r5, r6, r7, r9, r10, r11, lr} ; CHECK-ANDROID-NEXT: push {r4, r5, r6, r7, r9, r10, r11, lr} ; CHECK-ANDROID-NEXT: .pad #8 ; CHECK-ANDROID-NEXT: sub sp, sp, #8 ; CHECK-ANDROID-NEXT: mov r9, r8 ; CHECK-ANDROID-NEXT: mov r11, r10 ; CHECK-ANDROID-NEXT: mov r6, r3 ; CHECK-ANDROID-NEXT: mov r7, r2 ; CHECK-ANDROID-NEXT: mov r4, r1 ; CHECK-ANDROID-NEXT: mov r5, r0 ; CHECK-ANDROID-NEXT: mov r0, #1 ; CHECK-ANDROID-NEXT: mov r1, #2 ; CHECK-ANDROID-NEXT: mov r2, #3 ; CHECK-ANDROID-NEXT: mov r3, #4 ; CHECK-ANDROID-NEXT: mov r10, #0 ; CHECK-ANDROID-NEXT: mov r8, #0 ; CHECK-ANDROID-NEXT: bl params_in_reg2 ; CHECK-ANDROID-NEXT: mov r0, r5 ; CHECK-ANDROID-NEXT: mov r1, r4 ; CHECK-ANDROID-NEXT: mov r2, r7 ; CHECK-ANDROID-NEXT: mov r3, r6 ; CHECK-ANDROID-NEXT: mov r10, r11 ; CHECK-ANDROID-NEXT: mov r8, r9 ; CHECK-ANDROID-NEXT: bl params_in_reg2 ; CHECK-ANDROID-NEXT: add sp, sp, #8 ; CHECK-ANDROID-NEXT: pop {r4, r5, r6, r7, r9, r10, r11, pc} %error_ptr_ref = alloca swifterror %swift_error*, align 8 store %swift_error* null, %swift_error** %error_ptr_ref call swiftcc void @params_in_reg2(i32 1, i32 2, i32 3, i32 4, i8* swiftself null, %swift_error** nocapture swifterror %error_ptr_ref) call swiftcc void @params_in_reg2(i32 %0, i32 %1, i32 %2, i32 %3, i8* swiftself %4, %swift_error** nocapture swifterror %err) ret void } declare swiftcc void @params_in_reg2(i32, i32, i32, i32, i8* swiftself, %swift_error** nocapture swifterror %err) define swiftcc { i32, i32, i32, i32} @params_and_return_in_reg(i32, i32, i32, i32, i8* swiftself, %swift_error** nocapture swifterror %err) { ; CHECK-APPLE-LABEL: params_and_return_in_reg: ; CHECK-APPLE: @ %bb.0: ; CHECK-APPLE-NEXT: push {r4, r5, r6, r7, r10, r11, lr} ; CHECK-APPLE-NEXT: add r7, sp, #20 ; CHECK-APPLE-NEXT: sub sp, sp, #20 ; CHECK-APPLE-NEXT: bfc sp, #0, #3 ; CHECK-APPLE-NEXT: mov r6, r8 ; CHECK-APPLE-NEXT: str r10, [sp, #12] @ 4-byte Spill ; CHECK-APPLE-NEXT: str r3, [sp, #8] @ 4-byte Spill ; CHECK-APPLE-NEXT: mov r4, r2 ; CHECK-APPLE-NEXT: mov r11, r1 ; CHECK-APPLE-NEXT: mov r5, r0 ; CHECK-APPLE-NEXT: mov r0, #1 ; CHECK-APPLE-NEXT: mov r1, #2 ; CHECK-APPLE-NEXT: mov r2, #3 ; CHECK-APPLE-NEXT: mov r3, #4 ; CHECK-APPLE-NEXT: mov r10, #0 ; CHECK-APPLE-NEXT: mov r8, #0 ; CHECK-APPLE-NEXT: bl _params_in_reg2 ; CHECK-APPLE-NEXT: ldr r3, [sp, #8] @ 4-byte Reload ; CHECK-APPLE-NEXT: mov r0, r5 ; CHECK-APPLE-NEXT: ldr r10, [sp, #12] @ 4-byte Reload ; CHECK-APPLE-NEXT: mov r1, r11 ; CHECK-APPLE-NEXT: str r8, [sp, #4] @ 4-byte Spill ; CHECK-APPLE-NEXT: mov r2, r4 ; CHECK-APPLE-NEXT: mov r8, r6 ; CHECK-APPLE-NEXT: bl _params_and_return_in_reg2 ; CHECK-APPLE-NEXT: str r8, [sp, #12] @ 4-byte Spill ; CHECK-APPLE-NEXT: mov r4, r0 ; CHECK-APPLE-NEXT: ldr r8, [sp, #4] @ 4-byte Reload ; CHECK-APPLE-NEXT: mov r5, r1 ; CHECK-APPLE-NEXT: mov r6, r2 ; CHECK-APPLE-NEXT: mov r11, r3 ; CHECK-APPLE-NEXT: mov r0, #1 ; CHECK-APPLE-NEXT: mov r1, #2 ; CHECK-APPLE-NEXT: mov r2, #3 ; CHECK-APPLE-NEXT: mov r3, #4 ; CHECK-APPLE-NEXT: mov r10, #0 ; CHECK-APPLE-NEXT: bl _params_in_reg2 ; CHECK-APPLE-NEXT: mov r0, r4 ; CHECK-APPLE-NEXT: mov r1, r5 ; CHECK-APPLE-NEXT: mov r2, r6 ; CHECK-APPLE-NEXT: mov r3, r11 ; CHECK-APPLE-NEXT: ldr r8, [sp, #12] @ 4-byte Reload ; CHECK-APPLE-NEXT: sub sp, r7, #20 ; CHECK-APPLE-NEXT: pop {r4, r5, r6, r7, r10, r11, pc} ; ; CHECK-O0-LABEL: params_and_return_in_reg: ; CHECK-O0: @ %bb.0: ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: push {r10} ; CHECK-O0-NEXT: sub sp, sp, #76 ; CHECK-O0-NEXT: bfc sp, #0, #3 ; CHECK-O0-NEXT: str r8, [sp, #24] @ 4-byte Spill ; CHECK-O0-NEXT: str r10, [sp, #4] @ 4-byte Spill ; CHECK-O0-NEXT: str r3, [sp, #20] @ 4-byte Spill ; CHECK-O0-NEXT: str r2, [sp, #16] @ 4-byte Spill ; CHECK-O0-NEXT: str r1, [sp, #12] @ 4-byte Spill ; CHECK-O0-NEXT: str r0, [sp, #8] @ 4-byte Spill ; CHECK-O0-NEXT: @ implicit-def: $r0 ; CHECK-O0-NEXT: mov r8, #0 ; CHECK-O0-NEXT: str r8, [sp, #28] @ 4-byte Spill ; CHECK-O0-NEXT: mov r0, #1 ; CHECK-O0-NEXT: str r0, [sp, #32] @ 4-byte Spill ; CHECK-O0-NEXT: mov r1, #2 ; CHECK-O0-NEXT: str r1, [sp, #36] @ 4-byte Spill ; CHECK-O0-NEXT: mov r2, #3 ; CHECK-O0-NEXT: str r2, [sp, #40] @ 4-byte Spill ; CHECK-O0-NEXT: mov r3, #4 ; CHECK-O0-NEXT: str r3, [sp, #44] @ 4-byte Spill ; CHECK-O0-NEXT: mov r10, r8 ; CHECK-O0-NEXT: bl _params_in_reg2 ; CHECK-O0-NEXT: ldr r10, [sp, #4] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r0, [sp, #8] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r1, [sp, #12] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r2, [sp, #16] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r3, [sp, #20] @ 4-byte Reload ; CHECK-O0-NEXT: mov r9, r8 ; CHECK-O0-NEXT: ldr r8, [sp, #24] @ 4-byte Reload ; CHECK-O0-NEXT: str r9, [sp, #48] @ 4-byte Spill ; CHECK-O0-NEXT: bl _params_and_return_in_reg2 ; CHECK-O0-NEXT: ldr r10, [sp, #28] @ 4-byte Reload ; CHECK-O0-NEXT: mov r9, r0 ; CHECK-O0-NEXT: ldr r0, [sp, #32] @ 4-byte Reload ; CHECK-O0-NEXT: str r9, [sp, #52] @ 4-byte Spill ; CHECK-O0-NEXT: mov r9, r1 ; CHECK-O0-NEXT: ldr r1, [sp, #36] @ 4-byte Reload ; CHECK-O0-NEXT: str r9, [sp, #56] @ 4-byte Spill ; CHECK-O0-NEXT: mov r9, r2 ; CHECK-O0-NEXT: ldr r2, [sp, #40] @ 4-byte Reload ; CHECK-O0-NEXT: str r9, [sp, #60] @ 4-byte Spill ; CHECK-O0-NEXT: mov r9, r3 ; CHECK-O0-NEXT: ldr r3, [sp, #44] @ 4-byte Reload ; CHECK-O0-NEXT: str r9, [sp, #64] @ 4-byte Spill ; CHECK-O0-NEXT: mov r9, r8 ; CHECK-O0-NEXT: ldr r8, [sp, #48] @ 4-byte Reload ; CHECK-O0-NEXT: str r9, [sp, #68] @ 4-byte Spill ; CHECK-O0-NEXT: bl _params_in_reg2 ; CHECK-O0-NEXT: ldr r0, [sp, #52] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r1, [sp, #56] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r2, [sp, #60] @ 4-byte Reload ; CHECK-O0-NEXT: ldr r3, [sp, #64] @ 4-byte Reload ; CHECK-O0-NEXT: mov r9, r8 ; CHECK-O0-NEXT: ldr r8, [sp, #68] @ 4-byte Reload ; CHECK-O0-NEXT: sub sp, r7, #4 ; CHECK-O0-NEXT: pop {r10} ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: params_and_return_in_reg: ; CHECK-ANDROID: @ %bb.0: ; CHECK-ANDROID-NEXT: .save {r4, r5, r6, r7, r9, r10, r11, lr} ; CHECK-ANDROID-NEXT: push {r4, r5, r6, r7, r9, r10, r11, lr} ; CHECK-ANDROID-NEXT: .pad #16 ; CHECK-ANDROID-NEXT: sub sp, sp, #16 ; CHECK-ANDROID-NEXT: str r8, [sp, #4] @ 4-byte Spill ; CHECK-ANDROID-NEXT: mov r11, r10 ; CHECK-ANDROID-NEXT: mov r6, r3 ; CHECK-ANDROID-NEXT: mov r7, r2 ; CHECK-ANDROID-NEXT: mov r4, r1 ; CHECK-ANDROID-NEXT: mov r5, r0 ; CHECK-ANDROID-NEXT: mov r0, #1 ; CHECK-ANDROID-NEXT: mov r1, #2 ; CHECK-ANDROID-NEXT: mov r2, #3 ; CHECK-ANDROID-NEXT: mov r3, #4 ; CHECK-ANDROID-NEXT: mov r10, #0 ; CHECK-ANDROID-NEXT: mov r8, #0 ; CHECK-ANDROID-NEXT: bl params_in_reg2 ; CHECK-ANDROID-NEXT: mov r9, r8 ; CHECK-ANDROID-NEXT: ldr r8, [sp, #4] @ 4-byte Reload ; CHECK-ANDROID-NEXT: mov r0, r5 ; CHECK-ANDROID-NEXT: mov r1, r4 ; CHECK-ANDROID-NEXT: mov r2, r7 ; CHECK-ANDROID-NEXT: mov r3, r6 ; CHECK-ANDROID-NEXT: mov r10, r11 ; CHECK-ANDROID-NEXT: bl params_and_return_in_reg2 ; CHECK-ANDROID-NEXT: mov r4, r0 ; CHECK-ANDROID-NEXT: mov r5, r1 ; CHECK-ANDROID-NEXT: mov r6, r2 ; CHECK-ANDROID-NEXT: mov r7, r3 ; CHECK-ANDROID-NEXT: mov r11, r8 ; CHECK-ANDROID-NEXT: mov r0, #1 ; CHECK-ANDROID-NEXT: mov r1, #2 ; CHECK-ANDROID-NEXT: mov r2, #3 ; CHECK-ANDROID-NEXT: mov r3, #4 ; CHECK-ANDROID-NEXT: mov r10, #0 ; CHECK-ANDROID-NEXT: mov r8, r9 ; CHECK-ANDROID-NEXT: bl params_in_reg2 ; CHECK-ANDROID-NEXT: mov r0, r4 ; CHECK-ANDROID-NEXT: mov r1, r5 ; CHECK-ANDROID-NEXT: mov r2, r6 ; CHECK-ANDROID-NEXT: mov r3, r7 ; CHECK-ANDROID-NEXT: mov r8, r11 ; CHECK-ANDROID-NEXT: add sp, sp, #16 ; CHECK-ANDROID-NEXT: pop {r4, r5, r6, r7, r9, r10, r11, pc} %error_ptr_ref = alloca swifterror %swift_error*, align 8 store %swift_error* null, %swift_error** %error_ptr_ref call swiftcc void @params_in_reg2(i32 1, i32 2, i32 3, i32 4, i8* swiftself null, %swift_error** nocapture swifterror %error_ptr_ref) %val = call swiftcc { i32, i32, i32, i32 } @params_and_return_in_reg2(i32 %0, i32 %1, i32 %2, i32 %3, i8* swiftself %4, %swift_error** nocapture swifterror %err) call swiftcc void @params_in_reg2(i32 1, i32 2, i32 3, i32 4, i8* swiftself null, %swift_error** nocapture swifterror %error_ptr_ref) ret { i32, i32, i32, i32 }%val } declare swiftcc { i32, i32, i32, i32 } @params_and_return_in_reg2(i32, i32, i32, i32, i8* swiftself, %swift_error** nocapture swifterror %err) declare void @acallee(i8*) ; Make sure we don't tail call if the caller returns a swifterror value. We ; would have to move into the swifterror register before the tail call. define swiftcc void @tailcall_from_swifterror(%swift_error** swifterror %error_ptr_ref) { ; CHECK-APPLE-LABEL: tailcall_from_swifterror: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {r4, lr} ; CHECK-APPLE-NEXT: mov r0, #0 ; CHECK-APPLE-NEXT: mov r4, r8 ; CHECK-APPLE-NEXT: bl _acallee ; CHECK-APPLE-NEXT: mov r8, r4 ; CHECK-APPLE-NEXT: pop {r4, pc} ; ; CHECK-O0-LABEL: tailcall_from_swifterror: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: sub sp, sp, #4 ; CHECK-O0-NEXT: str r8, [sp] @ 4-byte Spill ; CHECK-O0-NEXT: mov r0, #0 ; CHECK-O0-NEXT: bl _acallee ; CHECK-O0-NEXT: ldr r8, [sp] @ 4-byte Reload ; CHECK-O0-NEXT: mov sp, r7 ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: tailcall_from_swifterror: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r4, lr} ; CHECK-ANDROID-NEXT: push {r4, lr} ; CHECK-ANDROID-NEXT: mov r0, #0 ; CHECK-ANDROID-NEXT: mov r4, r8 ; CHECK-ANDROID-NEXT: bl acallee ; CHECK-ANDROID-NEXT: mov r8, r4 ; CHECK-ANDROID-NEXT: pop {r4, pc} entry: tail call void @acallee(i8* null) ret void } declare swiftcc void @foo2(%swift_error** swifterror) ; Make sure we properly assign registers during fast-isel. define swiftcc %swift_error* @testAssign(i8* %error_ref) { ; CHECK-APPLE-LABEL: testAssign: ; CHECK-APPLE: @ %bb.0: @ %entry ; CHECK-APPLE-NEXT: push {r8, lr} ; CHECK-APPLE-NEXT: sub sp, sp, #4 ; CHECK-APPLE-NEXT: mov r8, #0 ; CHECK-APPLE-NEXT: bl _foo2 ; CHECK-APPLE-NEXT: mov r0, r8 ; CHECK-APPLE-NEXT: add sp, sp, #4 ; CHECK-APPLE-NEXT: pop {r8, pc} ; ; CHECK-O0-LABEL: testAssign: ; CHECK-O0: @ %bb.0: @ %entry ; CHECK-O0-NEXT: push {r7, lr} ; CHECK-O0-NEXT: mov r7, sp ; CHECK-O0-NEXT: push {r8} ; CHECK-O0-NEXT: sub sp, sp, #8 ; CHECK-O0-NEXT: @ implicit-def: $r1 ; CHECK-O0-NEXT: mov r8, #0 ; CHECK-O0-NEXT: bl _foo2 ; CHECK-O0-NEXT: str r8, [sp] @ 4-byte Spill ; CHECK-O0-NEXT: @ %bb.1: @ %a ; CHECK-O0-NEXT: ldr r0, [sp] @ 4-byte Reload ; CHECK-O0-NEXT: sub sp, r7, #4 ; CHECK-O0-NEXT: pop {r8} ; CHECK-O0-NEXT: pop {r7, pc} ; ; CHECK-ANDROID-LABEL: testAssign: ; CHECK-ANDROID: @ %bb.0: @ %entry ; CHECK-ANDROID-NEXT: .save {r8, lr} ; CHECK-ANDROID-NEXT: push {r8, lr} ; CHECK-ANDROID-NEXT: .pad #8 ; CHECK-ANDROID-NEXT: sub sp, sp, #8 ; CHECK-ANDROID-NEXT: mov r8, #0 ; CHECK-ANDROID-NEXT: bl foo2 ; CHECK-ANDROID-NEXT: mov r0, r8 ; CHECK-ANDROID-NEXT: add sp, sp, #8 ; CHECK-ANDROID-NEXT: pop {r8, pc} entry: %error_ptr = alloca swifterror %swift_error* store %swift_error* null, %swift_error** %error_ptr call swiftcc void @foo2(%swift_error** swifterror %error_ptr) br label %a a: %error = load %swift_error*, %swift_error** %error_ptr ret %swift_error* %error }