OSDN Git Service

* config/sparc/sparc.md (movdi_insn_sp64_novis): New pattern.
[pf3gnuchains/gcc-fork.git] / gcc / explow.c
index 92f99ad..0f067ca 100644 (file)
@@ -1,5 +1,6 @@
 /* Subroutines for manipulating rtx's in semantically interesting ways.
-   Copyright (C) 1987, 91, 94-97, 1998, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1991, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -24,7 +25,9 @@ Boston, MA 02111-1307, USA.  */
 #include "toplev.h"
 #include "rtl.h"
 #include "tree.h"
+#include "tm_p.h"
 #include "flags.h"
+#include "function.h"
 #include "expr.h"
 #include "hard-reg-set.h"
 #include "insn-config.h"
@@ -36,8 +39,8 @@ Boston, MA 02111-1307, USA.  */
 #define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
 #endif
 
-static rtx break_out_memory_refs       PROTO((rtx));
-static void emit_stack_probe           PROTO((rtx));
+static rtx break_out_memory_refs       PARAMS ((rtx));
+static void emit_stack_probe           PARAMS ((rtx));
 
 
 /* Truncate and perhaps sign-extend C as appropriate for MODE.  */
@@ -214,7 +217,7 @@ plus_constant_for_output_wide (x, c)
 
   if (GET_CODE (x) == LO_SUM)
     return gen_rtx_LO_SUM (mode, XEXP (x, 0),
-                   plus_constant_for_output (XEXP (x, 1), c));
+                          plus_constant_for_output (XEXP (x, 1), c));
 
   else
     return plus_constant (x, c);
@@ -580,11 +583,11 @@ memory_address (mode, x)
   if (oldx == x)
     return x;
   else if (GET_CODE (x) == REG)
-    mark_reg_pointer (x, 1);
+    mark_reg_pointer (x, BITS_PER_UNIT);
   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), 1);
+    mark_reg_pointer (XEXP (x, 0), BITS_PER_UNIT);
 
   /* OLDX may have been the address on a temporary.  Update the address
      to indicate that X is now used.  */
@@ -730,7 +733,12 @@ force_reg (mode, x)
 
   if (GET_CODE (x) == REG)
     return x;
+  
   temp = gen_reg_rtx (mode);
+  
+  if (! general_operand (x, mode))
+    x = force_operand (x, NULL_RTX);
+  
   insn = emit_move_insn (temp, x);
 
   /* Let optimizers know that TEMP's value never changes
@@ -844,6 +852,11 @@ adjust_stack (adjust)
   if (adjust == const0_rtx)
     return;
 
+  /* We expect all variable sized adjustments to be multiple of
+     PREFERRED_STACK_BOUNDARY.  */
+  if (GET_CODE (adjust) == CONST_INT)
+    stack_pointer_delta -= INTVAL (adjust);
+
   temp = expand_binop (Pmode,
 #ifdef STACK_GROWS_DOWNWARD
                       add_optab,
@@ -870,6 +883,11 @@ anti_adjust_stack (adjust)
   if (adjust == const0_rtx)
     return;
 
+  /* We expect all variable sized adjustments to be multiple of
+     PREFERRED_STACK_BOUNDARY.  */
+  if (GET_CODE (adjust) == CONST_INT)
+    stack_pointer_delta += INTVAL (adjust);
+
   temp = expand_binop (Pmode,
 #ifdef STACK_GROWS_DOWNWARD
                       sub_optab,
@@ -931,7 +949,7 @@ emit_stack_save (save_level, psave, after)
 {
   rtx sa = *psave;
   /* The default is that we use a move insn and save in a Pmode object.  */
-  rtx (*fcn) PROTO ((rtx, rtx)) = gen_move_insn;
+  rtx (*fcn) PARAMS ((rtx, rtx)) = gen_move_insn;
   enum machine_mode mode = STACK_SAVEAREA_MODE (save_level);
 
   /* See if this machine has anything special to do for this kind of save.  */
@@ -1013,7 +1031,7 @@ emit_stack_restore (save_level, sa, after)
      rtx sa;
 {
   /* The default is that we use a move insn.  */
-  rtx (*fcn) PROTO ((rtx, rtx)) = gen_move_insn;
+  rtx (*fcn) PARAMS ((rtx, rtx)) = gen_move_insn;
 
   /* See if this machine has anything special to do for this kind of save.  */
   switch (save_level)
@@ -1171,6 +1189,13 @@ allocate_dynamic_stack_space (size, target, known_align)
   if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
     size = convert_to_mode (Pmode, size, 1);
 
+  /* We can't attempt to minimize alignment necessary, because we don't
+     know the final value of preferred_stack_boundary yet while executing
+     this code.  */
+#ifdef PREFERRED_STACK_BOUNDARY
+  cfun->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
+#endif
+
   /* We will need to ensure that the address we return is aligned to
      BIGGEST_ALIGNMENT.  If STACK_DYNAMIC_OFFSET is defined, we don't
      always know its final value at this point in the compilation (it 
@@ -1280,6 +1305,13 @@ allocate_dynamic_stack_space (size, target, known_align)
 
   do_pending_stack_adjust ();
 
+ /* We ought to be called always on the toplevel and stack ought to be aligned
+    propertly.  */
+#ifdef PREFERRED_STACK_BOUNDARY
+  if (stack_pointer_delta % (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT))
+    abort ();
+#endif
+
   /* If needed, check that we have the required amount of stack.  Take into
      account what has already been checked.  */
   if (flag_stack_check && ! STACK_CHECK_BUILTIN)
@@ -1290,7 +1322,7 @@ allocate_dynamic_stack_space (size, target, known_align)
       || REGNO (target) < FIRST_PSEUDO_REGISTER)
     target = gen_reg_rtx (Pmode);
 
-  mark_reg_pointer (target, known_align / BITS_PER_UNIT);
+  mark_reg_pointer (target, known_align);
 
   /* Perform the required allocation from the stack.  Some systems do
      this differently than simply incrementing/decrementing from the
@@ -1299,19 +1331,22 @@ allocate_dynamic_stack_space (size, target, known_align)
   if (HAVE_allocate_stack)
     {
       enum machine_mode mode = STACK_SIZE_MODE;
+      insn_operand_predicate_fn pred;
 
-      if (insn_operand_predicate[(int) CODE_FOR_allocate_stack][0]
-         && ! ((*insn_operand_predicate[(int) CODE_FOR_allocate_stack][0])
-               (target, Pmode)))
+      pred = insn_data[(int) CODE_FOR_allocate_stack].operand[0].predicate;
+      if (pred && ! ((*pred) (target, Pmode)))
 #ifdef POINTERS_EXTEND_UNSIGNED
        target = convert_memory_address (Pmode, target);
 #else
        target = copy_to_mode_reg (Pmode, target);
 #endif
+
+      if (mode == VOIDmode)
+       mode = Pmode;
+
       size = convert_modes (mode, ptr_mode, size, 1);
-      if (insn_operand_predicate[(int) CODE_FOR_allocate_stack][1]
-         && ! ((*insn_operand_predicate[(int) CODE_FOR_allocate_stack][1])
-               (size, mode)))
+      pred = insn_data[(int) CODE_FOR_allocate_stack].operand[1].predicate;
+      if (pred && ! ((*pred) (size, mode)))
        size = copy_to_mode_reg (mode, size);
 
       emit_insn (gen_allocate_stack (target, size));
@@ -1323,6 +1358,33 @@ allocate_dynamic_stack_space (size, target, known_align)
       emit_move_insn (target, virtual_stack_dynamic_rtx);
 #endif
       size = convert_modes (Pmode, ptr_mode, size, 1);
+
+      /* Check stack bounds if necessary.  */
+      if (current_function_limit_stack)
+       {
+         rtx available;
+         rtx space_available = gen_label_rtx ();
+#ifdef STACK_GROWS_DOWNWARD
+         available = expand_binop (Pmode, sub_optab, 
+                                   stack_pointer_rtx, stack_limit_rtx,
+                                   NULL_RTX, 1, OPTAB_WIDEN);
+#else
+         available = expand_binop (Pmode, sub_optab, 
+                                   stack_limit_rtx, stack_pointer_rtx,
+                                   NULL_RTX, 1, OPTAB_WIDEN);
+#endif
+         emit_cmp_and_jump_insns (available, size, GEU, NULL_RTX, Pmode, 1,
+                                  0, space_available);
+#ifdef HAVE_trap
+         if (HAVE_trap)
+           emit_insn (gen_trap ());
+         else
+#endif
+           error ("stack limits not supported on this target");
+         emit_barrier ();
+         emit_label (space_available);
+       }
+
       anti_adjust_stack (size);
 #ifdef SETJMP_VIA_SAVE_AREA
       if (setjmpless_size != NULL_RTX)
@@ -1369,6 +1431,19 @@ allocate_dynamic_stack_space (size, target, known_align)
   return target;
 }
 \f
+/* A front end may want to override GCC's stack checking by providing a 
+   run-time routine to call to check the stack, so provide a mechanism for
+   calling that routine.  */
+
+static rtx stack_check_libfunc;
+
+void
+set_stack_check_libfunc (libfunc)
+     rtx libfunc;
+{
+  stack_check_libfunc = libfunc;
+}
+\f
 /* Emit one stack probe at ADDRESS, an address within the stack.  */
 
 static void
@@ -1402,30 +1477,39 @@ probe_stack_range (first, size)
      HOST_WIDE_INT first;
      rtx size;
 {
-  /* First see if we have an insn to check the stack.  Use it if so.  */
+  /* First see if the front end has set up a function for us to call to
+     check the stack.  */
+  if (stack_check_libfunc != 0)
+    emit_library_call (stack_check_libfunc, 0, VOIDmode, 1,
+                      memory_address (QImode,
+                                      gen_rtx (STACK_GROW_OP, Pmode,
+                                               stack_pointer_rtx,
+                                               plus_constant (size, first))),
+                      ptr_mode);
+
+  /* Next see if we have an insn to check the stack.  Use it if so.  */
 #ifdef HAVE_check_stack
-  if (HAVE_check_stack)
+  else if (HAVE_check_stack)
     {
+      insn_operand_predicate_fn pred;
       rtx last_addr
        = force_operand (gen_rtx_STACK_GROW_OP (Pmode,
                                                stack_pointer_rtx,
                                                plus_constant (size, first)),
                         NULL_RTX);
 
-      if (insn_operand_predicate[(int) CODE_FOR_check_stack][0]
-         && ! ((*insn_operand_predicate[(int) CODE_FOR_check_stack][0])
-               (last_address, Pmode)))
-       last_address = copy_to_mode_reg (Pmode, last_address);
+      pred = insn_data[(int) CODE_FOR_check_stack].operand[0].predicate;
+      if (pred && ! ((*pred) (last_addr, Pmode)))
+       last_addr = copy_to_mode_reg (Pmode, last_addr);
 
-      emit_insn (gen_check_stack (last_address));
-      return;
+      emit_insn (gen_check_stack (last_addr));
     }
 #endif
 
   /* If we have to generate explicit probes, see if we have a constant
      small number of them to generate.  If so, that's the easy case.  */
-  if (GET_CODE (size) == CONST_INT
-      && INTVAL (size) < 10 * STACK_CHECK_PROBE_INTERVAL)
+  else if (GET_CODE (size) == CONST_INT
+          && INTVAL (size) < 10 * STACK_CHECK_PROBE_INTERVAL)
     {
       HOST_WIDE_INT offset;
 
@@ -1497,10 +1581,6 @@ probe_stack_range (first, size)
       emit_note (NULL_PTR, NOTE_INSN_LOOP_END);
       emit_label (end_lab);
 
-      /* If will be doing stupid optimization, show test_addr is still live. */
-      if (obey_regdecls)
-       emit_insn (gen_rtx_USE (VOIDmode, test_addr));
-
       emit_stack_probe (last_addr);
     }
 }
@@ -1509,21 +1589,34 @@ probe_stack_range (first, size)
    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.  */
+   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 (valtype, func)
+hard_function_value (valtype, func, outgoing)
      tree valtype;
      tree func ATTRIBUTE_UNUSED;
+     int outgoing ATTRIBUTE_UNUSED;
 {
-  rtx val = FUNCTION_VALUE (valtype, func);
+  rtx val;
+
+#ifdef FUNCTION_OUTGOING_VALUE
+  if (outgoing)
+    val = FUNCTION_OUTGOING_VALUE (valtype, func);
+  else
+#endif
+    val = FUNCTION_VALUE (valtype, func);
+
   if (GET_CODE (val) == REG
       && GET_MODE (val) == BLKmode)
     {
-      int bytes = int_size_in_bytes (valtype);
+      unsigned HOST_WIDE_INT bytes = int_size_in_bytes (valtype);
       enum machine_mode tmpmode;
+
       for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-           tmpmode != MAX_MACHINE_MODE;
+           tmpmode != VOIDmode;
            tmpmode = GET_MODE_WIDER_MODE (tmpmode))
         {
           /* Have we found a large enough mode?  */
@@ -1532,7 +1625,7 @@ hard_function_value (valtype, func)
         }
 
       /* No suitable mode found.  */
-      if (tmpmode == MAX_MACHINE_MODE)
+      if (tmpmode == VOIDmode)
         abort ();
 
       PUT_MODE (val, tmpmode);