You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
6.4 KiB
182 lines
6.4 KiB
commit 14041afe24556efd5845564aa183b6451fd9d6cc |
|
Author: law <law@138bc75d-0d04-0410-961f-82ee72b054a4> |
|
Date: Thu Feb 1 16:22:56 2018 +0000 |
|
|
|
PR target/84128 |
|
* config/i386/i386.c (release_scratch_register_on_entry): Add new |
|
OFFSET and RELEASE_VIA_POP arguments. Use SP+OFFSET to restore |
|
the scratch if RELEASE_VIA_POP is false. |
|
(ix86_adjust_stack_and_probe_stack_clash): Un-constify SIZE. |
|
If we have to save a temporary register, decrement SIZE appropriately. |
|
Pass new arguments to release_scratch_register_on_entry. |
|
(ix86_adjust_stack_and_probe): Likewise. |
|
(ix86_emit_probe_stack_range): Pass new arguments to |
|
release_scratch_register_on_entry. |
|
|
|
PR target/84128 |
|
* gcc.target/i386/pr84128.c: New test. |
|
|
|
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c |
|
index 2fe2a0c..c25d26c 100644 |
|
--- a/gcc/config/i386/i386.c |
|
+++ b/gcc/config/i386/i386.c |
|
@@ -10182,22 +10182,39 @@ get_scratch_register_on_entry (struct scratch_reg *sr) |
|
} |
|
} |
|
|
|
-/* Release a scratch register obtained from the preceding function. */ |
|
+/* Release a scratch register obtained from the preceding function. |
|
+ |
|
+ If RELEASE_VIA_POP is true, we just pop the register off the stack |
|
+ to release it. This is what non-Linux systems use with -fstack-check. |
|
+ |
|
+ Otherwise we use OFFSET to locate the saved register and the |
|
+ allocated stack space becomes part of the local frame and is |
|
+ deallcated by the epilogue. */ |
|
|
|
static void |
|
-release_scratch_register_on_entry (struct scratch_reg *sr) |
|
+release_scratch_register_on_entry (struct scratch_reg *sr, HOST_WIDE_INT offset, |
|
+ bool release_via_pop) |
|
{ |
|
if (sr->saved) |
|
{ |
|
- struct machine_function *m = cfun->machine; |
|
- rtx x, insn = emit_insn (gen_pop (sr->reg)); |
|
+ if (release_via_pop) |
|
+ { |
|
+ struct machine_function *m = cfun->machine; |
|
+ rtx x, insn = emit_insn (gen_pop (sr->reg)); |
|
|
|
- /* The RTX_FRAME_RELATED_P mechanism doesn't know about pop. */ |
|
- RTX_FRAME_RELATED_P (insn) = 1; |
|
- x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (UNITS_PER_WORD)); |
|
- x = gen_rtx_SET (VOIDmode, stack_pointer_rtx, x); |
|
- add_reg_note (insn, REG_FRAME_RELATED_EXPR, x); |
|
- m->fs.sp_offset -= UNITS_PER_WORD; |
|
+ /* The RTX FRAME_RELATED_P mechanism doesn't know about pop. */ |
|
+ RTX_FRAME_RELATED_P (insn) = 1; |
|
+ x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (UNITS_PER_WORD)); |
|
+ x = gen_rtx_SET (VOIDmode, stack_pointer_rtx, x); |
|
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR, x); |
|
+ m->fs.sp_offset -= UNITS_PER_WORD; |
|
+ } |
|
+ else |
|
+ { |
|
+ rtx x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset)); |
|
+ x = gen_rtx_SET (VOIDmode, sr->reg, gen_rtx_MEM (word_mode, x)); |
|
+ emit_insn (x); |
|
+ } |
|
} |
|
} |
|
|
|
@@ -10212,7 +10229,7 @@ release_scratch_register_on_entry (struct scratch_reg *sr) |
|
pushed on the stack. */ |
|
|
|
static void |
|
-ix86_adjust_stack_and_probe_stack_clash (const HOST_WIDE_INT size, |
|
+ix86_adjust_stack_and_probe_stack_clash (HOST_WIDE_INT size, |
|
const bool int_registers_saved) |
|
{ |
|
struct machine_function *m = cfun->machine; |
|
@@ -10331,6 +10348,12 @@ ix86_adjust_stack_and_probe_stack_clash (const HOST_WIDE_INT size, |
|
struct scratch_reg sr; |
|
get_scratch_register_on_entry (&sr); |
|
|
|
+ /* If we needed to save a register, then account for any space |
|
+ that was pushed (we are not going to pop the register when |
|
+ we do the restore). */ |
|
+ if (sr.saved) |
|
+ size -= UNITS_PER_WORD; |
|
+ |
|
/* Step 1: round SIZE down to a multiple of the interval. */ |
|
HOST_WIDE_INT rounded_size = size & -probe_interval; |
|
|
|
@@ -10379,7 +10402,9 @@ ix86_adjust_stack_and_probe_stack_clash (const HOST_WIDE_INT size, |
|
m->fs.cfa_reg == stack_pointer_rtx); |
|
dump_stack_clash_frame_info (PROBE_LOOP, size != rounded_size); |
|
|
|
- release_scratch_register_on_entry (&sr); |
|
+ /* This does not deallocate the space reserved for the scratch |
|
+ register. That will be deallocated in the epilogue. */ |
|
+ release_scratch_register_on_entry (&sr, size, false); |
|
} |
|
|
|
/* Make sure nothing is scheduled before we are done. */ |
|
@@ -10392,7 +10417,7 @@ ix86_adjust_stack_and_probe_stack_clash (const HOST_WIDE_INT size, |
|
pushed on the stack. */ |
|
|
|
static void |
|
-ix86_adjust_stack_and_probe (const HOST_WIDE_INT size, |
|
+ix86_adjust_stack_and_probe (HOST_WIDE_INT size, |
|
const bool int_registers_saved) |
|
{ |
|
/* We skip the probe for the first interval + a small dope of 4 words and |
|
@@ -10465,6 +10490,11 @@ ix86_adjust_stack_and_probe (const HOST_WIDE_INT size, |
|
|
|
get_scratch_register_on_entry (&sr); |
|
|
|
+ /* If we needed to save a register, then account for any space |
|
+ that was pushed (we are not going to pop the register when |
|
+ we do the restore). */ |
|
+ if (sr.saved) |
|
+ size -= UNITS_PER_WORD; |
|
|
|
/* Step 1: round SIZE to the previous multiple of the interval. */ |
|
|
|
@@ -10516,7 +10546,9 @@ ix86_adjust_stack_and_probe (const HOST_WIDE_INT size, |
|
(get_probe_interval () |
|
+ dope)))); |
|
|
|
- release_scratch_register_on_entry (&sr); |
|
+ /* This does not deallocate the space reserved for the scratch |
|
+ register. That will be deallocated in the epilogue. */ |
|
+ release_scratch_register_on_entry (&sr, size, false); |
|
} |
|
|
|
gcc_assert (cfun->machine->fs.cfa_reg != stack_pointer_rtx); |
|
@@ -10669,7 +10701,7 @@ ix86_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size, |
|
sr.reg), |
|
rounded_size - size)); |
|
|
|
- release_scratch_register_on_entry (&sr); |
|
+ release_scratch_register_on_entry (&sr, size, true); |
|
} |
|
|
|
/* Make sure nothing is scheduled before we are done. */ |
|
diff --git a/gcc/testsuite/gcc.target/i386/pr84128.c b/gcc/testsuite/gcc.target/i386/pr84128.c |
|
new file mode 100644 |
|
index 0000000..a8323fd |
|
--- /dev/null |
|
+++ b/gcc/testsuite/gcc.target/i386/pr84128.c |
|
@@ -0,0 +1,30 @@ |
|
+/* { dg-do run } */ |
|
+/* { dg-options "-O2 -march=i686 -mtune=generic -fstack-clash-protection" } */ |
|
+/* { dg-require-effective-target ia32 } */ |
|
+ |
|
+__attribute__ ((noinline, noclone, weak, regparm (3))) |
|
+int |
|
+f1 (long arg0, int (*pf) (long, void *)) |
|
+{ |
|
+ unsigned char buf[32768]; |
|
+ return pf (arg0, buf); |
|
+} |
|
+ |
|
+__attribute__ ((noinline, noclone, weak)) |
|
+int |
|
+f2 (long arg0, void *ignored) |
|
+{ |
|
+ if (arg0 != 17) |
|
+ __builtin_abort (); |
|
+ return 19; |
|
+} |
|
+ |
|
+int |
|
+main (void) |
|
+{ |
|
+ if (f1 (17, f2) != 19) |
|
+ __builtin_abort (); |
|
+ return 0; |
|
+} |
|
+ |
|
+
|
|
|