/* Subroutines for manipulating rtx's in semantically interesting ways.
Copyright (C) 1987, 1991, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
#include "recog.h"
#include "langhooks.h"
-static rtx break_out_memory_refs PARAMS ((rtx));
-static void emit_stack_probe PARAMS ((rtx));
+static rtx break_out_memory_refs (rtx);
+static void emit_stack_probe (rtx);
/* Truncate and perhaps sign-extend C as appropriate for MODE. */
HOST_WIDE_INT
-trunc_int_for_mode (c, mode)
- HOST_WIDE_INT c;
- enum machine_mode mode;
+trunc_int_for_mode (HOST_WIDE_INT c, enum machine_mode mode)
{
int width = GET_MODE_BITSIZE (mode);
This function should be used via the `plus_constant' macro. */
rtx
-plus_constant_wide (x, c)
- rtx x;
- HOST_WIDE_INT c;
+plus_constant_wide (rtx x, HOST_WIDE_INT c)
{
RTX_CODE code;
rtx y;
it is not isomorphic to X. */
rtx
-eliminate_constant_term (x, constptr)
- rtx x;
- rtx *constptr;
+eliminate_constant_term (rtx x, rtx *constptr)
{
rtx x0, x1;
rtx tem;
return x;
}
-/* Returns the insn that next references REG after INSN, or 0
- if REG is clobbered before next referenced or we cannot find
- an insn that references REG in a straight-line piece of code. */
-
-rtx
-find_next_ref (reg, insn)
- rtx reg;
- rtx insn;
-{
- rtx next;
-
- for (insn = NEXT_INSN (insn); insn; insn = next)
- {
- next = NEXT_INSN (insn);
- if (GET_CODE (insn) == NOTE)
- continue;
- if (GET_CODE (insn) == CODE_LABEL
- || GET_CODE (insn) == BARRIER)
- return 0;
- if (GET_CODE (insn) == INSN
- || GET_CODE (insn) == JUMP_INSN
- || GET_CODE (insn) == CALL_INSN)
- {
- if (reg_set_p (reg, insn))
- return 0;
- if (reg_mentioned_p (reg, PATTERN (insn)))
- return insn;
- if (GET_CODE (insn) == JUMP_INSN)
- {
- if (any_uncondjump_p (insn))
- next = JUMP_LABEL (insn);
- else
- return 0;
- }
- if (GET_CODE (insn) == CALL_INSN
- && REGNO (reg) < FIRST_PSEUDO_REGISTER
- && call_used_regs[REGNO (reg)])
- return 0;
- }
- else
- abort ();
- }
- return 0;
-}
-
/* Return an rtx for the size in bytes of the value of EXP. */
rtx
-expr_size (exp)
- tree exp;
+expr_size (tree exp)
{
- tree size = (*lang_hooks.expr_size) (exp);
-
- if (CONTAINS_PLACEHOLDER_P (size))
- size = build (WITH_RECORD_EXPR, sizetype, size, exp);
+ tree size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (lang_hooks.expr_size (exp), exp);
return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), 0);
}
if the size can vary or is larger than an integer. */
HOST_WIDE_INT
-int_expr_size (exp)
- tree exp;
+int_expr_size (tree exp)
{
- tree t = (*lang_hooks.expr_size) (exp);
+ tree t = lang_hooks.expr_size (exp);
if (t == 0
|| TREE_CODE (t) != INTEGER_CST
Values returned by expand_expr with 1 for sum_ok fit this constraint. */
static rtx
-break_out_memory_refs (x)
- rtx x;
+break_out_memory_refs (rtx x)
{
if (GET_CODE (x) == MEM
|| (CONSTANT_P (x) && CONSTANT_ADDRESS_P (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
used. */
rtx
-convert_memory_address (to_mode, x)
- enum machine_mode to_mode;
- rtx x;
+convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED,
+ rtx x)
{
- enum machine_mode from_mode = to_mode == ptr_mode ? Pmode : ptr_mode;
+#ifndef POINTERS_EXTEND_UNSIGNED
+ return x;
+#else /* defined(POINTERS_EXTEND_UNSIGNED) */
+ enum machine_mode from_mode;
rtx temp;
enum rtx_code code;
+ /* If X already has the right mode, just return it. */
+ if (GET_MODE (x) == to_mode)
+ return x;
+
+ from_mode = to_mode == ptr_mode ? Pmode : ptr_mode;
+
/* Here we handle some special cases. If none of them apply, fall through
to the default case. */
switch (GET_CODE (x))
return convert_modes (to_mode, from_mode,
x, POINTERS_EXTEND_UNSIGNED);
+#endif /* defined(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.
but then you wouldn't get indexed addressing in the reference. */
rtx
-copy_all_regs (x)
- rtx x;
+copy_all_regs (rtx x)
{
if (GET_CODE (x) == REG)
{
works by copying X or subexpressions of it into registers. */
rtx
-memory_address (mode, x)
- enum machine_mode mode;
- rtx x;
+memory_address (enum machine_mode mode, rtx x)
{
rtx oldx = x;
if (GET_CODE (x) == ADDRESSOF)
return x;
-#ifdef POINTERS_EXTEND_UNSIGNED
- if (GET_MODE (x) != Pmode)
- x = convert_memory_address (Pmode, x);
-#endif
+ x = convert_memory_address (Pmode, x);
- /* By passing constant addresses thru registers
+ /* By passing constant addresses through registers
we get a chance to cse them. */
if (! cse_not_expected && CONSTANT_P (x) && CONSTANT_ADDRESS_P (x))
x = force_reg (Pmode, x);
/* Like `memory_address' but pretend `flag_force_addr' is 0. */
rtx
-memory_address_noforce (mode, x)
- enum machine_mode mode;
- rtx x;
+memory_address_noforce (enum machine_mode mode, rtx x)
{
int ambient_force_addr = flag_force_addr;
rtx val;
Pass through anything else unchanged. */
rtx
-validize_mem (ref)
- rtx ref;
+validize_mem (rtx ref)
{
if (GET_CODE (ref) != MEM)
return ref;
appropriate. */
void
-maybe_set_unchanging (ref, t)
- rtx ref;
- tree t;
+maybe_set_unchanging (rtx ref, tree t)
{
/* We can set RTX_UNCHANGING_P from TREE_READONLY for decls whose
initialization is only executed once, or whose initializer always
Perhaps even if it is a MEM, if there is no need to change it. */
rtx
-stabilize (x)
- rtx x;
+stabilize (rtx x)
{
if (GET_CODE (x) != MEM
|| ! rtx_unstable_p (XEXP (x, 0)))
/* Copy the value or contents of X to a new temp reg and return that reg. */
rtx
-copy_to_reg (x)
- rtx x;
+copy_to_reg (rtx x)
{
rtx temp = gen_reg_rtx (GET_MODE (x));
in case X is a constant. */
rtx
-copy_addr_to_reg (x)
- rtx x;
+copy_addr_to_reg (rtx x)
{
return copy_to_mode_reg (Pmode, x);
}
in case X is a constant. */
rtx
-copy_to_mode_reg (mode, x)
- enum machine_mode mode;
- rtx x;
+copy_to_mode_reg (enum machine_mode mode, rtx x)
{
rtx temp = gen_reg_rtx (mode);
since we mark it as a "constant" register. */
rtx
-force_reg (mode, x)
- enum machine_mode mode;
- rtx x;
+force_reg (enum machine_mode mode, rtx x)
{
rtx temp, insn, set;
&& ! rtx_equal_p (x, SET_SRC (set)))
set_unique_reg_note (insn, REG_EQUAL, x);
+ /* Let optimizers know that TEMP is a pointer, and if so, the
+ known alignment of that pointer. */
+ {
+ unsigned align = 0;
+ if (GET_CODE (x) == SYMBOL_REF)
+ {
+ align = BITS_PER_UNIT;
+ if (SYMBOL_REF_DECL (x) && DECL_P (SYMBOL_REF_DECL (x)))
+ align = DECL_ALIGN (SYMBOL_REF_DECL (x));
+ }
+ else if (GET_CODE (x) == LABEL_REF)
+ align = BITS_PER_UNIT;
+ else if (GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
+ {
+ rtx s = XEXP (XEXP (x, 0), 0);
+ rtx c = XEXP (XEXP (x, 0), 1);
+ unsigned sa, ca;
+
+ sa = BITS_PER_UNIT;
+ if (SYMBOL_REF_DECL (s) && DECL_P (SYMBOL_REF_DECL (s)))
+ sa = DECL_ALIGN (SYMBOL_REF_DECL (s));
+
+ ca = exact_log2 (INTVAL (c) & -INTVAL (c)) * BITS_PER_UNIT;
+
+ align = MIN (sa, ca);
+ }
+
+ if (align)
+ mark_reg_pointer (temp, align);
+ }
+
return temp;
}
that reg. Otherwise, return X. */
rtx
-force_not_mem (x)
- rtx x;
+force_not_mem (rtx x)
{
rtx temp;
return x;
temp = gen_reg_rtx (GET_MODE (x));
+
+ if (MEM_POINTER (x))
+ REG_POINTER (temp) = 1;
+
emit_move_insn (temp, x);
return temp;
}
MODE is the mode to use for X in case it is a constant. */
rtx
-copy_to_suggested_reg (x, target, mode)
- rtx x, target;
- enum machine_mode mode;
+copy_to_suggested_reg (rtx x, rtx target, enum machine_mode mode)
{
rtx temp;
FOR_CALL is nonzero if this call is promoting args for a call. */
+#if defined(PROMOTE_MODE) && !defined(PROMOTE_FUNCTION_MODE)
+#define PROMOTE_FUNCTION_MODE PROMOTE_MODE
+#endif
+
enum machine_mode
-promote_mode (type, mode, punsignedp, for_call)
- tree type;
- enum machine_mode mode;
- int *punsignedp;
- int for_call ATTRIBUTE_UNUSED;
+promote_mode (tree type, enum machine_mode mode, int *punsignedp,
+ int for_call ATTRIBUTE_UNUSED)
{
enum tree_code code = TREE_CODE (type);
int unsignedp = *punsignedp;
-#ifdef PROMOTE_FOR_CALL_ONLY
+#ifndef PROMOTE_MODE
if (! for_call)
return mode;
#endif
switch (code)
{
-#ifdef PROMOTE_MODE
+#ifdef PROMOTE_FUNCTION_MODE
case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
case CHAR_TYPE: case REAL_TYPE: case OFFSET_TYPE:
- PROMOTE_MODE (mode, unsignedp, type);
+#ifdef PROMOTE_MODE
+ if (for_call)
+ {
+#endif
+ PROMOTE_FUNCTION_MODE (mode, unsignedp, type);
+#ifdef PROMOTE_MODE
+ }
+ else
+ {
+ PROMOTE_MODE (mode, unsignedp, type);
+ }
+#endif
break;
#endif
This pops when ADJUST is positive. ADJUST need not be constant. */
void
-adjust_stack (adjust)
- rtx adjust;
+adjust_stack (rtx adjust)
{
rtx temp;
adjust = protect_from_queue (adjust, 0);
This pushes when ADJUST is positive. ADJUST need not be constant. */
void
-anti_adjust_stack (adjust)
- rtx adjust;
+anti_adjust_stack (rtx adjust)
{
rtx temp;
adjust = protect_from_queue (adjust, 0);
by this machine. SIZE is the desired size, which need not be constant. */
rtx
-round_push (size)
- rtx size;
+round_push (rtx size)
{
int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
are emitted at the current position. */
void
-emit_stack_save (save_level, psave, after)
- enum save_level save_level;
- rtx *psave;
- rtx after;
+emit_stack_save (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) PARAMS ((rtx, rtx)) = gen_move_insn;
+ rtx (*fcn) (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. */
current position. */
void
-emit_stack_restore (save_level, sa, after)
- enum save_level save_level;
- rtx after;
- rtx sa;
+emit_stack_restore (enum save_level save_level, rtx sa, rtx after)
{
/* The default is that we use a move insn. */
- rtx (*fcn) PARAMS ((rtx, rtx)) = gen_move_insn;
+ rtx (*fcn) (rtx, rtx) = gen_move_insn;
/* See if this machine has anything special to do for this kind of save. */
switch (save_level)
references to variable arrays below the code
that deletes (pops) the arrays. */
emit_insn (gen_rtx_CLOBBER (VOIDmode,
- gen_rtx_MEM (BLKmode,
+ gen_rtx_MEM (BLKmode,
gen_rtx_SCRATCH (VOIDmode))));
emit_insn (gen_rtx_CLOBBER (VOIDmode,
gen_rtx_MEM (BLKmode, stack_pointer_rtx)));
frame, thus causing a crash if a longjmp unwinds to it. */
void
-optimize_save_area_alloca (insns)
- rtx insns;
+optimize_save_area_alloca (rtx insns)
{
rtx insn;
KNOWN_ALIGN is the alignment (in bits) that we know SIZE has. */
rtx
-allocate_dynamic_stack_space (size, target, known_align)
- rtx size;
- rtx target;
- int known_align;
+allocate_dynamic_stack_space (rtx size, rtx target, int known_align)
{
#ifdef SETJMP_VIA_SAVE_AREA
rtx setjmpless_size = NULL_RTX;
static GTY(()) rtx stack_check_libfunc;
void
-set_stack_check_libfunc (libfunc)
- rtx libfunc;
+set_stack_check_libfunc (rtx libfunc)
{
stack_check_libfunc = libfunc;
}
/* Emit one stack probe at ADDRESS, an address within the stack. */
static void
-emit_stack_probe (address)
- rtx address;
+emit_stack_probe (rtx address)
{
rtx memref = gen_rtx_MEM (word_mode, address);
#endif
void
-probe_stack_range (first, size)
- HOST_WIDE_INT first;
- rtx size;
+probe_stack_range (HOST_WIDE_INT first, rtx size)
{
/* First ensure SIZE is Pmode. */
if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
stack_pointer_rtx,
plus_constant (size, first)));
-#ifdef POINTERS_EXTEND_UNSIGNED
- if (GET_MODE (addr) != ptr_mode)
- addr = convert_memory_address (ptr_mode, addr);
-#endif
-
+ addr = convert_memory_address (ptr_mode, addr);
emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr,
ptr_mode);
}
and 0 otherwise. */
rtx
-hard_function_value (valtype, func, outgoing)
- tree valtype;
- tree func ATTRIBUTE_UNUSED;
- int outgoing ATTRIBUTE_UNUSED;
+hard_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
+ int outgoing ATTRIBUTE_UNUSED)
{
rtx val;
in which a scalar value of mode MODE was returned by a library call. */
rtx
-hard_libcall_value (mode)
- enum machine_mode mode;
+hard_libcall_value (enum machine_mode mode)
{
return LIBCALL_VALUE (mode);
}
what `enum tree_code' means. */
int
-rtx_to_tree_code (code)
- enum rtx_code code;
+rtx_to_tree_code (enum rtx_code code)
{
enum tree_code tcode;