[llvm] r357352 - [RISCV] Add codegen support for ilp32f, ilp32d, lp64f, and lp64d ("hard float") ABIs

Alex Bradbury via llvm-commits llvm-commits at lists.llvm.org
Sat Mar 30 10:59:30 PDT 2019


Author: asb
Date: Sat Mar 30 10:59:30 2019
New Revision: 357352

URL: http://llvm.org/viewvc/llvm-project?rev=357352&view=rev
Log:
[RISCV] Add codegen support for ilp32f, ilp32d, lp64f, and lp64d ("hard float") ABIs

This patch adds support for the RISC-V hard float ABIs, building on top of
rL355771, which added basic target-abi parsing and MC layer support. It also
builds on some re-organisations and expansion of the upstream ABI and calling
convention tests which were recently committed directly upstream.

A number of aspects of the RISC-V float hard float ABIs require frontend
support (e.g. flattening of structs and passing int+fp for fp+fp structs in a
pair of registers), and will be addressed in a Clang patch.

As can be seen from the tests, it would be worthwhile extending
RISCVMergeBaseOffsets to handle constant pool as well as global accesses.

Differential Revision: https://reviews.llvm.org/D59357


Added:
    llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32d.ll
    llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32f-ilp32d-common.ll
Modified:
    llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td
    llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp
    llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp
    llvm/trunk/test/CodeGen/RISCV/callee-saved-fpr32s.ll
    llvm/trunk/test/CodeGen/RISCV/callee-saved-fpr64s.ll
    llvm/trunk/test/CodeGen/RISCV/callee-saved-gprs.ll
    llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32-ilp32f-common.ll
    llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32-ilp32f-ilp32d-common.ll
    llvm/trunk/test/CodeGen/RISCV/calling-conv-lp64-lp64f-common.ll
    llvm/trunk/test/CodeGen/RISCV/calling-conv-lp64-lp64f-lp64d-common.ll
    llvm/trunk/test/CodeGen/RISCV/target-abi-valid.ll
    llvm/trunk/test/CodeGen/RISCV/vararg.ll

Modified: llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td Sat Mar 30 10:59:30 2019
@@ -16,6 +16,14 @@
 def CSR_ILP32_LP64
     : CalleeSavedRegs<(add X1, X3, X4, X8, X9, (sequence "X%u", 18, 27))>;
 
+def CSR_ILP32F_LP64F
+    : CalleeSavedRegs<(add CSR_ILP32_LP64,
+                       F8_32, F9_32, (sequence "F%u_32", 18, 27))>;
+
+def CSR_ILP32D_LP64D
+    : CalleeSavedRegs<(add CSR_ILP32_LP64,
+                       F8_64, F9_64, (sequence "F%u_64", 18, 27))>;
+
 // Needed for implementation of RISCVRegisterInfo::getNoPreservedMask()
 def CSR_NoRegs : CalleeSavedRegs<(add)>;
 

Modified: llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp Sat Mar 30 10:59:30 2019
@@ -49,8 +49,17 @@ RISCVTargetLowering::RISCVTargetLowering
   RISCVABI::ABI ABI = Subtarget.getTargetABI();
   assert(ABI != RISCVABI::ABI_Unknown && "Improperly initialised target ABI");
 
-  if (ABI != RISCVABI::ABI_ILP32 && ABI != RISCVABI::ABI_LP64)
+  switch (ABI) {
+  default:
     report_fatal_error("Don't know how to lower this ABI");
+  case RISCVABI::ABI_ILP32:
+  case RISCVABI::ABI_ILP32F:
+  case RISCVABI::ABI_ILP32D:
+  case RISCVABI::ABI_LP64:
+  case RISCVABI::ABI_LP64F:
+  case RISCVABI::ABI_LP64D:
+    break;
+  }
 
   MVT XLenVT = Subtarget.getXLenVT();
 
@@ -981,6 +990,14 @@ static const MCPhysReg ArgGPRs[] = {
   RISCV::X10, RISCV::X11, RISCV::X12, RISCV::X13,
   RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17
 };
+static const MCPhysReg ArgFPR32s[] = {
+  RISCV::F10_32, RISCV::F11_32, RISCV::F12_32, RISCV::F13_32,
+  RISCV::F14_32, RISCV::F15_32, RISCV::F16_32, RISCV::F17_32
+};
+static const MCPhysReg ArgFPR64s[] = {
+  RISCV::F10_64, RISCV::F11_64, RISCV::F12_64, RISCV::F13_64,
+  RISCV::F14_64, RISCV::F15_64, RISCV::F16_64, RISCV::F17_64
+};
 
 // Pass a 2*XLEN argument that has been split into two XLEN values through
 // registers or the stack as necessary.
@@ -1021,9 +1038,10 @@ static bool CC_RISCVAssign2XLen(unsigned
 }
 
 // Implements the RISC-V calling convention. Returns true upon failure.
-static bool CC_RISCV(const DataLayout &DL, unsigned ValNo, MVT ValVT, MVT LocVT,
-                     CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
-                     CCState &State, bool IsFixed, bool IsRet, Type *OrigTy) {
+static bool CC_RISCV(const DataLayout &DL, RISCVABI::ABI ABI, unsigned ValNo,
+                     MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo,
+                     ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsFixed,
+                     bool IsRet, Type *OrigTy) {
   unsigned XLen = DL.getLargestLegalIntTypeSizeInBits();
   assert(XLen == 32 || XLen == 64);
   MVT XLenVT = XLen == 32 ? MVT::i32 : MVT::i64;
@@ -1033,10 +1051,42 @@ static bool CC_RISCV(const DataLayout &D
   if (IsRet && ValNo > 1)
     return true;
 
-  if (ValVT == MVT::f32) {
+  // UseGPRForF32 if targeting one of the soft-float ABIs, if passing a
+  // variadic argument, or if no F32 argument registers are available.
+  bool UseGPRForF32 = true;
+  // UseGPRForF64 if targeting soft-float ABIs or an FLEN=32 ABI, if passing a
+  // variadic argument, or if no F64 argument registers are available.
+  bool UseGPRForF64 = true;
+
+  switch (ABI) {
+  default:
+    llvm_unreachable("Unexpected ABI");
+  case RISCVABI::ABI_ILP32:
+  case RISCVABI::ABI_LP64:
+    break;
+  case RISCVABI::ABI_ILP32F:
+  case RISCVABI::ABI_LP64F:
+    UseGPRForF32 = !IsFixed;
+    break;
+  case RISCVABI::ABI_ILP32D:
+  case RISCVABI::ABI_LP64D:
+    UseGPRForF32 = !IsFixed;
+    UseGPRForF64 = !IsFixed;
+    break;
+  }
+
+  if (State.getFirstUnallocated(ArgFPR32s) == array_lengthof(ArgFPR32s))
+    UseGPRForF32 = true;
+  if (State.getFirstUnallocated(ArgFPR64s) == array_lengthof(ArgFPR64s))
+    UseGPRForF64 = true;
+
+  // From this point on, rely on UseGPRForF32, UseGPRForF64 and similar local
+  // variables rather than directly checking against the target ABI.
+
+  if (UseGPRForF32 && ValVT == MVT::f32) {
     LocVT = XLenVT;
     LocInfo = CCValAssign::BCvt;
-  } else if (XLen == 64 && ValVT == MVT::f64) {
+  } else if (UseGPRForF64 && XLen == 64 && ValVT == MVT::f64) {
     LocVT = MVT::i64;
     LocInfo = CCValAssign::BCvt;
   }
@@ -1064,8 +1114,9 @@ static bool CC_RISCV(const DataLayout &D
   assert(PendingLocs.size() == PendingArgFlags.size() &&
          "PendingLocs and PendingArgFlags out of sync");
 
-  // Handle passing f64 on RV32D with a soft float ABI.
-  if (XLen == 32 && ValVT == MVT::f64) {
+  // Handle passing f64 on RV32D with a soft float ABI or when floating point
+  // registers are exhausted.
+  if (UseGPRForF64 && XLen == 32 && ValVT == MVT::f64) {
     assert(!ArgFlags.isSplit() && PendingLocs.empty() &&
            "Can't lower f64 if it is split");
     // Depending on available argument GPRS, f64 may be passed in a pair of
@@ -1114,7 +1165,13 @@ static bool CC_RISCV(const DataLayout &D
   }
 
   // Allocate to a register if possible, or else a stack slot.
-  unsigned Reg = State.AllocateReg(ArgGPRs);
+  unsigned Reg;
+  if (ValVT == MVT::f32 && !UseGPRForF32)
+    Reg = State.AllocateReg(ArgFPR32s, ArgFPR64s);
+  else if (ValVT == MVT::f64 && !UseGPRForF64)
+    Reg = State.AllocateReg(ArgFPR64s, ArgFPR32s);
+  else
+    Reg = Reg = State.AllocateReg(ArgGPRs);
   unsigned StackOffset = Reg ? 0 : State.AllocateStack(XLen / 8, XLen / 8);
 
   // If we reach this point and PendingLocs is non-empty, we must be at the
@@ -1135,7 +1192,8 @@ static bool CC_RISCV(const DataLayout &D
     return false;
   }
 
-  assert(LocVT == XLenVT && "Expected an XLenVT at this stage");
+  assert((!UseGPRForF32 || !UseGPRForF64 || LocVT == XLenVT) &&
+         "Expected an XLenVT at this stage");
 
   if (Reg) {
     State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
@@ -1167,7 +1225,8 @@ void RISCVTargetLowering::analyzeInputAr
     else if (Ins[i].isOrigArg())
       ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
 
-    if (CC_RISCV(MF.getDataLayout(), i, ArgVT, ArgVT, CCValAssign::Full,
+    RISCVABI::ABI ABI = MF.getSubtarget<RISCVSubtarget>().getTargetABI();
+    if (CC_RISCV(MF.getDataLayout(), ABI, i, ArgVT, ArgVT, CCValAssign::Full,
                  ArgFlags, CCInfo, /*IsRet=*/true, IsRet, ArgTy)) {
       LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type "
                         << EVT(ArgVT).getEVTString() << '\n');
@@ -1187,7 +1246,8 @@ void RISCVTargetLowering::analyzeOutputA
     ISD::ArgFlagsTy ArgFlags = Outs[i].Flags;
     Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
 
-    if (CC_RISCV(MF.getDataLayout(), i, ArgVT, ArgVT, CCValAssign::Full,
+    RISCVABI::ABI ABI = MF.getSubtarget<RISCVSubtarget>().getTargetABI();
+    if (CC_RISCV(MF.getDataLayout(), ABI, i, ArgVT, ArgVT, CCValAssign::Full,
                  ArgFlags, CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) {
       LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type "
                         << EVT(ArgVT).getEVTString() << "\n");
@@ -1224,8 +1284,24 @@ static SDValue unpackFromRegLoc(Selectio
   MachineRegisterInfo &RegInfo = MF.getRegInfo();
   EVT LocVT = VA.getLocVT();
   SDValue Val;
+  const TargetRegisterClass *RC;
+
+  switch (LocVT.getSimpleVT().SimpleTy) {
+  default:
+    llvm_unreachable("Unexpected register type");
+  case MVT::i32:
+  case MVT::i64:
+    RC = &RISCV::GPRRegClass;
+    break;
+  case MVT::f32:
+    RC = &RISCV::FPR32RegClass;
+    break;
+  case MVT::f64:
+    RC = &RISCV::FPR64RegClass;
+    break;
+  }
 
-  unsigned VReg = RegInfo.createVirtualRegister(&RISCV::GPRRegClass);
+  unsigned VReg = RegInfo.createVirtualRegister(RC);
   RegInfo.addLiveIn(VA.getLocReg(), VReg);
   Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
 
@@ -1802,8 +1878,9 @@ bool RISCVTargetLowering::CanLowerReturn
   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
     MVT VT = Outs[i].VT;
     ISD::ArgFlagsTy ArgFlags = Outs[i].Flags;
-    if (CC_RISCV(MF.getDataLayout(), i, VT, VT, CCValAssign::Full, ArgFlags,
-                 CCInfo, /*IsFixed=*/true, /*IsRet=*/true, nullptr))
+    RISCVABI::ABI ABI = MF.getSubtarget<RISCVSubtarget>().getTargetABI();
+    if (CC_RISCV(MF.getDataLayout(), ABI, i, VT, VT, CCValAssign::Full,
+                 ArgFlags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true, nullptr))
       return false;
   }
   return true;

Modified: llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp Sat Mar 30 10:59:30 2019
@@ -40,7 +40,20 @@ RISCVRegisterInfo::getCalleeSavedRegs(co
       return CSR_XLEN_F32_Interrupt_SaveList;
     return CSR_Interrupt_SaveList;
   }
-  return CSR_ILP32_LP64_SaveList;
+
+  switch (Subtarget.getTargetABI()) {
+  default:
+    llvm_unreachable("Unrecognized ABI");
+  case RISCVABI::ABI_ILP32:
+  case RISCVABI::ABI_LP64:
+    return CSR_ILP32_LP64_SaveList;
+  case RISCVABI::ABI_ILP32F:
+  case RISCVABI::ABI_LP64F:
+    return CSR_ILP32F_LP64F_SaveList;
+  case RISCVABI::ABI_ILP32D:
+  case RISCVABI::ABI_LP64D:
+    return CSR_ILP32D_LP64D_SaveList;
+  }
 }
 
 BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
@@ -127,5 +140,18 @@ RISCVRegisterInfo::getCallPreservedMask(
       return CSR_XLEN_F32_Interrupt_RegMask;
     return CSR_Interrupt_RegMask;
   }
-  return CSR_ILP32_LP64_RegMask;
+
+  switch (Subtarget.getTargetABI()) {
+  default:
+    llvm_unreachable("Unrecognized ABI");
+  case RISCVABI::ABI_ILP32:
+  case RISCVABI::ABI_LP64:
+    return CSR_ILP32_LP64_RegMask;
+  case RISCVABI::ABI_ILP32F:
+  case RISCVABI::ABI_LP64F:
+    return CSR_ILP32F_LP64F_RegMask;
+  case RISCVABI::ABI_ILP32D:
+  case RISCVABI::ABI_LP64D:
+    return CSR_ILP32D_LP64D_RegMask;
+  }
 }

Modified: llvm/trunk/test/CodeGen/RISCV/callee-saved-fpr32s.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/callee-saved-fpr32s.ll?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/callee-saved-fpr32s.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/callee-saved-fpr32s.ll Sat Mar 30 10:59:30 2019
@@ -2,10 +2,19 @@
 ; RUN:   | FileCheck %s -check-prefix=ILP32-LP64
 ; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s \
 ; RUN:   | FileCheck %s -check-prefix=ILP32-LP64
+; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi ilp32f -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=ILP32F-LP64F
+; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi lp64f -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=ILP32F-LP64F
+; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32d -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=ILP32D-LP64D
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi lp64d -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=ILP32D-LP64D
 
 @var = global [32 x float] zeroinitializer
 
 ; All floating point registers are temporaries for the ilp32 and lp64 ABIs.
+; fs0-fs11 are callee-saved for the ilp32f, ilp32d, lp64f, and lp64d ABIs.
 
 ; This function tests that RISCVRegisterInfo::getCalleeSavedRegs returns
 ; something appropriate.
@@ -80,6 +89,42 @@ define void @callee() {
 ; ILP32-LP64-NEXT:    fsw ft1, 4(a1)
 ; ILP32-LP64-NEXT:    fsw ft0, %lo(var)(a0)
 ; ILP32-LP64-NEXT:    ret
+;
+; ILP32F-LP64F-LABEL: callee:
+; ILP32F-LP64F:       # %bb.0:
+; ILP32F-LP64F-NEXT:    addi sp, sp, -48
+; ILP32F-LP64F-NEXT:    fsw fs0, 44(sp)
+; ILP32F-LP64F-NEXT:    fsw fs1, 40(sp)
+; ILP32F-LP64F-NEXT:    fsw fs2, 36(sp)
+; ILP32F-LP64F-NEXT:    fsw fs3, 32(sp)
+; ILP32F-LP64F-NEXT:    fsw fs4, 28(sp)
+; ILP32F-LP64F-NEXT:    fsw fs5, 24(sp)
+; ILP32F-LP64F-NEXT:    fsw fs6, 20(sp)
+; ILP32F-LP64F-NEXT:    fsw fs7, 16(sp)
+; ILP32F-LP64F-NEXT:    fsw fs8, 12(sp)
+; ILP32F-LP64F-NEXT:    fsw fs9, 8(sp)
+; ILP32F-LP64F-NEXT:    fsw fs10, 4(sp)
+; ILP32F-LP64F-NEXT:    fsw fs11, 0(sp)
+; ILP32F-LP64F-NEXT:    lui a0, %hi(var)
+; ILP32F-LP64F-NEXT:    addi a1, a0, %lo(var)
+;
+; ILP32D-LP64D-LABEL: callee:
+; ILP32D-LP64D:       # %bb.0:
+; ILP32D-LP64D-NEXT:    addi sp, sp, -96
+; ILP32D-LP64D-NEXT:    fsd fs0, 88(sp)
+; ILP32D-LP64D-NEXT:    fsd fs1, 80(sp)
+; ILP32D-LP64D-NEXT:    fsd fs2, 72(sp)
+; ILP32D-LP64D-NEXT:    fsd fs3, 64(sp)
+; ILP32D-LP64D-NEXT:    fsd fs4, 56(sp)
+; ILP32D-LP64D-NEXT:    fsd fs5, 48(sp)
+; ILP32D-LP64D-NEXT:    fsd fs6, 40(sp)
+; ILP32D-LP64D-NEXT:    fsd fs7, 32(sp)
+; ILP32D-LP64D-NEXT:    fsd fs8, 24(sp)
+; ILP32D-LP64D-NEXT:    fsd fs9, 16(sp)
+; ILP32D-LP64D-NEXT:    fsd fs10, 8(sp)
+; ILP32D-LP64D-NEXT:    fsd fs11, 0(sp)
+; ILP32D-LP64D-NEXT:    lui a0, %hi(var)
+; ILP32D-LP64D-NEXT:    addi a1, a0, %lo(var)
   %val = load [32 x float], [32 x float]* @var
   store volatile [32 x float] %val, [32 x float]* @var
   ret void
@@ -89,17 +134,75 @@ define void @callee() {
 ; something appropriate.
 ;
 ; For the soft float ABIs, no floating point registers are preserved, and
-; codegen will use only ft0 in the body of caller.
+; codegen will use only ft0 in the body of caller. For the 'f' and 'd ABIs,
+; fs0-fs11 are preserved across calls.
 
 define void @caller() {
 ; ILP32-LP64-LABEL: caller:
 ; ILP32-LP64-NOT:     ft{{[1-9][0-9]*}}
 ; ILP32-LP64-NOT:     fs{{[0-9]+}}
 ; ILP32-LP64-NOT:     fa{{[0-9]+}}
-; ILP32-LP64:         ret
+; ILP32-LP64:         call callee
 ; ILP32-LP64-NOT:     ft{{[1-9][0-9]*}}
 ; ILP32-LP64-NOT:     fs{{[0-9]+}}
 ; ILP32-LP64-NOT:     fa{{[0-9]+}}
+; ILP32-LP64:         ret
+;
+; ILP32F-LP64F-LABEL: caller:
+; ILP32F-LP64F:       flw fs8, 80(s1)
+; ILP32F-LP64F-NEXT:  flw fs9, 84(s1)
+; ILP32F-LP64F-NEXT:  flw fs10, 88(s1)
+; ILP32F-LP64F-NEXT:  flw fs11, 92(s1)
+; ILP32F-LP64F-NEXT:  flw fs0, 96(s1)
+; ILP32F-LP64F-NEXT:  flw fs1, 100(s1)
+; ILP32F-LP64F-NEXT:  flw fs2, 104(s1)
+; ILP32F-LP64F-NEXT:  flw fs3, 108(s1)
+; ILP32F-LP64F-NEXT:  flw fs4, 112(s1)
+; ILP32F-LP64F-NEXT:  flw fs5, 116(s1)
+; ILP32F-LP64F-NEXT:  flw fs6, 120(s1)
+; ILP32F-LP64F-NEXT:  flw fs7, 124(s1)
+; ILP32F-LP64F-NEXT:  call callee
+; ILP32F-LP64F-NEXT:  fsw fs7, 124(s1)
+; ILP32F-LP64F-NEXT:  fsw fs6, 120(s1)
+; ILP32F-LP64F-NEXT:  fsw fs5, 116(s1)
+; ILP32F-LP64F-NEXT:  fsw fs4, 112(s1)
+; ILP32F-LP64F-NEXT:  fsw fs3, 108(s1)
+; ILP32F-LP64F-NEXT:  fsw fs2, 104(s1)
+; ILP32F-LP64F-NEXT:  fsw fs1, 100(s1)
+; ILP32F-LP64F-NEXT:  fsw fs0, 96(s1)
+; ILP32F-LP64F-NEXT:  fsw fs11, 92(s1)
+; ILP32F-LP64F-NEXT:  fsw fs10, 88(s1)
+; ILP32F-LP64F-NEXT:  fsw fs9, 84(s1)
+; ILP32F-LP64F-NEXT:  fsw fs8, 80(s1)
+; ILP32F-LP64F-NEXT:  lw ft0, {{[0-9]+}}(sp)
+;
+; ILP32D-LP64D-LABEL: caller:
+; ILP32D-LP64D:       flw fs8, 80(s1)
+; ILP32D-LP64D-NEXT:  flw fs9, 84(s1)
+; ILP32D-LP64D-NEXT:  flw fs10, 88(s1)
+; ILP32D-LP64D-NEXT:  flw fs11, 92(s1)
+; ILP32D-LP64D-NEXT:  flw fs0, 96(s1)
+; ILP32D-LP64D-NEXT:  flw fs1, 100(s1)
+; ILP32D-LP64D-NEXT:  flw fs2, 104(s1)
+; ILP32D-LP64D-NEXT:  flw fs3, 108(s1)
+; ILP32D-LP64D-NEXT:  flw fs4, 112(s1)
+; ILP32D-LP64D-NEXT:  flw fs5, 116(s1)
+; ILP32D-LP64D-NEXT:  flw fs6, 120(s1)
+; ILP32D-LP64D-NEXT:  flw fs7, 124(s1)
+; ILP32D-LP64D-NEXT:  call callee
+; ILP32D-LP64D-NEXT:  fsw fs7, 124(s1)
+; ILP32D-LP64D-NEXT:  fsw fs6, 120(s1)
+; ILP32D-LP64D-NEXT:  fsw fs5, 116(s1)
+; ILP32D-LP64D-NEXT:  fsw fs4, 112(s1)
+; ILP32D-LP64D-NEXT:  fsw fs3, 108(s1)
+; ILP32D-LP64D-NEXT:  fsw fs2, 104(s1)
+; ILP32D-LP64D-NEXT:  fsw fs1, 100(s1)
+; ILP32D-LP64D-NEXT:  fsw fs0, 96(s1)
+; ILP32D-LP64D-NEXT:  fsw fs11, 92(s1)
+; ILP32D-LP64D-NEXT:  fsw fs10, 88(s1)
+; ILP32D-LP64D-NEXT:  fsw fs9, 84(s1)
+; ILP32D-LP64D-NEXT:  fsw fs8, 80(s1)
+; ILP32D-LP64D-NEXT:  flw ft0, {{[0-9]+}}(sp)
   %val = load [32 x float], [32 x float]* @var
   call void @callee()
   store volatile [32 x float] %val, [32 x float]* @var

Modified: llvm/trunk/test/CodeGen/RISCV/callee-saved-fpr64s.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/callee-saved-fpr64s.ll?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/callee-saved-fpr64s.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/callee-saved-fpr64s.ll Sat Mar 30 10:59:30 2019
@@ -1,12 +1,16 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
 ; RUN:   | FileCheck %s -check-prefix=ILP32-LP64
 ; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
 ; RUN:   | FileCheck %s -check-prefix=ILP32-LP64
+; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32d -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=ILP32D-LP64D
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi lp64d -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=ILP32D-LP64D
 
 @var = global [32 x double] zeroinitializer
 
 ; All floating point registers are temporaries for the ilp32 and lp64 ABIs.
+; fs0-fs11 are callee-saved for the ilp32f, ilp32d, lp64f, and lp64d ABIs.
 
 ; This function tests that RISCVRegisterInfo::getCalleeSavedRegs returns
 ; something appropriate.
@@ -81,6 +85,24 @@ define void @callee() {
 ; ILP32-LP64-NEXT:    fsd ft1, 8(a1)
 ; ILP32-LP64-NEXT:    fsd ft0, %lo(var)(a0)
 ; ILP32-LP64-NEXT:    ret
+;
+; ILP32D-LP64D-LABEL: callee:
+; ILP32D-LP64D:       # %bb.0:
+; ILP32D-LP64D-NEXT:    addi sp, sp, -96
+; ILP32D-LP64D-NEXT:    fsd fs0, 88(sp)
+; ILP32D-LP64D-NEXT:    fsd fs1, 80(sp)
+; ILP32D-LP64D-NEXT:    fsd fs2, 72(sp)
+; ILP32D-LP64D-NEXT:    fsd fs3, 64(sp)
+; ILP32D-LP64D-NEXT:    fsd fs4, 56(sp)
+; ILP32D-LP64D-NEXT:    fsd fs5, 48(sp)
+; ILP32D-LP64D-NEXT:    fsd fs6, 40(sp)
+; ILP32D-LP64D-NEXT:    fsd fs7, 32(sp)
+; ILP32D-LP64D-NEXT:    fsd fs8, 24(sp)
+; ILP32D-LP64D-NEXT:    fsd fs9, 16(sp)
+; ILP32D-LP64D-NEXT:    fsd fs10, 8(sp)
+; ILP32D-LP64D-NEXT:    fsd fs11, 0(sp)
+; ILP32D-LP64D-NEXT:    lui a0, %hi(var)
+; ILP32D-LP64D-NEXT:    addi a1, a0, %lo(var)
   %val = load [32 x double], [32 x double]* @var
   store volatile [32 x double] %val, [32 x double]* @var
   ret void
@@ -90,17 +112,47 @@ define void @callee() {
 ; something appropriate.
 ;
 ; For the soft float ABIs, no floating point registers are preserved, and
-; codegen will use only ft0 in the body of caller.
+; codegen will use only ft0 in the body of caller. For the 'f' and 'd ABIs,
+; fs0-fs11 are preserved across calls.
 
 define void @caller() {
 ; ILP32-LP64-LABEL: caller:
 ; ILP32-LP64-NOT:     ft{{[1-9][0-9]*}}
 ; ILP32-LP64-NOT:     fs{{[0-9]+}}
 ; ILP32-LP64-NOT:     fa{{[0-9]+}}
-; ILP32-LP64:         ret
+; ILP32-LP64:         call callee
 ; ILP32-LP64-NOT:     ft{{[1-9][0-9]*}}
 ; ILP32-LP64-NOT:     fs{{[0-9]+}}
 ; ILP32-LP64-NOT:     fa{{[0-9]+}}
+; ILP32-LP64:         ret
+;
+; ILP32F-LP64D-LABEL: caller:
+; ILP32D-LP64D: fld	fs8, 160(s1)
+; ILP32D-LP64D-NEXT: fld fs9, 168(s1)
+; ILP32D-LP64D-NEXT: fld fs10, 176(s1)
+; ILP32D-LP64D-NEXT: fld fs11, 184(s1)
+; ILP32D-LP64D-NEXT: fld fs0, 192(s1)
+; ILP32D-LP64D-NEXT: fld fs1, 200(s1)
+; ILP32D-LP64D-NEXT: fld fs2, 208(s1)
+; ILP32D-LP64D-NEXT: fld fs3, 216(s1)
+; ILP32D-LP64D-NEXT: fld fs4, 224(s1)
+; ILP32D-LP64D-NEXT: fld fs5, 232(s1)
+; ILP32D-LP64D-NEXT: fld fs6, 240(s1)
+; ILP32D-LP64D-NEXT: fld fs7, 248(s1)
+; ILP32D-LP64D-NEXT: call	callee
+; ILP32D-LP64D-NEXT: fsd fs7, 248(s1)
+; ILP32D-LP64D-NEXT: fsd fs6, 240(s1)
+; ILP32D-LP64D-NEXT: fsd fs5, 232(s1)
+; ILP32D-LP64D-NEXT: fsd fs4, 224(s1)
+; ILP32D-LP64D-NEXT: fsd fs3, 216(s1)
+; ILP32D-LP64D-NEXT: fsd fs2, 208(s1)
+; ILP32D-LP64D-NEXT: fsd fs1, 200(s1)
+; ILP32D-LP64D-NEXT: fsd fs0, 192(s1)
+; ILP32D-LP64D-NEXT: fsd fs11, 184(s1)
+; ILP32D-LP64D-NEXT: fsd fs10, 176(s1)
+; ILP32D-LP64D-NEXT: fsd fs9, 168(s1)
+; ILP32D-LP64D-NEXT: fsd fs8, 160(s1)
+; ILP32D-LP64D-NEXT: fld ft0, {{[0-9]+}}(sp)
   %val = load [32 x double], [32 x double]* @var
   call void @callee()
   store volatile [32 x double] %val, [32 x double]* @var

Modified: llvm/trunk/test/CodeGen/RISCV/callee-saved-gprs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/callee-saved-gprs.ll?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/callee-saved-gprs.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/callee-saved-gprs.ll Sat Mar 30 10:59:30 2019
@@ -1,9 +1,21 @@
 ; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
 ; RUN:   | FileCheck %s -check-prefix=RV32I
+; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi ilp32f -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=RV32I
+; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32f -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=RV32I
+; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32d -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=RV32I
 ; RUN: llc -mtriple=riscv32 -verify-machineinstrs -frame-pointer=all < %s \
 ; RUN:   | FileCheck %s -check-prefix=RV32I-WITH-FP
 ; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
 ; RUN:   | FileCheck %s -check-prefix=RV64I
+; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi ilp32f -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=RV64I
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi ilp32f -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=RV64I
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi ilp32d -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s -check-prefix=RV64I
 ; RUN: llc -mtriple=riscv64 -verify-machineinstrs -frame-pointer=all < %s \
 ; RUN:   | FileCheck %s -check-prefix=RV64I-WITH-FP
 

Modified: llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32-ilp32f-common.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32-ilp32f-common.ll?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32-ilp32f-common.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32-ilp32f-common.ll Sat Mar 30 10:59:30 2019
@@ -1,8 +1,14 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
 ; RUN:   | FileCheck -check-prefix=RV32I-FPELIM %s
+; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi ilp32f \
+; RUN:    -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32I-FPELIM %s
 ; RUN: llc -mtriple=riscv32 -verify-machineinstrs -frame-pointer=all < %s \
 ; RUN:   | FileCheck -check-prefix=RV32I-WITHFP %s
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs -frame-pointer=all \
+; RUN:   -mattr=+f -target-abi ilp32f < %s \
+; RUN:   | FileCheck -check-prefix=RV32I-WITHFP %s
 
 ; This file contains tests that should have identical output for the ilp32,
 ; and ilp32f. As well as calling convention details, we check that

Modified: llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32-ilp32f-ilp32d-common.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32-ilp32f-ilp32d-common.ll?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32-ilp32f-ilp32d-common.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32-ilp32f-ilp32d-common.ll Sat Mar 30 10:59:30 2019
@@ -1,8 +1,20 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
 ; RUN:   | FileCheck -check-prefix=RV32I-FPELIM %s
+; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi ilp32f \
+; RUN:    -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32I-FPELIM %s
+; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32d \
+; RUN:    -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32I-FPELIM %s
 ; RUN: llc -mtriple=riscv32 -verify-machineinstrs -frame-pointer=all < %s \
 ; RUN:   | FileCheck -check-prefix=RV32I-WITHFP %s
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs -frame-pointer=all \
+; RUN:   -mattr=+f -target-abi ilp32f < %s \
+; RUN:   | FileCheck -check-prefix=RV32I-WITHFP %s
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs -frame-pointer=all \
+; RUN:   -mattr=+d -target-abi ilp32d < %s \
+; RUN:   | FileCheck -check-prefix=RV32I-WITHFP %s
 
 ; This file contains tests that should have identical output for the ilp32,
 ; ilp32f, and ilp32d ABIs. i.e. where no arguments are passed according to

Added: llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32d.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32d.ll?rev=357352&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32d.ll (added)
+++ llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32d.ll Sat Mar 30 10:59:30 2019
@@ -0,0 +1,294 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs -mattr=+d \
+; RUN:     -target-abi ilp32d < %s \
+; RUN:   | FileCheck -check-prefix=RV32-ILP32D %s
+
+; This file contains tests that will have differing output for the ilp32 and
+; ilp32f ABIs.
+
+define i32 @callee_double_in_fpr(i32 %a, double %b) nounwind {
+; RV32-ILP32D-LABEL: callee_double_in_fpr:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    fcvt.w.d a1, fa0, rtz
+; RV32-ILP32D-NEXT:    add a0, a0, a1
+; RV32-ILP32D-NEXT:    ret
+  %b_fptosi = fptosi double %b to i32
+  %1 = add i32 %a, %b_fptosi
+  ret i32 %1
+}
+
+define i32 @caller_double_in_fpr() nounwind {
+; RV32-ILP32D-LABEL: caller_double_in_fpr:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    addi sp, sp, -16
+; RV32-ILP32D-NEXT:    sw ra, 12(sp)
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI1_0)
+; RV32-ILP32D-NEXT:    addi a0, a0, %lo(.LCPI1_0)
+; RV32-ILP32D-NEXT:    fld fa0, 0(a0)
+; RV32-ILP32D-NEXT:    addi a0, zero, 1
+; RV32-ILP32D-NEXT:    call callee_double_in_fpr
+; RV32-ILP32D-NEXT:    lw ra, 12(sp)
+; RV32-ILP32D-NEXT:    addi sp, sp, 16
+; RV32-ILP32D-NEXT:    ret
+  %1 = call i32 @callee_double_in_fpr(i32 1, double 2.0)
+  ret i32 %1
+}
+
+; Must keep define on a single line due to an update_llc_test_checks.py limitation
+define i32 @callee_double_in_fpr_exhausted_gprs(i64 %a, i64 %b, i64 %c, i64 %d, i32 %e, double %f) nounwind {
+; RV32-ILP32D-LABEL: callee_double_in_fpr_exhausted_gprs:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    fcvt.w.d a0, fa0, rtz
+; RV32-ILP32D-NEXT:    lw a1, 0(sp)
+; RV32-ILP32D-NEXT:    add a0, a1, a0
+; RV32-ILP32D-NEXT:    ret
+  %f_fptosi = fptosi double %f to i32
+  %1 = add i32 %e, %f_fptosi
+  ret i32 %1
+}
+
+define i32 @caller_double_in_fpr_exhausted_gprs() nounwind {
+; RV32-ILP32D-LABEL: caller_double_in_fpr_exhausted_gprs:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    addi sp, sp, -16
+; RV32-ILP32D-NEXT:    sw ra, 12(sp)
+; RV32-ILP32D-NEXT:    addi a0, zero, 5
+; RV32-ILP32D-NEXT:    sw a0, 0(sp)
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI3_0)
+; RV32-ILP32D-NEXT:    addi a0, a0, %lo(.LCPI3_0)
+; RV32-ILP32D-NEXT:    fld fa0, 0(a0)
+; RV32-ILP32D-NEXT:    addi a0, zero, 1
+; RV32-ILP32D-NEXT:    mv a1, zero
+; RV32-ILP32D-NEXT:    addi a2, zero, 2
+; RV32-ILP32D-NEXT:    mv a3, zero
+; RV32-ILP32D-NEXT:    addi a4, zero, 3
+; RV32-ILP32D-NEXT:    mv a5, zero
+; RV32-ILP32D-NEXT:    addi a6, zero, 4
+; RV32-ILP32D-NEXT:    mv a7, zero
+; RV32-ILP32D-NEXT:    call callee_double_in_fpr_exhausted_gprs
+; RV32-ILP32D-NEXT:    lw ra, 12(sp)
+; RV32-ILP32D-NEXT:    addi sp, sp, 16
+; RV32-ILP32D-NEXT:    ret
+  %1 = call i32 @callee_double_in_fpr_exhausted_gprs(
+      i64 1, i64 2, i64 3, i64 4, i32 5, double 6.0)
+  ret i32 %1
+}
+
+; Must keep define on a single line due to an update_llc_test_checks.py limitation
+define i32 @callee_double_in_gpr_exhausted_fprs(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i) nounwind {
+; RV32-ILP32D-LABEL: callee_double_in_gpr_exhausted_fprs:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    addi sp, sp, -16
+; RV32-ILP32D-NEXT:    sw a0, 8(sp)
+; RV32-ILP32D-NEXT:    sw a1, 12(sp)
+; RV32-ILP32D-NEXT:    fld ft0, 8(sp)
+; RV32-ILP32D-NEXT:    fcvt.w.d a0, ft0, rtz
+; RV32-ILP32D-NEXT:    fcvt.w.d a1, fa7, rtz
+; RV32-ILP32D-NEXT:    add a0, a1, a0
+; RV32-ILP32D-NEXT:    addi sp, sp, 16
+; RV32-ILP32D-NEXT:    ret
+  %h_fptosi = fptosi double %h to i32
+  %i_fptosi = fptosi double %i to i32
+  %1 = add i32 %h_fptosi, %i_fptosi
+  ret i32 %1
+}
+
+define i32 @caller_double_in_gpr_exhausted_fprs() nounwind {
+; RV32-ILP32D-LABEL: caller_double_in_gpr_exhausted_fprs:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    addi sp, sp, -16
+; RV32-ILP32D-NEXT:    sw ra, 12(sp)
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI5_0)
+; RV32-ILP32D-NEXT:    addi a0, a0, %lo(.LCPI5_0)
+; RV32-ILP32D-NEXT:    lui a1, %hi(.LCPI5_1)
+; RV32-ILP32D-NEXT:    addi a1, a1, %lo(.LCPI5_1)
+; RV32-ILP32D-NEXT:    lui a2, %hi(.LCPI5_2)
+; RV32-ILP32D-NEXT:    addi a2, a2, %lo(.LCPI5_2)
+; RV32-ILP32D-NEXT:    lui a3, %hi(.LCPI5_3)
+; RV32-ILP32D-NEXT:    addi a3, a3, %lo(.LCPI5_3)
+; RV32-ILP32D-NEXT:    lui a4, %hi(.LCPI5_4)
+; RV32-ILP32D-NEXT:    addi a4, a4, %lo(.LCPI5_4)
+; RV32-ILP32D-NEXT:    lui a5, %hi(.LCPI5_5)
+; RV32-ILP32D-NEXT:    addi a5, a5, %lo(.LCPI5_5)
+; RV32-ILP32D-NEXT:    fld fa0, 0(a5)
+; RV32-ILP32D-NEXT:    fld fa1, 0(a4)
+; RV32-ILP32D-NEXT:    fld fa2, 0(a3)
+; RV32-ILP32D-NEXT:    fld fa3, 0(a2)
+; RV32-ILP32D-NEXT:    fld fa4, 0(a1)
+; RV32-ILP32D-NEXT:    fld fa5, 0(a0)
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI5_6)
+; RV32-ILP32D-NEXT:    addi a0, a0, %lo(.LCPI5_6)
+; RV32-ILP32D-NEXT:    fld fa6, 0(a0)
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI5_7)
+; RV32-ILP32D-NEXT:    addi a0, a0, %lo(.LCPI5_7)
+; RV32-ILP32D-NEXT:    fld fa7, 0(a0)
+; RV32-ILP32D-NEXT:    mv a0, zero
+; RV32-ILP32D-NEXT:    lui a1, 262688
+; RV32-ILP32D-NEXT:    call callee_double_in_gpr_exhausted_fprs
+; RV32-ILP32D-NEXT:    lw ra, 12(sp)
+; RV32-ILP32D-NEXT:    addi sp, sp, 16
+; RV32-ILP32D-NEXT:    ret
+  %1 = call i32 @callee_double_in_gpr_exhausted_fprs(
+      double 1.0, double 2.0, double 3.0, double 4.0, double 5.0, double 6.0,
+      double 7.0, double 8.0, double 9.0)
+  ret i32 %1
+}
+
+; Must keep define on a single line due to an update_llc_test_checks.py limitation
+define i32 @callee_double_in_gpr_and_stack_almost_exhausted_gprs_fprs(i64 %a, double %b, i64 %c, double %d, i64 %e, double %f, i32 %g, double %h, double %i, double %j, double %k, double %l, double %m) nounwind {
+; RV32-ILP32D-LABEL: callee_double_in_gpr_and_stack_almost_exhausted_gprs_fprs:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    addi sp, sp, -16
+; RV32-ILP32D-NEXT:    lw a0, 16(sp)
+; RV32-ILP32D-NEXT:    sw a7, 8(sp)
+; RV32-ILP32D-NEXT:    sw a0, 12(sp)
+; RV32-ILP32D-NEXT:    fld ft0, 8(sp)
+; RV32-ILP32D-NEXT:    fcvt.w.d a0, ft0, rtz
+; RV32-ILP32D-NEXT:    add a0, a6, a0
+; RV32-ILP32D-NEXT:    addi sp, sp, 16
+; RV32-ILP32D-NEXT:    ret
+  %m_fptosi = fptosi double %m to i32
+  %1 = add i32 %g, %m_fptosi
+  ret i32 %1
+}
+
+define i32 @caller_double_in_gpr_and_stack_almost_exhausted_gprs_fprs() nounwind {
+; RV32-ILP32D-LABEL: caller_double_in_gpr_and_stack_almost_exhausted_gprs_fprs:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    addi sp, sp, -16
+; RV32-ILP32D-NEXT:    sw ra, 12(sp)
+; RV32-ILP32D-NEXT:    lui a0, 262816
+; RV32-ILP32D-NEXT:    sw a0, 0(sp)
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI7_0)
+; RV32-ILP32D-NEXT:    addi a6, a0, %lo(.LCPI7_0)
+; RV32-ILP32D-NEXT:    lui a1, %hi(.LCPI7_1)
+; RV32-ILP32D-NEXT:    addi a1, a1, %lo(.LCPI7_1)
+; RV32-ILP32D-NEXT:    lui a2, %hi(.LCPI7_2)
+; RV32-ILP32D-NEXT:    addi a2, a2, %lo(.LCPI7_2)
+; RV32-ILP32D-NEXT:    lui a3, %hi(.LCPI7_3)
+; RV32-ILP32D-NEXT:    addi a3, a3, %lo(.LCPI7_3)
+; RV32-ILP32D-NEXT:    lui a4, %hi(.LCPI7_4)
+; RV32-ILP32D-NEXT:    addi a4, a4, %lo(.LCPI7_4)
+; RV32-ILP32D-NEXT:    lui a5, %hi(.LCPI7_5)
+; RV32-ILP32D-NEXT:    addi a5, a5, %lo(.LCPI7_5)
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI7_6)
+; RV32-ILP32D-NEXT:    addi a0, a0, %lo(.LCPI7_6)
+; RV32-ILP32D-NEXT:    fld fa0, 0(a0)
+; RV32-ILP32D-NEXT:    fld fa1, 0(a5)
+; RV32-ILP32D-NEXT:    fld fa2, 0(a4)
+; RV32-ILP32D-NEXT:    fld fa3, 0(a3)
+; RV32-ILP32D-NEXT:    fld fa4, 0(a2)
+; RV32-ILP32D-NEXT:    fld fa5, 0(a1)
+; RV32-ILP32D-NEXT:    fld fa6, 0(a6)
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI7_7)
+; RV32-ILP32D-NEXT:    addi a0, a0, %lo(.LCPI7_7)
+; RV32-ILP32D-NEXT:    fld fa7, 0(a0)
+; RV32-ILP32D-NEXT:    addi a0, zero, 1
+; RV32-ILP32D-NEXT:    mv a1, zero
+; RV32-ILP32D-NEXT:    addi a2, zero, 3
+; RV32-ILP32D-NEXT:    mv a3, zero
+; RV32-ILP32D-NEXT:    addi a4, zero, 5
+; RV32-ILP32D-NEXT:    mv a5, zero
+; RV32-ILP32D-NEXT:    addi a6, zero, 7
+; RV32-ILP32D-NEXT:    mv a7, zero
+; RV32-ILP32D-NEXT:    call callee_double_in_gpr_and_stack_almost_exhausted_gprs_fprs
+; RV32-ILP32D-NEXT:    lw ra, 12(sp)
+; RV32-ILP32D-NEXT:    addi sp, sp, 16
+; RV32-ILP32D-NEXT:    ret
+  %1 = call i32 @callee_double_in_gpr_and_stack_almost_exhausted_gprs_fprs(
+      i64 1, double 2.0, i64 3, double 4.0, i64 5, double 6.0, i32 7, double 8.0,
+      double 9.0, double 10.0, double 11.0, double 12.0, double 13.0)
+  ret i32 %1
+}
+
+
+; Must keep define on a single line due to an update_llc_test_checks.py limitation
+define i32 @callee_double_on_stack_exhausted_gprs_fprs(i64 %a, double %b, i64 %c, double %d, i64 %e, double %f, i64 %g, double %h, double %i, double %j, double %k, double %l, double %m) nounwind {
+; RV32-ILP32D-LABEL: callee_double_on_stack_exhausted_gprs_fprs:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    fld ft0, 0(sp)
+; RV32-ILP32D-NEXT:    fcvt.w.d a0, ft0, rtz
+; RV32-ILP32D-NEXT:    add a0, a6, a0
+; RV32-ILP32D-NEXT:    ret
+  %g_trunc = trunc i64 %g to i32
+  %m_fptosi = fptosi double %m to i32
+  %1 = add i32 %g_trunc, %m_fptosi
+  ret i32 %1
+}
+
+define i32 @caller_double_on_stack_exhausted_gprs_fprs() nounwind {
+; RV32-ILP32D-LABEL: caller_double_on_stack_exhausted_gprs_fprs:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    addi sp, sp, -16
+; RV32-ILP32D-NEXT:    sw ra, 12(sp)
+; RV32-ILP32D-NEXT:    lui a0, 262816
+; RV32-ILP32D-NEXT:    sw a0, 4(sp)
+; RV32-ILP32D-NEXT:    sw zero, 0(sp)
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI9_0)
+; RV32-ILP32D-NEXT:    addi a6, a0, %lo(.LCPI9_0)
+; RV32-ILP32D-NEXT:    lui a1, %hi(.LCPI9_1)
+; RV32-ILP32D-NEXT:    addi a1, a1, %lo(.LCPI9_1)
+; RV32-ILP32D-NEXT:    lui a2, %hi(.LCPI9_2)
+; RV32-ILP32D-NEXT:    addi a2, a2, %lo(.LCPI9_2)
+; RV32-ILP32D-NEXT:    lui a3, %hi(.LCPI9_3)
+; RV32-ILP32D-NEXT:    addi a3, a3, %lo(.LCPI9_3)
+; RV32-ILP32D-NEXT:    lui a4, %hi(.LCPI9_4)
+; RV32-ILP32D-NEXT:    addi a4, a4, %lo(.LCPI9_4)
+; RV32-ILP32D-NEXT:    lui a5, %hi(.LCPI9_5)
+; RV32-ILP32D-NEXT:    addi a5, a5, %lo(.LCPI9_5)
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI9_6)
+; RV32-ILP32D-NEXT:    addi a0, a0, %lo(.LCPI9_6)
+; RV32-ILP32D-NEXT:    fld fa0, 0(a0)
+; RV32-ILP32D-NEXT:    fld fa1, 0(a5)
+; RV32-ILP32D-NEXT:    fld fa2, 0(a4)
+; RV32-ILP32D-NEXT:    fld fa3, 0(a3)
+; RV32-ILP32D-NEXT:    fld fa4, 0(a2)
+; RV32-ILP32D-NEXT:    fld fa5, 0(a1)
+; RV32-ILP32D-NEXT:    fld fa6, 0(a6)
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI9_7)
+; RV32-ILP32D-NEXT:    addi a0, a0, %lo(.LCPI9_7)
+; RV32-ILP32D-NEXT:    fld fa7, 0(a0)
+; RV32-ILP32D-NEXT:    addi a0, zero, 1
+; RV32-ILP32D-NEXT:    mv a1, zero
+; RV32-ILP32D-NEXT:    addi a2, zero, 3
+; RV32-ILP32D-NEXT:    mv a3, zero
+; RV32-ILP32D-NEXT:    addi a4, zero, 5
+; RV32-ILP32D-NEXT:    mv a5, zero
+; RV32-ILP32D-NEXT:    addi a6, zero, 7
+; RV32-ILP32D-NEXT:    mv a7, zero
+; RV32-ILP32D-NEXT:    call callee_double_on_stack_exhausted_gprs_fprs
+; RV32-ILP32D-NEXT:    lw ra, 12(sp)
+; RV32-ILP32D-NEXT:    addi sp, sp, 16
+; RV32-ILP32D-NEXT:    ret
+  %1 = call i32 @callee_double_on_stack_exhausted_gprs_fprs(
+      i64 1, double 2.0, i64 3, double 4.0, i64 5, double 6.0, i64 7, double 8.0,
+      double 9.0, double 10.0, double 11.0, double 12.0, double 13.0)
+  ret i32 %1
+}
+
+define double @callee_double_ret() nounwind {
+; RV32-ILP32D-LABEL: callee_double_ret:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    lui a0, %hi(.LCPI10_0)
+; RV32-ILP32D-NEXT:    addi a0, a0, %lo(.LCPI10_0)
+; RV32-ILP32D-NEXT:    fld fa0, 0(a0)
+; RV32-ILP32D-NEXT:    ret
+  ret double 1.0
+}
+
+define i32 @caller_double_ret() nounwind {
+; RV32-ILP32D-LABEL: caller_double_ret:
+; RV32-ILP32D:       # %bb.0:
+; RV32-ILP32D-NEXT:    addi sp, sp, -16
+; RV32-ILP32D-NEXT:    sw ra, 12(sp)
+; RV32-ILP32D-NEXT:    call callee_double_ret
+; RV32-ILP32D-NEXT:    fsd fa0, 0(sp)
+; RV32-ILP32D-NEXT:    lw a0, 0(sp)
+; RV32-ILP32D-NEXT:    lw ra, 12(sp)
+; RV32-ILP32D-NEXT:    addi sp, sp, 16
+; RV32-ILP32D-NEXT:    ret
+  %1 = call double @callee_double_ret()
+  %2 = bitcast double %1 to i64
+  %3 = trunc i64 %2 to i32
+  ret i32 %3
+}

Added: llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32f-ilp32d-common.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32f-ilp32d-common.ll?rev=357352&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32f-ilp32d-common.ll (added)
+++ llvm/trunk/test/CodeGen/RISCV/calling-conv-ilp32f-ilp32d-common.ll Sat Mar 30 10:59:30 2019
@@ -0,0 +1,221 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs -mattr=+f \
+; RUN:     -target-abi ilp32f < %s \
+; RUN:   | FileCheck -check-prefix=RV32-ILP32FD %s
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs -mattr=+d \
+; RUN:     -target-abi ilp32d < %s \
+; RUN:   | FileCheck -check-prefix=RV32-ILP32FD %s
+
+; This file contains tests that should have identical output for the ilp32f
+; and ilp32d ABIs.
+
+define i32 @callee_float_in_fpr(i32 %a, float %b) nounwind {
+; RV32-ILP32FD-LABEL: callee_float_in_fpr:
+; RV32-ILP32FD:       # %bb.0:
+; RV32-ILP32FD-NEXT:    fcvt.w.s a1, fa0, rtz
+; RV32-ILP32FD-NEXT:    add a0, a0, a1
+; RV32-ILP32FD-NEXT:    ret
+  %b_fptosi = fptosi float %b to i32
+  %1 = add i32 %a, %b_fptosi
+  ret i32 %1
+}
+
+define i32 @caller_float_in_fpr() nounwind {
+; RV32-ILP32FD-LABEL: caller_float_in_fpr:
+; RV32-ILP32FD:       # %bb.0:
+; RV32-ILP32FD-NEXT:    addi sp, sp, -16
+; RV32-ILP32FD-NEXT:    sw ra, 12(sp)
+; RV32-ILP32FD-NEXT:    lui a0, %hi(.LCPI1_0)
+; RV32-ILP32FD-NEXT:    addi a0, a0, %lo(.LCPI1_0)
+; RV32-ILP32FD-NEXT:    flw fa0, 0(a0)
+; RV32-ILP32FD-NEXT:    addi a0, zero, 1
+; RV32-ILP32FD-NEXT:    call callee_float_in_fpr
+; RV32-ILP32FD-NEXT:    lw ra, 12(sp)
+; RV32-ILP32FD-NEXT:    addi sp, sp, 16
+; RV32-ILP32FD-NEXT:    ret
+  %1 = call i32 @callee_float_in_fpr(i32 1, float 2.0)
+  ret i32 %1
+}
+
+; Must keep define on a single line due to an update_llc_test_checks.py limitation
+define i32 @callee_float_in_fpr_exhausted_gprs(i64 %a, i64 %b, i64 %c, i64 %d, i32 %e, float %f) nounwind {
+; RV32-ILP32FD-LABEL: callee_float_in_fpr_exhausted_gprs:
+; RV32-ILP32FD:       # %bb.0:
+; RV32-ILP32FD-NEXT:    fcvt.w.s a0, fa0, rtz
+; RV32-ILP32FD-NEXT:    lw a1, 0(sp)
+; RV32-ILP32FD-NEXT:    add a0, a1, a0
+; RV32-ILP32FD-NEXT:    ret
+  %f_fptosi = fptosi float %f to i32
+  %1 = add i32 %e, %f_fptosi
+  ret i32 %1
+}
+
+define i32 @caller_float_in_fpr_exhausted_gprs() nounwind {
+; RV32-ILP32FD-LABEL: caller_float_in_fpr_exhausted_gprs:
+; RV32-ILP32FD:       # %bb.0:
+; RV32-ILP32FD-NEXT:    addi sp, sp, -16
+; RV32-ILP32FD-NEXT:    sw ra, 12(sp)
+; RV32-ILP32FD-NEXT:    addi a0, zero, 5
+; RV32-ILP32FD-NEXT:    sw a0, 0(sp)
+; RV32-ILP32FD-NEXT:    lui a0, %hi(.LCPI3_0)
+; RV32-ILP32FD-NEXT:    addi a0, a0, %lo(.LCPI3_0)
+; RV32-ILP32FD-NEXT:    flw fa0, 0(a0)
+; RV32-ILP32FD-NEXT:    addi a0, zero, 1
+; RV32-ILP32FD-NEXT:    mv a1, zero
+; RV32-ILP32FD-NEXT:    addi a2, zero, 2
+; RV32-ILP32FD-NEXT:    mv a3, zero
+; RV32-ILP32FD-NEXT:    addi a4, zero, 3
+; RV32-ILP32FD-NEXT:    mv a5, zero
+; RV32-ILP32FD-NEXT:    addi a6, zero, 4
+; RV32-ILP32FD-NEXT:    mv a7, zero
+; RV32-ILP32FD-NEXT:    call callee_float_in_fpr_exhausted_gprs
+; RV32-ILP32FD-NEXT:    lw ra, 12(sp)
+; RV32-ILP32FD-NEXT:    addi sp, sp, 16
+; RV32-ILP32FD-NEXT:    ret
+  %1 = call i32 @callee_float_in_fpr_exhausted_gprs(
+      i64 1, i64 2, i64 3, i64 4, i32 5, float 6.0)
+  ret i32 %1
+}
+
+; Must keep define on a single line due to an update_llc_test_checks.py limitation
+define i32 @callee_float_in_gpr_exhausted_fprs(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, float %i) nounwind {
+; RV32-ILP32FD-LABEL: callee_float_in_gpr_exhausted_fprs:
+; RV32-ILP32FD:       # %bb.0:
+; RV32-ILP32FD-NEXT:    fcvt.w.s a1, fa7, rtz
+; RV32-ILP32FD-NEXT:    fmv.w.x ft0, a0
+; RV32-ILP32FD-NEXT:    fcvt.w.s a0, ft0, rtz
+; RV32-ILP32FD-NEXT:    add a0, a1, a0
+; RV32-ILP32FD-NEXT:    ret
+  %h_fptosi = fptosi float %h to i32
+  %i_fptosi = fptosi float %i to i32
+  %1 = add i32 %h_fptosi, %i_fptosi
+  ret i32 %1
+}
+
+define i32 @caller_float_in_gpr_exhausted_fprs() nounwind {
+; RV32-ILP32FD-LABEL: caller_float_in_gpr_exhausted_fprs:
+; RV32-ILP32FD:       # %bb.0:
+; RV32-ILP32FD-NEXT:    addi sp, sp, -16
+; RV32-ILP32FD-NEXT:    sw ra, 12(sp)
+; RV32-ILP32FD-NEXT:    lui a0, %hi(.LCPI5_0)
+; RV32-ILP32FD-NEXT:    addi a0, a0, %lo(.LCPI5_0)
+; RV32-ILP32FD-NEXT:    lui a1, %hi(.LCPI5_1)
+; RV32-ILP32FD-NEXT:    addi a1, a1, %lo(.LCPI5_1)
+; RV32-ILP32FD-NEXT:    lui a2, %hi(.LCPI5_2)
+; RV32-ILP32FD-NEXT:    addi a2, a2, %lo(.LCPI5_2)
+; RV32-ILP32FD-NEXT:    lui a3, %hi(.LCPI5_3)
+; RV32-ILP32FD-NEXT:    addi a3, a3, %lo(.LCPI5_3)
+; RV32-ILP32FD-NEXT:    lui a4, %hi(.LCPI5_4)
+; RV32-ILP32FD-NEXT:    addi a4, a4, %lo(.LCPI5_4)
+; RV32-ILP32FD-NEXT:    lui a5, %hi(.LCPI5_5)
+; RV32-ILP32FD-NEXT:    addi a5, a5, %lo(.LCPI5_5)
+; RV32-ILP32FD-NEXT:    flw fa0, 0(a5)
+; RV32-ILP32FD-NEXT:    flw fa1, 0(a4)
+; RV32-ILP32FD-NEXT:    flw fa2, 0(a3)
+; RV32-ILP32FD-NEXT:    flw fa3, 0(a2)
+; RV32-ILP32FD-NEXT:    flw fa4, 0(a1)
+; RV32-ILP32FD-NEXT:    flw fa5, 0(a0)
+; RV32-ILP32FD-NEXT:    lui a0, %hi(.LCPI5_6)
+; RV32-ILP32FD-NEXT:    addi a0, a0, %lo(.LCPI5_6)
+; RV32-ILP32FD-NEXT:    flw fa6, 0(a0)
+; RV32-ILP32FD-NEXT:    lui a0, %hi(.LCPI5_7)
+; RV32-ILP32FD-NEXT:    addi a0, a0, %lo(.LCPI5_7)
+; RV32-ILP32FD-NEXT:    flw fa7, 0(a0)
+; RV32-ILP32FD-NEXT:    lui a0, 266496
+; RV32-ILP32FD-NEXT:    call callee_float_in_gpr_exhausted_fprs
+; RV32-ILP32FD-NEXT:    lw ra, 12(sp)
+; RV32-ILP32FD-NEXT:    addi sp, sp, 16
+; RV32-ILP32FD-NEXT:    ret
+  %1 = call i32 @callee_float_in_gpr_exhausted_fprs(
+      float 1.0, float 2.0, float 3.0, float 4.0, float 5.0, float 6.0,
+      float 7.0, float 8.0, float 9.0)
+  ret i32 %1
+}
+
+; Must keep define on a single line due to an update_llc_test_checks.py limitation
+define i32 @callee_float_on_stack_exhausted_gprs_fprs(i64 %a, float %b, i64 %c, float %d, i64 %e, float %f, i64 %g, float %h, float %i, float %j, float %k, float %l, float %m) nounwind {
+; RV32-ILP32FD-LABEL: callee_float_on_stack_exhausted_gprs_fprs:
+; RV32-ILP32FD:       # %bb.0:
+; RV32-ILP32FD-NEXT:    flw ft0, 0(sp)
+; RV32-ILP32FD-NEXT:    fcvt.w.s a0, ft0, rtz
+; RV32-ILP32FD-NEXT:    add a0, a6, a0
+; RV32-ILP32FD-NEXT:    ret
+  %g_trunc = trunc i64 %g to i32
+  %m_fptosi = fptosi float %m to i32
+  %1 = add i32 %g_trunc, %m_fptosi
+  ret i32 %1
+}
+
+define i32 @caller_float_on_stack_exhausted_gprs_fprs() nounwind {
+; RV32-ILP32FD-LABEL: caller_float_on_stack_exhausted_gprs_fprs:
+; RV32-ILP32FD:       # %bb.0:
+; RV32-ILP32FD-NEXT:    addi sp, sp, -16
+; RV32-ILP32FD-NEXT:    sw ra, 12(sp)
+; RV32-ILP32FD-NEXT:    lui a0, 267520
+; RV32-ILP32FD-NEXT:    sw a0, 0(sp)
+; RV32-ILP32FD-NEXT:    lui a0, %hi(.LCPI7_0)
+; RV32-ILP32FD-NEXT:    addi a6, a0, %lo(.LCPI7_0)
+; RV32-ILP32FD-NEXT:    lui a1, %hi(.LCPI7_1)
+; RV32-ILP32FD-NEXT:    addi a1, a1, %lo(.LCPI7_1)
+; RV32-ILP32FD-NEXT:    lui a2, %hi(.LCPI7_2)
+; RV32-ILP32FD-NEXT:    addi a2, a2, %lo(.LCPI7_2)
+; RV32-ILP32FD-NEXT:    lui a3, %hi(.LCPI7_3)
+; RV32-ILP32FD-NEXT:    addi a3, a3, %lo(.LCPI7_3)
+; RV32-ILP32FD-NEXT:    lui a4, %hi(.LCPI7_4)
+; RV32-ILP32FD-NEXT:    addi a4, a4, %lo(.LCPI7_4)
+; RV32-ILP32FD-NEXT:    lui a5, %hi(.LCPI7_5)
+; RV32-ILP32FD-NEXT:    addi a5, a5, %lo(.LCPI7_5)
+; RV32-ILP32FD-NEXT:    lui a0, %hi(.LCPI7_6)
+; RV32-ILP32FD-NEXT:    addi a0, a0, %lo(.LCPI7_6)
+; RV32-ILP32FD-NEXT:    flw fa0, 0(a0)
+; RV32-ILP32FD-NEXT:    flw fa1, 0(a5)
+; RV32-ILP32FD-NEXT:    flw fa2, 0(a4)
+; RV32-ILP32FD-NEXT:    flw fa3, 0(a3)
+; RV32-ILP32FD-NEXT:    flw fa4, 0(a2)
+; RV32-ILP32FD-NEXT:    flw fa5, 0(a1)
+; RV32-ILP32FD-NEXT:    flw fa6, 0(a6)
+; RV32-ILP32FD-NEXT:    lui a0, %hi(.LCPI7_7)
+; RV32-ILP32FD-NEXT:    addi a0, a0, %lo(.LCPI7_7)
+; RV32-ILP32FD-NEXT:    flw fa7, 0(a0)
+; RV32-ILP32FD-NEXT:    addi a0, zero, 1
+; RV32-ILP32FD-NEXT:    mv a1, zero
+; RV32-ILP32FD-NEXT:    addi a2, zero, 3
+; RV32-ILP32FD-NEXT:    mv a3, zero
+; RV32-ILP32FD-NEXT:    addi a4, zero, 5
+; RV32-ILP32FD-NEXT:    mv a5, zero
+; RV32-ILP32FD-NEXT:    addi a6, zero, 7
+; RV32-ILP32FD-NEXT:    mv a7, zero
+; RV32-ILP32FD-NEXT:    call callee_float_on_stack_exhausted_gprs_fprs
+; RV32-ILP32FD-NEXT:    lw ra, 12(sp)
+; RV32-ILP32FD-NEXT:    addi sp, sp, 16
+; RV32-ILP32FD-NEXT:    ret
+  %1 = call i32 @callee_float_on_stack_exhausted_gprs_fprs(
+      i64 1, float 2.0, i64 3, float 4.0, i64 5, float 6.0, i64 7, float 8.0,
+      float 9.0, float 10.0, float 11.0, float 12.0, float 13.0)
+  ret i32 %1
+}
+
+define float @callee_float_ret() nounwind {
+; RV32-ILP32FD-LABEL: callee_float_ret:
+; RV32-ILP32FD:       # %bb.0:
+; RV32-ILP32FD-NEXT:    lui a0, %hi(.LCPI8_0)
+; RV32-ILP32FD-NEXT:    addi a0, a0, %lo(.LCPI8_0)
+; RV32-ILP32FD-NEXT:    flw fa0, 0(a0)
+; RV32-ILP32FD-NEXT:    ret
+  ret float 1.0
+}
+
+define i32 @caller_float_ret() nounwind {
+; RV32-ILP32FD-LABEL: caller_float_ret:
+; RV32-ILP32FD:       # %bb.0:
+; RV32-ILP32FD-NEXT:    addi sp, sp, -16
+; RV32-ILP32FD-NEXT:    sw ra, 12(sp)
+; RV32-ILP32FD-NEXT:    call callee_float_ret
+; RV32-ILP32FD-NEXT:    fmv.x.w a0, fa0
+; RV32-ILP32FD-NEXT:    lw ra, 12(sp)
+; RV32-ILP32FD-NEXT:    addi sp, sp, 16
+; RV32-ILP32FD-NEXT:    ret
+  %1 = call float @callee_float_ret()
+  %2 = bitcast float %1 to i32
+  ret i32 %2
+}

Modified: llvm/trunk/test/CodeGen/RISCV/calling-conv-lp64-lp64f-common.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/calling-conv-lp64-lp64f-common.ll?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/calling-conv-lp64-lp64f-common.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/calling-conv-lp64-lp64f-common.ll Sat Mar 30 10:59:30 2019
@@ -1,6 +1,9 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
 ; RUN:   | FileCheck -check-prefix=RV64I %s
+; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi lp64f \
+; RUN:    -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I %s
 
 ; This file contains tests that should have identical output for the lp64 and
 ; lp64f ABIs. It doesn't check codegen when frame pointer elimination is

Modified: llvm/trunk/test/CodeGen/RISCV/calling-conv-lp64-lp64f-lp64d-common.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/calling-conv-lp64-lp64f-lp64d-common.ll?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/calling-conv-lp64-lp64f-lp64d-common.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/calling-conv-lp64-lp64f-lp64d-common.ll Sat Mar 30 10:59:30 2019
@@ -1,6 +1,12 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
 ; RUN:   | FileCheck -check-prefix=RV64I %s
+; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi lp64f \
+; RUN:    -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi lp64d \
+; RUN:    -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I %s
 
 ; This file contains tests that should have identical output for the lp64,
 ; lp64f, and lp64d ABIs. i.e. where no arguments are passed according to

Modified: llvm/trunk/test/CodeGen/RISCV/target-abi-valid.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/target-abi-valid.ll?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/target-abi-valid.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/target-abi-valid.ll Sat Mar 30 10:59:30 2019
@@ -14,6 +14,18 @@
 ; RUN:   | FileCheck -check-prefix=CHECK-IMP %s
 ; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi lp64 < %s \
 ; RUN:   | FileCheck -check-prefix=CHECK-IMP %s
+; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi ilp32f < %s 2>&1 \
+; RUN:   | FileCheck -check-prefix=CHECK-IMP %s
+; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32f < %s 2>&1 \
+; RUN:   | FileCheck -check-prefix=CHECK-IMP %s
+; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32d < %s 2>&1 \
+; RUN:   | FileCheck -check-prefix=CHECK-IMP %s
+; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi lp64f < %s 2>&1 \
+; RUN:   | FileCheck -check-prefix=CHECK-IMP %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi lp64f < %s 2>&1 \
+; RUN:   | FileCheck -check-prefix=CHECK-IMP %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi lp64d < %s 2>&1 \
+; RUN:   | FileCheck -check-prefix=CHECK-IMP %s
 
 define void @nothing() nounwind {
 ; CHECK-IMP-LABEL: nothing:
@@ -22,19 +34,7 @@ define void @nothing() nounwind {
   ret void
 }
 
-; RUN: not llc -mtriple=riscv32 -mattr=+f -target-abi ilp32f < %s 2>&1 \
-; RUN:   | FileCheck -check-prefix=CHECK-UNIMP %s
-; RUN: not llc -mtriple=riscv32 -mattr=+d -target-abi ilp32f < %s 2>&1 \
-; RUN:   | FileCheck -check-prefix=CHECK-UNIMP %s
-; RUN: not llc -mtriple=riscv32 -mattr=+d -target-abi ilp32d < %s 2>&1 \
-; RUN:   | FileCheck -check-prefix=CHECK-UNIMP %s
 ; RUN: not llc -mtriple=riscv32 -target-abi ilp32e < %s 2>&1 \
 ; RUN:   | FileCheck -check-prefix=CHECK-UNIMP %s
-; RUN: not llc -mtriple=riscv64 -mattr=+f -target-abi lp64f < %s 2>&1 \
-; RUN:   | FileCheck -check-prefix=CHECK-UNIMP %s
-; RUN: not llc -mtriple=riscv64 -mattr=+d -target-abi lp64f < %s 2>&1 \
-; RUN:   | FileCheck -check-prefix=CHECK-UNIMP %s
-; RUN: not llc -mtriple=riscv64 -mattr=+d -target-abi lp64d < %s 2>&1 \
-; RUN:   | FileCheck -check-prefix=CHECK-UNIMP %s
 
 ; CHECK-UNIMP: LLVM ERROR: Don't know how to lower this ABI

Modified: llvm/trunk/test/CodeGen/RISCV/vararg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/vararg.ll?rev=357352&r1=357351&r2=357352&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/vararg.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/vararg.ll Sat Mar 30 10:59:30 2019
@@ -5,16 +5,26 @@
 ; RUN:   | FileCheck -check-prefix=ILP32-ILP32F-WITHFP %s
 ; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
 ; RUN:   | FileCheck -check-prefix=RV32D-ILP32-ILP32F-ILP32D-FPELIM %s
+; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32f \
+; RUN:     -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32D-ILP32-ILP32F-ILP32D-FPELIM %s
+; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32d \
+; RUN:     -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32D-ILP32-ILP32F-ILP32D-FPELIM %s
 ; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
 ; RUN:   | FileCheck -check-prefix=LP64-LP64F-LP64D-FPELIM %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi lp64f \
+; RUN:     -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=LP64-LP64F-LP64D-FPELIM %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi lp64d \
+; RUN:     -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=LP64-LP64F-LP64D-FPELIM %s
 ; RUN: llc -mtriple=riscv64 -verify-machineinstrs -frame-pointer=all < %s \
 ; RUN:   | FileCheck -check-prefix=LP64-LP64F-LP64D-WITHFP %s
 
-; TODO: RUN lines for ilp32f/ilp32d/lp64f/lp64d must be added when hard float
-; ABI Support lands. The same vararg calling convention is used for
-; ilp32/ilp32f/ilp32d and for lp64/lp64f/lp64d. Different CHECK lines are
-; required for RV32D due to slight codegen differences due to the way the
-; f64 load operations are lowered.
+; The same vararg calling convention is used for ilp32/ilp32f/ilp32d and for
+; lp64/lp64f/lp64d. Different CHECK lines are required for RV32D due to slight
+; codegen differences due to the way the f64 load operations are lowered.
 
 declare void @llvm.va_start(i8*)
 declare void @llvm.va_end(i8*)




More information about the llvm-commits mailing list