[llvm-branch-commits] [llvm] release/22.x: [SystemZ] Remove custom lowering of f16 IS_FPCLASS (#187532) (PR #187943)
https://github.com/dyung closed https://github.com/llvm/llvm-project/pull/187943 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] release/22.x: [SystemZ] Remove custom lowering of f16 IS_FPCLASS (#187532) (PR #187943)
https://github.com/dyung updated
https://github.com/llvm/llvm-project/pull/187943
>From 94411c9d56849f00ceb7fac6a4fd7d70490881b7 Mon Sep 17 00:00:00 2001
From: Dominik Steenken
Date: Sun, 22 Mar 2026 17:19:24 +0100
Subject: [PATCH] [SystemZ] Remove custom lowering of f16 IS_FPCLASS (#187532)
As pointed out in #187518 , currently, `__builtin_isnormal` returns
`true` for subnormal half precision floating point numbers on `s390x.
This is because there is a custom lowering defined which lowers an `f16`
`IS_FPCLASS` ISD node by extending the `f16` value to `f32`, and then
using SystemZ's "test data class" instruction to determine whether the
number is subnormal. However, a number that is subnormal in 16 bits of
precision will no longer be subnormal in 32 bits of precision, and so
the test always returns true, i.e. all subnormal numbers are classified
as normal.
This PR addresses this by removing the custom lowering and instead
relying on the generic expansion of `IS_FPCLASS`, which does not have
this error.
Fixes #187518 .
(cherry picked from commit 6eb5ac52ca56fd31c41a619a14093430b27132c3)
---
.../Target/SystemZ/SystemZISelLowering.cpp| 4 +-
llvm/test/CodeGen/SystemZ/is_fpclass.ll | 94 +--
2 files changed, 85 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 8f21e00983601..f9a41cbeec004 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -561,7 +561,7 @@ SystemZTargetLowering::SystemZTargetLowering(const
TargetMachine &TM,
setOperationAction(ISD::FP_ROUND, MVT::f16, LibCall);
setOperationAction(ISD::STRICT_FP_ROUND, MVT::f16, LibCall);
setOperationAction(ISD::BITCAST, MVT::i16, Custom);
-setOperationAction(ISD::IS_FPCLASS, MVT::f16, Custom);
+
for (auto Op : {ISD::FNEG, ISD::FABS, ISD::FCOPYSIGN})
setOperationAction(Op, MVT::f16, Legal);
}
@@ -7129,8 +7129,6 @@ SDValue SystemZTargetLowering::lowerIS_FPCLASS(SDValue Op,
TDCMask |= SystemZ::TDCMASK_ZERO_MINUS;
SDValue TDCMaskV = DAG.getConstant(TDCMask, DL, MVT::i64);
- if (Arg.getSimpleValueType() == MVT::f16)
-Arg = DAG.getFPExtendOrRound(Arg, SDLoc(Arg), MVT::f32);
SDValue Intr = DAG.getNode(SystemZISD::TDC, DL, ResultVT, Arg, TDCMaskV);
return getCCResult(DAG, Intr);
}
diff --git a/llvm/test/CodeGen/SystemZ/is_fpclass.ll
b/llvm/test/CodeGen/SystemZ/is_fpclass.ll
index 98b856c5737ed..8734a1464d2e0 100644
--- a/llvm/test/CodeGen/SystemZ/is_fpclass.ll
+++ b/llvm/test/CodeGen/SystemZ/is_fpclass.ll
@@ -12,16 +12,13 @@ declare i1 @llvm.is.fpclass.f128(fp128, i32)
define i1 @isnan_h(half %x) {
; CHECK-LABEL: isnan_h:
; CHECK: # %bb.0:
-; CHECK-NEXT:stmg %r14, %r15, 112(%r15)
-; CHECK-NEXT:.cfi_offset %r14, -48
-; CHECK-NEXT:.cfi_offset %r15, -40
-; CHECK-NEXT:aghi %r15, -160
-; CHECK-NEXT:.cfi_def_cfa_offset 320
-; CHECK-NEXT:brasl %r14, __extendhfsf2@PLT
-; CHECK-NEXT:tceb %f0, 15
-; CHECK-NEXT:ipm %r2
-; CHECK-NEXT:srl %r2, 28
-; CHECK-NEXT:lmg %r14, %r15, 272(%r15)
+; CHECK-NEXT:# kill: def $f0h killed $f0h def $f0d
+; CHECK-NEXT:lgdr %r0, %f0
+; CHECK-NEXT:risbg %r0, %r0, 49, 191, 16
+; CHECK-NEXT:chi %r0, 31744
+; CHECK-NEXT:ipm %r0
+; CHECK-NEXT:risbg %r2, %r0, 63, 191, 35
+; CHECK-NEXT:# kill: def $r2l killed $r2l killed $r2d
; CHECK-NEXT:br %r14
%1 = call i1 @llvm.is.fpclass.f16(half %x, i32 3) ; nan
ret i1 %1
@@ -161,3 +158,80 @@ define i1 @isnotfinite_f(float %x) {
ret i1 %1
}
+
+define i1 @isnormal_h(half %x) {
+; CHECK-LABEL: isnormal_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT:# kill: def $f0h killed $f0h def $f0d
+; CHECK-NEXT:lgdr %r0, %f0
+; CHECK-NEXT:risbg %r0, %r0, 49, 191, 16
+; CHECK-NEXT:ahi %r0, -1024
+; CHECK-NEXT:llhr %r0, %r0
+; CHECK-NEXT:chi %r0, 30720
+; CHECK-NEXT:ipm %r0
+; CHECK-NEXT:risbg %r2, %r0, 63, 191, 36
+; CHECK-NEXT:# kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass.f16(half %x, i32 264) ; 0x108 = normal
+ ret i1 %1
+}
+
+define i1 @isnormal_f(float %x) {
+; CHECK-LABEL: isnormal_f:
+; CHECK: # %bb.0:
+; CHECK-NEXT:tceb %f0, 768
+; CHECK-NEXT:ipm %r2
+; CHECK-NEXT:srl %r2, 28
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 264) ; 0x108 = normal
+ ret i1 %1
+}
+
+define i1 @isnormal_d(double %x) {
+; CHECK-LABEL: isnormal_d:
+; CHECK: # %bb.0:
+; CHECK-NEXT:tcdb %f0, 768
+; CHECK-NEXT:ipm %r2
+; CHECK-NEXT:srl %r2, 28
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 264) ; 0x108 = normal
+ ret i1 %1
+}
+
+define i1 @issubnormal_h(half %x) {
+; CHECK-LABEL: issubnormal_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT:# kill: def $f0h killed $f0h def $f0d
+; CHECK-NEXT:lgdr %r0, %f0
+; CHECK-NEXT
[llvm-branch-commits] [llvm] release/22.x: [SystemZ] Remove custom lowering of f16 IS_FPCLASS (#187532) (PR #187943)
https://github.com/uweigand approved this pull request. LGTM. Bugfix to a feature new in 22.x, so would be good to get the fix there too. (This will also help Rust, where the bug showed up initially.) https://github.com/llvm/llvm-project/pull/187943 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] release/22.x: [SystemZ] Remove custom lowering of f16 IS_FPCLASS (#187532) (PR #187943)
llvmbot wrote:
@llvm/pr-subscribers-backend-systemz
Author: None (llvmbot)
Changes
Backport 6eb5ac52ca56fd31c41a619a14093430b27132c3
Requested by: @uweigand
---
Full diff: https://github.com/llvm/llvm-project/pull/187943.diff
2 Files Affected:
- (modified) llvm/lib/Target/SystemZ/SystemZISelLowering.cpp (+1-3)
- (modified) llvm/test/CodeGen/SystemZ/is_fpclass.ll (+84-10)
``diff
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 8f21e00983601..f9a41cbeec004 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -561,7 +561,7 @@ SystemZTargetLowering::SystemZTargetLowering(const
TargetMachine &TM,
setOperationAction(ISD::FP_ROUND, MVT::f16, LibCall);
setOperationAction(ISD::STRICT_FP_ROUND, MVT::f16, LibCall);
setOperationAction(ISD::BITCAST, MVT::i16, Custom);
-setOperationAction(ISD::IS_FPCLASS, MVT::f16, Custom);
+
for (auto Op : {ISD::FNEG, ISD::FABS, ISD::FCOPYSIGN})
setOperationAction(Op, MVT::f16, Legal);
}
@@ -7129,8 +7129,6 @@ SDValue SystemZTargetLowering::lowerIS_FPCLASS(SDValue Op,
TDCMask |= SystemZ::TDCMASK_ZERO_MINUS;
SDValue TDCMaskV = DAG.getConstant(TDCMask, DL, MVT::i64);
- if (Arg.getSimpleValueType() == MVT::f16)
-Arg = DAG.getFPExtendOrRound(Arg, SDLoc(Arg), MVT::f32);
SDValue Intr = DAG.getNode(SystemZISD::TDC, DL, ResultVT, Arg, TDCMaskV);
return getCCResult(DAG, Intr);
}
diff --git a/llvm/test/CodeGen/SystemZ/is_fpclass.ll
b/llvm/test/CodeGen/SystemZ/is_fpclass.ll
index 98b856c5737ed..8734a1464d2e0 100644
--- a/llvm/test/CodeGen/SystemZ/is_fpclass.ll
+++ b/llvm/test/CodeGen/SystemZ/is_fpclass.ll
@@ -12,16 +12,13 @@ declare i1 @llvm.is.fpclass.f128(fp128, i32)
define i1 @isnan_h(half %x) {
; CHECK-LABEL: isnan_h:
; CHECK: # %bb.0:
-; CHECK-NEXT:stmg %r14, %r15, 112(%r15)
-; CHECK-NEXT:.cfi_offset %r14, -48
-; CHECK-NEXT:.cfi_offset %r15, -40
-; CHECK-NEXT:aghi %r15, -160
-; CHECK-NEXT:.cfi_def_cfa_offset 320
-; CHECK-NEXT:brasl %r14, __extendhfsf2@PLT
-; CHECK-NEXT:tceb %f0, 15
-; CHECK-NEXT:ipm %r2
-; CHECK-NEXT:srl %r2, 28
-; CHECK-NEXT:lmg %r14, %r15, 272(%r15)
+; CHECK-NEXT:# kill: def $f0h killed $f0h def $f0d
+; CHECK-NEXT:lgdr %r0, %f0
+; CHECK-NEXT:risbg %r0, %r0, 49, 191, 16
+; CHECK-NEXT:chi %r0, 31744
+; CHECK-NEXT:ipm %r0
+; CHECK-NEXT:risbg %r2, %r0, 63, 191, 35
+; CHECK-NEXT:# kill: def $r2l killed $r2l killed $r2d
; CHECK-NEXT:br %r14
%1 = call i1 @llvm.is.fpclass.f16(half %x, i32 3) ; nan
ret i1 %1
@@ -161,3 +158,80 @@ define i1 @isnotfinite_f(float %x) {
ret i1 %1
}
+
+define i1 @isnormal_h(half %x) {
+; CHECK-LABEL: isnormal_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT:# kill: def $f0h killed $f0h def $f0d
+; CHECK-NEXT:lgdr %r0, %f0
+; CHECK-NEXT:risbg %r0, %r0, 49, 191, 16
+; CHECK-NEXT:ahi %r0, -1024
+; CHECK-NEXT:llhr %r0, %r0
+; CHECK-NEXT:chi %r0, 30720
+; CHECK-NEXT:ipm %r0
+; CHECK-NEXT:risbg %r2, %r0, 63, 191, 36
+; CHECK-NEXT:# kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass.f16(half %x, i32 264) ; 0x108 = normal
+ ret i1 %1
+}
+
+define i1 @isnormal_f(float %x) {
+; CHECK-LABEL: isnormal_f:
+; CHECK: # %bb.0:
+; CHECK-NEXT:tceb %f0, 768
+; CHECK-NEXT:ipm %r2
+; CHECK-NEXT:srl %r2, 28
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 264) ; 0x108 = normal
+ ret i1 %1
+}
+
+define i1 @isnormal_d(double %x) {
+; CHECK-LABEL: isnormal_d:
+; CHECK: # %bb.0:
+; CHECK-NEXT:tcdb %f0, 768
+; CHECK-NEXT:ipm %r2
+; CHECK-NEXT:srl %r2, 28
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 264) ; 0x108 = normal
+ ret i1 %1
+}
+
+define i1 @issubnormal_h(half %x) {
+; CHECK-LABEL: issubnormal_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT:# kill: def $f0h killed $f0h def $f0d
+; CHECK-NEXT:lgdr %r0, %f0
+; CHECK-NEXT:risbg %r0, %r0, 49, 191, 16
+; CHECK-NEXT:ahi %r0, -1
+; CHECK-NEXT:clfi %r0, 1023
+; CHECK-NEXT:ipm %r0
+; CHECK-NEXT:risbg %r2, %r0, 63, 191, 36
+; CHECK-NEXT:# kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass.f16(half %x, i32 144) ; 0x90 = subnormal
+ ret i1 %1
+}
+
+define i1 @issubnormal_f(float %x) {
+; CHECK-LABEL: issubnormal_f:
+; CHECK: # %bb.0:
+; CHECK-NEXT:tceb %f0, 192
+; CHECK-NEXT:ipm %r2
+; CHECK-NEXT:srl %r2, 28
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 144) ; 0x90 = subnormal
+ ret i1 %1
+}
+
+define i1 @issubnormal_d(double %x) {
+; CHECK-LABEL: issubnormal_d:
+; CHECK: # %bb.0:
+; CHECK-NEXT:tcdb %f0, 192
+; CHECK-NEXT:ipm %r2
+; CHECK-NEXT:srl %r2, 28
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass
[llvm-branch-commits] [llvm] release/22.x: [SystemZ] Remove custom lowering of f16 IS_FPCLASS (#187532) (PR #187943)
llvmbot wrote: @uweigand What do you think about merging this PR to the release branch? https://github.com/llvm/llvm-project/pull/187943 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] release/22.x: [SystemZ] Remove custom lowering of f16 IS_FPCLASS (#187532) (PR #187943)
https://github.com/llvmbot milestoned https://github.com/llvm/llvm-project/pull/187943 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] release/22.x: [SystemZ] Remove custom lowering of f16 IS_FPCLASS (#187532) (PR #187943)
https://github.com/llvmbot created
https://github.com/llvm/llvm-project/pull/187943
Backport 6eb5ac52ca56fd31c41a619a14093430b27132c3
Requested by: @uweigand
>From 288a77bc75b43a1d5c53216c0ff2fd47cea945c2 Mon Sep 17 00:00:00 2001
From: Dominik Steenken
Date: Sun, 22 Mar 2026 17:19:24 +0100
Subject: [PATCH] [SystemZ] Remove custom lowering of f16 IS_FPCLASS (#187532)
As pointed out in #187518 , currently, `__builtin_isnormal` returns
`true` for subnormal half precision floating point numbers on `s390x.
This is because there is a custom lowering defined which lowers an `f16`
`IS_FPCLASS` ISD node by extending the `f16` value to `f32`, and then
using SystemZ's "test data class" instruction to determine whether the
number is subnormal. However, a number that is subnormal in 16 bits of
precision will no longer be subnormal in 32 bits of precision, and so
the test always returns true, i.e. all subnormal numbers are classified
as normal.
This PR addresses this by removing the custom lowering and instead
relying on the generic expansion of `IS_FPCLASS`, which does not have
this error.
Fixes #187518 .
(cherry picked from commit 6eb5ac52ca56fd31c41a619a14093430b27132c3)
---
.../Target/SystemZ/SystemZISelLowering.cpp| 4 +-
llvm/test/CodeGen/SystemZ/is_fpclass.ll | 94 +--
2 files changed, 85 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 8f21e00983601..f9a41cbeec004 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -561,7 +561,7 @@ SystemZTargetLowering::SystemZTargetLowering(const
TargetMachine &TM,
setOperationAction(ISD::FP_ROUND, MVT::f16, LibCall);
setOperationAction(ISD::STRICT_FP_ROUND, MVT::f16, LibCall);
setOperationAction(ISD::BITCAST, MVT::i16, Custom);
-setOperationAction(ISD::IS_FPCLASS, MVT::f16, Custom);
+
for (auto Op : {ISD::FNEG, ISD::FABS, ISD::FCOPYSIGN})
setOperationAction(Op, MVT::f16, Legal);
}
@@ -7129,8 +7129,6 @@ SDValue SystemZTargetLowering::lowerIS_FPCLASS(SDValue Op,
TDCMask |= SystemZ::TDCMASK_ZERO_MINUS;
SDValue TDCMaskV = DAG.getConstant(TDCMask, DL, MVT::i64);
- if (Arg.getSimpleValueType() == MVT::f16)
-Arg = DAG.getFPExtendOrRound(Arg, SDLoc(Arg), MVT::f32);
SDValue Intr = DAG.getNode(SystemZISD::TDC, DL, ResultVT, Arg, TDCMaskV);
return getCCResult(DAG, Intr);
}
diff --git a/llvm/test/CodeGen/SystemZ/is_fpclass.ll
b/llvm/test/CodeGen/SystemZ/is_fpclass.ll
index 98b856c5737ed..8734a1464d2e0 100644
--- a/llvm/test/CodeGen/SystemZ/is_fpclass.ll
+++ b/llvm/test/CodeGen/SystemZ/is_fpclass.ll
@@ -12,16 +12,13 @@ declare i1 @llvm.is.fpclass.f128(fp128, i32)
define i1 @isnan_h(half %x) {
; CHECK-LABEL: isnan_h:
; CHECK: # %bb.0:
-; CHECK-NEXT:stmg %r14, %r15, 112(%r15)
-; CHECK-NEXT:.cfi_offset %r14, -48
-; CHECK-NEXT:.cfi_offset %r15, -40
-; CHECK-NEXT:aghi %r15, -160
-; CHECK-NEXT:.cfi_def_cfa_offset 320
-; CHECK-NEXT:brasl %r14, __extendhfsf2@PLT
-; CHECK-NEXT:tceb %f0, 15
-; CHECK-NEXT:ipm %r2
-; CHECK-NEXT:srl %r2, 28
-; CHECK-NEXT:lmg %r14, %r15, 272(%r15)
+; CHECK-NEXT:# kill: def $f0h killed $f0h def $f0d
+; CHECK-NEXT:lgdr %r0, %f0
+; CHECK-NEXT:risbg %r0, %r0, 49, 191, 16
+; CHECK-NEXT:chi %r0, 31744
+; CHECK-NEXT:ipm %r0
+; CHECK-NEXT:risbg %r2, %r0, 63, 191, 35
+; CHECK-NEXT:# kill: def $r2l killed $r2l killed $r2d
; CHECK-NEXT:br %r14
%1 = call i1 @llvm.is.fpclass.f16(half %x, i32 3) ; nan
ret i1 %1
@@ -161,3 +158,80 @@ define i1 @isnotfinite_f(float %x) {
ret i1 %1
}
+
+define i1 @isnormal_h(half %x) {
+; CHECK-LABEL: isnormal_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT:# kill: def $f0h killed $f0h def $f0d
+; CHECK-NEXT:lgdr %r0, %f0
+; CHECK-NEXT:risbg %r0, %r0, 49, 191, 16
+; CHECK-NEXT:ahi %r0, -1024
+; CHECK-NEXT:llhr %r0, %r0
+; CHECK-NEXT:chi %r0, 30720
+; CHECK-NEXT:ipm %r0
+; CHECK-NEXT:risbg %r2, %r0, 63, 191, 36
+; CHECK-NEXT:# kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass.f16(half %x, i32 264) ; 0x108 = normal
+ ret i1 %1
+}
+
+define i1 @isnormal_f(float %x) {
+; CHECK-LABEL: isnormal_f:
+; CHECK: # %bb.0:
+; CHECK-NEXT:tceb %f0, 768
+; CHECK-NEXT:ipm %r2
+; CHECK-NEXT:srl %r2, 28
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 264) ; 0x108 = normal
+ ret i1 %1
+}
+
+define i1 @isnormal_d(double %x) {
+; CHECK-LABEL: isnormal_d:
+; CHECK: # %bb.0:
+; CHECK-NEXT:tcdb %f0, 768
+; CHECK-NEXT:ipm %r2
+; CHECK-NEXT:srl %r2, 28
+; CHECK-NEXT:br %r14
+ %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 264) ; 0x108 = normal
+ ret i1 %1
+}
+
+define i1 @issubnormal_h(half %x) {
+; CHECK-LABEL: issubnormal_h:
+; CHECK: # %bb.0:
+; CHECK-NEXT:# kil
