From patchwork Sun Oct 21 20:26:02 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: XFAIL a couple of gnat.dg testcases on MIPS From: Eric Botcazou X-Patchwork-Id: 193057 Message-Id: <35552984.Dl31KDtAYV@polaris> To: gcc-patches@gcc.gnu.org Date: Sun, 21 Oct 2012 22:26:02 +0200 They are reported as failing with the n32 ABI, but the failures are spurious. Tested on mips64el-linux-gnu, applied on the mainline and 4.7 branch. 2012-10-21 Eric Botcazou * gnat.dg/specs/atomic1.ads: XFAIL on MIPS. * gnat.dg/specs/addr1.ads: Likewise. diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index e4fbb32..1dab31b 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -310,6 +310,7 @@ extern const char *mips_output_sync (void); extern const char *mips_output_sync_loop (rtx, rtx *); extern unsigned int mips_sync_loop_insns (rtx, rtx *); extern const char *mips_output_division (const char *, rtx *); +extern const char *mips_output_probe_stack_range (rtx, rtx); extern unsigned int mips_hard_regno_nregs (int, enum machine_mode); extern bool mips_linked_madd_p (rtx, rtx); extern bool mips_store_data_bypass_p (rtx, rtx); diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index c23d00e..9d1e0a4 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "output.h" #include "tree.h" #include "function.h" +#include "except.h" #include "expr.h" #include "optabs.h" #include "libfuncs.h" @@ -10005,6 +10006,134 @@ mips_emit_loadgp (void) emit_insn (gen_loadgp_blockage ()); } +#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 +mips_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 r3 = gen_rtx_REG (Pmode, 3); + rtx r12 = gen_rtx_REG (Pmode, 12); + + /* 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, r3, + plus_constant (stack_pointer_rtx, -first))); + + /* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */ + if (rounded_size > 32768) + { + emit_move_insn (r12, GEN_INT (rounded_size)); + emit_insn (gen_rtx_SET (VOIDmode, r12, + gen_rtx_MINUS (Pmode, r3, r12))); + } + else + emit_insn (gen_rtx_SET (VOIDmode, r12, + plus_constant (r3, -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. */ + + gcc_assert (Pmode == SImode); + emit_insn (gen_probe_stack_rangesi (r3, r3, r12)); + + + /* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time + that SIZE is equal to ROUNDED_SIZE. */ + + /* TEMP = SIZE - ROUNDED_SIZE. */ + if (size != rounded_size) + emit_stack_probe (plus_constant (r12, 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 * +mips_output_probe_stack_range (rtx reg1, rtx reg2) +{ + static int labelno = 0; + char loop_lab[32], end_lab[32], tmp[64]; + 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; + strcpy (tmp, "beq\t%0,%1,"); + output_asm_insn (strcat (tmp, &end_lab[1]), xops); + + /* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */ + xops[1] = GEN_INT (-PROBE_INTERVAL); + output_asm_insn (" addiu\t%0,%0,%1", xops); + + /* Probe at TEST_ADDR and branch. */ + fprintf (asm_out_file, "\tb\t"); + assemble_name_raw (asm_out_file, loop_lab); + fputc ('\n', asm_out_file); + output_asm_insn (" sd\t$0,0(%0)", xops); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, end_lab); + + return ""; +} + /* A for_each_rtx callback. Stop the search if *X is a kernel register. */ static int @@ -10044,6 +10173,9 @@ mips_expand_prologue (void) if (flag_stack_usage_info) current_function_static_stack_size = size; + if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && size) + mips_emit_probe_stack_range (STACK_CHECK_PROTECT, size); + /* Save the registers. Allocate up to MIPS_MAX_FIRST_STACK_STEP bytes beforehand; this is enough to cover the register save area without going out of range. */ diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index a854327..206a5db 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -78,7 +78,8 @@ ;; Used in a call expression in place of args_size. It's present for PIC ;; indirect calls where it contains args_size and the function symbol. (UNSPEC_CALL_ATTR 55) - + (UNSPEC_PROBE_STACK_RANGE 56) + (UNSPEC_ADDRESS_FIRST 100) (TLS_GET_TP_REGNUM 3) @@ -5773,6 +5774,14 @@ DONE; }) +(define_insn "probe_stack_rangesi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "register_operand" "r")] + UNSPEC_PROBE_STACK_RANGE))] + "" + "* return mips_output_probe_stack_range (operands[0], operands[2]);") + ;; Block any insns from being moved before this point, since the ;; profiling call to mcount can use various registers that aren't ;; saved or used to pass arguments.