]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/explow.c
Enhance to fill the last delay slot of a call with an unconditional jump.
[gcc.git] / gcc / explow.c
index f33dba9898e9d233f607acdcc190e87e160009d5..211ce202090905ecfb2bc4254e6252eb20fe9b1f 100644 (file)
@@ -29,12 +29,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "insn-flags.h"
 #include "insn-codes.h"
 
-/* Return an rtx for the sum of X and the integer C.  */
+/* Return an rtx for the sum of X and the integer C.
+
+   This fucntion should be used via the `plus_constant' macro.  */
 
 rtx
-plus_constant (x, c)
+plus_constant_wide (x, c)
      register rtx x;
-     register int c;
+     register HOST_WIDE_INT c;
 {
   register RTX_CODE code;
   register enum machine_mode mode;
@@ -51,15 +53,15 @@ plus_constant (x, c)
   switch (code)
     {
     case CONST_INT:
-      return gen_rtx (CONST_INT, VOIDmode, (INTVAL (x) + c));
+      return GEN_INT (INTVAL (x) + c);
 
     case CONST_DOUBLE:
       {
-       int l1 = CONST_DOUBLE_LOW (x);
-       int h1 = CONST_DOUBLE_HIGH (x);
-       int l2 = c;
-       int h2 = c < 0 ? ~0 : 0;
-       int lv, hv;
+       HOST_WIDE_INT l1 = CONST_DOUBLE_LOW (x);
+       HOST_WIDE_INT h1 = CONST_DOUBLE_HIGH (x);
+       HOST_WIDE_INT l2 = c;
+       HOST_WIDE_INT h2 = c < 0 ? ~0 : 0;
+       HOST_WIDE_INT lv, hv;
 
        add_double (l1, h1, l2, h2, &lv, &hv);
 
@@ -99,17 +101,13 @@ plus_constant (x, c)
         Look for constant term in the sum and combine
         with C.  For an integer constant term, we make a combined
         integer.  For a constant term that is not an explicit integer,
-        we cannot really combine, but group them together anyway.  */
-      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
-       {
-         c += INTVAL (XEXP (x, 0));
-         x = XEXP (x, 1);
-       }
-      else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
-       {
-         c += INTVAL (XEXP (x, 1));
-         x = XEXP (x, 0);
-       }
+        we cannot really combine, but group them together anyway.  
+
+        Use a recursive call in case the remaining operand is something
+        that we handle specially, such as a SYMBOL_REF.  */
+
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+       return plus_constant (XEXP (x, 0), c + INTVAL (XEXP (x, 1)));
       else if (CONSTANT_P (XEXP (x, 0)))
        return gen_rtx (PLUS, mode,
                        plus_constant (XEXP (x, 0), c),
@@ -121,7 +119,7 @@ plus_constant (x, c)
     }
 
   if (c != 0)
-    x = gen_rtx (PLUS, mode, x, gen_rtx (CONST_INT, VOIDmode, c));
+    x = gen_rtx (PLUS, mode, x, GEN_INT (c));
 
   if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
     return x;
@@ -131,12 +129,14 @@ plus_constant (x, c)
     return x;
 }
 
-/* This is the same a `plus_constant', except that it handles LO_SUM.  */
+/* This is the same as `plus_constant', except that it handles LO_SUM.
+
+   This function should be used via the `plus_constant_for_output' macro.  */
 
 rtx
-plus_constant_for_output (x, c)
+plus_constant_for_output_wide (x, c)
      register rtx x;
-     register int c;
+     register HOST_WIDE_INT c;
 {
   register RTX_CODE code = GET_CODE (x);
   register enum machine_mode mode = GET_MODE (x);
@@ -243,7 +243,7 @@ expr_size (exp)
      tree exp;
 {
   return expand_expr (size_in_bytes (TREE_TYPE (exp)),
-                     0, TYPE_MODE (sizetype), 0);
+                     NULL_RTX, TYPE_MODE (sizetype), 0);
 }
 \f
 /* Return a copy of X in which all memory references
@@ -381,15 +381,15 @@ memory_address (mode, x)
       rtx y = eliminate_constant_term (x, &constant_term);
       if (constant_term == const0_rtx
          || ! memory_address_p (mode, y))
-       return force_operand (x, 0);
+       return force_operand (x, NULL_RTX);
 
       y = gen_rtx (PLUS, GET_MODE (x), copy_to_reg (y), constant_term);
       if (! memory_address_p (mode, y))
-       return force_operand (x, 0);
+       return force_operand (x, NULL_RTX);
       return y;
     }
   if (GET_CODE (x) == MULT || GET_CODE (x) == MINUS)
-    return force_operand (x, 0);
+    return force_operand (x, NULL_RTX);
 
   /* If we have a register that's an invalid address,
      it must be a hard reg of the wrong class.  Copy it to a pseudo.  */
@@ -412,7 +412,7 @@ memory_address (mode, x)
       if (general_operand (x, Pmode))
        return force_reg (Pmode, x);
       else
-       return force_operand (x, 0);
+       return force_operand (x, NULL_RTX);
     }
   return x;
 }
@@ -554,7 +554,7 @@ force_reg (mode, x)
      and that X can be substituted for it.  */
   if (CONSTANT_P (x))
     {
-      rtx note = find_reg_note (insn, REG_EQUAL, 0);
+      rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
 
       if (note)
        XEXP (note, 0) = x;
@@ -666,21 +666,161 @@ round_push (size)
     {
       int new = (INTVAL (size) + align - 1) / align * align;
       if (INTVAL (size) != new)
-       size = gen_rtx (CONST_INT, VOIDmode, new);
+       size = GEN_INT (new);
     }
   else
     {
-      size = expand_divmod (0, CEIL_DIV_EXPR, Pmode, size,
-                           gen_rtx (CONST_INT, VOIDmode, align),
-                           0, 1);
-      size = expand_mult (Pmode, size,
-                         gen_rtx (CONST_INT, VOIDmode, align),
-                         0, 1);
+      size = expand_divmod (0, CEIL_DIV_EXPR, Pmode, size, GEN_INT (align),
+                           NULL_RTX, 1);
+      size = expand_mult (Pmode, size, GEN_INT (align), NULL_RTX, 1);
     }
 #endif /* STACK_BOUNDARY */
   return size;
 }
 \f
+/* Save the stack pointer for the purpose in SAVE_LEVEL.  PSAVE is a pointer
+   to a previously-created save area.  If no save area has been allocated,
+   this function will allocate one.  If a save area is specified, it
+   must be of the proper mode.
+
+   The insns are emitted after insn AFTER, if nonzero, otherwise the insns
+   are emitted at the current position.  */
+
+void
+emit_stack_save (save_level, psave, after)
+     enum save_level save_level;
+     rtx *psave;
+     rtx after;
+{
+  rtx sa = *psave;
+  /* The default is that we use a move insn and save in a Pmode object.  */
+  rtx (*fcn) () = gen_move_insn;
+  enum machine_mode mode = Pmode;
+
+  /* See if this machine has anything special to do for this kind of save.  */
+  switch (save_level)
+    {
+#ifdef HAVE_save_stack_block
+    case SAVE_BLOCK:
+      if (HAVE_save_stack_block)
+       {
+         fcn = gen_save_stack_block;
+         mode = insn_operand_mode[CODE_FOR_save_stack_block][0];
+       }
+      break;
+#endif
+#ifdef HAVE_save_stack_function
+    case SAVE_FUNCTION:
+      if (HAVE_save_stack_function)
+       {
+         fcn = gen_save_stack_function;
+         mode = insn_operand_mode[CODE_FOR_save_stack_function][0];
+       }
+      break;
+#endif
+#ifdef HAVE_save_stack_nonlocal
+    case SAVE_NONLOCAL:
+      if (HAVE_save_stack_nonlocal)
+       {
+         fcn = gen_save_stack_nonlocal;
+         mode = insn_operand_mode[CODE_FOR_save_stack_nonlocal][0];
+       }
+      break;
+#endif
+    }
+
+  /* If there is no save area and we have to allocate one, do so.  Otherwise
+     verify the save area is the proper mode.  */
+
+  if (sa == 0)
+    {
+      if (mode != VOIDmode)
+       {
+         if (save_level == SAVE_NONLOCAL)
+           *psave = sa = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
+         else
+           *psave = sa = gen_reg_rtx (mode);
+       }
+    }
+  else
+    {
+      if (mode == VOIDmode || GET_MODE (sa) != mode)
+       abort ();
+    }
+
+  if (sa != 0)
+    sa = validize_mem (sa);
+
+  if (after)
+    {
+      rtx seq;
+
+      start_sequence ();
+      emit_insn (fcn (sa, stack_pointer_rtx));
+      seq = gen_sequence ();
+      end_sequence ();
+      emit_insn_after (seq, after);
+    }
+  else
+    emit_insn (fcn (sa, stack_pointer_rtx));
+}
+
+/* Restore the stack pointer for the purpose in SAVE_LEVEL.  SA is the save
+   area made by emit_stack_save.  If it is zero, we have nothing to do. 
+
+   Put any emitted insns after insn AFTER, if nonzero, otherwise at 
+   current position.  */
+
+void
+emit_stack_restore (save_level, sa, after)
+     enum save_level save_level;
+     rtx after;
+     rtx sa;
+{
+  /* The default is that we use a move insn.  */
+  rtx (*fcn) () = gen_move_insn;
+
+  /* See if this machine has anything special to do for this kind of save.  */
+  switch (save_level)
+    {
+#ifdef HAVE_restore_stack_block
+    case SAVE_BLOCK:
+      if (HAVE_restore_stack_block)
+       fcn = gen_restore_stack_block;
+      break;
+#endif
+#ifdef HAVE_restore_stack_function
+    case SAVE_FUNCTION:
+      if (HAVE_restore_stack_function)
+       fcn = gen_restore_stack_function;
+      break;
+#endif
+#ifdef HAVE_restore_stack_nonlocal
+
+    case SAVE_NONLOCAL:
+      if (HAVE_restore_stack_nonlocal)
+       fcn = gen_restore_stack_nonlocal;
+      break;
+#endif
+    }
+
+  if (sa != 0)
+    sa = validize_mem (sa);
+
+  if (after)
+    {
+      rtx seq;
+
+      start_sequence ();
+      emit_insn (fcn (stack_pointer_rtx, sa));
+      seq = gen_sequence ();
+      end_sequence ();
+      emit_insn_after (seq, after);
+    }
+  else
+    emit_insn (fcn (stack_pointer_rtx, sa));
+}
+\f
 /* Return an rtx representing the address of an area of memory dynamically
    pushed on the stack.  This region of memory is always aligned to
    a multiple of BIGGEST_ALIGNMENT.
@@ -725,14 +865,16 @@ allocate_dynamic_stack_space (size, target, known_align)
 
 #ifdef MUST_ALIGN
 
-  if (GET_CODE (size) == CONST_INT)
-    size = gen_rtx (CONST_INT, VOIDmode,
-                   INTVAL (size) + (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1));
-  else
-    size = expand_binop (Pmode, add_optab, size,
-                        gen_rtx (CONST_INT, VOIDmode,
-                                 BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1),
-                        0, 1, OPTAB_LIB_WIDEN);
+  if (known_align % BIGGEST_ALIGNMENT != 0)
+    {
+      if (GET_CODE (size) == CONST_INT)
+       size = GEN_INT (INTVAL (size)
+                       + (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1));
+      else
+       size = expand_binop (Pmode, add_optab, size,
+                            GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1),
+                            NULL_RTX, 1, OPTAB_LIB_WIDEN);
+    }
 #endif
 
 #ifdef SETJMP_VIA_SAVE_AREA
@@ -744,9 +886,9 @@ allocate_dynamic_stack_space (size, target, known_align)
   {
     rtx dynamic_offset
       = expand_binop (Pmode, sub_optab, virtual_stack_dynamic_rtx,
-                     stack_pointer_rtx, 0, 1, OPTAB_LIB_WIDEN);
+                     stack_pointer_rtx, NULL_RTX, 1, OPTAB_LIB_WIDEN);
     size = expand_binop (Pmode, add_optab, size, dynamic_offset,
-                        0, 1, OPTAB_LIB_WIDEN);
+                        NULL_RTX, 1, OPTAB_LIB_WIDEN);
   }
 #endif /* SETJMP_VIA_SAVE_AREA */
 
@@ -764,8 +906,13 @@ allocate_dynamic_stack_space (size, target, known_align)
      way of knowing which systems have this problem.  So we avoid even
      momentarily mis-aligning the stack.  */
 
+#ifdef STACK_BOUNDARY
+#ifndef SETJMP_VIA_SAVE_AREA /* If we added a variable amount to SIZE,
+                               we can no longer assume it is aligned.  */
   if (known_align % STACK_BOUNDARY != 0)
+#endif
     size = round_push (size);
+#endif
 
   do_pending_stack_adjust ();
 
@@ -774,6 +921,8 @@ allocate_dynamic_stack_space (size, target, known_align)
       || REGNO (target) < FIRST_PSEUDO_REGISTER)
     target = gen_reg_rtx (Pmode);
 
+  mark_reg_pointer (target);
+
 #ifndef STACK_GROWS_DOWNWARD
   emit_move_insn (target, virtual_stack_dynamic_rtx);
 #endif
@@ -806,14 +955,12 @@ allocate_dynamic_stack_space (size, target, known_align)
   if (known_align % BIGGEST_ALIGNMENT != 0)
     {
       target = expand_divmod (0, CEIL_DIV_EXPR, Pmode, target,
-                             gen_rtx (CONST_INT, VOIDmode,
-                                      BIGGEST_ALIGNMENT / BITS_PER_UNIT),
-                             0, 1);
+                             GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),
+                             NULL_RTX, 1);
 
       target = expand_mult (Pmode, target,
-                           gen_rtx (CONST_INT, VOIDmode,
-                                    BIGGEST_ALIGNMENT / BITS_PER_UNIT),
-                           0, 1);
+                           GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),
+                           NULL_RTX, 1);
     }
 #endif
   
This page took 0.037986 seconds and 5 git commands to generate.