@@ -735,8 +735,7 @@ static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI) {
735735 if (MemType.isVector ())
736736 return RTLIB::UNKNOWN_LIBCALL;
737737
738- #define LCALLS (A, B ) \
739- { A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL }
738+ #define LCALLS (A, B ) {A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL}
740739#define LCALL5 (A ) \
741740 LCALLS (A, 1 ), LCALLS (A, 2 ), LCALLS (A, 4 ), LCALLS (A, 8 ), LCALLS (A, 16 )
742741 switch (Opc) {
@@ -992,6 +991,150 @@ LegalizerHelper::createSetStateLibcall(MachineIRBuilder &MIRBuilder,
992991 LocObserver, nullptr );
993992}
994993
994+ // / Returns the corresponding libcall for the given Pred and
995+ // / the ICMP predicate that should be generated to compare with #0
996+ // / after the libcall.
997+ static std::pair<RTLIB::Libcall, CmpInst::Predicate>
998+ getFCMPLibcallDesc (const CmpInst::Predicate Pred) {
999+
1000+ switch (Pred) {
1001+ case CmpInst::FCMP_OEQ:
1002+ return {RTLIB::OEQ_F128, CmpInst::ICMP_EQ};
1003+ case CmpInst::FCMP_UNE:
1004+ return {RTLIB::UNE_F128, CmpInst::ICMP_NE};
1005+ case CmpInst::FCMP_OGE:
1006+ return {RTLIB::OGE_F128, CmpInst::ICMP_SGE};
1007+ case CmpInst::FCMP_OLT:
1008+ return {RTLIB::OLT_F128, CmpInst::ICMP_SLT};
1009+ case CmpInst::FCMP_OLE:
1010+ return {RTLIB::OLE_F128, CmpInst::ICMP_SLE};
1011+ case CmpInst::FCMP_OGT:
1012+ return {RTLIB::OGT_F128, CmpInst::ICMP_SGT};
1013+ case CmpInst::FCMP_UNO:
1014+ return {RTLIB::UO_F128, CmpInst::ICMP_NE};
1015+ default :
1016+ return {RTLIB::UNKNOWN_LIBCALL, CmpInst::BAD_ICMP_PREDICATE};
1017+ }
1018+ }
1019+
1020+ LegalizerHelper::LegalizeResult
1021+ LegalizerHelper::createFCMPLibcall (MachineIRBuilder &MIRBuilder,
1022+ MachineInstr &MI,
1023+ LostDebugLocObserver &LocObserver) {
1024+ auto &MF = MIRBuilder.getMF ();
1025+ auto &Ctx = MF.getFunction ().getContext ();
1026+ const GFCmp *Cmp = cast<GFCmp>(&MI);
1027+
1028+ LLT OpLLT = MRI.getType (Cmp->getLHSReg ());
1029+ if (OpLLT != LLT::scalar (128 ) || OpLLT != MRI.getType (Cmp->getRHSReg ()))
1030+ return UnableToLegalize;
1031+
1032+ Type *OpType = getFloatTypeForLLT (Ctx, OpLLT);
1033+
1034+ // DstReg type is s32
1035+ const Register DstReg = Cmp->getReg (0 );
1036+ const auto Cond = Cmp->getCond ();
1037+
1038+ // Reference:
1039+ // https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1
1040+ // Generates a libcall followed by ICMP.
1041+ const auto BuildLibcall =
1042+ [&](const RTLIB::Libcall Libcall, const CmpInst::Predicate ICmpPred,
1043+ const DstOp &Res = LLT::scalar (32 )) -> Register {
1044+ // FCMP libcall always returns an i32, and needs an ICMP with #0.
1045+ constexpr LLT TempLLT = LLT::scalar (32 );
1046+ Register Temp = MRI.createGenericVirtualRegister (TempLLT);
1047+ // Generate libcall, holding result in Temp
1048+ const auto Status = createLibcall (
1049+ MIRBuilder, Libcall, {Temp, Type::getInt32Ty (Ctx), 0 },
1050+ {{Cmp->getLHSReg (), OpType, 0 }, {Cmp->getRHSReg (), OpType, 1 }},
1051+ LocObserver, &MI);
1052+ if (!Status)
1053+ return {};
1054+
1055+ // Compare temp with #0 to get the final result.
1056+ return MIRBuilder
1057+ .buildICmp (ICmpPred, Res, Temp, MIRBuilder.buildConstant (TempLLT, 0 ))
1058+ .getReg (0 );
1059+ };
1060+
1061+ // Simple case if we have a direct mapping from predicate to libcall
1062+ if (const auto [Libcall, ICmpPred] = getFCMPLibcallDesc (Cond);
1063+ Libcall != RTLIB::UNKNOWN_LIBCALL &&
1064+ ICmpPred != CmpInst::BAD_ICMP_PREDICATE) {
1065+ if (BuildLibcall (Libcall, ICmpPred, DstReg)) {
1066+ return Legalized;
1067+ }
1068+ return UnableToLegalize;
1069+ }
1070+
1071+ // No direct mapping found, should be generated as combination of libcalls.
1072+
1073+ switch (Cond) {
1074+ case CmpInst::FCMP_UEQ: {
1075+ // FCMP_UEQ: unordered or equal
1076+ // Convert into (FCMP_OEQ || FCMP_UNO).
1077+
1078+ const auto [OeqLibcall, OeqPred] = getFCMPLibcallDesc (CmpInst::FCMP_OEQ);
1079+ const auto Oeq = BuildLibcall (OeqLibcall, OeqPred);
1080+
1081+ const auto [UnoLibcall, UnoPred] = getFCMPLibcallDesc (CmpInst::FCMP_UNO);
1082+ const auto Uno = BuildLibcall (UnoLibcall, UnoPred);
1083+ if (Oeq && Uno)
1084+ MIRBuilder.buildOr (DstReg, Oeq, Uno);
1085+ else
1086+ return UnableToLegalize;
1087+
1088+ break ;
1089+ }
1090+ case CmpInst::FCMP_ONE: {
1091+ // FCMP_ONE: ordered and operands are unequal
1092+ // Convert into (!FCMP_OEQ && !FCMP_UNO).
1093+
1094+ // We inverse the predicate instead of generating a NOT
1095+ // to save one instruction.
1096+ // On AArch64 isel can even select two cmp into a single ccmp.
1097+ const auto [OeqLibcall, OeqPred] = getFCMPLibcallDesc (CmpInst::FCMP_OEQ);
1098+ const auto NotOeq =
1099+ BuildLibcall (OeqLibcall, CmpInst::getInversePredicate (OeqPred));
1100+
1101+ const auto [UnoLibcall, UnoPred] = getFCMPLibcallDesc (CmpInst::FCMP_UNO);
1102+ const auto NotUno =
1103+ BuildLibcall (UnoLibcall, CmpInst::getInversePredicate (UnoPred));
1104+
1105+ if (NotOeq && NotUno)
1106+ MIRBuilder.buildAnd (DstReg, NotOeq, NotUno);
1107+ else
1108+ return UnableToLegalize;
1109+
1110+ break ;
1111+ }
1112+ case CmpInst::FCMP_ULT:
1113+ case CmpInst::FCMP_UGE:
1114+ case CmpInst::FCMP_UGT:
1115+ case CmpInst::FCMP_ULE:
1116+ case CmpInst::FCMP_ORD: {
1117+ // Convert into: !(inverse(Pred))
1118+ // E.g. FCMP_ULT becomes !FCMP_OGE
1119+ // This is equivalent to the following, but saves some instructions.
1120+ // MIRBuilder.buildNot(
1121+ // PredTy,
1122+ // MIRBuilder.buildFCmp(CmpInst::getInversePredicate(Pred), PredTy,
1123+ // Op1, Op2));
1124+ const auto [InversedLibcall, InversedPred] =
1125+ getFCMPLibcallDesc (CmpInst::getInversePredicate (Cond));
1126+ if (!BuildLibcall (InversedLibcall,
1127+ CmpInst::getInversePredicate (InversedPred), DstReg))
1128+ return UnableToLegalize;
1129+ break ;
1130+ }
1131+ default :
1132+ return UnableToLegalize;
1133+ }
1134+
1135+ return Legalized;
1136+ }
1137+
9951138// The function is used to legalize operations that set default environment
9961139// state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
9971140// On most targets supported in glibc FE_DFL_MODE is defined as
@@ -1138,6 +1281,13 @@ LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) {
11381281 return Status;
11391282 break ;
11401283 }
1284+ case TargetOpcode::G_FCMP: {
1285+ LegalizeResult Status = createFCMPLibcall (MIRBuilder, MI, LocObserver);
1286+ if (Status != Legalized)
1287+ return Status;
1288+ MI.eraseFromParent ();
1289+ return Status;
1290+ }
11411291 case TargetOpcode::G_FPTOSI:
11421292 case TargetOpcode::G_FPTOUI: {
11431293 // FIXME: Support other types
0 commit comments