[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
Fri Aug 7 09:23:25 PDT 2026
https://github.com/DanielCChen updated https://github.com/llvm/llvm-project/pull/213298
>From d55cb6d31bd26897f5c18baba29b98928008fd87 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 1/7] 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 e338a08338657..bc5b6b4d861a0 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -11968,6 +11968,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 ||
@@ -11993,7 +11994,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();
}
@@ -12026,16 +12099,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
+}
>From 0c9357e44079747bfd0d85d3eeee6005c204366f Mon Sep 17 00:00:00 2001
From: Daniel Chen <cdchen at ca.ibm.com>
Date: Thu, 6 Aug 2026 15:03:03 -0400
Subject: [PATCH 2/7] To address review comments.
---
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 49 ++++++-------------
.../test/CodeGen/PowerPC/fp-classify-aix32.ll | 49 +++++--------------
2 files changed, 27 insertions(+), 71 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index bc5b6b4d861a0..9c9dadff944fa 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -12070,39 +12070,27 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
return SDValue();
}
- // Determine which comparison instruction to use based on vector support
+ // Determine which comparison instruction to use based on vector support.
+ // On VSX targets (pwr7+) use xscmpudp for both f32 and f64; extend f32 first.
+ // On non-VSX targets use fcmpu (FCMPUD for f64, FCMPUS for f32).
unsigned CmpOp;
-
if (Subtarget.hasVSX()) {
- // Use xscmpudp for VSX targets (both f32 and f64)
- // For f32, extend to f64 first
- if (VT == MVT::f32) {
+ if (VT == MVT::f32)
LHS = DAG.getNode(ISD::FP_EXTEND, Dl, MVT::f64, LHS);
- } else if (VT != MVT::f64) {
- return SDValue();
- }
CmpOp = PPC::XSCMPUDP;
} else {
- // Use fcmpu for non-VSX targets
- // FCMPUS and FCMPUD both map to the same fcmpu instruction,
- // just with different register classes (f4rc vs f8rc)
- if (VT == MVT::f64) {
- CmpOp = PPC::FCMPUD;
- } else if (VT == MVT::f32) {
- CmpOp = PPC::FCMPUS;
- } else {
- return SDValue();
- }
+ CmpOp = (VT == MVT::f64) ? PPC::FCMPUD : PPC::FCMPUS;
}
- // Create the comparison: fcmpu/xscmpudp CR, LHS, LHS
- // The CR field output will be allocated by the register allocator
+ // Create the comparison: xscmpudp/fcmpu CR, LHS, LHS
+ // The CR field output will be allocated by the register allocator.
SDValue Cmp = SDValue(DAG.getMachineNode(CmpOp, Dl, MVT::i32, LHS, LHS), 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).
+ // When useCRBits() is true, i1 is a legal CR-bit type (e.g. pwr8+).
+ // Extract the relevant CR sub-register, invert, and zero-extend to ResVT.
if (Subtarget.useCRBits()) {
+ // isNaN (fcNan) : FU bit set when unordered => extract sub_eq, then NOT
+ // !isNaN (~fcNan): EQ bit set when ordered => extract sub_un, then NOT
SDValue NanCheck = SDValue(
DAG.getMachineNode(
TargetOpcode::EXTRACT_SUBREG, Dl, MVT::i1, Cmp,
@@ -12115,17 +12103,12 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
return Result;
}
- // !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)
+ // !useCRBits: i1 is not a legal type on targets where useCRBits() is false.
+ // Materialise the boolean result directly in ResVT without passing through i1.
//
- // 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.
+ // fcmpu/xscmpudp 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)
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);
diff --git a/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll b/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
index 0cb327c6027c2..7d0e151b90311 100644
--- a/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
+++ b/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
@@ -1,42 +1,15 @@
; 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
-;
+; Test IS_FPCLASS lowering on 32-bit AIX targets (pwr7, pwr8) for the
+; following masks:
+; 504 = fcFinite (isfinite)
+; 516 = fcInf (isinf)
+; 519 = fcInf|fcNan (!isfinite)
+; 3 = fcNan (isnan)
+; 1020 = ~fcNan (!isnan)
+;
+; Covers both strictfp and non-strictfp variants at default and -O0
+; optimisation levels.
+
; 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 \
>From 20882cda49dea911d510f689fa8593d443432df2 Mon Sep 17 00:00:00 2001
From: Daniel Chen <cdchen at ca.ibm.com>
Date: Thu, 6 Aug 2026 16:32:53 -0400
Subject: [PATCH 3/7] To address review comments.
---
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 11 ++------
.../test/CodeGen/PowerPC/fp-classify-aix32.ll | 26 +++++++------------
2 files changed, 12 insertions(+), 25 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 9c9dadff944fa..d28006ad8dbdf 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -12059,13 +12059,6 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
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();
}
@@ -12103,8 +12096,8 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
return Result;
}
- // !useCRBits: i1 is not a legal type on targets where useCRBits() is false.
- // Materialise the boolean result directly in ResVT without passing through i1.
+ // !useCRBits: i1 is not a legal type. Materialise the boolean result
+ // directly in ResVT without passing through i1.
//
// fcmpu/xscmpudp 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)
diff --git a/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll b/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
index 7d0e151b90311..09c21de00eac6 100644
--- a/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
+++ b/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
@@ -19,7 +19,7 @@
; 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 ---
+; --- fcFinite (504) ---
define zeroext i1 @test_isfinite_f64(double %x) nounwind {
; PPC32-PWR7-LABEL: test_isfinite_f64:
@@ -213,7 +213,7 @@ define zeroext i1 @test_isfinite_f32_strict(float %x) strictfp {
ret i1 %result
}
-; --- fcInf (516) - latent crash from crt_isinf/__builtin_isinf ---
+; --- fcInf (516) ---
define zeroext i1 @test_isinf_f64(double %x) nounwind {
; PPC32-PWR7-LABEL: test_isinf_f64:
@@ -407,7 +407,7 @@ define zeroext i1 @test_isinf_f32_strict(float %x) strictfp {
ret i1 %result
}
-; --- fcInf|fcNan (519) - latent crash from post-legalize SimplifySetCC ---
+; --- fcInf|fcNan (519) ---
define zeroext i1 @test_not_finite_f64(double %x) nounwind {
; PPC32-PWR7-LABEL: test_not_finite_f64:
@@ -600,13 +600,11 @@ define zeroext i1 @test_not_finite_f32_strict(float %x) strictfp {
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) ---
+; --- fcNan (3) / ~fcNan (1020) at -O0 on PPC32 ---
;
; 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.
+; LowerIS_FPCLASS is called. These functions use nounwind (not strictfp) so
+; that llc -O0 exercises the type-legalization path.
define zeroext i1 @test_isnan_f64_O0(double %x) nounwind {
; PPC32-PWR7-LABEL: test_isnan_f64_O0:
@@ -750,14 +748,10 @@ define zeroext i1 @test_isnotnan_f32_O0(float %x) nounwind {
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.
+; --- fcNan (3) / ~fcNan (1020) on PPC32 with strictfp ---
+;
+; On PPC32 (useCRBits=false) the legal SETCC result type is i32. These cases
+; verify that LowerIS_FPCLASS returns the correct ResVT instead of i1.
define zeroext i1 @test_isnan_f64(double %x) strictfp {
; PPC32-PWR7-LABEL: test_isnan_f64:
>From 671956712458133c79a5c452b7ba7d91a83fc143 Mon Sep 17 00:00:00 2001
From: Daniel Chen <cdchen at ca.ibm.com>
Date: Thu, 6 Aug 2026 19:59:38 -0400
Subject: [PATCH 4/7] To reduce the scope of the fix to 64-bit only to address
Roland's review comments.
---
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 109 +--
.../test/CodeGen/PowerPC/fp-classify-aix32.ll | 896 ------------------
2 files changed, 16 insertions(+), 989 deletions(-)
delete 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 d28006ad8dbdf..eb32ae8f704ce 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -817,8 +817,10 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::FCANONICALIZE, MVT::f32, Legal);
}
- setOperationAction(ISD::IS_FPCLASS, MVT::f32, Custom);
- setOperationAction(ISD::IS_FPCLASS, MVT::f64, Custom);
+ if (Subtarget.isPPC64() || Subtarget.useCRBits()) {
+ setOperationAction(ISD::IS_FPCLASS, MVT::f32, Custom);
+ setOperationAction(ISD::IS_FPCLASS, MVT::f64, Custom);
+ }
if (Subtarget.hasAltivec()) {
for (MVT VT : { MVT::v16i8, MVT::v8i16, MVT::v4i32 }) {
@@ -11968,7 +11970,6 @@ 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 ||
@@ -11988,80 +11989,10 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
return getDataClassTest(LHS, Category, Dl, DAG, Subtarget);
}
- // For non-P9Vector targets, we can only check for NaN using fcmpu/xscmpudp
- // These instructions set CR bits based on comparison with itself:
- // - If value is NaN, the comparison is unordered (FU bit set)
- // - 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 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);
- }
+ // For non-P9Vector targets, we can only check for NaN using fcmpu/xscmpudp.
+ // Return SDValue() for all non-NaN masks to let the generic expander handle them.
+ if ((Category != fcNan) && (Category != ~fcNan))
return SDValue();
- }
// Determine which comparison instruction to use based on vector support.
// On VSX targets (pwr7+) use xscmpudp for both f32 and f64; extend f32 first.
@@ -12079,32 +12010,24 @@ 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);
- // When useCRBits() is true, i1 is a legal CR-bit type (e.g. pwr8+).
- // Extract the relevant CR sub-register, invert, and zero-extend to ResVT.
+ // When useCRBits() is true, i1 is a legal CR-bit type (pwr8+ on both
+ // 32-bit and 64-bit targets). Extract the relevant CR sub-register and
+ // invert to produce the i1 result.
if (Subtarget.useCRBits()) {
- // isNaN (fcNan) : FU bit set when unordered => extract sub_eq, then NOT
- // !isNaN (~fcNan): EQ bit set when ordered => extract sub_un, then NOT
+ // isNaN (fcNan) : EQ=0 when unordered => extract sub_eq, NOT => 1
+ // !isNaN (~fcNan): UN=0 when ordered => extract sub_un, NOT => 1
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. Materialise the boolean result
- // directly in ResVT without passing through i1.
- //
- // fcmpu/xscmpudp 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)
- 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);
+ // Only 64-bit targets without useCRBits (e.g. pwr7 64-bit) reach here.
+ // Return SDValue() to let the generic expander handle the fcNan/~fcNan masks.
+ return SDValue();
}
// 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
deleted file mode 100644
index 09c21de00eac6..0000000000000
--- a/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
+++ /dev/null
@@ -1,896 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; Test IS_FPCLASS lowering on 32-bit AIX targets (pwr7, pwr8) for the
-; following masks:
-; 504 = fcFinite (isfinite)
-; 516 = fcInf (isinf)
-; 519 = fcInf|fcNan (!isfinite)
-; 3 = fcNan (isnan)
-; 1020 = ~fcNan (!isnan)
-;
-; Covers both strictfp and non-strictfp variants at default and -O0
-; optimisation levels.
-
-; 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) ---
-
-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) ---
-
-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) ---
-
-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 ---
-;
-; At -O0 the IS_FPCLASS node is type-legalized from i1 to i32 before
-; LowerIS_FPCLASS is called. These functions use nounwind (not strictfp) so
-; that llc -O0 exercises the type-legalization path.
-
-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 with strictfp ---
-;
-; On PPC32 (useCRBits=false) the legal SETCC result type is i32. These cases
-; verify that LowerIS_FPCLASS returns the correct ResVT instead of i1.
-
-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
-}
>From 9cbab7738d10b500a5f4f7aa17c2df3d8460001b Mon Sep 17 00:00:00 2001
From: Daniel Chen <cdchen at ca.ibm.com>
Date: Fri, 7 Aug 2026 12:04:36 -0400
Subject: [PATCH 5/7] Revert "To reduce the scope of the fix to 64-bit only to
address Roland's review comments."
This reverts commit 671956712458133c79a5c452b7ba7d91a83fc143.
---
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 109 ++-
.../test/CodeGen/PowerPC/fp-classify-aix32.ll | 896 ++++++++++++++++++
2 files changed, 989 insertions(+), 16 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 eb32ae8f704ce..d28006ad8dbdf 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -817,10 +817,8 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::FCANONICALIZE, MVT::f32, Legal);
}
- if (Subtarget.isPPC64() || Subtarget.useCRBits()) {
- setOperationAction(ISD::IS_FPCLASS, MVT::f32, Custom);
- setOperationAction(ISD::IS_FPCLASS, MVT::f64, Custom);
- }
+ setOperationAction(ISD::IS_FPCLASS, MVT::f32, Custom);
+ setOperationAction(ISD::IS_FPCLASS, MVT::f64, Custom);
if (Subtarget.hasAltivec()) {
for (MVT VT : { MVT::v16i8, MVT::v8i16, MVT::v4i32 }) {
@@ -11970,6 +11968,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 ||
@@ -11989,10 +11988,80 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
return getDataClassTest(LHS, Category, Dl, DAG, Subtarget);
}
- // For non-P9Vector targets, we can only check for NaN using fcmpu/xscmpudp.
- // Return SDValue() for all non-NaN masks to let the generic expander handle them.
- if ((Category != fcNan) && (Category != ~fcNan))
+ // For non-P9Vector targets, we can only check for NaN using fcmpu/xscmpudp
+ // These instructions set CR bits based on comparison with itself:
+ // - If value is NaN, the comparison is unordered (FU bit set)
+ // - 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 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);
+ }
return SDValue();
+ }
// Determine which comparison instruction to use based on vector support.
// On VSX targets (pwr7+) use xscmpudp for both f32 and f64; extend f32 first.
@@ -12010,24 +12079,32 @@ 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);
- // When useCRBits() is true, i1 is a legal CR-bit type (pwr8+ on both
- // 32-bit and 64-bit targets). Extract the relevant CR sub-register and
- // invert to produce the i1 result.
+ // When useCRBits() is true, i1 is a legal CR-bit type (e.g. pwr8+).
+ // Extract the relevant CR sub-register, invert, and zero-extend to ResVT.
if (Subtarget.useCRBits()) {
- // isNaN (fcNan) : EQ=0 when unordered => extract sub_eq, NOT => 1
- // !isNaN (~fcNan): UN=0 when ordered => extract sub_un, NOT => 1
+ // isNaN (fcNan) : FU bit set when unordered => extract sub_eq, then NOT
+ // !isNaN (~fcNan): EQ bit set when ordered => extract sub_un, then NOT
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);
- return DAG.getNOT(Dl, NanCheck, MVT::i1);
+ SDValue Result = DAG.getNOT(Dl, NanCheck, MVT::i1);
+ if (ResVT != MVT::i1)
+ Result = DAG.getZExtOrTrunc(Result, Dl, ResVT);
+ return Result;
}
- // Only 64-bit targets without useCRBits (e.g. pwr7 64-bit) reach here.
- // Return SDValue() to let the generic expander handle the fcNan/~fcNan masks.
- return SDValue();
+ // !useCRBits: i1 is not a legal type. Materialise the boolean result
+ // directly in ResVT without passing through i1.
+ //
+ // fcmpu/xscmpudp 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)
+ 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..09c21de00eac6
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
@@ -0,0 +1,896 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; Test IS_FPCLASS lowering on 32-bit AIX targets (pwr7, pwr8) for the
+; following masks:
+; 504 = fcFinite (isfinite)
+; 516 = fcInf (isinf)
+; 519 = fcInf|fcNan (!isfinite)
+; 3 = fcNan (isnan)
+; 1020 = ~fcNan (!isnan)
+;
+; Covers both strictfp and non-strictfp variants at default and -O0
+; optimisation levels.
+
+; 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) ---
+
+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) ---
+
+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) ---
+
+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 ---
+;
+; At -O0 the IS_FPCLASS node is type-legalized from i1 to i32 before
+; LowerIS_FPCLASS is called. These functions use nounwind (not strictfp) so
+; that llc -O0 exercises the type-legalization path.
+
+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 with strictfp ---
+;
+; On PPC32 (useCRBits=false) the legal SETCC result type is i32. These cases
+; verify that LowerIS_FPCLASS returns the correct ResVT instead of i1.
+
+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
+}
>From 16d64a9d2b758571b901c2ab6b2476cb01910f9c Mon Sep 17 00:00:00 2001
From: Daniel Chen <cdchen at ca.ibm.com>
Date: Fri, 7 Aug 2026 12:04:52 -0400
Subject: [PATCH 6/7] Revert "To address review comments."
This reverts commit 20882cda49dea911d510f689fa8593d443432df2.
---
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 11 ++++++--
.../test/CodeGen/PowerPC/fp-classify-aix32.ll | 26 ++++++++++++-------
2 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index d28006ad8dbdf..9c9dadff944fa 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -12059,6 +12059,13 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
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();
}
@@ -12096,8 +12103,8 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
return Result;
}
- // !useCRBits: i1 is not a legal type. Materialise the boolean result
- // directly in ResVT without passing through i1.
+ // !useCRBits: i1 is not a legal type on targets where useCRBits() is false.
+ // Materialise the boolean result directly in ResVT without passing through i1.
//
// fcmpu/xscmpudp 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)
diff --git a/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll b/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
index 09c21de00eac6..7d0e151b90311 100644
--- a/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
+++ b/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
@@ -19,7 +19,7 @@
; 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) ---
+; --- fcFinite (504) - actual compiler-rt crash from crt_isfinite ---
define zeroext i1 @test_isfinite_f64(double %x) nounwind {
; PPC32-PWR7-LABEL: test_isfinite_f64:
@@ -213,7 +213,7 @@ define zeroext i1 @test_isfinite_f32_strict(float %x) strictfp {
ret i1 %result
}
-; --- fcInf (516) ---
+; --- fcInf (516) - latent crash from crt_isinf/__builtin_isinf ---
define zeroext i1 @test_isinf_f64(double %x) nounwind {
; PPC32-PWR7-LABEL: test_isinf_f64:
@@ -407,7 +407,7 @@ define zeroext i1 @test_isinf_f32_strict(float %x) strictfp {
ret i1 %result
}
-; --- fcInf|fcNan (519) ---
+; --- 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:
@@ -600,11 +600,13 @@ define zeroext i1 @test_not_finite_f32_strict(float %x) strictfp {
declare i1 @llvm.is.fpclass.f64(double, i32)
declare i1 @llvm.is.fpclass.f32(float, i32)
-; --- fcNan (3) / ~fcNan (1020) at -O0 on PPC32 ---
+; --- 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. These functions use nounwind (not strictfp) so
-; that llc -O0 exercises the type-legalization path.
+; 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:
@@ -748,10 +750,14 @@ define zeroext i1 @test_isnotnan_f32_O0(float %x) nounwind {
ret i1 %result
}
-; --- fcNan (3) / ~fcNan (1020) on PPC32 with strictfp ---
-;
-; On PPC32 (useCRBits=false) the legal SETCC result type is i32. These cases
-; verify that LowerIS_FPCLASS returns the correct ResVT instead of i1.
+; --- 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:
>From c0841675d893dba4a3eb6e64bb8eda272e18aeba Mon Sep 17 00:00:00 2001
From: Daniel Chen <cdchen at ca.ibm.com>
Date: Fri, 7 Aug 2026 12:05:11 -0400
Subject: [PATCH 7/7] Revert "To address review comments."
This reverts commit 0c9357e44079747bfd0d85d3eeee6005c204366f.
---
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 49 +++++++++++++------
.../test/CodeGen/PowerPC/fp-classify-aix32.ll | 49 ++++++++++++++-----
2 files changed, 71 insertions(+), 27 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 9c9dadff944fa..bc5b6b4d861a0 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -12070,27 +12070,39 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
return SDValue();
}
- // Determine which comparison instruction to use based on vector support.
- // On VSX targets (pwr7+) use xscmpudp for both f32 and f64; extend f32 first.
- // On non-VSX targets use fcmpu (FCMPUD for f64, FCMPUS for f32).
+ // Determine which comparison instruction to use based on vector support
unsigned CmpOp;
+
if (Subtarget.hasVSX()) {
- if (VT == MVT::f32)
+ // Use xscmpudp for VSX targets (both f32 and f64)
+ // For f32, extend to f64 first
+ if (VT == MVT::f32) {
LHS = DAG.getNode(ISD::FP_EXTEND, Dl, MVT::f64, LHS);
+ } else if (VT != MVT::f64) {
+ return SDValue();
+ }
CmpOp = PPC::XSCMPUDP;
} else {
- CmpOp = (VT == MVT::f64) ? PPC::FCMPUD : PPC::FCMPUS;
+ // Use fcmpu for non-VSX targets
+ // FCMPUS and FCMPUD both map to the same fcmpu instruction,
+ // just with different register classes (f4rc vs f8rc)
+ if (VT == MVT::f64) {
+ CmpOp = PPC::FCMPUD;
+ } else if (VT == MVT::f32) {
+ CmpOp = PPC::FCMPUS;
+ } else {
+ return SDValue();
+ }
}
- // Create the comparison: xscmpudp/fcmpu CR, LHS, LHS
- // The CR field output will be allocated by the register allocator.
+ // Create the comparison: fcmpu/xscmpudp CR, LHS, LHS
+ // The CR field output will be allocated by the register allocator
SDValue Cmp = SDValue(DAG.getMachineNode(CmpOp, Dl, MVT::i32, LHS, LHS), 0);
- // When useCRBits() is true, i1 is a legal CR-bit type (e.g. pwr8+).
- // Extract the relevant CR sub-register, invert, and zero-extend to ResVT.
+ // 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()) {
- // isNaN (fcNan) : FU bit set when unordered => extract sub_eq, then NOT
- // !isNaN (~fcNan): EQ bit set when ordered => extract sub_un, then NOT
SDValue NanCheck = SDValue(
DAG.getMachineNode(
TargetOpcode::EXTRACT_SUBREG, Dl, MVT::i1, Cmp,
@@ -12103,12 +12115,17 @@ SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
return Result;
}
- // !useCRBits: i1 is not a legal type on targets where useCRBits() is false.
- // Materialise the boolean result directly in ResVT without passing through 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)
//
- // fcmpu/xscmpudp 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);
diff --git a/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll b/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
index 7d0e151b90311..0cb327c6027c2 100644
--- a/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
+++ b/llvm/test/CodeGen/PowerPC/fp-classify-aix32.ll
@@ -1,15 +1,42 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; Test IS_FPCLASS lowering on 32-bit AIX targets (pwr7, pwr8) for the
-; following masks:
-; 504 = fcFinite (isfinite)
-; 516 = fcInf (isinf)
-; 519 = fcInf|fcNan (!isfinite)
-; 3 = fcNan (isnan)
-; 1020 = ~fcNan (!isnan)
-;
-; Covers both strictfp and non-strictfp variants at default and -O0
-; optimisation levels.
-
+; 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 \
More information about the llvm-commits
mailing list