From: Stefan Schulze Frielinghaus Date: Fri, 24 Jan 2025 11:53:44 +0000 (+0100) Subject: s390: Implement isfinite and isnormal optabs X-Git-Tag: basepoints/gcc-16~2377 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b00bd29286345cc90afc61dcb16d1fa44976dae6;p=thirdparty%2Fgcc.git s390: Implement isfinite and isnormal optabs Merge new optabs with the existing implementations for signbit and isinf. gcc/ChangeLog: * config/s390/s390.h (S390_TDC_POSITIVE_ZERO): Remove. (S390_TDC_NEGATIVE_ZERO): Remove. (S390_TDC_POSITIVE_NORMALIZED_BFP_NUMBER): Remove. (S390_TDC_NEGATIVE_NORMALIZED_BFP_NUMBER): Remove. (S390_TDC_POSITIVE_DENORMALIZED_BFP_NUMBER): Remove. (S390_TDC_NEGATIVE_DENORMALIZED_BFP_NUMBER): Remove. (S390_TDC_POSITIVE_INFINITY): Remove. (S390_TDC_NEGATIVE_INFINITY): Remove. (S390_TDC_POSITIVE_QUIET_NAN): Remove. (S390_TDC_NEGATIVE_QUIET_NAN): Remove. (S390_TDC_POSITIVE_SIGNALING_NAN): Remove. (S390_TDC_NEGATIVE_SIGNALING_NAN): Remove. (S390_TDC_POSITIVE_DENORMALIZED_DFP_NUMBER): Remove. (S390_TDC_NEGATIVE_DENORMALIZED_DFP_NUMBER): Remove. (S390_TDC_POSITIVE_NORMALIZED_DFP_NUMBER): Remove. (S390_TDC_NEGATIVE_NORMALIZED_DFP_NUMBER): Remove. (S390_TDC_SIGNBIT_SET): Remove. (S390_TDC_INFINITY): Remove. * config/s390/s390.md (signbit2): Merge this one (isinf2): and this one into (2): new expander. (isnormal2): New BFP expander. (isnormal2): New DFP expander. * config/s390/vector.md (signbittf2_vr): Merge this one (isinftf2_vr): and this one into (tf2_vr): new expander. (signbittf2): Merge this one (isinftf2): and this one into (tf2): new expander. gcc/testsuite/ChangeLog: * gcc.target/s390/isfinite-isinf-isnormal-signbit-1.c: New test. * gcc.target/s390/isfinite-isinf-isnormal-signbit-2.c: New test. * gcc.target/s390/isfinite-isinf-isnormal-signbit-3.c: New test. * gcc.target/s390/isfinite-isinf-isnormal-signbit.h: New test. --- diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h index 957877b6a38..6f7195db04e 100644 --- a/gcc/config/s390/s390.h +++ b/gcc/config/s390/s390.h @@ -305,37 +305,6 @@ extern const char *s390_host_detect_local_cpu (int argc, const char **argv); "%{!mesa:%{!mzarch:%{m31:-mesa}%{m64:-mzarch}}}", \ "%{!march=*:-march=z900}" -/* Constants needed to control the TEST DATA CLASS (TDC) instruction. */ -#define S390_TDC_POSITIVE_ZERO (1 << 11) -#define S390_TDC_NEGATIVE_ZERO (1 << 10) -#define S390_TDC_POSITIVE_NORMALIZED_BFP_NUMBER (1 << 9) -#define S390_TDC_NEGATIVE_NORMALIZED_BFP_NUMBER (1 << 8) -#define S390_TDC_POSITIVE_DENORMALIZED_BFP_NUMBER (1 << 7) -#define S390_TDC_NEGATIVE_DENORMALIZED_BFP_NUMBER (1 << 6) -#define S390_TDC_POSITIVE_INFINITY (1 << 5) -#define S390_TDC_NEGATIVE_INFINITY (1 << 4) -#define S390_TDC_POSITIVE_QUIET_NAN (1 << 3) -#define S390_TDC_NEGATIVE_QUIET_NAN (1 << 2) -#define S390_TDC_POSITIVE_SIGNALING_NAN (1 << 1) -#define S390_TDC_NEGATIVE_SIGNALING_NAN (1 << 0) - -/* The following values are different for DFP. */ -#define S390_TDC_POSITIVE_DENORMALIZED_DFP_NUMBER (1 << 9) -#define S390_TDC_NEGATIVE_DENORMALIZED_DFP_NUMBER (1 << 8) -#define S390_TDC_POSITIVE_NORMALIZED_DFP_NUMBER (1 << 7) -#define S390_TDC_NEGATIVE_NORMALIZED_DFP_NUMBER (1 << 6) - -/* For signbit, the BFP-DFP-difference makes no difference. */ -#define S390_TDC_SIGNBIT_SET (S390_TDC_NEGATIVE_ZERO \ - | S390_TDC_NEGATIVE_NORMALIZED_BFP_NUMBER \ - | S390_TDC_NEGATIVE_DENORMALIZED_BFP_NUMBER\ - | S390_TDC_NEGATIVE_INFINITY \ - | S390_TDC_NEGATIVE_QUIET_NAN \ - | S390_TDC_NEGATIVE_SIGNALING_NAN ) - -#define S390_TDC_INFINITY (S390_TDC_POSITIVE_INFINITY \ - | S390_TDC_NEGATIVE_INFINITY ) - /* Target machine storage layout. */ /* Everything is big-endian. */ diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index 8ce93a04873..c164ea72c78 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -441,6 +441,81 @@ (define_constants [(TBEGIN_MASK 65292)]) ; 0xff0c (define_constants [(TBEGINC_MASK 65288)]) ; 0xff08 +;; TEST DATA CLASS + +; Data class bitmap: +; +; positive zero 11 +; negative zero 10 +; positive normalized bfp number 9 +; negative normalized bfp number 8 +; positive denormalized bfp number 7 +; negative denormalized bfp number 6 +; positive infinity 5 +; negative infinity 4 +; positive quiet nan 3 +; negative quiet nan 2 +; positive signaling nan 1 +; negative signaling nan 0 +; +; The following values are different for DFP: +; +; positive denormalized dfp number 9 +; negative denormalized dfp number 8 +; positive normalized dfp number 7 +; negative normalized dfp number 6 + +; For signbit, the BFP-DFP-difference makes no difference. +; S390_TDC_SIGNBIT_SET = negative_zero +; | negative_normalized_bfp_number +; | negative_denormalized_bfp_number +; | negative_infinity +; | negative_quiet_nan +; | negative_signaling_nan +; = 1365 +; +; For finite, the BFP-DFP-difference makes no difference. +; S390_TDC_FINITE = positive_zero +; | negative_zero +; | positive_normalized_bfp_number +; | negative_normalized_bfp_number +; | positive_denormalized_bfp_number +; | negative_denormalized_bfp_number +; = 4032 +; +; S390_TDC_INFINITY = positive_infinity +; | negative_infinity +; = 48 +; +; S390_TDC_NORMAL_BFP = positive_normalized_bfp_number +; | negative_normalized_bfp_number +; = 768 +; +; S390_TDC_NORMAL_DFP = positive_normalized_dfp_number +; | negative_normalized_dfp_number +; = 192 + +(define_constants [(S390_TDC_SIGNBIT_SET 1365) + (S390_TDC_FINITE 4032) + (S390_TDC_INFINITY 48) + (S390_TDC_NORMAL_BFP 768) + (S390_TDC_NORMAL_DFP 192)]) + +(define_int_iterator TDC_CLASS [S390_TDC_SIGNBIT_SET + S390_TDC_FINITE + S390_TDC_INFINITY]) + +(define_int_iterator TDC_CLASS_BFP [S390_TDC_SIGNBIT_SET + S390_TDC_FINITE + S390_TDC_INFINITY + S390_TDC_NORMAL_BFP]) + +(define_int_attr tdc_insn [(S390_TDC_SIGNBIT_SET "signbit") + (S390_TDC_FINITE "isfinite") + (S390_TDC_INFINITY "isinf") + (S390_TDC_NORMAL_BFP "isnormal") + (S390_TDC_NORMAL_DFP "isnormal")]) + ;; Instruction operand type as used in the Principles of Operation. ;; Used to determine defaults for length and other attribute values. @@ -3670,29 +3745,32 @@ ; Test data class. ; -(define_expand "signbit2" +(define_expand "2" [(set (reg:CCZ CC_REGNUM) - (unspec:CCZ [(match_operand:FP_ALL 1 "register_operand" "f") - (match_dup 2)] - UNSPEC_TDC_INSN)) + (unspec:CCZ [(match_operand:FP_ALL 1 "register_operand" "f") + (const_int TDC_CLASS)] + UNSPEC_TDC_INSN)) (set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CC_TO_INT))] - "TARGET_HARD_FLOAT" -{ - operands[2] = GEN_INT (S390_TDC_SIGNBIT_SET); -}) + (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CC_TO_INT))] + "TARGET_HARD_FLOAT") -(define_expand "isinf2" +(define_expand "isnormal2" [(set (reg:CCZ CC_REGNUM) - (unspec:CCZ [(match_operand:FP_ALL 1 "register_operand" "f") - (match_dup 2)] - UNSPEC_TDC_INSN)) + (unspec:CCZ [(match_operand:BFP 1 "register_operand" "f") + (const_int S390_TDC_NORMAL_BFP)] + UNSPEC_TDC_INSN)) (set (match_operand:SI 0 "register_operand" "=d") - (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CC_TO_INT))] - "TARGET_HARD_FLOAT" -{ - operands[2] = GEN_INT (S390_TDC_INFINITY); -}) + (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CC_TO_INT))] + "TARGET_HARD_FLOAT") + +(define_expand "isnormal2" + [(set (reg:CCZ CC_REGNUM) + (unspec:CCZ [(match_operand:DFP_ALL 1 "register_operand" "f") + (const_int S390_TDC_NORMAL_DFP)] + UNSPEC_TDC_INSN)) + (set (match_operand:SI 0 "register_operand" "=d") + (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CC_TO_INT))] + "TARGET_HARD_DFP") ; This extracts CC into a GPR properly shifted. The actual IPM ; instruction will be issued by reload. The constraint of operand 1 diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md index 7247e89807c..547e6a28281 100644 --- a/gcc/config/s390/vector.md +++ b/gcc/config/s390/vector.md @@ -3238,11 +3238,11 @@ ; test data class -(define_expand "signbittf2_vr" +(define_expand "tf2_vr" [(parallel [(set (reg:CCRAW CC_REGNUM) (unspec:CCRAW [(match_operand:TF 1 "register_operand" "") - (match_dup 2)] + (const_int TDC_CLASS_BFP)] UNSPEC_VEC_VFTCICC)) (clobber (scratch:TI))]) (set (match_operand:SI 0 "register_operand" "") @@ -3251,40 +3251,14 @@ (if_then_else:SI (eq (reg:CCRAW CC_REGNUM) (const_int 8)) (const_int 1) (match_dup 0)))] - "TARGET_VXE" -{ - operands[2] = GEN_INT (S390_TDC_SIGNBIT_SET); -}) - -(define_expand "signbittf2" - [(match_operand:SI 0 "register_operand" "") - (match_operand:TF 1 "register_operand" "")] - "HAVE_TF (signbittf2)" - { EXPAND_TF (signbittf2, 2); }) - -(define_expand "isinftf2_vr" - [(parallel - [(set (reg:CCRAW CC_REGNUM) - (unspec:CCRAW [(match_operand:TF 1 "register_operand" "") - (match_dup 2)] - UNSPEC_VEC_VFTCICC)) - (clobber (scratch:TI))]) - (set (match_operand:SI 0 "register_operand" "") - (const_int 0)) - (set (match_dup 0) - (if_then_else:SI (eq (reg:CCRAW CC_REGNUM) (const_int 8)) - (const_int 1) - (match_dup 0)))] - "TARGET_VXE" -{ - operands[2] = GEN_INT (S390_TDC_INFINITY); -}) + "TARGET_VXE") -(define_expand "isinftf2" +(define_expand "tf2" [(match_operand:SI 0 "register_operand" "") - (match_operand:TF 1 "register_operand" "")] - "HAVE_TF (isinftf2)" - { EXPAND_TF (isinftf2, 2); }) + (match_operand:TF 1 "register_operand" "") + (const_int TDC_CLASS_BFP)] + "HAVE_TF (tf2)" + { EXPAND_TF (tf2, 2); }) ; ; Vector byte swap patterns diff --git a/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-1.c b/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-1.c new file mode 100644 index 00000000000..a832036c88d --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-1.c @@ -0,0 +1,62 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=z9-ec -mzarch" } */ + +#define SIGNBIT(T) \ + int signbit_##T (T x) { return __builtin_signbit (x); } + +SIGNBIT (float) +/* { dg-final { scan-assembler-times {tceb\t%f[0-9]+,1365} 1 } } */ + +SIGNBIT (double) +/* { dg-final { scan-assembler-times {tcdb\t%f[0-9]+,1365} 1 } } */ + +SIGNBIT (_Decimal32) +/* { dg-final { scan-assembler-times {tdcet\t%f[0-9]+,1365} 1 } } */ + +SIGNBIT (_Decimal64) +/* { dg-final { scan-assembler-times {tdcdt\t%f[0-9]+,1365} 1 } } */ + +#define ISFINITE(T) \ + int isfinite_##T (T x) { return __builtin_isfinite (x); } + +ISFINITE (float) +/* { dg-final { scan-assembler-times {tceb\t%f[0-9]+,4032} 1 } } */ + +ISFINITE (double) +/* { dg-final { scan-assembler-times {tcdb\t%f[0-9]+,4032} 1 } } */ + +ISFINITE (_Decimal32) +/* { dg-final { scan-assembler-times {tdcet\t%f[0-9]+,4032} 1 } } */ + +ISFINITE (_Decimal64) +/* { dg-final { scan-assembler-times {tdcdt\t%f[0-9]+,4032} 1 } } */ + +#define ISINF(T) \ + int isinf_##T (T x) { return __builtin_isinf (x); } + +ISINF (float) +/* { dg-final { scan-assembler-times {tceb\t%f[0-9]+,48} 1 } } */ + +ISINF (double) +/* { dg-final { scan-assembler-times {tcdb\t%f[0-9]+,48} 1 } } */ + +ISINF (_Decimal32) +/* { dg-final { scan-assembler-times {tdcet\t%f[0-9]+,48} 1 } } */ + +ISINF (_Decimal64) +/* { dg-final { scan-assembler-times {tdcdt\t%f[0-9]+,48} 1 } } */ + +#define ISNORMAL(T) \ + int isnormal_##T (T x) { return __builtin_isnormal (x); } + +ISNORMAL (float) +/* { dg-final { scan-assembler-times {tceb\t%f[0-9]+,768} 1 } } */ + +ISNORMAL (double) +/* { dg-final { scan-assembler-times {tcdb\t%f[0-9]+,768} 1 } } */ + +ISNORMAL (_Decimal32) +/* { dg-final { scan-assembler-times {tdcet\t%f[0-9]+,192} 1 } } */ + +ISNORMAL (_Decimal64) +/* { dg-final { scan-assembler-times {tdcdt\t%f[0-9]+,192} 1 } } */ diff --git a/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-2.c b/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-2.c new file mode 100644 index 00000000000..2ff5a37c0f0 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-2.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=z13 -mzarch" } */ + +#include "isfinite-isinf-isnormal-signbit.h" + +/* { dg-final { scan-assembler-times {tcxb\t%f[0-9]+,1365} 1 } } SIGNBIT long double */ +/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,1365} 1 } } SIGNBIT _Decimal128 */ +/* { dg-final { scan-assembler-times {tcxb\t%f[0-9]+,4032} 1 } } ISFINITE long double */ +/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,4032} 1 } } ISFINITE _Decimal128 */ +/* { dg-final { scan-assembler-times {tcxb\t%f[0-9]+,48} 1 } } ISINF long double */ +/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,48} 1 } } ISINF _Decimal128 */ +/* { dg-final { scan-assembler-times {tcxb\t%f[0-9]+,768} 1 } } ISNORMAL long double */ +/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,192} 1 } } ISNORMAL _Decimal128 */ diff --git a/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-3.c b/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-3.c new file mode 100644 index 00000000000..8f67553c7da --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-3.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=z14 -mzarch" } */ + +#include "isfinite-isinf-isnormal-signbit.h" + +/* { dg-final { scan-assembler-times {wftcixb\t%v[0-9]+,%v[0-9]+,1365} 1 } } */ +/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,1365} 1 } } */ +/* { dg-final { scan-assembler-times {wftcixb\t%v[0-9]+,%v[0-9]+,4032} 1 } } */ +/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,4032} 1 } } */ +/* { dg-final { scan-assembler-times {wftcixb\t%v[0-9]+,%v[0-9]+,48} 1 } } */ +/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,48} 1 } } */ +/* { dg-final { scan-assembler-times {wftcixb\t%v[0-9]+,%v[0-9]+,768} 1 } } */ +/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,192} 1 } } */ diff --git a/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit.h b/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit.h new file mode 100644 index 00000000000..9195f7c5f67 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit.h @@ -0,0 +1,23 @@ +#define SIGNBIT(T, U) \ + int signbit_##U (T x) { return __builtin_signbit (x); } + +SIGNBIT (long double, long_double) +SIGNBIT (_Decimal128, _Decimal128) + +#define ISFINITE(T, U) \ + int isfinite_##U (T x) { return __builtin_isfinite (x); } + +ISFINITE (long double, long_double) +ISFINITE (_Decimal128, _Decimal128) + +#define ISINF(T, U) \ + int isinf_##U (T x) { return __builtin_isinf (x); } + +ISINF (long double, long_double) +ISINF (_Decimal128, _Decimal128) + +#define ISNORMAL(T, U) \ + int isnormal_##U (T x) { return __builtin_isnormal (x); } + +ISNORMAL (long double, long_double) +ISNORMAL (_Decimal128, _Decimal128)