OSDN Git Service

2008-04-01 Rafael Espindola <espindola@google.com>
[pf3gnuchains/gcc-fork.git] / gcc / explow.c
index 6a40690..612fb1b 100644 (file)
@@ -1,12 +1,13 @@
 /* Subroutines for manipulating rtx's in semantically interesting ways.
    Copyright (C) 1987, 1991, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 
 #include "config.h"
@@ -37,6 +37,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "ggc.h"
 #include "recog.h"
 #include "langhooks.h"
+#include "target.h"
+#include "output.h"
 
 static rtx break_out_memory_refs (rtx);
 static void emit_stack_probe (rtx);
@@ -242,9 +244,13 @@ expr_size (tree exp)
   if (TREE_CODE (exp) == WITH_SIZE_EXPR)
     size = TREE_OPERAND (exp, 1);
   else
-    size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (lang_hooks.expr_size (exp), exp);
+    {
+      size = lang_hooks.expr_size (exp);
+      gcc_assert (size);
+      size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, exp);
+    }
 
-  return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), 0);
+  return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), EXPAND_NORMAL);
 }
 
 /* Return a wide integer for the size in bytes of the value of EXP, or -1
@@ -258,7 +264,10 @@ int_expr_size (tree exp)
   if (TREE_CODE (exp) == WITH_SIZE_EXPR)
     size = TREE_OPERAND (exp, 1);
   else
-    size = lang_hooks.expr_size (exp);
+    {
+      size = lang_hooks.expr_size (exp);
+      gcc_assert (size);
+    }
 
   if (size == 0 || !host_integerp (size, 0))
     return -1;
@@ -313,6 +322,7 @@ convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED,
                        rtx x)
 {
 #ifndef POINTERS_EXTEND_UNSIGNED
+  gcc_assert (GET_MODE (x) == to_mode || GET_MODE (x) == VOIDmode);
   return x;
 #else /* defined(POINTERS_EXTEND_UNSIGNED) */
   enum machine_mode from_mode;
@@ -371,12 +381,15 @@ convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED,
     case MULT:
       /* For addition we can safely permute the conversion and addition
         operation if one operand is a constant and converting the constant
-        does not change it.  We can always safely permute them if we are
-        making the address narrower.  */
+        does not change it or if one operand is a constant and we are
+        using a ptr_extend instruction  (POINTERS_EXTEND_UNSIGNED < 0).
+        We can always safely permute them if we are making the address
+        narrower.  */
       if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode)
          || (GET_CODE (x) == PLUS
              && GET_CODE (XEXP (x, 1)) == CONST_INT
-             && XEXP (x, 1) == convert_memory_address (to_mode, XEXP (x, 1))))
+             && (XEXP (x, 1) == convert_memory_address (to_mode, XEXP (x, 1))
+                 || POINTERS_EXTEND_UNSIGNED < 0)))
        return gen_rtx_fmt_ee (GET_CODE (x), to_mode,
                               convert_memory_address (to_mode, XEXP (x, 0)),
                               XEXP (x, 1));
@@ -418,18 +431,21 @@ memory_address (enum machine_mode mode, rtx x)
 
       /* At this point, any valid address is accepted.  */
       if (memory_address_p (mode, x))
-       goto win;
+       goto done;
 
       /* If it was valid before but breaking out memory refs invalidated it,
         use it the old way.  */
       if (memory_address_p (mode, oldx))
-       goto win2;
+       {
+         x = oldx;
+         goto done;
+       }
 
       /* Perform machine-dependent transformations on X
         in certain cases.  This is not necessary since the code
         below can handle all possible cases, but machine-dependent
         transformations can make better code.  */
-      LEGITIMIZE_ADDRESS (x, oldx, mode, win);
+      LEGITIMIZE_ADDRESS (x, oldx, mode, done);
 
       /* PLUS and MULT can appear in special ways
         as the result of attempts to make an address usable for indexing.
@@ -469,27 +485,11 @@ memory_address (enum machine_mode mode, rtx x)
         the register is a valid address.  */
       else
        x = force_reg (Pmode, x);
-
-      goto done;
-
-    win2:
-      x = oldx;
-    win:
-      if (flag_force_addr && ! cse_not_expected && !REG_P (x)
-         /* Don't copy an addr via a reg if it is one of our stack slots.  */
-         && ! (GET_CODE (x) == PLUS
-               && (XEXP (x, 0) == virtual_stack_vars_rtx
-                   || XEXP (x, 0) == virtual_incoming_args_rtx)))
-       {
-         if (general_operand (x, Pmode))
-           x = force_reg (Pmode, x);
-         else
-           x = force_operand (x, NULL_RTX);
-       }
     }
 
  done:
 
+  gcc_assert (memory_address_p (mode, x));
   /* If we didn't change the address, we are done.  Otherwise, mark
      a reg as a pointer if we have REG or REG + CONST_INT.  */
   if (oldx == x)
@@ -508,20 +508,6 @@ memory_address (enum machine_mode mode, rtx x)
   return x;
 }
 
-/* Like `memory_address' but pretend `flag_force_addr' is 0.  */
-
-rtx
-memory_address_noforce (enum machine_mode mode, rtx x)
-{
-  int ambient_force_addr = flag_force_addr;
-  rtx val;
-
-  flag_force_addr = 0;
-  val = memory_address (mode, x);
-  flag_force_addr = ambient_force_addr;
-  return val;
-}
-
 /* Convert a mem ref into one with a valid memory address.
    Pass through anything else unchanged.  */
 
@@ -530,13 +516,68 @@ validize_mem (rtx ref)
 {
   if (!MEM_P (ref))
     return ref;
-  if (! (flag_force_addr && CONSTANT_ADDRESS_P (XEXP (ref, 0)))
-      && memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
+  ref = use_anchored_address (ref);
+  if (memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
     return ref;
 
   /* Don't alter REF itself, since that is probably a stack slot.  */
   return replace_equiv_address (ref, XEXP (ref, 0));
 }
+
+/* If X is a memory reference to a member of an object block, try rewriting
+   it to use an anchor instead.  Return the new memory reference on success
+   and the old one on failure.  */
+
+rtx
+use_anchored_address (rtx x)
+{
+  rtx base;
+  HOST_WIDE_INT offset;
+
+  if (!flag_section_anchors)
+    return x;
+
+  if (!MEM_P (x))
+    return x;
+
+  /* Split the address into a base and offset.  */
+  base = XEXP (x, 0);
+  offset = 0;
+  if (GET_CODE (base) == CONST
+      && GET_CODE (XEXP (base, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (base, 0), 1)) == CONST_INT)
+    {
+      offset += INTVAL (XEXP (XEXP (base, 0), 1));
+      base = XEXP (XEXP (base, 0), 0);
+    }
+
+  /* Check whether BASE is suitable for anchors.  */
+  if (GET_CODE (base) != SYMBOL_REF
+      || !SYMBOL_REF_HAS_BLOCK_INFO_P (base)
+      || SYMBOL_REF_ANCHOR_P (base)
+      || SYMBOL_REF_BLOCK (base) == NULL
+      || !targetm.use_anchors_for_symbol_p (base))
+    return x;
+
+  /* Decide where BASE is going to be.  */
+  place_block_symbol (base);
+
+  /* Get the anchor we need to use.  */
+  offset += SYMBOL_REF_BLOCK_OFFSET (base);
+  base = get_section_anchor (SYMBOL_REF_BLOCK (base), offset,
+                            SYMBOL_REF_TLS_MODEL (base));
+
+  /* Work out the offset from the anchor.  */
+  offset -= SYMBOL_REF_BLOCK_OFFSET (base);
+
+  /* If we're going to run a CSE pass, force the anchor into a register.
+     We will then be able to reuse registers for several accesses, if the
+     target costs say that that's worthwhile.  */
+  if (!cse_not_expected)
+    base = force_reg (GET_MODE (base), base);
+
+  return replace_equiv_address (x, plus_constant (base, offset));
+}
 \f
 /* Copy the value or contents of X to a new temp reg and return that reg.  */
 
@@ -656,6 +697,8 @@ force_reg (enum machine_mode mode, rtx x)
 
        align = MIN (sa, ca);
       }
+    else if (MEM_P (x) && MEM_POINTER (x))
+      align = MEM_ALIGN (x);
 
     if (align)
       mark_reg_pointer (temp, align);
@@ -713,10 +756,10 @@ copy_to_suggested_reg (rtx x, rtx target, enum machine_mode mode)
 #endif
 
 enum machine_mode
-promote_mode (tree type, enum machine_mode mode, int *punsignedp,
+promote_mode (const_tree type, enum machine_mode mode, int *punsignedp,
              int for_call ATTRIBUTE_UNUSED)
 {
-  enum tree_code code = TREE_CODE (type);
+  const enum tree_code code = TREE_CODE (type);
   int unsignedp = *punsignedp;
 
 #ifndef PROMOTE_MODE
@@ -728,7 +771,7 @@ promote_mode (tree type, enum machine_mode mode, int *punsignedp,
     {
 #ifdef PROMOTE_FUNCTION_MODE
     case INTEGER_TYPE:   case ENUMERAL_TYPE:   case BOOLEAN_TYPE:
-    case CHAR_TYPE:      case REAL_TYPE:       case OFFSET_TYPE:
+    case REAL_TYPE:      case OFFSET_TYPE:     case FIXED_POINT_TYPE:
 #ifdef PROMOTE_MODE
       if (for_call)
        {
@@ -1404,24 +1447,19 @@ probe_stack_range (HOST_WIDE_INT first, rtx size)
 /* Return an rtx representing the register or memory location
    in which a scalar value of data type VALTYPE
    was returned by a function call to function FUNC.
-   FUNC is a FUNCTION_DECL node if the precise function is known,
-   otherwise 0.
+   FUNC is a FUNCTION_DECL, FNTYPE a FUNCTION_TYPE node if the precise
+   function is known, otherwise 0.
    OUTGOING is 1 if on a machine with register windows this function
    should return the register in which the function will put its result
    and 0 otherwise.  */
 
 rtx
-hard_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
+hard_function_value (const_tree valtype, const_tree func, const_tree fntype,
                     int outgoing ATTRIBUTE_UNUSED)
 {
   rtx val;
 
-#ifdef FUNCTION_OUTGOING_VALUE
-  if (outgoing)
-    val = FUNCTION_OUTGOING_VALUE (valtype, func);
-  else
-#endif
-    val = FUNCTION_VALUE (valtype, func);
+  val = targetm.calls.function_value (valtype, func ? func : fntype, outgoing);
 
   if (REG_P (val)
       && GET_MODE (val) == BLKmode)