| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | |
| ; RUN: llc -mtriple riscv32-unknown-linux-gnu -o - %s | FileCheck %s | |
| ; RUN: llc -mtriple riscv32-unknown-elf -o - %s | FileCheck %s | |
| ; RUN: sed -e 's/!llvm.module.flags = !{!0}/!llvm.module.flags = !{!0, !15, !16}/' -e 's/^;CF: //' %s \ | |
| ; RUN: | llc -mtriple=riscv32 -verify-machineinstrs \ | |
| ; RUN: | FileCheck -check-prefix=CHECK-CF-RV32 %s | |
| ; RUN: sed -e 's/!llvm.module.flags = !{!0}/!llvm.module.flags = !{!0, !15, !16}/' -e 's/^;CF: //' %s \ | |
| ; RUN: | llc -mtriple=riscv64 -verify-machineinstrs \ | |
| ; RUN: | FileCheck -check-prefix=CHECK-CF-RV64 %s | |
| ; RUN: sed -e 's/!llvm.module.flags = !{!0}/!llvm.module.flags = !{!0, !15, !16}/' -e 's/^;CF: //' %s \ | |
| ; RUN: | llc -code-model=large -mtriple=riscv32 -verify-machineinstrs \ | |
| ; RUN: | FileCheck -check-prefix=CHECK-CF-RV32-LARGE %s | |
| ; RUN: sed -e 's/!llvm.module.flags = !{!0}/!llvm.module.flags = !{!0, !15, !16}/' -e 's/^;CF: //' %s \ | |
| ; RUN: | llc -code-model=large -mtriple=riscv64 -verify-machineinstrs \ | |
| ; RUN: | FileCheck -check-prefix=CHECK-CF-RV64-LARGE %s | |
| ; Perform tail call optimization for global address. | |
| declare i32 @callee_tail(i32 %i) | |
| define i32 @caller_tail(i32 %i) nounwind { | |
| ; CHECK-LABEL: caller_tail: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: tail callee_tail | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_tail: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: tail callee_tail, t2 | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_tail: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: tail callee_tail, t2 | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_tail: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi0: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a1, %pcrel_hi(.LCPI0_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi0)(a1) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t2 | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_tail: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi0: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a1, %pcrel_hi(.LCPI0_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi0)(a1) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t2 | |
| entry: | |
| %r = tail call i32 @callee_tail(i32 %i) | |
| ret i32 %r | |
| } | |
| ; Perform tail call optimization for external symbol. | |
| @dest = global [2 x i8] zeroinitializer | |
| define void @caller_extern(ptr %src) optsize { | |
| ; CHECK-LABEL: caller_extern: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: mv a1, a0 | |
| ; CHECK-NEXT: lui a0, %hi(dest) | |
| ; CHECK-NEXT: addi a0, a0, %lo(dest) | |
| ; CHECK-NEXT: li a2, 7 | |
| ; CHECK-NEXT: tail memcpy | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_extern: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: mv a1, a0 | |
| ; CHECK-CF-RV32-NEXT: lui a0, %hi(dest) | |
| ; CHECK-CF-RV32-NEXT: addi a0, a0, %lo(dest) | |
| ; CHECK-CF-RV32-NEXT: li a2, 7 | |
| ; CHECK-CF-RV32-NEXT: tail memcpy | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_extern: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: mv a1, a0 | |
| ; CHECK-CF-RV64-NEXT: lui a0, %hi(dest) | |
| ; CHECK-CF-RV64-NEXT: addi a0, a0, %lo(dest) | |
| ; CHECK-CF-RV64-NEXT: li a2, 7 | |
| ; CHECK-CF-RV64-NEXT: tail memcpy | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_extern: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a1, a0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi1: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI1_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi1)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi2: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a2, %pcrel_hi(.LCPI1_1) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi2)(a2) | |
| ; CHECK-CF-RV32-LARGE-NEXT: li a2, 7 | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t2 | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_extern: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a1, a0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi1: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI1_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi1)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi2: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a2, %pcrel_hi(.LCPI1_1) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi2)(a2) | |
| ; CHECK-CF-RV64-LARGE-NEXT: li a2, 7 | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t2 | |
| ; CHECK-LARGE-ZICFILP-LABEL: caller_extern: | |
| ; CHECK-LARGE-ZICFILP: # %bb.0: # %entry | |
| ; CHECK-LARGE-ZICFILP-NEXT: lpad 0 | |
| ; CHECK-LARGE-ZICFILP-NEXT: mv a1, a0 | |
| ; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi1: | |
| ; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI1_0) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi1)(a0) | |
| ; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi2: | |
| ; CHECK-LARGE-ZICFILP-NEXT: auipc a2, %pcrel_hi(.LCPI1_1) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi2)(a2) | |
| ; CHECK-LARGE-ZICFILP-NEXT: li a2, 7 | |
| ; CHECK-LARGE-ZICFILP-NEXT: jr t2 | |
| entry: | |
| tail call void @llvm.memcpy.p0.p0.i32(ptr @dest, ptr %src, i32 7, i1 false) | |
| ret void | |
| } | |
| ; Perform tail call optimization for external symbol. | |
| @dest_pgso = global [2 x i8] zeroinitializer | |
| define void @caller_extern_pgso(ptr %src) !prof !14 { | |
| ; CHECK-LABEL: caller_extern_pgso: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: mv a1, a0 | |
| ; CHECK-NEXT: lui a0, %hi(dest_pgso) | |
| ; CHECK-NEXT: addi a0, a0, %lo(dest_pgso) | |
| ; CHECK-NEXT: li a2, 7 | |
| ; CHECK-NEXT: tail memcpy | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_extern_pgso: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: mv a1, a0 | |
| ; CHECK-CF-RV32-NEXT: lui a0, %hi(dest_pgso) | |
| ; CHECK-CF-RV32-NEXT: addi a0, a0, %lo(dest_pgso) | |
| ; CHECK-CF-RV32-NEXT: li a2, 7 | |
| ; CHECK-CF-RV32-NEXT: tail memcpy | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_extern_pgso: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: mv a1, a0 | |
| ; CHECK-CF-RV64-NEXT: lui a0, %hi(dest_pgso) | |
| ; CHECK-CF-RV64-NEXT: addi a0, a0, %lo(dest_pgso) | |
| ; CHECK-CF-RV64-NEXT: li a2, 7 | |
| ; CHECK-CF-RV64-NEXT: tail memcpy | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_extern_pgso: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a1, a0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi3: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI2_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi3)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi4: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a2, %pcrel_hi(.LCPI2_1) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi4)(a2) | |
| ; CHECK-CF-RV32-LARGE-NEXT: li a2, 7 | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t2 | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_extern_pgso: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a1, a0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi3: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI2_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi3)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi4: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a2, %pcrel_hi(.LCPI2_1) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi4)(a2) | |
| ; CHECK-CF-RV64-LARGE-NEXT: li a2, 7 | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t2 | |
| ; CHECK-LARGE-ZICFILP-LABEL: caller_extern_pgso: | |
| ; CHECK-LARGE-ZICFILP: # %bb.0: # %entry | |
| ; CHECK-LARGE-ZICFILP-NEXT: lpad 0 | |
| ; CHECK-LARGE-ZICFILP-NEXT: mv a1, a0 | |
| ; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi3: | |
| ; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI2_0) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi3)(a0) | |
| ; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi4: | |
| ; CHECK-LARGE-ZICFILP-NEXT: auipc a2, %pcrel_hi(.LCPI2_1) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi4)(a2) | |
| ; CHECK-LARGE-ZICFILP-NEXT: li a2, 7 | |
| ; CHECK-LARGE-ZICFILP-NEXT: jr t2 | |
| entry: | |
| tail call void @llvm.memcpy.p0.p0.i32(ptr @dest_pgso, ptr %src, i32 7, i1 false) | |
| ret void | |
| } | |
| ; Perform indirect tail call optimization (for function pointer call). | |
| declare void @callee_indirect1() | |
| declare void @callee_indirect2() | |
| define void @caller_indirect_tail(i32 %a) nounwind { | |
| ; CHECK-LABEL: caller_indirect_tail: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: beqz a0, .LBB3_2 | |
| ; CHECK-NEXT: # %bb.1: # %entry | |
| ; CHECK-NEXT: lui t1, %hi(callee_indirect2) | |
| ; CHECK-NEXT: addi t1, t1, %lo(callee_indirect2) | |
| ; CHECK-NEXT: jr t1 | |
| ; CHECK-NEXT: .LBB3_2: | |
| ; CHECK-NEXT: lui t1, %hi(callee_indirect1) | |
| ; CHECK-NEXT: addi t1, t1, %lo(callee_indirect1) | |
| ; CHECK-NEXT: jr t1 | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_indirect_tail: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: beqz a0, .LBB3_2 | |
| ; CHECK-CF-RV32-NEXT: # %bb.1: # %entry | |
| ; CHECK-CF-RV32-NEXT: lui t1, %hi(callee_indirect2) | |
| ; CHECK-CF-RV32-NEXT: addi t1, t1, %lo(callee_indirect2) | |
| ; CHECK-CF-RV32-NEXT: jr t1 | |
| ; CHECK-CF-RV32-NEXT: .LBB3_2: | |
| ; CHECK-CF-RV32-NEXT: lui t1, %hi(callee_indirect1) | |
| ; CHECK-CF-RV32-NEXT: addi t1, t1, %lo(callee_indirect1) | |
| ; CHECK-CF-RV32-NEXT: jr t1 | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_indirect_tail: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: sext.w a0, a0 | |
| ; CHECK-CF-RV64-NEXT: beqz a0, .LBB3_2 | |
| ; CHECK-CF-RV64-NEXT: # %bb.1: # %entry | |
| ; CHECK-CF-RV64-NEXT: lui t1, %hi(callee_indirect2) | |
| ; CHECK-CF-RV64-NEXT: addi t1, t1, %lo(callee_indirect2) | |
| ; CHECK-CF-RV64-NEXT: jr t1 | |
| ; CHECK-CF-RV64-NEXT: .LBB3_2: | |
| ; CHECK-CF-RV64-NEXT: lui t1, %hi(callee_indirect1) | |
| ; CHECK-CF-RV64-NEXT: addi t1, t1, %lo(callee_indirect1) | |
| ; CHECK-CF-RV64-NEXT: jr t1 | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_indirect_tail: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: beqz a0, .LBB3_2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: # %bb.1: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi6: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI3_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t1, %pcrel_lo(.Lpcrel_hi6)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t1 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .LBB3_2: | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi5: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI3_1) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t1, %pcrel_lo(.Lpcrel_hi5)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t1 | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_indirect_tail: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: sext.w a0, a0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: beqz a0, .LBB3_2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: # %bb.1: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi6: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI3_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t1, %pcrel_lo(.Lpcrel_hi6)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t1 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .LBB3_2: | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi5: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI3_1) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t1, %pcrel_lo(.Lpcrel_hi5)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t1 | |
| entry: | |
| %tobool = icmp eq i32 %a, 0 | |
| %callee = select i1 %tobool, ptr @callee_indirect1, ptr @callee_indirect2 | |
| tail call void %callee() | |
| ret void | |
| } | |
| ; Make sure we don't use t0 as the source for jr as that is a hint to pop the | |
| ; return address stack on some microarchitectures. | |
| define i32 @caller_indirect_no_t0(ptr %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7) { | |
| ; CHECK-LABEL: caller_indirect_no_t0: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: mv t1, a0 | |
| ; CHECK-NEXT: mv a0, a1 | |
| ; CHECK-NEXT: mv a1, a2 | |
| ; CHECK-NEXT: mv a2, a3 | |
| ; CHECK-NEXT: mv a3, a4 | |
| ; CHECK-NEXT: mv a4, a5 | |
| ; CHECK-NEXT: mv a5, a6 | |
| ; CHECK-NEXT: mv a6, a7 | |
| ; CHECK-NEXT: jr t1 | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_indirect_no_t0: | |
| ; CHECK-CF-RV32: # %bb.0: | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: mv t1, a0 | |
| ; CHECK-CF-RV32-NEXT: mv a0, a1 | |
| ; CHECK-CF-RV32-NEXT: mv a1, a2 | |
| ; CHECK-CF-RV32-NEXT: mv a2, a3 | |
| ; CHECK-CF-RV32-NEXT: mv a3, a4 | |
| ; CHECK-CF-RV32-NEXT: mv a4, a5 | |
| ; CHECK-CF-RV32-NEXT: mv a5, a6 | |
| ; CHECK-CF-RV32-NEXT: mv a6, a7 | |
| ; CHECK-CF-RV32-NEXT: jr t1 | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_indirect_no_t0: | |
| ; CHECK-CF-RV64: # %bb.0: | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: mv t1, a0 | |
| ; CHECK-CF-RV64-NEXT: mv a0, a1 | |
| ; CHECK-CF-RV64-NEXT: mv a1, a2 | |
| ; CHECK-CF-RV64-NEXT: mv a2, a3 | |
| ; CHECK-CF-RV64-NEXT: mv a3, a4 | |
| ; CHECK-CF-RV64-NEXT: mv a4, a5 | |
| ; CHECK-CF-RV64-NEXT: mv a5, a6 | |
| ; CHECK-CF-RV64-NEXT: mv a6, a7 | |
| ; CHECK-CF-RV64-NEXT: jr t1 | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_indirect_no_t0: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv t1, a0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a0, a1 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a1, a2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a2, a3 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a3, a4 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a4, a5 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a5, a6 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a6, a7 | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t1 | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_indirect_no_t0: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv t1, a0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a0, a1 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a1, a2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a2, a3 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a3, a4 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a4, a5 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a5, a6 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a6, a7 | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t1 | |
| %9 = tail call i32 %0(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7) | |
| ret i32 %9 | |
| } | |
| ; Do not tail call optimize functions with varargs passed by stack. | |
| declare i32 @callee_varargs(i32, ...) | |
| define void @caller_varargs(i32 %a, i32 %b) nounwind { | |
| ; CHECK-LABEL: caller_varargs: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: addi sp, sp, -16 | |
| ; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: mv a2, a1 | |
| ; CHECK-NEXT: mv a3, a0 | |
| ; CHECK-NEXT: mv a4, a0 | |
| ; CHECK-NEXT: mv a5, a1 | |
| ; CHECK-NEXT: mv a6, a1 | |
| ; CHECK-NEXT: mv a7, a0 | |
| ; CHECK-NEXT: sw a0, 0(sp) | |
| ; CHECK-NEXT: call callee_varargs | |
| ; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: addi sp, sp, 16 | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_varargs: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: mv a2, a1 | |
| ; CHECK-CF-RV32-NEXT: mv a3, a0 | |
| ; CHECK-CF-RV32-NEXT: mv a4, a0 | |
| ; CHECK-CF-RV32-NEXT: mv a5, a1 | |
| ; CHECK-CF-RV32-NEXT: mv a6, a1 | |
| ; CHECK-CF-RV32-NEXT: mv a7, a0 | |
| ; CHECK-CF-RV32-NEXT: sw a0, 0(sp) | |
| ; CHECK-CF-RV32-NEXT: call callee_varargs | |
| ; CHECK-CF-RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV32-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_varargs: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: mv a2, a1 | |
| ; CHECK-CF-RV64-NEXT: mv a3, a0 | |
| ; CHECK-CF-RV64-NEXT: mv a4, a0 | |
| ; CHECK-CF-RV64-NEXT: mv a5, a1 | |
| ; CHECK-CF-RV64-NEXT: mv a6, a1 | |
| ; CHECK-CF-RV64-NEXT: mv a7, a0 | |
| ; CHECK-CF-RV64-NEXT: sd a0, 0(sp) | |
| ; CHECK-CF-RV64-NEXT: call callee_varargs | |
| ; CHECK-CF-RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV64-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_varargs: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi7: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a2, %pcrel_hi(.LCPI5_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi7)(a2) | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a2, a1 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a3, a0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a4, a0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a5, a1 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a6, a1 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a7, a0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw a0, 0(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV32-LARGE-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_varargs: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd ra, 8(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi7: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a2, %pcrel_hi(.LCPI5_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi7)(a2) | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a2, a1 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a3, a0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a4, a0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a5, a1 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a6, a1 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mv a7, a0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd a0, 0(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld ra, 8(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV64-LARGE-NEXT: ret | |
| ; CHECK-LARGE-ZICFILP-LABEL: caller_varargs: | |
| ; CHECK-LARGE-ZICFILP: # %bb.0: # %entry | |
| ; CHECK-LARGE-ZICFILP-NEXT: lpad 0 | |
| ; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, -16 | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi7: | |
| ; CHECK-LARGE-ZICFILP-NEXT: auipc a2, %pcrel_hi(.LCPI5_0) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi7)(a2) | |
| ; CHECK-LARGE-ZICFILP-NEXT: mv a2, a1 | |
| ; CHECK-LARGE-ZICFILP-NEXT: mv a3, a0 | |
| ; CHECK-LARGE-ZICFILP-NEXT: mv a4, a0 | |
| ; CHECK-LARGE-ZICFILP-NEXT: mv a5, a1 | |
| ; CHECK-LARGE-ZICFILP-NEXT: mv a6, a1 | |
| ; CHECK-LARGE-ZICFILP-NEXT: mv a7, a0 | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw a0, 0(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: jalr t2 | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, 16 | |
| ; CHECK-LARGE-ZICFILP-NEXT: ret | |
| entry: | |
| %call = tail call i32 (i32, ...) @callee_varargs(i32 %a, i32 %b, i32 %b, i32 %a, i32 %a, i32 %b, i32 %b, i32 %a, i32 %a) | |
| ret void | |
| } | |
| ; Do not tail call optimize if stack is used to pass parameters. | |
| declare i32 @callee_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n) | |
| define i32 @caller_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n) nounwind { | |
| ; CHECK-LABEL: caller_args: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: addi sp, sp, -32 | |
| ; CHECK-NEXT: sw ra, 28(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: lw t0, 32(sp) | |
| ; CHECK-NEXT: lw t1, 36(sp) | |
| ; CHECK-NEXT: lw t2, 40(sp) | |
| ; CHECK-NEXT: lw t3, 44(sp) | |
| ; CHECK-NEXT: lw t4, 48(sp) | |
| ; CHECK-NEXT: lw t5, 52(sp) | |
| ; CHECK-NEXT: sw t4, 16(sp) | |
| ; CHECK-NEXT: sw t5, 20(sp) | |
| ; CHECK-NEXT: sw t0, 0(sp) | |
| ; CHECK-NEXT: sw t1, 4(sp) | |
| ; CHECK-NEXT: sw t2, 8(sp) | |
| ; CHECK-NEXT: sw t3, 12(sp) | |
| ; CHECK-NEXT: call callee_args | |
| ; CHECK-NEXT: lw ra, 28(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: addi sp, sp, 32 | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_args: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, -32 | |
| ; CHECK-CF-RV32-NEXT: sw ra, 28(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: lw t0, 32(sp) | |
| ; CHECK-CF-RV32-NEXT: lw t1, 36(sp) | |
| ; CHECK-CF-RV32-NEXT: lw t2, 40(sp) | |
| ; CHECK-CF-RV32-NEXT: lw t3, 44(sp) | |
| ; CHECK-CF-RV32-NEXT: lw t4, 48(sp) | |
| ; CHECK-CF-RV32-NEXT: lw t5, 52(sp) | |
| ; CHECK-CF-RV32-NEXT: sw t4, 16(sp) | |
| ; CHECK-CF-RV32-NEXT: sw t5, 20(sp) | |
| ; CHECK-CF-RV32-NEXT: sw t0, 0(sp) | |
| ; CHECK-CF-RV32-NEXT: sw t1, 4(sp) | |
| ; CHECK-CF-RV32-NEXT: sw t2, 8(sp) | |
| ; CHECK-CF-RV32-NEXT: sw t3, 12(sp) | |
| ; CHECK-CF-RV32-NEXT: call callee_args | |
| ; CHECK-CF-RV32-NEXT: lw ra, 28(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, 32 | |
| ; CHECK-CF-RV32-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_args: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, -64 | |
| ; CHECK-CF-RV64-NEXT: sd ra, 56(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: ld t0, 64(sp) | |
| ; CHECK-CF-RV64-NEXT: ld t1, 72(sp) | |
| ; CHECK-CF-RV64-NEXT: ld t2, 80(sp) | |
| ; CHECK-CF-RV64-NEXT: ld t3, 88(sp) | |
| ; CHECK-CF-RV64-NEXT: ld t4, 96(sp) | |
| ; CHECK-CF-RV64-NEXT: ld t5, 104(sp) | |
| ; CHECK-CF-RV64-NEXT: sd t4, 32(sp) | |
| ; CHECK-CF-RV64-NEXT: sd t5, 40(sp) | |
| ; CHECK-CF-RV64-NEXT: sd t0, 0(sp) | |
| ; CHECK-CF-RV64-NEXT: sd t1, 8(sp) | |
| ; CHECK-CF-RV64-NEXT: sd t2, 16(sp) | |
| ; CHECK-CF-RV64-NEXT: sd t3, 24(sp) | |
| ; CHECK-CF-RV64-NEXT: call callee_args | |
| ; CHECK-CF-RV64-NEXT: ld ra, 56(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, 64 | |
| ; CHECK-CF-RV64-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_args: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, -32 | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw ra, 28(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t0, 32(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t1, 36(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t3, 40(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t4, 44(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, 48(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t5, 52(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t2, 16(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t5, 20(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi8: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc t2, %pcrel_hi(.LCPI6_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t0, 0(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t1, 4(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi8)(t2) | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t3, 8(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t4, 12(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw ra, 28(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, 32 | |
| ; CHECK-CF-RV32-LARGE-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_args: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, -64 | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd ra, 56(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t0, 64(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t1, 72(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t3, 80(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t4, 88(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, 96(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t5, 104(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t2, 32(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t5, 40(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi8: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc t2, %pcrel_hi(.LCPI6_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t0, 0(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t1, 8(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi8)(t2) | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t3, 16(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t4, 24(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld ra, 56(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, 64 | |
| ; CHECK-CF-RV64-LARGE-NEXT: ret | |
| ; CHECK-LARGE-ZICFILP-LABEL: caller_args: | |
| ; CHECK-LARGE-ZICFILP: # %bb.0: # %entry | |
| ; CHECK-LARGE-ZICFILP-NEXT: lpad 0 | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t0, 4(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t1, 0(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t2, 8(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t3, 12(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t4, 20(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t5, 16(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw t1, 0(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw t0, 4(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw t2, 8(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi8: | |
| ; CHECK-LARGE-ZICFILP-NEXT: auipc t0, %pcrel_hi(.LCPI6_0) | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw t3, 12(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi8)(t0) | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw t5, 16(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw t4, 20(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: jr t2 | |
| entry: | |
| %r = tail call i32 @callee_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n) | |
| ret i32 %r | |
| } | |
| ; Do not tail call optimize if parameters need to be passed indirectly. | |
| declare i32 @callee_indirect_args(fp128 %a) | |
| define void @caller_indirect_args() nounwind { | |
| ; CHECK-LABEL: caller_indirect_args: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: addi sp, sp, -32 | |
| ; CHECK-NEXT: sw ra, 28(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: lui a1, 262128 | |
| ; CHECK-NEXT: mv a0, sp | |
| ; CHECK-NEXT: sw zero, 0(sp) | |
| ; CHECK-NEXT: sw zero, 4(sp) | |
| ; CHECK-NEXT: sw zero, 8(sp) | |
| ; CHECK-NEXT: sw a1, 12(sp) | |
| ; CHECK-NEXT: call callee_indirect_args | |
| ; CHECK-NEXT: lw ra, 28(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: addi sp, sp, 32 | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_indirect_args: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, -32 | |
| ; CHECK-CF-RV32-NEXT: sw ra, 28(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: lui a1, 262128 | |
| ; CHECK-CF-RV32-NEXT: mv a0, sp | |
| ; CHECK-CF-RV32-NEXT: sw zero, 0(sp) | |
| ; CHECK-CF-RV32-NEXT: sw zero, 4(sp) | |
| ; CHECK-CF-RV32-NEXT: sw zero, 8(sp) | |
| ; CHECK-CF-RV32-NEXT: sw a1, 12(sp) | |
| ; CHECK-CF-RV32-NEXT: call callee_indirect_args | |
| ; CHECK-CF-RV32-NEXT: lw ra, 28(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, 32 | |
| ; CHECK-CF-RV32-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_indirect_args: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: lui a1, 16383 | |
| ; CHECK-CF-RV64-NEXT: slli a1, a1, 36 | |
| ; CHECK-CF-RV64-NEXT: li a0, 0 | |
| ; CHECK-CF-RV64-NEXT: tail callee_indirect_args, t2 | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_indirect_args: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, -32 | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw ra, 28(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi9: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI7_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi9)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lui a1, 262128 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mv a0, sp | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw zero, 0(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw zero, 4(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw zero, 8(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw a1, 12(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw ra, 28(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, 32 | |
| ; CHECK-CF-RV32-LARGE-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_indirect_args: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi9: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI7_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi9)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: lui a1, 16383 | |
| ; CHECK-CF-RV64-LARGE-NEXT: slli a1, a1, 36 | |
| ; CHECK-CF-RV64-LARGE-NEXT: li a0, 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t2 | |
| ; CHECK-LARGE-ZICFILP-LABEL: caller_indirect_args: | |
| ; CHECK-LARGE-ZICFILP: # %bb.0: # %entry | |
| ; CHECK-LARGE-ZICFILP-NEXT: lpad 0 | |
| ; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, -16 | |
| ; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi9: | |
| ; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI7_0) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi9)(a0) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lui a1, 262128 | |
| ; CHECK-LARGE-ZICFILP-NEXT: mv a0, sp | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw zero, 0(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw zero, 4(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw zero, 8(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw a1, 12(sp) | |
| ; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, 16 | |
| ; CHECK-LARGE-ZICFILP-NEXT: jr t2 | |
| entry: | |
| %call = tail call i32 @callee_indirect_args(fp128 0xL00000000000000003FFF000000000000) | |
| ret void | |
| } | |
| ; Perform tail call optimization for external weak symbol. | |
| declare extern_weak void @callee_weak() | |
| define void @caller_weak() nounwind { | |
| ; CHECK-LABEL: caller_weak: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: tail callee_weak | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_weak: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: tail callee_weak, t2 | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_weak: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: tail callee_weak, t2 | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_weak: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi10: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI8_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi10)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t2 | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_weak: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi10: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI8_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi10)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t2 | |
| entry: | |
| tail call void @callee_weak() | |
| ret void | |
| } | |
| ; Exception-handling functions need a special set of instructions to indicate a | |
| ; return to the hardware. Tail-calling another function would probably break | |
| ; this. | |
| declare void @callee_irq() | |
| define void @caller_irq() nounwind "interrupt"="machine" { | |
| ; CHECK-LABEL: caller_irq: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: addi sp, sp, -64 | |
| ; CHECK-NEXT: sw ra, 60(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw t0, 56(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw t1, 52(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw t2, 48(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw a0, 44(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw a1, 40(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw a2, 36(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw a3, 32(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw a4, 28(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw a5, 24(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw a6, 20(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw a7, 16(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw t3, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw t4, 8(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw t5, 4(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: sw t6, 0(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: call callee_irq | |
| ; CHECK-NEXT: lw ra, 60(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw t0, 56(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw t1, 52(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw t2, 48(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw a0, 44(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw a1, 40(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw a2, 36(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw a3, 32(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw a4, 28(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw a5, 24(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw a6, 20(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw a7, 16(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw t3, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw t4, 8(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw t5, 4(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: lw t6, 0(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: addi sp, sp, 64 | |
| ; CHECK-NEXT: mret | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_irq: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, -64 | |
| ; CHECK-CF-RV32-NEXT: sw ra, 60(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw t0, 56(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw t1, 52(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw t2, 48(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw a0, 44(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw a1, 40(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw a2, 36(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw a3, 32(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw a4, 28(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw a5, 24(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw a6, 20(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw a7, 16(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw t3, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw t4, 8(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw t5, 4(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: sw t6, 0(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: call callee_irq | |
| ; CHECK-CF-RV32-NEXT: lw ra, 60(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw t0, 56(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw t1, 52(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw t2, 48(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw a0, 44(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw a1, 40(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw a2, 36(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw a3, 32(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw a4, 28(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw a5, 24(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw a6, 20(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw a7, 16(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw t3, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw t4, 8(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw t5, 4(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: lw t6, 0(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, 64 | |
| ; CHECK-CF-RV32-NEXT: mret | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_irq: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, -128 | |
| ; CHECK-CF-RV64-NEXT: sd ra, 120(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd t0, 112(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd t1, 104(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd t2, 96(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd a0, 88(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd a1, 80(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd a2, 72(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd a3, 64(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd a4, 56(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd a5, 48(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd a6, 40(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd a7, 32(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd t3, 24(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd t4, 16(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd t5, 8(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: sd t6, 0(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: call callee_irq | |
| ; CHECK-CF-RV64-NEXT: ld ra, 120(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld t0, 112(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld t1, 104(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld t2, 96(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld a0, 88(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld a1, 80(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld a2, 72(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld a3, 64(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld a4, 56(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld a5, 48(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld a6, 40(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld a7, 32(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld t3, 24(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld t4, 16(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld t5, 8(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: ld t6, 0(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, 128 | |
| ; CHECK-CF-RV64-NEXT: mret | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_irq: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, -64 | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw ra, 60(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t0, 56(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t1, 52(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t2, 48(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw a0, 44(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw a1, 40(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw a2, 36(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw a3, 32(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw a4, 28(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw a5, 24(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw a6, 20(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw a7, 16(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t3, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t4, 8(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t5, 4(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw t6, 0(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi11: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI9_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi11)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw ra, 60(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t0, 56(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t1, 52(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, 48(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a0, 44(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a1, 40(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a2, 36(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a3, 32(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a4, 28(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a5, 24(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a6, 20(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a7, 16(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t3, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t4, 8(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t5, 4(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t6, 0(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, 64 | |
| ; CHECK-CF-RV32-LARGE-NEXT: mret | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_irq: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, -128 | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd ra, 120(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t0, 112(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t1, 104(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t2, 96(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd a0, 88(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd a1, 80(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd a2, 72(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd a3, 64(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd a4, 56(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd a5, 48(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd a6, 40(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd a7, 32(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t3, 24(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t4, 16(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t5, 8(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd t6, 0(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi11: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI9_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi11)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld ra, 120(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t0, 112(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t1, 104(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, 96(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a0, 88(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a1, 80(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a2, 72(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a3, 64(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a4, 56(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a5, 48(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a6, 40(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a7, 32(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t3, 24(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t4, 16(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t5, 8(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t6, 0(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, 128 | |
| ; CHECK-CF-RV64-LARGE-NEXT: mret | |
| entry: | |
| tail call void @callee_irq() | |
| ret void | |
| } | |
| ; Byval parameters hand the function a pointer directly into the stack area | |
| ; we want to reuse during a tail call. Do not tail call optimize functions with | |
| ; byval parameters. | |
| declare i32 @callee_byval(ptr byval(ptr) %a) | |
| define i32 @caller_byval() nounwind { | |
| ; CHECK-LABEL: caller_byval: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: addi sp, sp, -16 | |
| ; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: lw a0, 8(sp) | |
| ; CHECK-NEXT: sw a0, 4(sp) | |
| ; CHECK-NEXT: addi a0, sp, 4 | |
| ; CHECK-NEXT: call callee_byval | |
| ; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: addi sp, sp, 16 | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_byval: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: lw a0, 8(sp) | |
| ; CHECK-CF-RV32-NEXT: sw a0, 4(sp) | |
| ; CHECK-CF-RV32-NEXT: addi a0, sp, 4 | |
| ; CHECK-CF-RV32-NEXT: call callee_byval | |
| ; CHECK-CF-RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV32-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_byval: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, -32 | |
| ; CHECK-CF-RV64-NEXT: sd ra, 24(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: ld a0, 16(sp) | |
| ; CHECK-CF-RV64-NEXT: sd a0, 8(sp) | |
| ; CHECK-CF-RV64-NEXT: addi a0, sp, 8 | |
| ; CHECK-CF-RV64-NEXT: call callee_byval | |
| ; CHECK-CF-RV64-NEXT: ld ra, 24(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, 32 | |
| ; CHECK-CF-RV64-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_byval: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a0, 8(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw a0, 4(sp) | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi12: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI10_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi12)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi a0, sp, 4 | |
| ; CHECK-CF-RV32-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV32-LARGE-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_byval: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, -32 | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd ra, 24(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a0, 16(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd a0, 8(sp) | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi12: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI10_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi12)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi a0, sp, 8 | |
| ; CHECK-CF-RV64-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld ra, 24(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, 32 | |
| ; CHECK-CF-RV64-LARGE-NEXT: ret | |
| entry: | |
| %a = alloca ptr | |
| %r = tail call i32 @callee_byval(ptr byval(ptr) %a) | |
| ret i32 %r | |
| } | |
| ; Do not tail call optimize if callee uses structret semantics. | |
| %struct.A = type { i32 } | |
| @a = global %struct.A zeroinitializer | |
| declare void @callee_struct(ptr sret(%struct.A) %a) | |
| define void @caller_nostruct() nounwind { | |
| ; CHECK-LABEL: caller_nostruct: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: addi sp, sp, -16 | |
| ; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: lui a0, %hi(a) | |
| ; CHECK-NEXT: addi a0, a0, %lo(a) | |
| ; CHECK-NEXT: call callee_struct | |
| ; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: addi sp, sp, 16 | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_nostruct: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: lui a0, %hi(a) | |
| ; CHECK-CF-RV32-NEXT: addi a0, a0, %lo(a) | |
| ; CHECK-CF-RV32-NEXT: call callee_struct | |
| ; CHECK-CF-RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV32-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_nostruct: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: lui a0, %hi(a) | |
| ; CHECK-CF-RV64-NEXT: addi a0, a0, %lo(a) | |
| ; CHECK-CF-RV64-NEXT: call callee_struct | |
| ; CHECK-CF-RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV64-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_nostruct: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi13: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI11_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi13)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi14: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a1, %pcrel_hi(.LCPI11_1) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi14)(a1) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV32-LARGE-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_nostruct: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd ra, 8(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi13: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI11_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi13)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi14: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a1, %pcrel_hi(.LCPI11_1) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi14)(a1) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld ra, 8(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV64-LARGE-NEXT: ret | |
| ; CHECK-LARGE-ZICFILP-LABEL: caller_nostruct: | |
| ; CHECK-LARGE-ZICFILP: # %bb.0: # %entry | |
| ; CHECK-LARGE-ZICFILP-NEXT: lpad 0 | |
| ; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, -16 | |
| ; CHECK-LARGE-ZICFILP-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi13: | |
| ; CHECK-LARGE-ZICFILP-NEXT: auipc a0, %pcrel_hi(.LCPI11_0) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi13)(a0) | |
| ; CHECK-LARGE-ZICFILP-NEXT: .Lpcrel_hi14: | |
| ; CHECK-LARGE-ZICFILP-NEXT: auipc a1, %pcrel_hi(.LCPI11_1) | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi14)(a1) | |
| ; CHECK-LARGE-ZICFILP-NEXT: jalr t2 | |
| ; CHECK-LARGE-ZICFILP-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-LARGE-ZICFILP-NEXT: addi sp, sp, 16 | |
| ; CHECK-LARGE-ZICFILP-NEXT: ret | |
| entry: | |
| tail call void @callee_struct(ptr sret(%struct.A) @a) | |
| ret void | |
| } | |
| ; A caller using structret semantics does not prevent tail call optimization. | |
| declare void @callee_nostruct() | |
| define void @caller_struct(ptr sret(%struct.A) %a) nounwind { | |
| ; CHECK-LABEL: caller_struct: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: tail callee_nostruct | |
| ; | |
| ; CHECK-CF-RV32-LABEL: caller_struct: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: tail callee_nostruct, t2 | |
| ; | |
| ; CHECK-CF-RV64-LABEL: caller_struct: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: tail callee_nostruct, t2 | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: caller_struct: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi15: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI12_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi15)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t2 | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: caller_struct: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi15: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI12_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi15)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t2 | |
| entry: | |
| tail call void @callee_nostruct() | |
| ret void | |
| } | |
| ; Do not tail call optimize if disabled. | |
| define i32 @disable_tail_calls(i32 %i) nounwind "disable-tail-calls"="true" { | |
| ; CHECK-LABEL: disable_tail_calls: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: addi sp, sp, -16 | |
| ; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-NEXT: call callee_tail | |
| ; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-NEXT: addi sp, sp, 16 | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV32-LABEL: disable_tail_calls: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-NEXT: call callee_tail | |
| ; CHECK-CF-RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV32-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LABEL: disable_tail_calls: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-NEXT: call callee_tail | |
| ; CHECK-CF-RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV64-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: disable_tail_calls: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV32-LARGE-NEXT: sw ra, 12(sp) # 4-byte Folded Spill | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi16: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a1, %pcrel_hi(.LCPI13_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi16)(a1) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw ra, 12(sp) # 4-byte Folded Reload | |
| ; CHECK-CF-RV32-LARGE-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV32-LARGE-NEXT: ret | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: disable_tail_calls: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, -16 | |
| ; CHECK-CF-RV64-LARGE-NEXT: sd ra, 8(sp) # 8-byte Folded Spill | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi16: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a1, %pcrel_hi(.LCPI13_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi16)(a1) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jalr t2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld ra, 8(sp) # 8-byte Folded Reload | |
| ; CHECK-CF-RV64-LARGE-NEXT: addi sp, sp, 16 | |
| ; CHECK-CF-RV64-LARGE-NEXT: ret | |
| entry: | |
| %rv = tail call i32 @callee_tail(i32 %i) | |
| ret i32 %rv | |
| } | |
| ; Duplicate returns to enable tail call optimizations. | |
| declare i32 @test() | |
| declare i32 @test1() | |
| declare i32 @test2() | |
| declare i32 @test3() | |
| define i32 @duplicate_returns(i32 %a, i32 %b) nounwind { | |
| ; CHECK-LABEL: duplicate_returns: | |
| ; CHECK: # %bb.0: # %entry | |
| ; CHECK-NEXT: beqz a0, .LBB14_4 | |
| ; CHECK-NEXT: # %bb.1: # %if.else | |
| ; CHECK-NEXT: beqz a1, .LBB14_5 | |
| ; CHECK-NEXT: # %bb.2: # %if.else4 | |
| ; CHECK-NEXT: bge a1, a0, .LBB14_6 | |
| ; CHECK-NEXT: # %bb.3: # %if.then6 | |
| ; CHECK-NEXT: tail test2 | |
| ; CHECK-NEXT: .LBB14_4: # %if.then | |
| ; CHECK-NEXT: tail test | |
| ; CHECK-NEXT: .LBB14_5: # %if.then2 | |
| ; CHECK-NEXT: tail test1 | |
| ; CHECK-NEXT: .LBB14_6: # %if.else8 | |
| ; CHECK-NEXT: tail test3 | |
| ; | |
| ; CHECK-CF-RV32-LABEL: duplicate_returns: | |
| ; CHECK-CF-RV32: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-NEXT: beqz a0, .LBB14_4 | |
| ; CHECK-CF-RV32-NEXT: # %bb.1: # %if.else | |
| ; CHECK-CF-RV32-NEXT: beqz a1, .LBB14_5 | |
| ; CHECK-CF-RV32-NEXT: # %bb.2: # %if.else4 | |
| ; CHECK-CF-RV32-NEXT: bge a1, a0, .LBB14_6 | |
| ; CHECK-CF-RV32-NEXT: # %bb.3: # %if.then6 | |
| ; CHECK-CF-RV32-NEXT: tail test2, t2 | |
| ; CHECK-CF-RV32-NEXT: .LBB14_4: # %if.then | |
| ; CHECK-CF-RV32-NEXT: tail test, t2 | |
| ; CHECK-CF-RV32-NEXT: .LBB14_5: # %if.then2 | |
| ; CHECK-CF-RV32-NEXT: tail test1, t2 | |
| ; CHECK-CF-RV32-NEXT: .LBB14_6: # %if.else8 | |
| ; CHECK-CF-RV32-NEXT: tail test3, t2 | |
| ; | |
| ; CHECK-CF-RV64-LABEL: duplicate_returns: | |
| ; CHECK-CF-RV64: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-NEXT: sext.w a0, a0 | |
| ; CHECK-CF-RV64-NEXT: beqz a0, .LBB14_4 | |
| ; CHECK-CF-RV64-NEXT: # %bb.1: # %if.else | |
| ; CHECK-CF-RV64-NEXT: sext.w a1, a1 | |
| ; CHECK-CF-RV64-NEXT: beqz a1, .LBB14_5 | |
| ; CHECK-CF-RV64-NEXT: # %bb.2: # %if.else4 | |
| ; CHECK-CF-RV64-NEXT: bge a1, a0, .LBB14_6 | |
| ; CHECK-CF-RV64-NEXT: # %bb.3: # %if.then6 | |
| ; CHECK-CF-RV64-NEXT: tail test2, t2 | |
| ; CHECK-CF-RV64-NEXT: .LBB14_4: # %if.then | |
| ; CHECK-CF-RV64-NEXT: tail test, t2 | |
| ; CHECK-CF-RV64-NEXT: .LBB14_5: # %if.then2 | |
| ; CHECK-CF-RV64-NEXT: tail test1, t2 | |
| ; CHECK-CF-RV64-NEXT: .LBB14_6: # %if.else8 | |
| ; CHECK-CF-RV64-NEXT: tail test3, t2 | |
| ; | |
| ; CHECK-CF-RV32-LARGE-LABEL: duplicate_returns: | |
| ; CHECK-CF-RV32-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV32-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV32-LARGE-NEXT: beqz a0, .LBB14_4 | |
| ; CHECK-CF-RV32-LARGE-NEXT: # %bb.1: # %if.else | |
| ; CHECK-CF-RV32-LARGE-NEXT: beqz a1, .LBB14_5 | |
| ; CHECK-CF-RV32-LARGE-NEXT: # %bb.2: # %if.else4 | |
| ; CHECK-CF-RV32-LARGE-NEXT: bge a1, a0, .LBB14_6 | |
| ; CHECK-CF-RV32-LARGE-NEXT: # %bb.3: # %if.then6 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi19: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI14_1) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi19)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .LBB14_4: # %if.then | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi17: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI14_3) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi17)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .LBB14_5: # %if.then2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi18: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI14_2) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi18)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t2 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .LBB14_6: # %if.else8 | |
| ; CHECK-CF-RV32-LARGE-NEXT: .Lpcrel_hi20: | |
| ; CHECK-CF-RV32-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI14_0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: lw t2, %pcrel_lo(.Lpcrel_hi20)(a0) | |
| ; CHECK-CF-RV32-LARGE-NEXT: jr t2 | |
| ; | |
| ; CHECK-CF-RV64-LARGE-LABEL: duplicate_returns: | |
| ; CHECK-CF-RV64-LARGE: # %bb.0: # %entry | |
| ; CHECK-CF-RV64-LARGE-NEXT: lpad 0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: sext.w a0, a0 | |
| ; CHECK-CF-RV64-LARGE-NEXT: beqz a0, .LBB14_4 | |
| ; CHECK-CF-RV64-LARGE-NEXT: # %bb.1: # %if.else | |
| ; CHECK-CF-RV64-LARGE-NEXT: sext.w a1, a1 | |
| ; CHECK-CF-RV64-LARGE-NEXT: beqz a1, .LBB14_5 | |
| ; CHECK-CF-RV64-LARGE-NEXT: # %bb.2: # %if.else4 | |
| ; CHECK-CF-RV64-LARGE-NEXT: bge a1, a0, .LBB14_6 | |
| ; CHECK-CF-RV64-LARGE-NEXT: # %bb.3: # %if.then6 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi19: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI14_1) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi19)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .LBB14_4: # %if.then | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi17: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI14_3) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi17)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .LBB14_5: # %if.then2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi18: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI14_2) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi18)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t2 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .LBB14_6: # %if.else8 | |
| ; CHECK-CF-RV64-LARGE-NEXT: .Lpcrel_hi20: | |
| ; CHECK-CF-RV64-LARGE-NEXT: auipc a0, %pcrel_hi(.LCPI14_0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: ld t2, %pcrel_lo(.Lpcrel_hi20)(a0) | |
| ; CHECK-CF-RV64-LARGE-NEXT: jr t2 | |
| entry: | |
| %cmp = icmp eq i32 %a, 0 | |
| br i1 %cmp, label %if.then, label %if.else | |
| if.then: ; preds = %entry | |
| %call = tail call i32 @test() | |
| br label %return | |
| if.else: ; preds = %entry | |
| %cmp1 = icmp eq i32 %b, 0 | |
| br i1 %cmp1, label %if.then2, label %if.else4 | |
| if.then2: ; preds = %if.else | |
| %call3 = tail call i32 @test1() | |
| br label %return | |
| if.else4: ; preds = %if.else | |
| %cmp5 = icmp sgt i32 %a, %b | |
| br i1 %cmp5, label %if.then6, label %if.else8 | |
| if.then6: ; preds = %if.else4 | |
| %call7 = tail call i32 @test2() | |
| br label %return | |
| if.else8: ; preds = %if.else4 | |
| %call9 = tail call i32 @test3() | |
| br label %return | |
| return: ; preds = %if.else8, %if.then6, %if.then2, %if.then | |
| %retval = phi i32 [ %call, %if.then ], [ %call3, %if.then2 ], [ %call7, %if.then6 ], [ %call9, %if.else8 ] | |
| ret i32 %retval | |
| } | |
| !llvm.module.flags = !{!0} | |
| !0 = !{i32 1, !"ProfileSummary", !1} | |
| !1 = !{!2, !3, !4, !5, !6, !7, !8, !9} | |
| !2 = !{!"ProfileFormat", !"InstrProf"} | |
| !3 = !{!"TotalCount", i64 10000} | |
| !4 = !{!"MaxCount", i64 10} | |
| !5 = !{!"MaxInternalCount", i64 1} | |
| !6 = !{!"MaxFunctionCount", i64 1000} | |
| !7 = !{!"NumCounts", i64 3} | |
| !8 = !{!"NumFunctions", i64 3} | |
| !9 = !{!"DetailedSummary", !10} | |
| !10 = !{!11, !12, !13} | |
| !11 = !{i32 10000, i64 100, i32 1} | |
| !12 = !{i32 999000, i64 100, i32 1} | |
| !13 = !{i32 999999, i64 1, i32 2} | |
| !14 = !{!"function_entry_count", i64 0} | |
| ;CF: !15 = !{i32 8, !"cf-protection-branch", i32 1} | |
| ;CF: !16 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"} |