aix.h (STACK_CHECK_STATIC_BUILTIN): Define to 1.
* config/rs6000/aix.h (STACK_CHECK_STATIC_BUILTIN): Define to 1. * config/rs6000/linux.h (STACK_CHECK_STATIC_BUILTIN): Likewise. * config/rs6000/linux64.h (STACK_CHECK_STATIC_BUILTIN): Likewise. (STACK_CHECK_PROTECT): Define. * config/rs6000/rs6000.c (rs6000_emit_probe_stack_range): New function. (output_probe_stack_range): Likewise. (rs6000_emit_prologue): Invoke rs6000_emit_probe_stack_range if static builtin stack checking is enabled. * config/rs6000/rs6000-protos.h (output_probe_stack_range): Declare. * config/rs6000/rs6000.md (UNSPECV_PROBE_STACK_RANGE): New constant. (probe_stack_range): New insn. From-SVN: r163424
This commit is contained in:
parent
410841c6d5
commit
39acb18f66
@ -1,3 +1,17 @@
|
||||
2010-08-20 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* config/rs6000/aix.h (STACK_CHECK_STATIC_BUILTIN): Define to 1.
|
||||
* config/rs6000/linux.h (STACK_CHECK_STATIC_BUILTIN): Likewise.
|
||||
* config/rs6000/linux64.h (STACK_CHECK_STATIC_BUILTIN): Likewise.
|
||||
(STACK_CHECK_PROTECT): Define.
|
||||
* config/rs6000/rs6000.c (rs6000_emit_probe_stack_range): New function.
|
||||
(output_probe_stack_range): Likewise.
|
||||
(rs6000_emit_prologue): Invoke rs6000_emit_probe_stack_range if static
|
||||
builtin stack checking is enabled.
|
||||
* config/rs6000/rs6000-protos.h (output_probe_stack_range): Declare.
|
||||
* config/rs6000/rs6000.md (UNSPECV_PROBE_STACK_RANGE): New constant.
|
||||
(probe_stack_range): New insn.
|
||||
|
||||
2010-08-20 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
PR target/45336
|
||||
|
@ -260,3 +260,6 @@
|
||||
|
||||
/* WINT_TYPE */
|
||||
#define WINT_TYPE "int"
|
||||
|
||||
/* Static stack checking is supported by means of probes. */
|
||||
#define STACK_CHECK_STATIC_BUILTIN 1
|
||||
|
@ -130,3 +130,6 @@
|
||||
#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
|
||||
#define RS6000_DEFAULT_LONG_DOUBLE_SIZE 128
|
||||
#endif
|
||||
|
||||
/* Static stack checking is supported by means of probes. */
|
||||
#define STACK_CHECK_STATIC_BUILTIN 1
|
||||
|
@ -573,3 +573,9 @@ extern enum rs6000_cmodel cmodel;
|
||||
#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
|
||||
#define RS6000_DEFAULT_LONG_DOUBLE_SIZE 128
|
||||
#endif
|
||||
|
||||
/* Static stack checking is supported by means of probes. */
|
||||
#define STACK_CHECK_STATIC_BUILTIN 1
|
||||
|
||||
/* The default value isn't sufficient in 64-bit mode. */
|
||||
#define STACK_CHECK_PROTECT (TARGET_64BIT ? 16 * 1024 : 12 * 1024)
|
||||
|
@ -95,6 +95,7 @@ extern void rs6000_emit_sCOND (enum machine_mode, rtx[]);
|
||||
extern void rs6000_emit_cbranch (enum machine_mode, rtx[]);
|
||||
extern char * output_cbranch (rtx, const char *, int, rtx);
|
||||
extern char * output_e500_flip_gt_bit (rtx, rtx);
|
||||
extern const char * output_probe_stack_range (rtx, rtx);
|
||||
extern rtx rs6000_emit_set_const (rtx, enum machine_mode, rtx, int);
|
||||
extern int rs6000_emit_cmove (rtx, rtx, rtx, rtx);
|
||||
extern int rs6000_emit_vector_cond_expr (rtx, rtx, rtx, rtx, rtx, rtx);
|
||||
|
@ -18788,6 +18788,137 @@ rs6000_emit_allocate_stack (HOST_WIDE_INT size, rtx copy_reg)
|
||||
GEN_INT (-size))));
|
||||
}
|
||||
|
||||
#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
|
||||
|
||||
#if PROBE_INTERVAL > 32768
|
||||
#error Cannot use indexed addressing mode for stack probing
|
||||
#endif
|
||||
|
||||
/* Emit code to probe a range of stack addresses from FIRST to FIRST+SIZE,
|
||||
inclusive. These are offsets from the current stack pointer. */
|
||||
|
||||
static void
|
||||
rs6000_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size)
|
||||
{
|
||||
/* See if we have a constant small number of probes to generate. If so,
|
||||
that's the easy case. */
|
||||
if (first + size <= 32768)
|
||||
{
|
||||
HOST_WIDE_INT i;
|
||||
|
||||
/* Probe at FIRST + N * PROBE_INTERVAL for values of N from 1 until
|
||||
it exceeds SIZE. If only one probe is needed, this will not
|
||||
generate any code. Then probe at FIRST + SIZE. */
|
||||
for (i = PROBE_INTERVAL; i < size; i += PROBE_INTERVAL)
|
||||
emit_stack_probe (plus_constant (stack_pointer_rtx, -(first + i)));
|
||||
|
||||
emit_stack_probe (plus_constant (stack_pointer_rtx, -(first + size)));
|
||||
}
|
||||
|
||||
/* Otherwise, do the same as above, but in a loop. Note that we must be
|
||||
extra careful with variables wrapping around because we might be at
|
||||
the very top (or the very bottom) of the address space and we have
|
||||
to be able to handle this case properly; in particular, we use an
|
||||
equality test for the loop condition. */
|
||||
else
|
||||
{
|
||||
HOST_WIDE_INT rounded_size;
|
||||
rtx r12 = gen_rtx_REG (Pmode, 12);
|
||||
rtx r0 = gen_rtx_REG (Pmode, 0);
|
||||
|
||||
/* Sanity check for the addressing mode we're going to use. */
|
||||
gcc_assert (first <= 32768);
|
||||
|
||||
/* Step 1: round SIZE to the previous multiple of the interval. */
|
||||
|
||||
rounded_size = size & -PROBE_INTERVAL;
|
||||
|
||||
|
||||
/* Step 2: compute initial and final value of the loop counter. */
|
||||
|
||||
/* TEST_ADDR = SP + FIRST. */
|
||||
emit_insn (gen_rtx_SET (VOIDmode, r12,
|
||||
plus_constant (stack_pointer_rtx, -first)));
|
||||
|
||||
/* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */
|
||||
if (rounded_size > 32768)
|
||||
{
|
||||
emit_move_insn (r0, GEN_INT (-rounded_size));
|
||||
emit_insn (gen_rtx_SET (VOIDmode, r0,
|
||||
gen_rtx_PLUS (Pmode, r12, r0)));
|
||||
}
|
||||
else
|
||||
emit_insn (gen_rtx_SET (VOIDmode, r0,
|
||||
plus_constant (r12, -rounded_size)));
|
||||
|
||||
|
||||
/* Step 3: the loop
|
||||
|
||||
while (TEST_ADDR != LAST_ADDR)
|
||||
{
|
||||
TEST_ADDR = TEST_ADDR + PROBE_INTERVAL
|
||||
probe at TEST_ADDR
|
||||
}
|
||||
|
||||
probes at FIRST + N * PROBE_INTERVAL for values of N from 1
|
||||
until it is equal to ROUNDED_SIZE. */
|
||||
|
||||
if (TARGET_64BIT)
|
||||
emit_insn (gen_probe_stack_rangedi (r12, r12, r0));
|
||||
else
|
||||
emit_insn (gen_probe_stack_rangesi (r12, r12, r0));
|
||||
|
||||
|
||||
/* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time
|
||||
that SIZE is equal to ROUNDED_SIZE. */
|
||||
|
||||
if (size != rounded_size)
|
||||
emit_stack_probe (plus_constant (r12, rounded_size - size));
|
||||
}
|
||||
}
|
||||
|
||||
/* Probe a range of stack addresses from REG1 to REG2 inclusive. These are
|
||||
absolute addresses. */
|
||||
|
||||
const char *
|
||||
output_probe_stack_range (rtx reg1, rtx reg2)
|
||||
{
|
||||
static int labelno = 0;
|
||||
char loop_lab[32], end_lab[32];
|
||||
rtx xops[2];
|
||||
|
||||
ASM_GENERATE_INTERNAL_LABEL (loop_lab, "LPSRL", labelno);
|
||||
ASM_GENERATE_INTERNAL_LABEL (end_lab, "LPSRE", labelno++);
|
||||
|
||||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, loop_lab);
|
||||
|
||||
/* Jump to END_LAB if TEST_ADDR == LAST_ADDR. */
|
||||
xops[0] = reg1;
|
||||
xops[1] = reg2;
|
||||
if (TARGET_64BIT)
|
||||
output_asm_insn ("{cmp|cmpd} 0,%0,%1", xops);
|
||||
else
|
||||
output_asm_insn ("{cmp|cmpw} 0,%0,%1", xops);
|
||||
|
||||
fputs ("\tbeq 0,", asm_out_file);
|
||||
assemble_name_raw (asm_out_file, end_lab);
|
||||
fputc ('\n', asm_out_file);
|
||||
|
||||
/* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */
|
||||
xops[1] = GEN_INT (-PROBE_INTERVAL);
|
||||
output_asm_insn ("{cal %0,%1(%0)|addi %0,%0,%1}", xops);
|
||||
|
||||
/* Probe at TEST_ADDR and branch. */
|
||||
output_asm_insn ("{st|stw} 0,0(%0)", xops);
|
||||
fprintf (asm_out_file, "\tb ");
|
||||
assemble_name_raw (asm_out_file, loop_lab);
|
||||
fputc ('\n', asm_out_file);
|
||||
|
||||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, end_lab);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Add to 'insn' a note which is PATTERN (INSN) but with REG replaced
|
||||
with (plus:P (reg 1) VAL), and with REG2 replaced with RREG if REG2
|
||||
is not NULL. It would be nice if dwarf2out_frame_debug_expr could
|
||||
@ -19400,6 +19531,9 @@ rs6000_emit_prologue (void)
|
||||
&& call_used_regs[STATIC_CHAIN_REGNUM]);
|
||||
HOST_WIDE_INT sp_offset = 0;
|
||||
|
||||
if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && info->total_size)
|
||||
rs6000_emit_probe_stack_range (STACK_CHECK_PROTECT, info->total_size);
|
||||
|
||||
if (TARGET_FIX_AND_CONTINUE)
|
||||
{
|
||||
/* gdb on darwin arranges to forward a function from the old
|
||||
|
@ -115,6 +115,7 @@
|
||||
[(UNSPECV_BLOCK 0)
|
||||
(UNSPECV_LL 1) ; load-locked
|
||||
(UNSPECV_SC 2) ; store-conditional
|
||||
(UNSPECV_PROBE_STACK_RANGE 3) ; probe range of stack addresses
|
||||
(UNSPECV_EH_RR 9) ; eh_reg_restore
|
||||
])
|
||||
|
||||
@ -12663,6 +12664,15 @@
|
||||
"{st%U0%X0|stw%U0%X0} 0,%0"
|
||||
[(set_attr "type" "store")
|
||||
(set_attr "length" "4")])
|
||||
|
||||
(define_insn "probe_stack_range<P:mode>"
|
||||
[(set (match_operand:P 0 "register_operand" "=r")
|
||||
(unspec_volatile:P [(match_operand:P 1 "register_operand" "0")
|
||||
(match_operand:P 2 "register_operand" "r")]
|
||||
UNSPECV_PROBE_STACK_RANGE))]
|
||||
""
|
||||
"* return output_probe_stack_range (operands[0], operands[2]);"
|
||||
[(set_attr "type" "three")])
|
||||
|
||||
;; Compare insns are next. Note that the RS/6000 has two types of compares,
|
||||
;; signed & unsigned, and one type of branch.
|
||||
|
Loading…
Reference in New Issue
Block a user