Skip to content

Commit 94564b7

Browse files
author
mattarde
committed
[X86][GlobalIsel] Support IS_FP_CLASS intrinsic 1/4
1 parent 90de4a4 commit 94564b7

File tree

4 files changed

+561
-0
lines changed

4 files changed

+561
-0
lines changed

llvm/lib/CodeGen/LowLevelTypeUtils.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ const llvm::fltSemantics &llvm::getFltSemanticForLLT(LLT Ty) {
8080
return APFloat::IEEEsingle();
8181
case 64:
8282
return APFloat::IEEEdouble();
83+
case 80:
84+
return APFloat::x87DoubleExtended();
8385
case 128:
8486
return APFloat::IEEEquad();
8587
}

llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "X86LegalizerInfo.h"
1414
#include "X86Subtarget.h"
1515
#include "X86TargetMachine.h"
16+
#include "llvm/CodeGen/CodeGenCommonISel.h"
1617
#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
1718
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
1819
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
@@ -579,6 +580,7 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
579580
getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE})
580581
.lower();
581582

583+
getActionDefinitionsBuilder(G_IS_FPCLASS).custom();
582584
// fp intrinsics
583585
getActionDefinitionsBuilder(G_INTRINSIC_ROUNDEVEN)
584586
.scalarize(0)
@@ -616,6 +618,8 @@ bool X86LegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
616618
return legalizeFPTOSI(MI, MRI, Helper);
617619
case TargetOpcode::G_GET_ROUNDING:
618620
return legalizeGETROUNDING(MI, MRI, Helper);
621+
case TargetOpcode::G_IS_FPCLASS:
622+
return legalizeIsFPClass(MI, MRI, Helper);
619623
}
620624
llvm_unreachable("expected switch to return");
621625
}
@@ -853,10 +857,236 @@ bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI,
853857
auto RetValTrunc = MIRBuilder.buildZExtOrTrunc(DstTy, RetVal);
854858

855859
MIRBuilder.buildCopy(Dst, RetValTrunc);
860+
MI.eraseFromParent();
861+
return true;
862+
}
863+
864+
bool X86LegalizerInfo::expandFPClassTestForF32OrF64(
865+
MachineInstr &MI, MachineRegisterInfo &MRI, LegalizerHelper &Helper) const {
866+
MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
867+
auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
868+
FPClassTest Test = static_cast<FPClassTest>(MI.getOperand(2).getImm());
869+
assert(!SrcTy.isVector() && "G_IS_FPCLASS does not support vectors yet");
870+
const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
871+
872+
// Some checks may be represented as inversion of simpler check, for example
873+
// "inf|normal|subnormal|zero" => !"nan".
874+
bool IsInverted = false;
875+
876+
if (FPClassTest InvertedCheck = invertFPClassTestIfSimpler(Test, false)) {
877+
Test = InvertedCheck;
878+
IsInverted = true;
879+
}
880+
881+
// In the general case use integer operations.
882+
unsigned BitSize = SrcTy.getScalarSizeInBits();
883+
LLT IntVT = LLT::scalar(BitSize);
884+
// MachineInstrBuilder OpAsInt = MIRBuilder.buildBitcast(IntVT, SrcReg);
885+
MachineInstrBuilder OpAsInt = MIRBuilder.buildCopy(IntVT, SrcReg);
886+
887+
// Various Mask
888+
APInt SignMask = APInt::getSignMask(BitSize);
889+
APInt ValueMask = APInt::getSignedMaxValue(BitSize);
890+
APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt();
891+
APInt InfPlus1 = Inf + 1;
892+
APInt ExpMask = Inf;
893+
APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
894+
APInt QNaNBitMask =
895+
APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
896+
APInt InvertionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
897+
898+
auto ValueMaskV = MIRBuilder.buildConstant(IntVT, ValueMask);
899+
auto SignBitV = MIRBuilder.buildConstant(IntVT, SignMask);
900+
auto ExpMaskV = MIRBuilder.buildConstant(IntVT, ExpMask);
901+
auto ZeroV = MIRBuilder.buildConstant(IntVT, 0);
902+
auto InfV = MIRBuilder.buildConstant(IntVT, Inf);
903+
auto InfPlus1V = MIRBuilder.buildConstant(IntVT, InfPlus1);
904+
auto ResultInvertedV = MIRBuilder.buildConstant(DstTy, InvertionMask);
905+
906+
MachineInstrBuilder Res;
907+
const auto appendResult = [&](MachineInstrBuilder &PartialRes) {
908+
if (PartialRes.getInstr()) {
909+
if (Res.getInstr()) {
910+
Res = MIRBuilder.buildOr(DstTy, Res, PartialRes);
911+
} else {
912+
Res = PartialRes;
913+
}
914+
}
915+
};
916+
// Split the value into sign bit and absolute value.
917+
auto AbsV = MIRBuilder.buildAnd(IntVT, OpAsInt, ValueMaskV);
918+
auto SignVDestReg = MRI.createGenericVirtualRegister(LLT::scalar(1));
919+
auto SignV =
920+
MIRBuilder.buildICmp(CmpInst::ICMP_SLT, SignVDestReg, OpAsInt, ZeroV);
921+
922+
// Tests that involve more than one class should be processed first.
923+
MachineInstrBuilder PartialRes;
924+
925+
if ((Test & fcFinite) == fcFinite) {
926+
// finite(V) ==> abs(V) < exp_mask
927+
PartialRes = MIRBuilder.buildICmp(
928+
IsInverted ? CmpInst::ICMP_SGE : CmpInst::ICMP_SLT,
929+
MRI.createGenericVirtualRegister(LLT::scalar(1)), AbsV, ExpMaskV);
930+
Test &= ~fcFinite;
931+
} else if ((Test & fcFinite) == fcPosFinite) {
932+
// finite(V) && V > 0 ==> V < exp_mask
933+
PartialRes = MIRBuilder.buildICmp(
934+
IsInverted ? CmpInst::ICMP_UGE : CmpInst::ICMP_ULT,
935+
MRI.createGenericVirtualRegister(LLT::scalar(1)), OpAsInt, ExpMaskV);
936+
Test &= ~fcPosFinite;
937+
} else if ((Test & fcFinite) == fcNegFinite) {
938+
// finite(V) && V < 0 ==> abs(V) < exp_mask && signbit == 1
939+
auto PartialResPart = MIRBuilder.buildICmp(
940+
CmpInst::ICMP_SLT, MRI.createGenericVirtualRegister(LLT::scalar(1)),
941+
AbsV, ExpMaskV);
942+
PartialRes = MIRBuilder.buildAnd(LLT::scalar(1), PartialResPart, SignV);
943+
Test &= ~fcNegFinite;
944+
}
945+
appendResult(PartialRes);
946+
947+
if (FPClassTest PartialCheck = Test & (fcZero | fcSubnormal)) {
948+
// fcZero | fcSubnormal => test all exponent bits are 0
949+
// TODO: Handle sign bit specific cases
950+
if (PartialCheck == (fcZero | fcSubnormal)) {
951+
auto ExpBits = MIRBuilder.buildAnd(IntVT, OpAsInt, ExpMaskV);
952+
auto ExpIsZero = MIRBuilder.buildICmp(
953+
CmpInst::ICMP_EQ, MRI.createGenericVirtualRegister(LLT::scalar(1)),
954+
ExpBits, ZeroV);
955+
appendResult(ExpIsZero);
956+
Test &= ~PartialCheck & fcAllFlags;
957+
}
958+
}
959+
960+
// Check for individual classes.
961+
if (unsigned PartialCheck = Test & fcZero) {
962+
if (PartialCheck == fcPosZero)
963+
PartialRes = MIRBuilder.buildICmp(
964+
CmpInst::ICMP_EQ, MRI.createGenericVirtualRegister(LLT::scalar(1)),
965+
OpAsInt, ZeroV);
966+
else if (PartialCheck == fcZero)
967+
PartialRes = MIRBuilder.buildICmp(
968+
CmpInst::ICMP_EQ, MRI.createGenericVirtualRegister(LLT::scalar(1)),
969+
AbsV, ZeroV);
970+
else // ISD::fcNegZero
971+
PartialRes = MIRBuilder.buildICmp(
972+
CmpInst::ICMP_EQ, MRI.createGenericVirtualRegister(LLT::scalar(1)),
973+
OpAsInt, SignBitV);
974+
appendResult(PartialRes);
975+
}
976+
if (unsigned PartialCheck = Test & fcSubnormal) {
977+
assert("Not Supported yet!");
978+
}
979+
if (unsigned PartialCheck = Test & fcInf) {
980+
if (PartialCheck == fcPosInf)
981+
PartialRes = MIRBuilder.buildICmp(
982+
IsInverted ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ,
983+
MRI.createGenericVirtualRegister(LLT::scalar(1)), OpAsInt, InfV);
984+
else if (PartialCheck == fcInf)
985+
PartialRes = MIRBuilder.buildICmp(
986+
IsInverted ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ,
987+
MRI.createGenericVirtualRegister(LLT::scalar(1)), AbsV, InfV);
988+
else { // ISD::fcNegInf
989+
APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
990+
auto NegInfV = MIRBuilder.buildConstant(IntVT, NegInf);
991+
PartialRes = MIRBuilder.buildICmp(
992+
IsInverted ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ,
993+
MRI.createGenericVirtualRegister(LLT::scalar(1)), OpAsInt, NegInfV);
994+
}
995+
MIRBuilder.buildCopy(DstReg, PartialRes);
996+
MI.eraseFromParent();
997+
return true;
998+
}
999+
if (unsigned PartialCheck = Test & fcNan) {
1000+
APInt InfWithQnanBit = Inf | QNaNBitMask;
1001+
auto InfWithQnanBitV = MIRBuilder.buildConstant(IntVT, InfWithQnanBit);
1002+
if (PartialCheck == fcNan) {
1003+
// isnan(V) ==> abs(V) > int(inf)
1004+
auto AbsDstReg = MRI.createGenericVirtualRegister(LLT::scalar(BitSize));
1005+
auto FAbsV = MIRBuilder.buildCopy(AbsDstReg, SrcReg);
1006+
auto InfVDstReg = MRI.createGenericVirtualRegister(LLT::scalar(BitSize));
1007+
PartialRes = MIRBuilder.buildFCmp(
1008+
CmpInst::FCMP_UEQ, MRI.createGenericVirtualRegister(LLT::scalar(1)),
1009+
FAbsV, FAbsV);
1010+
} else if (PartialCheck == fcQNan) {
1011+
// isquiet(V) ==> abs(V) >= (unsigned(Inf) | quiet_bit)
1012+
PartialRes = MIRBuilder.buildICmp(
1013+
IsInverted ? CmpInst::ICMP_SLT : CmpInst::ICMP_SGE,
1014+
MRI.createGenericVirtualRegister(LLT::scalar(1)), AbsV,
1015+
InfWithQnanBitV);
1016+
1017+
} else { // ISD::fcSNan
1018+
// issignaling(V) ==> abs(V) > unsigned(Inf) &&
1019+
// abs(V) < (unsigned(Inf) | quiet_bit)
1020+
auto IsNotQnan = MIRBuilder.buildICmp(
1021+
CmpInst::ICMP_SLT, MRI.createGenericVirtualRegister(LLT::scalar(1)),
1022+
AbsV, InfWithQnanBitV);
1023+
auto IsNan = MIRBuilder.buildICmp(
1024+
CmpInst::ICMP_SGE, MRI.createGenericVirtualRegister(LLT::scalar(1)),
1025+
AbsV, InfPlus1V);
1026+
PartialRes = MIRBuilder.buildAnd(LLT::scalar(1), IsNan, IsNotQnan);
1027+
}
1028+
MIRBuilder.buildCopy(DstReg, PartialRes);
1029+
MI.eraseFromParent();
1030+
return true;
1031+
}
1032+
if (unsigned PartialCheck = Test & fcNormal) {
1033+
assert("Not Supported yet!");
1034+
}
1035+
if (unsigned PartialCheck = Test & fcSubnormal) {
1036+
// subnormal(V) ==> abs(V) < exp_mask && signbit == 0
1037+
auto ExpBits = MIRBuilder.buildAnd(IntVT, OpAsInt, ExpMaskV);
1038+
auto ExpIsZero = MIRBuilder.buildICmp(
1039+
CmpInst::ICMP_EQ, MRI.createGenericVirtualRegister(LLT::scalar(1)),
1040+
ExpBits, ZeroV);
1041+
auto SignBit = MIRBuilder.buildICmp(
1042+
CmpInst::ICMP_EQ, MRI.createGenericVirtualRegister(LLT::scalar(1)),
1043+
SignV, ZeroV);
1044+
PartialRes = MIRBuilder.buildAnd(LLT::scalar(1), ExpIsZero, SignBit);
1045+
appendResult(PartialRes);
1046+
}
1047+
if (!Res.getInstr()) {
1048+
Res = MIRBuilder.buildConstant(LLT::scalar(1), IsInverted);
1049+
MIRBuilder.buildCopy(DstReg, Res);
1050+
MI.eraseFromParent();
1051+
return true;
1052+
}
8561053

1054+
MIRBuilder.buildCopy(DstReg, Res);
8571055
MI.eraseFromParent();
8581056
return true;
8591057
}
1058+
bool X86LegalizerInfo::expandFPClassTestForF80(MachineInstr &MI,
1059+
MachineRegisterInfo &MRI,
1060+
LegalizerHelper &Helper) const {
1061+
return false;
1062+
}
1063+
1064+
bool X86LegalizerInfo::legalizeIsFPClass(MachineInstr &MI,
1065+
MachineRegisterInfo &MRI,
1066+
LegalizerHelper &Helper) const {
1067+
MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1068+
auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
1069+
assert(!SrcTy.isVector() && "G_IS_FPCLASS does not support vectors yet");
1070+
1071+
FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
1072+
if (Mask == fcNone) {
1073+
MIRBuilder.buildConstant(DstReg, 0);
1074+
MI.eraseFromParent();
1075+
return true;
1076+
}
1077+
if (Mask == fcAllFlags) {
1078+
MIRBuilder.buildConstant(DstReg, 1);
1079+
MI.eraseFromParent();
1080+
return true;
1081+
}
1082+
bool IsF80 = (SrcTy == LLT::scalar(80));
1083+
// For f32/f64/f80 if NoFpException is set, we can use the FCMP
1084+
// Some checks can be implemented using float comparisons, if floating point
1085+
// exceptions are ignored.
1086+
1087+
if (IsF80)
1088+
return expandFPClassTestForF80(MI, MRI, Helper);
1089+
}
8601090

8611091
bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
8621092
MachineInstr &MI) const {

llvm/lib/Target/X86/GISel/X86LegalizerInfo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ class X86LegalizerInfo : public LegalizerInfo {
5757

5858
bool legalizeGETROUNDING(MachineInstr &MI, MachineRegisterInfo &MRI,
5959
LegalizerHelper &Helper) const;
60+
bool expandFPClassTestForF32OrF64(MachineInstr &MI, MachineRegisterInfo &MRI,
61+
LegalizerHelper &Helper) const;
62+
bool expandFPClassTestForF80(MachineInstr &MI, MachineRegisterInfo &MRI,
63+
LegalizerHelper &Helper) const;
64+
bool legalizeIsFPClass(MachineInstr &MI, MachineRegisterInfo &MRI,
65+
LegalizerHelper &Helper) const;
6066
};
6167
} // namespace llvm
6268
#endif

0 commit comments

Comments
 (0)