[llvm] [RISCV][GISel] Legalize G_IS_FPCLASS for fp128 (PR #195738)

Gábor Spaits via llvm-commits llvm-commits at lists.llvm.org
Wed May 6 00:53:19 PDT 2026


https://github.com/spaits updated https://github.com/llvm/llvm-project/pull/195738

>From fd5ce99a441f974411421c8b5bdf1137c422a674 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Mon, 4 May 2026 22:31:28 +0200
Subject: [PATCH 1/5] [RISCV][GISel] Legalize G_IS_FPCLASS for fp128

When compiling `libc/src/stdlib/strtold.cpp` with GlobalISel there is a failure. Calls to `@llvm.is.fpclass.f128` are translated to G_IS_FPCLASS, which couldn't be laglized.

This PR tries to address that.
---
 .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp |  2 +-
 .../legalizer/legalize-is-fpclass-rv32.mir    | 42 +++++++++++++++++++
 .../legalizer/legalize-is-fpclass-rv64.mir    | 32 ++++++++++++++
 3 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 52fa1cf9fa3cc..0b7eedadbf4af 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -583,7 +583,7 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
       .customFor(ST.hasStdExtF(), {{s1, s32}})
       .customFor(ST.hasStdExtD(), {{s1, s64}})
       .customFor(ST.hasStdExtZfh(), {{s1, s16}})
-      .lowerFor({{s1, s32}, {s1, s64}});
+      .lowerFor({{s1, s32}, {s1, s64}, {s1, s128}});
 
   getActionDefinitionsBuilder(G_FCONSTANT)
       .legalFor(ST.hasStdExtF(), {s32})
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 fb8c5c39962a8..a01b0ab701fca 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
@@ -50,3 +50,45 @@ body:             |
     PseudoRET implicit $x10
 
 ...
+---
+name:            is_fpclass_f128
+body:             |
+  bb.1:
+    ; CHECK-LABEL: name: is_fpclass_f128
+    ; CHECK: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 2147483647
+    ; CHECK-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 2147418112
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s32) = G_AND [[DEF]], [[C]]
+    ; CHECK-NEXT: [[AND1:%[0-9]+]]:_(s32) = G_AND [[DEF]], [[C]]
+    ; CHECK-NEXT: [[AND2:%[0-9]+]]:_(s32) = G_AND [[DEF]], [[C]]
+    ; CHECK-NEXT: [[AND3:%[0-9]+]]:_(s32) = G_AND [[DEF]], [[C1]]
+    ; CHECK-NEXT: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+    ; CHECK-NEXT: [[XOR:%[0-9]+]]:_(s32) = G_XOR [[AND]], [[C2]]
+    ; CHECK-NEXT: [[XOR1:%[0-9]+]]:_(s32) = G_XOR [[AND1]], [[C2]]
+    ; CHECK-NEXT: [[XOR2:%[0-9]+]]:_(s32) = G_XOR [[AND2]], [[C2]]
+    ; CHECK-NEXT: [[XOR3:%[0-9]+]]:_(s32) = G_XOR [[AND3]], [[C2]]
+    ; CHECK-NEXT: [[OR:%[0-9]+]]:_(s32) = G_OR [[XOR]], [[XOR1]]
+    ; CHECK-NEXT: [[OR1:%[0-9]+]]:_(s32) = G_OR [[OR]], [[XOR2]]
+    ; CHECK-NEXT: [[OR2:%[0-9]+]]:_(s32) = G_OR [[OR1]], [[XOR3]]
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[OR2]](s32), [[C2]]
+    ; CHECK-NEXT: [[OR3:%[0-9]+]]:_(s32) = G_OR [[C4]], [[ICMP]]
+    ; CHECK-NEXT: [[XOR4:%[0-9]+]]:_(s32) = G_XOR [[DEF]], [[C2]]
+    ; CHECK-NEXT: [[XOR5:%[0-9]+]]:_(s32) = G_XOR [[DEF]], [[C2]]
+    ; CHECK-NEXT: [[XOR6:%[0-9]+]]:_(s32) = G_XOR [[DEF]], [[C2]]
+    ; CHECK-NEXT: [[XOR7:%[0-9]+]]:_(s32) = G_XOR [[DEF]], [[C3]]
+    ; CHECK-NEXT: [[OR4:%[0-9]+]]:_(s32) = G_OR [[XOR4]], [[XOR5]]
+    ; CHECK-NEXT: [[OR5:%[0-9]+]]:_(s32) = G_OR [[OR4]], [[XOR6]]
+    ; CHECK-NEXT: [[OR6:%[0-9]+]]:_(s32) = G_OR [[OR5]], [[XOR7]]
+    ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[OR6]](s32), [[C2]]
+    ; CHECK-NEXT: [[OR7:%[0-9]+]]:_(s32) = G_OR [[OR3]], [[ICMP1]]
+    ; CHECK-NEXT: $x10 = COPY [[OR7]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:_(s128) = G_IMPLICIT_DEF
+    %1:_(s1) = G_IS_FPCLASS %0(s128), 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
index 735398b873c6c..ecddc3484f697 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
@@ -50,3 +50,35 @@ body:             |
     PseudoRET implicit $x10
 
 ...
+---
+name:            is_fpclass_f128
+body:             |
+  bb.1:
+    ; CHECK-LABEL: name: is_fpclass_f128
+    ; CHECK: [[DEF:%[0-9]+]]:_(s64) = G_IMPLICIT_DEF
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 -1
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 9223372036854775807
+    ; CHECK-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+    ; CHECK-NEXT: [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 9223090561878065152
+    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s64) = G_AND [[DEF]], [[C]]
+    ; CHECK-NEXT: [[AND1:%[0-9]+]]:_(s64) = G_AND [[DEF]], [[C1]]
+    ; CHECK-NEXT: [[C4:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+    ; CHECK-NEXT: [[XOR:%[0-9]+]]:_(s64) = G_XOR [[AND]], [[C2]]
+    ; CHECK-NEXT: [[XOR1:%[0-9]+]]:_(s64) = G_XOR [[AND1]], [[C2]]
+    ; CHECK-NEXT: [[OR:%[0-9]+]]:_(s64) = G_OR [[XOR]], [[XOR1]]
+    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s64) = G_ICMP intpred(eq), [[OR]](s64), [[C2]]
+    ; CHECK-NEXT: [[OR1:%[0-9]+]]:_(s64) = G_OR [[C4]], [[ICMP]]
+    ; CHECK-NEXT: [[XOR2:%[0-9]+]]:_(s64) = G_XOR [[DEF]], [[C2]]
+    ; CHECK-NEXT: [[XOR3:%[0-9]+]]:_(s64) = G_XOR [[DEF]], [[C3]]
+    ; CHECK-NEXT: [[OR2:%[0-9]+]]:_(s64) = G_OR [[XOR2]], [[XOR3]]
+    ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(s64) = G_ICMP intpred(eq), [[OR2]](s64), [[C2]]
+    ; CHECK-NEXT: [[OR3:%[0-9]+]]:_(s64) = G_OR [[OR1]], [[ICMP1]]
+    ; CHECK-NEXT: $x10 = COPY [[OR3]](s64)
+    ; CHECK-NEXT: PseudoRET implicit $x10
+    %0:_(s128) = G_IMPLICIT_DEF
+    %1:_(s1) = G_IS_FPCLASS %0(s128), 608
+    %2:_(s64) = G_ANYEXT %1(s1)
+    $x10 = COPY %2(s64)
+    PseudoRET implicit $x10
+
+...

>From f471d223053041b5aa702316c2fe44163248de0a Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Tue, 5 May 2026 09:50:23 +0200
Subject: [PATCH 2/5] Catch all lowering, end-to-end tests

---
 .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp |   2 +-
 .../RISCV/GlobalISel/double-intrinsics.ll     | 129 ++++++++++++++++++
 .../GlobalISel/legalizer-info-validation.mir  |   4 +-
 3 files changed, 132 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 0b7eedadbf4af..b7efee8bf4c83 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -583,7 +583,7 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
       .customFor(ST.hasStdExtF(), {{s1, s32}})
       .customFor(ST.hasStdExtD(), {{s1, s64}})
       .customFor(ST.hasStdExtZfh(), {{s1, s16}})
-      .lowerFor({{s1, s32}, {s1, s64}, {s1, s128}});
+      .lower();
 
   getActionDefinitionsBuilder(G_FCONSTANT)
       .legalFor(ST.hasStdExtF(), {s32})
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/double-intrinsics.ll b/llvm/test/CodeGen/RISCV/GlobalISel/double-intrinsics.ll
index 906e4bc41d960..13f1dbff77e1a 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/double-intrinsics.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/double-intrinsics.ll
@@ -1014,6 +1014,135 @@ define i1 @isnan_d_fpclass(double %x) {
   ret i1 %1
 }
 
+define i1 @isnan_q_fpclass(fp128 %x) {
+; RV32IFD-LABEL: isnan_q_fpclass:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    lw a3, 4(a0)
+; RV32IFD-NEXT:    lw a2, 12(a0)
+; RV32IFD-NEXT:    lw a1, 8(a0)
+; RV32IFD-NEXT:    slli a2, a2, 1
+; RV32IFD-NEXT:    beqz a3, .LBB26_2
+; RV32IFD-NEXT:  # %bb.1:
+; RV32IFD-NEXT:    snez a0, a3
+; RV32IFD-NEXT:    j .LBB26_3
+; RV32IFD-NEXT:  .LBB26_2:
+; RV32IFD-NEXT:    lw a0, 0(a0)
+; RV32IFD-NEXT:    snez a0, a0
+; RV32IFD-NEXT:  .LBB26_3:
+; RV32IFD-NEXT:    lui a3, 524272
+; RV32IFD-NEXT:    srli a2, a2, 1
+; RV32IFD-NEXT:    bnez a1, .LBB26_6
+; RV32IFD-NEXT:  # %bb.4:
+; RV32IFD-NEXT:    bne a2, a3, .LBB26_7
+; RV32IFD-NEXT:  .LBB26_5:
+; RV32IFD-NEXT:    ret
+; RV32IFD-NEXT:  .LBB26_6:
+; RV32IFD-NEXT:    snez a0, a1
+; RV32IFD-NEXT:    beq a2, a3, .LBB26_5
+; RV32IFD-NEXT:  .LBB26_7:
+; RV32IFD-NEXT:    sltu a0, a3, a2
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: isnan_q_fpclass:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    lui a2, 32767
+; RV64IFD-NEXT:    slli a3, a1, 1
+; RV64IFD-NEXT:    slli a1, a2, 36
+; RV64IFD-NEXT:    srli a2, a3, 1
+; RV64IFD-NEXT:    beq a2, a1, .LBB26_2
+; RV64IFD-NEXT:  # %bb.1:
+; RV64IFD-NEXT:    sltu a0, a1, a2
+; RV64IFD-NEXT:    ret
+; RV64IFD-NEXT:  .LBB26_2:
+; RV64IFD-NEXT:    snez a0, a0
+; RV64IFD-NEXT:    ret
+;
+; RV32I-LABEL: isnan_q_fpclass:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    lw a3, 4(a0)
+; RV32I-NEXT:    lw a2, 12(a0)
+; RV32I-NEXT:    lw a1, 8(a0)
+; RV32I-NEXT:    slli a2, a2, 1
+; RV32I-NEXT:    beqz a3, .LBB26_2
+; RV32I-NEXT:  # %bb.1:
+; RV32I-NEXT:    snez a0, a3
+; RV32I-NEXT:    j .LBB26_3
+; RV32I-NEXT:  .LBB26_2:
+; RV32I-NEXT:    lw a0, 0(a0)
+; RV32I-NEXT:    snez a0, a0
+; RV32I-NEXT:  .LBB26_3:
+; RV32I-NEXT:    lui a3, 524272
+; RV32I-NEXT:    srli a2, a2, 1
+; RV32I-NEXT:    bnez a1, .LBB26_6
+; RV32I-NEXT:  # %bb.4:
+; RV32I-NEXT:    bne a2, a3, .LBB26_7
+; RV32I-NEXT:  .LBB26_5:
+; RV32I-NEXT:    ret
+; RV32I-NEXT:  .LBB26_6:
+; RV32I-NEXT:    snez a0, a1
+; RV32I-NEXT:    beq a2, a3, .LBB26_5
+; RV32I-NEXT:  .LBB26_7:
+; RV32I-NEXT:    sltu a0, a3, a2
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: isnan_q_fpclass:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    lui a2, 32767
+; RV64I-NEXT:    slli a3, a1, 1
+; RV64I-NEXT:    slli a1, a2, 36
+; RV64I-NEXT:    srli a2, a3, 1
+; RV64I-NEXT:    beq a2, a1, .LBB26_2
+; RV64I-NEXT:  # %bb.1:
+; RV64I-NEXT:    sltu a0, a1, a2
+; RV64I-NEXT:    ret
+; RV64I-NEXT:  .LBB26_2:
+; RV64I-NEXT:    snez a0, a0
+; RV64I-NEXT:    ret
+  %1 = call i1 @llvm.is.fpclass.f128(fp128 %x, i32 3)  ; nan
+  ret i1 %1
+}
+
+define i1 @iszero_q_fpclass(fp128 %x) {
+; RV32IFD-LABEL: iszero_q_fpclass:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    lw a1, 0(a0)
+; RV32IFD-NEXT:    lw a2, 4(a0)
+; RV32IFD-NEXT:    lw a3, 8(a0)
+; RV32IFD-NEXT:    lw a0, 12(a0)
+; RV32IFD-NEXT:    or a1, a1, a2
+; RV32IFD-NEXT:    or a0, a3, a0
+; RV32IFD-NEXT:    or a0, a1, a0
+; RV32IFD-NEXT:    seqz a0, a0
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: iszero_q_fpclass:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    or a0, a0, a1
+; RV64IFD-NEXT:    seqz a0, a0
+; RV64IFD-NEXT:    ret
+;
+; RV32I-LABEL: iszero_q_fpclass:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    lw a1, 0(a0)
+; RV32I-NEXT:    lw a2, 4(a0)
+; RV32I-NEXT:    lw a3, 8(a0)
+; RV32I-NEXT:    lw a0, 12(a0)
+; RV32I-NEXT:    or a1, a1, a2
+; RV32I-NEXT:    or a0, a3, a0
+; RV32I-NEXT:    or a0, a1, a0
+; RV32I-NEXT:    seqz a0, a0
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: iszero_q_fpclass:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    or a0, a0, a1
+; RV64I-NEXT:    seqz a0, a0
+; RV64I-NEXT:    ret
+  %1 = call i1 @llvm.is.fpclass.f128(fp128 %x, i32 64)  ; zero
+  ret i1 %1
+}
+
+
 define double @tan_f64(double %a) nounwind {
 ; RV32IFD-LABEL: tan_f64:
 ; RV32IFD:       # %bb.0:
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
index fc488807372e9..8edbf1a966dca 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
@@ -606,8 +606,8 @@
 # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: G_IS_FPCLASS (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
-# DEBUG-NEXT: .. the first uncovered type index: 2, OK
-# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
+# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: G_FCANONICALIZE (opcode {{[0-9]+}}): 1 type index, 0 imm indices
 # DEBUG-NEXT: .. the first uncovered type index: 1, OK
 # DEBUG-NEXT: .. the first uncovered imm index: 0, OK

>From c7956413f19d5e139d169b9ce4e0b3d3ac554d07 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Tue, 5 May 2026 22:16:17 +0200
Subject: [PATCH 3/5] Remove unnecessary test

---
 .../legalizer/legalize-is-fpclass-rv32.mir    | 42 -------------------
 1 file changed, 42 deletions(-)

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 a01b0ab701fca..fb8c5c39962a8 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
@@ -50,45 +50,3 @@ body:             |
     PseudoRET implicit $x10
 
 ...
----
-name:            is_fpclass_f128
-body:             |
-  bb.1:
-    ; CHECK-LABEL: name: is_fpclass_f128
-    ; CHECK: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF
-    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1
-    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 2147483647
-    ; CHECK-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
-    ; CHECK-NEXT: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 2147418112
-    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s32) = G_AND [[DEF]], [[C]]
-    ; CHECK-NEXT: [[AND1:%[0-9]+]]:_(s32) = G_AND [[DEF]], [[C]]
-    ; CHECK-NEXT: [[AND2:%[0-9]+]]:_(s32) = G_AND [[DEF]], [[C]]
-    ; CHECK-NEXT: [[AND3:%[0-9]+]]:_(s32) = G_AND [[DEF]], [[C1]]
-    ; CHECK-NEXT: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
-    ; CHECK-NEXT: [[XOR:%[0-9]+]]:_(s32) = G_XOR [[AND]], [[C2]]
-    ; CHECK-NEXT: [[XOR1:%[0-9]+]]:_(s32) = G_XOR [[AND1]], [[C2]]
-    ; CHECK-NEXT: [[XOR2:%[0-9]+]]:_(s32) = G_XOR [[AND2]], [[C2]]
-    ; CHECK-NEXT: [[XOR3:%[0-9]+]]:_(s32) = G_XOR [[AND3]], [[C2]]
-    ; CHECK-NEXT: [[OR:%[0-9]+]]:_(s32) = G_OR [[XOR]], [[XOR1]]
-    ; CHECK-NEXT: [[OR1:%[0-9]+]]:_(s32) = G_OR [[OR]], [[XOR2]]
-    ; CHECK-NEXT: [[OR2:%[0-9]+]]:_(s32) = G_OR [[OR1]], [[XOR3]]
-    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[OR2]](s32), [[C2]]
-    ; CHECK-NEXT: [[OR3:%[0-9]+]]:_(s32) = G_OR [[C4]], [[ICMP]]
-    ; CHECK-NEXT: [[XOR4:%[0-9]+]]:_(s32) = G_XOR [[DEF]], [[C2]]
-    ; CHECK-NEXT: [[XOR5:%[0-9]+]]:_(s32) = G_XOR [[DEF]], [[C2]]
-    ; CHECK-NEXT: [[XOR6:%[0-9]+]]:_(s32) = G_XOR [[DEF]], [[C2]]
-    ; CHECK-NEXT: [[XOR7:%[0-9]+]]:_(s32) = G_XOR [[DEF]], [[C3]]
-    ; CHECK-NEXT: [[OR4:%[0-9]+]]:_(s32) = G_OR [[XOR4]], [[XOR5]]
-    ; CHECK-NEXT: [[OR5:%[0-9]+]]:_(s32) = G_OR [[OR4]], [[XOR6]]
-    ; CHECK-NEXT: [[OR6:%[0-9]+]]:_(s32) = G_OR [[OR5]], [[XOR7]]
-    ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(s32) = G_ICMP intpred(eq), [[OR6]](s32), [[C2]]
-    ; CHECK-NEXT: [[OR7:%[0-9]+]]:_(s32) = G_OR [[OR3]], [[ICMP1]]
-    ; CHECK-NEXT: $x10 = COPY [[OR7]](s32)
-    ; CHECK-NEXT: PseudoRET implicit $x10
-    %0:_(s128) = G_IMPLICIT_DEF
-    %1:_(s1) = G_IS_FPCLASS %0(s128), 608
-    %2:_(s32) = G_ANYEXT %1(s1)
-    $x10 = COPY %2(s32)
-    PseudoRET implicit $x10
-
-...

>From 40be362c4c87fef5a515d2185cc43f951c83ae86 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Tue, 5 May 2026 22:17:37 +0200
Subject: [PATCH 4/5] Remove unnecessary test

---
 .../legalizer/legalize-is-fpclass-rv64.mir    | 32 -------------------
 1 file changed, 32 deletions(-)

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 ecddc3484f697..735398b873c6c 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
@@ -50,35 +50,3 @@ body:             |
     PseudoRET implicit $x10
 
 ...
----
-name:            is_fpclass_f128
-body:             |
-  bb.1:
-    ; CHECK-LABEL: name: is_fpclass_f128
-    ; CHECK: [[DEF:%[0-9]+]]:_(s64) = G_IMPLICIT_DEF
-    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 -1
-    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 9223372036854775807
-    ; CHECK-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
-    ; CHECK-NEXT: [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 9223090561878065152
-    ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s64) = G_AND [[DEF]], [[C]]
-    ; CHECK-NEXT: [[AND1:%[0-9]+]]:_(s64) = G_AND [[DEF]], [[C1]]
-    ; CHECK-NEXT: [[C4:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
-    ; CHECK-NEXT: [[XOR:%[0-9]+]]:_(s64) = G_XOR [[AND]], [[C2]]
-    ; CHECK-NEXT: [[XOR1:%[0-9]+]]:_(s64) = G_XOR [[AND1]], [[C2]]
-    ; CHECK-NEXT: [[OR:%[0-9]+]]:_(s64) = G_OR [[XOR]], [[XOR1]]
-    ; CHECK-NEXT: [[ICMP:%[0-9]+]]:_(s64) = G_ICMP intpred(eq), [[OR]](s64), [[C2]]
-    ; CHECK-NEXT: [[OR1:%[0-9]+]]:_(s64) = G_OR [[C4]], [[ICMP]]
-    ; CHECK-NEXT: [[XOR2:%[0-9]+]]:_(s64) = G_XOR [[DEF]], [[C2]]
-    ; CHECK-NEXT: [[XOR3:%[0-9]+]]:_(s64) = G_XOR [[DEF]], [[C3]]
-    ; CHECK-NEXT: [[OR2:%[0-9]+]]:_(s64) = G_OR [[XOR2]], [[XOR3]]
-    ; CHECK-NEXT: [[ICMP1:%[0-9]+]]:_(s64) = G_ICMP intpred(eq), [[OR2]](s64), [[C2]]
-    ; CHECK-NEXT: [[OR3:%[0-9]+]]:_(s64) = G_OR [[OR1]], [[ICMP1]]
-    ; CHECK-NEXT: $x10 = COPY [[OR3]](s64)
-    ; CHECK-NEXT: PseudoRET implicit $x10
-    %0:_(s128) = G_IMPLICIT_DEF
-    %1:_(s1) = G_IS_FPCLASS %0(s128), 608
-    %2:_(s64) = G_ANYEXT %1(s1)
-    $x10 = COPY %2(s64)
-    PseudoRET implicit $x10
-
-...

>From e8416ade58b6644cc9b97b477ff8ffd194004bd0 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <gaborspaits1 at gmail.com>
Date: Wed, 6 May 2026 09:53:03 +0200
Subject: [PATCH 5/5] Add more tests

---
 .../RISCV/GlobalISel/double-intrinsics.ll     | 282 +++++++++++++++++-
 1 file changed, 281 insertions(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/double-intrinsics.ll b/llvm/test/CodeGen/RISCV/GlobalISel/double-intrinsics.ll
index 13f1dbff77e1a..33338591d6e35 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/double-intrinsics.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/double-intrinsics.ll
@@ -1138,7 +1138,287 @@ define i1 @iszero_q_fpclass(fp128 %x) {
 ; RV64I-NEXT:    or a0, a0, a1
 ; RV64I-NEXT:    seqz a0, a0
 ; RV64I-NEXT:    ret
-  %1 = call i1 @llvm.is.fpclass.f128(fp128 %x, i32 64)  ; zero
+  %1 = call i1 @llvm.is.fpclass.f128(fp128 %x, i32 64)  ; positive zero
+  ret i1 %1
+}
+
+define i1 @isinf_q_fpclass(fp128 %x) {
+; RV32IFD-LABEL: isinf_q_fpclass:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    lw a1, 0(a0)
+; RV32IFD-NEXT:    lw a2, 12(a0)
+; RV32IFD-NEXT:    lw a4, 4(a0)
+; RV32IFD-NEXT:    lw a3, 8(a0)
+; RV32IFD-NEXT:    lui a5, 1048560
+; RV32IFD-NEXT:    slli a6, a2, 1
+; RV32IFD-NEXT:    sltiu a0, a1, 0
+; RV32IFD-NEXT:    sltu a1, a4, a4
+; RV32IFD-NEXT:    seqz a7, a4
+; RV32IFD-NEXT:    and a7, a7, a0
+; RV32IFD-NEXT:    or a1, a1, a7
+; RV32IFD-NEXT:    seqz a7, a3
+; RV32IFD-NEXT:    and a7, a7, a1
+; RV32IFD-NEXT:    sub a1, a3, a1
+; RV32IFD-NEXT:    sltu t0, a3, a3
+; RV32IFD-NEXT:    srli a6, a6, 1
+; RV32IFD-NEXT:    sub a4, a4, a0
+; RV32IFD-NEXT:    xor a3, a2, a6
+; RV32IFD-NEXT:    or a2, t0, a7
+; RV32IFD-NEXT:    add a5, a6, a5
+; RV32IFD-NEXT:    beqz a4, .LBB28_2
+; RV32IFD-NEXT:  # %bb.1:
+; RV32IFD-NEXT:    sltiu a0, a4, 0
+; RV32IFD-NEXT:  .LBB28_2:
+; RV32IFD-NEXT:    mv a4, a3
+; RV32IFD-NEXT:    sub a2, a5, a2
+; RV32IFD-NEXT:    lui a3, 524256
+; RV32IFD-NEXT:    beqz a1, .LBB28_4
+; RV32IFD-NEXT:  # %bb.3:
+; RV32IFD-NEXT:    sltiu a0, a1, 0
+; RV32IFD-NEXT:  .LBB28_4:
+; RV32IFD-NEXT:    snez a1, a4
+; RV32IFD-NEXT:    beq a2, a3, .LBB28_6
+; RV32IFD-NEXT:  # %bb.5:
+; RV32IFD-NEXT:    sltu a0, a2, a3
+; RV32IFD-NEXT:  .LBB28_6:
+; RV32IFD-NEXT:    xori a1, a1, 1
+; RV32IFD-NEXT:    and a0, a0, a1
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: isinf_q_fpclass:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    slli a2, a1, 1
+; RV64IFD-NEXT:    li a3, 1
+; RV64IFD-NEXT:    sltiu a0, a0, 0
+; RV64IFD-NEXT:    srli a2, a2, 1
+; RV64IFD-NEXT:    slli a3, a3, 48
+; RV64IFD-NEXT:    xor a1, a1, a2
+; RV64IFD-NEXT:    sub a2, a2, a3
+; RV64IFD-NEXT:    lui a3, 16383
+; RV64IFD-NEXT:    mv a1, a1
+; RV64IFD-NEXT:    sub a2, a2, a0
+; RV64IFD-NEXT:    slli a3, a3, 37
+; RV64IFD-NEXT:    snez a1, a1
+; RV64IFD-NEXT:    beq a2, a3, .LBB28_2
+; RV64IFD-NEXT:  # %bb.1:
+; RV64IFD-NEXT:    sltu a0, a2, a3
+; RV64IFD-NEXT:  .LBB28_2:
+; RV64IFD-NEXT:    xori a1, a1, 1
+; RV64IFD-NEXT:    and a0, a0, a1
+; RV64IFD-NEXT:    ret
+;
+; RV32I-LABEL: isinf_q_fpclass:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    lw a1, 0(a0)
+; RV32I-NEXT:    lw a2, 12(a0)
+; RV32I-NEXT:    lw a4, 4(a0)
+; RV32I-NEXT:    lw a3, 8(a0)
+; RV32I-NEXT:    lui a5, 1048560
+; RV32I-NEXT:    slli a6, a2, 1
+; RV32I-NEXT:    sltiu a0, a1, 0
+; RV32I-NEXT:    sltu a1, a4, a4
+; RV32I-NEXT:    seqz a7, a4
+; RV32I-NEXT:    and a7, a7, a0
+; RV32I-NEXT:    or a1, a1, a7
+; RV32I-NEXT:    seqz a7, a3
+; RV32I-NEXT:    and a7, a7, a1
+; RV32I-NEXT:    sub a1, a3, a1
+; RV32I-NEXT:    sltu t0, a3, a3
+; RV32I-NEXT:    srli a6, a6, 1
+; RV32I-NEXT:    sub a4, a4, a0
+; RV32I-NEXT:    xor a3, a2, a6
+; RV32I-NEXT:    or a2, t0, a7
+; RV32I-NEXT:    add a5, a6, a5
+; RV32I-NEXT:    beqz a4, .LBB28_2
+; RV32I-NEXT:  # %bb.1:
+; RV32I-NEXT:    sltiu a0, a4, 0
+; RV32I-NEXT:  .LBB28_2:
+; RV32I-NEXT:    mv a4, a3
+; RV32I-NEXT:    sub a2, a5, a2
+; RV32I-NEXT:    lui a3, 524256
+; RV32I-NEXT:    beqz a1, .LBB28_4
+; RV32I-NEXT:  # %bb.3:
+; RV32I-NEXT:    sltiu a0, a1, 0
+; RV32I-NEXT:  .LBB28_4:
+; RV32I-NEXT:    snez a1, a4
+; RV32I-NEXT:    beq a2, a3, .LBB28_6
+; RV32I-NEXT:  # %bb.5:
+; RV32I-NEXT:    sltu a0, a2, a3
+; RV32I-NEXT:  .LBB28_6:
+; RV32I-NEXT:    xori a1, a1, 1
+; RV32I-NEXT:    and a0, a0, a1
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: isinf_q_fpclass:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    slli a2, a1, 1
+; RV64I-NEXT:    li a3, 1
+; RV64I-NEXT:    sltiu a0, a0, 0
+; RV64I-NEXT:    srli a2, a2, 1
+; RV64I-NEXT:    slli a3, a3, 48
+; RV64I-NEXT:    xor a1, a1, a2
+; RV64I-NEXT:    sub a2, a2, a3
+; RV64I-NEXT:    lui a3, 16383
+; RV64I-NEXT:    mv a1, a1
+; RV64I-NEXT:    sub a2, a2, a0
+; RV64I-NEXT:    slli a3, a3, 37
+; RV64I-NEXT:    snez a1, a1
+; RV64I-NEXT:    beq a2, a3, .LBB28_2
+; RV64I-NEXT:  # %bb.1:
+; RV64I-NEXT:    sltu a0, a2, a3
+; RV64I-NEXT:  .LBB28_2:
+; RV64I-NEXT:    xori a1, a1, 1
+; RV64I-NEXT:    and a0, a0, a1
+; RV64I-NEXT:    ret
+  %1 = call i1 @llvm.is.fpclass.f128(fp128 %x, i32 256)  ; positive infinity
+  ret i1 %1
+}
+
+define i1 @isinf_or_zero_q_fpclass(fp128 %x) {
+; RV32IFD-LABEL: isinf_or_zero_q_fpclass:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    lw a3, 0(a0)
+; RV32IFD-NEXT:    lw a4, 12(a0)
+; RV32IFD-NEXT:    lw a5, 4(a0)
+; RV32IFD-NEXT:    lw a6, 8(a0)
+; RV32IFD-NEXT:    lui a7, 1048560
+; RV32IFD-NEXT:    slli t0, a4, 1
+; RV32IFD-NEXT:    or a1, a3, a5
+; RV32IFD-NEXT:    or a2, a6, a4
+; RV32IFD-NEXT:    sltiu a0, a3, 0
+; RV32IFD-NEXT:    sltu a3, a5, a5
+; RV32IFD-NEXT:    seqz t1, a5
+; RV32IFD-NEXT:    and t1, t1, a0
+; RV32IFD-NEXT:    or a3, a3, t1
+; RV32IFD-NEXT:    seqz t1, a6
+; RV32IFD-NEXT:    and t1, t1, a3
+; RV32IFD-NEXT:    sub a3, a6, a3
+; RV32IFD-NEXT:    sltu t2, a6, a6
+; RV32IFD-NEXT:    srli t0, t0, 1
+; RV32IFD-NEXT:    sub a5, a5, a0
+; RV32IFD-NEXT:    xor a6, a4, t0
+; RV32IFD-NEXT:    or a4, t2, t1
+; RV32IFD-NEXT:    add a7, t0, a7
+; RV32IFD-NEXT:    beqz a5, .LBB29_2
+; RV32IFD-NEXT:  # %bb.1:
+; RV32IFD-NEXT:    sltiu a0, a5, 0
+; RV32IFD-NEXT:  .LBB29_2:
+; RV32IFD-NEXT:    mv a6, a6
+; RV32IFD-NEXT:    or a5, a1, a2
+; RV32IFD-NEXT:    sub a1, a7, a4
+; RV32IFD-NEXT:    lui a2, 524256
+; RV32IFD-NEXT:    beqz a3, .LBB29_4
+; RV32IFD-NEXT:  # %bb.3:
+; RV32IFD-NEXT:    sltiu a0, a3, 0
+; RV32IFD-NEXT:  .LBB29_4:
+; RV32IFD-NEXT:    snez a4, a6
+; RV32IFD-NEXT:    seqz a3, a5
+; RV32IFD-NEXT:    beq a1, a2, .LBB29_6
+; RV32IFD-NEXT:  # %bb.5:
+; RV32IFD-NEXT:    sltu a0, a1, a2
+; RV32IFD-NEXT:  .LBB29_6:
+; RV32IFD-NEXT:    xori a1, a4, 1
+; RV32IFD-NEXT:    and a0, a0, a1
+; RV32IFD-NEXT:    or a0, a3, a0
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: isinf_or_zero_q_fpclass:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    slli a2, a1, 1
+; RV64IFD-NEXT:    or a5, a0, a1
+; RV64IFD-NEXT:    li a3, 1
+; RV64IFD-NEXT:    sltiu a0, a0, 0
+; RV64IFD-NEXT:    srli a2, a2, 1
+; RV64IFD-NEXT:    slli a3, a3, 48
+; RV64IFD-NEXT:    xor a1, a1, a2
+; RV64IFD-NEXT:    sub a2, a2, a3
+; RV64IFD-NEXT:    lui a3, 16383
+; RV64IFD-NEXT:    slli a3, a3, 37
+; RV64IFD-NEXT:    mv a1, a1
+; RV64IFD-NEXT:    sub a4, a2, a0
+; RV64IFD-NEXT:    snez a2, a1
+; RV64IFD-NEXT:    seqz a1, a5
+; RV64IFD-NEXT:    beq a4, a3, .LBB29_2
+; RV64IFD-NEXT:  # %bb.1:
+; RV64IFD-NEXT:    sltu a0, a4, a3
+; RV64IFD-NEXT:  .LBB29_2:
+; RV64IFD-NEXT:    xori a2, a2, 1
+; RV64IFD-NEXT:    and a0, a0, a2
+; RV64IFD-NEXT:    or a0, a1, a0
+; RV64IFD-NEXT:    ret
+;
+; RV32I-LABEL: isinf_or_zero_q_fpclass:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    lw a3, 0(a0)
+; RV32I-NEXT:    lw a4, 12(a0)
+; RV32I-NEXT:    lw a5, 4(a0)
+; RV32I-NEXT:    lw a6, 8(a0)
+; RV32I-NEXT:    lui a7, 1048560
+; RV32I-NEXT:    slli t0, a4, 1
+; RV32I-NEXT:    or a1, a3, a5
+; RV32I-NEXT:    or a2, a6, a4
+; RV32I-NEXT:    sltiu a0, a3, 0
+; RV32I-NEXT:    sltu a3, a5, a5
+; RV32I-NEXT:    seqz t1, a5
+; RV32I-NEXT:    and t1, t1, a0
+; RV32I-NEXT:    or a3, a3, t1
+; RV32I-NEXT:    seqz t1, a6
+; RV32I-NEXT:    and t1, t1, a3
+; RV32I-NEXT:    sub a3, a6, a3
+; RV32I-NEXT:    sltu t2, a6, a6
+; RV32I-NEXT:    srli t0, t0, 1
+; RV32I-NEXT:    sub a5, a5, a0
+; RV32I-NEXT:    xor a6, a4, t0
+; RV32I-NEXT:    or a4, t2, t1
+; RV32I-NEXT:    add a7, t0, a7
+; RV32I-NEXT:    beqz a5, .LBB29_2
+; RV32I-NEXT:  # %bb.1:
+; RV32I-NEXT:    sltiu a0, a5, 0
+; RV32I-NEXT:  .LBB29_2:
+; RV32I-NEXT:    mv a6, a6
+; RV32I-NEXT:    or a5, a1, a2
+; RV32I-NEXT:    sub a1, a7, a4
+; RV32I-NEXT:    lui a2, 524256
+; RV32I-NEXT:    beqz a3, .LBB29_4
+; RV32I-NEXT:  # %bb.3:
+; RV32I-NEXT:    sltiu a0, a3, 0
+; RV32I-NEXT:  .LBB29_4:
+; RV32I-NEXT:    snez a4, a6
+; RV32I-NEXT:    seqz a3, a5
+; RV32I-NEXT:    beq a1, a2, .LBB29_6
+; RV32I-NEXT:  # %bb.5:
+; RV32I-NEXT:    sltu a0, a1, a2
+; RV32I-NEXT:  .LBB29_6:
+; RV32I-NEXT:    xori a1, a4, 1
+; RV32I-NEXT:    and a0, a0, a1
+; RV32I-NEXT:    or a0, a3, a0
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: isinf_or_zero_q_fpclass:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    slli a2, a1, 1
+; RV64I-NEXT:    or a5, a0, a1
+; RV64I-NEXT:    li a3, 1
+; RV64I-NEXT:    sltiu a0, a0, 0
+; RV64I-NEXT:    srli a2, a2, 1
+; RV64I-NEXT:    slli a3, a3, 48
+; RV64I-NEXT:    xor a1, a1, a2
+; RV64I-NEXT:    sub a2, a2, a3
+; RV64I-NEXT:    lui a3, 16383
+; RV64I-NEXT:    slli a3, a3, 37
+; RV64I-NEXT:    mv a1, a1
+; RV64I-NEXT:    sub a4, a2, a0
+; RV64I-NEXT:    snez a2, a1
+; RV64I-NEXT:    seqz a1, a5
+; RV64I-NEXT:    beq a4, a3, .LBB29_2
+; RV64I-NEXT:  # %bb.1:
+; RV64I-NEXT:    sltu a0, a4, a3
+; RV64I-NEXT:  .LBB29_2:
+; RV64I-NEXT:    xori a2, a2, 1
+; RV64I-NEXT:    and a0, a0, a2
+; RV64I-NEXT:    or a0, a1, a0
+; RV64I-NEXT:    ret
+  %1 = call i1 @llvm.is.fpclass.f128(fp128 %x, i32 320) ; positive zero or inf.
   ret i1 %1
 }
 



More information about the llvm-commits mailing list