diff --git a/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp b/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp index be1771b19316f9..1806fcf4b5a166 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp @@ -94,11 +94,60 @@ struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler { void assignValueToReg(Register ValVReg, Register PhysReg, const 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 VAs, + std::function *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(VAHi)); + } + + auto assignFunc = [=]() { + assignValueToReg(NewRegs[0], VALo.getLocReg(), VALo); + if (VAHi.isRegLoc()) + assignValueToReg(NewRegs[1], VAHi.getLocReg(), VAHi); + }; + + if (Thunk) { + *Thunk = assignFunc; + return 1; + } + + assignFunc(); + return 1; + } + private: MachineInstrBuilder MIB; @@ -170,6 +219,44 @@ struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler { IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA); } + unsigned assignCustomValue(CallLowering::ArgInfo &Arg, + ArrayRef VAs, + std::function *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))}; + + 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(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). @@ -212,6 +299,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 +312,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 00000000000000..8fc77feae2d431 --- /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 00000000000000..3b4aca1e6953da --- /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 00000000000000..e33e279f7f4897 --- /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 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 + ; 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 +} + +; 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): + ; 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 00000000000000..31c759adefc534 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32f-ilp32d-common.ll @@ -0,0 +1,273 @@ +; 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_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 + ; 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 +} + +; 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): + ; 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 00000000000000..4d6275db77bc89 --- /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 00000000000000..a45af04c09b21c --- /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 00000000000000..90ab171dd55a95 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64d.ll @@ -0,0 +1,273 @@ +; 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 +} + +; 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): + ; 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 +}