[llvm] [AIX BB] Fix IS_FPCLASS expansion crash for mask fcInf|fcNan on targets without SETUEQ (PR #213298)

Daniel Chen via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 31 10:52:57 PDT 2026


https://github.com/DanielCChen updated https://github.com/llvm/llvm-project/pull/213298

>From 2d7b5053bfcb970a45e32c21bbca9c083f43b375 Mon Sep 17 00:00:00 2001
From: Daniel Chen <cdchen at ca.ibm.com>
Date: Fri, 31 Jul 2026 11:40:09 -0400
Subject: [PATCH] Fix IS_FPCLASS expansion crash for mask fcInf|fcNan on
 targets without SETUEQ

---
 llvm/lib/Target/PowerPC/PPCISelLowering.cpp   |  24 ++++
 .../PowerPC/fp-classify-not-finite-aix32.ll   | 127 ++++++++++++++++++
 2 files changed, 151 insertions(+)
 create mode 100644 llvm/test/CodeGen/PowerPC/fp-classify-not-finite-aix32.ll

diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 1a80d0a05655a..e0b59644b8ece 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -11991,6 +11991,30 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
   // - If value is not NaN, the comparison is equal (EQ bit set)
 
   if ((Category != fcNan) && (Category != ~fcNan)) {
+    // On 32-bit PPC targets (where i64 is not a legal type), the generic
+    // integer-bitcast expansion of IS_FPCLASS produces illegal i64 nodes and
+    // crashes.  Handle fcInf|fcNan (!isfinite) and fcFinite (isfinite) here
+    // using fabs + SETCC with the target's legal result type.
+    // On 64-bit PPC targets, leave these for the generic expander which uses
+    // the integer-bitcast path and produces better code.
+    if (!Subtarget.isPPC64()) {
+      EVT ResultVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
+      const llvm::fltSemantics &Sem =
+          VT == MVT::f64 ? llvm::APFloat::IEEEdouble()
+                         : llvm::APFloat::IEEEsingle();
+      if (Category == (fcInf | fcNan)) {
+        // !isfinite(x) ==> fabs(x) >= +inf
+        SDValue Abs = DAG.getNode(ISD::FABS, Dl, VT, LHS);
+        SDValue Inf = DAG.getConstantFP(llvm::APFloat::getInf(Sem), Dl, VT);
+        return DAG.getSetCC(Dl, ResultVT, Abs, Inf, ISD::SETUGE);
+      }
+      if (Category == fcFinite) {
+        // isfinite(x) ==> fabs(x) < +inf
+        SDValue Abs = DAG.getNode(ISD::FABS, Dl, VT, LHS);
+        SDValue Inf = DAG.getConstantFP(llvm::APFloat::getInf(Sem), Dl, VT);
+        return DAG.getSetCC(Dl, ResultVT, Abs, Inf, ISD::SETOLT);
+      }
+    }
     // If not checking for NaN or non-NaN, we can't handle this without P9Vector
     return SDValue();
   }
diff --git a/llvm/test/CodeGen/PowerPC/fp-classify-not-finite-aix32.ll b/llvm/test/CodeGen/PowerPC/fp-classify-not-finite-aix32.ll
new file mode 100644
index 0000000000000..0cf20ac2ac3be
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/fp-classify-not-finite-aix32.ll
@@ -0,0 +1,127 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; Test that IS_FPCLASS with mask fcInf|fcNan (519, "!isfinite") is correctly
+; lowered on 32-bit AIX targets (pwr7, pwr8).
+;
+; Root cause: commit 7e1aba74 moved setOperationAction(IS_FPCLASS, Custom) to an
+; unconditional block, so all PPC targets including powerpc64-ibm-aix -m32 now
+; mark IS_FPCLASS as Custom.  When SimplifySetCC sees IS_FPCLASS is
+; LegalOrCustom, it transforms SETUEQ(fabs(x), +inf) into a new
+; IS_FPCLASS(x, fcInf|fcNan=519) node post-legalize.  LowerIS_FPCLASS returned
+; SDValue() for mask 519 (only handling fcNan and ~fcNan), causing ExpandNode to
+; call expandIS_FPCLASS post-legalize with an i1 result type that is not legal
+; on PPC32 (i32 is the legal SETCC result type when useCRBits=false), crashing
+; with "Cannot select: i1 = is_fpclass" or "Unexpected illegal type".
+;
+; Fix: LowerIS_FPCLASS now handles fcInf|fcNan and fcFinite on !isPPC64() targets
+; by emitting fabs(x) u>= +inf (SETUGE) and fabs(x) olt +inf (SETOLT)
+; respectively, using getSetCCResultType() for the correct legal result type.
+; Both the strictfp (hasNoFPExcept=false) and non-strictfp (hasNoFPExcept=true)
+; paths are covered since the fix is in LowerIS_FPCLASS, not expandIS_FPCLASS.
+;
+; RUN: llc -mtriple=powerpc-ibm-aix -mcpu=pwr7 < %s \
+; RUN:   -verify-machineinstrs -ppc-asm-full-reg-names | FileCheck %s --check-prefix=PPC32-PWR7
+; RUN: llc -mtriple=powerpc-ibm-aix -mcpu=pwr8 < %s \
+; RUN:   -verify-machineinstrs -ppc-asm-full-reg-names | FileCheck %s --check-prefix=PPC32-PWR8
+
+; Non-strictfp (nounwind): IS_FPCLASS node carries nofpexcept=true.
+define zeroext i1 @test_not_finite_f64(double %x) nounwind {
+; PPC32-PWR7-LABEL: test_not_finite_f64:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-NEXT:    lwz r3, L..C0(r2) # %const.0
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    isellt r3, 0, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_not_finite_f64:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    lwz r3, L..C0(r2) # %const.0
+; PPC32-PWR8-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    isellt r3, 0, r3
+; PPC32-PWR8-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f64(double %x, i32 519)
+  ret i1 %result
+}
+
+define zeroext i1 @test_not_finite_f32(float %x) nounwind {
+; PPC32-PWR7-LABEL: test_not_finite_f32:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-NEXT:    lwz r3, L..C1(r2) # %const.0
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    isellt r3, 0, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_not_finite_f32:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    lwz r3, L..C1(r2) # %const.0
+; PPC32-PWR8-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    isellt r3, 0, r3
+; PPC32-PWR8-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f32(float %x, i32 519)
+  ret i1 %result
+}
+
+; Strictfp: IS_FPCLASS node carries nofpexcept=false.
+; This matches the actual compiler-rt build scenario where -ffp-model=strict
+; causes IS_FPCLASS(519) to be emitted and reach LowerIS_FPCLASS unexpanded.
+define zeroext i1 @test_not_finite_f64_strict(double %x) strictfp {
+; PPC32-PWR7-LABEL: test_not_finite_f64_strict:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-NEXT:    lwz r3, L..C2(r2) # %const.0
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    isellt r3, 0, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_not_finite_f64_strict:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    lwz r3, L..C2(r2) # %const.0
+; PPC32-PWR8-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    isellt r3, 0, r3
+; PPC32-PWR8-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f64(double %x, i32 519)
+  ret i1 %result
+}
+
+define zeroext i1 @test_not_finite_f32_strict(float %x) strictfp {
+; PPC32-PWR7-LABEL: test_not_finite_f32_strict:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-NEXT:    lwz r3, L..C3(r2) # %const.0
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    isellt r3, 0, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_not_finite_f32_strict:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    lwz r3, L..C3(r2) # %const.0
+; PPC32-PWR8-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    isellt r3, 0, r3
+; PPC32-PWR8-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f32(float %x, i32 519)
+  ret i1 %result
+}
+
+declare i1 @llvm.is.fpclass.f64(double, i32)
+declare i1 @llvm.is.fpclass.f32(float, i32)



More information about the llvm-commits mailing list