[llvm] [RISCG][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
Fri Nov 10 15:50:04 PST 2023


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

Add legalizer, regbankselect, and isel supports for floating point version of G_IS_FPCLASS.

>From 51c9a13c4909cd04bc475f50c3de96f556ff267f 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] [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 | 30 +++++++++++++++----
 .../RISCV/GISel/RISCVRegisterBankInfo.cpp     |  6 ++++
 .../instruction-select/is-fpclass-rv32.mir    | 25 ++++++++++++++++
 .../instruction-select/is-fpclass-rv64.mir    | 25 ++++++++++++++++
 .../legalizer/rv32/legalize-is-fpclass.mir    | 24 +++++++++++++++
 .../legalizer/rv64/legalize-is-fpclass.mir    | 24 +++++++++++++++
 .../regbankselect/is-fpclass-rv32.mir         | 23 ++++++++++++++
 .../regbankselect/is-fpclass-rv64.mir         | 23 ++++++++++++++
 10 files changed, 204 insertions(+), 5 deletions(-)
 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/rv32/legalize-is-fpclass.mir
 create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv64/legalize-is-fpclass.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 cde5bc7d9a981f1..f0f34a62b431a0c 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 b8acd98939b9fc7..9f2d10bca23f025 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -69,6 +69,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;
@@ -419,6 +421,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;
   }
@@ -948,6 +952,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 1aba6b78d8a9d9b..44f469a5aea138c 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -215,12 +215,21 @@ 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([=, &ST](const LegalityQuery &Query) -> bool {
-        return typeIs(0, sXLen)(Query) &&
-               ((ST.hasStdExtF() && typeIs(1, s32)(Query)) ||
-                (ST.hasStdExtD() && typeIs(1, s64)(Query)));
-      })
+      .legalIf(isScalarAndFP)
+      .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(isScalarAndFP)
       .clampScalar(0, sXLen, sXLen);
 
   getActionDefinitionsBuilder(G_FCONSTANT)
@@ -270,6 +279,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 60b6de0a760dcbb..af3529e170d6a21 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
@@ -246,6 +246,12 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
         {GPRValueMapping, nullptr, FPRValueMapping, FPRValueMapping});
     break;
   }
+  case TargetOpcode::G_IS_FPCLASS: {
+    LLT FPTy = MRI.getType(MI.getOperand(1).getReg());
+    OperandsMapping = getOperandsMapping(
+        {GPRValueMapping, getFPValueMapping(FPTy.getSizeInBits()), nullptr});
+    break;
+  }
   default:
     return getInvalidInstructionMapping();
   }
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/rv32/legalize-is-fpclass.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv32/legalize-is-fpclass.mir
new file mode 100644
index 000000000000000..3f8b77aa59264f0
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv32/legalize-is-fpclass.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/rv64/legalize-is-fpclass.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv64/legalize-is-fpclass.mir
new file mode 100644
index 000000000000000..96bf5270a91107a
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv64/legalize-is-fpclass.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
+...



More information about the llvm-commits mailing list