/* Subroutines for manipulating rtx's in semantically interesting ways.
Copyright (C) 1987, 1991, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "ggc.h"
#include "recog.h"
#include "langhooks.h"
+#include "target.h"
+#include "output.h"
static rtx break_out_memory_refs (rtx);
static void emit_stack_probe (rtx);
if (TREE_CODE (exp) == WITH_SIZE_EXPR)
size = TREE_OPERAND (exp, 1);
else
- size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (lang_hooks.expr_size (exp), exp);
+ {
+ size = lang_hooks.expr_size (exp);
+ gcc_assert (size);
+ size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, exp);
+ }
- return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), 0);
+ return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), EXPAND_NORMAL);
}
/* Return a wide integer for the size in bytes of the value of EXP, or -1
if (TREE_CODE (exp) == WITH_SIZE_EXPR)
size = TREE_OPERAND (exp, 1);
else
- size = lang_hooks.expr_size (exp);
+ {
+ size = lang_hooks.expr_size (exp);
+ gcc_assert (size);
+ }
if (size == 0 || !host_integerp (size, 0))
return -1;
case MULT:
/* 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. */
+ does not change it or if one operand is a constant and we are
+ using a ptr_extend instruction (POINTERS_EXTEND_UNSIGNED < 0).
+ 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))))
+ && (XEXP (x, 1) == convert_memory_address (to_mode, XEXP (x, 1))
+ || POINTERS_EXTEND_UNSIGNED < 0)))
return gen_rtx_fmt_ee (GET_CODE (x), to_mode,
convert_memory_address (to_mode, XEXP (x, 0)),
XEXP (x, 1));
win2:
x = oldx;
win:
- if (flag_force_addr && ! cse_not_expected && !REG_P (x)
- /* Don't copy an addr via a reg if it is one of our stack slots. */
- && ! (GET_CODE (x) == PLUS
- && (XEXP (x, 0) == virtual_stack_vars_rtx
- || XEXP (x, 0) == virtual_incoming_args_rtx)))
+ if (flag_force_addr && ! cse_not_expected && !REG_P (x))
{
- if (general_operand (x, Pmode))
- x = force_reg (Pmode, x);
- else
- x = force_operand (x, NULL_RTX);
+ x = force_operand (x, NULL_RTX);
+ x = force_reg (Pmode, x);
}
}
{
if (!MEM_P (ref))
return ref;
+ ref = use_anchored_address (ref);
if (! (flag_force_addr && CONSTANT_ADDRESS_P (XEXP (ref, 0)))
&& memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
return ref;
/* Don't alter REF itself, since that is probably a stack slot. */
return replace_equiv_address (ref, XEXP (ref, 0));
}
+
+/* If X is a memory reference to a member of an object block, try rewriting
+ it to use an anchor instead. Return the new memory reference on success
+ and the old one on failure. */
+
+rtx
+use_anchored_address (rtx x)
+{
+ rtx base;
+ HOST_WIDE_INT offset;
+
+ if (!flag_section_anchors)
+ return x;
+
+ if (!MEM_P (x))
+ return x;
+
+ /* Split the address into a base and offset. */
+ base = XEXP (x, 0);
+ offset = 0;
+ if (GET_CODE (base) == CONST
+ && GET_CODE (XEXP (base, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (base, 0), 1)) == CONST_INT)
+ {
+ offset += INTVAL (XEXP (XEXP (base, 0), 1));
+ base = XEXP (XEXP (base, 0), 0);
+ }
+
+ /* Check whether BASE is suitable for anchors. */
+ if (GET_CODE (base) != SYMBOL_REF
+ || !SYMBOL_REF_HAS_BLOCK_INFO_P (base)
+ || SYMBOL_REF_ANCHOR_P (base)
+ || SYMBOL_REF_BLOCK (base) == NULL
+ || !targetm.use_anchors_for_symbol_p (base))
+ return x;
+
+ /* Decide where BASE is going to be. */
+ place_block_symbol (base);
+
+ /* Get the anchor we need to use. */
+ offset += SYMBOL_REF_BLOCK_OFFSET (base);
+ base = get_section_anchor (SYMBOL_REF_BLOCK (base), offset,
+ SYMBOL_REF_TLS_MODEL (base));
+
+ /* Work out the offset from the anchor. */
+ offset -= SYMBOL_REF_BLOCK_OFFSET (base);
+
+ /* If we're going to run a CSE pass, force the anchor into a register.
+ We will then be able to reuse registers for several accesses, if the
+ target costs say that that's worthwhile. */
+ if (!cse_not_expected)
+ base = force_reg (GET_MODE (base), base);
+
+ return replace_equiv_address (x, plus_constant (base, offset));
+}
\f
/* Copy the value or contents of X to a new temp reg and return that reg. */
align = MIN (sa, ca);
}
+ else if (MEM_P (x) && MEM_POINTER (x))
+ align = MEM_ALIGN (x);
if (align)
mark_reg_pointer (temp, align);
{
#ifdef PROMOTE_FUNCTION_MODE
case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
- case CHAR_TYPE: case REAL_TYPE: case OFFSET_TYPE:
+ case REAL_TYPE: case OFFSET_TYPE:
#ifdef PROMOTE_MODE
if (for_call)
{
/* Return an rtx representing the register or memory location
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.
+ FUNC is a FUNCTION_DECL, FNTYPE a FUNCTION_TYPE node if the precise
+ function is known, 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 (tree valtype, tree func ATTRIBUTE_UNUSED,
+hard_function_value (tree valtype, tree func, tree fntype,
int outgoing ATTRIBUTE_UNUSED)
{
rtx val;
-#ifdef FUNCTION_OUTGOING_VALUE
- if (outgoing)
- val = FUNCTION_OUTGOING_VALUE (valtype, func);
- else
-#endif
- val = FUNCTION_VALUE (valtype, func);
+ val = targetm.calls.function_value (valtype, func ? func : fntype, outgoing);
if (REG_P (val)
&& GET_MODE (val) == BLKmode)