re PR target/48032 (PowerPC64 -mcmodel=medium invalid ld offset)
authorAlan Modra <amodra@gmail.com>
Tue, 15 Mar 2011 02:19:28 +0000 (12:49 +1030)
committerAlan Modra <amodra@gcc.gnu.org>
Tue, 15 Mar 2011 02:19:28 +0000 (12:49 +1030)
PR target/48032
* config/rs6000/rs6000.c (offsettable_ok_by_alignment): Do not
presume symbol_refs without a symbol_ref_decl are suitably
aligned, nor other trees we may see here.  Handle anchor symbols.
(legitimate_constant_pool_address_p): Comment.  Add mode param.
Check cmodel=medium addresses.  Adjust all calls.
(rs6000_emit_move): Don't call offsettable_ok_by_alignment on
creating cmodel=medium optimized access to locals.
* config/rs6000/constraints.md (R): Pass QImode to
legitimate_constant_pool_address_p.
* config/rs6000/predicates.md (input_operand): Pass mode to
legitimate_constant_pool_address_p.
* config/rs6000/rs6000-protos.h (legitimate_constant_pool_address_p):
Update prototype.

From-SVN: r170976

gcc/ChangeLog
gcc/config/rs6000/constraints.md
gcc/config/rs6000/predicates.md
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c

index 5dde051c242574091de9b028afc4f9287e8433f7..a4bcde02f7525bb370a0d837a64cca1292a95a8c 100644 (file)
@@ -1,3 +1,20 @@
+2011-03-15  Alan Modra  <amodra@gmail.com>
+
+       PR target/48032
+       * config/rs6000/rs6000.c (offsettable_ok_by_alignment): Do not
+       presume symbol_refs without a symbol_ref_decl are suitably
+       aligned, nor other trees we may see here.  Handle anchor symbols.
+       (legitimate_constant_pool_address_p): Comment.  Add mode param.
+       Check cmodel=medium addresses.  Adjust all calls.
+       (rs6000_emit_move): Don't call offsettable_ok_by_alignment on
+       creating cmodel=medium optimized access to locals.
+       * config/rs6000/constraints.md (R): Pass QImode to
+       legitimate_constant_pool_address_p.
+       * config/rs6000/predicates.md (input_operand): Pass mode to
+       legitimate_constant_pool_address_p.
+       * config/rs6000/rs6000-protos.h (legitimate_constant_pool_address_p):
+       Update prototype.
+
 2011-03-14  Michael Meissner  <meissner@linux.vnet.ibm.com>
 
        PR target/48053
index 7eb991a326f32f70ad1a60673a8a87b2b93aa9e0..71b3b207ef8724370ce437a41938744119c1b5a2 100644 (file)
@@ -166,7 +166,7 @@ usually better to use @samp{m} or @samp{es} in @code{asm} statements)"
 
 (define_constraint "R"
   "AIX TOC entry"
-  (match_test "legitimate_constant_pool_address_p (op, false)"))
+  (match_test "legitimate_constant_pool_address_p (op, QImode, false)"))
 
 ;; General constraints
 
index 1796bf58eed788b3112d8af9075568f706b7c524..90947452b65cb00ef59dfbb4b8725a7c7633109a 100644 (file)
     return 1;
 
   /* A SYMBOL_REF referring to the TOC is valid.  */
-  if (legitimate_constant_pool_address_p (op, false))
+  if (legitimate_constant_pool_address_p (op, mode, false))
     return 1;
 
   /* A constant pool expression (relative to the TOC) is valid */
index 3b0d1dab7db1f73947d68a627005b5035871b3e2..d79af36ce04d3dd1b024ee57532703622ea553a3 100644 (file)
@@ -41,7 +41,8 @@ extern int small_data_operand (rtx, enum machine_mode);
 extern bool toc_relative_expr_p (rtx);
 extern bool invalid_e500_subreg (rtx, enum machine_mode);
 extern void validate_condition_mode (enum rtx_code, enum machine_mode);
-extern bool legitimate_constant_pool_address_p (const_rtx, bool);
+extern bool legitimate_constant_pool_address_p (const_rtx, enum machine_mode,
+                                               bool);
 extern bool legitimate_indirect_address_p (rtx, int);
 extern bool legitimate_indexed_address_p (rtx, int);
 extern bool avoiding_indexed_address_p (enum machine_mode);
index 231651e0d46e2edd8408af7924ac85383f08068e..0ff174519d3b8abe961bdccfbe1180ca8b2cf8e6 100644 (file)
@@ -5791,6 +5791,94 @@ virtual_stack_registers_memory_p (rtx op)
          && regnum <= LAST_VIRTUAL_POINTER_REGISTER);
 }
 
+/* Return true if memory accesses to OP are known to never straddle
+   a 32k boundary.  */
+
+static bool
+offsettable_ok_by_alignment (rtx op, HOST_WIDE_INT offset,
+                            enum machine_mode mode)
+{
+  tree decl, type;
+  unsigned HOST_WIDE_INT dsize, dalign;
+
+  if (GET_CODE (op) != SYMBOL_REF)
+    return false;
+
+  decl = SYMBOL_REF_DECL (op);
+  if (!decl)
+    {
+      if (GET_MODE_SIZE (mode) == 0)
+       return false;
+
+      /* -fsection-anchors loses the original SYMBOL_REF_DECL when
+        replacing memory addresses with an anchor plus offset.  We
+        could find the decl by rummaging around in the block->objects
+        VEC for the given offset but that seems like too much work.  */
+      dalign = 1;
+      if (SYMBOL_REF_HAS_BLOCK_INFO_P (op)
+         && SYMBOL_REF_ANCHOR_P (op)
+         && SYMBOL_REF_BLOCK (op) != NULL)
+       {
+         struct object_block *block = SYMBOL_REF_BLOCK (op);
+         HOST_WIDE_INT lsb, mask;
+
+         /* Given the alignment of the block..  */
+         dalign = block->alignment;
+         mask = dalign / BITS_PER_UNIT - 1;
+
+         /* ..and the combined offset of the anchor and any offset
+            to this block object..  */
+         offset += SYMBOL_REF_BLOCK_OFFSET (op);
+         lsb = offset & -offset;
+
+         /* ..find how many bits of the alignment we know for the
+            object.  */
+         mask &= lsb - 1;
+         dalign = mask + 1;
+       }
+      return dalign >= GET_MODE_SIZE (mode);
+    }
+
+  if (DECL_P (decl))
+    {
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       return true;
+
+      if (!DECL_SIZE_UNIT (decl))
+       return false;
+
+      if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
+       return false;
+
+      dsize = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+      if (dsize > 32768)
+       return false;
+
+      dalign = DECL_ALIGN_UNIT (decl);
+      return dalign >= dsize;
+    }
+
+  type = TREE_TYPE (decl);
+
+  if (TREE_CODE (decl) == STRING_CST)
+    dsize = TREE_STRING_LENGTH (decl);
+  else if (TYPE_SIZE_UNIT (type)
+          && host_integerp (TYPE_SIZE_UNIT (type), 1))
+    dsize = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
+  else
+    return false;
+  if (dsize > 32768)
+    return false;
+
+  dalign = TYPE_ALIGN (type);
+  if (CONSTANT_CLASS_P (decl))
+    dalign = CONSTANT_ALIGNMENT (decl, dalign);
+  else
+    dalign = DATA_ALIGNMENT (decl, dalign);
+  dalign /= BITS_PER_UNIT;
+  return dalign >= dsize;
+}
+
 static bool
 constant_pool_expr_p (rtx op)
 {
@@ -5815,8 +5903,12 @@ toc_relative_expr_p (rtx op)
          && XINT (tocrel_base, 1) == UNSPEC_TOCREL);
 }
 
+/* Return true if X is a constant pool address, and also for cmodel=medium
+   if X is a toc-relative address known to be offsettable within MODE.  */
+
 bool
-legitimate_constant_pool_address_p (const_rtx x, bool strict)
+legitimate_constant_pool_address_p (const_rtx x, enum machine_mode mode,
+                                   bool strict)
 {
   return (TARGET_TOC
          && (GET_CODE (x) == PLUS || GET_CODE (x) == LO_SUM)
@@ -5825,7 +5917,12 @@ legitimate_constant_pool_address_p (const_rtx x, bool strict)
              || ((TARGET_MINIMAL_TOC
                   || TARGET_CMODEL != CMODEL_SMALL)
                  && INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict)))
-         && toc_relative_expr_p (XEXP (x, 1)));
+         && toc_relative_expr_p (XEXP (x, 1))
+         && (TARGET_CMODEL != CMODEL_MEDIUM
+             || constant_pool_expr_p (XVECEXP (tocrel_base, 0, 0))
+             || mode == QImode
+             || offsettable_ok_by_alignment (XVECEXP (tocrel_base, 0, 0),
+                                             INTVAL (tocrel_offset), mode)));
 }
 
 static bool
@@ -5853,7 +5950,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
     return false;
   if (!reg_offset_addressing_ok_p (mode))
     return virtual_stack_registers_memory_p (x);
-  if (legitimate_constant_pool_address_p (x, strict))
+  if (legitimate_constant_pool_address_p (x, mode, strict))
     return true;
   if (GET_CODE (XEXP (x, 1)) != CONST_INT)
     return false;
@@ -6853,7 +6950,8 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
     return 1;
   if (reg_offset_p && legitimate_small_data_p (mode, x))
     return 1;
-  if (reg_offset_p && legitimate_constant_pool_address_p (x, reg_ok_strict))
+  if (reg_offset_p
+      && legitimate_constant_pool_address_p (x, mode, reg_ok_strict))
     return 1;
   /* If not REG_OK_STRICT (before reload) let pass any stack offset.  */
   if (! reg_ok_strict
@@ -6963,7 +7061,7 @@ rs6000_mode_dependent_address (const_rtx addr)
     case LO_SUM:
       /* Anything in the constant pool is sufficiently aligned that
         all bytes have the same high part address.  */
-      return !legitimate_constant_pool_address_p (addr, false);
+      return !legitimate_constant_pool_address_p (addr, QImode, false);
 
     /* Auto-increment cases are now treated generically in recog.c.  */
     case PRE_MODIFY:
@@ -7327,53 +7425,21 @@ rs6000_eliminate_indexed_memrefs (rtx operands[2])
 
   if (GET_CODE (operands[0]) == MEM
       && GET_CODE (XEXP (operands[0], 0)) != REG
-      && ! legitimate_constant_pool_address_p (XEXP (operands[0], 0), false))
+      && ! legitimate_constant_pool_address_p (XEXP (operands[0], 0),
+                                              GET_MODE (operands[0]), false))
     operands[0]
       = replace_equiv_address (operands[0],
                               copy_addr_to_reg (XEXP (operands[0], 0)));
 
   if (GET_CODE (operands[1]) == MEM
       && GET_CODE (XEXP (operands[1], 0)) != REG
-      && ! legitimate_constant_pool_address_p (XEXP (operands[1], 0), false))
+      && ! legitimate_constant_pool_address_p (XEXP (operands[1], 0),
+                                              GET_MODE (operands[1]), false))
     operands[1]
       = replace_equiv_address (operands[1],
                               copy_addr_to_reg (XEXP (operands[1], 0)));
 }
 
-/* Return true if memory accesses to DECL are known to never straddle
-   a 32k boundary.  */
-
-static bool
-offsettable_ok_by_alignment (tree decl)
-{
-  unsigned HOST_WIDE_INT dsize, dalign;
-
-  /* Presume any compiler generated symbol_ref is suitably aligned.  */
-  if (!decl)
-    return true;
-
-  if (TREE_CODE (decl) != VAR_DECL
-      && TREE_CODE (decl) != PARM_DECL
-      && TREE_CODE (decl) != RESULT_DECL
-      && TREE_CODE (decl) != FIELD_DECL)
-    return true;
-
-  if (!DECL_SIZE_UNIT (decl))
-    return false;
-
-  if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
-    return false;
-
-  dsize = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
-  if (dsize <= 1)
-    return true;
-  if (dsize > 32768)
-    return false;
-
-  dalign = DECL_ALIGN_UNIT (decl);
-  return dalign >= dsize;
-}
-
 /* Emit a move from SOURCE to DEST in mode MODE.  */
 void
 rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
@@ -7695,8 +7761,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
          || (TARGET_CMODEL == CMODEL_MEDIUM
              && GET_CODE (operands[1]) == SYMBOL_REF
              && !CONSTANT_POOL_ADDRESS_P (operands[1])
-             && SYMBOL_REF_LOCAL_P (operands[1])
-             && offsettable_ok_by_alignment (SYMBOL_REF_DECL (operands[1]))))
+             && SYMBOL_REF_LOCAL_P (operands[1])))
        {
          rtx reg = NULL_RTX;
          if (TARGET_CMODEL != CMODEL_SMALL)
@@ -7718,7 +7783,8 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
                   || (GET_CODE (operands[0]) == REG
                       && FP_REGNO_P (REGNO (operands[0]))))
               && GET_CODE (operands[1]) != HIGH
-              && ! legitimate_constant_pool_address_p (operands[1], false)
+              && ! legitimate_constant_pool_address_p (operands[1], mode,
+                                                       false)
               && ! toc_relative_expr_p (operands[1])
               && (TARGET_CMODEL == CMODEL_SMALL
                   || can_create_pseudo_p ()
@@ -16444,7 +16510,7 @@ print_operand_address (FILE *file, rtx x)
       fprintf (file, ")(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
     }
 #endif
-  else if (legitimate_constant_pool_address_p (x, true))
+  else if (legitimate_constant_pool_address_p (x, QImode, true))
     {
       /* This hack along with a corresponding hack in
         rs6000_output_addr_const_extra arranges to output addends