diff --git a/llvm/lib/Target/ARM/ARMCallingConv.cpp b/llvm/lib/Target/ARM/ARMCallingConv.cpp index 66a76a8c7a95a..a206e993394f7 100644 --- a/llvm/lib/Target/ARM/ARMCallingConv.cpp +++ b/llvm/lib/Target/ARM/ARMCallingConv.cpp @@ -298,7 +298,8 @@ static bool CustomAssignInRegList(unsigned ValNo, MVT ValVT, MVT LocVT, static bool CC_ARM_AAPCS_Custom_f16(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State) { - // f16 arguments are extended to i32 and assigned to a register in [r0, r3] + // f16 and bf16 arguments are extended to i32 and assigned to a register in + // [r0, r3]. return CustomAssignInRegList(ValNo, ValVT, MVT::i32, LocInfo, State, RRegList); } @@ -307,10 +308,25 @@ static bool CC_ARM_AAPCS_VFP_Custom_f16(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State) { - // f16 arguments are extended to f32 and assigned to a register in [s0, s15] + // f16 and bf16 arguments are extended to f32 and assigned to a register in + // [s0, s15]. return CustomAssignInRegList(ValNo, ValVT, MVT::f32, LocInfo, State, SRegList); } +static bool CC_ARM_AAPCS_Common_Custom_f16_Stack(unsigned ValNo, MVT ValVT, + MVT LocVT, + CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, + CCState &State) { + // f16 and bf16 (if not passed in a register) are assigned to a 32-bit stack + // slot, with the most-significant 16 bits unspecified. The 32-bit slot is + // important to make sure that the byte ordering is correct for big endian + // targets. + State.addLoc(CCValAssign::getCustomMem( + ValNo, ValVT, State.AllocateStack(4, Align(4)), MVT::i32, LocInfo)); + return true; +} + // Include the table generated calling convention implementations. #include "ARMGenCallingConv.inc" diff --git a/llvm/lib/Target/ARM/ARMCallingConv.td b/llvm/lib/Target/ARM/ARMCallingConv.td index 27f175a700336..f1ab1c3103740 100644 --- a/llvm/lib/Target/ARM/ARMCallingConv.td +++ b/llvm/lib/Target/ARM/ARMCallingConv.td @@ -139,7 +139,8 @@ def CC_ARM_AAPCS_Common : CallingConv<[ CCIfType<[i32], CCIfAlign<"8", CCAssignToStackWithShadow<4, 8, [R0, R1, R2, R3]>>>, CCIfType<[i32], CCAssignToStackWithShadow<4, 4, [R0, R1, R2, R3]>>, - CCIfType<[f16, bf16, f32], CCAssignToStackWithShadow<4, 4, [Q0, Q1, Q2, Q3]>>, + CCIfType<[f32], CCAssignToStackWithShadow<4, 4, [Q0, Q1, Q2, Q3]>>, + CCIfType<[f16, bf16], CCCustom<"CC_ARM_AAPCS_Common_Custom_f16_Stack">>, CCIfType<[f64], CCAssignToStackWithShadow<8, 8, [Q0, Q1, Q2, Q3]>>, CCIfType<[v2f64], CCIfAlign<"16", CCAssignToStackWithShadow<16, 16, [Q0, Q1, Q2, Q3]>>>, diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index bd8d6079e1ba8..160461bb82c36 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -4759,6 +4759,25 @@ SDValue ARMTargetLowering::LowerFormalArguments( VA.getLocMemOffset(), Flags.getByValSize()); InVals.push_back(DAG.getFrameIndex(FrameIndex, PtrVT)); CCInfo.nextInRegsParam(); + } else if (VA.needsCustom() && (VA.getValVT() == MVT::f16 || + VA.getValVT() == MVT::bf16)) { + // f16 and bf16 values are passed in the least-significant half of + // a 4 byte stack slot. This is done as-if the extension was done + // in a 32-bit register, so the actual bytes used for the value + // differ between little and big endian. + assert(VA.getLocVT().getSizeInBits() == 32); + unsigned FIOffset = VA.getLocMemOffset(); + int FI = MFI.CreateFixedObject(VA.getLocVT().getSizeInBits() / 8, + FIOffset, true); + + SDValue Addr = DAG.getFrameIndex(FI, PtrVT); + if (DAG.getDataLayout().isBigEndian()) + Addr = DAG.getObjectPtrOffset(dl, Addr, TypeSize::getFixed(2)); + + InVals.push_back(DAG.getLoad(VA.getValVT(), dl, Chain, Addr, + MachinePointerInfo::getFixedStack( + DAG.getMachineFunction(), FI))); + } else { unsigned FIOffset = VA.getLocMemOffset(); int FI = MFI.CreateFixedObject(VA.getLocVT().getSizeInBits()/8, diff --git a/llvm/test/CodeGen/Thumb2/bf16-pcs.ll b/llvm/test/CodeGen/Thumb2/bf16-pcs.ll new file mode 100644 index 0000000000000..2ffe420a20520 --- /dev/null +++ b/llvm/test/CodeGen/Thumb2/bf16-pcs.ll @@ -0,0 +1,388 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=armv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16 | FileCheck %s --check-prefix=LE +; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16 | FileCheck %s --check-prefix=BE +; RUN: llc -mtriple=armv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16,+bf16 | FileCheck %s --check-prefix=LE-BF16 +; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16,+bf16 | FileCheck %s --check-prefix=BE-BF16 + +;; Global ISel successfully generates code for some functions for little-endian +;; without +bf16, and falls back to SelectionDAG in all others. +; RUN: llc -mtriple=armv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=LE-GISEL +; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=BE +; RUN: llc -mtriple=armv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16,+bf16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=LE-BF16 +; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16,+bf16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=BE-BF16 + +define arm_aapcscc bfloat @callee_soft_bfloat_in_reg(bfloat %f) { +; LE-LABEL: callee_soft_bfloat_in_reg: +; LE: @ %bb.0: @ %entry +; LE-NEXT: bx lr +; +; BE-LABEL: callee_soft_bfloat_in_reg: +; BE: @ %bb.0: @ %entry +; BE-NEXT: bx lr +; +; LE-BF16-LABEL: callee_soft_bfloat_in_reg: +; LE-BF16: @ %bb.0: @ %entry +; LE-BF16-NEXT: .pad #4 +; LE-BF16-NEXT: sub sp, #4 +; LE-BF16-NEXT: strh.w r0, [sp, #2] +; LE-BF16-NEXT: ldrh.w r0, [sp, #2] +; LE-BF16-NEXT: add sp, #4 +; LE-BF16-NEXT: bx lr +; +; BE-BF16-LABEL: callee_soft_bfloat_in_reg: +; BE-BF16: @ %bb.0: @ %entry +; BE-BF16-NEXT: .pad #4 +; BE-BF16-NEXT: sub sp, #4 +; BE-BF16-NEXT: strh.w r0, [sp, #2] +; BE-BF16-NEXT: ldrh.w r0, [sp, #2] +; BE-BF16-NEXT: add sp, #4 +; BE-BF16-NEXT: bx lr +; +; LE-GISEL-LABEL: callee_soft_bfloat_in_reg: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: bx lr +entry: + ret bfloat %f +} + +define void @caller_soft_bfloat_in_reg() { +; LE-LABEL: caller_soft_bfloat_in_reg: +; LE: @ %bb.0: @ %entry +; LE-NEXT: .save {r7, lr} +; LE-NEXT: push {r7, lr} +; LE-NEXT: mov.w r0, #16256 +; LE-NEXT: bl callee_soft_bfloat_in_reg +; LE-NEXT: pop {r7, pc} +; +; BE-LABEL: caller_soft_bfloat_in_reg: +; BE: @ %bb.0: @ %entry +; BE-NEXT: .save {r7, lr} +; BE-NEXT: push {r7, lr} +; BE-NEXT: mov.w r0, #16256 +; BE-NEXT: bl callee_soft_bfloat_in_reg +; BE-NEXT: pop {r7, pc} +; +; LE-BF16-LABEL: caller_soft_bfloat_in_reg: +; LE-BF16: @ %bb.0: @ %entry +; LE-BF16-NEXT: .save {r7, lr} +; LE-BF16-NEXT: push {r7, lr} +; LE-BF16-NEXT: mov.w r0, #16256 +; LE-BF16-NEXT: bl callee_soft_bfloat_in_reg +; LE-BF16-NEXT: pop {r7, pc} +; +; BE-BF16-LABEL: caller_soft_bfloat_in_reg: +; BE-BF16: @ %bb.0: @ %entry +; BE-BF16-NEXT: .save {r7, lr} +; BE-BF16-NEXT: push {r7, lr} +; BE-BF16-NEXT: mov.w r0, #16256 +; BE-BF16-NEXT: bl callee_soft_bfloat_in_reg +; BE-BF16-NEXT: pop {r7, pc} +; +; LE-GISEL-LABEL: caller_soft_bfloat_in_reg: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: .save {r7, lr} +; LE-GISEL-NEXT: push {r7, lr} +; LE-GISEL-NEXT: mov.w r0, #16256 +; LE-GISEL-NEXT: bl callee_soft_bfloat_in_reg +; LE-GISEL-NEXT: pop {r7, pc} +entry: + %ret = call arm_aapcscc bfloat @callee_soft_bfloat_in_reg(bfloat 1.0) + ret void +} + +define arm_aapcscc bfloat @callee_soft_bfloat_on_stack(float %r0, float %r1, float %r2, float %r3, bfloat %f) { +; LE-LABEL: callee_soft_bfloat_on_stack: +; LE: @ %bb.0: @ %entry +; LE-NEXT: ldr r0, [sp] +; LE-NEXT: bx lr +; +; BE-LABEL: callee_soft_bfloat_on_stack: +; BE: @ %bb.0: @ %entry +; BE-NEXT: ldr r0, [sp] +; BE-NEXT: bx lr +; +; LE-BF16-LABEL: callee_soft_bfloat_on_stack: +; LE-BF16: @ %bb.0: @ %entry +; LE-BF16-NEXT: ldrh.w r0, [sp] +; LE-BF16-NEXT: bx lr +; +; BE-BF16-LABEL: callee_soft_bfloat_on_stack: +; BE-BF16: @ %bb.0: @ %entry +; BE-BF16-NEXT: ldrh.w r0, [sp, #2] +; BE-BF16-NEXT: bx lr +; +; LE-GISEL-LABEL: callee_soft_bfloat_on_stack: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: mov r0, sp +; LE-GISEL-NEXT: ldr r0, [r0] +; LE-GISEL-NEXT: bx lr +entry: + ret bfloat %f +} + +define void @caller_soft_bfloat_on_stack() { +; LE-LABEL: caller_soft_bfloat_on_stack: +; LE: @ %bb.0: @ %entry +; LE-NEXT: .save {r7, lr} +; LE-NEXT: push {r7, lr} +; LE-NEXT: .pad #8 +; LE-NEXT: sub sp, #8 +; LE-NEXT: mov.w r0, #16256 +; LE-NEXT: str r0, [sp] +; LE-NEXT: bl callee_soft_bfloat_on_stack +; LE-NEXT: add sp, #8 +; LE-NEXT: pop {r7, pc} +; +; BE-LABEL: caller_soft_bfloat_on_stack: +; BE: @ %bb.0: @ %entry +; BE-NEXT: .save {r7, lr} +; BE-NEXT: push {r7, lr} +; BE-NEXT: .pad #8 +; BE-NEXT: sub sp, #8 +; BE-NEXT: mov.w r0, #16256 +; BE-NEXT: str r0, [sp] +; BE-NEXT: bl callee_soft_bfloat_on_stack +; BE-NEXT: add sp, #8 +; BE-NEXT: pop {r7, pc} +; +; LE-BF16-LABEL: caller_soft_bfloat_on_stack: +; LE-BF16: @ %bb.0: @ %entry +; LE-BF16-NEXT: .save {r7, lr} +; LE-BF16-NEXT: push {r7, lr} +; LE-BF16-NEXT: .pad #8 +; LE-BF16-NEXT: sub sp, #8 +; LE-BF16-NEXT: mov.w r0, #16256 +; LE-BF16-NEXT: str r0, [sp] +; LE-BF16-NEXT: bl callee_soft_bfloat_on_stack +; LE-BF16-NEXT: add sp, #8 +; LE-BF16-NEXT: pop {r7, pc} +; +; BE-BF16-LABEL: caller_soft_bfloat_on_stack: +; BE-BF16: @ %bb.0: @ %entry +; BE-BF16-NEXT: .save {r7, lr} +; BE-BF16-NEXT: push {r7, lr} +; BE-BF16-NEXT: .pad #8 +; BE-BF16-NEXT: sub sp, #8 +; BE-BF16-NEXT: mov.w r0, #16256 +; BE-BF16-NEXT: str r0, [sp] +; BE-BF16-NEXT: bl callee_soft_bfloat_on_stack +; BE-BF16-NEXT: add sp, #8 +; BE-BF16-NEXT: pop {r7, pc} +; +; LE-GISEL-LABEL: caller_soft_bfloat_on_stack: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: .save {r7, lr} +; LE-GISEL-NEXT: push {r7, lr} +; LE-GISEL-NEXT: .pad #8 +; LE-GISEL-NEXT: sub sp, #8 +; LE-GISEL-NEXT: mov.w r0, #16256 +; LE-GISEL-NEXT: str r0, [sp] +; LE-GISEL-NEXT: bl callee_soft_bfloat_on_stack +; LE-GISEL-NEXT: add sp, #8 +; LE-GISEL-NEXT: pop {r7, pc} +entry: + %ret = call arm_aapcscc bfloat @callee_soft_bfloat_on_stack(float poison, float poison, float poison, float poison, bfloat 1.0) + ret void +} + +define arm_aapcs_vfpcc bfloat @callee_hard_bfloat_in_reg(bfloat %f) { +; LE-LABEL: callee_hard_bfloat_in_reg: +; LE: @ %bb.0: @ %entry +; LE-NEXT: bx lr +; +; BE-LABEL: callee_hard_bfloat_in_reg: +; BE: @ %bb.0: @ %entry +; BE-NEXT: bx lr +; +; LE-BF16-LABEL: callee_hard_bfloat_in_reg: +; LE-BF16: @ %bb.0: @ %entry +; LE-BF16-NEXT: .pad #4 +; LE-BF16-NEXT: sub sp, #4 +; LE-BF16-NEXT: vmov r0, s0 +; LE-BF16-NEXT: strh.w r0, [sp, #2] +; LE-BF16-NEXT: ldrh.w r0, [sp, #2] +; LE-BF16-NEXT: vmov s0, r0 +; LE-BF16-NEXT: add sp, #4 +; LE-BF16-NEXT: bx lr +; +; BE-BF16-LABEL: callee_hard_bfloat_in_reg: +; BE-BF16: @ %bb.0: @ %entry +; BE-BF16-NEXT: .pad #4 +; BE-BF16-NEXT: sub sp, #4 +; BE-BF16-NEXT: vmov r0, s0 +; BE-BF16-NEXT: strh.w r0, [sp, #2] +; BE-BF16-NEXT: ldrh.w r0, [sp, #2] +; BE-BF16-NEXT: vmov s0, r0 +; BE-BF16-NEXT: add sp, #4 +; BE-BF16-NEXT: bx lr +; +; LE-GISEL-LABEL: callee_hard_bfloat_in_reg: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: bx lr +entry: + ret bfloat %f +} + +define void @caller_hard_bfloat_in_reg() { +; LE-LABEL: caller_hard_bfloat_in_reg: +; LE: @ %bb.0: @ %entry +; LE-NEXT: .save {r7, lr} +; LE-NEXT: push {r7, lr} +; LE-NEXT: vldr s0, .LCPI5_0 +; LE-NEXT: bl callee_hard_bfloat_in_reg +; LE-NEXT: pop {r7, pc} +; LE-NEXT: .p2align 2 +; LE-NEXT: @ %bb.1: +; LE-NEXT: .LCPI5_0: +; LE-NEXT: .long 0x00003f80 @ float 2.27795078E-41 +; +; BE-LABEL: caller_hard_bfloat_in_reg: +; BE: @ %bb.0: @ %entry +; BE-NEXT: .save {r7, lr} +; BE-NEXT: push {r7, lr} +; BE-NEXT: vldr s0, .LCPI5_0 +; BE-NEXT: bl callee_hard_bfloat_in_reg +; BE-NEXT: pop {r7, pc} +; BE-NEXT: .p2align 2 +; BE-NEXT: @ %bb.1: +; BE-NEXT: .LCPI5_0: +; BE-NEXT: .long 0x00003f80 @ float 2.27795078E-41 +; +; LE-BF16-LABEL: caller_hard_bfloat_in_reg: +; LE-BF16: @ %bb.0: @ %entry +; LE-BF16-NEXT: .save {r7, lr} +; LE-BF16-NEXT: push {r7, lr} +; LE-BF16-NEXT: vldr s0, .LCPI5_0 +; LE-BF16-NEXT: bl callee_hard_bfloat_in_reg +; LE-BF16-NEXT: pop {r7, pc} +; LE-BF16-NEXT: .p2align 2 +; LE-BF16-NEXT: @ %bb.1: +; LE-BF16-NEXT: .LCPI5_0: +; LE-BF16-NEXT: .long 0x00003f80 @ float 2.27795078E-41 +; +; BE-BF16-LABEL: caller_hard_bfloat_in_reg: +; BE-BF16: @ %bb.0: @ %entry +; BE-BF16-NEXT: .save {r7, lr} +; BE-BF16-NEXT: push {r7, lr} +; BE-BF16-NEXT: vldr s0, .LCPI5_0 +; BE-BF16-NEXT: bl callee_hard_bfloat_in_reg +; BE-BF16-NEXT: pop {r7, pc} +; BE-BF16-NEXT: .p2align 2 +; BE-BF16-NEXT: @ %bb.1: +; BE-BF16-NEXT: .LCPI5_0: +; BE-BF16-NEXT: .long 0x00003f80 @ float 2.27795078E-41 +; +; LE-GISEL-LABEL: caller_hard_bfloat_in_reg: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: .save {r7, lr} +; LE-GISEL-NEXT: push {r7, lr} +; LE-GISEL-NEXT: vldr s0, .LCPI5_0 +; LE-GISEL-NEXT: bl callee_hard_bfloat_in_reg +; LE-GISEL-NEXT: pop {r7, pc} +; LE-GISEL-NEXT: .p2align 2 +; LE-GISEL-NEXT: @ %bb.1: +; LE-GISEL-NEXT: .LCPI5_0: +; LE-GISEL-NEXT: .long 0x00003f80 @ float 2.27795078E-41 +entry: + %ret = call arm_aapcs_vfpcc bfloat @callee_hard_bfloat_in_reg(bfloat 1.0) + ret void +} + +define arm_aapcs_vfpcc bfloat @callee_hard_bfloat_on_stack(float %s0, float %s1, float %s2, float %s3, float %s4, float %s5, float %s6, float %s7,float %s8, float %s9, float %s10, float %s11, float %s12, float %s13, float %s14, float %s15, bfloat %f) { +; LE-LABEL: callee_hard_bfloat_on_stack: +; LE: @ %bb.0: @ %entry +; LE-NEXT: vldr s0, [sp] +; LE-NEXT: bx lr +; +; BE-LABEL: callee_hard_bfloat_on_stack: +; BE: @ %bb.0: @ %entry +; BE-NEXT: vldr s0, [sp] +; BE-NEXT: bx lr +; +; LE-BF16-LABEL: callee_hard_bfloat_on_stack: +; LE-BF16: @ %bb.0: @ %entry +; LE-BF16-NEXT: ldrh.w r0, [sp] +; LE-BF16-NEXT: vmov s0, r0 +; LE-BF16-NEXT: bx lr +; +; BE-BF16-LABEL: callee_hard_bfloat_on_stack: +; BE-BF16: @ %bb.0: @ %entry +; BE-BF16-NEXT: ldrh.w r0, [sp, #2] +; BE-BF16-NEXT: vmov s0, r0 +; BE-BF16-NEXT: bx lr +; +; LE-GISEL-LABEL: callee_hard_bfloat_on_stack: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: mov r0, sp +; LE-GISEL-NEXT: ldr r0, [r0] +; LE-GISEL-NEXT: vmov s0, r0 +; LE-GISEL-NEXT: bx lr +entry: + ret bfloat %f +} + + +define void @caller_hard_bfloat_on_stack() { +; LE-LABEL: caller_hard_bfloat_on_stack: +; LE: @ %bb.0: @ %entry +; LE-NEXT: .save {r7, lr} +; LE-NEXT: push {r7, lr} +; LE-NEXT: .pad #8 +; LE-NEXT: sub sp, #8 +; LE-NEXT: mov.w r0, #16256 +; LE-NEXT: str r0, [sp] +; LE-NEXT: bl callee_hard_bfloat_on_stack +; LE-NEXT: add sp, #8 +; LE-NEXT: pop {r7, pc} +; +; BE-LABEL: caller_hard_bfloat_on_stack: +; BE: @ %bb.0: @ %entry +; BE-NEXT: .save {r7, lr} +; BE-NEXT: push {r7, lr} +; BE-NEXT: .pad #8 +; BE-NEXT: sub sp, #8 +; BE-NEXT: mov.w r0, #16256 +; BE-NEXT: str r0, [sp] +; BE-NEXT: bl callee_hard_bfloat_on_stack +; BE-NEXT: add sp, #8 +; BE-NEXT: pop {r7, pc} +; +; LE-BF16-LABEL: caller_hard_bfloat_on_stack: +; LE-BF16: @ %bb.0: @ %entry +; LE-BF16-NEXT: .save {r7, lr} +; LE-BF16-NEXT: push {r7, lr} +; LE-BF16-NEXT: .pad #8 +; LE-BF16-NEXT: sub sp, #8 +; LE-BF16-NEXT: mov.w r0, #16256 +; LE-BF16-NEXT: str r0, [sp] +; LE-BF16-NEXT: bl callee_hard_bfloat_on_stack +; LE-BF16-NEXT: add sp, #8 +; LE-BF16-NEXT: pop {r7, pc} +; +; BE-BF16-LABEL: caller_hard_bfloat_on_stack: +; BE-BF16: @ %bb.0: @ %entry +; BE-BF16-NEXT: .save {r7, lr} +; BE-BF16-NEXT: push {r7, lr} +; BE-BF16-NEXT: .pad #8 +; BE-BF16-NEXT: sub sp, #8 +; BE-BF16-NEXT: mov.w r0, #16256 +; BE-BF16-NEXT: str r0, [sp] +; BE-BF16-NEXT: bl callee_hard_bfloat_on_stack +; BE-BF16-NEXT: add sp, #8 +; BE-BF16-NEXT: pop {r7, pc} +; +; LE-GISEL-LABEL: caller_hard_bfloat_on_stack: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: .save {r7, lr} +; LE-GISEL-NEXT: push {r7, lr} +; LE-GISEL-NEXT: .pad #8 +; LE-GISEL-NEXT: sub sp, #8 +; LE-GISEL-NEXT: mov.w r0, #16256 +; LE-GISEL-NEXT: str r0, [sp] +; LE-GISEL-NEXT: bl callee_hard_bfloat_on_stack +; LE-GISEL-NEXT: add sp, #8 +; LE-GISEL-NEXT: pop {r7, pc} +entry: + %ret = call arm_aapcs_vfpcc bfloat @callee_hard_bfloat_on_stack(float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, bfloat 1.0) + ret void +} diff --git a/llvm/test/CodeGen/Thumb2/fp16-pcs.ll b/llvm/test/CodeGen/Thumb2/fp16-pcs.ll new file mode 100644 index 0000000000000..c0239a009f476 --- /dev/null +++ b/llvm/test/CodeGen/Thumb2/fp16-pcs.ll @@ -0,0 +1,360 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=armv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16 | FileCheck %s --check-prefix=LE +; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16 | FileCheck %s --check-prefix=BE +; RUN: llc -mtriple=armv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16,+fullfp16 | FileCheck %s --check-prefix=LE-FP16 +; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16,+fullfp16 | FileCheck %s --check-prefix=BE-FP16 + +;; Global ISel successfully generates code for some functions for little-endian +;; without +fullfp16, and falls back to SelectionDAG in all others. +; RUN: llc -mtriple=armv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=LE-GISEL +; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=BE +; RUN: llc -mtriple=armv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16,+fullfp16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=LE-FP16 +; RUN: llc -mtriple=armebv8m.main-none-eabi < %s -frame-pointer=none -mattr=+fp-armv8d16,+fullfp16 -global-isel=1 -global-isel-abort=2 | FileCheck %s --check-prefix=BE-FP16 + +define arm_aapcscc half @callee_soft_half_in_reg(half %f) { +; LE-LABEL: callee_soft_half_in_reg: +; LE: @ %bb.0: @ %entry +; LE-NEXT: bx lr +; +; BE-LABEL: callee_soft_half_in_reg: +; BE: @ %bb.0: @ %entry +; BE-NEXT: bx lr +; +; LE-FP16-LABEL: callee_soft_half_in_reg: +; LE-FP16: @ %bb.0: @ %entry +; LE-FP16-NEXT: vmov.f16 s0, r0 +; LE-FP16-NEXT: vmov r0, s0 +; LE-FP16-NEXT: bx lr +; +; BE-FP16-LABEL: callee_soft_half_in_reg: +; BE-FP16: @ %bb.0: @ %entry +; BE-FP16-NEXT: vmov.f16 s0, r0 +; BE-FP16-NEXT: vmov r0, s0 +; BE-FP16-NEXT: bx lr +; +; LE-GISEL-LABEL: callee_soft_half_in_reg: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: bx lr +entry: + ret half %f +} + +define void @caller_soft_half_in_reg() { +; LE-LABEL: caller_soft_half_in_reg: +; LE: @ %bb.0: @ %entry +; LE-NEXT: .save {r7, lr} +; LE-NEXT: push {r7, lr} +; LE-NEXT: mov.w r0, #15360 +; LE-NEXT: bl callee_soft_half_in_reg +; LE-NEXT: pop {r7, pc} +; +; BE-LABEL: caller_soft_half_in_reg: +; BE: @ %bb.0: @ %entry +; BE-NEXT: .save {r7, lr} +; BE-NEXT: push {r7, lr} +; BE-NEXT: mov.w r0, #15360 +; BE-NEXT: bl callee_soft_half_in_reg +; BE-NEXT: pop {r7, pc} +; +; LE-FP16-LABEL: caller_soft_half_in_reg: +; LE-FP16: @ %bb.0: @ %entry +; LE-FP16-NEXT: .save {r7, lr} +; LE-FP16-NEXT: push {r7, lr} +; LE-FP16-NEXT: mov.w r0, #15360 +; LE-FP16-NEXT: bl callee_soft_half_in_reg +; LE-FP16-NEXT: pop {r7, pc} +; +; BE-FP16-LABEL: caller_soft_half_in_reg: +; BE-FP16: @ %bb.0: @ %entry +; BE-FP16-NEXT: .save {r7, lr} +; BE-FP16-NEXT: push {r7, lr} +; BE-FP16-NEXT: mov.w r0, #15360 +; BE-FP16-NEXT: bl callee_soft_half_in_reg +; BE-FP16-NEXT: pop {r7, pc} +; +; LE-GISEL-LABEL: caller_soft_half_in_reg: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: .save {r7, lr} +; LE-GISEL-NEXT: push {r7, lr} +; LE-GISEL-NEXT: mov.w r0, #15360 +; LE-GISEL-NEXT: bl callee_soft_half_in_reg +; LE-GISEL-NEXT: pop {r7, pc} +entry: + %ret = call arm_aapcscc half @callee_soft_half_in_reg(half 1.0) + ret void +} + +define arm_aapcscc half @callee_soft_half_on_stack(float %r0, float %r1, float %r2, float %r3, half %f) { +; LE-LABEL: callee_soft_half_on_stack: +; LE: @ %bb.0: @ %entry +; LE-NEXT: ldr r0, [sp] +; LE-NEXT: bx lr +; +; BE-LABEL: callee_soft_half_on_stack: +; BE: @ %bb.0: @ %entry +; BE-NEXT: ldr r0, [sp] +; BE-NEXT: bx lr +; +; LE-FP16-LABEL: callee_soft_half_on_stack: +; LE-FP16: @ %bb.0: @ %entry +; LE-FP16-NEXT: vldr.16 s0, [sp] +; LE-FP16-NEXT: vmov r0, s0 +; LE-FP16-NEXT: bx lr +; +; BE-FP16-LABEL: callee_soft_half_on_stack: +; BE-FP16: @ %bb.0: @ %entry +; BE-FP16-NEXT: vldr.16 s0, [sp, #2] +; BE-FP16-NEXT: vmov r0, s0 +; BE-FP16-NEXT: bx lr +; +; LE-GISEL-LABEL: callee_soft_half_on_stack: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: mov r0, sp +; LE-GISEL-NEXT: ldr r0, [r0] +; LE-GISEL-NEXT: bx lr +entry: + ret half %f +} + +define void @caller_soft_half_on_stack() { +; LE-LABEL: caller_soft_half_on_stack: +; LE: @ %bb.0: @ %entry +; LE-NEXT: .save {r7, lr} +; LE-NEXT: push {r7, lr} +; LE-NEXT: .pad #8 +; LE-NEXT: sub sp, #8 +; LE-NEXT: mov.w r0, #15360 +; LE-NEXT: str r0, [sp] +; LE-NEXT: bl callee_soft_half_on_stack +; LE-NEXT: add sp, #8 +; LE-NEXT: pop {r7, pc} +; +; BE-LABEL: caller_soft_half_on_stack: +; BE: @ %bb.0: @ %entry +; BE-NEXT: .save {r7, lr} +; BE-NEXT: push {r7, lr} +; BE-NEXT: .pad #8 +; BE-NEXT: sub sp, #8 +; BE-NEXT: mov.w r0, #15360 +; BE-NEXT: str r0, [sp] +; BE-NEXT: bl callee_soft_half_on_stack +; BE-NEXT: add sp, #8 +; BE-NEXT: pop {r7, pc} +; +; LE-FP16-LABEL: caller_soft_half_on_stack: +; LE-FP16: @ %bb.0: @ %entry +; LE-FP16-NEXT: .save {r7, lr} +; LE-FP16-NEXT: push {r7, lr} +; LE-FP16-NEXT: .pad #8 +; LE-FP16-NEXT: sub sp, #8 +; LE-FP16-NEXT: mov.w r0, #15360 +; LE-FP16-NEXT: str r0, [sp] +; LE-FP16-NEXT: bl callee_soft_half_on_stack +; LE-FP16-NEXT: add sp, #8 +; LE-FP16-NEXT: pop {r7, pc} +; +; BE-FP16-LABEL: caller_soft_half_on_stack: +; BE-FP16: @ %bb.0: @ %entry +; BE-FP16-NEXT: .save {r7, lr} +; BE-FP16-NEXT: push {r7, lr} +; BE-FP16-NEXT: .pad #8 +; BE-FP16-NEXT: sub sp, #8 +; BE-FP16-NEXT: mov.w r0, #15360 +; BE-FP16-NEXT: str r0, [sp] +; BE-FP16-NEXT: bl callee_soft_half_on_stack +; BE-FP16-NEXT: add sp, #8 +; BE-FP16-NEXT: pop {r7, pc} +; +; LE-GISEL-LABEL: caller_soft_half_on_stack: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: .save {r7, lr} +; LE-GISEL-NEXT: push {r7, lr} +; LE-GISEL-NEXT: .pad #8 +; LE-GISEL-NEXT: sub sp, #8 +; LE-GISEL-NEXT: mov.w r0, #15360 +; LE-GISEL-NEXT: str r0, [sp] +; LE-GISEL-NEXT: bl callee_soft_half_on_stack +; LE-GISEL-NEXT: add sp, #8 +; LE-GISEL-NEXT: pop {r7, pc} +entry: + %ret = call arm_aapcscc half @callee_soft_half_on_stack(float poison, float poison, float poison, float poison, half 1.0) + ret void +} + +define arm_aapcs_vfpcc half @callee_hard_half_in_reg(half %f) { +; LE-LABEL: callee_hard_half_in_reg: +; LE: @ %bb.0: @ %entry +; LE-NEXT: bx lr +; +; BE-LABEL: callee_hard_half_in_reg: +; BE: @ %bb.0: @ %entry +; BE-NEXT: bx lr +; +; LE-FP16-LABEL: callee_hard_half_in_reg: +; LE-FP16: @ %bb.0: @ %entry +; LE-FP16-NEXT: bx lr +; +; BE-FP16-LABEL: callee_hard_half_in_reg: +; BE-FP16: @ %bb.0: @ %entry +; BE-FP16-NEXT: bx lr +; +; LE-GISEL-LABEL: callee_hard_half_in_reg: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: bx lr +entry: + ret half %f +} + +define void @caller_hard_half_in_reg() { +; LE-LABEL: caller_hard_half_in_reg: +; LE: @ %bb.0: @ %entry +; LE-NEXT: .save {r7, lr} +; LE-NEXT: push {r7, lr} +; LE-NEXT: vldr s0, .LCPI5_0 +; LE-NEXT: bl callee_hard_half_in_reg +; LE-NEXT: pop {r7, pc} +; LE-NEXT: .p2align 2 +; LE-NEXT: @ %bb.1: +; LE-NEXT: .LCPI5_0: +; LE-NEXT: .long 0x00003c00 @ float 2.15239444E-41 +; +; BE-LABEL: caller_hard_half_in_reg: +; BE: @ %bb.0: @ %entry +; BE-NEXT: .save {r7, lr} +; BE-NEXT: push {r7, lr} +; BE-NEXT: vldr s0, .LCPI5_0 +; BE-NEXT: bl callee_hard_half_in_reg +; BE-NEXT: pop {r7, pc} +; BE-NEXT: .p2align 2 +; BE-NEXT: @ %bb.1: +; BE-NEXT: .LCPI5_0: +; BE-NEXT: .long 0x00003c00 @ float 2.15239444E-41 +; +; LE-FP16-LABEL: caller_hard_half_in_reg: +; LE-FP16: @ %bb.0: @ %entry +; LE-FP16-NEXT: .save {r7, lr} +; LE-FP16-NEXT: push {r7, lr} +; LE-FP16-NEXT: vmov.f16 s0, #1.000000e+00 +; LE-FP16-NEXT: bl callee_hard_half_in_reg +; LE-FP16-NEXT: pop {r7, pc} +; +; BE-FP16-LABEL: caller_hard_half_in_reg: +; BE-FP16: @ %bb.0: @ %entry +; BE-FP16-NEXT: .save {r7, lr} +; BE-FP16-NEXT: push {r7, lr} +; BE-FP16-NEXT: vmov.f16 s0, #1.000000e+00 +; BE-FP16-NEXT: bl callee_hard_half_in_reg +; BE-FP16-NEXT: pop {r7, pc} +; +; LE-GISEL-LABEL: caller_hard_half_in_reg: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: .save {r7, lr} +; LE-GISEL-NEXT: push {r7, lr} +; LE-GISEL-NEXT: vldr s0, .LCPI5_0 +; LE-GISEL-NEXT: bl callee_hard_half_in_reg +; LE-GISEL-NEXT: pop {r7, pc} +; LE-GISEL-NEXT: .p2align 2 +; LE-GISEL-NEXT: @ %bb.1: +; LE-GISEL-NEXT: .LCPI5_0: +; LE-GISEL-NEXT: .long 0x00003c00 @ float 2.15239444E-41 +entry: + %ret = call arm_aapcs_vfpcc half @callee_hard_half_in_reg(half 1.0) + ret void +} + +define arm_aapcs_vfpcc half @callee_hard_half_on_stack(float %s0, float %s1, float %s2, float %s3, float %s4, float %s5, float %s6, float %s7,float %s8, float %s9, float %s10, float %s11, float %s12, float %s13, float %s14, float %s15, half %f) { +; LE-LABEL: callee_hard_half_on_stack: +; LE: @ %bb.0: @ %entry +; LE-NEXT: vldr s0, [sp] +; LE-NEXT: bx lr +; +; BE-LABEL: callee_hard_half_on_stack: +; BE: @ %bb.0: @ %entry +; BE-NEXT: vldr s0, [sp] +; BE-NEXT: bx lr +; +; LE-FP16-LABEL: callee_hard_half_on_stack: +; LE-FP16: @ %bb.0: @ %entry +; LE-FP16-NEXT: vldr.16 s0, [sp] +; LE-FP16-NEXT: bx lr +; +; BE-FP16-LABEL: callee_hard_half_on_stack: +; BE-FP16: @ %bb.0: @ %entry +; BE-FP16-NEXT: vldr.16 s0, [sp, #2] +; BE-FP16-NEXT: bx lr +; +; LE-GISEL-LABEL: callee_hard_half_on_stack: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: mov r0, sp +; LE-GISEL-NEXT: ldr r0, [r0] +; LE-GISEL-NEXT: vmov s0, r0 +; LE-GISEL-NEXT: bx lr +entry: + ret half %f +} + + +define void @caller_hard_half_on_stack() { +; LE-LABEL: caller_hard_half_on_stack: +; LE: @ %bb.0: @ %entry +; LE-NEXT: .save {r7, lr} +; LE-NEXT: push {r7, lr} +; LE-NEXT: .pad #8 +; LE-NEXT: sub sp, #8 +; LE-NEXT: mov.w r0, #15360 +; LE-NEXT: str r0, [sp] +; LE-NEXT: bl callee_hard_half_on_stack +; LE-NEXT: add sp, #8 +; LE-NEXT: pop {r7, pc} +; +; BE-LABEL: caller_hard_half_on_stack: +; BE: @ %bb.0: @ %entry +; BE-NEXT: .save {r7, lr} +; BE-NEXT: push {r7, lr} +; BE-NEXT: .pad #8 +; BE-NEXT: sub sp, #8 +; BE-NEXT: mov.w r0, #15360 +; BE-NEXT: str r0, [sp] +; BE-NEXT: bl callee_hard_half_on_stack +; BE-NEXT: add sp, #8 +; BE-NEXT: pop {r7, pc} +; +; LE-FP16-LABEL: caller_hard_half_on_stack: +; LE-FP16: @ %bb.0: @ %entry +; LE-FP16-NEXT: .save {r7, lr} +; LE-FP16-NEXT: push {r7, lr} +; LE-FP16-NEXT: .pad #8 +; LE-FP16-NEXT: sub sp, #8 +; LE-FP16-NEXT: mov.w r0, #15360 +; LE-FP16-NEXT: str r0, [sp] +; LE-FP16-NEXT: bl callee_hard_half_on_stack +; LE-FP16-NEXT: add sp, #8 +; LE-FP16-NEXT: pop {r7, pc} +; +; BE-FP16-LABEL: caller_hard_half_on_stack: +; BE-FP16: @ %bb.0: @ %entry +; BE-FP16-NEXT: .save {r7, lr} +; BE-FP16-NEXT: push {r7, lr} +; BE-FP16-NEXT: .pad #8 +; BE-FP16-NEXT: sub sp, #8 +; BE-FP16-NEXT: mov.w r0, #15360 +; BE-FP16-NEXT: str r0, [sp] +; BE-FP16-NEXT: bl callee_hard_half_on_stack +; BE-FP16-NEXT: add sp, #8 +; BE-FP16-NEXT: pop {r7, pc} +; +; LE-GISEL-LABEL: caller_hard_half_on_stack: +; LE-GISEL: @ %bb.0: @ %entry +; LE-GISEL-NEXT: .save {r7, lr} +; LE-GISEL-NEXT: push {r7, lr} +; LE-GISEL-NEXT: .pad #8 +; LE-GISEL-NEXT: sub sp, #8 +; LE-GISEL-NEXT: mov.w r0, #15360 +; LE-GISEL-NEXT: str r0, [sp] +; LE-GISEL-NEXT: bl callee_hard_half_on_stack +; LE-GISEL-NEXT: add sp, #8 +; LE-GISEL-NEXT: pop {r7, pc} +entry: + %ret = call arm_aapcs_vfpcc half @callee_hard_half_on_stack(float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, float poison, half 1.0) + ret void +}