From 39acb18f66f7b0ff8c36f5fa96e76168f959d2a1 Mon Sep 17 00:00:00 2001 From: Eric Botcazou <ebotcazou@adacore.com> Date: Fri, 20 Aug 2010 21:22:16 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 14 ++++ gcc/config/rs6000/aix.h | 3 + gcc/config/rs6000/linux.h | 3 + gcc/config/rs6000/linux64.h | 6 ++ gcc/config/rs6000/rs6000-protos.h | 1 + gcc/config/rs6000/rs6000.c | 134 ++++++++++++++++++++++++++++++ gcc/config/rs6000/rs6000.md | 10 +++ 7 files changed, 171 insertions(+) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9f7a8c587919..8a7634749100 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/config/rs6000/aix.h b/gcc/config/rs6000/aix.h index ec7add4c2e64..a5eb89da171f 100644 --- a/gcc/config/rs6000/aix.h +++ b/gcc/config/rs6000/aix.h @@ -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 diff --git a/gcc/config/rs6000/linux.h b/gcc/config/rs6000/linux.h index d41c0dc56ef5..c659a3eac476 100644 --- a/gcc/config/rs6000/linux.h +++ b/gcc/config/rs6000/linux.h @@ -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 diff --git a/gcc/config/rs6000/linux64.h b/gcc/config/rs6000/linux64.h index 900570f2ea17..0e165ea7199a 100644 --- a/gcc/config/rs6000/linux64.h +++ b/gcc/config/rs6000/linux64.h @@ -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) diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 02377f298e5b..8708accd7eaf 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -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); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 89e0127a479f..3928901cdd9a 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -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 diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 0ef7e98d9e53..c5e0ba1519b4 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -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. -- GitLab