[llvm] [RISCV][GISel] Add legalizer support for G_FADD/G_FSUB/G_FMUL/G_FDIV with F/D extensions. (PR #69804)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 20 19:14:46 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v
Author: Craig Topper (topperc)
<details>
<summary>Changes</summary>
This a simple patch to get initial FP support started.
Stacked on #<!-- -->69138
---
Patch is 78.41 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/69804.diff
9 Files Affected:
- (modified) llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp (+90)
- (modified) llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp (+11)
- (added) llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32-ilp32f-common.ll (+75)
- (added) llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32.ll (+121)
- (added) llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32d.ll (+364)
- (added) llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32f-ilp32d-common.ll (+273)
- (added) llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64-lp64f-common.ll (+62)
- (added) llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64.ll (+82)
- (added) llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64d.ll (+273)
``````````diff
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp b/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
index b605f2f621d040d..a7a87aef23db357 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp
@@ -93,11 +93,59 @@ 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 (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));
+ }
+
+ if (Thunk) {
+ *Thunk = [=]() {
+ assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
+ if (VAHi.isRegLoc())
+ assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
+ };
+ return 1;
+ }
+ assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo);
+ if (VAHi.isRegLoc())
+ assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi);
+ return 1;
+ }
+
private:
MachineInstrBuilder MIB;
@@ -168,6 +216,44 @@ 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))};
+
+ 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);
+ if (VAHi.isRegLoc())
+ 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).
@@ -210,6 +296,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;
@@ -221,6 +309,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/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 3aae38a7d18de98..0e603d833b792c0 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -28,6 +28,7 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) {
const LLT s8 = LLT::scalar(8);
const LLT s16 = LLT::scalar(16);
const LLT s32 = LLT::scalar(32);
+ const LLT s64 = LLT::scalar(64);
using namespace TargetOpcode;
@@ -198,6 +199,16 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) {
getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
+ // FP Operations
+
+ if (ST.hasStdExtF()) {
+ auto &FPOpActions =
+ getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
+ .legalFor({s32});
+ if (ST.hasStdExtD())
+ FPOpActions.legalFor({s64});
+ }
+
getLegacyLegalizerInfo().computeTables();
}
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..3b4aca1e6953dac
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32.ll
@@ -0,0 +1,121 @@
+; 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 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):
+ ; 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..e33e279f7f48978
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32d.ll
@@ -0,0 +1,364 @@
+; 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_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 imp...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/69804
More information about the llvm-commits
mailing list