OSDN Git Service

* jump.c (jump_optimize, follow_jumps, mark_jump_label): Disable some
[pf3gnuchains/gcc-fork.git] / gcc / explow.c
index 1c94b81..db0fbc8 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for manipulating rtx's in semantically interesting ways.
-   Copyright (C) 1987, 1991, 1994 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"
@@ -29,6 +30,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "insn-flags.h"
 #include "insn-codes.h"
 
+static rtx break_out_memory_refs       PROTO((rtx));
+
 /* Return an rtx for the sum of X and the integer C.
 
    This function should be used via the `plus_constant' macro.  */
@@ -288,6 +291,63 @@ break_out_memory_refs (x)
   return x;
 }
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+
+/* Given X, a memory address in ptr_mode, convert it to an address
+   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.  */
+
+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 gen_rtx (CONST, to_mode, 
+                     convert_memory_address (to_mode, XEXP (x, 0)));
+
+    case PLUS:
+    case MULT:
+      /* 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
+
 /* Given a memory address or facsimile X, construct a new address,
    currently equivalent, that is stable: future stores won't change it.
 
@@ -338,6 +398,11 @@ memory_address (mode, x)
 {
   register rtx oldx = x;
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+  if (GET_MODE (x) == ptr_mode)
+    x = convert_memory_address (Pmode, x);
+#endif
+
   /* By passing constant addresses thru registers
      we get a chance to cse them.  */
   if (! cse_not_expected && CONSTANT_P (x) && CONSTANT_ADDRESS_P (x))
@@ -400,7 +465,7 @@ memory_address (mode, x)
            }
        }
 
-      if (GET_CODE (x) == MULT || GET_CODE (x) == MINUS)
+      else if (GET_CODE (x) == MULT || GET_CODE (x) == MINUS)
        x = force_operand (x, NULL_RTX);
 
       /* If we have a register that's an invalid address,
@@ -438,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.  */
@@ -578,15 +643,19 @@ force_reg (mode, x)
      enum machine_mode mode;
      rtx x;
 {
-  register rtx temp, insn;
+  register rtx temp, insn, set;
 
   if (GET_CODE (x) == REG)
     return x;
   temp = gen_reg_rtx (mode);
   insn = emit_move_insn (temp, x);
+
   /* Let optimizers know that TEMP's value never changes
-     and that X can be substituted for it.  */
-  if (CONSTANT_P (x))
+     and that X can be substituted for it.  Don't get confused
+     if INSN set something else (such as a SUBREG of TEMP).  */
+  if (CONSTANT_P (x)
+      && (set = single_set (insn)) != 0
+      && SET_DEST (set) == temp)
     {
       rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
 
@@ -663,8 +732,13 @@ promote_mode (type, mode, punsignedp, for_call)
       break;
 #endif
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+    case REFERENCE_TYPE:
     case POINTER_TYPE:
+      mode = Pmode;
+      unsignedp = POINTERS_EXTEND_UNSIGNED;
       break;
+#endif
     }
 
   *punsignedp = unsignedp;
@@ -743,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),
@@ -920,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;
@@ -945,24 +1020,13 @@ 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)
-#define MUST_ALIGN
-#endif
-
-#if ! defined (MUST_ALIGN) && (!defined(STACK_BOUNDARY) || STACK_BOUNDARY < BIGGEST_ALIGNMENT)
-#define MUST_ALIGN
+#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET) || ! defined (STACK_BOUNDARY)
+#define MUST_ALIGN 1
+#else
+#define MUST_ALIGN (STACK_BOUNDARY < BIGGEST_ALIGNMENT)
 #endif
 
-#ifdef MUST_ALIGN
-
-#if 0 /* It turns out we must always make extra space, if MUST_ALIGN
-        because we must always round the address up at the end,
-        because we don't know whether the dynamic offset
-        will mess up the desired alignment.  */
-  /* If we have to round the address up regardless of known_align,
-     make extra space regardless, also.  */
-  if (known_align % BIGGEST_ALIGNMENT != 0)
-#endif
+  if (MUST_ALIGN)
     {
       if (GET_CODE (size) == CONST_INT)
        size = GEN_INT (INTVAL (size)
@@ -973,8 +1037,6 @@ allocate_dynamic_stack_space (size, target, known_align)
                             NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
 
-#endif
-
 #ifdef SETJMP_VIA_SAVE_AREA
   /* If setjmp restores regs from a save area in the stack frame,
      avoid clobbering the reg save area.  Note that the offset of
@@ -1007,8 +1069,8 @@ allocate_dynamic_stack_space (size, target, known_align)
 #ifdef STACK_BOUNDARY
   /* If we added a variable amount to SIZE,
      we can no longer assume it is aligned.  */
-#if !defined (SETJMP_VIA_SAVE_AREA) && !defined (MUST_ALIGN)
-  if (known_align % STACK_BOUNDARY != 0)
+#if !defined (SETJMP_VIA_SAVE_AREA)
+  if (MUST_ALIGN || known_align % STACK_BOUNDARY != 0)
 #endif
     size = round_push (size);
 #endif
@@ -1020,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);
@@ -1035,6 +1097,8 @@ allocate_dynamic_stack_space (size, target, known_align)
       enum machine_mode mode
        = insn_operand_mode[(int) CODE_FOR_allocate_stack][0];
 
+      size = convert_modes (mode, ptr_mode, size, 1);
+
       if (insn_operand_predicate[(int) CODE_FOR_allocate_stack][0]
          && ! ((*insn_operand_predicate[(int) CODE_FOR_allocate_stack][0])
                (size, mode)))
@@ -1044,21 +1108,20 @@ allocate_dynamic_stack_space (size, target, known_align)
     }
   else
 #endif
-    anti_adjust_stack (size);
+    {
+      size = convert_modes (Pmode, ptr_mode, size, 1);
+      anti_adjust_stack (size);
+    }
 
 #ifdef STACK_GROWS_DOWNWARD
   emit_move_insn (target, virtual_stack_dynamic_rtx);
 #endif
 
-#ifdef MUST_ALIGN
-#if 0  /* Even if we know the stack pointer has enough alignment,
-         there's no way to tell whether virtual_stack_dynamic_rtx shares that
-         alignment, so we still need to round the address up.  */
-  if (known_align % BIGGEST_ALIGNMENT != 0)
-#endif
+  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);
@@ -1069,7 +1132,6 @@ allocate_dynamic_stack_space (size, target, known_align)
                            GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),
                            NULL_RTX, 1);
     }
-#endif
   
   /* Some systems require a particular insn to refer to the stack
      to make the pages exist.  */
@@ -1096,7 +1158,28 @@ hard_function_value (valtype, func)
      tree valtype;
      tree func;
 {
-  return FUNCTION_VALUE (valtype, func);
+  rtx val = FUNCTION_VALUE (valtype, func);
+  if (GET_CODE (val) == REG
+      && GET_MODE (val) == BLKmode)
+    {
+      int bytes = int_size_in_bytes (valtype);
+      enum machine_mode tmpmode;
+      for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+           tmpmode != MAX_MACHINE_MODE;
+           tmpmode = GET_MODE_WIDER_MODE (tmpmode))
+        {
+          /* Have we found a large enough mode?  */
+          if (GET_MODE_SIZE (tmpmode) >= bytes)
+            break;
+        }
+
+      /* No suitable mode found.  */
+      if (tmpmode == MAX_MACHINE_MODE)
+        abort ();
+
+      PUT_MODE (val, tmpmode);
+    }      
+  return val;
 }
 
 /* Return an rtx representing the register or memory location