|
13 | 13 | #include "X86LegalizerInfo.h" |
14 | 14 | #include "X86Subtarget.h" |
15 | 15 | #include "X86TargetMachine.h" |
| 16 | +#include "llvm/CodeGen/CodeGenCommonISel.h" |
16 | 17 | #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" |
17 | 18 | #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" |
18 | 19 | #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" |
@@ -579,6 +580,7 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI, |
579 | 580 | getActionDefinitionsBuilder({G_DYN_STACKALLOC, G_STACKSAVE, G_STACKRESTORE}) |
580 | 581 | .lower(); |
581 | 582 |
|
| 583 | + getActionDefinitionsBuilder(G_IS_FPCLASS).custom(); |
582 | 584 | // fp intrinsics |
583 | 585 | getActionDefinitionsBuilder(G_INTRINSIC_ROUNDEVEN) |
584 | 586 | .scalarize(0) |
@@ -616,6 +618,8 @@ bool X86LegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI, |
616 | 618 | return legalizeFPTOSI(MI, MRI, Helper); |
617 | 619 | case TargetOpcode::G_GET_ROUNDING: |
618 | 620 | return legalizeGETROUNDING(MI, MRI, Helper); |
| 621 | + case TargetOpcode::G_IS_FPCLASS: |
| 622 | + return legalizeIsFPClass(MI, MRI, Helper); |
619 | 623 | } |
620 | 624 | llvm_unreachable("expected switch to return"); |
621 | 625 | } |
@@ -853,10 +857,236 @@ bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI, |
853 | 857 | auto RetValTrunc = MIRBuilder.buildZExtOrTrunc(DstTy, RetVal); |
854 | 858 |
|
855 | 859 | 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 | + } |
856 | 1053 |
|
| 1054 | + MIRBuilder.buildCopy(DstReg, Res); |
857 | 1055 | MI.eraseFromParent(); |
858 | 1056 | return true; |
859 | 1057 | } |
| 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 | +} |
860 | 1090 |
|
861 | 1091 | bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper, |
862 | 1092 | MachineInstr &MI) const { |
|
0 commit comments