[RISCV][GISel] Use libcalls for f32/f64 G_FCMP without F/D extensions. (#117660)
LegalizerHelp only supported f128 libcalls and incorrectly assumed that
the destination register for the G_FCMP was s32.
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index abfca50..709eb25 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -1003,23 +1003,36 @@
/// the ICMP predicate that should be generated to compare with #0
/// after the libcall.
static std::pair<RTLIB::Libcall, CmpInst::Predicate>
-getFCMPLibcallDesc(const CmpInst::Predicate Pred) {
+getFCMPLibcallDesc(const CmpInst::Predicate Pred, unsigned Size) {
+#define RTLIBCASE_CMP(LibcallPrefix, ICmpPred) \
+ do { \
+ switch (Size) { \
+ case 32: \
+ return {RTLIB::LibcallPrefix##32, ICmpPred}; \
+ case 64: \
+ return {RTLIB::LibcallPrefix##64, ICmpPred}; \
+ case 128: \
+ return {RTLIB::LibcallPrefix##128, ICmpPred}; \
+ default: \
+ llvm_unreachable("unexpected size"); \
+ } \
+ } while (0)
switch (Pred) {
case CmpInst::FCMP_OEQ:
- return {RTLIB::OEQ_F128, CmpInst::ICMP_EQ};
+ RTLIBCASE_CMP(OEQ_F, CmpInst::ICMP_EQ);
case CmpInst::FCMP_UNE:
- return {RTLIB::UNE_F128, CmpInst::ICMP_NE};
+ RTLIBCASE_CMP(UNE_F, CmpInst::ICMP_NE);
case CmpInst::FCMP_OGE:
- return {RTLIB::OGE_F128, CmpInst::ICMP_SGE};
+ RTLIBCASE_CMP(OGE_F, CmpInst::ICMP_SGE);
case CmpInst::FCMP_OLT:
- return {RTLIB::OLT_F128, CmpInst::ICMP_SLT};
+ RTLIBCASE_CMP(OLT_F, CmpInst::ICMP_SLT);
case CmpInst::FCMP_OLE:
- return {RTLIB::OLE_F128, CmpInst::ICMP_SLE};
+ RTLIBCASE_CMP(OLE_F, CmpInst::ICMP_SLE);
case CmpInst::FCMP_OGT:
- return {RTLIB::OGT_F128, CmpInst::ICMP_SGT};
+ RTLIBCASE_CMP(OGT_F, CmpInst::ICMP_SGT);
case CmpInst::FCMP_UNO:
- return {RTLIB::UO_F128, CmpInst::ICMP_NE};
+ RTLIBCASE_CMP(UO_F, CmpInst::ICMP_NE);
default:
return {RTLIB::UNKNOWN_LIBCALL, CmpInst::BAD_ICMP_PREDICATE};
}
@@ -1034,21 +1047,24 @@
const GFCmp *Cmp = cast<GFCmp>(&MI);
LLT OpLLT = MRI.getType(Cmp->getLHSReg());
- if (OpLLT != LLT::scalar(128) || OpLLT != MRI.getType(Cmp->getRHSReg()))
+ unsigned Size = OpLLT.getSizeInBits();
+ if ((Size != 32 && Size != 64 && Size != 128) ||
+ OpLLT != MRI.getType(Cmp->getRHSReg()))
return UnableToLegalize;
Type *OpType = getFloatTypeForLLT(Ctx, OpLLT);
// DstReg type is s32
const Register DstReg = Cmp->getReg(0);
+ LLT DstTy = MRI.getType(DstReg);
const auto Cond = Cmp->getCond();
// Reference:
// https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1
// Generates a libcall followed by ICMP.
- const auto BuildLibcall =
- [&](const RTLIB::Libcall Libcall, const CmpInst::Predicate ICmpPred,
- const DstOp &Res = LLT::scalar(32)) -> Register {
+ const auto BuildLibcall = [&](const RTLIB::Libcall Libcall,
+ const CmpInst::Predicate ICmpPred,
+ const DstOp &Res) -> Register {
// FCMP libcall always returns an i32, and needs an ICMP with #0.
constexpr LLT TempLLT = LLT::scalar(32);
Register Temp = MRI.createGenericVirtualRegister(TempLLT);
@@ -1067,7 +1083,7 @@
};
// Simple case if we have a direct mapping from predicate to libcall
- if (const auto [Libcall, ICmpPred] = getFCMPLibcallDesc(Cond);
+ if (const auto [Libcall, ICmpPred] = getFCMPLibcallDesc(Cond, Size);
Libcall != RTLIB::UNKNOWN_LIBCALL &&
ICmpPred != CmpInst::BAD_ICMP_PREDICATE) {
if (BuildLibcall(Libcall, ICmpPred, DstReg)) {
@@ -1083,11 +1099,13 @@
// FCMP_UEQ: unordered or equal
// Convert into (FCMP_OEQ || FCMP_UNO).
- const auto [OeqLibcall, OeqPred] = getFCMPLibcallDesc(CmpInst::FCMP_OEQ);
- const auto Oeq = BuildLibcall(OeqLibcall, OeqPred);
+ const auto [OeqLibcall, OeqPred] =
+ getFCMPLibcallDesc(CmpInst::FCMP_OEQ, Size);
+ const auto Oeq = BuildLibcall(OeqLibcall, OeqPred, DstTy);
- const auto [UnoLibcall, UnoPred] = getFCMPLibcallDesc(CmpInst::FCMP_UNO);
- const auto Uno = BuildLibcall(UnoLibcall, UnoPred);
+ const auto [UnoLibcall, UnoPred] =
+ getFCMPLibcallDesc(CmpInst::FCMP_UNO, Size);
+ const auto Uno = BuildLibcall(UnoLibcall, UnoPred, DstTy);
if (Oeq && Uno)
MIRBuilder.buildOr(DstReg, Oeq, Uno);
else
@@ -1102,13 +1120,15 @@
// We inverse the predicate instead of generating a NOT
// to save one instruction.
// On AArch64 isel can even select two cmp into a single ccmp.
- const auto [OeqLibcall, OeqPred] = getFCMPLibcallDesc(CmpInst::FCMP_OEQ);
+ const auto [OeqLibcall, OeqPred] =
+ getFCMPLibcallDesc(CmpInst::FCMP_OEQ, Size);
const auto NotOeq =
- BuildLibcall(OeqLibcall, CmpInst::getInversePredicate(OeqPred));
+ BuildLibcall(OeqLibcall, CmpInst::getInversePredicate(OeqPred), DstTy);
- const auto [UnoLibcall, UnoPred] = getFCMPLibcallDesc(CmpInst::FCMP_UNO);
+ const auto [UnoLibcall, UnoPred] =
+ getFCMPLibcallDesc(CmpInst::FCMP_UNO, Size);
const auto NotUno =
- BuildLibcall(UnoLibcall, CmpInst::getInversePredicate(UnoPred));
+ BuildLibcall(UnoLibcall, CmpInst::getInversePredicate(UnoPred), DstTy);
if (NotOeq && NotUno)
MIRBuilder.buildAnd(DstReg, NotOeq, NotUno);
@@ -1130,7 +1150,7 @@
// MIRBuilder.buildFCmp(CmpInst::getInversePredicate(Pred), PredTy,
// Op1, Op2));
const auto [InversedLibcall, InversedPred] =
- getFCMPLibcallDesc(CmpInst::getInversePredicate(Cond));
+ getFCMPLibcallDesc(CmpInst::getInversePredicate(Cond), Size);
if (!BuildLibcall(InversedLibcall,
CmpInst::getInversePredicate(InversedPred), DstReg))
return UnableToLegalize;