[llvm] [RISCV][GISel] Add FP calling convention support (PR #69138)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 24 16:09:29 PDT 2023


https://github.com/topperc updated https://github.com/llvm/llvm-project/pull/69138

>From 8f7ca493f7adf1878c42ad84a19a1501b0c081b4 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Sun, 15 Oct 2023 18:07:00 -0700
Subject: [PATCH 1/2] [RISCV][GISel] Add FP calling convention support using
 FPR and GPR registers.

This does not include passing values on the stack.

Test cases copied from SelectionDAG and converted to check MIR output.
Test cases that require stack were removed.
---
 .../Target/RISCV/GISel/RISCVCallLowering.cpp  |  65 ++++++++++
 .../calling-conv-ilp32-ilp32f-common.ll       |  75 +++++++++++
 .../irtranslator/calling-conv-ilp32.ll        |  60 +++++++++
 .../irtranslator/calling-conv-ilp32d.ll       | 122 ++++++++++++++++++
 .../calling-conv-ilp32f-ilp32d-common.ll      | 119 +++++++++++++++++
 .../calling-conv-lp64-lp64f-common.ll         |  62 +++++++++
 .../irtranslator/calling-conv-lp64.ll         |  82 ++++++++++++
 .../irtranslator/calling-conv-lp64d.ll        |  59 +++++++++
 8 files changed, 644 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32-ilp32f-common.ll
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32.ll
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32d.ll
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32f-ilp32d-common.ll
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64-lp64f-common.ll
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64.ll
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64d.ll

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp b/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
index ec3825a6f780e62..cbdcfc60c4a8267 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
@@ -94,11 +94,46 @@ struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
 
   void assignValueToReg(Register ValVReg, Register PhysReg,
                         CCValAssign VA) override {
+    // If we're passing an f32 value into an i64, anyextend before copying.
+    if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
+      ValVReg = MIRBuilder.buildAnyExt(LLT::scalar(64), ValVReg).getReg(0);
+
     Register ExtReg = extendRegister(ValVReg, VA);
     MIRBuilder.buildCopy(PhysReg, ExtReg);
     MIB.addUse(PhysReg, RegState::Implicit);
   }
 
+  unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
+                             ArrayRef<CCValAssign> VAs,
+                             std::function<void()> *Thunk) override {
+    assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
+    const CCValAssign &VALo = VAs[0];
+    const CCValAssign &VAHi = VAs[1];
+
+    assert(VAHi.needsCustom() && "Value doesn't need custom handling");
+    assert(VALo.getValNo() == VAHi.getValNo() &&
+           "Values belong to different arguments");
+
+    assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
+           VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
+           "unexpected custom value");
+
+    Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
+                          MRI.createGenericVirtualRegister(LLT::scalar(32))};
+    MIRBuilder.buildUnmerge(NewRegs, Arg.Regs[0]);
+
+    if (Thunk) {
+      *Thunk = [=]() {
+        assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
+        assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
+      };
+      return 1;
+    }
+    assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
+    assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
+    return 1;
+  }
+
 private:
   MachineInstrBuilder MIB;
 
@@ -170,6 +205,32 @@ struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
     IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA);
   }
 
+  unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
+                             ArrayRef<CCValAssign> VAs,
+                             std::function<void()> *Thunk = nullptr) override {
+    assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
+    const CCValAssign &VALo = VAs[0];
+    const CCValAssign &VAHi = VAs[1];
+
+    assert(VAHi.needsCustom() && "Value doesn't need custom handling");
+    assert(VALo.getValNo() == VAHi.getValNo() &&
+           "Values belong to different arguments");
+
+    assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&
+           VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&
+           "unexpected custom value");
+
+    Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
+                          MRI.createGenericVirtualRegister(LLT::scalar(32))};
+
+    assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
+    assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
+
+    MIRBuilder.buildMergeLikeInstr(Arg.Regs[0], NewRegs);
+
+    return 1;
+  }
+
   /// How the physical register gets marked varies between formal
   /// parameters (it's a basic-block live-in), and a call instruction
   /// (it's an implicit-def of the BL).
@@ -212,6 +273,8 @@ static bool isSupportedArgumentType(Type *T, const RISCVSubtarget &Subtarget) {
   // supported yet.
   if (T->isIntegerTy())
     return T->getIntegerBitWidth() <= Subtarget.getXLen() * 2;
+  if (T->isFloatTy() || T->isDoubleTy())
+    return true;
   if (T->isPointerTy())
     return true;
   return false;
@@ -223,6 +286,8 @@ static bool isSupportedReturnType(Type *T, const RISCVSubtarget &Subtarget) {
   // supported yet.
   if (T->isIntegerTy())
     return T->getIntegerBitWidth() <= Subtarget.getXLen() * 2;
+  if (T->isFloatTy() || T->isDoubleTy())
+    return true;
   if (T->isPointerTy())
     return true;
 
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32-ilp32f-common.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32-ilp32f-common.ll
new file mode 100644
index 000000000000000..8fc77feae2d431d
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32-ilp32f-common.ll
@@ -0,0 +1,75 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+; RUN: llc -mtriple=riscv32 -global-isel -stop-after=irtranslator \
+; RUN:    -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32I %s
+; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi ilp32f \
+; RUN:    -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32I %s
+
+; This file contains tests that should have identical output for the ilp32,
+; and ilp32f.
+
+; Check that on RV32 ilp32[f], double is passed in a pair of registers. Unlike
+; the convention for varargs, this need not be an aligned pair.
+
+define i32 @callee_double_in_regs(i32 %a, double %b) nounwind {
+  ; RV32I-LABEL: name: callee_double_in_regs
+  ; RV32I: bb.1 (%ir-block.0):
+  ; RV32I-NEXT:   liveins: $x10, $x11, $x12
+  ; RV32I-NEXT: {{  $}}
+  ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32I-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+  ; RV32I-NEXT:   [[COPY2:%[0-9]+]]:_(s32) = COPY $x12
+  ; RV32I-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY1]](s32), [[COPY2]](s32)
+  ; RV32I-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[MV]](s64)
+  ; RV32I-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[FPTOSI]]
+  ; RV32I-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32I-NEXT:   PseudoRET implicit $x10
+  %b_fptosi = fptosi double %b to i32
+  %1 = add i32 %a, %b_fptosi
+  ret i32 %1
+}
+
+define i32 @caller_double_in_regs() nounwind {
+  ; RV32I-LABEL: name: caller_double_in_regs
+  ; RV32I: bb.1 (%ir-block.0):
+  ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+  ; RV32I-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00
+  ; RV32I-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C1]](s64)
+  ; RV32I-NEXT:   $x10 = COPY [[C]](s32)
+  ; RV32I-NEXT:   $x11 = COPY [[UV]](s32)
+  ; RV32I-NEXT:   $x12 = COPY [[UV1]](s32)
+  ; RV32I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_in_regs, implicit-def $x1, implicit $x10, implicit $x11, implicit $x12, implicit-def $x10
+  ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32I-NEXT:   $x10 = COPY [[COPY]](s32)
+  ; RV32I-NEXT:   PseudoRET implicit $x10
+  %1 = call i32 @callee_double_in_regs(i32 1, double 2.0)
+  ret i32 %1
+}
+
+define double @callee_small_scalar_ret() nounwind {
+  ; RV32I-LABEL: name: callee_small_scalar_ret
+  ; RV32I: bb.1 (%ir-block.0):
+  ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.000000e+00
+  ; RV32I-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C]](s64)
+  ; RV32I-NEXT:   $x10 = COPY [[UV]](s32)
+  ; RV32I-NEXT:   $x11 = COPY [[UV1]](s32)
+  ; RV32I-NEXT:   PseudoRET implicit $x10, implicit $x11
+  ret double 1.0
+}
+
+define i64 @caller_small_scalar_ret() nounwind {
+  ; RV32I-LABEL: name: caller_small_scalar_ret
+  ; RV32I: bb.1 (%ir-block.0):
+  ; RV32I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_small_scalar_ret, implicit-def $x1, implicit-def $x10, implicit-def $x11
+  ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32I-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+  ; RV32I-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
+  ; RV32I-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[MV]](s64)
+  ; RV32I-NEXT:   $x10 = COPY [[UV]](s32)
+  ; RV32I-NEXT:   $x11 = COPY [[UV1]](s32)
+  ; RV32I-NEXT:   PseudoRET implicit $x10, implicit $x11
+  %1 = call double @callee_small_scalar_ret()
+  %2 = bitcast double %1 to i64
+  ret i64 %2
+}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32.ll
new file mode 100644
index 000000000000000..14eb6af1c4920dd
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32.ll
@@ -0,0 +1,60 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+; RUN: llc -mtriple=riscv32 -global-isel -stop-after=irtranslator \
+; RUN:   -verify-machineinstrs < %s | FileCheck -check-prefix=RV32I %s
+
+; Any tests that would have identical output for some combination of the ilp32*
+; ABIs belong in calling-conv-*-common.ll. This file contains tests that will
+; have different output across those ABIs. i.e. where some arguments would be
+; passed according to the floating point ABI.
+
+define i32 @callee_float_in_regs(i32 %a, float %b) nounwind {
+  ; RV32I-LABEL: name: callee_float_in_regs
+  ; RV32I: bb.1 (%ir-block.0):
+  ; RV32I-NEXT:   liveins: $x10, $x11
+  ; RV32I-NEXT: {{  $}}
+  ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32I-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+  ; RV32I-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[COPY1]](s32)
+  ; RV32I-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[FPTOSI]]
+  ; RV32I-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32I-NEXT:   PseudoRET implicit $x10
+  %b_fptosi = fptosi float %b to i32
+  %1 = add i32 %a, %b_fptosi
+  ret i32 %1
+}
+
+define i32 @caller_float_in_regs() nounwind {
+  ; RV32I-LABEL: name: caller_float_in_regs
+  ; RV32I: bb.1 (%ir-block.0):
+  ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+  ; RV32I-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00
+  ; RV32I-NEXT:   $x10 = COPY [[C]](s32)
+  ; RV32I-NEXT:   $x11 = COPY [[C1]](s32)
+  ; RV32I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_float_in_regs, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10
+  ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32I-NEXT:   $x10 = COPY [[COPY]](s32)
+  ; RV32I-NEXT:   PseudoRET implicit $x10
+  %1 = call i32 @callee_float_in_regs(i32 1, float 2.0)
+  ret i32 %1
+}
+
+define float @callee_tiny_scalar_ret() nounwind {
+  ; RV32I-LABEL: name: callee_tiny_scalar_ret
+  ; RV32I: bb.1 (%ir-block.0):
+  ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.000000e+00
+  ; RV32I-NEXT:   $x10 = COPY [[C]](s32)
+  ; RV32I-NEXT:   PseudoRET implicit $x10
+  ret float 1.0
+}
+
+define i32 @caller_tiny_scalar_ret() nounwind {
+  ; RV32I-LABEL: name: caller_tiny_scalar_ret
+  ; RV32I: bb.1 (%ir-block.0):
+  ; RV32I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_tiny_scalar_ret, implicit-def $x1, implicit-def $x10
+  ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32I-NEXT:   $x10 = COPY [[COPY]](s32)
+  ; RV32I-NEXT:   PseudoRET implicit $x10
+  %1 = call float @callee_tiny_scalar_ret()
+  %2 = bitcast float %1 to i32
+  ret i32 %2
+}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32d.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32d.ll
new file mode 100644
index 000000000000000..0e68699e3dc44a4
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32d.ll
@@ -0,0 +1,122 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32d \
+; RUN:    -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32-ILP32D %s
+
+; This file contains tests that will have differing output for the ilp32/ilp32f
+; and ilp32d ABIs.
+
+define i32 @callee_double_in_fpr(i32 %a, double %b) nounwind {
+  ; RV32-ILP32D-LABEL: name: callee_double_in_fpr
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   liveins: $x10, $f10_d
+  ; RV32-ILP32D-NEXT: {{  $}}
+  ; RV32-ILP32D-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32D-NEXT:   [[COPY1:%[0-9]+]]:_(s64) = COPY $f10_d
+  ; RV32-ILP32D-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[COPY1]](s64)
+  ; RV32-ILP32D-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[FPTOSI]]
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $x10
+  %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: name: caller_double_in_fpr
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+  ; RV32-ILP32D-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[C]](s32)
+  ; RV32-ILP32D-NEXT:   $f10_d = COPY [[C1]](s64)
+  ; RV32-ILP32D-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_in_fpr, implicit-def $x1, implicit $x10, implicit $f10_d, implicit-def $x10
+  ; RV32-ILP32D-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[COPY]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $x10
+  %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_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: name: callee_double_in_gpr_exhausted_fprs
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   liveins: $x10, $x11, $f10_d, $f11_d, $f12_d, $f13_d, $f14_d, $f15_d, $f16_d, $f17_d
+  ; RV32-ILP32D-NEXT: {{  $}}
+  ; RV32-ILP32D-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $f10_d
+  ; RV32-ILP32D-NEXT:   [[COPY1:%[0-9]+]]:_(s64) = COPY $f11_d
+  ; RV32-ILP32D-NEXT:   [[COPY2:%[0-9]+]]:_(s64) = COPY $f12_d
+  ; RV32-ILP32D-NEXT:   [[COPY3:%[0-9]+]]:_(s64) = COPY $f13_d
+  ; RV32-ILP32D-NEXT:   [[COPY4:%[0-9]+]]:_(s64) = COPY $f14_d
+  ; RV32-ILP32D-NEXT:   [[COPY5:%[0-9]+]]:_(s64) = COPY $f15_d
+  ; RV32-ILP32D-NEXT:   [[COPY6:%[0-9]+]]:_(s64) = COPY $f16_d
+  ; RV32-ILP32D-NEXT:   [[COPY7:%[0-9]+]]:_(s64) = COPY $f17_d
+  ; RV32-ILP32D-NEXT:   [[COPY8:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32D-NEXT:   [[COPY9:%[0-9]+]]:_(s32) = COPY $x11
+  ; RV32-ILP32D-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY8]](s32), [[COPY9]](s32)
+  ; RV32-ILP32D-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[COPY7]](s64)
+  ; RV32-ILP32D-NEXT:   [[FPTOSI1:%[0-9]+]]:_(s32) = G_FPTOSI [[MV]](s64)
+  ; RV32-ILP32D-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[FPTOSI]], [[FPTOSI1]]
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $x10
+  %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: name: caller_double_in_gpr_exhausted_fprs
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C2:%[0-9]+]]:_(s64) = G_FCONSTANT double 3.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C3:%[0-9]+]]:_(s64) = G_FCONSTANT double 4.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C4:%[0-9]+]]:_(s64) = G_FCONSTANT double 5.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C5:%[0-9]+]]:_(s64) = G_FCONSTANT double 6.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C6:%[0-9]+]]:_(s64) = G_FCONSTANT double 7.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C7:%[0-9]+]]:_(s64) = G_FCONSTANT double 8.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C8:%[0-9]+]]:_(s64) = G_FCONSTANT double 9.000000e+00
+  ; RV32-ILP32D-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C8]](s64)
+  ; RV32-ILP32D-NEXT:   $f10_d = COPY [[C]](s64)
+  ; RV32-ILP32D-NEXT:   $f11_d = COPY [[C1]](s64)
+  ; RV32-ILP32D-NEXT:   $f12_d = COPY [[C2]](s64)
+  ; RV32-ILP32D-NEXT:   $f13_d = COPY [[C3]](s64)
+  ; RV32-ILP32D-NEXT:   $f14_d = COPY [[C4]](s64)
+  ; RV32-ILP32D-NEXT:   $f15_d = COPY [[C5]](s64)
+  ; RV32-ILP32D-NEXT:   $f16_d = COPY [[C6]](s64)
+  ; RV32-ILP32D-NEXT:   $f17_d = COPY [[C7]](s64)
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[UV]](s32)
+  ; RV32-ILP32D-NEXT:   $x11 = COPY [[UV1]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_in_gpr_exhausted_fprs, implicit-def $x1, implicit $f10_d, implicit $f11_d, implicit $f12_d, implicit $f13_d, implicit $f14_d, implicit $f15_d, implicit $f16_d, implicit $f17_d, implicit $x10, implicit $x11, implicit-def $x10
+  ; RV32-ILP32D-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[COPY]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $x10
+  %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
+}
+
+define double @callee_double_ret() nounwind {
+  ; RV32-ILP32D-LABEL: name: callee_double_ret
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.000000e+00
+  ; RV32-ILP32D-NEXT:   $f10_d = COPY [[C]](s64)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $f10_d
+  ret double 1.0
+}
+
+define i32 @caller_double_ret() nounwind {
+  ; RV32-ILP32D-LABEL: name: caller_double_ret
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_ret, implicit-def $x1, implicit-def $f10_d
+  ; RV32-ILP32D-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $f10_d
+  ; RV32-ILP32D-NEXT:   [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64)
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[TRUNC]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $x10
+  %1 = call double @callee_double_ret()
+  %2 = bitcast double %1 to i64
+  %3 = trunc i64 %2 to i32
+  ret i32 %3
+}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32f-ilp32d-common.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32f-ilp32d-common.ll
new file mode 100644
index 000000000000000..23a20c0356fd4a1
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32f-ilp32d-common.ll
@@ -0,0 +1,119 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi ilp32f \
+; RUN:    -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32-ILP32FD %s
+; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32d \
+; RUN:    -global-isel -stop-after=irtranslator -verify-machineinstrs < %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: name: callee_float_in_fpr
+  ; RV32-ILP32FD: bb.1 (%ir-block.0):
+  ; RV32-ILP32FD-NEXT:   liveins: $x10, $f10_f
+  ; RV32-ILP32FD-NEXT: {{  $}}
+  ; RV32-ILP32FD-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32FD-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $f10_f
+  ; RV32-ILP32FD-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[COPY1]](s32)
+  ; RV32-ILP32FD-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[FPTOSI]]
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoRET implicit $x10
+  %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: name: caller_float_in_fpr
+  ; RV32-ILP32FD: bb.1 (%ir-block.0):
+  ; RV32-ILP32FD-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+  ; RV32-ILP32FD-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[C]](s32)
+  ; RV32-ILP32FD-NEXT:   $f10_f = COPY [[C1]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoCALL target-flags(riscv-call) @callee_float_in_fpr, implicit-def $x1, implicit $x10, implicit $f10_f, implicit-def $x10
+  ; RV32-ILP32FD-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[COPY]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoRET implicit $x10
+  %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_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: name: callee_float_in_gpr_exhausted_fprs
+  ; RV32-ILP32FD: bb.1 (%ir-block.0):
+  ; RV32-ILP32FD-NEXT:   liveins: $x10, $f10_f, $f11_f, $f12_f, $f13_f, $f14_f, $f15_f, $f16_f, $f17_f
+  ; RV32-ILP32FD-NEXT: {{  $}}
+  ; RV32-ILP32FD-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $f10_f
+  ; RV32-ILP32FD-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $f11_f
+  ; RV32-ILP32FD-NEXT:   [[COPY2:%[0-9]+]]:_(s32) = COPY $f12_f
+  ; RV32-ILP32FD-NEXT:   [[COPY3:%[0-9]+]]:_(s32) = COPY $f13_f
+  ; RV32-ILP32FD-NEXT:   [[COPY4:%[0-9]+]]:_(s32) = COPY $f14_f
+  ; RV32-ILP32FD-NEXT:   [[COPY5:%[0-9]+]]:_(s32) = COPY $f15_f
+  ; RV32-ILP32FD-NEXT:   [[COPY6:%[0-9]+]]:_(s32) = COPY $f16_f
+  ; RV32-ILP32FD-NEXT:   [[COPY7:%[0-9]+]]:_(s32) = COPY $f17_f
+  ; RV32-ILP32FD-NEXT:   [[COPY8:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32FD-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[COPY7]](s32)
+  ; RV32-ILP32FD-NEXT:   [[FPTOSI1:%[0-9]+]]:_(s32) = G_FPTOSI [[COPY8]](s32)
+  ; RV32-ILP32FD-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[FPTOSI]], [[FPTOSI1]]
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoRET implicit $x10
+  %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: name: caller_float_in_gpr_exhausted_fprs
+  ; RV32-ILP32FD: bb.1 (%ir-block.0):
+  ; RV32-ILP32FD-NEXT:   [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C2:%[0-9]+]]:_(s32) = G_FCONSTANT float 3.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C3:%[0-9]+]]:_(s32) = G_FCONSTANT float 4.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C4:%[0-9]+]]:_(s32) = G_FCONSTANT float 5.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C5:%[0-9]+]]:_(s32) = G_FCONSTANT float 6.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C6:%[0-9]+]]:_(s32) = G_FCONSTANT float 7.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C7:%[0-9]+]]:_(s32) = G_FCONSTANT float 8.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C8:%[0-9]+]]:_(s32) = G_FCONSTANT float 9.000000e+00
+  ; RV32-ILP32FD-NEXT:   $f10_f = COPY [[C]](s32)
+  ; RV32-ILP32FD-NEXT:   $f11_f = COPY [[C1]](s32)
+  ; RV32-ILP32FD-NEXT:   $f12_f = COPY [[C2]](s32)
+  ; RV32-ILP32FD-NEXT:   $f13_f = COPY [[C3]](s32)
+  ; RV32-ILP32FD-NEXT:   $f14_f = COPY [[C4]](s32)
+  ; RV32-ILP32FD-NEXT:   $f15_f = COPY [[C5]](s32)
+  ; RV32-ILP32FD-NEXT:   $f16_f = COPY [[C6]](s32)
+  ; RV32-ILP32FD-NEXT:   $f17_f = COPY [[C7]](s32)
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[C8]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoCALL target-flags(riscv-call) @callee_float_in_gpr_exhausted_fprs, implicit-def $x1, implicit $f10_f, implicit $f11_f, implicit $f12_f, implicit $f13_f, implicit $f14_f, implicit $f15_f, implicit $f16_f, implicit $f17_f, implicit $x10, implicit-def $x10
+  ; RV32-ILP32FD-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[COPY]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoRET implicit $x10
+  %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
+}
+
+define float @callee_float_ret() nounwind {
+  ; RV32-ILP32FD-LABEL: name: callee_float_ret
+  ; RV32-ILP32FD: bb.1 (%ir-block.0):
+  ; RV32-ILP32FD-NEXT:   [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.000000e+00
+  ; RV32-ILP32FD-NEXT:   $f10_f = COPY [[C]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoRET implicit $f10_f
+  ret float 1.0
+}
+
+define i32 @caller_float_ret() nounwind {
+  ; RV32-ILP32FD-LABEL: name: caller_float_ret
+  ; RV32-ILP32FD: bb.1 (%ir-block.0):
+  ; RV32-ILP32FD-NEXT:   PseudoCALL target-flags(riscv-call) @callee_float_ret, implicit-def $x1, implicit-def $f10_f
+  ; RV32-ILP32FD-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $f10_f
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[COPY]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoRET implicit $x10
+  %1 = call float @callee_float_ret()
+  %2 = bitcast float %1 to i32
+  ret i32 %2
+}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64-lp64f-common.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64-lp64f-common.ll
new file mode 100644
index 000000000000000..4d6275db77bc895
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64-lp64f-common.ll
@@ -0,0 +1,62 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+; RUN: llc -mtriple=riscv64 \
+; RUN:     -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I %s
+; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi lp64f \
+; RUN:    -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I %s
+
+; This file contains tests that should have identical output for the lp64 and
+; lp64f ABIs.
+
+define i64 @callee_double_in_regs(i64 %a, double %b) nounwind {
+  ; RV64I-LABEL: name: callee_double_in_regs
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   liveins: $x10, $x11
+  ; RV64I-NEXT: {{  $}}
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   [[COPY1:%[0-9]+]]:_(s64) = COPY $x11
+  ; RV64I-NEXT:   [[FPTOSI:%[0-9]+]]:_(s64) = G_FPTOSI [[COPY1]](s64)
+  ; RV64I-NEXT:   [[ADD:%[0-9]+]]:_(s64) = G_ADD [[COPY]], [[FPTOSI]]
+  ; RV64I-NEXT:   $x10 = COPY [[ADD]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %b_fptosi = fptosi double %b to i64
+  %1 = add i64 %a, %b_fptosi
+  ret i64 %1
+}
+
+define i64 @caller_double_in_regs() nounwind {
+  ; RV64I-LABEL: name: caller_double_in_regs
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+  ; RV64I-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00
+  ; RV64I-NEXT:   $x10 = COPY [[C]](s64)
+  ; RV64I-NEXT:   $x11 = COPY [[C1]](s64)
+  ; RV64I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_in_regs, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   $x10 = COPY [[COPY]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %1 = call i64 @callee_double_in_regs(i64 1, double 2.0)
+  ret i64 %1
+}
+
+define double @callee_double_ret() nounwind {
+  ; RV64I-LABEL: name: callee_double_ret
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.000000e+00
+  ; RV64I-NEXT:   $x10 = COPY [[C]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  ret double 1.0
+}
+
+define i64 @caller_double_ret() nounwind {
+  ; RV64I-LABEL: name: caller_double_ret
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_ret, implicit-def $x1, implicit-def $x10
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   $x10 = COPY [[COPY]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %1 = call double @callee_double_ret()
+  %2 = bitcast double %1 to i64
+  ret i64 %2
+}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64.ll
new file mode 100644
index 000000000000000..a45af04c09b21c6
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64.ll
@@ -0,0 +1,82 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+; RUN: llc -mtriple=riscv64 -global-isel -stop-after=irtranslator \
+; RUN:    -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV64,RV64I %s
+; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi=lp64 \
+; RUN:    -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefixes=RV64,RV64F %s
+
+; Any tests that would have identical output for some combination of the lp64*
+; ABIs belong in calling-conv-*-common.ll. This file contains tests that will
+; have different output across those ABIs. i.e. where some arguments would be
+; passed according to the floating point ABI.
+
+define i64 @callee_float_in_regs(i64 %a, float %b) nounwind {
+  ; RV64-LABEL: name: callee_float_in_regs
+  ; RV64: bb.1 (%ir-block.0):
+  ; RV64-NEXT:   liveins: $x10, $x11
+  ; RV64-NEXT: {{  $}}
+  ; RV64-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64-NEXT:   [[COPY1:%[0-9]+]]:_(s64) = COPY $x11
+  ; RV64-NEXT:   [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64)
+  ; RV64-NEXT:   [[FPTOSI:%[0-9]+]]:_(s64) = G_FPTOSI [[TRUNC]](s32)
+  ; RV64-NEXT:   [[ADD:%[0-9]+]]:_(s64) = G_ADD [[COPY]], [[FPTOSI]]
+  ; RV64-NEXT:   $x10 = COPY [[ADD]](s64)
+  ; RV64-NEXT:   PseudoRET implicit $x10
+  %b_fptosi = fptosi float %b to i64
+  %1 = add i64 %a, %b_fptosi
+  ret i64 %1
+}
+
+define i64 @caller_float_in_regs() nounwind {
+  ; RV64I-LABEL: name: caller_float_in_regs
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+  ; RV64I-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00
+  ; RV64I-NEXT:   [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[C1]](s32)
+  ; RV64I-NEXT:   $x10 = COPY [[C]](s64)
+  ; RV64I-NEXT:   $x11 = COPY [[ANYEXT]](s64)
+  ; RV64I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_float_in_regs, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   $x10 = COPY [[COPY]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  ;
+  ; RV64F-LABEL: name: caller_float_in_regs
+  ; RV64F: bb.1 (%ir-block.0):
+  ; RV64F-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+  ; RV64F-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00
+  ; RV64F-NEXT:   $x10 = COPY [[C]](s64)
+  ; RV64F-NEXT:   [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[C1]](s32)
+  ; RV64F-NEXT:   $x11 = COPY [[ANYEXT]](s64)
+  ; RV64F-NEXT:   PseudoCALL target-flags(riscv-call) @callee_float_in_regs, implicit-def $x1, implicit $x10, implicit $x11, implicit-def $x10
+  ; RV64F-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64F-NEXT:   $x10 = COPY [[COPY]](s64)
+  ; RV64F-NEXT:   PseudoRET implicit $x10
+  %1 = call i64 @callee_float_in_regs(i64 1, float 2.0)
+  ret i64 %1
+}
+
+define float @callee_tiny_scalar_ret() nounwind {
+  ; RV64-LABEL: name: callee_tiny_scalar_ret
+  ; RV64: bb.1 (%ir-block.0):
+  ; RV64-NEXT:   [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.000000e+00
+  ; RV64-NEXT:   [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[C]](s32)
+  ; RV64-NEXT:   $x10 = COPY [[ANYEXT]](s64)
+  ; RV64-NEXT:   PseudoRET implicit $x10
+  ret float 1.0
+}
+
+define i64 @caller_tiny_scalar_ret() nounwind {
+  ; RV64-LABEL: name: caller_tiny_scalar_ret
+  ; RV64: bb.1 (%ir-block.0):
+  ; RV64-NEXT:   PseudoCALL target-flags(riscv-call) @callee_tiny_scalar_ret, implicit-def $x1, implicit-def $x10
+  ; RV64-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64-NEXT:   [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64)
+  ; RV64-NEXT:   [[SEXT:%[0-9]+]]:_(s64) = G_SEXT [[TRUNC]](s32)
+  ; RV64-NEXT:   $x10 = COPY [[SEXT]](s64)
+  ; RV64-NEXT:   PseudoRET implicit $x10
+  %1 = call float @callee_tiny_scalar_ret()
+  %2 = bitcast float %1 to i32
+  %3 = sext i32 %2 to i64
+  ret i64 %3
+}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64d.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64d.ll
new file mode 100644
index 000000000000000..de465147a4a692f
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64d.ll
@@ -0,0 +1,59 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi lp64d \
+; RUN:    -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I %s
+
+; This file contains tests that should have identical output for the lp64 and
+; lp64f ABIs.
+
+define i64 @callee_double_in_regs(i64 %a, double %b) nounwind {
+  ; RV64I-LABEL: name: callee_double_in_regs
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   liveins: $x10, $f10_d
+  ; RV64I-NEXT: {{  $}}
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   [[COPY1:%[0-9]+]]:_(s64) = COPY $f10_d
+  ; RV64I-NEXT:   [[FPTOSI:%[0-9]+]]:_(s64) = G_FPTOSI [[COPY1]](s64)
+  ; RV64I-NEXT:   [[ADD:%[0-9]+]]:_(s64) = G_ADD [[COPY]], [[FPTOSI]]
+  ; RV64I-NEXT:   $x10 = COPY [[ADD]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %b_fptosi = fptosi double %b to i64
+  %1 = add i64 %a, %b_fptosi
+  ret i64 %1
+}
+
+define i64 @caller_double_in_regs() nounwind {
+  ; RV64I-LABEL: name: caller_double_in_regs
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+  ; RV64I-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00
+  ; RV64I-NEXT:   $x10 = COPY [[C]](s64)
+  ; RV64I-NEXT:   $f10_d = COPY [[C1]](s64)
+  ; RV64I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_in_regs, implicit-def $x1, implicit $x10, implicit $f10_d, implicit-def $x10
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   $x10 = COPY [[COPY]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %1 = call i64 @callee_double_in_regs(i64 1, double 2.0)
+  ret i64 %1
+}
+
+define double @callee_double_ret() nounwind {
+  ; RV64I-LABEL: name: callee_double_ret
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.000000e+00
+  ; RV64I-NEXT:   $f10_d = COPY [[C]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $f10_d
+  ret double 1.0
+}
+
+define i64 @caller_double_ret() nounwind {
+  ; RV64I-LABEL: name: caller_double_ret
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_ret, implicit-def $x1, implicit-def $f10_d
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $f10_d
+  ; RV64I-NEXT:   $x10 = COPY [[COPY]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %1 = call double @callee_double_ret()
+  %2 = bitcast double %1 to i64
+  ret i64 %2
+}

>From c504d922186eab64cfa53bb21ec44f5708afa8bc Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Fri, 20 Oct 2023 18:24:01 -0700
Subject: [PATCH 2/2] [RISCV][GISel] Add FP calling convention support using
 stack.

This builds on the register support to add stack support.
---
 .../Target/RISCV/GISel/RISCVCallLowering.cpp  |  42 ++-
 .../irtranslator/calling-conv-ilp32.ll        |  61 +++++
 .../irtranslator/calling-conv-ilp32d.ll       | 242 ++++++++++++++++++
 .../calling-conv-ilp32f-ilp32d-common.ll      | 154 +++++++++++
 .../irtranslator/calling-conv-lp64d.ll        | 214 ++++++++++++++++
 5 files changed, 705 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp b/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
index cbdcfc60c4a8267..1bbfec639862ee5 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
@@ -122,15 +122,29 @@ struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler {
                           MRI.createGenericVirtualRegister(LLT::scalar(32))};
     MIRBuilder.buildUnmerge(NewRegs, Arg.Regs[0]);
 
-    if (Thunk) {
-      *Thunk = [=]() {
-        assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
+    if (VAHi.isMemLoc()) {
+      LLT MemTy(VAHi.getLocVT());
+
+      MachinePointerInfo MPO;
+      Register StackAddr = getStackAddress(
+          MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
+
+      assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
+                           const_cast<CCValAssign &>(VAHi));
+    }
+
+    auto assignFunc = [=]() {
+      assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
+      if (VAHi.isRegLoc())
         assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
-      };
+    };
+
+    if (Thunk) {
+      *Thunk = assignFunc;
       return 1;
     }
-    assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
-    assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
+
+    assignFunc();
     return 1;
   }
 
@@ -207,7 +221,7 @@ struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
 
   unsigned assignCustomValue(CallLowering::ArgInfo &Arg,
                              ArrayRef<CCValAssign> VAs,
-                             std::function<void()> *Thunk = nullptr) override {
+                             std::function<void()> *Thunk) override {
     assert(VAs.size() >= 2 && "Expected at least 2 VAs.");
     const CCValAssign &VALo = VAs[0];
     const CCValAssign &VAHi = VAs[1];
@@ -223,8 +237,20 @@ struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler {
     Register NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
                           MRI.createGenericVirtualRegister(LLT::scalar(32))};
 
+    if (VAHi.isMemLoc()) {
+      LLT MemTy(VAHi.getLocVT());
+
+      MachinePointerInfo MPO;
+      Register StackAddr = getStackAddress(
+          MemTy.getSizeInBytes(), VAHi.getLocMemOffset(), MPO, Arg.Flags[0]);
+
+      assignValueToAddress(NewRegs[1], StackAddr, MemTy, MPO,
+                           const_cast<CCValAssign &>(VAHi));
+    }
+
     assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
-    assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
+    if (VAHi.isRegLoc())
+      assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
 
     MIRBuilder.buildMergeLikeInstr(Arg.Regs[0], NewRegs);
 
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32.ll
index 14eb6af1c4920dd..3b4aca1e6953dac 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32.ll
@@ -38,6 +38,67 @@ define i32 @caller_float_in_regs() nounwind {
   ret i32 %1
 }
 
+define i32 @callee_float_on_stack(i64 %a, i64 %b, i64 %c, i64 %d, float %e) nounwind {
+  ; RV32I-LABEL: name: callee_float_on_stack
+  ; RV32I: bb.1 (%ir-block.0):
+  ; RV32I-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
+  ; RV32I-NEXT: {{  $}}
+  ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32I-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+  ; RV32I-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
+  ; RV32I-NEXT:   [[COPY2:%[0-9]+]]:_(s32) = COPY $x12
+  ; RV32I-NEXT:   [[COPY3:%[0-9]+]]:_(s32) = COPY $x13
+  ; RV32I-NEXT:   [[MV1:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY2]](s32), [[COPY3]](s32)
+  ; RV32I-NEXT:   [[COPY4:%[0-9]+]]:_(s32) = COPY $x14
+  ; RV32I-NEXT:   [[COPY5:%[0-9]+]]:_(s32) = COPY $x15
+  ; RV32I-NEXT:   [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY4]](s32), [[COPY5]](s32)
+  ; RV32I-NEXT:   [[COPY6:%[0-9]+]]:_(s32) = COPY $x16
+  ; RV32I-NEXT:   [[COPY7:%[0-9]+]]:_(s32) = COPY $x17
+  ; RV32I-NEXT:   [[MV3:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY6]](s32), [[COPY7]](s32)
+  ; RV32I-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; RV32I-NEXT:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s32) from %fixed-stack.0, align 16)
+  ; RV32I-NEXT:   [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[MV3]](s64)
+  ; RV32I-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[TRUNC]], [[LOAD]]
+  ; RV32I-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32I-NEXT:   PseudoRET implicit $x10
+  %1 = trunc i64 %d to i32
+  %2 = bitcast float %e to i32
+  %3 = add i32 %1, %2
+  ret i32 %3
+}
+
+define i32 @caller_float_on_stack() nounwind {
+  ; RV32I-LABEL: name: caller_float_on_stack
+  ; RV32I: bb.1 (%ir-block.0):
+  ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+  ; RV32I-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
+  ; RV32I-NEXT:   [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
+  ; RV32I-NEXT:   [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
+  ; RV32I-NEXT:   [[C4:%[0-9]+]]:_(s32) = G_FCONSTANT float 5.000000e+00
+  ; RV32I-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C]](s64)
+  ; RV32I-NEXT:   [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C1]](s64)
+  ; RV32I-NEXT:   [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C2]](s64)
+  ; RV32I-NEXT:   [[UV6:%[0-9]+]]:_(s32), [[UV7:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C3]](s64)
+  ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $x2
+  ; RV32I-NEXT:   [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; RV32I-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C5]](s32)
+  ; RV32I-NEXT:   G_STORE [[C4]](s32), [[PTR_ADD]](p0) :: (store (s32) into stack, align 16)
+  ; RV32I-NEXT:   $x10 = COPY [[UV]](s32)
+  ; RV32I-NEXT:   $x11 = COPY [[UV1]](s32)
+  ; RV32I-NEXT:   $x12 = COPY [[UV2]](s32)
+  ; RV32I-NEXT:   $x13 = COPY [[UV3]](s32)
+  ; RV32I-NEXT:   $x14 = COPY [[UV4]](s32)
+  ; RV32I-NEXT:   $x15 = COPY [[UV5]](s32)
+  ; RV32I-NEXT:   $x16 = COPY [[UV6]](s32)
+  ; RV32I-NEXT:   $x17 = COPY [[UV7]](s32)
+  ; RV32I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_float_on_stack, implicit-def $x1, implicit $x10, implicit $x11, implicit $x12, implicit $x13, implicit $x14, implicit $x15, implicit $x16, implicit $x17, implicit-def $x10
+  ; RV32I-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32I-NEXT:   $x10 = COPY [[COPY1]](s32)
+  ; RV32I-NEXT:   PseudoRET implicit $x10
+  %1 = call i32 @callee_float_on_stack(i64 1, i64 2, i64 3, i64 4, float 5.0)
+  ret i32 %1
+}
+
 define float @callee_tiny_scalar_ret() nounwind {
   ; RV32I-LABEL: name: callee_tiny_scalar_ret
   ; RV32I: bb.1 (%ir-block.0):
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32d.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32d.ll
index 0e68699e3dc44a4..e33e279f7f48978 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32d.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32d.ll
@@ -37,6 +37,71 @@ define i32 @caller_double_in_fpr() nounwind {
   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: name: callee_double_in_fpr_exhausted_gprs
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $f10_d
+  ; RV32-ILP32D-NEXT: {{  $}}
+  ; RV32-ILP32D-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32D-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+  ; RV32-ILP32D-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
+  ; RV32-ILP32D-NEXT:   [[COPY2:%[0-9]+]]:_(s32) = COPY $x12
+  ; RV32-ILP32D-NEXT:   [[COPY3:%[0-9]+]]:_(s32) = COPY $x13
+  ; RV32-ILP32D-NEXT:   [[MV1:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY2]](s32), [[COPY3]](s32)
+  ; RV32-ILP32D-NEXT:   [[COPY4:%[0-9]+]]:_(s32) = COPY $x14
+  ; RV32-ILP32D-NEXT:   [[COPY5:%[0-9]+]]:_(s32) = COPY $x15
+  ; RV32-ILP32D-NEXT:   [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY4]](s32), [[COPY5]](s32)
+  ; RV32-ILP32D-NEXT:   [[COPY6:%[0-9]+]]:_(s32) = COPY $x16
+  ; RV32-ILP32D-NEXT:   [[COPY7:%[0-9]+]]:_(s32) = COPY $x17
+  ; RV32-ILP32D-NEXT:   [[MV3:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY6]](s32), [[COPY7]](s32)
+  ; RV32-ILP32D-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; RV32-ILP32D-NEXT:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s32) from %fixed-stack.0, align 16)
+  ; RV32-ILP32D-NEXT:   [[COPY8:%[0-9]+]]:_(s64) = COPY $f10_d
+  ; RV32-ILP32D-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[COPY8]](s64)
+  ; RV32-ILP32D-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[LOAD]], [[FPTOSI]]
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $x10
+  %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: name: caller_double_in_fpr_exhausted_gprs
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+  ; RV32-ILP32D-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
+  ; RV32-ILP32D-NEXT:   [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
+  ; RV32-ILP32D-NEXT:   [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
+  ; RV32-ILP32D-NEXT:   [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
+  ; RV32-ILP32D-NEXT:   [[C5:%[0-9]+]]:_(s64) = G_FCONSTANT double 6.000000e+00
+  ; RV32-ILP32D-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C]](s64)
+  ; RV32-ILP32D-NEXT:   [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C1]](s64)
+  ; RV32-ILP32D-NEXT:   [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C2]](s64)
+  ; RV32-ILP32D-NEXT:   [[UV6:%[0-9]+]]:_(s32), [[UV7:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C3]](s64)
+  ; RV32-ILP32D-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $x2
+  ; RV32-ILP32D-NEXT:   [[C6:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; RV32-ILP32D-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C6]](s32)
+  ; RV32-ILP32D-NEXT:   G_STORE [[C4]](s32), [[PTR_ADD]](p0) :: (store (s32) into stack, align 16)
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[UV]](s32)
+  ; RV32-ILP32D-NEXT:   $x11 = COPY [[UV1]](s32)
+  ; RV32-ILP32D-NEXT:   $x12 = COPY [[UV2]](s32)
+  ; RV32-ILP32D-NEXT:   $x13 = COPY [[UV3]](s32)
+  ; RV32-ILP32D-NEXT:   $x14 = COPY [[UV4]](s32)
+  ; RV32-ILP32D-NEXT:   $x15 = COPY [[UV5]](s32)
+  ; RV32-ILP32D-NEXT:   $x16 = COPY [[UV6]](s32)
+  ; RV32-ILP32D-NEXT:   $x17 = COPY [[UV7]](s32)
+  ; RV32-ILP32D-NEXT:   $f10_d = COPY [[C5]](s64)
+  ; RV32-ILP32D-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_in_fpr_exhausted_gprs, implicit-def $x1, implicit $x10, implicit $x11, implicit $x12, implicit $x13, implicit $x14, implicit $x15, implicit $x16, implicit $x17, implicit $f10_d, implicit-def $x10
+  ; RV32-ILP32D-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[COPY1]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $x10
+  %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: name: callee_double_in_gpr_exhausted_fprs
@@ -98,6 +163,183 @@ define i32 @caller_double_in_gpr_exhausted_fprs() nounwind {
   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: name: callee_double_in_gpr_and_stack_almost_exhausted_gprs_fprs
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $f10_d, $f11_d, $f12_d, $f13_d, $f14_d, $f15_d, $f16_d, $f17_d
+  ; RV32-ILP32D-NEXT: {{  $}}
+  ; RV32-ILP32D-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32D-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+  ; RV32-ILP32D-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
+  ; RV32-ILP32D-NEXT:   [[COPY2:%[0-9]+]]:_(s64) = COPY $f10_d
+  ; RV32-ILP32D-NEXT:   [[COPY3:%[0-9]+]]:_(s32) = COPY $x12
+  ; RV32-ILP32D-NEXT:   [[COPY4:%[0-9]+]]:_(s32) = COPY $x13
+  ; RV32-ILP32D-NEXT:   [[MV1:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY3]](s32), [[COPY4]](s32)
+  ; RV32-ILP32D-NEXT:   [[COPY5:%[0-9]+]]:_(s64) = COPY $f11_d
+  ; RV32-ILP32D-NEXT:   [[COPY6:%[0-9]+]]:_(s32) = COPY $x14
+  ; RV32-ILP32D-NEXT:   [[COPY7:%[0-9]+]]:_(s32) = COPY $x15
+  ; RV32-ILP32D-NEXT:   [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY6]](s32), [[COPY7]](s32)
+  ; RV32-ILP32D-NEXT:   [[COPY8:%[0-9]+]]:_(s64) = COPY $f12_d
+  ; RV32-ILP32D-NEXT:   [[COPY9:%[0-9]+]]:_(s32) = COPY $x16
+  ; RV32-ILP32D-NEXT:   [[COPY10:%[0-9]+]]:_(s64) = COPY $f13_d
+  ; RV32-ILP32D-NEXT:   [[COPY11:%[0-9]+]]:_(s64) = COPY $f14_d
+  ; RV32-ILP32D-NEXT:   [[COPY12:%[0-9]+]]:_(s64) = COPY $f15_d
+  ; RV32-ILP32D-NEXT:   [[COPY13:%[0-9]+]]:_(s64) = COPY $f16_d
+  ; RV32-ILP32D-NEXT:   [[COPY14:%[0-9]+]]:_(s64) = COPY $f17_d
+  ; RV32-ILP32D-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; RV32-ILP32D-NEXT:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s32) from %fixed-stack.0, align 16)
+  ; RV32-ILP32D-NEXT:   [[COPY15:%[0-9]+]]:_(s32) = COPY $x17
+  ; RV32-ILP32D-NEXT:   [[MV3:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY15]](s32), [[LOAD]](s32)
+  ; RV32-ILP32D-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[MV3]](s64)
+  ; RV32-ILP32D-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY9]], [[FPTOSI]]
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $x10
+  %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: name: caller_double_in_gpr_and_stack_almost_exhausted_gprs_fprs
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+  ; RV32-ILP32D-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
+  ; RV32-ILP32D-NEXT:   [[C3:%[0-9]+]]:_(s64) = G_FCONSTANT double 4.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C4:%[0-9]+]]:_(s64) = G_CONSTANT i64 5
+  ; RV32-ILP32D-NEXT:   [[C5:%[0-9]+]]:_(s64) = G_FCONSTANT double 6.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C6:%[0-9]+]]:_(s32) = G_CONSTANT i32 7
+  ; RV32-ILP32D-NEXT:   [[C7:%[0-9]+]]:_(s64) = G_FCONSTANT double 8.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C8:%[0-9]+]]:_(s64) = G_FCONSTANT double 9.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C9:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.000000e+01
+  ; RV32-ILP32D-NEXT:   [[C10:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.100000e+01
+  ; RV32-ILP32D-NEXT:   [[C11:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.200000e+01
+  ; RV32-ILP32D-NEXT:   [[C12:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.300000e+01
+  ; RV32-ILP32D-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C]](s64)
+  ; RV32-ILP32D-NEXT:   [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C2]](s64)
+  ; RV32-ILP32D-NEXT:   [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C4]](s64)
+  ; RV32-ILP32D-NEXT:   [[UV6:%[0-9]+]]:_(s32), [[UV7:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C12]](s64)
+  ; RV32-ILP32D-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $x2
+  ; RV32-ILP32D-NEXT:   [[C13:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; RV32-ILP32D-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C13]](s32)
+  ; RV32-ILP32D-NEXT:   G_STORE [[UV7]](s32), [[PTR_ADD]](p0) :: (store (s32) into stack, align 16)
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[UV]](s32)
+  ; RV32-ILP32D-NEXT:   $x11 = COPY [[UV1]](s32)
+  ; RV32-ILP32D-NEXT:   $f10_d = COPY [[C1]](s64)
+  ; RV32-ILP32D-NEXT:   $x12 = COPY [[UV2]](s32)
+  ; RV32-ILP32D-NEXT:   $x13 = COPY [[UV3]](s32)
+  ; RV32-ILP32D-NEXT:   $f11_d = COPY [[C3]](s64)
+  ; RV32-ILP32D-NEXT:   $x14 = COPY [[UV4]](s32)
+  ; RV32-ILP32D-NEXT:   $x15 = COPY [[UV5]](s32)
+  ; RV32-ILP32D-NEXT:   $f12_d = COPY [[C5]](s64)
+  ; RV32-ILP32D-NEXT:   $x16 = COPY [[C6]](s32)
+  ; RV32-ILP32D-NEXT:   $f13_d = COPY [[C7]](s64)
+  ; RV32-ILP32D-NEXT:   $f14_d = COPY [[C8]](s64)
+  ; RV32-ILP32D-NEXT:   $f15_d = COPY [[C9]](s64)
+  ; RV32-ILP32D-NEXT:   $f16_d = COPY [[C10]](s64)
+  ; RV32-ILP32D-NEXT:   $f17_d = COPY [[C11]](s64)
+  ; RV32-ILP32D-NEXT:   $x17 = COPY [[UV6]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_in_gpr_and_stack_almost_exhausted_gprs_fprs, implicit-def $x1, implicit $x10, implicit $x11, implicit $f10_d, implicit $x12, implicit $x13, implicit $f11_d, implicit $x14, implicit $x15, implicit $f12_d, implicit $x16, implicit $f13_d, implicit $f14_d, implicit $f15_d, implicit $f16_d, implicit $f17_d, implicit $x17, implicit-def $x10
+  ; RV32-ILP32D-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[COPY1]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $x10
+  %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: name: callee_double_on_stack_exhausted_gprs_fprs
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $f10_d, $f11_d, $f12_d, $f13_d, $f14_d, $f15_d, $f16_d, $f17_d
+  ; RV32-ILP32D-NEXT: {{  $}}
+  ; RV32-ILP32D-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32D-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+  ; RV32-ILP32D-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
+  ; RV32-ILP32D-NEXT:   [[COPY2:%[0-9]+]]:_(s64) = COPY $f10_d
+  ; RV32-ILP32D-NEXT:   [[COPY3:%[0-9]+]]:_(s32) = COPY $x12
+  ; RV32-ILP32D-NEXT:   [[COPY4:%[0-9]+]]:_(s32) = COPY $x13
+  ; RV32-ILP32D-NEXT:   [[MV1:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY3]](s32), [[COPY4]](s32)
+  ; RV32-ILP32D-NEXT:   [[COPY5:%[0-9]+]]:_(s64) = COPY $f11_d
+  ; RV32-ILP32D-NEXT:   [[COPY6:%[0-9]+]]:_(s32) = COPY $x14
+  ; RV32-ILP32D-NEXT:   [[COPY7:%[0-9]+]]:_(s32) = COPY $x15
+  ; RV32-ILP32D-NEXT:   [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY6]](s32), [[COPY7]](s32)
+  ; RV32-ILP32D-NEXT:   [[COPY8:%[0-9]+]]:_(s64) = COPY $f12_d
+  ; RV32-ILP32D-NEXT:   [[COPY9:%[0-9]+]]:_(s32) = COPY $x16
+  ; RV32-ILP32D-NEXT:   [[COPY10:%[0-9]+]]:_(s32) = COPY $x17
+  ; RV32-ILP32D-NEXT:   [[MV3:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY9]](s32), [[COPY10]](s32)
+  ; RV32-ILP32D-NEXT:   [[COPY11:%[0-9]+]]:_(s64) = COPY $f13_d
+  ; RV32-ILP32D-NEXT:   [[COPY12:%[0-9]+]]:_(s64) = COPY $f14_d
+  ; RV32-ILP32D-NEXT:   [[COPY13:%[0-9]+]]:_(s64) = COPY $f15_d
+  ; RV32-ILP32D-NEXT:   [[COPY14:%[0-9]+]]:_(s64) = COPY $f16_d
+  ; RV32-ILP32D-NEXT:   [[COPY15:%[0-9]+]]:_(s64) = COPY $f17_d
+  ; RV32-ILP32D-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; RV32-ILP32D-NEXT:   [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s64) from %fixed-stack.0, align 16)
+  ; RV32-ILP32D-NEXT:   [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[MV3]](s64)
+  ; RV32-ILP32D-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[LOAD]](s64)
+  ; RV32-ILP32D-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[TRUNC]], [[FPTOSI]]
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $x10
+  %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: name: caller_double_on_stack_exhausted_gprs_fprs
+  ; RV32-ILP32D: bb.1 (%ir-block.0):
+  ; RV32-ILP32D-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+  ; RV32-ILP32D-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
+  ; RV32-ILP32D-NEXT:   [[C3:%[0-9]+]]:_(s64) = G_FCONSTANT double 4.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C4:%[0-9]+]]:_(s64) = G_CONSTANT i64 5
+  ; RV32-ILP32D-NEXT:   [[C5:%[0-9]+]]:_(s64) = G_FCONSTANT double 6.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C6:%[0-9]+]]:_(s64) = G_CONSTANT i64 7
+  ; RV32-ILP32D-NEXT:   [[C7:%[0-9]+]]:_(s64) = G_FCONSTANT double 8.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C8:%[0-9]+]]:_(s64) = G_FCONSTANT double 9.000000e+00
+  ; RV32-ILP32D-NEXT:   [[C9:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.000000e+01
+  ; RV32-ILP32D-NEXT:   [[C10:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.100000e+01
+  ; RV32-ILP32D-NEXT:   [[C11:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.200000e+01
+  ; RV32-ILP32D-NEXT:   [[C12:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.300000e+01
+  ; RV32-ILP32D-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C]](s64)
+  ; RV32-ILP32D-NEXT:   [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C2]](s64)
+  ; RV32-ILP32D-NEXT:   [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C4]](s64)
+  ; RV32-ILP32D-NEXT:   [[UV6:%[0-9]+]]:_(s32), [[UV7:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C6]](s64)
+  ; RV32-ILP32D-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $x2
+  ; RV32-ILP32D-NEXT:   [[C13:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; RV32-ILP32D-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C13]](s32)
+  ; RV32-ILP32D-NEXT:   G_STORE [[C12]](s64), [[PTR_ADD]](p0) :: (store (s64) into stack, align 16)
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[UV]](s32)
+  ; RV32-ILP32D-NEXT:   $x11 = COPY [[UV1]](s32)
+  ; RV32-ILP32D-NEXT:   $f10_d = COPY [[C1]](s64)
+  ; RV32-ILP32D-NEXT:   $x12 = COPY [[UV2]](s32)
+  ; RV32-ILP32D-NEXT:   $x13 = COPY [[UV3]](s32)
+  ; RV32-ILP32D-NEXT:   $f11_d = COPY [[C3]](s64)
+  ; RV32-ILP32D-NEXT:   $x14 = COPY [[UV4]](s32)
+  ; RV32-ILP32D-NEXT:   $x15 = COPY [[UV5]](s32)
+  ; RV32-ILP32D-NEXT:   $f12_d = COPY [[C5]](s64)
+  ; RV32-ILP32D-NEXT:   $x16 = COPY [[UV6]](s32)
+  ; RV32-ILP32D-NEXT:   $x17 = COPY [[UV7]](s32)
+  ; RV32-ILP32D-NEXT:   $f13_d = COPY [[C7]](s64)
+  ; RV32-ILP32D-NEXT:   $f14_d = COPY [[C8]](s64)
+  ; RV32-ILP32D-NEXT:   $f15_d = COPY [[C9]](s64)
+  ; RV32-ILP32D-NEXT:   $f16_d = COPY [[C10]](s64)
+  ; RV32-ILP32D-NEXT:   $f17_d = COPY [[C11]](s64)
+  ; RV32-ILP32D-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_on_stack_exhausted_gprs_fprs, implicit-def $x1, implicit $x10, implicit $x11, implicit $f10_d, implicit $x12, implicit $x13, implicit $f11_d, implicit $x14, implicit $x15, implicit $f12_d, implicit $x16, implicit $x17, implicit $f13_d, implicit $f14_d, implicit $f15_d, implicit $f16_d, implicit $f17_d, implicit-def $x10
+  ; RV32-ILP32D-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32D-NEXT:   $x10 = COPY [[COPY1]](s32)
+  ; RV32-ILP32D-NEXT:   PseudoRET implicit $x10
+  %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: name: callee_double_ret
   ; RV32-ILP32D: bb.1 (%ir-block.0):
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32f-ilp32d-common.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32f-ilp32d-common.ll
index 23a20c0356fd4a1..31c759adefc5344 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32f-ilp32d-common.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32f-ilp32d-common.ll
@@ -40,6 +40,71 @@ define i32 @caller_float_in_fpr() nounwind {
   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: name: callee_float_in_fpr_exhausted_gprs
+  ; RV32-ILP32FD: bb.1 (%ir-block.0):
+  ; RV32-ILP32FD-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $f10_f
+  ; RV32-ILP32FD-NEXT: {{  $}}
+  ; RV32-ILP32FD-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32FD-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+  ; RV32-ILP32FD-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
+  ; RV32-ILP32FD-NEXT:   [[COPY2:%[0-9]+]]:_(s32) = COPY $x12
+  ; RV32-ILP32FD-NEXT:   [[COPY3:%[0-9]+]]:_(s32) = COPY $x13
+  ; RV32-ILP32FD-NEXT:   [[MV1:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY2]](s32), [[COPY3]](s32)
+  ; RV32-ILP32FD-NEXT:   [[COPY4:%[0-9]+]]:_(s32) = COPY $x14
+  ; RV32-ILP32FD-NEXT:   [[COPY5:%[0-9]+]]:_(s32) = COPY $x15
+  ; RV32-ILP32FD-NEXT:   [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY4]](s32), [[COPY5]](s32)
+  ; RV32-ILP32FD-NEXT:   [[COPY6:%[0-9]+]]:_(s32) = COPY $x16
+  ; RV32-ILP32FD-NEXT:   [[COPY7:%[0-9]+]]:_(s32) = COPY $x17
+  ; RV32-ILP32FD-NEXT:   [[MV3:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY6]](s32), [[COPY7]](s32)
+  ; RV32-ILP32FD-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; RV32-ILP32FD-NEXT:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s32) from %fixed-stack.0, align 16)
+  ; RV32-ILP32FD-NEXT:   [[COPY8:%[0-9]+]]:_(s32) = COPY $f10_f
+  ; RV32-ILP32FD-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[COPY8]](s32)
+  ; RV32-ILP32FD-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[LOAD]], [[FPTOSI]]
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoRET implicit $x10
+  %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: name: caller_float_in_fpr_exhausted_gprs
+  ; RV32-ILP32FD: bb.1 (%ir-block.0):
+  ; RV32-ILP32FD-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+  ; RV32-ILP32FD-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
+  ; RV32-ILP32FD-NEXT:   [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
+  ; RV32-ILP32FD-NEXT:   [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
+  ; RV32-ILP32FD-NEXT:   [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
+  ; RV32-ILP32FD-NEXT:   [[C5:%[0-9]+]]:_(s32) = G_FCONSTANT float 6.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C]](s64)
+  ; RV32-ILP32FD-NEXT:   [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C1]](s64)
+  ; RV32-ILP32FD-NEXT:   [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C2]](s64)
+  ; RV32-ILP32FD-NEXT:   [[UV6:%[0-9]+]]:_(s32), [[UV7:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C3]](s64)
+  ; RV32-ILP32FD-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $x2
+  ; RV32-ILP32FD-NEXT:   [[C6:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; RV32-ILP32FD-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C6]](s32)
+  ; RV32-ILP32FD-NEXT:   G_STORE [[C4]](s32), [[PTR_ADD]](p0) :: (store (s32) into stack, align 16)
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[UV]](s32)
+  ; RV32-ILP32FD-NEXT:   $x11 = COPY [[UV1]](s32)
+  ; RV32-ILP32FD-NEXT:   $x12 = COPY [[UV2]](s32)
+  ; RV32-ILP32FD-NEXT:   $x13 = COPY [[UV3]](s32)
+  ; RV32-ILP32FD-NEXT:   $x14 = COPY [[UV4]](s32)
+  ; RV32-ILP32FD-NEXT:   $x15 = COPY [[UV5]](s32)
+  ; RV32-ILP32FD-NEXT:   $x16 = COPY [[UV6]](s32)
+  ; RV32-ILP32FD-NEXT:   $x17 = COPY [[UV7]](s32)
+  ; RV32-ILP32FD-NEXT:   $f10_f = COPY [[C5]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoCALL target-flags(riscv-call) @callee_float_in_fpr_exhausted_gprs, implicit-def $x1, implicit $x10, implicit $x11, implicit $x12, implicit $x13, implicit $x14, implicit $x15, implicit $x16, implicit $x17, implicit $f10_f, implicit-def $x10
+  ; RV32-ILP32FD-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[COPY1]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoRET implicit $x10
+  %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: name: callee_float_in_gpr_exhausted_fprs
@@ -97,6 +162,95 @@ define i32 @caller_float_in_gpr_exhausted_fprs() nounwind {
   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: name: callee_float_on_stack_exhausted_gprs_fprs
+  ; RV32-ILP32FD: bb.1 (%ir-block.0):
+  ; RV32-ILP32FD-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $f10_f, $f11_f, $f12_f, $f13_f, $f14_f, $f15_f, $f16_f, $f17_f
+  ; RV32-ILP32FD-NEXT: {{  $}}
+  ; RV32-ILP32FD-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32FD-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+  ; RV32-ILP32FD-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
+  ; RV32-ILP32FD-NEXT:   [[COPY2:%[0-9]+]]:_(s32) = COPY $f10_f
+  ; RV32-ILP32FD-NEXT:   [[COPY3:%[0-9]+]]:_(s32) = COPY $x12
+  ; RV32-ILP32FD-NEXT:   [[COPY4:%[0-9]+]]:_(s32) = COPY $x13
+  ; RV32-ILP32FD-NEXT:   [[MV1:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY3]](s32), [[COPY4]](s32)
+  ; RV32-ILP32FD-NEXT:   [[COPY5:%[0-9]+]]:_(s32) = COPY $f11_f
+  ; RV32-ILP32FD-NEXT:   [[COPY6:%[0-9]+]]:_(s32) = COPY $x14
+  ; RV32-ILP32FD-NEXT:   [[COPY7:%[0-9]+]]:_(s32) = COPY $x15
+  ; RV32-ILP32FD-NEXT:   [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY6]](s32), [[COPY7]](s32)
+  ; RV32-ILP32FD-NEXT:   [[COPY8:%[0-9]+]]:_(s32) = COPY $f12_f
+  ; RV32-ILP32FD-NEXT:   [[COPY9:%[0-9]+]]:_(s32) = COPY $x16
+  ; RV32-ILP32FD-NEXT:   [[COPY10:%[0-9]+]]:_(s32) = COPY $x17
+  ; RV32-ILP32FD-NEXT:   [[MV3:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY9]](s32), [[COPY10]](s32)
+  ; RV32-ILP32FD-NEXT:   [[COPY11:%[0-9]+]]:_(s32) = COPY $f13_f
+  ; RV32-ILP32FD-NEXT:   [[COPY12:%[0-9]+]]:_(s32) = COPY $f14_f
+  ; RV32-ILP32FD-NEXT:   [[COPY13:%[0-9]+]]:_(s32) = COPY $f15_f
+  ; RV32-ILP32FD-NEXT:   [[COPY14:%[0-9]+]]:_(s32) = COPY $f16_f
+  ; RV32-ILP32FD-NEXT:   [[COPY15:%[0-9]+]]:_(s32) = COPY $f17_f
+  ; RV32-ILP32FD-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; RV32-ILP32FD-NEXT:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s32) from %fixed-stack.0, align 16)
+  ; RV32-ILP32FD-NEXT:   [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[MV3]](s64)
+  ; RV32-ILP32FD-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[LOAD]](s32)
+  ; RV32-ILP32FD-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[TRUNC]], [[FPTOSI]]
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[ADD]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoRET implicit $x10
+  %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: name: caller_float_on_stack_exhausted_gprs_fprs
+  ; RV32-ILP32FD: bb.1 (%ir-block.0):
+  ; RV32-ILP32FD-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+  ; RV32-ILP32FD-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 3
+  ; RV32-ILP32FD-NEXT:   [[C3:%[0-9]+]]:_(s32) = G_FCONSTANT float 4.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C4:%[0-9]+]]:_(s64) = G_CONSTANT i64 5
+  ; RV32-ILP32FD-NEXT:   [[C5:%[0-9]+]]:_(s32) = G_FCONSTANT float 6.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C6:%[0-9]+]]:_(s64) = G_CONSTANT i64 7
+  ; RV32-ILP32FD-NEXT:   [[C7:%[0-9]+]]:_(s32) = G_FCONSTANT float 8.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C8:%[0-9]+]]:_(s32) = G_FCONSTANT float 9.000000e+00
+  ; RV32-ILP32FD-NEXT:   [[C9:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.000000e+01
+  ; RV32-ILP32FD-NEXT:   [[C10:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.100000e+01
+  ; RV32-ILP32FD-NEXT:   [[C11:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.200000e+01
+  ; RV32-ILP32FD-NEXT:   [[C12:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.300000e+01
+  ; RV32-ILP32FD-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C]](s64)
+  ; RV32-ILP32FD-NEXT:   [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C2]](s64)
+  ; RV32-ILP32FD-NEXT:   [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C4]](s64)
+  ; RV32-ILP32FD-NEXT:   [[UV6:%[0-9]+]]:_(s32), [[UV7:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C6]](s64)
+  ; RV32-ILP32FD-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $x2
+  ; RV32-ILP32FD-NEXT:   [[C13:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; RV32-ILP32FD-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C13]](s32)
+  ; RV32-ILP32FD-NEXT:   G_STORE [[C12]](s32), [[PTR_ADD]](p0) :: (store (s32) into stack, align 16)
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[UV]](s32)
+  ; RV32-ILP32FD-NEXT:   $x11 = COPY [[UV1]](s32)
+  ; RV32-ILP32FD-NEXT:   $f10_f = COPY [[C1]](s32)
+  ; RV32-ILP32FD-NEXT:   $x12 = COPY [[UV2]](s32)
+  ; RV32-ILP32FD-NEXT:   $x13 = COPY [[UV3]](s32)
+  ; RV32-ILP32FD-NEXT:   $f11_f = COPY [[C3]](s32)
+  ; RV32-ILP32FD-NEXT:   $x14 = COPY [[UV4]](s32)
+  ; RV32-ILP32FD-NEXT:   $x15 = COPY [[UV5]](s32)
+  ; RV32-ILP32FD-NEXT:   $f12_f = COPY [[C5]](s32)
+  ; RV32-ILP32FD-NEXT:   $x16 = COPY [[UV6]](s32)
+  ; RV32-ILP32FD-NEXT:   $x17 = COPY [[UV7]](s32)
+  ; RV32-ILP32FD-NEXT:   $f13_f = COPY [[C7]](s32)
+  ; RV32-ILP32FD-NEXT:   $f14_f = COPY [[C8]](s32)
+  ; RV32-ILP32FD-NEXT:   $f15_f = COPY [[C9]](s32)
+  ; RV32-ILP32FD-NEXT:   $f16_f = COPY [[C10]](s32)
+  ; RV32-ILP32FD-NEXT:   $f17_f = COPY [[C11]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoCALL target-flags(riscv-call) @callee_float_on_stack_exhausted_gprs_fprs, implicit-def $x1, implicit $x10, implicit $x11, implicit $f10_f, implicit $x12, implicit $x13, implicit $f11_f, implicit $x14, implicit $x15, implicit $f12_f, implicit $x16, implicit $x17, implicit $f13_f, implicit $f14_f, implicit $f15_f, implicit $f16_f, implicit $f17_f, implicit-def $x10
+  ; RV32-ILP32FD-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x10
+  ; RV32-ILP32FD-NEXT:   $x10 = COPY [[COPY1]](s32)
+  ; RV32-ILP32FD-NEXT:   PseudoRET implicit $x10
+  %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: name: callee_float_ret
   ; RV32-ILP32FD: bb.1 (%ir-block.0):
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64d.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64d.ll
index de465147a4a692f..90ab171dd55a95d 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64d.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64d.ll
@@ -37,6 +37,220 @@ define i64 @caller_double_in_regs() nounwind {
   ret i64 %1
 }
 
+; Must keep define on a single line due to an update_llc_test_checks.py limitation
+define i64 @callee_double_in_fpr_exhausted_gprs(i128 %a, i128 %b, i128 %c, i128 %d, i64 %e, double %f) nounwind {
+  ; RV64I-LABEL: name: callee_double_in_fpr_exhausted_gprs
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $f10_d
+  ; RV64I-NEXT: {{  $}}
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   [[COPY1:%[0-9]+]]:_(s64) = COPY $x11
+  ; RV64I-NEXT:   [[MV:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[COPY]](s64), [[COPY1]](s64)
+  ; RV64I-NEXT:   [[COPY2:%[0-9]+]]:_(s64) = COPY $x12
+  ; RV64I-NEXT:   [[COPY3:%[0-9]+]]:_(s64) = COPY $x13
+  ; RV64I-NEXT:   [[MV1:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[COPY2]](s64), [[COPY3]](s64)
+  ; RV64I-NEXT:   [[COPY4:%[0-9]+]]:_(s64) = COPY $x14
+  ; RV64I-NEXT:   [[COPY5:%[0-9]+]]:_(s64) = COPY $x15
+  ; RV64I-NEXT:   [[MV2:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[COPY4]](s64), [[COPY5]](s64)
+  ; RV64I-NEXT:   [[COPY6:%[0-9]+]]:_(s64) = COPY $x16
+  ; RV64I-NEXT:   [[COPY7:%[0-9]+]]:_(s64) = COPY $x17
+  ; RV64I-NEXT:   [[MV3:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[COPY6]](s64), [[COPY7]](s64)
+  ; RV64I-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; RV64I-NEXT:   [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s64) from %fixed-stack.0, align 16)
+  ; RV64I-NEXT:   [[COPY8:%[0-9]+]]:_(s64) = COPY $f10_d
+  ; RV64I-NEXT:   [[FPTOSI:%[0-9]+]]:_(s64) = G_FPTOSI [[COPY8]](s64)
+  ; RV64I-NEXT:   [[ADD:%[0-9]+]]:_(s64) = G_ADD [[LOAD]], [[FPTOSI]]
+  ; RV64I-NEXT:   $x10 = COPY [[ADD]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %f_fptosi = fptosi double %f to i64
+  %1 = add i64 %e, %f_fptosi
+  ret i64 %1
+}
+
+define i64 @caller_double_in_fpr_exhausted_gprs() nounwind {
+  ; RV64I-LABEL: name: caller_double_in_fpr_exhausted_gprs
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   [[C:%[0-9]+]]:_(s128) = G_CONSTANT i128 1
+  ; RV64I-NEXT:   [[C1:%[0-9]+]]:_(s128) = G_CONSTANT i128 2
+  ; RV64I-NEXT:   [[C2:%[0-9]+]]:_(s128) = G_CONSTANT i128 3
+  ; RV64I-NEXT:   [[C3:%[0-9]+]]:_(s128) = G_CONSTANT i128 4
+  ; RV64I-NEXT:   [[C4:%[0-9]+]]:_(s64) = G_CONSTANT i64 5
+  ; RV64I-NEXT:   [[C5:%[0-9]+]]:_(s64) = G_FCONSTANT double 6.000000e+00
+  ; RV64I-NEXT:   [[UV:%[0-9]+]]:_(s64), [[UV1:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[C]](s128)
+  ; RV64I-NEXT:   [[UV2:%[0-9]+]]:_(s64), [[UV3:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[C1]](s128)
+  ; RV64I-NEXT:   [[UV4:%[0-9]+]]:_(s64), [[UV5:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[C2]](s128)
+  ; RV64I-NEXT:   [[UV6:%[0-9]+]]:_(s64), [[UV7:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[C3]](s128)
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $x2
+  ; RV64I-NEXT:   [[C6:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+  ; RV64I-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C6]](s64)
+  ; RV64I-NEXT:   G_STORE [[C4]](s64), [[PTR_ADD]](p0) :: (store (s64) into stack, align 16)
+  ; RV64I-NEXT:   $x10 = COPY [[UV]](s64)
+  ; RV64I-NEXT:   $x11 = COPY [[UV1]](s64)
+  ; RV64I-NEXT:   $x12 = COPY [[UV2]](s64)
+  ; RV64I-NEXT:   $x13 = COPY [[UV3]](s64)
+  ; RV64I-NEXT:   $x14 = COPY [[UV4]](s64)
+  ; RV64I-NEXT:   $x15 = COPY [[UV5]](s64)
+  ; RV64I-NEXT:   $x16 = COPY [[UV6]](s64)
+  ; RV64I-NEXT:   $x17 = COPY [[UV7]](s64)
+  ; RV64I-NEXT:   $f10_d = COPY [[C5]](s64)
+  ; RV64I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_in_fpr_exhausted_gprs, implicit-def $x1, implicit $x10, implicit $x11, implicit $x12, implicit $x13, implicit $x14, implicit $x15, implicit $x16, implicit $x17, implicit $f10_d, implicit-def $x10
+  ; RV64I-NEXT:   [[COPY1:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   $x10 = COPY [[COPY1]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %1 = call i64 @callee_double_in_fpr_exhausted_gprs(
+      i128 1, i128 2, i128 3, i128 4, i64 5, double 6.0)
+  ret i64 %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 {
+  ; RV64I-LABEL: name: callee_double_in_gpr_exhausted_fprs
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   liveins: $x10, $f10_d, $f11_d, $f12_d, $f13_d, $f14_d, $f15_d, $f16_d, $f17_d
+  ; RV64I-NEXT: {{  $}}
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $f10_d
+  ; RV64I-NEXT:   [[COPY1:%[0-9]+]]:_(s64) = COPY $f11_d
+  ; RV64I-NEXT:   [[COPY2:%[0-9]+]]:_(s64) = COPY $f12_d
+  ; RV64I-NEXT:   [[COPY3:%[0-9]+]]:_(s64) = COPY $f13_d
+  ; RV64I-NEXT:   [[COPY4:%[0-9]+]]:_(s64) = COPY $f14_d
+  ; RV64I-NEXT:   [[COPY5:%[0-9]+]]:_(s64) = COPY $f15_d
+  ; RV64I-NEXT:   [[COPY6:%[0-9]+]]:_(s64) = COPY $f16_d
+  ; RV64I-NEXT:   [[COPY7:%[0-9]+]]:_(s64) = COPY $f17_d
+  ; RV64I-NEXT:   [[COPY8:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[COPY7]](s64)
+  ; RV64I-NEXT:   [[FPTOSI1:%[0-9]+]]:_(s32) = G_FPTOSI [[COPY8]](s64)
+  ; RV64I-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[FPTOSI]], [[FPTOSI1]]
+  ; RV64I-NEXT:   [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[ADD]](s32)
+  ; RV64I-NEXT:   $x10 = COPY [[ANYEXT]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %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 {
+  ; RV64I-LABEL: name: caller_double_in_gpr_exhausted_fprs
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.000000e+00
+  ; RV64I-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00
+  ; RV64I-NEXT:   [[C2:%[0-9]+]]:_(s64) = G_FCONSTANT double 3.000000e+00
+  ; RV64I-NEXT:   [[C3:%[0-9]+]]:_(s64) = G_FCONSTANT double 4.000000e+00
+  ; RV64I-NEXT:   [[C4:%[0-9]+]]:_(s64) = G_FCONSTANT double 5.000000e+00
+  ; RV64I-NEXT:   [[C5:%[0-9]+]]:_(s64) = G_FCONSTANT double 6.000000e+00
+  ; RV64I-NEXT:   [[C6:%[0-9]+]]:_(s64) = G_FCONSTANT double 7.000000e+00
+  ; RV64I-NEXT:   [[C7:%[0-9]+]]:_(s64) = G_FCONSTANT double 8.000000e+00
+  ; RV64I-NEXT:   [[C8:%[0-9]+]]:_(s64) = G_FCONSTANT double 9.000000e+00
+  ; RV64I-NEXT:   $f10_d = COPY [[C]](s64)
+  ; RV64I-NEXT:   $f11_d = COPY [[C1]](s64)
+  ; RV64I-NEXT:   $f12_d = COPY [[C2]](s64)
+  ; RV64I-NEXT:   $f13_d = COPY [[C3]](s64)
+  ; RV64I-NEXT:   $f14_d = COPY [[C4]](s64)
+  ; RV64I-NEXT:   $f15_d = COPY [[C5]](s64)
+  ; RV64I-NEXT:   $f16_d = COPY [[C6]](s64)
+  ; RV64I-NEXT:   $f17_d = COPY [[C7]](s64)
+  ; RV64I-NEXT:   $x10 = COPY [[C8]](s64)
+  ; RV64I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_in_gpr_exhausted_fprs, implicit-def $x1, implicit $f10_d, implicit $f11_d, implicit $f12_d, implicit $f13_d, implicit $f14_d, implicit $f15_d, implicit $f16_d, implicit $f17_d, implicit $x10, implicit-def $x10
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64)
+  ; RV64I-NEXT:   [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[TRUNC]](s32)
+  ; RV64I-NEXT:   $x10 = COPY [[ANYEXT]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %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 i64 @callee_double_on_stack_exhausted_gprs_fprs(i128 %a, double %b, i128 %c, double %d, i128 %e, double %f, i128 %g, double %h, double %i, double %j, double %k, double %l, double %m) nounwind {
+  ; RV64I-LABEL: name: callee_double_on_stack_exhausted_gprs_fprs
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $f10_d, $f11_d, $f12_d, $f13_d, $f14_d, $f15_d, $f16_d, $f17_d
+  ; RV64I-NEXT: {{  $}}
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   [[COPY1:%[0-9]+]]:_(s64) = COPY $x11
+  ; RV64I-NEXT:   [[MV:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[COPY]](s64), [[COPY1]](s64)
+  ; RV64I-NEXT:   [[COPY2:%[0-9]+]]:_(s64) = COPY $f10_d
+  ; RV64I-NEXT:   [[COPY3:%[0-9]+]]:_(s64) = COPY $x12
+  ; RV64I-NEXT:   [[COPY4:%[0-9]+]]:_(s64) = COPY $x13
+  ; RV64I-NEXT:   [[MV1:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[COPY3]](s64), [[COPY4]](s64)
+  ; RV64I-NEXT:   [[COPY5:%[0-9]+]]:_(s64) = COPY $f11_d
+  ; RV64I-NEXT:   [[COPY6:%[0-9]+]]:_(s64) = COPY $x14
+  ; RV64I-NEXT:   [[COPY7:%[0-9]+]]:_(s64) = COPY $x15
+  ; RV64I-NEXT:   [[MV2:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[COPY6]](s64), [[COPY7]](s64)
+  ; RV64I-NEXT:   [[COPY8:%[0-9]+]]:_(s64) = COPY $f12_d
+  ; RV64I-NEXT:   [[COPY9:%[0-9]+]]:_(s64) = COPY $x16
+  ; RV64I-NEXT:   [[COPY10:%[0-9]+]]:_(s64) = COPY $x17
+  ; RV64I-NEXT:   [[MV3:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[COPY9]](s64), [[COPY10]](s64)
+  ; RV64I-NEXT:   [[COPY11:%[0-9]+]]:_(s64) = COPY $f13_d
+  ; RV64I-NEXT:   [[COPY12:%[0-9]+]]:_(s64) = COPY $f14_d
+  ; RV64I-NEXT:   [[COPY13:%[0-9]+]]:_(s64) = COPY $f15_d
+  ; RV64I-NEXT:   [[COPY14:%[0-9]+]]:_(s64) = COPY $f16_d
+  ; RV64I-NEXT:   [[COPY15:%[0-9]+]]:_(s64) = COPY $f17_d
+  ; RV64I-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
+  ; RV64I-NEXT:   [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s64) from %fixed-stack.0, align 16)
+  ; RV64I-NEXT:   [[TRUNC:%[0-9]+]]:_(s64) = G_TRUNC [[MV3]](s128)
+  ; RV64I-NEXT:   [[FPTOSI:%[0-9]+]]:_(s64) = G_FPTOSI [[LOAD]](s64)
+  ; RV64I-NEXT:   [[ADD:%[0-9]+]]:_(s64) = G_ADD [[TRUNC]], [[FPTOSI]]
+  ; RV64I-NEXT:   $x10 = COPY [[ADD]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %g_trunc = trunc i128 %g to i64
+  %m_fptosi = fptosi double %m to i64
+  %1 = add i64 %g_trunc, %m_fptosi
+  ret i64 %1
+}
+
+define i64 @caller_double_on_stack_exhausted_gprs_fprs() nounwind {
+  ; RV64I-LABEL: name: caller_double_on_stack_exhausted_gprs_fprs
+  ; RV64I: bb.1 (%ir-block.0):
+  ; RV64I-NEXT:   [[C:%[0-9]+]]:_(s128) = G_CONSTANT i128 1
+  ; RV64I-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00
+  ; RV64I-NEXT:   [[C2:%[0-9]+]]:_(s128) = G_CONSTANT i128 3
+  ; RV64I-NEXT:   [[C3:%[0-9]+]]:_(s64) = G_FCONSTANT double 4.000000e+00
+  ; RV64I-NEXT:   [[C4:%[0-9]+]]:_(s128) = G_CONSTANT i128 5
+  ; RV64I-NEXT:   [[C5:%[0-9]+]]:_(s64) = G_FCONSTANT double 6.000000e+00
+  ; RV64I-NEXT:   [[C6:%[0-9]+]]:_(s128) = G_CONSTANT i128 7
+  ; RV64I-NEXT:   [[C7:%[0-9]+]]:_(s64) = G_FCONSTANT double 8.000000e+00
+  ; RV64I-NEXT:   [[C8:%[0-9]+]]:_(s64) = G_FCONSTANT double 9.000000e+00
+  ; RV64I-NEXT:   [[C9:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.000000e+01
+  ; RV64I-NEXT:   [[C10:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.100000e+01
+  ; RV64I-NEXT:   [[C11:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.200000e+01
+  ; RV64I-NEXT:   [[C12:%[0-9]+]]:_(s64) = G_FCONSTANT double 1.300000e+01
+  ; RV64I-NEXT:   [[UV:%[0-9]+]]:_(s64), [[UV1:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[C]](s128)
+  ; RV64I-NEXT:   [[UV2:%[0-9]+]]:_(s64), [[UV3:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[C2]](s128)
+  ; RV64I-NEXT:   [[UV4:%[0-9]+]]:_(s64), [[UV5:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[C4]](s128)
+  ; RV64I-NEXT:   [[UV6:%[0-9]+]]:_(s64), [[UV7:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[C6]](s128)
+  ; RV64I-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $x2
+  ; RV64I-NEXT:   [[C13:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+  ; RV64I-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C13]](s64)
+  ; RV64I-NEXT:   G_STORE [[C12]](s64), [[PTR_ADD]](p0) :: (store (s64) into stack, align 16)
+  ; RV64I-NEXT:   $x10 = COPY [[UV]](s64)
+  ; RV64I-NEXT:   $x11 = COPY [[UV1]](s64)
+  ; RV64I-NEXT:   $f10_d = COPY [[C1]](s64)
+  ; RV64I-NEXT:   $x12 = COPY [[UV2]](s64)
+  ; RV64I-NEXT:   $x13 = COPY [[UV3]](s64)
+  ; RV64I-NEXT:   $f11_d = COPY [[C3]](s64)
+  ; RV64I-NEXT:   $x14 = COPY [[UV4]](s64)
+  ; RV64I-NEXT:   $x15 = COPY [[UV5]](s64)
+  ; RV64I-NEXT:   $f12_d = COPY [[C5]](s64)
+  ; RV64I-NEXT:   $x16 = COPY [[UV6]](s64)
+  ; RV64I-NEXT:   $x17 = COPY [[UV7]](s64)
+  ; RV64I-NEXT:   $f13_d = COPY [[C7]](s64)
+  ; RV64I-NEXT:   $f14_d = COPY [[C8]](s64)
+  ; RV64I-NEXT:   $f15_d = COPY [[C9]](s64)
+  ; RV64I-NEXT:   $f16_d = COPY [[C10]](s64)
+  ; RV64I-NEXT:   $f17_d = COPY [[C11]](s64)
+  ; RV64I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_double_on_stack_exhausted_gprs_fprs, implicit-def $x1, implicit $x10, implicit $x11, implicit $f10_d, implicit $x12, implicit $x13, implicit $f11_d, implicit $x14, implicit $x15, implicit $f12_d, implicit $x16, implicit $x17, implicit $f13_d, implicit $f14_d, implicit $f15_d, implicit $f16_d, implicit $f17_d, implicit-def $x10
+  ; RV64I-NEXT:   [[COPY1:%[0-9]+]]:_(s64) = COPY $x10
+  ; RV64I-NEXT:   $x10 = COPY [[COPY1]](s64)
+  ; RV64I-NEXT:   PseudoRET implicit $x10
+  %1 = call i64 @callee_double_on_stack_exhausted_gprs_fprs(
+      i128 1, double 2.0, i128 3, double 4.0, i128 5, double 6.0, i128 7, double 8.0,
+      double 9.0, double 10.0, double 11.0, double 12.0, double 13.0)
+  ret i64 %1
+}
+
 define double @callee_double_ret() nounwind {
   ; RV64I-LABEL: name: callee_double_ret
   ; RV64I: bb.1 (%ir-block.0):



More information about the llvm-commits mailing list