Revised patch, supporting linker that aligns the toc base.

This fixes a thinko in offsettable_ok_by_alignment.  It's not the
absolute placement that matters, but the toc-pointer relative offset.
So alignment of r2 also needs to be taken into account.

Changing offsettable_ok_by_alignment has a ripple effect into the 'm'
constraint so we also need to ensure rs6000_legitimize_reload_address
does not create invalid toc-relative addresses.  As found by
gcc.dg/torture/builtin-math-2.c -Os.  That's the reason for the
use_toc_relative_ref change.  I hope the size check along with
reg_offset_p is sufficient here.  It seems so, but it's difficult to
be certain due to how hard it is to get just the right combination of
reload conditions to trigger.

Bootstrapped and regression tested powerpc64-linux and
powerpc64le-linux, both with a new and old linker.  OK for mainline?

        PR target/65810
        * config/rs6000/rs6000.c (POWERPC64_TOC_POINTER_ALIGNMENT): Define.
        (offsettable_ok_by_alignment): Use minimum of decl and toc
        pointer alignment.  Replace dead code with assertion.
        (use_toc_relative_ref): Add mode arg.  Return false in -mcmodel=medium
        case if size exceeds toc pointer alignment.
        (rs6000_legitimize_reload_address): Update use_toc_relative_ref call.
        (rs6000_emit_move): Likewise.
        * configure.ac: Add linker toc pointer alignment check.
        * configure: Regenerate.
        * config.in: Regenerate.

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 222352)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -6497,13 +6497,21 @@ virtual_stack_registers_memory_p (rtx op)
 }
 
 /* Return true if a MODE sized memory accesses to OP plus OFFSET
-   is known to not straddle a 32k boundary.  */
+   is known to not straddle a 32k boundary.  This function is used
+   to determine whether -mcmodel=medium code can use TOC pointer
+   relative addressing for OP.  This means the alignment of the TOC
+   pointer must also be taken into account, and unfortunately that is
+   only 8 bytes.  */ 
 
+#ifndef POWERPC64_TOC_POINTER_ALIGNMENT
+#define POWERPC64_TOC_POINTER_ALIGNMENT 8
+#endif
+
 static bool
 offsettable_ok_by_alignment (rtx op, HOST_WIDE_INT offset,
                             machine_mode mode)
 {
-  tree decl, type;
+  tree decl;
   unsigned HOST_WIDE_INT dsize, dalign, lsb, mask;
 
   if (GET_CODE (op) != SYMBOL_REF)
@@ -6556,38 +6564,20 @@ offsettable_ok_by_alignment (rtx op, HOST_WIDE_INT
          if (dsize > 32768)
            return false;
 
-         return dalign / BITS_PER_UNIT >= dsize;
+         dalign /= BITS_PER_UNIT;
+         if (dalign > POWERPC64_TOC_POINTER_ALIGNMENT)
+           dalign = POWERPC64_TOC_POINTER_ALIGNMENT;
+         return dalign >= dsize;
        }
     }
   else
-    {
-      type = TREE_TYPE (decl);
+    gcc_unreachable ();
 
-      dalign = TYPE_ALIGN (type);
-      if (CONSTANT_CLASS_P (decl))
-       dalign = CONSTANT_ALIGNMENT (decl, dalign);
-      else
-       dalign = DATA_ALIGNMENT (decl, dalign);
-
-      if (dsize == 0)
-       {
-         /* BLKmode, check the entire object.  */
-         if (TREE_CODE (decl) == STRING_CST)
-           dsize = TREE_STRING_LENGTH (decl);
-         else if (TYPE_SIZE_UNIT (type)
-                  && tree_fits_uhwi_p (TYPE_SIZE_UNIT (type)))
-           dsize = tree_to_uhwi (TYPE_SIZE_UNIT (type));
-         else
-           return false;
-         if (dsize > 32768)
-           return false;
-
-         return dalign / BITS_PER_UNIT >= dsize;
-       }
-    }
-
   /* Find how many bits of the alignment we know for this access.  */
-  mask = dalign / BITS_PER_UNIT - 1;
+  dalign /= BITS_PER_UNIT;
+  if (dalign > POWERPC64_TOC_POINTER_ALIGNMENT)
+    dalign = POWERPC64_TOC_POINTER_ALIGNMENT;
+  mask = dalign - 1;
   lsb = offset & -offset;
   mask &= lsb - 1;
   dalign = mask + 1;
@@ -7526,13 +7516,14 @@ rs6000_cannot_force_const_mem (machine_mode mode A
    can be addressed relative to the toc pointer.  */
 
 static bool
-use_toc_relative_ref (rtx sym)
+use_toc_relative_ref (rtx sym, machine_mode mode)
 {
   return ((constant_pool_expr_p (sym)
           && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (sym),
                                               get_pool_mode (sym)))
          || (TARGET_CMODEL == CMODEL_MEDIUM
-             && SYMBOL_REF_LOCAL_P (sym)));
+             && SYMBOL_REF_LOCAL_P (sym)
+             && GET_MODE_SIZE (mode) <= POWERPC64_TOC_POINTER_ALIGNMENT));
 }
 
 /* Our implementation of LEGITIMIZE_RELOAD_ADDRESS.  Returns a value to
@@ -7737,7 +7728,7 @@ rs6000_legitimize_reload_address (rtx x, machine_m
   if (TARGET_TOC
       && reg_offset_p
       && GET_CODE (x) == SYMBOL_REF
-      && use_toc_relative_ref (x))
+      && use_toc_relative_ref (x, mode))
     {
       x = create_TOC_reference (x, NULL_RTX);
       if (TARGET_CMODEL != CMODEL_SMALL)
@@ -8810,7 +8801,7 @@ rs6000_emit_move (rtx dest, rtx source, machine_mo
         reference to it.  */
       if (TARGET_TOC
          && GET_CODE (operands[1]) == SYMBOL_REF
-         && use_toc_relative_ref (operands[1]))
+         && use_toc_relative_ref (operands[1], mode))
        operands[1] = create_TOC_reference (operands[1], operands[0]);
       else if (mode == Pmode
               && CONSTANT_P (operands[1])
Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac    (revision 222352)
+++ gcc/configure.ac    (working copy)
@@ -5087,6 +5087,31 @@ EOF
       AC_DEFINE(HAVE_LD_LARGE_TOC, 1,
     [Define if your PowerPC64 linker supports a large TOC.])
     fi
+
+    AC_CACHE_CHECK(linker toc pointer alignment,
+    gcc_cv_ld_toc_align,
+    [if test x$gcc_cv_as != x -a x$gcc_cv_ld != x -a x$gcc_cv_nm != x; then
+      cat > conftest.s <<EOF
+       .global _start
+       .text
+_start:
+       addis 9,2,x@got@ha
+       .section .data.rel.ro,"aw",@progbits
+       .p2align 16
+       .space 32768
+x:     .quad .TOC.
+EOF
+      if $gcc_cv_as -a64 -o conftest.o conftest.s > /dev/null 2>&1 \
+         && $gcc_cv_ld $emul_name -o conftest conftest.o > /dev/null 2>&1; then
+        gcc_cv_ld_toc_align=`$gcc_cv_nm conftest | ${AWK} '/\.TOC\./ { match 
($0, "0[[[:xdigit:]]]*", a); print strtonum ("0x" substr(a[[0]], 
length(a[[0]])-3)) }'`
+      fi
+      rm -f conftest conftest.o conftest.s
+    fi
+    ])
+    if test -n "$gcc_cv_ld_toc_align" && test $gcc_cv_ld_toc_align -gt 8; then
+      AC_DEFINE_UNQUOTED(POWERPC64_TOC_POINTER_ALIGNMENT, $gcc_cv_ld_toc_align,
+    [Define to .TOC. alignment forced by your linker.])
+    fi
     ;;
 esac
 

-- 
Alan Modra
Australia Development Lab, IBM

Reply via email to