Files
llvm-project/llvm/test/CodeGen/SystemZ/is_fpclass.ll
Dominik Steenken 6eb5ac52ca [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 .
2026-03-22 17:19:24 +01:00

238 lines
6.3 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; Test intrinsic 'is_fpclass'.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
declare i1 @llvm.is.fpclass.f16(half, i32)
declare i1 @llvm.is.fpclass.f32(float, i32)
declare i1 @llvm.is.fpclass.f64(double, i32)
declare i1 @llvm.is.fpclass.f128(fp128, i32)
define i1 @isnan_h(half %x) {
; CHECK-LABEL: isnan_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: 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
}
define i1 @isnan_f(float %x) {
; CHECK-LABEL: isnan_f:
; CHECK: # %bb.0:
; CHECK-NEXT: tceb %f0, 15
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 3) ; nan
ret i1 %1
}
define i1 @isnan_d(double %x) {
; CHECK-LABEL: isnan_d:
; CHECK: # %bb.0:
; CHECK-NEXT: tcdb %f0, 15
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f64(double %x, i32 3) ; nan
ret i1 %1
}
define i1 @isnan_x(fp128 %x) {
; CHECK-LABEL: isnan_x:
; CHECK: # %bb.0:
; CHECK-NEXT: ld %f0, 0(%r2)
; CHECK-NEXT: ld %f2, 8(%r2)
; CHECK-NEXT: tcxb %f0, 15
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f128(fp128 %x, i32 3) ; nan
ret i1 %1
}
define i1 @isqnan_f(float %x) {
; CHECK-LABEL: isqnan_f:
; CHECK: # %bb.0:
; CHECK-NEXT: tceb %f0, 12
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 2) ; qnan
ret i1 %1
}
define i1 @issnan_f(float %x) {
; CHECK-LABEL: issnan_f:
; CHECK: # %bb.0:
; CHECK-NEXT: tceb %f0, 3
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 1) ; snan
ret i1 %1
}
define i1 @isinf_f(float %x) {
; CHECK-LABEL: isinf_f:
; CHECK: # %bb.0:
; CHECK-NEXT: tceb %f0, 48
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 516) ; 0x204 = "inf"
ret i1 %1
}
define i1 @isposinf_f(float %x) {
; CHECK-LABEL: isposinf_f:
; CHECK: # %bb.0:
; CHECK-NEXT: tceb %f0, 32
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 512) ; 0x200 = "+inf"
ret i1 %1
}
define i1 @isneginf_f(float %x) {
; CHECK-LABEL: isneginf_f:
; CHECK: # %bb.0:
; CHECK-NEXT: tceb %f0, 16
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 4) ; "-inf"
ret i1 %1
}
define i1 @isfinite_f(float %x) {
; CHECK-LABEL: isfinite_f:
; CHECK: # %bb.0:
; CHECK-NEXT: tceb %f0, 4032
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 504) ; 0x1f8 = "finite"
ret i1 %1
}
define i1 @isposfinite_f(float %x) {
; CHECK-LABEL: isposfinite_f:
; CHECK: # %bb.0:
; CHECK-NEXT: tceb %f0, 2688
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 448) ; 0x1c0 = "+finite"
ret i1 %1
}
define i1 @isnegfinite_f(float %x) {
; CHECK-LABEL: isnegfinite_f:
; CHECK: # %bb.0:
; CHECK-NEXT: tceb %f0, 1344
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 56) ; 0x38 = "-finite"
ret i1 %1
}
define i1 @isnotfinite_f(float %x) {
; CHECK-LABEL: isnotfinite_f:
; CHECK: # %bb.0:
; CHECK-NEXT: tceb %f0, 63
; CHECK-NEXT: ipm %r2
; CHECK-NEXT: srl %r2, 28
; CHECK-NEXT: br %r14
%1 = call i1 @llvm.is.fpclass.f32(float %x, i32 519) ; ox207 = "inf|nan"
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.f64(double %x, i32 144) ; 0x90 = subnormal
ret i1 %1
}