https://gcc.gnu.org/g:f9af5890fbafb3f1ff514aef0805fd7c6b2d6858

commit r16-2318-gf9af5890fbafb3f1ff514aef0805fd7c6b2d6858
Author: Stefan Schulze Frielinghaus <stefa...@gcc.gnu.org>
Date:   Thu Jul 17 12:44:06 2025 +0200

    s390: Rework signbit optab
    
    Currently for a signbit operation instructions tc{f,d,x}b + ipm + srl
    are emitted.  If the source operand is a MEM, then a load precedes the
    sequence.  A faster implementation is by issuing a load either from a
    REG or MEM into a GPR followed by a shift.
    
    In spirit of the signbit function of the C standard, the signbit optab
    only guarantees that the resulting value is nonzero if the signbit is
    set.  The common code implementation computes a value where the signbit
    is stored in the most significant bit, i.e., all other bits are just
    masked out, whereas the current implementation of s390 results in a
    value where the signbit is stored in the least significant bit.
    Although, there is no guarantee where the signbit is stored, keep the
    current behaviour and, therefore, implement the signbit optab manually.
    
    Since z10, instruction lgdr can be effectively used for a 64-bit
    FPR-to-GPR load.  However, there exists no 32-bit pendant.  Thus, for
    target z10 make use of post-reload splitters which emit either a 64-bit
    or a 32-bit load depending on whether the source operand is a REG or a
    MEM and a corresponding 63 or 31-bit shift.  We can do without
    post-reload splitter in case of vector extensions since there we also
    have a 32-bit VR-to-GPR load via instruction vlgvf.
    
    gcc/ChangeLog:
    
            * config/s390/s390.md (signbit_tdc): Rename expander.
            (signbit<mode>2): New expander.
            (signbit<mode>2_z10): New expander.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/s390/isfinite-isinf-isnormal-signbit-2.c: Adapt
            scan assembler directives.
            * gcc.target/s390/isfinite-isinf-isnormal-signbit-3.c: Ditto.
            * gcc.target/s390/signbit-1.c: New test.
            * gcc.target/s390/signbit-2.c: New test.
            * gcc.target/s390/signbit-3.c: New test.
            * gcc.target/s390/signbit-4.c: New test.
            * gcc.target/s390/signbit-5.c: New test.
            * gcc.target/s390/signbit.h: New test.

Diff:
---
 gcc/config/s390/s390.md                            |  83 ++++++++++-
 .../s390/isfinite-isinf-isnormal-signbit-2.c       |   6 +-
 .../s390/isfinite-isinf-isnormal-signbit-3.c       |   6 +-
 gcc/testsuite/gcc.target/s390/signbit-1.c          |  40 ++++++
 gcc/testsuite/gcc.target/s390/signbit-2.c          |  40 ++++++
 gcc/testsuite/gcc.target/s390/signbit-3.c          | 152 +++++++++++++++++++++
 gcc/testsuite/gcc.target/s390/signbit-4.c          |  55 ++++++++
 gcc/testsuite/gcc.target/s390/signbit-5.c          |  35 +++++
 gcc/testsuite/gcc.target/s390/signbit.h            |  36 +++++
 9 files changed, 448 insertions(+), 5 deletions(-)

diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 02bc149b0fba..1edbfde4a981 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -121,6 +121,7 @@
 
    ; Test Data Class (TDC)
    UNSPEC_TDC_INSN
+   UNSPEC_SIGNBIT
 
    ; Byte-wise Population Count
    UNSPEC_POPCNT
@@ -513,7 +514,7 @@
                                    S390_TDC_INFINITY
                                    S390_TDC_NORMAL_BFP])
 
-(define_int_attr tdc_insn [(S390_TDC_SIGNBIT_SET "signbit")
+(define_int_attr tdc_insn [(S390_TDC_SIGNBIT_SET "signbit_tdc")
                           (S390_TDC_FINITE "isfinite")
                           (S390_TDC_INFINITY "isinf")
                           (S390_TDC_NORMAL_BFP "isnormal")
@@ -3782,6 +3783,86 @@
        (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CC_TO_INT))]
   "TARGET_HARD_DFP")
 
+(define_mode_iterator SIGNBIT_SINGLE [(SF "TARGET_HARD_FLOAT")
+                                     (SD "TARGET_HARD_DFP")])
+(define_expand "signbit<mode>2"
+  [(match_operand:SI 0 "register_operand")
+   (match_operand:SIGNBIT_SINGLE 1 "nonimmediate_operand")]
+  ""
+{
+  if (TARGET_VX && TARGET_64BIT)
+    {
+      emit_insn (gen_rtx_SET (operands[0], simplify_gen_subreg (SImode, 
operands[1], <MODE>mode, 0)));
+      emit_insn (gen_rtx_SET (operands[0], gen_rtx_LSHIFTRT (SImode, 
operands[0], GEN_INT (31))));
+    }
+  else if (TARGET_Z10 && TARGET_64BIT)
+    emit_insn (gen_signbit<mode>2_z10 (operands[0], operands[1]));
+  else
+    emit_insn (gen_signbit_tdc<mode>2 (operands[0], force_reg (<MODE>mode, 
operands[1])));
+  DONE;
+})
+
+(define_insn "signbit<mode>2_z10"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+       (unspec:SI [(match_operand:SIGNBIT_SINGLE 1 "nonimmediate_operand" 
"fRT")]
+                  UNSPEC_SIGNBIT))]
+  "TARGET_Z10 && TARGET_64BIT"
+  "#")
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand")
+       (unspec:SI [(match_operand:SIGNBIT_SINGLE 1 "register_operand")]
+                  UNSPEC_SIGNBIT))]
+  "TARGET_Z10 && TARGET_64BIT && reload_completed"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 0) (lshiftrt:DI (match_dup 0) (const_int 63)))]
+{
+  operands[0] = gen_rtx_REG (DImode, REGNO (operands[0]));
+  operands[1] = gen_rtx_REG (DImode, REGNO (operands[1]));
+})
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand")
+       (unspec:SI [(match_operand:SIGNBIT_SINGLE 1 "memory_operand")]
+                  UNSPEC_SIGNBIT))]
+  "TARGET_Z10 && TARGET_64BIT && reload_completed"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 31)))]
+{
+  operands[1] = change_address (operands[1], SImode, 0);
+})
+
+(define_mode_iterator SIGNBIT_DBL_TETRA [(DF "TARGET_HARD_FLOAT")
+                                        (TF "TARGET_HARD_FLOAT")
+                                        (DD "TARGET_HARD_DFP")
+                                        (TD "TARGET_HARD_DFP")])
+(define_expand "signbit<mode>2"
+  [(match_operand:SI 0 "register_operand")
+   (match_operand:SIGNBIT_DBL_TETRA 1 "nonimmediate_operand")]
+  ""
+{
+  if (TARGET_Z10 && TARGET_64BIT)
+    {
+      rtx reg_di = gen_reg_rtx (DImode);
+      if (<MODE>mode == TFmode || <MODE>mode == TDmode)
+       {
+         rtx reg_ti = gen_reg_rtx (TImode);
+         emit_insn (gen_rtx_SET (reg_ti, simplify_gen_subreg (TImode, 
operands[1], <MODE>mode, 0)));
+         emit_insn (gen_rtx_SET (reg_di, simplify_gen_subreg (DImode, reg_ti, 
TImode, 0)));
+       }
+      else
+       emit_insn (gen_rtx_SET (reg_di, simplify_gen_subreg (DImode, 
operands[1], <MODE>mode, 0)));
+      emit_insn (gen_rtx_SET (reg_di, gen_rtx_LSHIFTRT (DImode, reg_di, 
GEN_INT (63))));
+      rtx subreg = gen_rtx_SUBREG (SImode, reg_di, 4);
+      SUBREG_PROMOTED_VAR_P (subreg) = 1;
+      SUBREG_PROMOTED_SET (subreg, SRP_SIGNED_AND_UNSIGNED);
+      emit_insn (gen_rtx_SET (operands[0], subreg));
+    }
+  else
+    emit_insn (gen_signbit_tdc<mode>2 (operands[0], force_reg (<MODE>mode, 
operands[1])));
+  DONE;
+})
+
 ; This extracts CC into a GPR properly shifted.  The actual IPM
 ; instruction will be issued by reload.  The constraint of operand 1
 ; forces reload to use a GPR.  So reload will issue a movcc insn for
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
index 2ff5a37c0f0a..e1c7806ad96f 100644
--- a/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-2.c
+++ b/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-2.c
@@ -3,8 +3,10 @@
 
 #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]+,1365} 0 { target lp64 } } 
} SIGNBIT long double */
+/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,1365} 0 { target lp64 } 
} } SIGNBIT _Decimal128 */
+/* { dg-final { scan-assembler-times {tcxb\t%f[0-9]+,1365} 1 { target { ! lp64 
} } } } SIGNBIT long double */
+/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,1365} 1 { target { ! 
lp64 } } } } 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 */
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
index 8f67553c7dac..5c9986d06006 100644
--- a/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-3.c
+++ b/gcc/testsuite/gcc.target/s390/isfinite-isinf-isnormal-signbit-3.c
@@ -3,8 +3,10 @@
 
 #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]+,1365} 0 { 
target lp64 } } } */
+/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,1365} 0 { target lp64 } 
} } */
+/* { dg-final { scan-assembler-times {wftcixb\t%v[0-9]+,%v[0-9]+,1365} 1 { 
target { ! lp64 } } } } */
+/* { dg-final { scan-assembler-times {tdcxt\t%f[0-9]+,1365} 1 { target { ! 
lp64 } } } } */
 /* { 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 } } */
diff --git a/gcc/testsuite/gcc.target/s390/signbit-1.c 
b/gcc/testsuite/gcc.target/s390/signbit-1.c
new file mode 100644
index 000000000000..45f608a3f289
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/signbit-1.c
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -march=z900 -save-temps" } */
+/* { dg-final { scan-assembler-times {\ttceb\t} 2 } } */
+/* { dg-final { scan-assembler-times {\ttcdb\t} 2 } } */
+/* { dg-final { scan-assembler-times {\ttcxb\t} 2 } } */
+
+/* Binary Floating-Point */
+
+__attribute__ ((noipa))
+int signbit_float_reg (float x) { return __builtin_signbit (x); }
+__attribute__ ((noipa))
+int signbit_float_mem (float *x) { return __builtin_signbit (*x); }
+__attribute__ ((noipa))
+int signbit_double_reg (double x) { return __builtin_signbit (x); }
+__attribute__ ((noipa))
+int signbit_double_mem (double *x) { return __builtin_signbit (*x); }
+
+__attribute__ ((noipa))
+int
+signbit_longdouble_reg (long double x)
+{
+  __asm__ ("" : "+f" (x));
+  return __builtin_signbit (x);
+}
+
+__attribute__ ((noipa))
+int signbit_longdouble_mem (long double *x) { return __builtin_signbit (*x); }
+
+#include "signbit.h"
+TEST (float, float, __builtin_inff(), __builtin_nanf("42"), 0.f, 42.f)
+TEST (double, double, __builtin_inf(), __builtin_nan("42"), 0., 42.)
+TEST (longdouble, long double, __builtin_infl(), __builtin_nanl("42"), 0.L, 
42.L)
+
+int
+main (void)
+{
+  test_float ();
+  test_double ();
+  test_longdouble ();
+}
diff --git a/gcc/testsuite/gcc.target/s390/signbit-2.c 
b/gcc/testsuite/gcc.target/s390/signbit-2.c
new file mode 100644
index 000000000000..488c477c891a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/signbit-2.c
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -march=z9-ec -mzarch -save-temps" } */
+/* { dg-final { scan-assembler-times {\ttdcet\t} 2 } } */
+/* { dg-final { scan-assembler-times {\ttdcdt\t} 2 } } */
+/* { dg-final { scan-assembler-times {\ttdcxt\t} 2 } } */
+
+/* Decimal Floating-Point */
+
+__attribute__ ((noipa))
+int signbit_dec32_reg (_Decimal32 x) { return __builtin_signbit (x); }
+__attribute__ ((noipa))
+int signbit_dec32_mem (_Decimal32 *x) { return __builtin_signbit (*x); }
+__attribute__ ((noipa))
+int signbit_dec64_reg (_Decimal64 x) { return __builtin_signbit (x); }
+__attribute__ ((noipa))
+int signbit_dec64_mem (_Decimal64 *x) { return __builtin_signbit (*x); }
+
+__attribute__ ((noipa))
+int
+signbit_dec128_reg (_Decimal128 x)
+{
+  __asm__ ("" : "+f" (x));
+  return __builtin_signbit (x);
+}
+
+__attribute__ ((noipa))
+int signbit_dec128_mem (_Decimal128 *x) { return __builtin_signbit (*x); }
+
+#include "signbit.h"
+TEST (dec32, _Decimal32, __builtin_infd32(), __builtin_nand32("42"), 0.df, 
42.df)
+TEST (dec64, _Decimal64, __builtin_infd64(), __builtin_nand64("42"), 0.dd, 
42.dd)
+TEST (dec128, _Decimal128, __builtin_infd128(), __builtin_nand128("42"), 0.dl, 
42.dl)
+
+int
+main (void)
+{
+  test_dec32 ();
+  test_dec64 ();
+  test_dec128 ();
+}
diff --git a/gcc/testsuite/gcc.target/s390/signbit-3.c 
b/gcc/testsuite/gcc.target/s390/signbit-3.c
new file mode 100644
index 000000000000..2fad58bf3be7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/signbit-3.c
@@ -0,0 +1,152 @@
+/* { dg-do run { target lp64 } } */
+/* { dg-options "-O2 -march=z10 -save-temps" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/* Binary Floating-Point */
+
+/*
+** signbit_float_reg:
+**     lgdr    (%r[0-9]+),%f0
+**     srlg    (%r[0-9]+),\1,63
+**     lgfr    %r2,\2
+**     br      %r14
+*/
+__attribute__ ((noipa))
+int signbit_float_reg (float x) { return __builtin_signbit (x); }
+
+/*
+** signbit_float_mem:
+**    l        (%r[0-9]+),0\(%r2\)
+**    srl      \1,31
+**    lgfr     %r2,\1
+**    br       %r14
+*/
+__attribute__ ((noipa))
+int signbit_float_mem (float *x) { return __builtin_signbit (*x); }
+
+/*
+** signbit_double_reg:
+**    lgdr     (%r[0-9]+),%f0
+**    srlg     %r2,\1,63
+**    br       %r14
+*/
+__attribute__ ((noipa))
+int signbit_double_reg (double x) { return __builtin_signbit (x); }
+
+/*
+** signbit_double_mem:
+**    lg       (%r[0-9]+),0\(%r2\)
+**    srlg     %r2,\1,63
+**    br       %r14
+*/
+__attribute__ ((noipa))
+int signbit_double_mem (double *x) { return __builtin_signbit (*x); }
+
+/*
+** signbit_longdouble_reg:
+**     ld      %f0,0\(%r2\)
+**     ld      %f2,8\(%r2\)
+**     lgdr    (%r[0-9]+),%f0
+**     srlg    %r2,\1,63
+**     br      %r14
+*/
+__attribute__ ((noipa))
+int
+signbit_longdouble_reg (long double x)
+{
+  __asm__ ("" : "+f" (x));
+  return __builtin_signbit (x);
+}
+
+/*
+** signbit_longdouble_mem:
+**      lg     (%r[0-9]+),0\(%r2\)
+**      srlg   %r2,\1,63
+**      br     %r14
+*/
+__attribute__ ((noipa))
+int signbit_longdouble_mem (long double *x) { return __builtin_signbit (*x); }
+
+/* Decimal Floating-Point */
+
+/*
+** signbit_dec32_reg:
+**     lgdr    (%r[0-9]+),%f0
+**     srlg    (%r[0-9]+),\1,63
+**     lgfr    %r2,\2
+**     br      %r14
+*/
+__attribute__ ((noipa))
+int signbit_dec32_reg (_Decimal32 x) { return __builtin_signbit (x); }
+
+/*
+** signbit_dec32_mem:
+**    l        (%r[0-9]+),0\(%r2\)
+**    srl      \1,31
+**    lgfr     %r2,\1
+**    br       %r14
+*/
+__attribute__ ((noipa))
+int signbit_dec32_mem (_Decimal32 *x) { return __builtin_signbit (*x); }
+
+/*
+** signbit_dec64_reg:
+**    lgdr     (%r[0-9]+),%f0
+**    srlg     %r2,\1,63
+**    br       %r14
+*/
+__attribute__ ((noipa))
+int signbit_dec64_reg (_Decimal64 x) { return __builtin_signbit (x); }
+
+/*
+** signbit_dec64_mem:
+**    lg       (%r[0-9]+),0\(%r2\)
+**    srlg     %r2,\1,63
+**    br       %r14
+*/
+__attribute__ ((noipa))
+int signbit_dec64_mem (_Decimal64 *x) { return __builtin_signbit (*x); }
+
+/*
+** signbit_dec128_reg:
+**     ld      %f0,0\(%r2\)
+**     ld      %f2,8\(%r2\)
+**     lgdr    (%r[0-9]+),%f0
+**     srlg    %r2,\1,63
+**     br      %r14
+*/
+__attribute__ ((noipa))
+int
+signbit_dec128_reg (_Decimal128 x)
+{
+  __asm__ ("" : "+f" (x));
+  return __builtin_signbit (x);
+}
+
+/*
+** signbit_dec128_mem:
+**      lg     (%r[0-9]+),0\(%r2\)
+**      srlg   %r2,\1,63
+**      br     %r14
+*/
+__attribute__ ((noipa))
+int signbit_dec128_mem (_Decimal128 *x) { return __builtin_signbit (*x); }
+
+#include "signbit.h"
+TEST (float, float, __builtin_inff(), __builtin_nanf("42"), 0.f, 42.f)
+TEST (double, double, __builtin_inf(), __builtin_nan("42"), 0., 42.)
+TEST (longdouble, long double, __builtin_infl(), __builtin_nanl("42"), 0.L, 
42.L)
+TEST (dec32, _Decimal32, __builtin_infd32(), __builtin_nand32("42"), 0.df, 
42.df)
+TEST (dec64, _Decimal64, __builtin_infd64(), __builtin_nand64("42"), 0.dd, 
42.dd)
+TEST (dec128, _Decimal128, __builtin_infd128(), __builtin_nand128("42"), 0.dl, 
42.dl)
+
+int
+main (void)
+{
+  test_float ();
+  test_double ();
+  test_longdouble ();
+  test_dec32 ();
+  test_dec64 ();
+  test_dec128 ();
+}
diff --git a/gcc/testsuite/gcc.target/s390/signbit-4.c 
b/gcc/testsuite/gcc.target/s390/signbit-4.c
new file mode 100644
index 000000000000..2cb743edc3ac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/signbit-4.c
@@ -0,0 +1,55 @@
+/* { dg-do run { target lp64 } } */
+/* { dg-require-effective-target s390_vx } */
+/* { dg-options "-O2 -march=z13 -save-temps" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/* Binary Floating-Point */
+
+/*
+** signbit_float_reg:
+**    vlgvf    (%r[0-9]+),%v0,0
+**    risbgn   %r2,\1,64-1,128\+63,32\+1
+**    br       %r14
+*/
+__attribute__ ((noipa))
+int signbit_float_reg (float x) { return __builtin_signbit (x); }
+
+/*
+** signbit_float_mem:
+**    l        (%r[0-9]+),0\(%r2\)
+**    risbgn   %r2,\1,64-1,128\+63,32\+1
+**    br       %r14
+*/
+__attribute__ ((noipa))
+int signbit_float_mem (float *x) { return __builtin_signbit (*x); }
+
+/* Decimal Floating-Point */
+
+/*
+** signbit_dec32_reg:
+**    vlgvf    (%r[0-9]+),%v0,0
+**    risbgn   %r2,\1,64-1,128\+63,32\+1
+**    br       %r14
+*/
+__attribute__ ((noipa))
+int signbit_dec32_reg (_Decimal32 x) { return __builtin_signbit (x); }
+
+/*
+** signbit_dec32_mem:
+**    l        (%r[0-9]+),0\(%r2\)
+**    risbgn   %r2,\1,64-1,128\+63,32\+1
+**    br       %r14
+*/
+__attribute__ ((noipa))
+int signbit_dec32_mem (_Decimal32 *x) { return __builtin_signbit (*x); }
+
+#include "signbit.h"
+TEST (float, float, __builtin_inff(), __builtin_nanf("42"), 0.f, 42.f)
+TEST (dec32, _Decimal32, __builtin_infd32(), __builtin_nand32("42"), 0.df, 
42.df)
+
+int
+main (void)
+{
+  test_float ();
+  test_dec32 ();
+}
diff --git a/gcc/testsuite/gcc.target/s390/signbit-5.c 
b/gcc/testsuite/gcc.target/s390/signbit-5.c
new file mode 100644
index 000000000000..68403275f7ca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/signbit-5.c
@@ -0,0 +1,35 @@
+/* { dg-do run { target lp64 } } */
+/* { dg-options "-O2 -march=z14 -save-temps" } */
+
+/*
+** signbit_longdouble_reg:
+**      ld     %f0,0(%r2);ld   %f2,8+0(%r2)
+**      lgdr   (%r[0-9]+),%f0
+**      srlg   %r2,\1,63
+**      br     %r14
+*/
+__attribute__ ((noipa))
+int
+signbit_longdouble_reg (long double x)
+{
+  __asm__ ("" : "+f" (x));
+  return __builtin_signbit (x);
+}
+
+/*
+** signbit_longdouble_mem:
+**      lg     (%r[0-9]+),0\(%r2\)
+**      srlg   %r2,\1,63
+**      br     %r14
+*/
+__attribute__ ((noipa))
+int signbit_longdouble_mem (long double *x) { return __builtin_signbit (*x); }
+
+#include "signbit.h"
+TEST (longdouble, long double, __builtin_infl(), __builtin_nanl("42"), 0.L, 
42.L)
+
+int
+main (void)
+{
+  test_longdouble ();
+}
diff --git a/gcc/testsuite/gcc.target/s390/signbit.h 
b/gcc/testsuite/gcc.target/s390/signbit.h
new file mode 100644
index 000000000000..730e387752c4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/signbit.h
@@ -0,0 +1,36 @@
+#define TEST(T, U, I, N, C0, C42)                                              
\
+  void test_##T (void)                                                         
\
+  {                                                                            
\
+    U tmp;                                                                     
\
+    int x;                                                                     
\
+                                                                               
\
+    x = signbit_##T##_reg(C42);                                                
\
+    x += signbit_##T##_reg(C0);                                                
\
+    x += signbit_##T##_reg(I);                                                 
\
+    x += signbit_##T##_reg(N);                                                 
\
+    tmp = C42;                                                                 
\
+    x += signbit_##T##_mem(&tmp);                                              
\
+    tmp = C0;                                                                  
\
+    x += signbit_##T##_mem(&tmp);                                              
\
+    tmp = I;                                                                   
\
+    x += signbit_##T##_mem(&tmp);                                              
\
+    tmp = N;                                                                   
\
+    x += signbit_##T##_mem(&tmp);                                              
\
+    if (x != 0)                                                                
\
+      __builtin_abort();                                                       
\
+                                                                               
\
+    x = signbit_##T##_reg(-C42);                                               
\
+    x += signbit_##T##_reg(-C0);                                               
\
+    x += signbit_##T##_reg(-I);                                                
\
+    x += signbit_##T##_reg(-N);                                                
\
+    tmp = -C42;                                                                
\
+    x += signbit_##T##_mem(&tmp);                                              
\
+    tmp = -C0;                                                                 
\
+    x += signbit_##T##_mem(&tmp);                                              
\
+    tmp = -I;                                                                  
\
+    x += signbit_##T##_mem(&tmp);                                              
\
+    tmp = -N;                                                                  
\
+    x += signbit_##T##_mem(&tmp);                                              
\
+    if (x != 8)                                                                
\
+      __builtin_abort();                                                       
\
+  }

Reply via email to