162 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 42; RUN: llc --mtriple aarch64-none-eabi < %s -mattr=-fp-armv8 | FileCheck %s3 4; See also clang/test/CodeGen/aarch64-soft-float-abi.c, which tests the clang5; parts of the soft-float ABI.6 7; FP types up to 64-bit are passed in a general purpose register.8define half @test0(half %a, half %b) {9; CHECK-LABEL: test0:10; CHECK: // %bb.0: // %entry11; CHECK-NEXT: mov w0, w112; CHECK-NEXT: ret13entry:14 ret half %b15}16 17define bfloat @test1(i32 %a, bfloat %b) {18; CHECK-LABEL: test1:19; CHECK: // %bb.0: // %entry20; CHECK-NEXT: mov w0, w121; CHECK-NEXT: ret22entry:23 ret bfloat %b24}25 26define float @test2(i64 %a, float %b) {27; CHECK-LABEL: test2:28; CHECK: // %bb.0: // %entry29; CHECK-NEXT: mov w0, w130; CHECK-NEXT: ret31entry:32 ret float %b33}34 35define double @test3(half %a, double %b) {36; CHECK-LABEL: test3:37; CHECK: // %bb.0: // %entry38; CHECK-NEXT: mov x0, x139; CHECK-NEXT: ret40entry:41 ret double %b42}43 44; fp128 is passed in a pair of GPRs.45define fp128 @test4(fp128 %a, fp128 %b) {46; CHECK-LABEL: test4:47; CHECK: // %bb.0: // %entry48; CHECK-NEXT: mov x1, x349; CHECK-NEXT: mov x0, x250; CHECK-NEXT: ret51entry:52 ret fp128 %b53}54 55; fp128 is passed in an aligned pair of GPRs, leaving one register unused is56; necessary.57define fp128 @test5(float %a, fp128 %b) {58; CHECK-LABEL: test5:59; CHECK: // %bb.0: // %entry60; CHECK-NEXT: mov x1, x361; CHECK-NEXT: mov x0, x262; CHECK-NEXT: ret63entry:64 ret fp128 %b65}66 67; If the alignment of an fp128 leaves a register unused, it remains unused even68; if a later argument could fit in it.69define i64 @test6(i64 %a, fp128 %b, i64 %c) {70; CHECK-LABEL: test6:71; CHECK: // %bb.0: // %entry72; CHECK-NEXT: mov x0, x473; CHECK-NEXT: ret74entry:75 ret i64 %c76}77 78; HFAs are all bit-casted to integer types in the frontend when using the79; soft-float ABI, so they get passed in the same way as non-homeogeneous80; aggregates. The IR is identical to the equivalent integer types, so nothing81; to test here.82 83; The PCS for vector and HVA types is not defined by the soft-float ABI because84; these types are only defined by the ACLE when vector hardware is available,85; so nothing to test here.86 87; The front-end generates IR for va_arg which always reads from the integer88; register save area, and never the floating-point register save area. The89; layout of the va_list type remains the same, the floating-point related90; fields are unused. The only change needed in the backend is in va_start, to91; not attempt to save the floating-point registers or set the FP fields in the92; va_list.93%struct.__va_list = type { ptr, ptr, ptr, i32, i32 }94declare void @llvm.va_start(ptr)95define double @test20(i32 %a, ...) {96; CHECK-LABEL: test20:97; CHECK: // %bb.0: // %entry98; CHECK-NEXT: sub sp, sp, #9699; CHECK-NEXT: .cfi_def_cfa_offset 96100; CHECK-NEXT: mov w8, #-56 // =0xffffffc8101; CHECK-NEXT: add x10, sp, #8102; CHECK-NEXT: add x9, sp, #96103; CHECK-NEXT: str x8, [sp, #88]104; CHECK-NEXT: add x10, x10, #56105; CHECK-NEXT: ldrsw x8, [sp, #88]106; CHECK-NEXT: stp x1, x2, [sp, #8]107; CHECK-NEXT: stp x3, x4, [sp, #24]108; CHECK-NEXT: stp x5, x6, [sp, #40]109; CHECK-NEXT: stp x7, x9, [sp, #56]110; CHECK-NEXT: str x10, [sp, #72]111; CHECK-NEXT: tbz w8, #31, .LBB7_3112; CHECK-NEXT: // %bb.1: // %vaarg.maybe_reg113; CHECK-NEXT: add w9, w8, #8114; CHECK-NEXT: cmn w8, #8115; CHECK-NEXT: str w9, [sp, #88]116; CHECK-NEXT: b.gt .LBB7_3117; CHECK-NEXT: // %bb.2: // %vaarg.in_reg118; CHECK-NEXT: ldr x9, [sp, #72]119; CHECK-NEXT: add x8, x9, x8120; CHECK-NEXT: b .LBB7_4121; CHECK-NEXT: .LBB7_3: // %vaarg.on_stack122; CHECK-NEXT: ldr x8, [sp, #64]123; CHECK-NEXT: add x9, x8, #8124; CHECK-NEXT: str x9, [sp, #64]125; CHECK-NEXT: .LBB7_4: // %vaarg.end126; CHECK-NEXT: ldr x0, [x8]127; CHECK-NEXT: add sp, sp, #96128; CHECK-NEXT: ret129entry:130 %vl = alloca %struct.__va_list, align 8131 call void @llvm.va_start(ptr nonnull %vl)132 %gr_offs_p = getelementptr inbounds %struct.__va_list, ptr %vl, i64 0, i32 3133 %gr_offs = load i32, ptr %gr_offs_p, align 8134 %0 = icmp sgt i32 %gr_offs, -1135 br i1 %0, label %vaarg.on_stack, label %vaarg.maybe_reg136 137vaarg.maybe_reg: ; preds = %entry138 %new_reg_offs = add nsw i32 %gr_offs, 8139 store i32 %new_reg_offs, ptr %gr_offs_p, align 8140 %inreg = icmp slt i32 %gr_offs, -7141 br i1 %inreg, label %vaarg.in_reg, label %vaarg.on_stack142 143vaarg.in_reg: ; preds = %vaarg.maybe_reg144 %reg_top_p = getelementptr inbounds %struct.__va_list, ptr %vl, i64 0, i32 1145 %reg_top = load ptr, ptr %reg_top_p, align 8146 %1 = sext i32 %gr_offs to i64147 %2 = getelementptr inbounds i8, ptr %reg_top, i64 %1148 br label %vaarg.end149 150vaarg.on_stack: ; preds = %vaarg.maybe_reg, %entry151 %stack = load ptr, ptr %vl, align 8152 %new_stack = getelementptr inbounds i8, ptr %stack, i64 8153 store ptr %new_stack, ptr %vl, align 8154 br label %vaarg.end155 156vaarg.end: ; preds = %vaarg.on_stack, %vaarg.in_reg157 %vaargs.addr = phi ptr [ %2, %vaarg.in_reg ], [ %stack, %vaarg.on_stack ]158 %3 = load double, ptr %vaargs.addr, align 8159 ret double %3160}161 162