Commit 260c8ba3 by Eric Botcazou

expr.h (emit_stack_probe): Declare.

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

From-SVN: r161749
parent 8c54dc55
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> 2010-07-02 Richard Guenther <rguenther@suse.de>
PR target/43958 PR target/43958
...@@ -6,14 +23,14 @@ ...@@ -6,14 +23,14 @@
2010-07-02 Jan Hubicka <jh@suse.cz> 2010-07-02 Jan Hubicka <jh@suse.cz>
* ipa-split.c (verify_non_ssa_vars): Break out from ...; perform DFS walk * ipa-split.c (verify_non_ssa_vars): Break out from ...; perform DFS
backwards from entry_bb to check only those basic block of header walk backwards from entry_bb to check only those basic block of header
that might lead to execution of split part. that might lead to execution of split part.
(consider_split) ... here. (consider_split) ... here.
(find_return_bb): Allow assignment in return BB. (find_return_bb): Allow assignment in return BB.
(find_retval): New. (find_retval): New.
(split_function): Fix name of cloned function; take care of updating return (split_function): Fix name of cloned function; take care of updating
value in return_bb containing move. return value in return_bb containing move.
2010-07-02 Andreas Schwab <schwab@linux-m68k.org> 2010-07-02 Andreas Schwab <schwab@linux-m68k.org>
......
...@@ -161,6 +161,9 @@ do { \ ...@@ -161,6 +161,9 @@ do { \
#undef CTORS_SECTION_ASM_OP #undef CTORS_SECTION_ASM_OP
#undef DTORS_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" #define MD_UNWIND_SUPPORT "config/sparc/linux-unwind.h"
/* Linux currently uses RMO in uniprocessor mode, which is equivalent to /* Linux currently uses RMO in uniprocessor mode, which is equivalent to
......
...@@ -287,6 +287,9 @@ do { \ ...@@ -287,6 +287,9 @@ do { \
#undef CTORS_SECTION_ASM_OP #undef CTORS_SECTION_ASM_OP
#undef DTORS_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" #define MD_UNWIND_SUPPORT "config/sparc/linux-unwind.h"
/* Linux currently uses RMO in uniprocessor mode, which is equivalent to /* Linux currently uses RMO in uniprocessor mode, which is equivalent to
......
...@@ -188,4 +188,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -188,4 +188,7 @@ along with GCC; see the file COPYING3. If not see
#define PUSHSECTION_FORMAT "\t.pushsection\t\"%s\"\n" #define PUSHSECTION_FORMAT "\t.pushsection\t\"%s\"\n"
#endif #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" #define MD_UNWIND_SUPPORT "config/sparc/sol2-unwind.h"
...@@ -75,6 +75,7 @@ extern const char *output_return (rtx); ...@@ -75,6 +75,7 @@ extern const char *output_return (rtx);
extern const char *output_sibcall (rtx, rtx); extern const char *output_sibcall (rtx, rtx);
extern const char *output_v8plus_shift (rtx *, rtx, const char *); 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_v9branch (rtx, rtx, int, int, int, int, rtx);
extern const char *output_probe_stack_range (rtx, rtx);
extern bool emit_scc_insn (rtx []); extern bool emit_scc_insn (rtx []);
extern void emit_conditional_branch_insn (rtx []); extern void emit_conditional_branch_insn (rtx []);
extern void print_operand (FILE *, rtx, int); extern void print_operand (FILE *, rtx, int);
......
...@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
#include "insn-attr.h" #include "insn-attr.h"
#include "flags.h" #include "flags.h"
#include "function.h" #include "function.h"
#include "except.h"
#include "expr.h" #include "expr.h"
#include "optabs.h" #include "optabs.h"
#include "recog.h" #include "recog.h"
...@@ -4005,6 +4006,160 @@ sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED) ...@@ -4005,6 +4006,160 @@ sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
#endif #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 /* Save/restore call-saved registers from LOW to HIGH at BASE+OFFSET
as needed. LOW should be double-word aligned for 32-bit registers. as needed. LOW should be double-word aligned for 32-bit registers.
Return the new OFFSET. */ Return the new OFFSET. */
...@@ -4193,6 +4348,9 @@ sparc_expand_prologue (void) ...@@ -4193,6 +4348,9 @@ sparc_expand_prologue (void)
/* Advertise that the data calculated just above are now valid. */ /* Advertise that the data calculated just above are now valid. */
sparc_prologue_data_valid_p = true; 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) if (sparc_leaf_function_p)
{ {
frame_base_reg = stack_pointer_rtx; frame_base_reg = stack_pointer_rtx;
......
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
(UNSPECV_CAS 8) (UNSPECV_CAS 8)
(UNSPECV_SWAP 9) (UNSPECV_SWAP 9)
(UNSPECV_LDSTUB 10) (UNSPECV_LDSTUB 10)
(UNSPECV_PROBE_STACK_RANGE 11)
]) ])
...@@ -6340,6 +6341,15 @@ ...@@ -6340,6 +6341,15 @@
= adjust_address (operands[0], GET_MODE (operands[0]), SPARC_STACK_BIAS); = 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. ;; Prepare to return any type including a structure value.
(define_expand "untyped_return" (define_expand "untyped_return"
......
...@@ -43,7 +43,6 @@ along with GCC; see the file COPYING3. If not see ...@@ -43,7 +43,6 @@ along with GCC; see the file COPYING3. If not see
#include "output.h" #include "output.h"
static rtx break_out_memory_refs (rtx); static rtx break_out_memory_refs (rtx);
static void emit_stack_probe (rtx);
/* Truncate and perhaps sign-extend C as appropriate for MODE. */ /* Truncate and perhaps sign-extend C as appropriate for MODE. */
...@@ -1355,7 +1354,7 @@ set_stack_check_libfunc (const char *libfunc_name) ...@@ -1355,7 +1354,7 @@ set_stack_check_libfunc (const char *libfunc_name)
/* Emit one stack probe at ADDRESS, an address within the stack. */ /* Emit one stack probe at ADDRESS, an address within the stack. */
static void void
emit_stack_probe (rtx address) emit_stack_probe (rtx address)
{ {
rtx memref = gen_rtx_MEM (word_mode, address); rtx memref = gen_rtx_MEM (word_mode, address);
...@@ -1567,7 +1566,7 @@ anti_adjust_stack_and_probe (rtx size, bool adjust_back) ...@@ -1567,7 +1566,7 @@ anti_adjust_stack_and_probe (rtx size, bool adjust_back)
HOST_WIDE_INT isize = INTVAL (size), i; HOST_WIDE_INT isize = INTVAL (size), i;
bool first_probe = true; 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 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 needed, this will not generate any code. Then adjust and probe
to PROBE_INTERVAL + SIZE. */ to PROBE_INTERVAL + SIZE. */
...@@ -1623,13 +1622,13 @@ anti_adjust_stack_and_probe (rtx size, bool adjust_back) ...@@ -1623,13 +1622,13 @@ anti_adjust_stack_and_probe (rtx size, bool adjust_back)
/* Step 3: the loop /* Step 3: the loop
while (SP != LAST_ADDR) while (SP != LAST_ADDR)
{ {
SP = SP + PROBE_INTERVAL SP = SP + PROBE_INTERVAL
probe at SP 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. */ values of N from 1 until it is equal to ROUNDED_SIZE. */
emit_label (loop_lab); emit_label (loop_lab);
...@@ -1647,7 +1646,7 @@ anti_adjust_stack_and_probe (rtx size, bool adjust_back) ...@@ -1647,7 +1646,7 @@ anti_adjust_stack_and_probe (rtx size, bool adjust_back)
emit_label (end_lab); 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. */ assert at compile-time that SIZE is equal to ROUNDED_SIZE. */
/* TEMP = SIZE - ROUNDED_SIZE. */ /* TEMP = SIZE - ROUNDED_SIZE. */
......
...@@ -645,6 +645,9 @@ extern void update_nonlocal_goto_save_area (void); ...@@ -645,6 +645,9 @@ extern void update_nonlocal_goto_save_area (void);
says how many bytes. */ says how many bytes. */
extern rtx allocate_dynamic_stack_space (rtx, rtx, int); 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. /* 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 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 the current stack pointer. STACK_GROWS_DOWNWARD says whether to add
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment