[llvm] [PowerPC] Fix IS_FPCLASS crash on 32-bit AIX targets for fcFinite/fcInf/fcInf|fcNan masks (PR #213298)

Daniel Chen via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 3 04:06:15 PDT 2026


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

>From 8a489614c9c23cd1614f602da356d35fc01ae6c1 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   | 113 ++-
 .../test/CodeGen/PowerPC/fp-classify-aix32.ll | 929 ++++++++++++++++++
 2 files changed, 1032 insertions(+), 10 deletions(-)
 create mode 100644 llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll

diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 1a80d0a05655a..56f99ea221116 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -11966,6 +11966,7 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
   uint64_t RHSC = Op.getConstantOperandVal(1);
   SDLoc Dl(Op);
   FPClassTest Category = static_cast<FPClassTest>(RHSC);
+  EVT ResVT = Op.getValueType();
   EVT VT = LHS.getValueType();
 
   assert((VT == MVT::f32 || VT == MVT::f64 ||
@@ -11991,7 +11992,79 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
   // - If value is not NaN, the comparison is equal (EQ bit set)
 
   if ((Category != fcNan) && (Category != ~fcNan)) {
-    // If not checking for NaN or non-NaN, we can't handle this without P9Vector
+    // On 32-bit PPC targets (where i64 is not a legal type), the generic
+    // integer-bitcast path in expandIS_FPCLASS produces illegal i64 nodes after
+    // type legalization has already run.  Expand every non-NaN mask using only
+    // fabs + SETCC comparisons (all legal on PPC scalar f32/f64).
+    //
+    // On 64-bit PPC we return SDValue() to let the generic expander use the
+    // integer-bitcast path which 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();
+      SDValue Abs = DAG.getNode(ISD::FABS, Dl, VT, LHS);
+      SDValue Inf = DAG.getConstantFP(llvm::APFloat::getInf(Sem), Dl, VT);
+
+      // Handle the four masks expressible via fabs-vs-infinity comparisons:
+      //   fcInf | fcNan  (519) : !isfinite(x)  <=>  fabs(x) u>= +inf
+      //   fcFinite        (504): isfinite(x)    <=>  fabs(x) o<  +inf
+      //   fcInf           (516): isinf(x)       <=>  fabs(x) o== +inf
+      //   ~fcInf & ALL    (507): !isinf(x)      <=>  fabs(x) u!= +inf  (SETUNE)
+      //
+      // For any other mask, decompose into the above via complement / OR so we
+      // never fall through to the integer-bitcast path which needs i64.
+      if (Category == (fcInf | fcNan)) {
+        // !isfinite(x) ==> fabs(x) u>= +inf
+        return DAG.getSetCC(Dl, ResultVT, Abs, Inf, ISD::SETUGE);
+      }
+      if (Category == fcFinite) {
+        // isfinite(x) ==> fabs(x) o< +inf
+        return DAG.getSetCC(Dl, ResultVT, Abs, Inf, ISD::SETOLT);
+      }
+      if (Category == fcInf) {
+        // isinf(x) ==> fabs(x) o== +inf
+        return DAG.getSetCC(Dl, ResultVT, Abs, Inf, ISD::SETOEQ);
+      }
+      // ~fcInf = all flags except fcPosInf and fcNegInf = "not inf"
+      // fabs(x) u!= +inf  (unordered-or-not-equal catches NaN too)
+      FPClassTest NotInf = static_cast<FPClassTest>(fcAllFlags & ~fcInf);
+      if (Category == NotInf)
+        return DAG.getSetCC(Dl, ResultVT, Abs, Inf, ISD::SETUNE);
+
+      // General case: decompose mask into (isinf | isnan) and/or isfinite
+      // parts and combine with OR/NOT.
+      //
+      // Any remaining mask can be built from:
+      //   IsInf   = SETOEQ(fabs, +inf)
+      //   IsNan   = SETUO(x, x)          [but NaN path handled above]
+      //   IsFinite= SETOLT(fabs, +inf)
+      //
+      // Use the complement trick: if ~Category is one of our simple masks,
+      // negate it.
+      FPClassTest InvCategory =
+          static_cast<FPClassTest>(fcAllFlags & ~Category);
+      SDValue InvResult;
+      if (InvCategory == (fcInf | fcNan))
+        InvResult = DAG.getSetCC(Dl, ResultVT, Abs, Inf, ISD::SETUGE);
+      else if (InvCategory == fcFinite)
+        InvResult = DAG.getSetCC(Dl, ResultVT, Abs, Inf, ISD::SETOLT);
+      else if (InvCategory == fcInf)
+        InvResult = DAG.getSetCC(Dl, ResultVT, Abs, Inf, ISD::SETOEQ);
+      else if (InvCategory == NotInf)
+        InvResult = DAG.getSetCC(Dl, ResultVT, Abs, Inf, ISD::SETUNE);
+      if (InvResult)
+        return DAG.getNOT(Dl, InvResult, ResultVT);
+
+      // Any remaining mask involves sign-sensitive sub-classes (fcPosInf,
+      // fcNegInf, fcNormal, fcSubnormal, fcZero) that cannot be expressed
+      // via fabs-vs-infinity comparisons alone.  Return SDValue() to let the
+      // generic legalizer handle it; if it crashes on PPC32 that is a
+      // pre-existing limitation, not a regression introduced here.
+      return SDValue();
+    }
     return SDValue();
   }
 
@@ -12024,16 +12097,36 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
   // The CR field output will be allocated by the register allocator
   SDValue Cmp = SDValue(DAG.getMachineNode(CmpOp, Dl, MVT::i32, LHS, LHS), 0);
 
-  // Extract the unordered bit (FU) from the CR field
-  // For NaN detection: FU bit is set if operands are unordered (i.e., NaN)
-  SDValue NanCheck = SDValue(
-      DAG.getMachineNode(
-          TargetOpcode::EXTRACT_SUBREG, Dl, MVT::i1, Cmp,
-          DAG.getTargetConstant(Category == ~fcNan ? PPC::sub_un : PPC::sub_eq,
-                                Dl, MVT::i32)),
-      0);
+  // When useCRBits() is true (64-bit targets), i1 is a legal CR-bit type.
+  // Extract the relevant CR sub-register, invert via getNOT, and
+  // zero-extend to ResVT if needed (ResVT == i1 on 64-bit, so no-op there).
+  if (Subtarget.useCRBits()) {
+    SDValue NanCheck = SDValue(
+        DAG.getMachineNode(
+            TargetOpcode::EXTRACT_SUBREG, Dl, MVT::i1, Cmp,
+            DAG.getTargetConstant(
+                Category == ~fcNan ? PPC::sub_un : PPC::sub_eq, Dl, MVT::i32)),
+        0);
+    SDValue Result = DAG.getNOT(Dl, NanCheck, MVT::i1);
+    if (ResVT != MVT::i1)
+      Result = DAG.getZExtOrTrunc(Result, Dl, ResVT);
+    return Result;
+  }
 
-  return DAG.getNOT(Dl, NanCheck, MVT::i1);
+  // !useCRBits: i1 is not a legal type on PPC32.  Materialise the boolean
+  // result directly in ResVT (i32) without passing through i1.
+  //
+  // fcmpu/xscmpudp sets CR bits: EQ=1, UN=0 when not NaN
+  //                               EQ=0, UN=1 when NaN
+  //
+  // isNaN  (fcNan) : want 1 when unordered  =>  SELECT_CC(LHS, LHS, 1, 0, UO)
+  // !isNaN (~fcNan): want 1 when ordered    =>  SELECT_CC(LHS, LHS, 1, 0, O)
+  //
+  // LHS may be an f32 extended to f64 for the VSX path above; NaN is
+  // preserved by FP_EXTEND so using LHS here is correct for both f32 and f64.
+  ISD::CondCode CC = (Category == fcNan) ? ISD::SETUO : ISD::SETO;
+  return DAG.getSelectCC(Dl, LHS, LHS, DAG.getConstant(1, Dl, ResVT),
+                         DAG.getConstant(0, Dl, ResVT), CC);
 }
 
 // Adjust the length value for a load/store with length to account for the
diff --git a/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll b/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
new file mode 100644
index 0000000000000..0cb327c6027c2
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
@@ -0,0 +1,929 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; Test IS_FPCLASS lowering 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.  On 32-bit PPC (useCRBits=false, i64 not legal),
+; this exposed two bugs:
+;
+; (1) Crash for masks fcFinite/fcInf/fcInf|fcNan: LowerIS_FPCLASS returned
+;     SDValue() for these masks, causing ExpandNode to call expandIS_FPCLASS
+;     post-legalize.  The integer-bitcast path there produces illegal i64 nodes
+;     on PPC32, crashing with "Cannot select: i1 = is_fpclass".
+;     Fix: handle these masks in LowerIS_FPCLASS via fabs + SETCC using
+;     getSetCCResultType() for the correct legal result type (i32).
+;
+; (2) Wrong result type for masks fcNan/~fcNan at -O2: 7e1aba74 added the
+;     fcmpu/xscmpudp path for isnan/!isnan but always returned MVT::i1.
+;     On PPC32 the legal SETCC result type is i32, so the i1 return is wrong
+;     after type legalization.  Fix: zero-extend the i1 CR-bit result to ResVT.
+;     (7e1aba74's fp-classify-nan.ll has no PPC32 RUN lines, so this was
+;     silently untested.)
+;
+; (3) Crash for masks fcNan/~fcNan at -O0: at -O0 the IS_FPCLASS node is
+;     type-legalized from i1 to i32 before LowerIS_FPCLASS is called.  The
+;     previous fix emitted getNOT(..., MVT::i1) + ZExtOrTrunc, but MVT::i1 is
+;     not a legal type on PPC32 (useCRBits=false), so the intermediate i1 XOR
+;     node triggered "Unexpected illegal type" in LegalizeDAG.  At -O2 this
+;     path was never reached because the nofpexcept flag caused expandIS_FPCLASS
+;     to handle the node earlier.
+;     Fix: for !useCRBits(), avoid i1 entirely and emit SELECT_CC(x,x,1,0,UO/O)
+;     which materialises the i32 result directly via a single xscmpudp/fcmpu.
+;
+; Masks covered:
+;   504 = fcFinite    -- actual compiler-rt crash (crt_isfinite/__builtin_isfinite)
+;   516 = fcInf       -- latent crash (crt_isinf/__builtin_isinf)
+;   519 = fcInf|fcNan -- latent crash (post-legalize SimplifySetCC transform)
+;     3 = fcNan       -- wrong result type at -O2; crash at -O0 on PPC32
+;  1020 = ~fcNan      -- wrong result type at -O2; crash at -O0 on PPC32
+;
+; 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
+; RUN: llc -mtriple=powerpc-ibm-aix -mcpu=pwr7 -O0 < %s \
+; RUN:   -verify-machineinstrs -ppc-asm-full-reg-names | FileCheck %s --check-prefix=PPC32-PWR7-O0
+; RUN: llc -mtriple=powerpc-ibm-aix -mcpu=pwr8 -O0 < %s \
+; RUN:   -verify-machineinstrs -ppc-asm-full-reg-names | FileCheck %s --check-prefix=PPC32-PWR8-O0
+
+; --- fcFinite (504) - actual compiler-rt crash from crt_isfinite ---
+
+define zeroext i1 @test_isfinite_f64(double %x) nounwind {
+; PPC32-PWR7-LABEL: test_isfinite_f64:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-NEXT:    lwz r3, L..C0(r2) # %const.0
+; PPC32-PWR7-NEXT:    li r4, 1
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 0
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    isellt r3, r4, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isfinite_f64:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    lwz r3, L..C0(r2) # %const.0
+; PPC32-PWR8-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-NEXT:    li r4, 1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 0
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    isellt r3, r4, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isfinite_f64:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C0(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 29, 31, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isfinite_f64:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C0(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f64(double %x, i32 504)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isfinite_f32(float %x) nounwind {
+; PPC32-PWR7-LABEL: test_isfinite_f32:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-NEXT:    lwz r3, L..C1(r2) # %const.0
+; PPC32-PWR7-NEXT:    li r4, 1
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 0
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    isellt r3, r4, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isfinite_f32:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    lwz r3, L..C1(r2) # %const.0
+; PPC32-PWR8-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-NEXT:    li r4, 1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 0
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    isellt r3, r4, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isfinite_f32:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C1(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    fcmpu cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 29, 31, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isfinite_f32:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C1(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f32(float %x, i32 504)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isfinite_f64_strict(double %x) strictfp {
+; PPC32-PWR7-LABEL: test_isfinite_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:    li r4, 1
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 0
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    isellt r3, r4, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isfinite_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:    li r4, 1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 0
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    isellt r3, r4, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isfinite_f64_strict:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C2(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 29, 31, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isfinite_f64_strict:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C2(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f64(double %x, i32 504)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isfinite_f32_strict(float %x) strictfp {
+; PPC32-PWR7-LABEL: test_isfinite_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:    li r4, 1
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 0
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    isellt r3, r4, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isfinite_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:    li r4, 1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 0
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    isellt r3, r4, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isfinite_f32_strict:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C3(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    fcmpu cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 29, 31, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isfinite_f32_strict:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C3(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f32(float %x, i32 504)
+  ret i1 %result
+}
+
+; --- fcInf (516) - latent crash from crt_isinf/__builtin_isinf ---
+
+define zeroext i1 @test_isinf_f64(double %x) nounwind {
+; PPC32-PWR7-LABEL: test_isinf_f64:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-NEXT:    lwz r3, L..C4(r2) # %const.0
+; PPC32-PWR7-NEXT:    li r4, 1
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 0
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    iseleq r3, r4, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isinf_f64:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    lwz r3, L..C4(r2) # %const.0
+; PPC32-PWR8-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-NEXT:    li r4, 1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 0
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    iseleq r3, r4, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isinf_f64:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C4(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 31, 31, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isinf_f64:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C4(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, eq
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f64(double %x, i32 516)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isinf_f32(float %x) nounwind {
+; PPC32-PWR7-LABEL: test_isinf_f32:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-NEXT:    lwz r3, L..C5(r2) # %const.0
+; PPC32-PWR7-NEXT:    li r4, 1
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 0
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    iseleq r3, r4, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isinf_f32:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    lwz r3, L..C5(r2) # %const.0
+; PPC32-PWR8-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-NEXT:    li r4, 1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 0
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    iseleq r3, r4, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isinf_f32:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C5(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    fcmpu cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 31, 31, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isinf_f32:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C5(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, eq
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f32(float %x, i32 516)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isinf_f64_strict(double %x) strictfp {
+; PPC32-PWR7-LABEL: test_isinf_f64_strict:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-NEXT:    lwz r3, L..C6(r2) # %const.0
+; PPC32-PWR7-NEXT:    li r4, 1
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 0
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    iseleq r3, r4, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isinf_f64_strict:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    lwz r3, L..C6(r2) # %const.0
+; PPC32-PWR8-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-NEXT:    li r4, 1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 0
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    iseleq r3, r4, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isinf_f64_strict:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C6(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 31, 31, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isinf_f64_strict:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C6(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, eq
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f64(double %x, i32 516)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isinf_f32_strict(float %x) strictfp {
+; PPC32-PWR7-LABEL: test_isinf_f32_strict:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-NEXT:    lwz r3, L..C7(r2) # %const.0
+; PPC32-PWR7-NEXT:    li r4, 1
+; PPC32-PWR7-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-NEXT:    li r3, 0
+; PPC32-PWR7-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR7-NEXT:    iseleq r3, r4, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isinf_f32_strict:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    lwz r3, L..C7(r2) # %const.0
+; PPC32-PWR8-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-NEXT:    li r4, 1
+; PPC32-PWR8-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-NEXT:    li r3, 0
+; PPC32-PWR8-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-NEXT:    iseleq r3, r4, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isinf_f32_strict:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C7(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    fcmpu cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 31, 31, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isinf_f32_strict:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C7(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, eq
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f32(float %x, i32 516)
+  ret i1 %result
+}
+
+; --- fcInf|fcNan (519) - latent crash from post-legalize SimplifySetCC ---
+
+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..C8(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..C8(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
+;
+; PPC32-PWR7-O0-LABEL: test_not_finite_f64:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C8(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 29, 31, 31
+; PPC32-PWR7-O0-NEXT:    xori r3, r3, 1
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_not_finite_f64:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C8(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, lt
+; PPC32-PWR8-O0-NEXT:    li r4, 1
+; PPC32-PWR8-O0-NEXT:    li r3, 0
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-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..C9(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..C9(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
+;
+; PPC32-PWR7-O0-LABEL: test_not_finite_f32:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C9(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    fcmpu cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 29, 31, 31
+; PPC32-PWR7-O0-NEXT:    xori r3, r3, 1
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_not_finite_f32:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C9(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, lt
+; PPC32-PWR8-O0-NEXT:    li r4, 1
+; PPC32-PWR8-O0-NEXT:    li r3, 0
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f32(float %x, i32 519)
+  ret i1 %result
+}
+
+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..C10(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..C10(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
+;
+; PPC32-PWR7-O0-LABEL: test_not_finite_f64_strict:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C10(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 29, 31, 31
+; PPC32-PWR7-O0-NEXT:    xori r3, r3, 1
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_not_finite_f64_strict:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C10(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, lt
+; PPC32-PWR8-O0-NEXT:    li r4, 1
+; PPC32-PWR8-O0-NEXT:    li r3, 0
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-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..C11(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..C11(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
+;
+; PPC32-PWR7-O0-LABEL: test_not_finite_f32_strict:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR7-O0-NEXT:    lwz r3, L..C11(r2) # %const.0
+; PPC32-PWR7-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR7-O0-NEXT:    fcmpu cr7, f0, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    rlwinm r3, r3, 29, 31, 31
+; PPC32-PWR7-O0-NEXT:    xori r3, r3, 1
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_not_finite_f32_strict:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xsabsdp f0, f1
+; PPC32-PWR8-O0-NEXT:    lwz r3, L..C11(r2) # %const.0
+; PPC32-PWR8-O0-NEXT:    lfs f1, 0(r3)
+; PPC32-PWR8-O0-NEXT:    fcmpu cr0, f0, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, lt
+; PPC32-PWR8-O0-NEXT:    li r4, 1
+; PPC32-PWR8-O0-NEXT:    li r3, 0
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-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)
+
+; --- fcNan (3) / ~fcNan (1020) at -O0 on PPC32 - illegal i1 crash (bug 3) ---
+;
+; At -O0 the IS_FPCLASS node is type-legalized from i1 to i32 before
+; LowerIS_FPCLASS is called.  The fix emits SELECT_CC(x,x,1,0,SETUO/SETO)
+; which materialises i32 directly via xscmpudp/fcmpu + isel, never touching
+; the illegal i1 type.  These functions use nounwind (not strictfp) so that
+; llc -O0 exercises the type-legalization path that was crashing.
+
+define zeroext i1 @test_isnan_f64_O0(double %x) nounwind {
+; PPC32-PWR7-LABEL: test_isnan_f64_O0:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    iseleq r3, 0, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isnan_f64_O0:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    iseleq r3, 0, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isnan_f64_O0:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f1, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    clrlwi r3, r3, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isnan_f64_O0:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, eq
+; PPC32-PWR8-O0-NEXT:    crnot 4*cr5+lt, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f64(double %x, i32 3)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isnan_f32_O0(float %x) nounwind {
+; PPC32-PWR7-LABEL: test_isnan_f32_O0:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    iseleq r3, 0, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isnan_f32_O0:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    iseleq r3, 0, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isnan_f32_O0:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f1, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    clrlwi r3, r3, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isnan_f32_O0:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, eq
+; PPC32-PWR8-O0-NEXT:    crnot 4*cr5+lt, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f32(float %x, i32 3)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isnotnan_f64_O0(double %x) nounwind {
+; PPC32-PWR7-LABEL: test_isnotnan_f64_O0:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    isel r3, 0, r3, un
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isnotnan_f64_O0:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    isel r3, 0, r3, un
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isnotnan_f64_O0:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f1, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    clrlwi r3, r3, 31
+; PPC32-PWR7-O0-NEXT:    xori r3, r3, 1
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isnotnan_f64_O0:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, un
+; PPC32-PWR8-O0-NEXT:    crnot 4*cr5+lt, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f64(double %x, i32 1020)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isnotnan_f32_O0(float %x) nounwind {
+; PPC32-PWR7-LABEL: test_isnotnan_f32_O0:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    isel r3, 0, r3, un
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isnotnan_f32_O0:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    isel r3, 0, r3, un
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isnotnan_f32_O0:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f1, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    clrlwi r3, r3, 31
+; PPC32-PWR7-O0-NEXT:    xori r3, r3, 1
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isnotnan_f32_O0:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, un
+; PPC32-PWR8-O0-NEXT:    crnot 4*cr5+lt, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f32(float %x, i32 1020)
+  ret i1 %result
+}
+
+; --- fcNan (3) / ~fcNan (1020) on PPC32 - latent result-type bug from 7e1aba74 ---
+;
+; 7e1aba74 added the fcmpu/xscmpudp path for fcNan/~fcNan but always returned
+; MVT::i1 from LowerIS_FPCLASS.  On PPC32 (useCRBits=false) the legal SETCC
+; result type is i32, so returning i1 would produce an illegal type after type
+; legalization.  The fix zero-extends the i1 CR-bit result to ResVT (i32).
+; 7e1aba74's own fp-classify-nan.ll test has no PPC32 RUN lines, so this was
+; silently untested.  These cases exercise the ZExtOrTrunc fix.
+
+define zeroext i1 @test_isnan_f64(double %x) strictfp {
+; PPC32-PWR7-LABEL: test_isnan_f64:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    iseleq r3, 0, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isnan_f64:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    iseleq r3, 0, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isnan_f64:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f1, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    clrlwi r3, r3, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isnan_f64:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, eq
+; PPC32-PWR8-O0-NEXT:    crnot 4*cr5+lt, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f64(double %x, i32 3)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isnan_f32(float %x) strictfp {
+; PPC32-PWR7-LABEL: test_isnan_f32:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    iseleq r3, 0, r3
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isnan_f32:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    iseleq r3, 0, r3
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isnan_f32:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f1, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    clrlwi r3, r3, 31
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isnan_f32:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, eq
+; PPC32-PWR8-O0-NEXT:    crnot 4*cr5+lt, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f32(float %x, i32 3)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isnotnan_f64(double %x) strictfp {
+; PPC32-PWR7-LABEL: test_isnotnan_f64:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    isel r3, 0, r3, un
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isnotnan_f64:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    isel r3, 0, r3, un
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isnotnan_f64:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f1, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    clrlwi r3, r3, 31
+; PPC32-PWR7-O0-NEXT:    xori r3, r3, 1
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isnotnan_f64:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, un
+; PPC32-PWR8-O0-NEXT:    crnot 4*cr5+lt, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f64(double %x, i32 1020)
+  ret i1 %result
+}
+
+define zeroext i1 @test_isnotnan_f32(float %x) strictfp {
+; PPC32-PWR7-LABEL: test_isnotnan_f32:
+; PPC32-PWR7:       # %bb.0:
+; PPC32-PWR7-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR7-NEXT:    li r3, 1
+; PPC32-PWR7-NEXT:    isel r3, 0, r3, un
+; PPC32-PWR7-NEXT:    blr
+;
+; PPC32-PWR8-LABEL: test_isnotnan_f32:
+; PPC32-PWR8:       # %bb.0:
+; PPC32-PWR8-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-NEXT:    li r3, 1
+; PPC32-PWR8-NEXT:    isel r3, 0, r3, un
+; PPC32-PWR8-NEXT:    blr
+;
+; PPC32-PWR7-O0-LABEL: test_isnotnan_f32:
+; PPC32-PWR7-O0:       # %bb.0:
+; PPC32-PWR7-O0-NEXT:    xscmpudp cr7, f1, f1
+; PPC32-PWR7-O0-NEXT:    mfocrf r3, 1
+; PPC32-PWR7-O0-NEXT:    clrlwi r3, r3, 31
+; PPC32-PWR7-O0-NEXT:    xori r3, r3, 1
+; PPC32-PWR7-O0-NEXT:    blr
+;
+; PPC32-PWR8-O0-LABEL: test_isnotnan_f32:
+; PPC32-PWR8-O0:       # %bb.0:
+; PPC32-PWR8-O0-NEXT:    xscmpudp cr0, f1, f1
+; PPC32-PWR8-O0-NEXT:    crmove 4*cr5+lt, un
+; PPC32-PWR8-O0-NEXT:    crnot 4*cr5+lt, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    li r4, 0
+; PPC32-PWR8-O0-NEXT:    li r3, 1
+; PPC32-PWR8-O0-NEXT:    isel r3, r3, r4, 4*cr5+lt
+; PPC32-PWR8-O0-NEXT:    blr
+  %result = call i1 @llvm.is.fpclass.f32(float %x, i32 1020)
+  ret i1 %result
+}



More information about the llvm-commits mailing list