@@ -67,6 +67,8 @@ class RISCVInstructionSelector : public InstructionSelector {
67
67
bool selectSExtInreg (MachineInstr &MI, MachineIRBuilder &MIB) const ;
68
68
bool selectSelect (MachineInstr &MI, MachineIRBuilder &MIB,
69
69
MachineRegisterInfo &MRI) const ;
70
+ bool selectFPCompare (MachineInstr &MI, MachineIRBuilder &MIB,
71
+ MachineRegisterInfo &MRI) const ;
70
72
71
73
ComplexRendererFns selectShiftMask (MachineOperand &Root) const ;
72
74
ComplexRendererFns selectAddrRegImm (MachineOperand &Root) const ;
@@ -415,6 +417,8 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
415
417
}
416
418
case TargetOpcode::G_SELECT:
417
419
return selectSelect (MI, MIB, MRI);
420
+ case TargetOpcode::G_FCMP:
421
+ return selectFPCompare (MI, MIB, MRI);
418
422
default :
419
423
return false ;
420
424
}
@@ -820,6 +824,130 @@ bool RISCVInstructionSelector::selectSelect(MachineInstr &MI,
820
824
return constrainSelectedInstRegOperands (*Result, TII, TRI, RBI);
821
825
}
822
826
827
+ // Convert an FCMP predicate to one of the supported F or D instructions.
828
+ static unsigned getFCmpOpcode (CmpInst::Predicate Pred, unsigned Size) {
829
+ assert ((Size == 32 || Size == 64 ) && " Unsupported size" );
830
+ switch (Pred) {
831
+ default :
832
+ llvm_unreachable (" Unsupported predicate" );
833
+ case CmpInst::FCMP_OLT:
834
+ return Size == 32 ? RISCV::FLT_S : RISCV::FLT_D;
835
+ case CmpInst::FCMP_OLE:
836
+ return Size == 32 ? RISCV::FLE_S : RISCV::FLE_D;
837
+ case CmpInst::FCMP_OEQ:
838
+ return Size == 32 ? RISCV::FEQ_S : RISCV::FEQ_D;
839
+ }
840
+ }
841
+
842
+ // Try legalizing an FCMP by swapping or inverting the predicate to one that
843
+ // is supported.
844
+ static bool legalizeFCmpPredicate (Register &LHS, Register &RHS,
845
+ CmpInst::Predicate &Pred, bool &NeedInvert) {
846
+ auto isLegalFCmpPredicate = [](CmpInst::Predicate Pred) {
847
+ return Pred == CmpInst::FCMP_OLT || Pred == CmpInst::FCMP_OLE ||
848
+ Pred == CmpInst::FCMP_OEQ;
849
+ };
850
+
851
+ assert (!isLegalFCmpPredicate (Pred) && " Predicate already legal?" );
852
+
853
+ CmpInst::Predicate InvPred = CmpInst::getSwappedPredicate (Pred);
854
+ if (isLegalFCmpPredicate (InvPred)) {
855
+ Pred = InvPred;
856
+ std::swap (LHS, RHS);
857
+ return true ;
858
+ }
859
+
860
+ InvPred = CmpInst::getInversePredicate (Pred);
861
+ NeedInvert = true ;
862
+ if (isLegalFCmpPredicate (InvPred)) {
863
+ Pred = InvPred;
864
+ return true ;
865
+ }
866
+ InvPred = CmpInst::getSwappedPredicate (InvPred);
867
+ if (isLegalFCmpPredicate (InvPred)) {
868
+ Pred = InvPred;
869
+ std::swap (LHS, RHS);
870
+ return true ;
871
+ }
872
+
873
+ return false ;
874
+ }
875
+
876
+ // Emit a sequence of instructions to compare LHS and RHS using Pred. Return
877
+ // the result in DstReg.
878
+ // FIXME: Maybe we should expand this earlier.
879
+ bool RISCVInstructionSelector::selectFPCompare (MachineInstr &MI,
880
+ MachineIRBuilder &MIB,
881
+ MachineRegisterInfo &MRI) const {
882
+ auto &CmpMI = cast<GFCmp>(MI);
883
+ CmpInst::Predicate Pred = CmpMI.getCond ();
884
+
885
+ Register DstReg = CmpMI.getReg (0 );
886
+ Register LHS = CmpMI.getLHSReg ();
887
+ Register RHS = CmpMI.getRHSReg ();
888
+
889
+ unsigned Size = MRI.getType (LHS).getSizeInBits ();
890
+ assert ((Size == 32 || Size == 64 ) && " Unexpected size" );
891
+
892
+ Register TmpReg = DstReg;
893
+
894
+ bool NeedInvert = false ;
895
+ // First try swapping operands or inverting.
896
+ if (legalizeFCmpPredicate (LHS, RHS, Pred, NeedInvert)) {
897
+ if (NeedInvert)
898
+ TmpReg = MRI.createVirtualRegister (&RISCV::GPRRegClass);
899
+ auto Cmp = MIB.buildInstr (getFCmpOpcode (Pred, Size), {TmpReg}, {LHS, RHS});
900
+ if (!Cmp.constrainAllUses (TII, TRI, RBI))
901
+ return false ;
902
+ } else if (Pred == CmpInst::FCMP_ONE || Pred == CmpInst::FCMP_UEQ) {
903
+ // fcmp one LHS, RHS => (OR (FLT LHS, RHS), (FLT RHS, LHS))
904
+ NeedInvert = Pred == CmpInst::FCMP_UEQ;
905
+ auto Cmp1 = MIB.buildInstr (getFCmpOpcode (CmpInst::FCMP_OLT, Size),
906
+ {&RISCV::GPRRegClass}, {LHS, RHS});
907
+ if (!Cmp1.constrainAllUses (TII, TRI, RBI))
908
+ return false ;
909
+ auto Cmp2 = MIB.buildInstr (getFCmpOpcode (CmpInst::FCMP_OLT, Size),
910
+ {&RISCV::GPRRegClass}, {RHS, LHS});
911
+ if (!Cmp2.constrainAllUses (TII, TRI, RBI))
912
+ return false ;
913
+ if (NeedInvert)
914
+ TmpReg = MRI.createVirtualRegister (&RISCV::GPRRegClass);
915
+ auto Or =
916
+ MIB.buildInstr (RISCV::OR, {TmpReg}, {Cmp1.getReg (0 ), Cmp2.getReg (0 )});
917
+ if (!Or.constrainAllUses (TII, TRI, RBI))
918
+ return false ;
919
+ } else if (Pred == CmpInst::FCMP_ORD || Pred == CmpInst::FCMP_UNO) {
920
+ // fcmp ord LHS, RHS => (AND (FEQ LHS, LHS), (FEQ RHS, RHS))
921
+ // FIXME: If LHS and RHS are the same we can use a single FEQ.
922
+ NeedInvert = Pred == CmpInst::FCMP_UNO;
923
+ auto Cmp1 = MIB.buildInstr (getFCmpOpcode (CmpInst::FCMP_OEQ, Size),
924
+ {&RISCV::GPRRegClass}, {LHS, LHS});
925
+ if (!Cmp1.constrainAllUses (TII, TRI, RBI))
926
+ return false ;
927
+ auto Cmp2 = MIB.buildInstr (getFCmpOpcode (CmpInst::FCMP_OEQ, Size),
928
+ {&RISCV::GPRRegClass}, {RHS, RHS});
929
+ if (!Cmp2.constrainAllUses (TII, TRI, RBI))
930
+ return false ;
931
+ if (NeedInvert)
932
+ TmpReg = MRI.createVirtualRegister (&RISCV::GPRRegClass);
933
+ auto And =
934
+ MIB.buildInstr (RISCV::AND, {TmpReg}, {Cmp1.getReg (0 ), Cmp2.getReg (0 )});
935
+ if (!And.constrainAllUses (TII, TRI, RBI))
936
+ return false ;
937
+ } else
938
+ llvm_unreachable (" Unhandled predicate" );
939
+
940
+ // Emit an XORI to invert the result if needed.
941
+ if (NeedInvert) {
942
+ auto Xor = MIB.buildInstr (RISCV::XORI, {DstReg}, {TmpReg}).addImm (1 );
943
+ if (!Xor.constrainAllUses (TII, TRI, RBI))
944
+ return false ;
945
+ }
946
+
947
+ MI.eraseFromParent ();
948
+ return true ;
949
+ }
950
+
823
951
namespace llvm {
824
952
InstructionSelector *
825
953
createRISCVInstructionSelector (const RISCVTargetMachine &TM,
0 commit comments