-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[RISCV][GISel] Add instruction selection for G_FADD/G_FSUB/G_FMUL/G_FDIV with F/D extensions. #69808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-backend-risc-v @llvm/pr-subscribers-llvm-globalisel Author: Craig Topper (topperc) ChangesStacked on #69805 Patch is 99.19 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/69808.diff 14 Files Affected:
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/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index ab2125a3615f385..2d68d7f3bd010d1 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -382,6 +382,13 @@ const TargetRegisterClass *RISCVInstructionSelector::getRegClassForTypeOnBank(
return &RISCV::GPRRegClass;
}
+ if (RB.getID() == RISCV::FPRRegBankID) {
+ if (Ty.getSizeInBits() == 32)
+ return &RISCV::FPR32RegClass;
+ if (Ty.getSizeInBits() == 64)
+ return &RISCV::FPR64RegClass;
+ }
+
// TODO: Non-GPR register classes.
return nullptr;
}
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/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
index 4ede55fc8c54f68..39a183ca6091165 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
@@ -26,12 +26,16 @@ namespace RISCV {
RegisterBankInfo::PartialMapping PartMappings[] = {
{0, 32, GPRRegBank},
- {0, 64, GPRRegBank}
+ {0, 64, GPRRegBank},
+ {0, 32, FPRRegBank},
+ {0, 64, FPRRegBank},
};
enum PartialMappingIdx {
PMI_GPR32 = 0,
- PMI_GPR64 = 1
+ PMI_GPR64 = 1,
+ PMI_FPR32 = 2,
+ PMI_FPR64 = 3,
};
RegisterBankInfo::ValueMapping ValueMappings[] = {
@@ -44,13 +48,23 @@ RegisterBankInfo::ValueMapping ValueMappings[] = {
// Maximum 3 GPR operands; 64 bit.
{&PartMappings[PMI_GPR64], 1},
{&PartMappings[PMI_GPR64], 1},
- {&PartMappings[PMI_GPR64], 1}
+ {&PartMappings[PMI_GPR64], 1},
+ // Maximum 3 FPR operands; 32 bit.
+ {&PartMappings[PMI_FPR32], 1},
+ {&PartMappings[PMI_FPR32], 1},
+ {&PartMappings[PMI_FPR32], 1},
+ // Maximum 3 FPR operands; 64 bit.
+ {&PartMappings[PMI_FPR64], 1},
+ {&PartMappings[PMI_FPR64], 1},
+ {&PartMappings[PMI_FPR64], 1},
};
enum ValueMappingsIdx {
InvalidIdx = 0,
GPR32Idx = 1,
- GPR64Idx = 4
+ GPR64Idx = 4,
+ FPR32Idx = 7,
+ FPR64Idx = 10,
};
} // namespace RISCV
} // namespace llvm
@@ -101,6 +115,9 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
return Mapping;
}
+ const MachineFunction &MF = *MI.getParent()->getParent();
+ const MachineRegisterInfo &MRI = MF.getRegInfo();
+
unsigned GPRSize = getMaximumSize(RISCV::GPRRegBankID);
assert((GPRSize == 32 || GPRSize == 64) && "Unexpected GPR size");
@@ -157,6 +174,16 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OperandsMapping = getOperandsMapping(
{GPRValueMapping, GPRValueMapping, GPRValueMapping, GPRValueMapping});
break;
+ case TargetOpcode::G_FADD:
+ case TargetOpcode::G_FSUB:
+ case TargetOpcode::G_FMUL:
+ case TargetOpcode::G_FDIV: {
+ LLT Ty = MRI.getType(MI.getOperand(0).getReg());
+ OperandsMapping = Ty.getSizeInBits() == 64
+ ? &RISCV::ValueMappings[RISCV::FPR64Idx]
+ : &RISCV::ValueMappings[RISCV::FPR32Idx];
+ break;
+ }
default:
return getInvalidInstructionMapping();
}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/fp-arith.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/fp-arith.mir
new file mode 100644
index 000000000000000..0a4fa10ba0b67e5
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/fp-arith.mir
@@ -0,0 +1,198 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv32 -mattr=+d -run-pass=instruction-select \
+# RUN: -simplify-mir -verify-machineinstrs %s -o - | FileCheck %s
+# RUN: llc -mtriple=riscv64 -mattr=+d -run-pass=instruction-select \
+# RUN: -simplify-mir -verify-machineinstrs %s -o - | FileCheck %s
+
+---
+name: fadd_f32
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $f10_f, $f11_f
+
+ ; CHECK-LABEL: name: fadd_f32
+ ; CHECK: liveins: $f10_f, $f11_f
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr32 = COPY $f10_f
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:fpr32 = COPY $f11_f
+ ; CHECK-NEXT: [[FADD_S:%[0-9]+]]:fpr32 = nofpexcept FADD_S [[COPY]], [[COPY1]], 7
+ ; CHECK-NEXT: $f10_f = COPY [[FADD_S]]
+ ; CHECK-NEXT: PseudoRET implicit $f10_f
+ %0:fprb(s32) = COPY $f10_f
+ %1:fprb(s32) = COPY $f11_f
+ %2:fprb(s32) = G_FADD %0, %1
+ $f10_f = COPY %2(s32)
+ PseudoRET implicit $f10_f
+
+...
+---
+name: fsub_f32
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $f10_f, $f11_f
+
+ ; CHECK-LABEL: name: fsub_f32
+ ; CHECK: liveins: $f10_f, $f11_f
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr32 = COPY $f10_f
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:fpr32 = COPY $f11_f
+ ; CHECK-NEXT: [[FSUB_S:%[0-9]+]]:fpr32 = nofpexcept FSUB_S [[COPY]], [[COPY1]], 7
+ ; CHECK-NEXT: $f10_f = COPY [[FSUB_S]]
+ ; CHECK-NEXT: PseudoRET implicit $f10_f
+ %0:fprb(s32) = COPY $f10_f
+ %1:fprb(s32) = COPY $f11_f
+ %2:fprb(s32) = G_FSUB %0, %1
+ $f10_f = COPY %2(s32)
+ PseudoRET implicit $f10_f
+
+...
+---
+name: fmul_f32
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $f10_f, $f11_f
+
+ ; CHECK-LABEL: name: fmul_f32
+ ; CHECK: liveins: $f10_f, $f11_f
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr32 = COPY $f10_f
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:fpr32 = COPY $f11_f
+ ; CHECK-NEXT: [[FMUL_S:%[0-9]+]]:fpr32 = nofpexcept FMUL_S [[COPY]], [[COPY1]], 7
+ ; CHECK-NEXT: $f10_f = COPY [[FMUL_S]]
+ ; CHECK-NEXT: PseudoRET implicit $f10_f
+ %0:fprb(s32) = COPY $f10_f
+ %1:fprb(s32) = COPY $f11_f
+ %2:fprb(s32) = G_FMUL %0, %1
+ $f10_f = COPY %2(s32)
+ PseudoRET implicit $f10_f
+
+...
+---
+name: fdiv_f32
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $f10_f, $f11_f
+
+ ; CHECK-LABEL: name: fdiv_f32
+ ; CHECK: liveins: $f10_f, $f11_f
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr32 = COPY $f10_f
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:fpr32 = COPY $f11_f
+ ; CHECK-NEXT: [[FDIV_S:%[0-9]+]]:fpr32 = nofpexcept FDIV_S [[COPY]], [[COPY1]], 7
+ ; CHECK-NEXT: $f10_f = COPY [[FDIV_S]]
+ ; CHECK-NEXT: PseudoRET implicit $f10_f
+ %0:fprb(s32) = COPY $f10_f
+ %1:fprb(s32) = COPY $f11_f
+ %2:fprb(s32) = G_FDIV %0, %1
+ $f10_f = COPY %2(s32)
+ PseudoRET implicit $f10_f
+
+...
+---
+name: fadd_f64
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $f10_d, $f11_d
+
+ ; CHECK-LABEL: name: fadd_f64
+ ; CHECK: liveins: $f10_d, $f11_d
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:fpr64 = COPY $f11_d
+ ; CHECK-NEXT: [[FADD_D:%[0-9]+]]:fpr64 = nofpexcept FADD_D [[COPY]], [[COPY1]], 7
+ ; CHECK-NEXT: $f10_d = COPY [[FADD_D]]
+ ; CHECK-NEXT: PseudoRET implicit $f10_d
+ %0:fprb(s64) = COPY $f10_d
+ %1:fprb(s64) = COPY $f11_d
+ %2:fprb(s64) = G_FADD %0, %1
+ $f10_d = COPY %2(s64)
+ PseudoRET implicit $f10_d
+
+...
+---
+name: fsub_f64
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $f10_d, $f11_d
+
+ ; CHECK-LABEL: name: fsub_f64
+ ; CHECK: liveins: $f10_d, $f11_d
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:fpr64 = COPY $f11_d
+ ; CHECK-NEXT: [[FSUB_D:%[0-9]+]]:fpr64 = nofpexcept FSUB_D [[COPY]], [[COPY1]], 7
+ ; CHECK-NEXT: $f10_d = COPY [[FSUB_D]]
+ ; CHECK-NEXT: PseudoRET implicit $f10_d
+ %0:fprb(s64) = COPY $f10_d
+ %1:fprb(s64) = COPY $f11_d
+ %2:fprb(s64) = G_FSUB %0, %1
+ $f10_d = COPY %2(s64)
+ PseudoRET implicit $f10_d
+
+...
+---
+name: fmul_f64
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $f10_d, $f11_d
+
+ ; CHECK-LABEL: name: fmul_f64
+ ; CHECK: liveins: $f10_d, $f11_d
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:fpr64 = COPY $f11_d
+ ; CHECK-NEXT: [[FMUL_D:%[0-9]+]]:fpr64 = nofpexcept FMUL_D [[COPY]], [[COPY1]], 7
+ ; CHECK-NEXT: $f10_d = COPY [[FMUL_D]]
+ ; CHECK-NEXT: PseudoRET implicit $f10_d
+ %0:fprb(s64) = COPY $f10_d
+ %1:fprb(s64) = COPY $f11_d
+ %2:fprb(s64) = G_FMUL %0, %1
+ $f10_d = COPY %2(s64)
+ PseudoRET implicit $f10_d
+
+...
+---
+name: fdiv_f64
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $f10_d, $f11_d
+
+ ; CHECK-LABEL: name: fdiv_f64
+ ; CHECK: liveins: $f10_d, $f11_d
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:fpr64 = COPY $f11_d
+ ; CHECK-NEXT: [[FDIV_D:%[0-9]+]]:fpr64 = nofpexcept FDIV_D [[COPY]], [[COPY1]], 7
+ ; CHECK-NEXT: $f10_d = COPY [[FDIV_D]]
+ ; CHECK-NEXT: PseudoRET implicit $f10_d
+ %0:fprb(s64) = COPY $f10_d
+ %1:fprb(s64) = COPY $f11_d
+ %2:fprb(s64) = G_FDIV %0, %1
+ $f10_d = COPY %2(s64)
+ PseudoRET implicit $f10_d
+
+...
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
...
[truncated]
|
@@ -198,6 +199,16 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) { | |||
|
|||
getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0}); | |||
|
|||
// FP Operations | |||
|
|||
if (ST.hasStdExtF()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
X86 has also a fleet of extensions, but RISC-V will probably win. They do it slightly different:
getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV}) |
0ba07b6
to
849a34e
Compare
if (ST.hasStdExtD()) | ||
FPOpActions.legalFor({s64}); | ||
} | ||
getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this bit stylistic or functional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was intended to be stylistic. It was suggested in earlier review. It should be in the legalizer patch.
…DIV with F/D extensions.
849a34e
to
025dd59
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
…DIV with F/D extensions. (llvm#69808)
Stacked on #69805