PR target/83862 pointed out a problem I put into the 128-bit floating point
type signbit optimization.  The issue is we want to avoid doing a load to a
floating point/vector register and then a direct move to do signbit, so we
change the load to load the upper 64-bits of the floating point value to get
the sign bit.  Unfortunately, if the type is IEEE 128-bit and memory is
addressed with an indexed address on a little endian system, it generates an
illegal address and generates an internal compiler error.

I have tested this on a little endian power8 system, with bootstrap compilers.
There was not regression, and the new test passes.  Can I install this into the
trunk?

The same code is also in GCC 6 and 7.  While, -mabi=ieeelongdouble is not
supported in those releases, you can get a failure if you use an explicit
_Float128 type instead of long double.  Assuming that the bug shows up, can I
apply these patches to those branches as well?

[gcc]
2018-01-16  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        PR target/83862
        * config/rs6000/rs6000.c (rs6000_split_signbit): Do not create an
        illegal address on little endian systems if the source value is in
        memory addressed with indexed addressing.
        * config/rs6000/rs6000.md (signbit<mode>2_dm): Likewise.
        (signbit<mode>2_dm_<su>ext): Likewise.

[gcc/testsuite]
2018-01-16  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        PR target/83862
        * gcc.target/powerpc/pr83862.c: New test.

-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 256753)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -23341,9 +23341,27 @@ rs6000_split_signbit (rtx dest, rtx src)
 
   if (MEM_P (src))
     {
-      rtx mem = (WORDS_BIG_ENDIAN
-                ? adjust_address (src, DImode, 0)
-                : adjust_address (src, DImode, 8));
+      rtx addr = XEXP (src, 0);
+      rtx mem;
+
+      if (!WORDS_BIG_ENDIAN)
+       {
+         /* Do not create an illegal address for indexed addressing when we
+            add in the 8 to address the second word where the sign bit is.
+            Instead use the desitnation register as a base register.  */
+         if (GET_CODE (addr) == PLUS
+             && !rs6000_legitimate_offset_address_p (DImode, addr, true, true))
+           {
+             emit_insn (gen_rtx_SET (dest, addr));
+             mem = change_address (src, DImode,
+                                   gen_rtx_PLUS (Pmode, dest, GEN_INT (8)));
+           }
+         else
+           mem = adjust_address (src, DImode, 8);
+       }
+      else
+       mem = adjust_address (src, DImode, 0);
+
       emit_insn (gen_rtx_SET (dest_di, mem));
     }
 
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md (revision 256753)
+++ gcc/config/rs6000/rs6000.md (working copy)
@@ -4835,9 +4835,11 @@ (define_expand "copysign<mode>3"
   })
 
 ;; Optimize signbit on 64-bit systems with direct move to avoid doing the store
-;; and load.
+;; and load.  We restrict signbit coming from a load to use a base register for
+;; the destination, in case we need to use the base register as a tempoary
+;; address register.
 (define_insn_and_split "signbit<mode>2_dm"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r")
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r,&b,r")
        (unspec:SI
         [(match_operand:SIGNBIT 1 "input_operand" "wa,m,r")]
         UNSPEC_SIGNBIT))]
@@ -4853,7 +4855,7 @@ (define_insn_and_split "signbit<mode>2_d
   (set_attr "type" "mftgpr,load,integer")])
 
 (define_insn_and_split "*signbit<mode>2_dm_<su>ext"
-  [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r")
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r,&b,r")
        (any_extend:DI
         (unspec:SI
          [(match_operand:SIGNBIT 1 "input_operand" "wa,m,r")]
Index: gcc/testsuite/gcc.target/powerpc/pr83862.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/pr83862.c  (nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/pr83862.c  (working copy)
@@ -0,0 +1,21 @@
+/* PR target/83862.c */
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-mpower8-vector -O2 -mabi=ieeelongdouble -Wno-psabi" } */
+
+/* On little endian systems, optimizing signbit of IEEE 128-bit values from
+   memory could abort if the memory address was indexed (reg+reg).  The
+   optimization is only on 64-bit machines with direct move.
+
+   Compile with -g -O2 -mabi=ieeelongdouble -Wno-psabi.  */
+
+#ifndef TYPE
+#define TYPE long double
+#endif
+
+int sbr (TYPE a) { return __builtin_signbit (a); }
+int sbm (TYPE *a) { return __builtin_signbit (*a); }
+int sbo (TYPE *a) { return __builtin_signbit (a[4]); }
+int sbi (TYPE *a, unsigned long n) { return __builtin_signbit (a[n]); }
+void sbs (int *p, TYPE a) { *p = __builtin_signbit (a); }

Reply via email to