[llvm] [RISCV][GISel] Add support for G_IS_FPCLASS in F and D extensions (PR #72000)

Min-Yih Hsu via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 22 16:42:02 PST 2023


https://github.com/mshockwave updated https://github.com/llvm/llvm-project/pull/72000

>From eeb13b145ef6083830d50b4e8a4b9687e316007d Mon Sep 17 00:00:00 2001
From: Min-Yih Hsu <min.hsu at sifive.com>
Date: Fri, 10 Nov 2023 10:51:21 -0800
Subject: [PATCH 01/11] [RISCG][GISel] Add support for G_IS_FPCLASS in F and D
 extensions

Add legalizer, regbankselect, and isel supports for floating point
version of G_IS_FPCLASS.
---
 .../CodeGen/GlobalISel/LegalizerHelper.cpp    |  1 +
 .../RISCV/GISel/RISCVInstructionSelector.cpp  | 28 +++++++++++++++++++
 .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 24 ++++++++++++++++
 .../RISCV/GISel/RISCVRegisterBankInfo.cpp     |  6 ++++
 .../instruction-select/is-fpclass-rv32.mir    | 25 +++++++++++++++++
 .../instruction-select/is-fpclass-rv64.mir    | 25 +++++++++++++++++
 .../legalizer/legalize-is-fpclass-rv32.mir    | 24 ++++++++++++++++
 .../legalizer/legalize-is-fpclass-rv64.mir    | 24 ++++++++++++++++
 .../regbankselect/is-fpclass-rv32.mir         | 23 +++++++++++++++
 .../regbankselect/is-fpclass-rv64.mir         | 23 +++++++++++++++
 10 files changed, 203 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir

diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 47d676e94720765..11d01429485dcbc 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -2483,6 +2483,7 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
 
   case TargetOpcode::G_FPTOSI:
   case TargetOpcode::G_FPTOUI:
+  case TargetOpcode::G_IS_FPCLASS:
     Observer.changingInstr(MI);
 
     if (TypeIdx == 0)
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 3c72269d1e00c2f..90dc78f47fb82f1 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -72,6 +72,8 @@ class RISCVInstructionSelector : public InstructionSelector {
                     MachineRegisterInfo &MRI) const;
   bool selectFPCompare(MachineInstr &MI, MachineIRBuilder &MIB,
                        MachineRegisterInfo &MRI) const;
+  bool selectIsFPClass(MachineInstr &MI, MachineIRBuilder &MIB,
+                       MachineRegisterInfo &MRI) const;
 
   ComplexRendererFns selectShiftMask(MachineOperand &Root) const;
   ComplexRendererFns selectAddrRegImm(MachineOperand &Root) const;
@@ -564,6 +566,8 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
     return selectSelect(MI, MIB, MRI);
   case TargetOpcode::G_FCMP:
     return selectFPCompare(MI, MIB, MRI);
+  case TargetOpcode::G_IS_FPCLASS:
+    return selectIsFPClass(MI, MIB, MRI);
   default:
     return false;
   }
@@ -1099,6 +1103,30 @@ bool RISCVInstructionSelector::selectFPCompare(MachineInstr &MI,
   return true;
 }
 
+bool RISCVInstructionSelector::selectIsFPClass(MachineInstr &MI,
+                                               MachineIRBuilder &MIB,
+                                               MachineRegisterInfo &MRI) const {
+  Register CheckResult = MI.getOperand(0).getReg();
+  Register Src = MI.getOperand(1).getReg();
+  int64_t MaskImm = MI.getOperand(2).getImm();
+  unsigned NewOpc = MRI.getType(Src).getSizeInBits() == 32 ? RISCV::FCLASS_S
+                                                           : RISCV::FCLASS_D;
+
+  Register FClassResult = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+  // Insert FCLASS_S/D.
+  auto FClass = MIB.buildInstr(NewOpc, {FClassResult}, {Src});
+  if (!FClass.constrainAllUses(TII, TRI, RBI))
+    return false;
+  // Insert AND to check Src aginst the mask.
+  auto And = MIB.buildInstr(RISCV::ANDI, {CheckResult}, {FClassResult})
+                 .addImm(MaskImm);
+  if (!And.constrainAllUses(TII, TRI, RBI))
+    return false;
+
+  MI.eraseFromParent();
+  return true;
+}
+
 namespace llvm {
 InstructionSelector *
 createRISCVInstructionSelector(const RISCVTargetMachine &TM,
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 9eb5812e024b915..9b74190d00336ba 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -240,10 +240,23 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) {
                 typeIs(1, s32)(Query));
       });
 
+  // Predicates shared by G_FCMP and G_IS_FPCLASS.
+  auto isScalarAndFP = [=, &ST](const LegalityQuery &Query) -> bool {
+    return typeIs(0, sXLen)(Query) &&
+           ((ST.hasStdExtF() && typeIs(1, s32)(Query)) ||
+            (ST.hasStdExtD() && typeIs(1, s64)(Query)));
+  };
   getActionDefinitionsBuilder(G_FCMP)
       .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
       .clampScalar(0, sXLen, sXLen);
 
+  // TODO: Support vector version of G_IS_FPCLASS.
+  getActionDefinitionsBuilder(G_IS_FPCLASS)
+      // This line basically equals to `legalIf(isScalarAndFP)` + post
+      // processing depicted in legalizeCustom.
+      .customIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
+      .clampScalar(0, sXLen, sXLen);
+
   getActionDefinitionsBuilder(G_FCONSTANT).legalIf(typeIsScalarFPArith(0, ST));
 
   getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
@@ -309,6 +322,17 @@ bool RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
     return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
            LegalizerHelper::Legalized;
   }
+  case TargetOpcode::G_IS_FPCLASS: {
+    // Turn LLVM IR's floating point classes to that in RISCV,
+    // which is simply rotating the 10-bit immediate right by two bits.
+    MachineOperand &ImmOp = MI.getOperand(2);
+    APInt ClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
+    ImmOp.setImm(ClassImm.rotr(2).getLimitedValue());
+    // Note that we do NOT want to notify Observer as it will
+    // send this instruction back to the legalizer chain and eventually
+    // falls into an infinite loop.
+    return true;
+  }
   }
 
   llvm_unreachable("expected switch to return");
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
index 6d77e2b7edd9010..6afa73c956a4fe9 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
@@ -353,6 +353,12 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
     OpdsMapping[2] = OpdsMapping[3] = getFPValueMapping(Size);
     break;
   }
+  case TargetOpcode::G_IS_FPCLASS: {
+    LLT FPTy = MRI.getType(MI.getOperand(1).getReg());
+    OperandsMapping = getOperandsMapping(
+        {GPRValueMapping, getFPValueMapping(FPTy.getSizeInBits()), nullptr});
+    break;
+  }
   default:
     // By default map all scalars to GPR.
     for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
new file mode 100644
index 000000000000000..9590b1afe1d32fe
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
@@ -0,0 +1,25 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+# RUN: llc -mtriple=riscv32 -mattr=+d -run-pass=instruction-select -verify-machineinstrs %s -o - | \
+# RUN: FileCheck %s
+
+---
+name:            is_fpclass_f32
+legalized:       true
+regBankSelected: true
+body:             |
+  bb.0:
+    liveins: $f10_f
+
+    ; CHECK-LABEL: name: is_fpclass_f32
+    ; CHECK: liveins: $f10_f
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr32 = COPY $f10_f
+    ; CHECK-NEXT: [[FCLASS_S:%[0-9]+]]:gpr = FCLASS_S [[COPY]]
+    ; CHECK-NEXT: [[ANDI:%[0-9]+]]:gpr = ANDI [[FCLASS_S]], 152
+    ; CHECK-NEXT: $x10 = COPY [[ANDI]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:fprb(s32) = COPY $f10_f
+    %1:gprb(s32) = G_IS_FPCLASS %0(s32), 152
+    $x10 = COPY %1(s32)
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
new file mode 100644
index 000000000000000..98f748ed98481a8
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
@@ -0,0 +1,25 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+# RUN: llc -mtriple=riscv64 -mattr=+d -run-pass=instruction-select -verify-machineinstrs %s -o - | \
+# RUN: FileCheck %s
+
+---
+name:            is_fpclass_f64
+legalized:       true
+regBankSelected: true
+body:             |
+  bb.0:
+    liveins: $f10_d
+
+    ; CHECK-LABEL: name: is_fpclass_f64
+    ; CHECK: liveins: $f10_d
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
+    ; CHECK-NEXT: [[FCLASS_D:%[0-9]+]]:gpr = FCLASS_D [[COPY]]
+    ; CHECK-NEXT: [[ANDI:%[0-9]+]]:gpr = ANDI [[FCLASS_D]], 152
+    ; CHECK-NEXT: $x10 = COPY [[ANDI]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:fprb(s64) = COPY $f10_d
+    %1:gprb(s64) = G_IS_FPCLASS %0(s64), 152
+    $x10 = COPY %1(s64)
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir
new file mode 100644
index 000000000000000..3f8b77aa59264f0
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir
@@ -0,0 +1,24 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+# RUN: llc -mtriple=riscv32 -mattr=+d -run-pass=legalizer %s -o - \
+# RUN: | FileCheck %s
+
+---
+name:            is_fpclass_f32
+body:             |
+  bb.1:
+    liveins: $f10_f
+
+    ; CHECK-LABEL: name: is_fpclass_f32
+    ; CHECK: liveins: $f10_f
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $f10_f
+    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:_(s32) = G_IS_FPCLASS [[COPY]](s32), 152
+    ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:_(s32) = COPY $f10_f
+    %1:_(s1) = G_IS_FPCLASS %0(s32), 608
+    %2:_(s32) = G_ANYEXT %1(s1)
+    $x10 = COPY %2(s32)
+    PseudoRET implicit $x10
+
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir
new file mode 100644
index 000000000000000..96bf5270a91107a
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir
@@ -0,0 +1,24 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+# RUN: llc -mtriple=riscv64 -mattr=+d -run-pass=legalizer %s -o - \
+# RUN: | FileCheck %s
+
+---
+name:            is_fpclass_f64
+body:             |
+  bb.1:
+    liveins: $f10_d
+
+    ; CHECK-LABEL: name: is_fpclass_f64
+    ; CHECK: liveins: $f10_d
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $f10_d
+    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:_(s64) = G_IS_FPCLASS [[COPY]](s64), 152
+    ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:_(s64) = COPY $f10_d
+    %1:_(s1) = G_IS_FPCLASS %0(s64), 608
+    %2:_(s64) = G_ANYEXT %1(s1)
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir
new file mode 100644
index 000000000000000..6c8241f14b73135
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir
@@ -0,0 +1,23 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+# RUN: llc -mtriple=riscv32 -mattr=+d -run-pass=regbankselect -verify-machineinstrs %s -o - \
+# RUN: | FileCheck %s
+
+---
+name:            is_fpclass_f32
+legalized:       true
+body:             |
+  bb.0:
+    liveins: $f10_f
+
+    ; CHECK-LABEL: name: is_fpclass_f32
+    ; CHECK: liveins: $f10_f
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fprb(s32) = COPY $f10_f
+    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:gprb(s32) = G_IS_FPCLASS [[COPY]](s32), 152
+    ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:_(s32) = COPY $f10_f
+    %3:_(s32) = G_IS_FPCLASS %0(s32), 152
+    $x10 = COPY %3(s32)
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir
new file mode 100644
index 000000000000000..ad6fcd0dd379e38
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir
@@ -0,0 +1,23 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+# RUN: llc -mtriple=riscv64 -mattr=+d -run-pass=regbankselect -verify-machineinstrs %s -o - \
+# RUN: | FileCheck %s
+
+---
+name:            is_fpclass_f64
+legalized:       true
+body:             |
+  bb.0:
+    liveins: $f10_d
+
+    ; CHECK-LABEL: name: is_fpclass_f64
+    ; CHECK: liveins: $f10_d
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fprb(s64) = COPY $f10_d
+    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:gprb(s64) = G_IS_FPCLASS [[COPY]](s64), 152
+    ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:_(s64) = COPY $f10_d
+    %3:_(s64) = G_IS_FPCLASS %0(s64), 152
+    $x10 = COPY %3(s64)
+    PseudoRET implicit $x10
+...

>From 7b839278c9254bdbc72e0bbc1b1e96ce0d10e9fb Mon Sep 17 00:00:00 2001
From: Min-Yih Hsu <min.hsu at sifive.com>
Date: Mon, 13 Nov 2023 08:55:24 -0800
Subject: [PATCH 02/11] Move transformation of FPClass mask from legalizer to
 isel

And addressed some comments.
---
 .../RISCV/GISel/RISCVInstructionSelector.cpp  | 13 ++++++---
 .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 27 ++-----------------
 .../instruction-select/is-fpclass-rv64.mir    |  2 +-
 .../legalizer/legalize-is-fpclass-rv64.mir    |  2 +-
 4 files changed, 13 insertions(+), 31 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 90dc78f47fb82f1..ba1e458be94114a 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -1106,20 +1106,25 @@ bool RISCVInstructionSelector::selectFPCompare(MachineInstr &MI,
 bool RISCVInstructionSelector::selectIsFPClass(MachineInstr &MI,
                                                MachineIRBuilder &MIB,
                                                MachineRegisterInfo &MRI) const {
-  Register CheckResult = MI.getOperand(0).getReg();
+  Register GISFPCLASS = MI.getOperand(0).getReg();
   Register Src = MI.getOperand(1).getReg();
-  int64_t MaskImm = MI.getOperand(2).getImm();
+  const MachineOperand &ImmOp = MI.getOperand(2);
   unsigned NewOpc = MRI.getType(Src).getSizeInBits() == 32 ? RISCV::FCLASS_S
                                                            : RISCV::FCLASS_D;
 
+  // Turn LLVM IR's floating point classes to that in RISCV,
+  // by simply rotating the 10-bit immediate right by two bits.
+  APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
+  APInt FClassMask = GFpClassImm.rotr(2);
+
   Register FClassResult = MRI.createVirtualRegister(&RISCV::GPRRegClass);
   // Insert FCLASS_S/D.
   auto FClass = MIB.buildInstr(NewOpc, {FClassResult}, {Src});
   if (!FClass.constrainAllUses(TII, TRI, RBI))
     return false;
   // Insert AND to check Src aginst the mask.
-  auto And = MIB.buildInstr(RISCV::ANDI, {CheckResult}, {FClassResult})
-                 .addImm(MaskImm);
+  auto And = MIB.buildInstr(RISCV::ANDI, {GISFPCLASS}, {FClassResult})
+                 .addImm(FClassMask.getLimitedValue());
   if (!And.constrainAllUses(TII, TRI, RBI))
     return false;
 
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 9b74190d00336ba..6b97f1c919e0637 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -240,21 +240,9 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) {
                 typeIs(1, s32)(Query));
       });
 
-  // Predicates shared by G_FCMP and G_IS_FPCLASS.
-  auto isScalarAndFP = [=, &ST](const LegalityQuery &Query) -> bool {
-    return typeIs(0, sXLen)(Query) &&
-           ((ST.hasStdExtF() && typeIs(1, s32)(Query)) ||
-            (ST.hasStdExtD() && typeIs(1, s64)(Query)));
-  };
-  getActionDefinitionsBuilder(G_FCMP)
-      .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
-      .clampScalar(0, sXLen, sXLen);
-
   // TODO: Support vector version of G_IS_FPCLASS.
-  getActionDefinitionsBuilder(G_IS_FPCLASS)
-      // This line basically equals to `legalIf(isScalarAndFP)` + post
-      // processing depicted in legalizeCustom.
-      .customIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
+  getActionDefinitionsBuilder({G_FCMP, G_IS_FPCLASS})
+      .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
       .clampScalar(0, sXLen, sXLen);
 
   getActionDefinitionsBuilder(G_FCONSTANT).legalIf(typeIsScalarFPArith(0, ST));
@@ -322,17 +310,6 @@ bool RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
     return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
            LegalizerHelper::Legalized;
   }
-  case TargetOpcode::G_IS_FPCLASS: {
-    // Turn LLVM IR's floating point classes to that in RISCV,
-    // which is simply rotating the 10-bit immediate right by two bits.
-    MachineOperand &ImmOp = MI.getOperand(2);
-    APInt ClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
-    ImmOp.setImm(ClassImm.rotr(2).getLimitedValue());
-    // Note that we do NOT want to notify Observer as it will
-    // send this instruction back to the legalizer chain and eventually
-    // falls into an infinite loop.
-    return true;
-  }
   }
 
   llvm_unreachable("expected switch to return");
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
index 98f748ed98481a8..38c47ef1ec59277 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
@@ -19,7 +19,7 @@ body:             |
     ; CHECK-NEXT: $x10 = COPY [[ANDI]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s64) = COPY $f10_d
-    %1:gprb(s64) = G_IS_FPCLASS %0(s64), 152
+    %1:gprb(s64) = G_IS_FPCLASS %0(s64), 608
     $x10 = COPY %1(s64)
     PseudoRET implicit $x10
 ...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir
index 96bf5270a91107a..7c4ef4828021881 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir
@@ -12,7 +12,7 @@ body:             |
     ; CHECK: liveins: $f10_d
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $f10_d
-    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:_(s64) = G_IS_FPCLASS [[COPY]](s64), 152
+    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:_(s64) = G_IS_FPCLASS [[COPY]](s64), 608
     ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s64)
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:_(s64) = COPY $f10_d

>From af4af5aba3b9ce7699ab11c45c95d5a55ab883dc Mon Sep 17 00:00:00 2001
From: Min-Yih Hsu <min.hsu at sifive.com>
Date: Mon, 13 Nov 2023 09:00:15 -0800
Subject: [PATCH 03/11] fixup! Move transformation of FPClass mask from
 legalizer to isel

---
 .../RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir   | 2 +-
 .../RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir   | 2 +-
 .../RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir        | 4 ++--
 .../RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir        | 4 ++--
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
index 9590b1afe1d32fe..1a57288a6b3038a 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
@@ -19,7 +19,7 @@ body:             |
     ; CHECK-NEXT: $x10 = COPY [[ANDI]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s32) = COPY $f10_f
-    %1:gprb(s32) = G_IS_FPCLASS %0(s32), 152
+    %1:gprb(s32) = G_IS_FPCLASS %0(s32), 608
     $x10 = COPY %1(s32)
     PseudoRET implicit $x10
 ...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir
index 3f8b77aa59264f0..c588d3cdfbb61a3 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir
@@ -12,7 +12,7 @@ body:             |
     ; CHECK: liveins: $f10_f
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $f10_f
-    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:_(s32) = G_IS_FPCLASS [[COPY]](s32), 152
+    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:_(s32) = G_IS_FPCLASS [[COPY]](s32), 608
     ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s32)
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:_(s32) = COPY $f10_f
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir
index 6c8241f14b73135..6804d75111340d2 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir
@@ -13,11 +13,11 @@ body:             |
     ; CHECK: liveins: $f10_f
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fprb(s32) = COPY $f10_f
-    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:gprb(s32) = G_IS_FPCLASS [[COPY]](s32), 152
+    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:gprb(s32) = G_IS_FPCLASS [[COPY]](s32), 608
     ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s32)
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:_(s32) = COPY $f10_f
-    %3:_(s32) = G_IS_FPCLASS %0(s32), 152
+    %3:_(s32) = G_IS_FPCLASS %0(s32), 608
     $x10 = COPY %3(s32)
     PseudoRET implicit $x10
 ...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir
index ad6fcd0dd379e38..708b1f12fe1f4bf 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir
@@ -13,11 +13,11 @@ body:             |
     ; CHECK: liveins: $f10_d
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fprb(s64) = COPY $f10_d
-    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:gprb(s64) = G_IS_FPCLASS [[COPY]](s64), 152
+    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:gprb(s64) = G_IS_FPCLASS [[COPY]](s64), 608
     ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s64)
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:_(s64) = COPY $f10_d
-    %3:_(s64) = G_IS_FPCLASS %0(s64), 152
+    %3:_(s64) = G_IS_FPCLASS %0(s64), 608
     $x10 = COPY %3(s64)
     PseudoRET implicit $x10
 ...

>From c7f5416ceda19688f84d2ad8c38b4ba8c72598b1 Mon Sep 17 00:00:00 2001
From: Min-Yih Hsu <min.hsu at sifive.com>
Date: Mon, 13 Nov 2023 10:34:32 -0800
Subject: [PATCH 04/11] Make sure the result only set/clear the LSB

---
 .../RISCV/GISel/RISCVInstructionSelector.cpp  | 33 +++++++++++++++----
 .../instruction-select/is-fpclass-rv32.mir    | 25 +++++++++++++-
 .../instruction-select/is-fpclass-rv64.mir    | 25 +++++++++++++-
 3 files changed, 75 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index ba1e458be94114a..96e6d2f56cb2f3c 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -1109,24 +1109,45 @@ bool RISCVInstructionSelector::selectIsFPClass(MachineInstr &MI,
   Register GISFPCLASS = MI.getOperand(0).getReg();
   Register Src = MI.getOperand(1).getReg();
   const MachineOperand &ImmOp = MI.getOperand(2);
+  const unsigned XLen = STI.getXLen();
   unsigned NewOpc = MRI.getType(Src).getSizeInBits() == 32 ? RISCV::FCLASS_S
                                                            : RISCV::FCLASS_D;
 
   // Turn LLVM IR's floating point classes to that in RISCV,
   // by simply rotating the 10-bit immediate right by two bits.
   APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
-  APInt FClassMask = GFpClassImm.rotr(2);
+  APInt FClassMask = GFpClassImm.rotr(2).zext(XLen);
 
   Register FClassResult = MRI.createVirtualRegister(&RISCV::GPRRegClass);
   // Insert FCLASS_S/D.
   auto FClass = MIB.buildInstr(NewOpc, {FClassResult}, {Src});
   if (!FClass.constrainAllUses(TII, TRI, RBI))
     return false;
-  // Insert AND to check Src aginst the mask.
-  auto And = MIB.buildInstr(RISCV::ANDI, {GISFPCLASS}, {FClassResult})
-                 .addImm(FClassMask.getLimitedValue());
-  if (!And.constrainAllUses(TII, TRI, RBI))
-    return false;
+
+  // If there is only a single bit set in the mask, lower to SLLI + SRLI.
+  if (FClassMask.popcount() == 1) {
+    Register SLResult = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+    auto SLLI = MIB.buildInstr(RISCV::SLLI, {SLResult}, {FClassResult})
+                    .addImm(FClassMask.countl_zero());
+    if (!SLLI.constrainAllUses(TII, TRI, RBI))
+      return false;
+    auto SRLI =
+        MIB.buildInstr(RISCV::SRLI, {GISFPCLASS}, {SLResult}).addImm(XLen - 1);
+    if (!SRLI.constrainAllUses(TII, TRI, RBI))
+      return false;
+  } else {
+    // Otherwise, lower to AND + SNEZ.
+    Register AndResult = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+    auto And = MIB.buildInstr(RISCV::ANDI, {AndResult}, {FClassResult})
+                   .addImm(FClassMask.getLimitedValue());
+    if (!And.constrainAllUses(TII, TRI, RBI))
+      return false;
+
+    Register Zero = RISCV::X0;
+    auto SNEZ = MIB.buildInstr(RISCV::SLTU, {GISFPCLASS}, {Zero, AndResult});
+    if (!SNEZ.constrainAllUses(TII, TRI, RBI))
+      return false;
+  }
 
   MI.eraseFromParent();
   return true;
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
index 1a57288a6b3038a..c379c5ab950f580 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
@@ -16,10 +16,33 @@ body:             |
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr32 = COPY $f10_f
     ; CHECK-NEXT: [[FCLASS_S:%[0-9]+]]:gpr = FCLASS_S [[COPY]]
     ; CHECK-NEXT: [[ANDI:%[0-9]+]]:gpr = ANDI [[FCLASS_S]], 152
-    ; CHECK-NEXT: $x10 = COPY [[ANDI]]
+    ; CHECK-NEXT: [[SLTU:%[0-9]+]]:gpr = SLTU $x0, [[ANDI]]
+    ; CHECK-NEXT: $x10 = COPY [[SLTU]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s32) = COPY $f10_f
     %1:gprb(s32) = G_IS_FPCLASS %0(s32), 608
     $x10 = COPY %1(s32)
     PseudoRET implicit $x10
 ...
+---
+name:            is_fpclass_f32_onehot
+legalized:       true
+regBankSelected: true
+body:             |
+  bb.0:
+    liveins: $f10_f
+
+    ; CHECK-LABEL: name: is_fpclass_f32_onehot
+    ; CHECK: liveins: $f10_f
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr32 = COPY $f10_f
+    ; CHECK-NEXT: [[FCLASS_S:%[0-9]+]]:gpr = FCLASS_S [[COPY]]
+    ; CHECK-NEXT: [[SLLI:%[0-9]+]]:gpr = SLLI [[FCLASS_S]], 23
+    ; CHECK-NEXT: [[SRLI:%[0-9]+]]:gpr = SRLI [[SLLI]], 31
+    ; CHECK-NEXT: $x10 = COPY [[SRLI]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:fprb(s32) = COPY $f10_f
+    %1:gprb(s32) = G_IS_FPCLASS %0(s32), 1
+    $x10 = COPY %1(s32)
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
index 38c47ef1ec59277..ed4390dbbd83f41 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
@@ -16,10 +16,33 @@ body:             |
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
     ; CHECK-NEXT: [[FCLASS_D:%[0-9]+]]:gpr = FCLASS_D [[COPY]]
     ; CHECK-NEXT: [[ANDI:%[0-9]+]]:gpr = ANDI [[FCLASS_D]], 152
-    ; CHECK-NEXT: $x10 = COPY [[ANDI]]
+    ; CHECK-NEXT: [[SLTU:%[0-9]+]]:gpr = SLTU $x0, [[ANDI]]
+    ; CHECK-NEXT: $x10 = COPY [[SLTU]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s64) = COPY $f10_d
     %1:gprb(s64) = G_IS_FPCLASS %0(s64), 608
     $x10 = COPY %1(s64)
     PseudoRET implicit $x10
 ...
+---
+name:            is_fpclass_f64_onehot
+legalized:       true
+regBankSelected: true
+body:             |
+  bb.0:
+    liveins: $f10_d
+
+    ; CHECK-LABEL: name: is_fpclass_f64_onehot
+    ; CHECK: liveins: $f10_d
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
+    ; CHECK-NEXT: [[FCLASS_D:%[0-9]+]]:gpr = FCLASS_D [[COPY]]
+    ; CHECK-NEXT: [[SLLI:%[0-9]+]]:gpr = SLLI [[FCLASS_D]], 55
+    ; CHECK-NEXT: [[SRLI:%[0-9]+]]:gpr = SRLI [[SLLI]], 63
+    ; CHECK-NEXT: $x10 = COPY [[SRLI]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:fprb(s64) = COPY $f10_d
+    %1:gprb(s64) = G_IS_FPCLASS %0(s64), 1
+    $x10 = COPY %1(s64)
+    PseudoRET implicit $x10
+...

>From a5edd34f8641291d03716967ef05f6d5253127a8 Mon Sep 17 00:00:00 2001
From: Min-Yih Hsu <min.hsu at sifive.com>
Date: Mon, 13 Nov 2023 12:15:07 -0800
Subject: [PATCH 05/11] Address review comments

And add another special case where FCLASS mask is one.
---
 .../RISCV/GISel/RISCVInstructionSelector.cpp  | 29 +++++++++++--------
 .../instruction-select/is-fpclass-rv32.mir    | 20 +++++++++++++
 .../instruction-select/is-fpclass-rv64.mir    | 20 +++++++++++++
 3 files changed, 57 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 96e6d2f56cb2f3c..026d4cddfaa3748 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -1113,7 +1113,7 @@ bool RISCVInstructionSelector::selectIsFPClass(MachineInstr &MI,
   unsigned NewOpc = MRI.getType(Src).getSizeInBits() == 32 ? RISCV::FCLASS_S
                                                            : RISCV::FCLASS_D;
 
-  // Turn LLVM IR's floating point classes to that in RISCV,
+  // Turn LLVM IR's floating point classes to that in RISC-V,
   // by simply rotating the 10-bit immediate right by two bits.
   APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
   APInt FClassMask = GFpClassImm.rotr(2).zext(XLen);
@@ -1124,27 +1124,32 @@ bool RISCVInstructionSelector::selectIsFPClass(MachineInstr &MI,
   if (!FClass.constrainAllUses(TII, TRI, RBI))
     return false;
 
-  // If there is only a single bit set in the mask, lower to SLLI + SRLI.
-  if (FClassMask.popcount() == 1) {
-    Register SLResult = MRI.createVirtualRegister(&RISCV::GPRRegClass);
-    auto SLLI = MIB.buildInstr(RISCV::SLLI, {SLResult}, {FClassResult})
-                    .addImm(FClassMask.countl_zero());
+  if (FClassMask == 1) {
+    // We don't need to generate additional instructions if Mask is 1, as the
+    // `ANDI rs, 1` that follows will suffice.
+    MRI.replaceRegWith(GISFPCLASS, FClassResult);
+  } else if (FClassMask.popcount() == 1) {
+    // If there is only a single bit set in the mask, lower to SLLI + SRLI.
+    auto SLLI =
+        MIB.buildInstr(RISCV::SLLI, {&RISCV::GPRRegClass}, {FClassResult})
+            .addImm(FClassMask.countl_zero());
     if (!SLLI.constrainAllUses(TII, TRI, RBI))
       return false;
-    auto SRLI =
-        MIB.buildInstr(RISCV::SRLI, {GISFPCLASS}, {SLResult}).addImm(XLen - 1);
+    auto SRLI = MIB.buildInstr(RISCV::SRLI, {GISFPCLASS}, {SLLI.getReg(0)})
+                    .addImm(XLen - 1);
     if (!SRLI.constrainAllUses(TII, TRI, RBI))
       return false;
   } else {
     // Otherwise, lower to AND + SNEZ.
-    Register AndResult = MRI.createVirtualRegister(&RISCV::GPRRegClass);
-    auto And = MIB.buildInstr(RISCV::ANDI, {AndResult}, {FClassResult})
-                   .addImm(FClassMask.getLimitedValue());
+    auto And =
+        MIB.buildInstr(RISCV::ANDI, {&RISCV::GPRRegClass}, {FClassResult})
+            .addImm(FClassMask.getLimitedValue());
     if (!And.constrainAllUses(TII, TRI, RBI))
       return false;
 
     Register Zero = RISCV::X0;
-    auto SNEZ = MIB.buildInstr(RISCV::SLTU, {GISFPCLASS}, {Zero, AndResult});
+    auto SNEZ =
+        MIB.buildInstr(RISCV::SLTU, {GISFPCLASS}, {Zero, And.getReg(0)});
     if (!SNEZ.constrainAllUses(TII, TRI, RBI))
       return false;
   }
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
index c379c5ab950f580..fafc24c1ad4c019 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
@@ -46,3 +46,23 @@ body:             |
     $x10 = COPY %1(s32)
     PseudoRET implicit $x10
 ...
+---
+name:            is_fpclass_f32_one
+legalized:       true
+regBankSelected: true
+body:             |
+  bb.0:
+    liveins: $f10_f
+
+    ; CHECK-LABEL: name: is_fpclass_f32_one
+    ; CHECK: liveins: $f10_f
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr32 = COPY $f10_f
+    ; CHECK-NEXT: [[FCLASS_S:%[0-9]+]]:gpr = FCLASS_S [[COPY]]
+    ; CHECK-NEXT: $x10 = COPY [[FCLASS_S]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:fprb(s32) = COPY $f10_f
+    %1:gprb(s32) = G_IS_FPCLASS %0(s32), 4
+    $x10 = COPY %1(s32)
+    PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
index ed4390dbbd83f41..b7bd7151d96711b 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
@@ -46,3 +46,23 @@ body:             |
     $x10 = COPY %1(s64)
     PseudoRET implicit $x10
 ...
+---
+name:            is_fpclass_f64_one
+legalized:       true
+regBankSelected: true
+body:             |
+  bb.0:
+    liveins: $f10_d
+
+    ; CHECK-LABEL: name: is_fpclass_f64_one
+    ; CHECK: liveins: $f10_d
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
+    ; CHECK-NEXT: [[FCLASS_D:%[0-9]+]]:gpr = FCLASS_D [[COPY]]
+    ; CHECK-NEXT: $x10 = COPY [[FCLASS_D]]
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:fprb(s64) = COPY $f10_d
+    %1:gprb(s64) = G_IS_FPCLASS %0(s64), 4
+    $x10 = COPY %1(s64)
+    PseudoRET implicit $x10
+...

>From 9fb37712b73b7b5a4e8c19feae5cc0bf185ff6b6 Mon Sep 17 00:00:00 2001
From: Min-Yih Hsu <min.hsu at sifive.com>
Date: Mon, 13 Nov 2023 18:59:11 -0800
Subject: [PATCH 06/11] fixup! Address review comments

---
 .../Target/RISCV/GISel/RISCVInstructionSelector.cpp  | 12 ++++++++----
 .../instruction-select/is-fpclass-rv32.mir           |  3 ++-
 .../instruction-select/is-fpclass-rv64.mir           |  3 ++-
 3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 026d4cddfaa3748..85b303249262104 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -1125,9 +1125,13 @@ bool RISCVInstructionSelector::selectIsFPClass(MachineInstr &MI,
     return false;
 
   if (FClassMask == 1) {
-    // We don't need to generate additional instructions if Mask is 1, as the
-    // `ANDI rs, 1` that follows will suffice.
-    MRI.replaceRegWith(GISFPCLASS, FClassResult);
+    // If Mask is 1, we don't need to generate additional instructions
+    // other than `ANDI rs, 1`, which will likely be folded into an identical
+    // one commonly generated for G_IS_FPCLASS's users.
+    auto And =
+        MIB.buildInstr(RISCV::ANDI, {GISFPCLASS}, {FClassResult}).addImm(1U);
+    if (!And.constrainAllUses(TII, TRI, RBI))
+      return false;
   } else if (FClassMask.popcount() == 1) {
     // If there is only a single bit set in the mask, lower to SLLI + SRLI.
     auto SLLI =
@@ -1140,7 +1144,7 @@ bool RISCVInstructionSelector::selectIsFPClass(MachineInstr &MI,
     if (!SRLI.constrainAllUses(TII, TRI, RBI))
       return false;
   } else {
-    // Otherwise, lower to AND + SNEZ.
+    // Otherwise, lower to ANDI + SNEZ.
     auto And =
         MIB.buildInstr(RISCV::ANDI, {&RISCV::GPRRegClass}, {FClassResult})
             .addImm(FClassMask.getLimitedValue());
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
index fafc24c1ad4c019..6c9ad537d971566 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
@@ -59,7 +59,8 @@ body:             |
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr32 = COPY $f10_f
     ; CHECK-NEXT: [[FCLASS_S:%[0-9]+]]:gpr = FCLASS_S [[COPY]]
-    ; CHECK-NEXT: $x10 = COPY [[FCLASS_S]]
+    ; CHECK-NEXT: [[ANDI:%[0-9]+]]:gpr = ANDI [[FCLASS_S]], 1
+    ; CHECK-NEXT: $x10 = COPY [[ANDI]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s32) = COPY $f10_f
     %1:gprb(s32) = G_IS_FPCLASS %0(s32), 4
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
index b7bd7151d96711b..6b63124cdbac26c 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
@@ -59,7 +59,8 @@ body:             |
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
     ; CHECK-NEXT: [[FCLASS_D:%[0-9]+]]:gpr = FCLASS_D [[COPY]]
-    ; CHECK-NEXT: $x10 = COPY [[FCLASS_D]]
+    ; CHECK-NEXT: [[ANDI:%[0-9]+]]:gpr = ANDI [[FCLASS_D]], 1
+    ; CHECK-NEXT: $x10 = COPY [[ANDI]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s64) = COPY $f10_d
     %1:gprb(s64) = G_IS_FPCLASS %0(s64), 4

>From a606d3fbaa7ef10d0f7aac7f5f64f46cd4b76391 Mon Sep 17 00:00:00 2001
From: Min Hsu <min.hsu at sifive.com>
Date: Wed, 22 Nov 2023 14:41:23 -0800
Subject: [PATCH 07/11] Create a generic instruction for G_IS_FPCLASS

Creating a generic instruction, RISCV::G_FCLASS, so that we can reuse
the SelectionDAG patterns during ISel.
---
 .../RISCV/GISel/RISCVInstructionSelector.cpp  | 65 +------------------
 .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 33 ++++++++--
 .../Target/RISCV/GISel/RISCVLegalizerInfo.h   |  4 ++
 .../RISCV/GISel/RISCVRegisterBankInfo.cpp     |  9 +--
 llvm/lib/Target/RISCV/RISCVInstrGISel.td      | 25 +++++++
 llvm/lib/Target/RISCV/RISCVInstrInfo.td       |  6 ++
 .../instruction-select/is-fpclass-rv32.mir    | 33 +++++++---
 .../instruction-select/is-fpclass-rv64.mir    | 33 +++++++---
 .../legalizer/legalize-is-fpclass-rv32.mir    |  8 ++-
 .../legalizer/legalize-is-fpclass-rv64.mir    |  8 ++-
 .../regbankselect/is-fpclass-rv32.mir         | 16 +++--
 .../regbankselect/is-fpclass-rv64.mir         | 16 +++--
 12 files changed, 148 insertions(+), 108 deletions(-)
 create mode 100644 llvm/lib/Target/RISCV/RISCVInstrGISel.td

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 85b303249262104..9a47e988067fcce 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -72,8 +72,6 @@ class RISCVInstructionSelector : public InstructionSelector {
                     MachineRegisterInfo &MRI) const;
   bool selectFPCompare(MachineInstr &MI, MachineIRBuilder &MIB,
                        MachineRegisterInfo &MRI) const;
-  bool selectIsFPClass(MachineInstr &MI, MachineIRBuilder &MIB,
-                       MachineRegisterInfo &MRI) const;
 
   ComplexRendererFns selectShiftMask(MachineOperand &Root) const;
   ComplexRendererFns selectAddrRegImm(MachineOperand &Root) const;
@@ -396,7 +394,7 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
   preISelLower(MI, MIB, MRI);
   const unsigned Opc = MI.getOpcode();
 
-  if (!isPreISelGenericOpcode(Opc) || Opc == TargetOpcode::G_PHI) {
+  if (!MI.isPreISelOpcode() || Opc == TargetOpcode::G_PHI) {
     if (Opc == TargetOpcode::PHI || Opc == TargetOpcode::G_PHI) {
       const Register DefReg = MI.getOperand(0).getReg();
       const LLT DefTy = MRI.getType(DefReg);
@@ -566,8 +564,6 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
     return selectSelect(MI, MIB, MRI);
   case TargetOpcode::G_FCMP:
     return selectFPCompare(MI, MIB, MRI);
-  case TargetOpcode::G_IS_FPCLASS:
-    return selectIsFPClass(MI, MIB, MRI);
   default:
     return false;
   }
@@ -1103,65 +1099,6 @@ bool RISCVInstructionSelector::selectFPCompare(MachineInstr &MI,
   return true;
 }
 
-bool RISCVInstructionSelector::selectIsFPClass(MachineInstr &MI,
-                                               MachineIRBuilder &MIB,
-                                               MachineRegisterInfo &MRI) const {
-  Register GISFPCLASS = MI.getOperand(0).getReg();
-  Register Src = MI.getOperand(1).getReg();
-  const MachineOperand &ImmOp = MI.getOperand(2);
-  const unsigned XLen = STI.getXLen();
-  unsigned NewOpc = MRI.getType(Src).getSizeInBits() == 32 ? RISCV::FCLASS_S
-                                                           : RISCV::FCLASS_D;
-
-  // Turn LLVM IR's floating point classes to that in RISC-V,
-  // by simply rotating the 10-bit immediate right by two bits.
-  APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
-  APInt FClassMask = GFpClassImm.rotr(2).zext(XLen);
-
-  Register FClassResult = MRI.createVirtualRegister(&RISCV::GPRRegClass);
-  // Insert FCLASS_S/D.
-  auto FClass = MIB.buildInstr(NewOpc, {FClassResult}, {Src});
-  if (!FClass.constrainAllUses(TII, TRI, RBI))
-    return false;
-
-  if (FClassMask == 1) {
-    // If Mask is 1, we don't need to generate additional instructions
-    // other than `ANDI rs, 1`, which will likely be folded into an identical
-    // one commonly generated for G_IS_FPCLASS's users.
-    auto And =
-        MIB.buildInstr(RISCV::ANDI, {GISFPCLASS}, {FClassResult}).addImm(1U);
-    if (!And.constrainAllUses(TII, TRI, RBI))
-      return false;
-  } else if (FClassMask.popcount() == 1) {
-    // If there is only a single bit set in the mask, lower to SLLI + SRLI.
-    auto SLLI =
-        MIB.buildInstr(RISCV::SLLI, {&RISCV::GPRRegClass}, {FClassResult})
-            .addImm(FClassMask.countl_zero());
-    if (!SLLI.constrainAllUses(TII, TRI, RBI))
-      return false;
-    auto SRLI = MIB.buildInstr(RISCV::SRLI, {GISFPCLASS}, {SLLI.getReg(0)})
-                    .addImm(XLen - 1);
-    if (!SRLI.constrainAllUses(TII, TRI, RBI))
-      return false;
-  } else {
-    // Otherwise, lower to ANDI + SNEZ.
-    auto And =
-        MIB.buildInstr(RISCV::ANDI, {&RISCV::GPRRegClass}, {FClassResult})
-            .addImm(FClassMask.getLimitedValue());
-    if (!And.constrainAllUses(TII, TRI, RBI))
-      return false;
-
-    Register Zero = RISCV::X0;
-    auto SNEZ =
-        MIB.buildInstr(RISCV::SLTU, {GISFPCLASS}, {Zero, And.getReg(0)});
-    if (!SNEZ.constrainAllUses(TII, TRI, RBI))
-      return false;
-  }
-
-  MI.eraseFromParent();
-  return true;
-}
-
 namespace llvm {
 InstructionSelector *
 createRISCVInstructionSelector(const RISCVTargetMachine &TM,
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 6b97f1c919e0637..e7dbb430f5b1497 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -34,9 +34,8 @@ static LegalityPredicate typeIsScalarFPArith(unsigned TypeIdx,
   };
 }
 
-RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) {
-  const unsigned XLen = ST.getXLen();
-  const LLT sXLen = LLT::scalar(XLen);
+RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
+    : STI(ST), XLen(STI.getXLen()), sXLen(LLT::scalar(XLen)) {
   const LLT sDoubleXLen = LLT::scalar(2 * XLen);
   const LLT p0 = LLT::pointer(0, XLen);
   const LLT s8 = LLT::scalar(8);
@@ -240,11 +239,14 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) {
                 typeIs(1, s32)(Query));
       });
 
-  // TODO: Support vector version of G_IS_FPCLASS.
-  getActionDefinitionsBuilder({G_FCMP, G_IS_FPCLASS})
+  getActionDefinitionsBuilder(G_FCMP)
       .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
       .clampScalar(0, sXLen, sXLen);
 
+  // TODO: Support vector version of G_IS_FPCLASS.
+  getActionDefinitionsBuilder(G_IS_FPCLASS)
+      .customIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)));
+
   getActionDefinitionsBuilder(G_FCONSTANT).legalIf(typeIsScalarFPArith(0, ST));
 
   getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
@@ -310,6 +312,27 @@ bool RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
     return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
            LegalizerHelper::Legalized;
   }
+  case TargetOpcode::G_IS_FPCLASS: {
+    Register GISFPCLASS = MI.getOperand(0).getReg();
+    Register Src = MI.getOperand(1).getReg();
+    const MachineOperand &ImmOp = MI.getOperand(2);
+    const unsigned XLen = STI.getXLen();
+    const LLT sXLen = LLT::scalar(XLen);
+    MachineIRBuilder MIB(MI);
+
+    // Turn LLVM IR's floating point classes to that in RISC-V,
+    // by simply rotating the 10-bit immediate right by two bits.
+    APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
+    auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen));
+    auto ConstZero = MIB.buildConstant(sXLen, 0);
+
+    auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src});
+    auto And = MIB.buildAnd(sXLen, GFClass, FClassMask);
+    MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero);
+
+    MI.eraseFromParent();
+    return true;
+  }
   }
 
   llvm_unreachable("expected switch to return");
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h
index f39d3a130d85063..6a5f49cd98d1842 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.h
@@ -23,6 +23,10 @@ class RISCVSubtarget;
 
 /// This class provides the information for the target register banks.
 class RISCVLegalizerInfo : public LegalizerInfo {
+  const RISCVSubtarget &STI;
+  const unsigned XLen;
+  const LLT sXLen;
+
 public:
   RISCVLegalizerInfo(const RISCVSubtarget &ST);
 
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
index 6afa73c956a4fe9..c2f07e1aa651fe9 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
@@ -330,7 +330,8 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
     OpdsMapping[3] = GPRValueMapping;
     break;
   case TargetOpcode::G_FPTOSI:
-  case TargetOpcode::G_FPTOUI: {
+  case TargetOpcode::G_FPTOUI:
+  case RISCV::G_FCLASS: {
     LLT Ty = MRI.getType(MI.getOperand(1).getReg());
     OpdsMapping[0] = GPRValueMapping;
     OpdsMapping[1] = getFPValueMapping(Ty.getSizeInBits());
@@ -353,12 +354,6 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
     OpdsMapping[2] = OpdsMapping[3] = getFPValueMapping(Size);
     break;
   }
-  case TargetOpcode::G_IS_FPCLASS: {
-    LLT FPTy = MRI.getType(MI.getOperand(1).getReg());
-    OperandsMapping = getOperandsMapping(
-        {GPRValueMapping, getFPValueMapping(FPTy.getSizeInBits()), nullptr});
-    break;
-  }
   default:
     // By default map all scalars to GPR.
     for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
diff --git a/llvm/lib/Target/RISCV/RISCVInstrGISel.td b/llvm/lib/Target/RISCV/RISCVInstrGISel.td
new file mode 100644
index 000000000000000..f7958705a5965b8
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVInstrGISel.td
@@ -0,0 +1,25 @@
+//===-- RISCVGIsel.td - RISC-V GlobalISel Patterns ---------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// This file contains patterns that are relevant to GlobalISel, including
+/// GIComplexOperandMatcher definitions for equivalent SelectionDAG
+/// ComplexPatterns.
+//
+//===----------------------------------------------------------------------===//
+
+class RISCVGenericInstruction : GenericInstruction {
+  let Namespace = "RISCV";
+}
+
+def G_FCLASS : RISCVGenericInstruction {
+  let OutOperandList = (outs type0:$dst);
+  let InOperandList = (ins type1:$src);
+  let hasSideEffects = false;
+}
+def : GINodeEquiv<G_FCLASS, riscv_fpclass>;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 7e54c83ce4e2a8e..edc08187d8f775a 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -2127,3 +2127,9 @@ include "RISCVInstrInfoXVentana.td"
 include "RISCVInstrInfoXTHead.td"
 include "RISCVInstrInfoXSf.td"
 include "RISCVInstrInfoXCV.td"
+
+//===----------------------------------------------------------------------===//
+// Global ISel
+//===----------------------------------------------------------------------===//
+
+include "RISCVInstrGISel.td"
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
index 6c9ad537d971566..705c70757e80b6e 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv32.mir
@@ -20,8 +20,12 @@ body:             |
     ; CHECK-NEXT: $x10 = COPY [[SLTU]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s32) = COPY $f10_f
-    %1:gprb(s32) = G_IS_FPCLASS %0(s32), 608
-    $x10 = COPY %1(s32)
+    %3:gprb(s32) = G_CONSTANT i32 152
+    %4:gprb(s32) = G_CONSTANT i32 0
+    %5:gprb(s32) = G_FCLASS %0(s32)
+    %6:gprb(s32) = G_AND %5, %3
+    %7:gprb(s32) = G_ICMP intpred(ne), %6(s32), %4
+    $x10 = COPY %7(s32)
     PseudoRET implicit $x10
 ...
 ---
@@ -37,13 +41,17 @@ body:             |
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr32 = COPY $f10_f
     ; CHECK-NEXT: [[FCLASS_S:%[0-9]+]]:gpr = FCLASS_S [[COPY]]
-    ; CHECK-NEXT: [[SLLI:%[0-9]+]]:gpr = SLLI [[FCLASS_S]], 23
-    ; CHECK-NEXT: [[SRLI:%[0-9]+]]:gpr = SRLI [[SLLI]], 31
-    ; CHECK-NEXT: $x10 = COPY [[SRLI]]
+    ; CHECK-NEXT: [[ANDI:%[0-9]+]]:gpr = ANDI [[FCLASS_S]], 256
+    ; CHECK-NEXT: [[SLTU:%[0-9]+]]:gpr = SLTU $x0, [[ANDI]]
+    ; CHECK-NEXT: $x10 = COPY [[SLTU]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s32) = COPY $f10_f
-    %1:gprb(s32) = G_IS_FPCLASS %0(s32), 1
-    $x10 = COPY %1(s32)
+    %3:gprb(s32) = G_CONSTANT i32 256
+    %4:gprb(s32) = G_CONSTANT i32 0
+    %5:gprb(s32) = G_FCLASS %0(s32)
+    %6:gprb(s32) = G_AND %5, %3
+    %7:gprb(s32) = G_ICMP intpred(ne), %6(s32), %4
+    $x10 = COPY %7(s32)
     PseudoRET implicit $x10
 ...
 ---
@@ -60,10 +68,15 @@ body:             |
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr32 = COPY $f10_f
     ; CHECK-NEXT: [[FCLASS_S:%[0-9]+]]:gpr = FCLASS_S [[COPY]]
     ; CHECK-NEXT: [[ANDI:%[0-9]+]]:gpr = ANDI [[FCLASS_S]], 1
-    ; CHECK-NEXT: $x10 = COPY [[ANDI]]
+    ; CHECK-NEXT: [[SLTU:%[0-9]+]]:gpr = SLTU $x0, [[ANDI]]
+    ; CHECK-NEXT: $x10 = COPY [[SLTU]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s32) = COPY $f10_f
-    %1:gprb(s32) = G_IS_FPCLASS %0(s32), 4
-    $x10 = COPY %1(s32)
+    %3:gprb(s32) = G_CONSTANT i32 1
+    %4:gprb(s32) = G_CONSTANT i32 0
+    %5:gprb(s32) = G_FCLASS %0(s32)
+    %6:gprb(s32) = G_AND %5, %3
+    %7:gprb(s32) = G_ICMP intpred(ne), %6(s32), %4
+    $x10 = COPY %7(s32)
     PseudoRET implicit $x10
 ...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
index 6b63124cdbac26c..e970bc23a8c1a27 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/is-fpclass-rv64.mir
@@ -20,8 +20,12 @@ body:             |
     ; CHECK-NEXT: $x10 = COPY [[SLTU]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s64) = COPY $f10_d
-    %1:gprb(s64) = G_IS_FPCLASS %0(s64), 608
-    $x10 = COPY %1(s64)
+    %3:gprb(s64) = G_CONSTANT i64 152
+    %4:gprb(s64) = G_CONSTANT i64 0
+    %5:gprb(s64) = G_FCLASS %0(s64)
+    %6:gprb(s64) = G_AND %5, %3
+    %7:gprb(s64) = G_ICMP intpred(ne), %6(s64), %4
+    $x10 = COPY %7(s64)
     PseudoRET implicit $x10
 ...
 ---
@@ -37,13 +41,17 @@ body:             |
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
     ; CHECK-NEXT: [[FCLASS_D:%[0-9]+]]:gpr = FCLASS_D [[COPY]]
-    ; CHECK-NEXT: [[SLLI:%[0-9]+]]:gpr = SLLI [[FCLASS_D]], 55
-    ; CHECK-NEXT: [[SRLI:%[0-9]+]]:gpr = SRLI [[SLLI]], 63
-    ; CHECK-NEXT: $x10 = COPY [[SRLI]]
+    ; CHECK-NEXT: [[ANDI:%[0-9]+]]:gpr = ANDI [[FCLASS_D]], 256
+    ; CHECK-NEXT: [[SLTU:%[0-9]+]]:gpr = SLTU $x0, [[ANDI]]
+    ; CHECK-NEXT: $x10 = COPY [[SLTU]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s64) = COPY $f10_d
-    %1:gprb(s64) = G_IS_FPCLASS %0(s64), 1
-    $x10 = COPY %1(s64)
+    %3:gprb(s64) = G_CONSTANT i64 256
+    %4:gprb(s64) = G_CONSTANT i64 0
+    %5:gprb(s64) = G_FCLASS %0(s64)
+    %6:gprb(s64) = G_AND %5, %3
+    %7:gprb(s64) = G_ICMP intpred(ne), %6(s64), %4
+    $x10 = COPY %7(s64)
     PseudoRET implicit $x10
 ...
 ---
@@ -60,10 +68,15 @@ body:             |
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
     ; CHECK-NEXT: [[FCLASS_D:%[0-9]+]]:gpr = FCLASS_D [[COPY]]
     ; CHECK-NEXT: [[ANDI:%[0-9]+]]:gpr = ANDI [[FCLASS_D]], 1
-    ; CHECK-NEXT: $x10 = COPY [[ANDI]]
+    ; CHECK-NEXT: [[SLTU:%[0-9]+]]:gpr = SLTU $x0, [[ANDI]]
+    ; CHECK-NEXT: $x10 = COPY [[SLTU]]
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:fprb(s64) = COPY $f10_d
-    %1:gprb(s64) = G_IS_FPCLASS %0(s64), 4
-    $x10 = COPY %1(s64)
+    %3:gprb(s64) = G_CONSTANT i64 1
+    %4:gprb(s64) = G_CONSTANT i64 0
+    %5:gprb(s64) = G_FCLASS %0(s64)
+    %6:gprb(s64) = G_AND %5, %3
+    %7:gprb(s64) = G_ICMP intpred(ne), %6(s64), %4
+    $x10 = COPY %7(s64)
     PseudoRET implicit $x10
 ...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir
index c588d3cdfbb61a3..b35a68b20ad151e 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv32.mir
@@ -12,8 +12,12 @@ body:             |
     ; CHECK: liveins: $f10_f
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $f10_f
-    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:_(s32) = G_IS_FPCLASS [[COPY]](s32), 608
-    ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s32)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 152
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[FCLASS:%[0-9]+]]:_(s32) = G_FCLASS [[COPY]](s32)
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s32) = G_AND [[FCLASS]], [[C]]
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(ne), [[AND]](s32), [[C1]]
+    ; CHECK-NEXT: $x10 = COPY [[ICMP]](s32)
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:_(s32) = COPY $f10_f
     %1:_(s1) = G_IS_FPCLASS %0(s32), 608
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir
index 7c4ef4828021881..8b27e2875c537ac 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/legalize-is-fpclass-rv64.mir
@@ -12,8 +12,12 @@ body:             |
     ; CHECK: liveins: $f10_d
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $f10_d
-    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:_(s64) = G_IS_FPCLASS [[COPY]](s64), 608
-    ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s64)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 152
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+    ; CHECK-NEXT: [[FCLASS:%[0-9]+]]:_(s64) = G_FCLASS [[COPY]](s64)
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s64) = G_AND [[FCLASS]], [[C]]
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s64) = G_ICMP intpred(ne), [[AND]](s64), [[C1]]
+    ; CHECK-NEXT: $x10 = COPY [[ICMP]](s64)
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:_(s64) = COPY $f10_d
     %1:_(s1) = G_IS_FPCLASS %0(s64), 608
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir
index 6804d75111340d2..e48c1cbaba303f2 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv32.mir
@@ -13,11 +13,19 @@ body:             |
     ; CHECK: liveins: $f10_f
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fprb(s32) = COPY $f10_f
-    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:gprb(s32) = G_IS_FPCLASS [[COPY]](s32), 608
-    ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s32)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s32) = G_CONSTANT i32 152
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:gprb(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[FCLASS:%[0-9]+]]:gprb(s32) = G_FCLASS [[COPY]](s32)
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:gprb(s32) = G_AND [[FCLASS]], [[C]]
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:gprb(s32) = G_ICMP intpred(ne), [[AND]](s32), [[C1]]
+    ; CHECK-NEXT: $x10 = COPY [[ICMP]](s32)
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:_(s32) = COPY $f10_f
-    %3:_(s32) = G_IS_FPCLASS %0(s32), 608
-    $x10 = COPY %3(s32)
+    %3:_(s32) = G_CONSTANT i32 152
+    %4:_(s32) = G_CONSTANT i32 0
+    %5:_(s32) = G_FCLASS %0(s32)
+    %6:_(s32) = G_AND %5, %3
+    %7:_(s32) = G_ICMP intpred(ne), %6(s32), %4
+    $x10 = COPY %7(s32)
     PseudoRET implicit $x10
 ...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir
index 708b1f12fe1f4bf..afe999ea42be43d 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/is-fpclass-rv64.mir
@@ -13,11 +13,19 @@ body:             |
     ; CHECK: liveins: $f10_d
     ; CHECK-NEXT: {{  $}}
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:fprb(s64) = COPY $f10_d
-    ; CHECK-NEXT: [[IS_FPCLASS:%[0-9]+]]:gprb(s64) = G_IS_FPCLASS [[COPY]](s64), 608
-    ; CHECK-NEXT: $x10 = COPY [[IS_FPCLASS]](s64)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:gprb(s64) = G_CONSTANT i64 152
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:gprb(s64) = G_CONSTANT i64 0
+    ; CHECK-NEXT: [[FCLASS:%[0-9]+]]:gprb(s64) = G_FCLASS [[COPY]](s64)
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:gprb(s64) = G_AND [[FCLASS]], [[C]]
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:gprb(s64) = G_ICMP intpred(ne), [[AND]](s64), [[C1]]
+    ; CHECK-NEXT: $x10 = COPY [[ICMP]](s64)
     ; CHECK-NEXT: PseudoRET implicit $x10
     %0:_(s64) = COPY $f10_d
-    %3:_(s64) = G_IS_FPCLASS %0(s64), 608
-    $x10 = COPY %3(s64)
+    %3:_(s64) = G_CONSTANT i64 152
+    %4:_(s64) = G_CONSTANT i64 0
+    %5:_(s64) = G_FCLASS %0(s64)
+    %6:_(s64) = G_AND %5, %3
+    %7:_(s64) = G_ICMP intpred(ne), %6(s64), %4
+    $x10 = COPY %7(s64)
     PseudoRET implicit $x10
 ...

>From 5c7a0bb798a41346f025339c0afefb7b11986d00 Mon Sep 17 00:00:00 2001
From: Min Hsu <min.hsu at sifive.com>
Date: Wed, 22 Nov 2023 14:50:21 -0800
Subject: [PATCH 08/11] fixup! Create a generic instruction for G_IS_FPCLASS

---
 llvm/lib/Target/RISCV/RISCVInstrGISel.td | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrGISel.td b/llvm/lib/Target/RISCV/RISCVInstrGISel.td
index f7958705a5965b8..588297ecb928c0d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrGISel.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrGISel.td
@@ -1,4 +1,4 @@
-//===-- RISCVGIsel.td - RISC-V GlobalISel Patterns ---------*- tablegen -*-===//
+//===-- RISCVInstrGISel.td - RISC-V GISel target pseudos ----*- tablegen -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -7,9 +7,9 @@
 //===----------------------------------------------------------------------===//
 //
 /// \file
-/// This file contains patterns that are relevant to GlobalISel, including
-/// GIComplexOperandMatcher definitions for equivalent SelectionDAG
-/// ComplexPatterns.
+// RISC-V GlobalISel target pseudo instruction definitions. This is kept
+// separately from the other tablegen files for organizational purposes, but
+// share the same infrastructure.
 //
 //===----------------------------------------------------------------------===//
 
@@ -17,6 +17,7 @@ class RISCVGenericInstruction : GenericInstruction {
   let Namespace = "RISCV";
 }
 
+// Pseudo equivalent to a RISCVISD::FPCLASS.
 def G_FCLASS : RISCVGenericInstruction {
   let OutOperandList = (outs type0:$dst);
   let InOperandList = (ins type1:$src);

>From 378efa232c45ddae7fab5df034913b77ea867dc8 Mon Sep 17 00:00:00 2001
From: Min Hsu <min.hsu at sifive.com>
Date: Wed, 22 Nov 2023 15:04:14 -0800
Subject: [PATCH 09/11] fixup! Create a generic instruction for G_IS_FPCLASS

---
 llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index e7dbb430f5b1497..3bea7096b8c2584 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -316,8 +316,6 @@ bool RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
     Register GISFPCLASS = MI.getOperand(0).getReg();
     Register Src = MI.getOperand(1).getReg();
     const MachineOperand &ImmOp = MI.getOperand(2);
-    const unsigned XLen = STI.getXLen();
-    const LLT sXLen = LLT::scalar(XLen);
     MachineIRBuilder MIB(MI);
 
     // Turn LLVM IR's floating point classes to that in RISC-V,

>From 8b570e3e8f7f77a27d66f4d1f96a57631e5ab62a Mon Sep 17 00:00:00 2001
From: Min Hsu <min.hsu at sifive.com>
Date: Wed, 22 Nov 2023 15:30:35 -0800
Subject: [PATCH 10/11] Rebase and address comments in the legalizer

---
 llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 3bea7096b8c2584..4c05643dbee442b 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -38,6 +38,7 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
     : STI(ST), XLen(STI.getXLen()), sXLen(LLT::scalar(XLen)) {
   const LLT sDoubleXLen = LLT::scalar(2 * XLen);
   const LLT p0 = LLT::pointer(0, XLen);
+  const LLT s1 = LLT::scalar(1);
   const LLT s8 = LLT::scalar(8);
   const LLT s16 = LLT::scalar(16);
   const LLT s32 = LLT::scalar(32);
@@ -245,7 +246,7 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
 
   // TODO: Support vector version of G_IS_FPCLASS.
   getActionDefinitionsBuilder(G_IS_FPCLASS)
-      .customIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)));
+      .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST)));
 
   getActionDefinitionsBuilder(G_FCONSTANT).legalIf(typeIsScalarFPArith(0, ST));
 

>From f78fd86b86c43a1a076164a66c0fefe80d8c7e03 Mon Sep 17 00:00:00 2001
From: Min Hsu <min.hsu at sifive.com>
Date: Wed, 22 Nov 2023 16:36:58 -0800
Subject: [PATCH 11/11] Rename RISCVISD::FPCLASS

---
 llvm/lib/Target/RISCV/RISCVInstrGISel.td | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrGISel.td b/llvm/lib/Target/RISCV/RISCVInstrGISel.td
index 588297ecb928c0d..ede8c9809833ccc 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrGISel.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrGISel.td
@@ -17,10 +17,10 @@ class RISCVGenericInstruction : GenericInstruction {
   let Namespace = "RISCV";
 }
 
-// Pseudo equivalent to a RISCVISD::FPCLASS.
+// Pseudo equivalent to a RISCVISD::FCLASS.
 def G_FCLASS : RISCVGenericInstruction {
   let OutOperandList = (outs type0:$dst);
   let InOperandList = (ins type1:$src);
   let hasSideEffects = false;
 }
-def : GINodeEquiv<G_FCLASS, riscv_fpclass>;
+def : GINodeEquiv<G_FCLASS, riscv_fclass>;



More information about the llvm-commits mailing list