#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;
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);
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),
}
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;
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);
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
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. */
if (general_operand (x, Pmode))
return force_reg (Pmode, x);
else
- return force_operand (x, 0);
+ return force_operand (x, NULL_RTX);
}
return 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;
{
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.
#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
{
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 */
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 ();
|| 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
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