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:
Eric Botcazou 2010-08-20 21:22:16 +00:00 committed by Eric Botcazou
parent 410841c6d5
commit 39acb18f66
7 changed files with 171 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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.