/* 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, 2006, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "tm.h"
#include "diagnostic-core.h"
#include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "stor-layout.h"
#include "tm_p.h"
#include "flags.h"
#include "except.h"
+#include "hard-reg-set.h"
#include "function.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
#include "expr.h"
+#include "insn-codes.h"
#include "optabs.h"
#include "libfuncs.h"
-#include "hard-reg-set.h"
-#include "insn-config.h"
-#include "ggc.h"
#include "recog.h"
#include "langhooks.h"
#include "target.h"
/* Truncate and perhaps sign-extend C as appropriate for MODE. */
HOST_WIDE_INT
-trunc_int_for_mode (HOST_WIDE_INT c, enum machine_mode mode)
+trunc_int_for_mode (HOST_WIDE_INT c, machine_mode mode)
{
int width = GET_MODE_PRECISION (mode);
/* You want to truncate to a _what_? */
- gcc_assert (SCALAR_INT_MODE_P (mode));
+ gcc_assert (SCALAR_INT_MODE_P (mode)
+ || POINTER_BOUNDS_MODE_P (mode));
/* Canonicalize BImode to 0 and STORE_FLAG_VALUE. */
if (mode == BImode)
return c;
}
-/* Return an rtx for the sum of X and the integer C. */
+/* Return an rtx for the sum of X and the integer C, given that X has
+ mode MODE. INPLACE is true if X can be modified inplace or false
+ if it must be treated as immutable. */
rtx
-plus_constant (rtx x, HOST_WIDE_INT c)
+plus_constant (machine_mode mode, rtx x, HOST_WIDE_INT c,
+ bool inplace)
{
RTX_CODE code;
rtx y;
- enum machine_mode mode;
rtx tem;
int all_constant = 0;
+ gcc_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode);
+
if (c == 0)
return x;
restart:
code = GET_CODE (x);
- mode = GET_MODE (x);
y = x;
switch (code)
{
- case CONST_INT:
- return GEN_INT (INTVAL (x) + c);
-
- case CONST_DOUBLE:
- {
- unsigned HOST_WIDE_INT l1 = CONST_DOUBLE_LOW (x);
- HOST_WIDE_INT h1 = CONST_DOUBLE_HIGH (x);
- unsigned HOST_WIDE_INT l2 = c;
- HOST_WIDE_INT h2 = c < 0 ? ~0 : 0;
- unsigned HOST_WIDE_INT lv;
- HOST_WIDE_INT hv;
-
- add_double (l1, h1, l2, h2, &lv, &hv);
-
- return immed_double_const (lv, hv, VOIDmode);
- }
-
+ CASE_CONST_SCALAR_INT:
+ return immed_wide_int_const (wi::add (std::make_pair (x, mode), c),
+ mode);
case MEM:
/* If this is a reference to the constant pool, try replacing it with
a reference to a new constant. If the resulting address isn't
if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
{
- tem
- = force_const_mem (GET_MODE (x),
- plus_constant (get_pool_constant (XEXP (x, 0)),
- c));
- if (memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
+ tem = plus_constant (mode, get_pool_constant (XEXP (x, 0)), c);
+ tem = force_const_mem (GET_MODE (x), tem);
+ /* Targets may disallow some constants in the constant pool, thus
+ force_const_mem may return NULL_RTX. */
+ if (tem && memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
return tem;
}
break;
case CONST:
/* If adding to something entirely constant, set a flag
so that we can add a CONST around the result. */
+ if (inplace && shared_const_p (x))
+ inplace = false;
x = XEXP (x, 0);
all_constant = 1;
goto restart;
break;
case PLUS:
- /* The interesting case is adding the integer to a sum.
- 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.
-
- Restart or use a recursive call in case the remaining operand is
- something that we handle specially, such as a SYMBOL_REF.
+ /* The interesting case is adding the integer to a sum. Look
+ for constant term in the sum and combine with C. For an
+ integer constant term or a constant term that is not an
+ explicit integer, we combine or group them together anyway.
We may not immediately return from the recursive call here, lest
all_constant gets lost. */
- if (CONST_INT_P (XEXP (x, 1)))
- {
- c += INTVAL (XEXP (x, 1));
-
- if (GET_MODE (x) != VOIDmode)
- c = trunc_int_for_mode (c, GET_MODE (x));
-
- x = XEXP (x, 0);
- goto restart;
- }
- else if (CONSTANT_P (XEXP (x, 1)))
+ if (CONSTANT_P (XEXP (x, 1)))
{
- x = gen_rtx_PLUS (mode, XEXP (x, 0), plus_constant (XEXP (x, 1), c));
+ rtx term = plus_constant (mode, XEXP (x, 1), c, inplace);
+ if (term == const0_rtx)
+ x = XEXP (x, 0);
+ else if (inplace)
+ XEXP (x, 1) = term;
+ else
+ x = gen_rtx_PLUS (mode, XEXP (x, 0), term);
c = 0;
}
- else if (find_constant_term_loc (&y))
+ else if (rtx *const_loc = find_constant_term_loc (&y))
{
- /* We need to be careful since X may be shared and we can't
- modify it in place. */
- rtx copy = copy_rtx (x);
- rtx *const_loc = find_constant_term_loc (©);
-
- *const_loc = plus_constant (*const_loc, c);
- x = copy;
+ if (!inplace)
+ {
+ /* We need to be careful since X may be shared and we can't
+ modify it in place. */
+ x = copy_rtx (x);
+ const_loc = find_constant_term_loc (&x);
+ }
+ *const_loc = plus_constant (mode, *const_loc, c, true);
c = 0;
}
break;
}
if (c != 0)
- x = gen_rtx_PLUS (mode, x, GEN_INT (c));
+ x = gen_rtx_PLUS (mode, x, gen_int_mode (c, mode));
if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
return x;
return x;
}
-/* Return an rtx for the size in bytes of the value of EXP. */
-
-rtx
-expr_size (tree exp)
-{
- tree size;
-
- if (TREE_CODE (exp) == WITH_SIZE_EXPR)
- size = TREE_OPERAND (exp, 1);
- else
- {
- size = tree_expr_size (exp);
- gcc_assert (size);
- gcc_assert (size == SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, exp));
- }
-
- 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 the size can vary or is larger than an integer. */
-
-HOST_WIDE_INT
-int_expr_size (tree exp)
-{
- tree size;
-
- if (TREE_CODE (exp) == WITH_SIZE_EXPR)
- size = TREE_OPERAND (exp, 1);
- else
- {
- size = tree_expr_size (exp);
- gcc_assert (size);
- }
-
- if (size == 0 || !host_integerp (size, 0))
- return -1;
-
- return tree_low_cst (size, 0);
-}
\f
/* Return a copy of X in which all memory references
and all constants that involve symbol refs
an address in the address space's address mode, or vice versa (TO_MODE says
which way). We take advantage of the fact that pointers are not allowed to
overflow by commuting arithmetic operations over conversions so that address
- arithmetic insns can be used. */
+ arithmetic insns can be used. IN_CONST is true if this conversion is inside
+ a CONST. */
-rtx
-convert_memory_address_addr_space (enum machine_mode to_mode ATTRIBUTE_UNUSED,
- rtx x, addr_space_t as ATTRIBUTE_UNUSED)
+static rtx
+convert_memory_address_addr_space_1 (machine_mode to_mode ATTRIBUTE_UNUSED,
+ rtx x, addr_space_t as ATTRIBUTE_UNUSED,
+ bool in_const ATTRIBUTE_UNUSED)
{
#ifndef POINTERS_EXTEND_UNSIGNED
gcc_assert (GET_MODE (x) == to_mode || GET_MODE (x) == VOIDmode);
return x;
#else /* defined(POINTERS_EXTEND_UNSIGNED) */
- enum machine_mode pointer_mode, address_mode, from_mode;
+ machine_mode pointer_mode, address_mode, from_mode;
rtx temp;
enum rtx_code code;
to the default case. */
switch (GET_CODE (x))
{
- case CONST_INT:
- case CONST_DOUBLE:
+ CASE_CONST_SCALAR_INT:
if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode))
code = TRUNCATE;
else if (POINTERS_EXTEND_UNSIGNED < 0)
break;
case LABEL_REF:
- temp = gen_rtx_LABEL_REF (to_mode, XEXP (x, 0));
+ temp = gen_rtx_LABEL_REF (to_mode, LABEL_REF_LABEL (x));
LABEL_REF_NONLOCAL_P (temp) = LABEL_REF_NONLOCAL_P (x);
return temp;
break;
case CONST:
return gen_rtx_CONST (to_mode,
- convert_memory_address_addr_space
- (to_mode, XEXP (x, 0), as));
+ convert_memory_address_addr_space_1
+ (to_mode, XEXP (x, 0), as, true));
break;
case PLUS:
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. */
+ narrower. Inside a CONST RTL, this is safe for both pointers
+ zero or sign extended as pointers cannot wrap. */
if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode)
|| (GET_CODE (x) == PLUS
&& CONST_INT_P (XEXP (x, 1))
- && (XEXP (x, 1) == convert_memory_address_addr_space
- (to_mode, XEXP (x, 1), as)
- || POINTERS_EXTEND_UNSIGNED < 0)))
+ && ((in_const && POINTERS_EXTEND_UNSIGNED != 0)
+ || XEXP (x, 1) == convert_memory_address_addr_space_1
+ (to_mode, XEXP (x, 1), as, in_const)
+ || POINTERS_EXTEND_UNSIGNED < 0)))
return gen_rtx_fmt_ee (GET_CODE (x), to_mode,
- convert_memory_address_addr_space
- (to_mode, XEXP (x, 0), as),
+ convert_memory_address_addr_space_1
+ (to_mode, XEXP (x, 0), as, in_const),
XEXP (x, 1));
break;
x, POINTERS_EXTEND_UNSIGNED);
#endif /* defined(POINTERS_EXTEND_UNSIGNED) */
}
+
+/* Given X, a memory address in address space AS' pointer mode, convert it to
+ an address in the address space's address mode, or vice versa (TO_MODE says
+ which way). We take advantage of the fact that pointers are not allowed to
+ overflow by commuting arithmetic operations over conversions so that address
+ arithmetic insns can be used. */
+
+rtx
+convert_memory_address_addr_space (machine_mode to_mode, rtx x, addr_space_t as)
+{
+ return convert_memory_address_addr_space_1 (to_mode, x, as, false);
+}
\f
+
/* Return something equivalent to X but valid as a memory address for something
of mode MODE in the named address space AS. When X is not itself valid,
this works by copying X or subexpressions of it into registers. */
rtx
-memory_address_addr_space (enum machine_mode mode, rtx x, addr_space_t as)
+memory_address_addr_space (machine_mode mode, rtx x, addr_space_t as)
{
rtx oldx = x;
- enum machine_mode address_mode = targetm.addr_space.address_mode (as);
+ machine_mode address_mode = targetm.addr_space.address_mode (as);
x = convert_memory_address_addr_space (address_mode, x, as);
return x;
}
-/* Convert a mem ref into one with a valid memory address.
- Pass through anything else unchanged. */
+/* If REF is a MEM with an invalid address, change it into a valid address.
+ Pass through anything else unchanged. REF must be an unshared rtx and
+ the function may modify it in-place. */
rtx
validize_mem (rtx ref)
MEM_ADDR_SPACE (ref)))
return ref;
- /* Don't alter REF itself, since that is probably a stack slot. */
- return replace_equiv_address (ref, XEXP (ref, 0));
+ return replace_equiv_address (ref, XEXP (ref, 0), true);
}
/* If X is a memory reference to a member of an object block, try rewriting
{
rtx base;
HOST_WIDE_INT offset;
+ machine_mode mode;
if (!flag_section_anchors)
return x;
/* 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. */
+ mode = GET_MODE (base);
if (!cse_not_expected)
- base = force_reg (GET_MODE (base), base);
+ base = force_reg (mode, base);
- return replace_equiv_address (x, plus_constant (base, offset));
+ return replace_equiv_address (x, plus_constant (mode, base, offset));
}
\f
/* Copy the value or contents of X to a new temp reg and return that reg. */
in case X is a constant. */
rtx
-copy_to_mode_reg (enum machine_mode mode, rtx x)
+copy_to_mode_reg (machine_mode mode, rtx x)
{
rtx temp = gen_reg_rtx (mode);
since we mark it as a "constant" register. */
rtx
-force_reg (enum machine_mode mode, rtx x)
+force_reg (machine_mode mode, rtx x)
{
- rtx temp, insn, set;
+ rtx temp, set;
+ rtx_insn *insn;
if (REG_P (x))
return x;
MODE is the mode to use for X in case it is a constant. */
rtx
-copy_to_suggested_reg (rtx x, rtx target, enum machine_mode mode)
+copy_to_suggested_reg (rtx x, rtx target, machine_mode mode)
{
rtx temp;
FOR_RETURN is nonzero if the caller is promoting the return value
of FNDECL, else it is for promoting args. */
-enum machine_mode
-promote_function_mode (const_tree type, enum machine_mode mode, int *punsignedp,
+machine_mode
+promote_function_mode (const_tree type, machine_mode mode, int *punsignedp,
const_tree funtype, int for_return)
{
/* Called without a type node for a libcall. */
PUNSIGNEDP points to the signedness of the type and may be adjusted
to show what signedness to use on extension operations. */
-enum machine_mode
-promote_mode (const_tree type ATTRIBUTE_UNUSED, enum machine_mode mode,
+machine_mode
+promote_mode (const_tree type ATTRIBUTE_UNUSED, machine_mode mode,
int *punsignedp ATTRIBUTE_UNUSED)
{
#ifdef PROMOTE_MODE
mode of DECL. If PUNSIGNEDP is not NULL, store there the unsignedness
of DECL after promotion. */
-enum machine_mode
+machine_mode
promote_decl_mode (const_tree decl, int *punsignedp)
{
tree type = TREE_TYPE (decl);
int unsignedp = TYPE_UNSIGNED (type);
- enum machine_mode mode = DECL_MODE (decl);
- enum machine_mode pmode;
+ machine_mode mode = DECL_MODE (decl);
+ machine_mode pmode;
if (TREE_CODE (decl) == RESULT_DECL
|| TREE_CODE (decl) == PARM_DECL)
static void
adjust_stack_1 (rtx adjust, bool anti_p)
{
- rtx temp, insn;
+ rtx temp;
+ rtx_insn *insn;
-#ifndef STACK_GROWS_DOWNWARD
/* Hereafter anti_p means subtract_p. */
- anti_p = !anti_p;
-#endif
+ if (!STACK_GROWS_DOWNWARD)
+ anti_p = !anti_p;
temp = expand_binop (Pmode,
anti_p ? sub_optab : add_optab,
substituted by the right value in vregs pass and optimized
during combine. */
align_rtx = virtual_preferred_stack_boundary_rtx;
- alignm1_rtx = force_operand (plus_constant (align_rtx, -1), NULL_RTX);
+ alignm1_rtx = force_operand (plus_constant (Pmode, align_rtx, -1),
+ NULL_RTX);
}
/* CEIL_DIV_EXPR needs to worry about the addition overflowing,
{
rtx sa = *psave;
/* The default is that we use a move insn and save in a Pmode object. */
- rtx (*fcn) (rtx, rtx) = gen_move_insn;
- enum machine_mode mode = STACK_SAVEAREA_MODE (save_level);
+ rtx (*fcn) (rtx, rtx) = gen_move_insn_uncast;
+ machine_mode mode = STACK_SAVEAREA_MODE (save_level);
/* See if this machine has anything special to do for this kind of save. */
switch (save_level)
emit_stack_restore (enum save_level save_level, rtx sa)
{
/* The default is that we use a move insn. */
- rtx (*fcn) (rtx, rtx) = gen_move_insn;
+ rtx (*fcn) (rtx, rtx) = gen_move_insn_uncast;
+
+ /* If stack_realign_drap, the x86 backend emits a prologue that aligns both
+ STACK_POINTER and HARD_FRAME_POINTER.
+ If stack_realign_fp, the x86 backend emits a prologue that aligns only
+ STACK_POINTER. This renders the HARD_FRAME_POINTER unusable for accessing
+ aligned variables, which is reflected in ix86_can_eliminate.
+ We normally still have the realigned STACK_POINTER that we can use.
+ But if there is a stack restore still present at reload, it can trigger
+ mark_not_eliminable for the STACK_POINTER, leaving no way to eliminate
+ FRAME_POINTER into a hard reg.
+ To prevent this situation, we force need_drap if we emit a stack
+ restore. */
+ if (SUPPORTS_STACK_ALIGNMENT)
+ crtl->need_drap = true;
/* See if this machine has anything special to do for this kind of save. */
switch (save_level)
}
/* Invoke emit_stack_save on the nonlocal_goto_save_area for the current
- function. This function should be called whenever we allocate or
- deallocate dynamic stack space. */
+ function. This should be called whenever we allocate or deallocate
+ dynamic stack space. */
void
update_nonlocal_goto_save_area (void)
emit_stack_save (SAVE_NONLOCAL, &r_save);
}
+
+/* Record a new stack level for the current function. This should be called
+ whenever we allocate or deallocate dynamic stack space. */
+
+void
+record_new_stack_level (void)
+{
+ /* Record the new stack level for nonlocal gotos. */
+ if (cfun->nonlocal_goto_save_area)
+ update_nonlocal_goto_save_area ();
+
+ /* Record the new stack level for SJLJ exceptions. */
+ if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
+ update_sjlj_context ();
+}
\f
/* Return an rtx representing the address of an area of memory dynamically
pushed on the stack.
unsigned required_align, bool cannot_accumulate)
{
HOST_WIDE_INT stack_usage_size = -1;
- rtx final_label, final_target, target;
+ rtx_code_label *final_label;
+ rtx final_target, target;
unsigned extra_align = 0;
bool must_align;
{
/* Look into the last emitted insn and see if we can deduce
something for the register. */
- rtx insn, set, note;
+ rtx_insn *insn;
+ rtx set, note;
insn = get_last_insn ();
if ((set = single_set (insn)) && rtx_equal_p (SET_DEST (set), size))
{
{
unsigned extra = (required_align - extra_align) / BITS_PER_UNIT;
- size = plus_constant (size, extra);
+ size = plus_constant (Pmode, size, extra);
size = force_operand (size, NULL_RTX);
if (flag_stack_usage_info)
current_function_has_unbounded_dynamic_stack_size = 1;
}
- final_label = NULL_RTX;
+ final_label = NULL;
final_target = NULL_RTX;
/* If we are splitting the stack, we need to ask the backend whether
least it doesn't cause a stack overflow. */
if (flag_split_stack)
{
- rtx available_label, ask, space, func;
+ rtx_code_label *available_label;
+ rtx ask, space, func;
- available_label = NULL_RTX;
+ available_label = NULL;
#ifdef HAVE_split_stack_space_check
if (HAVE_split_stack_space_check)
else
{
ask = expand_binop (Pmode, add_optab, size,
- GEN_INT (required_align / BITS_PER_UNIT - 1),
+ gen_int_mode (required_align / BITS_PER_UNIT - 1,
+ Pmode),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
must_align = true;
}
else if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
probe_stack_range (STACK_CHECK_PROTECT, size);
+ /* Don't let anti_adjust_stack emit notes. */
+ suppress_reg_args_size = true;
+
/* Perform the required allocation from the stack. Some systems do
this differently than simply incrementing/decrementing from the
stack pointer, such as acquiring the space by calling malloc(). */
{
int saved_stack_pointer_delta;
-#ifndef STACK_GROWS_DOWNWARD
- emit_move_insn (target, virtual_stack_dynamic_rtx);
-#endif
+ if (!STACK_GROWS_DOWNWARD)
+ emit_move_insn (target, virtual_stack_dynamic_rtx);
/* Check stack bounds if necessary. */
if (crtl->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
+ rtx_code_label *space_available = gen_label_rtx ();
+ if (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);
+
emit_cmp_and_jump_insns (available, size, GEU, NULL_RTX, Pmode, 1,
space_available);
#ifdef HAVE_trap
}
saved_stack_pointer_delta = stack_pointer_delta;
- suppress_reg_args_size = true;
if (flag_stack_check && STACK_CHECK_MOVING_SP)
anti_adjust_stack_and_probe (size, false);
The constant size alloca should preserve
crtl->preferred_stack_boundary alignment. */
stack_pointer_delta = saved_stack_pointer_delta;
- suppress_reg_args_size = false;
-#ifdef STACK_GROWS_DOWNWARD
- emit_move_insn (target, virtual_stack_dynamic_rtx);
-#endif
+ if (STACK_GROWS_DOWNWARD)
+ emit_move_insn (target, virtual_stack_dynamic_rtx);
}
+ suppress_reg_args_size = false;
+
/* Finish up the split stack handling. */
if (final_label != NULL_RTX)
{
but we know it can't. So add ourselves and then do
TRUNC_DIV_EXPR. */
target = expand_binop (Pmode, add_optab, target,
- GEN_INT (required_align / BITS_PER_UNIT - 1),
+ gen_int_mode (required_align / BITS_PER_UNIT - 1,
+ Pmode),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
target = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, target,
- GEN_INT (required_align / BITS_PER_UNIT),
+ gen_int_mode (required_align / BITS_PER_UNIT,
+ Pmode),
NULL_RTX, 1);
target = expand_mult (Pmode, target,
- GEN_INT (required_align / BITS_PER_UNIT),
+ gen_int_mode (required_align / BITS_PER_UNIT,
+ Pmode),
NULL_RTX, 1);
}
/* Now that we've committed to a return value, mark its alignment. */
mark_reg_pointer (target, required_align);
- /* Record the new stack level for nonlocal gotos. */
- if (cfun->nonlocal_goto_save_area != 0)
- update_nonlocal_goto_save_area ();
+ /* Record the new stack level. */
+ record_new_stack_level ();
return target;
}
void
emit_stack_probe (rtx address)
{
- rtx memref = gen_rtx_MEM (word_mode, address);
+#ifdef HAVE_probe_stack_address
+ if (HAVE_probe_stack_address)
+ emit_insn (gen_probe_stack_address (address));
+ else
+#endif
+ {
+ rtx memref = gen_rtx_MEM (word_mode, address);
- MEM_VOLATILE_P (memref) = 1;
+ MEM_VOLATILE_P (memref) = 1;
- /* See if we have an insn to probe the stack. */
+ /* See if we have an insn to probe the stack. */
#ifdef HAVE_probe_stack
- if (HAVE_probe_stack)
- emit_insn (gen_probe_stack (memref));
- else
+ if (HAVE_probe_stack)
+ emit_insn (gen_probe_stack (memref));
+ else
#endif
- emit_move_insn (memref, const0_rtx);
+ emit_move_insn (memref, const0_rtx);
+ }
}
/* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive.
#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
-#ifdef STACK_GROWS_DOWNWARD
+#if STACK_GROWS_DOWNWARD
#define STACK_GROW_OP MINUS
#define STACK_GROW_OPTAB sub_optab
#define STACK_GROW_OFF(off) -(off)
rtx addr = memory_address (Pmode,
gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
- plus_constant (size, first)));
+ plus_constant (Pmode,
+ size, first)));
emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr,
Pmode);
- return;
}
/* Next see if we have an insn to check the stack. */
#ifdef HAVE_check_stack
- if (HAVE_check_stack)
+ else if (HAVE_check_stack)
{
struct expand_operand ops[1];
rtx addr = memory_address (Pmode,
gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
- plus_constant (size, first)));
-
+ plus_constant (Pmode,
+ size, first)));
+ bool success;
create_input_operand (&ops[0], addr, Pmode);
- if (maybe_expand_insn (CODE_FOR_check_stack, 1, ops))
- return;
+ success = maybe_expand_insn (CODE_FOR_check_stack, 1, ops);
+ gcc_assert (success);
}
#endif
for (i = PROBE_INTERVAL; i < isize; i += PROBE_INTERVAL)
{
addr = memory_address (Pmode,
- plus_constant (stack_pointer_rtx,
+ plus_constant (Pmode, stack_pointer_rtx,
STACK_GROW_OFF (first + i)));
emit_stack_probe (addr);
}
addr = memory_address (Pmode,
- plus_constant (stack_pointer_rtx,
+ plus_constant (Pmode, stack_pointer_rtx,
STACK_GROW_OFF (first + isize)));
emit_stack_probe (addr);
}
else
{
rtx rounded_size, rounded_size_op, test_addr, last_addr, temp;
- rtx loop_lab = gen_label_rtx ();
- rtx end_lab = gen_label_rtx ();
-
+ rtx_code_label *loop_lab = gen_label_rtx ();
+ rtx_code_label *end_lab = gen_label_rtx ();
/* Step 1: round SIZE to the previous multiple of the interval. */
/* ROUNDED_SIZE = SIZE & -PROBE_INTERVAL */
rounded_size
- = simplify_gen_binary (AND, Pmode, size, GEN_INT (-PROBE_INTERVAL));
+ = simplify_gen_binary (AND, Pmode, size,
+ gen_int_mode (-PROBE_INTERVAL, Pmode));
rounded_size_op = force_operand (rounded_size, NULL_RTX);
/* TEST_ADDR = SP + FIRST. */
test_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
- GEN_INT (first)), NULL_RTX);
+ gen_int_mode (first, Pmode)),
+ NULL_RTX);
/* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */
last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
/* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */
temp = expand_binop (Pmode, STACK_GROW_OPTAB, test_addr,
- GEN_INT (PROBE_INTERVAL), test_addr,
+ gen_int_mode (PROBE_INTERVAL, Pmode), test_addr,
1, OPTAB_WIDEN);
gcc_assert (temp == test_addr);
/* Use [base + disp} addressing mode if supported. */
HOST_WIDE_INT offset = INTVAL (temp);
addr = memory_address (Pmode,
- plus_constant (last_addr,
+ plus_constant (Pmode, last_addr,
STACK_GROW_OFF (offset)));
}
else
emit_stack_probe (addr);
}
}
+
+ /* Make sure nothing is scheduled before we are done. */
+ emit_insn (gen_blockage ());
}
/* Adjust the stack pointer by minus SIZE (an rtx for a number of bytes)
}
if (first_probe)
- anti_adjust_stack (plus_constant (size, PROBE_INTERVAL + dope));
+ anti_adjust_stack (plus_constant (Pmode, size, PROBE_INTERVAL + dope));
else
- anti_adjust_stack (plus_constant (size, PROBE_INTERVAL - i));
+ anti_adjust_stack (plus_constant (Pmode, size, PROBE_INTERVAL - i));
emit_stack_probe (stack_pointer_rtx);
}
else
{
rtx rounded_size, rounded_size_op, last_addr, temp;
- rtx loop_lab = gen_label_rtx ();
- rtx end_lab = gen_label_rtx ();
+ rtx_code_label *loop_lab = gen_label_rtx ();
+ rtx_code_label *end_lab = gen_label_rtx ();
/* Step 1: round SIZE to the previous multiple of the interval. */
/* ROUNDED_SIZE = SIZE & -PROBE_INTERVAL */
rounded_size
- = simplify_gen_binary (AND, Pmode, size, GEN_INT (-PROBE_INTERVAL));
+ = simplify_gen_binary (AND, Pmode, size,
+ gen_int_mode (-PROBE_INTERVAL, Pmode));
rounded_size_op = force_operand (rounded_size, NULL_RTX);
/* Adjust back and account for the additional first interval. */
if (adjust_back)
- adjust_stack (plus_constant (size, PROBE_INTERVAL + dope));
+ adjust_stack (plus_constant (Pmode, size, PROBE_INTERVAL + dope));
else
adjust_stack (GEN_INT (PROBE_INTERVAL + dope));
}
&& GET_MODE (val) == BLKmode)
{
unsigned HOST_WIDE_INT bytes = int_size_in_bytes (valtype);
- enum machine_mode tmpmode;
+ machine_mode tmpmode;
/* int_size_in_bytes can return -1. We don't need a check here
since the value of bytes will then be large enough that no
in which a scalar value of mode MODE was returned by a library call. */
rtx
-hard_libcall_value (enum machine_mode mode, rtx fun)
+hard_libcall_value (machine_mode mode, rtx fun)
{
return targetm.calls.libcall_value (mode, fun);
}