OSDN Git Service

* jump.c (jump_optimize, follow_jumps, mark_jump_label): Disable some
[pf3gnuchains/gcc-fork.git] / gcc / explow.c
index ac73f4b..db0fbc8 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for manipulating rtx's in semantically interesting ways.
-   Copyright (C) 1987, 1991, 1994, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 91, 94, 95, 96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include "config.h"
@@ -30,7 +31,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "insn-codes.h"
 
 static rtx break_out_memory_refs       PROTO((rtx));
-static rtx convert_memory_address      PROTO((rtx));
 
 /* Return an rtx for the sum of X and the integer C.
 
@@ -294,32 +294,57 @@ break_out_memory_refs (x)
 #ifdef POINTERS_EXTEND_UNSIGNED
 
 /* Given X, a memory address in ptr_mode, convert it to an address
-   in Pmode.  We take advantage of the fact that pointers are not
-   allowed to overflow by commuting arithmetic operations over
-   conversions so that address arithmetic insns can be used.  */
+   in Pmode, or vice versa (TO_MODE says which way).  We take advantage of
+   the fact that pointers are not allowed to overflow by commuting arithmetic
+   operations over conversions so that address arithmetic insns can be
+   used.  */
 
-static rtx
-convert_memory_address (x)
+rtx
+convert_memory_address (to_mode, x)
+     enum machine_mode to_mode;
      rtx x;
 {
+  enum machine_mode from_mode = to_mode == ptr_mode ? Pmode : ptr_mode;
+  rtx temp;
+
+  /* Here we handle some special cases.  If none of them apply, fall through
+     to the default case.  */
   switch (GET_CODE (x))
     {
     case CONST_INT:
     case CONST_DOUBLE:
+      return x;
+
     case LABEL_REF:
+      return gen_rtx (LABEL_REF, to_mode, XEXP (x, 0));
+
     case SYMBOL_REF:
+      temp = gen_rtx (SYMBOL_REF, to_mode, XSTR (x, 0));
+      SYMBOL_REF_FLAG (temp) = SYMBOL_REF_FLAG (x);
+      CONSTANT_POOL_ADDRESS_P (temp) = CONSTANT_POOL_ADDRESS_P (x);
+      return temp;
+
     case CONST:
-      return x;
+      return gen_rtx (CONST, to_mode, 
+                     convert_memory_address (to_mode, XEXP (x, 0)));
 
     case PLUS:
     case MULT:
-      return gen_rtx (GET_CODE (x), Pmode, 
-                     convert_memory_address (XEXP (x, 0)),
-                     convert_memory_address (XEXP (x, 1)));
-
-    default:
-      return convert_modes (Pmode, ptr_mode, x, POINTERS_EXTEND_UNSIGNED);
+      /* For addition the second operand is a small constant, we can safely
+        permute the converstion and addition operation.  We can always safely
+        permute them if we are making the address narrower.  In addition,
+        always permute the operations if this is a constant.  */
+      if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode)
+         || (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT
+             && (INTVAL (XEXP (x, 1)) + 20000 < 40000
+                 || CONSTANT_P (XEXP (x, 0)))))
+       return gen_rtx (GET_CODE (x), to_mode, 
+                       convert_memory_address (to_mode, XEXP (x, 0)),
+                       convert_memory_address (to_mode, XEXP (x, 1)));
     }
+
+  return convert_modes (to_mode, from_mode,
+                       x, POINTERS_EXTEND_UNSIGNED);
 }
 #endif
 
@@ -375,7 +400,7 @@ memory_address (mode, x)
 
 #ifdef POINTERS_EXTEND_UNSIGNED
   if (GET_MODE (x) == ptr_mode)
-    x = convert_memory_address (x);
+    x = convert_memory_address (Pmode, x);
 #endif
 
   /* By passing constant addresses thru registers
@@ -478,11 +503,11 @@ memory_address (mode, x)
   if (oldx == x)
     return x;
   else if (GET_CODE (x) == REG)
-    mark_reg_pointer (x);
+    mark_reg_pointer (x, 1);
   else if (GET_CODE (x) == PLUS
           && GET_CODE (XEXP (x, 0)) == REG
           && GET_CODE (XEXP (x, 1)) == CONST_INT)
-    mark_reg_pointer (XEXP (x, 0));
+    mark_reg_pointer (XEXP (x, 0), 1);
 
   /* OLDX may have been the address on a temporary.  Update the address
      to indicate that X is now used.  */
@@ -708,6 +733,7 @@ promote_mode (type, mode, punsignedp, for_call)
 #endif
 
 #ifdef POINTERS_EXTEND_UNSIGNED
+    case REFERENCE_TYPE:
     case POINTER_TYPE:
       mode = Pmode;
       unsignedp = POINTERS_EXTEND_UNSIGNED;
@@ -791,7 +817,8 @@ round_push (size)
   else
     {
       /* CEIL_DIV_EXPR needs to worry about the addition overflowing,
-        but we know it can't.  So add ourselves and then do TRUNC_DIV_EXPR. */
+        but we know it can't.  So add ourselves and then do
+        TRUNC_DIV_EXPR.  */
       size = expand_binop (Pmode, add_optab, size, GEN_INT (align - 1),
                           NULL_RTX, 1, OPTAB_LIB_WIDEN);
       size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size, GEN_INT (align),
@@ -968,7 +995,7 @@ allocate_dynamic_stack_space (size, target, known_align)
      int known_align;
 {
   /* If we're asking for zero bytes, it doesn't matter what we point
-     to since we can't derefference it.  But return a reasonable
+     to since we can't dereference it.  But return a reasonable
      address anyway.  */
   if (size == const0_rtx)
     return virtual_stack_dynamic_rtx;
@@ -993,7 +1020,7 @@ allocate_dynamic_stack_space (size, target, known_align)
      If we have to align, we must leave space in SIZE for the hole
      that might result from the alignment operation.  */
 
-#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET) || defined (ALLOCATE_OUTGOING_ARGS) || ! defined (STACK_BOUNDARY)
+#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET) || ! defined (STACK_BOUNDARY)
 #define MUST_ALIGN 1
 #else
 #define MUST_ALIGN (STACK_BOUNDARY < BIGGEST_ALIGNMENT)
@@ -1055,7 +1082,7 @@ allocate_dynamic_stack_space (size, target, known_align)
       || REGNO (target) < FIRST_PSEUDO_REGISTER)
     target = gen_reg_rtx (Pmode);
 
-  mark_reg_pointer (target);
+  mark_reg_pointer (target, known_align / BITS_PER_UNIT);
 
 #ifndef STACK_GROWS_DOWNWARD
   emit_move_insn (target, virtual_stack_dynamic_rtx);
@@ -1093,7 +1120,8 @@ allocate_dynamic_stack_space (size, target, known_align)
   if (MUST_ALIGN)
     {
       /* CEIL_DIV_EXPR needs to worry about the addition overflowing,
-        but we know it can't.  So add ourselves and then do TRUNC_DIV_EXPR. */
+        but we know it can't.  So add ourselves and then do
+        TRUNC_DIV_EXPR.  */
       target = expand_binop (Pmode, add_optab, target,
                             GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1),
                             NULL_RTX, 1, OPTAB_LIB_WIDEN);