diff options
author | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-07-02 21:25:28 +0000 |
---|---|---|
committer | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-07-02 21:25:28 +0000 |
commit | f164c08a5ab59fc045ab26b4bbae6d8ecb0f5fff (patch) | |
tree | 07029562f5d29447aaea45407baa8ff6842f7694 | |
parent | 85f98cf615062134f884e8d112254aab8437392f (diff) | |
download | gcc-f164c08a5ab59fc045ab26b4bbae6d8ecb0f5fff.tar.gz |
* expr.h (emit_stack_probe): Declare.
* explow.c (emit_stack_probe): Make global.
(anti_adjust_stack_and_probe): Fix comments.
* config/sparc/linux.h (STACK_CHECK_STATIC_BUILTIN): Define to 1.
* config/sparc/linux64.h (STACK_CHECK_STATIC_BUILTIN): Likewise.
* config/sparc/sol2.h (STACK_CHECK_STATIC_BUILTIN): Likewise.
* config/sparc/sparc.c: Include except.h.
(sparc_emit_probe_stack_range): New function.
(output_probe_stack_range): Likewise.
(sparc_expand_prologue): Invoke sparc_emit_probe_stack_range if static
built-in stack checking is enabled.
* config/sparc/sparc-protos.h (output_probe_stack_range): Declare.
* config/sparc/sparc.md (UNSPECV_PROBE_STACK_RANGE): New constant.
(probe_stack_range): New insn.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@161749 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 25 | ||||
-rw-r--r-- | gcc/config/sparc/linux.h | 3 | ||||
-rw-r--r-- | gcc/config/sparc/linux64.h | 3 | ||||
-rw-r--r-- | gcc/config/sparc/sol2.h | 3 | ||||
-rw-r--r-- | gcc/config/sparc/sparc-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.c | 158 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.md | 10 | ||||
-rw-r--r-- | gcc/explow.c | 19 | ||||
-rw-r--r-- | gcc/expr.h | 3 |
9 files changed, 211 insertions, 14 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ef80e6e35a3..60db5de3dbc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2010-07-02 Eric Botcazou <ebotcazou@adacore.com> + + * expr.h (emit_stack_probe): Declare. + * explow.c (emit_stack_probe): Make global. + (anti_adjust_stack_and_probe): Fix comments. + * config/sparc/linux.h (STACK_CHECK_STATIC_BUILTIN): Define to 1. + * config/sparc/linux64.h (STACK_CHECK_STATIC_BUILTIN): Likewise. + * config/sparc/sol2.h (STACK_CHECK_STATIC_BUILTIN): Likewise. + * config/sparc/sparc.c: Include except.h. + (sparc_emit_probe_stack_range): New function. + (output_probe_stack_range): Likewise. + (sparc_expand_prologue): Invoke sparc_emit_probe_stack_range if static + built-in stack checking is enabled. + * config/sparc/sparc-protos.h (output_probe_stack_range): Declare. + * config/sparc/sparc.md (UNSPECV_PROBE_STACK_RANGE): New constant. + (probe_stack_range): New insn. + 2010-07-02 Richard Guenther <rguenther@suse.de> PR target/43958 @@ -6,14 +23,14 @@ 2010-07-02 Jan Hubicka <jh@suse.cz> - * ipa-split.c (verify_non_ssa_vars): Break out from ...; perform DFS walk - backwards from entry_bb to check only those basic block of header + * ipa-split.c (verify_non_ssa_vars): Break out from ...; perform DFS + walk backwards from entry_bb to check only those basic block of header that might lead to execution of split part. (consider_split) ... here. (find_return_bb): Allow assignment in return BB. (find_retval): New. - (split_function): Fix name of cloned function; take care of updating return - value in return_bb containing move. + (split_function): Fix name of cloned function; take care of updating + return value in return_bb containing move. 2010-07-02 Andreas Schwab <schwab@linux-m68k.org> diff --git a/gcc/config/sparc/linux.h b/gcc/config/sparc/linux.h index b12c881ebed..530a6ae7065 100644 --- a/gcc/config/sparc/linux.h +++ b/gcc/config/sparc/linux.h @@ -161,6 +161,9 @@ do { \ #undef CTORS_SECTION_ASM_OP #undef DTORS_SECTION_ASM_OP +/* Static stack checking is supported by means of probes. */ +#define STACK_CHECK_STATIC_BUILTIN 1 + #define MD_UNWIND_SUPPORT "config/sparc/linux-unwind.h" /* Linux currently uses RMO in uniprocessor mode, which is equivalent to diff --git a/gcc/config/sparc/linux64.h b/gcc/config/sparc/linux64.h index c2e78d726de..369c13c8e3c 100644 --- a/gcc/config/sparc/linux64.h +++ b/gcc/config/sparc/linux64.h @@ -287,6 +287,9 @@ do { \ #undef CTORS_SECTION_ASM_OP #undef DTORS_SECTION_ASM_OP +/* Static stack checking is supported by means of probes. */ +#define STACK_CHECK_STATIC_BUILTIN 1 + #define MD_UNWIND_SUPPORT "config/sparc/linux-unwind.h" /* Linux currently uses RMO in uniprocessor mode, which is equivalent to diff --git a/gcc/config/sparc/sol2.h b/gcc/config/sparc/sol2.h index a341bcfd30b..26c9ac7d396 100644 --- a/gcc/config/sparc/sol2.h +++ b/gcc/config/sparc/sol2.h @@ -188,4 +188,7 @@ along with GCC; see the file COPYING3. If not see #define PUSHSECTION_FORMAT "\t.pushsection\t\"%s\"\n" #endif +/* Static stack checking is supported by means of probes. */ +#define STACK_CHECK_STATIC_BUILTIN 1 + #define MD_UNWIND_SUPPORT "config/sparc/sol2-unwind.h" diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h index cc51280596c..35c99b967ba 100644 --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -75,6 +75,7 @@ extern const char *output_return (rtx); extern const char *output_sibcall (rtx, rtx); extern const char *output_v8plus_shift (rtx *, rtx, const char *); extern const char *output_v9branch (rtx, rtx, int, int, int, int, rtx); +extern const char *output_probe_stack_range (rtx, rtx); extern bool emit_scc_insn (rtx []); extern void emit_conditional_branch_insn (rtx []); extern void print_operand (FILE *, rtx, int); diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 412f27c3066..f00b1ccfe5d 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "insn-attr.h" #include "flags.h" #include "function.h" +#include "except.h" #include "expr.h" #include "optabs.h" #include "recog.h" @@ -4005,6 +4006,160 @@ sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED) #endif } +#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP) + +#if PROBE_INTERVAL > 4096 +#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. + + Note that we don't use the REG+REG addressing mode for the probes because + of the stack bias in 64-bit mode. And it doesn't really buy us anything + so the advantages of having a single code win here. */ + +static void +sparc_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size) +{ + rtx g1 = gen_rtx_REG (Pmode, 1); + + /* See if we have a constant small number of probes to generate. If so, + that's the easy case. */ + if (size <= PROBE_INTERVAL) + { + emit_move_insn (g1, GEN_INT (first)); + emit_insn (gen_rtx_SET (VOIDmode, g1, + gen_rtx_MINUS (Pmode, stack_pointer_rtx, g1))); + emit_stack_probe (plus_constant (g1, -size)); + } + + /* The run-time loop is made up of 10 insns in the generic case while the + compile-time loop is made up of 4+2*(n-2) insns for n # of intervals. */ + else if (size <= 5 * PROBE_INTERVAL) + { + HOST_WIDE_INT i; + + emit_move_insn (g1, GEN_INT (first + PROBE_INTERVAL)); + emit_insn (gen_rtx_SET (VOIDmode, g1, + gen_rtx_MINUS (Pmode, stack_pointer_rtx, g1))); + emit_stack_probe (g1); + + /* Probe at FIRST + N * PROBE_INTERVAL for values of N from 2 until + it exceeds SIZE. If only two probes are needed, this will not + generate any code. Then probe at FIRST + SIZE. */ + for (i = 2 * PROBE_INTERVAL; i < size; i += PROBE_INTERVAL) + { + emit_insn (gen_rtx_SET (VOIDmode, g1, + plus_constant (g1, -PROBE_INTERVAL))); + emit_stack_probe (g1); + } + + emit_stack_probe (plus_constant (g1, (i - PROBE_INTERVAL) - 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 g4 = gen_rtx_REG (Pmode, 4); + + emit_move_insn (g1, GEN_INT (first)); + + + /* Step 1: round SIZE to the previous multiple of the interval. */ + + rounded_size = size & -PROBE_INTERVAL; + emit_move_insn (g4, GEN_INT (rounded_size)); + + + /* Step 2: compute initial and final value of the loop counter. */ + + /* TEST_ADDR = SP + FIRST. */ + emit_insn (gen_rtx_SET (VOIDmode, g1, + gen_rtx_MINUS (Pmode, stack_pointer_rtx, g1))); + + /* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */ + emit_insn (gen_rtx_SET (VOIDmode, g4, gen_rtx_MINUS (Pmode, g1, g4))); + + + /* 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 (g1, g1, g4)); + else + emit_insn (gen_probe_stack_rangesi (g1, g1, g4)); + + + /* 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 (g4, rounded_size - size)); + } + + /* Make sure nothing is scheduled before we are done. */ + emit_insn (gen_blockage ()); +} + +/* 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; + output_asm_insn ("cmp\t%0, %1", xops); + if (TARGET_ARCH64) + fputs ("\tbe,pn\t%xcc,", asm_out_file); + else + fputs ("\tbe\t", 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 (" add\t%0, %1, %0", xops); + + /* Probe at TEST_ADDR and branch. */ + if (TARGET_ARCH64) + fputs ("\tba,pt\t%xcc,", asm_out_file); + else + fputs ("\tba\t", asm_out_file); + assemble_name_raw (asm_out_file, loop_lab); + fputc ('\n', asm_out_file); + xops[1] = GEN_INT (SPARC_STACK_BIAS); + output_asm_insn (" st\t%%g0, [%0+%1]", xops); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, end_lab); + + return ""; +} + /* Save/restore call-saved registers from LOW to HIGH at BASE+OFFSET as needed. LOW should be double-word aligned for 32-bit registers. Return the new OFFSET. */ @@ -4193,6 +4348,9 @@ sparc_expand_prologue (void) /* Advertise that the data calculated just above are now valid. */ sparc_prologue_data_valid_p = true; + if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && actual_fsize) + sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, actual_fsize); + if (sparc_leaf_function_p) { frame_base_reg = stack_pointer_rtx; diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 7eb8ece783a..301a63c2693 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -75,6 +75,7 @@ (UNSPECV_CAS 8) (UNSPECV_SWAP 9) (UNSPECV_LDSTUB 10) + (UNSPECV_PROBE_STACK_RANGE 11) ]) @@ -6340,6 +6341,15 @@ = adjust_address (operands[0], GET_MODE (operands[0]), SPARC_STACK_BIAS); }) +(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" "multi")]) + ;; Prepare to return any type including a structure value. (define_expand "untyped_return" diff --git a/gcc/explow.c b/gcc/explow.c index 40b3a6ef424..bd2ab798aa0 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -43,7 +43,6 @@ along with GCC; see the file COPYING3. If not see #include "output.h" static rtx break_out_memory_refs (rtx); -static void emit_stack_probe (rtx); /* Truncate and perhaps sign-extend C as appropriate for MODE. */ @@ -1355,7 +1354,7 @@ set_stack_check_libfunc (const char *libfunc_name) /* Emit one stack probe at ADDRESS, an address within the stack. */ -static void +void emit_stack_probe (rtx address) { rtx memref = gen_rtx_MEM (word_mode, address); @@ -1567,7 +1566,7 @@ anti_adjust_stack_and_probe (rtx size, bool adjust_back) HOST_WIDE_INT isize = INTVAL (size), i; bool first_probe = true; - /* Adjust SP and probe to PROBE_INTERVAL + N * PROBE_INTERVAL for + /* Adjust SP and probe at PROBE_INTERVAL + 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 adjust and probe to PROBE_INTERVAL + SIZE. */ @@ -1623,13 +1622,13 @@ anti_adjust_stack_and_probe (rtx size, bool adjust_back) /* Step 3: the loop - while (SP != LAST_ADDR) - { - SP = SP + PROBE_INTERVAL - probe at SP - } + while (SP != LAST_ADDR) + { + SP = SP + PROBE_INTERVAL + probe at SP + } - adjusts SP and probes to PROBE_INTERVAL + N * PROBE_INTERVAL for + adjusts SP and probes at PROBE_INTERVAL + N * PROBE_INTERVAL for values of N from 1 until it is equal to ROUNDED_SIZE. */ emit_label (loop_lab); @@ -1647,7 +1646,7 @@ anti_adjust_stack_and_probe (rtx size, bool adjust_back) emit_label (end_lab); - /* Step 4: adjust SP and probe to PROBE_INTERVAL + SIZE if we cannot + /* Step 4: adjust SP and probe at PROBE_INTERVAL + SIZE if we cannot assert at compile-time that SIZE is equal to ROUNDED_SIZE. */ /* TEMP = SIZE - ROUNDED_SIZE. */ diff --git a/gcc/expr.h b/gcc/expr.h index 6ee964a39f4..c71b8edcbb7 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -645,6 +645,9 @@ extern void update_nonlocal_goto_save_area (void); says how many bytes. */ extern rtx allocate_dynamic_stack_space (rtx, rtx, int); +/* Emit one stack probe at ADDRESS, an address within the stack. */ +extern void emit_stack_probe (rtx); + /* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive. FIRST is a constant and size is a Pmode RTX. These are offsets from the current stack pointer. STACK_GROWS_DOWNWARD says whether to add |