OSDN Git Service

2003-06-10 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / explow.c
index 7a770ee..ec7a69a 100644 (file)
@@ -22,6 +22,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "toplev.h"
 #include "rtl.h"
 #include "tree.h"
@@ -34,6 +36,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "insn-config.h"
 #include "ggc.h"
 #include "recog.h"
+#include "langhooks.h"
 
 static rtx break_out_memory_refs       PARAMS ((rtx));
 static void emit_stack_probe           PARAMS ((rtx));
@@ -48,6 +51,10 @@ trunc_int_for_mode (c, mode)
 {
   int width = GET_MODE_BITSIZE (mode);
 
+  /* You want to truncate to a _what_?  */
+  if (! SCALAR_INT_MODE_P (mode))
+    abort ();
+
   /* Canonicalize BImode to 0 and STORE_FLAG_VALUE.  */
   if (mode == BImode)
     return c & 1 ? STORE_FLAG_VALUE : 0;
@@ -285,20 +292,32 @@ rtx
 expr_size (exp)
      tree exp;
 {
-  tree size;
+  tree size = (*lang_hooks.expr_size) (exp);
 
-  if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd'
-      && DECL_SIZE_UNIT (exp) != 0)
-    size = DECL_SIZE_UNIT (exp);
-  else
-    size = size_in_bytes (TREE_TYPE (exp));
-
-  if (TREE_CODE (size) != INTEGER_CST
-      && contains_placeholder_p (size))
+  if (CONTAINS_PLACEHOLDER_P (size))
     size = build (WITH_RECORD_EXPR, sizetype, size, exp);
 
   return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), 0);
+}
+
+/* Return a wide integer for the size in bytes of the value of EXP, or -1
+   if the size can vary or is larger than an integer.  */
+
+HOST_WIDE_INT
+int_expr_size (exp)
+     tree exp;
+{
+  tree t = (*lang_hooks.expr_size) (exp);
+
+  if (t == 0
+      || TREE_CODE (t) != INTEGER_CST
+      || TREE_OVERFLOW (t)
+      || TREE_INT_CST_HIGH (t) != 0
+      /* If the result would appear negative, it's too big to represent.  */
+      || (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0)
+    return -1;
 
+  return TREE_INT_CST_LOW (t);
 }
 \f
 /* Return a copy of X in which all memory references
@@ -353,6 +372,7 @@ convert_memory_address (to_mode, x)
 {
   enum machine_mode from_mode = to_mode == ptr_mode ? Pmode : ptr_mode;
   rtx temp;
+  enum rtx_code code;
 
   /* Here we handle some special cases.  If none of them apply, fall through
      to the default case.  */
@@ -360,55 +380,55 @@ convert_memory_address (to_mode, x)
     {
     case CONST_INT:
     case CONST_DOUBLE:
-      return x;
+      if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode))
+       code = TRUNCATE;
+      else if (POINTERS_EXTEND_UNSIGNED < 0)
+       break;
+      else if (POINTERS_EXTEND_UNSIGNED > 0)
+       code = ZERO_EXTEND;
+      else
+       code = SIGN_EXTEND;
+      temp = simplify_unary_operation (code, to_mode, x, from_mode);
+      if (temp)
+       return temp;
+      break;
 
     case SUBREG:
-      if (POINTERS_EXTEND_UNSIGNED >= 0
-         && (SUBREG_PROMOTED_VAR_P (x) || REG_POINTER (SUBREG_REG (x)))
+      if ((SUBREG_PROMOTED_VAR_P (x) || REG_POINTER (SUBREG_REG (x)))
          && GET_MODE (SUBREG_REG (x)) == to_mode)
        return SUBREG_REG (x);
       break;
 
     case LABEL_REF:
-      if (POINTERS_EXTEND_UNSIGNED >= 0)
-       {
-         temp = gen_rtx_LABEL_REF (to_mode, XEXP (x, 0));
-         LABEL_REF_NONLOCAL_P (temp) = LABEL_REF_NONLOCAL_P (x);
-         return temp;
-       }
+      temp = gen_rtx_LABEL_REF (to_mode, XEXP (x, 0));
+      LABEL_REF_NONLOCAL_P (temp) = LABEL_REF_NONLOCAL_P (x);
+      return temp;
       break;
 
     case SYMBOL_REF:
-      if (POINTERS_EXTEND_UNSIGNED >= 0)
-       {
-         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);
-         STRING_POOL_ADDRESS_P (temp) = STRING_POOL_ADDRESS_P (x);
-         return temp;
-       }
+      temp = shallow_copy_rtx (x);
+      PUT_MODE (temp, to_mode);
+      return temp;
       break;
 
     case CONST:
-      if (POINTERS_EXTEND_UNSIGNED >= 0)
-        return gen_rtx_CONST (to_mode,
-                             convert_memory_address (to_mode, XEXP (x, 0)));
+      return gen_rtx_CONST (to_mode,
+                           convert_memory_address (to_mode, XEXP (x, 0)));
       break;
 
     case PLUS:
     case MULT:
-      /* For addition the second operand is a small constant, we can safely
-        permute the conversion 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 (POINTERS_EXTEND_UNSIGNED >= 0
-         && (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))))))
+      /* 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.  */
+      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))))
        return gen_rtx_fmt_ee (GET_CODE (x), to_mode,
                               convert_memory_address (to_mode, XEXP (x, 0)),
-                              convert_memory_address (to_mode, XEXP (x, 1)));
+                              XEXP (x, 1));
       break;
 
     default:
@@ -636,11 +656,20 @@ maybe_set_unchanging (ref, t)
   /* We can set RTX_UNCHANGING_P from TREE_READONLY for decls whose
      initialization is only executed once, or whose initializer always
      has the same value.  Currently we simplify this to PARM_DECLs in the
-     first case, and decls with TREE_CONSTANT initializers in the second.  */
+     first case, and decls with TREE_CONSTANT initializers in the second.
+
+     We cannot do this for non-static aggregates, because of the double
+     writes that can be generated by store_constructor, depending on the
+     contents of the initializer.  Yes, this does eliminate a good fraction
+     of the number of uses of RTX_UNCHANGING_P for a language like Ada.
+     It also eliminates a good quantity of bugs.  Let this be incentive to
+     eliminate RTX_UNCHANGING_P entirely in favour of a more reliable
+     solution, perhaps based on alias sets.  */
+
   if ((TREE_READONLY (t) && DECL_P (t)
+       && (TREE_STATIC (t) || ! AGGREGATE_TYPE_P (TREE_TYPE (t)))
        && (TREE_CODE (t) == PARM_DECL
-          || DECL_INITIAL (t) == NULL_TREE
-          || TREE_CONSTANT (DECL_INITIAL (t))))
+          || (DECL_INITIAL (t) && TREE_CONSTANT (DECL_INITIAL (t)))))
       || TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
     RTX_UNCHANGING_P (ref) = 1;
 }
@@ -654,7 +683,6 @@ rtx
 stabilize (x)
      rtx x;
 {
-
   if (GET_CODE (x) != MEM
       || ! rtx_unstable_p (XEXP (x, 0)))
     return x;
@@ -755,7 +783,8 @@ force_reg (mode, x)
      if INSN set something else (such as a SUBREG of TEMP).  */
   if (CONSTANT_P (x)
       && (set = single_set (insn)) != 0
-      && SET_DEST (set) == temp)
+      && SET_DEST (set) == temp
+      && ! rtx_equal_p (x, SET_SRC (set)))
     set_unique_reg_note (insn, REG_EQUAL, x);
 
   return temp;
@@ -802,7 +831,7 @@ copy_to_suggested_reg (x, target, mode)
    PUNSIGNEDP points to the signedness of the type and may be adjusted
    to show what signedness to use on extension operations.
 
-   FOR_CALL is non-zero if this call is promoting args for a call.  */
+   FOR_CALL is nonzero if this call is promoting args for a call.  */
 
 enum machine_mode
 promote_mode (type, mode, punsignedp, for_call)
@@ -914,11 +943,14 @@ round_push (size)
      rtx size;
 {
   int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+
   if (align == 1)
     return size;
+
   if (GET_CODE (size) == CONST_INT)
     {
-      int new = (INTVAL (size) + align - 1) / align * align;
+      HOST_WIDE_INT new = (INTVAL (size) + align - 1) / align * align;
+
       if (INTVAL (size) != new)
        size = GEN_INT (new);
     }
@@ -933,6 +965,7 @@ round_push (size)
                            NULL_RTX, 1);
       size = expand_mult (Pmode, size, GEN_INT (align), NULL_RTX, 1);
     }
+
   return size;
 }
 \f
@@ -1009,7 +1042,7 @@ emit_stack_save (save_level, psave, after)
       if (sa != 0)
        sa = validize_mem (sa);
       emit_insn (fcn (sa, stack_pointer_rtx));
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
       emit_insn_after (seq, after);
     }
@@ -1062,7 +1095,17 @@ emit_stack_restore (save_level, sa, after)
     }
 
   if (sa != 0)
-    sa = validize_mem (sa);
+    {
+      sa = validize_mem (sa);
+      /* These clobbers prevent the scheduler from moving
+        references to variable arrays below the code
+        that deletes (pops) the arrays.  */
+      emit_insn (gen_rtx_CLOBBER (VOIDmode,
+                   gen_rtx_MEM (BLKmode, 
+                       gen_rtx_SCRATCH (VOIDmode))));
+      emit_insn (gen_rtx_CLOBBER (VOIDmode,
+                   gen_rtx_MEM (BLKmode, stack_pointer_rtx)));
+    }
 
   if (after)
     {
@@ -1070,7 +1113,7 @@ emit_stack_restore (save_level, sa, after)
 
       start_sequence ();
       emit_insn (fcn (stack_pointer_rtx, sa));
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
       emit_insn_after (seq, after);
     }
@@ -1202,7 +1245,7 @@ allocate_dynamic_stack_space (size, target, known_align)
      always know its final value at this point in the compilation (it
      might depend on the size of the outgoing parameter lists, for
      example), so we must align the value to be returned in that case.
-     (Note that STACK_DYNAMIC_OFFSET will have a default non-zero value if
+     (Note that STACK_DYNAMIC_OFFSET will have a default nonzero value if
      STACK_POINTER_OFFSET or ACCUMULATE_OUTGOING_ARGS are defined).
      We must also do an alignment operation on the returned value if
      the stack pointer alignment is less strict that BIGGEST_ALIGNMENT.
@@ -1334,7 +1377,7 @@ allocate_dynamic_stack_space (size, target, known_align)
 
       pred = insn_data[(int) CODE_FOR_allocate_stack].operand[1].predicate;
       if (pred && ! ((*pred) (size, mode)))
-       size = copy_to_mode_reg (mode, size);
+       size = copy_to_mode_reg (mode, convert_to_mode (mode, size, 1));
 
       emit_insn (gen_allocate_stack (target, size));
     }
@@ -1375,7 +1418,7 @@ allocate_dynamic_stack_space (size, target, known_align)
 #ifdef SETJMP_VIA_SAVE_AREA
       if (setjmpless_size != NULL_RTX)
        {
-         rtx note_target = get_last_insn ();
+         rtx note_target = get_last_insn ();
 
          REG_NOTES (note_target)
            = gen_rtx_EXPR_LIST (REG_SAVE_AREA, setjmpless_size,
@@ -1404,13 +1447,6 @@ allocate_dynamic_stack_space (size, target, known_align)
                            NULL_RTX, 1);
     }
 
-  /* Some systems require a particular insn to refer to the stack
-     to make the pages exist.  */
-#ifdef HAVE_probe
-  if (HAVE_probe)
-    emit_insn (gen_probe ());
-#endif
-
   /* Record the new stack level for nonlocal gotos.  */
   if (nonlocal_goto_handler_slots != 0)
     emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
@@ -1422,14 +1458,13 @@ allocate_dynamic_stack_space (size, target, known_align)
    run-time routine to call to check the stack, so provide a mechanism for
    calling that routine.  */
 
-static rtx stack_check_libfunc;
+static GTY(()) rtx stack_check_libfunc;
 
 void
 set_stack_check_libfunc (libfunc)
      rtx libfunc;
 {
   stack_check_libfunc = libfunc;
-  ggc_add_rtx_root (&stack_check_libfunc, 1);
 }
 \f
 /* Emit one stack probe at ADDRESS, an address within the stack.  */
@@ -1474,9 +1509,9 @@ probe_stack_range (first, size)
   if (stack_check_libfunc != 0)
     {
       rtx addr = memory_address (QImode,
-                                gen_rtx (STACK_GROW_OP, Pmode,
-                                         stack_pointer_rtx,
-                                         plus_constant (size, first)));
+                                gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+                                                stack_pointer_rtx,
+                                                plus_constant (size, first)));
 
 #ifdef POINTERS_EXTEND_UNSIGNED
       if (GET_MODE (addr) != ptr_mode)
@@ -1493,9 +1528,9 @@ probe_stack_range (first, size)
     {
       insn_operand_predicate_fn pred;
       rtx last_addr
-       = force_operand (gen_rtx_STACK_GROW_OP (Pmode,
-                                               stack_pointer_rtx,
-                                               plus_constant (size, first)),
+       = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+                                        stack_pointer_rtx,
+                                        plus_constant (size, first)),
                         NULL_RTX);
 
       pred = insn_data[(int) CODE_FOR_check_stack].operand[0].predicate;
@@ -1620,17 +1655,17 @@ hard_function_value (valtype, func, outgoing)
         will match and we will abort later in this function.  */
 
       for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-           tmpmode != VOIDmode;
-           tmpmode = GET_MODE_WIDER_MODE (tmpmode))
-        {
-          /* Have we found a large enough mode?  */
-          if (GET_MODE_SIZE (tmpmode) >= bytes)
-            break;
-        }
+          tmpmode != VOIDmode;
+          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 == VOIDmode)
-        abort ();
+       abort ();
 
       PUT_MODE (val, tmpmode);
     }
@@ -1684,3 +1719,5 @@ rtx_to_tree_code (code)
     }
   return ((int) tcode);
 }
+
+#include "gt-explow.h"