@@ -735,8 +735,7 @@ static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI) {
735
735
if (MemType.isVector ())
736
736
return RTLIB::UNKNOWN_LIBCALL;
737
737
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}
740
739
#define LCALL5 (A ) \
741
740
LCALLS (A, 1 ), LCALLS (A, 2 ), LCALLS (A, 4 ), LCALLS (A, 8 ), LCALLS (A, 16 )
742
741
switch (Opc) {
@@ -992,6 +991,150 @@ LegalizerHelper::createSetStateLibcall(MachineIRBuilder &MIRBuilder,
992
991
LocObserver, nullptr );
993
992
}
994
993
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
+
995
1138
// The function is used to legalize operations that set default environment
996
1139
// state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
997
1140
// On most targets supported in glibc FE_DFL_MODE is defined as
@@ -1138,6 +1281,13 @@ LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) {
1138
1281
return Status;
1139
1282
break ;
1140
1283
}
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
+ }
1141
1291
case TargetOpcode::G_FPTOSI:
1142
1292
case TargetOpcode::G_FPTOUI: {
1143
1293
// FIXME: Support other types
0 commit comments