This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA][PATCH] Improve initial probe for noreturn functions for x86 target



The x86 port relies on implicit probes that occur when a call instruction pushes the return address onto the stack. Those implicit calls allow the target to avoid emitting explicit stack probes.

Of course we have to account for tail call optimizations which turn the call into a jump -- in particular a tail call to a noreturn function (I won't go into the details, but other tail calls are safe).

To handle this we emit an explicit probe at the start of any function which is marked as noreturn. That probe hits the red zone, which is of course ok if we're using the red zone, but causes valgrind headaches if we are not using the red zone.

This patch changes that probe so that instead of

orl $0,-4(sp)

we instead generate

push eax
pop eax

[ With the obvious adjustments in 64 bit mode. ]

The push/pop sequence is one more instruction, but may actually be faster than the internal RMW aspects of the orl style. The push/pop sequence is valgrind safe and is actually shorter than the orl probe by a few bytes.


Bootstrapped and regression tested on x86.

OK for the trunk?

Jeff
            * config/i386/i386.c (ix86_emit_restore_reg_using_pop): Prototype.
            (ix86_adjust_stack_and_probe_stack_clash): Use a push/pop sequence
            to probe at the start of a noreturn function.
    
            * gcc.target/i386/stack-check-12.c: New test

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index ea29ef3..fc43962 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -101,6 +101,8 @@ static void ix86_print_operand_address_as (FILE *, rtx, addr_space_t, bool);
 static bool ix86_save_reg (unsigned int, bool, bool);
 static bool ix86_function_naked (const_tree);
 static bool ix86_notrack_prefixed_insn_p (rtx);
+static void ix86_emit_restore_reg_using_pop (rtx);
+
 
 #ifndef CHECK_STACK_LIMIT
 #define CHECK_STACK_LIMIT (-1)
@@ -12124,8 +12126,9 @@ ix86_adjust_stack_and_probe_stack_clash (const HOST_WIDE_INT size)
      we just probe when we cross PROBE_INTERVAL.  */
   if (TREE_THIS_VOLATILE (cfun->decl))
     {
-      emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
-				       -GET_MODE_SIZE (word_mode)));
+      rtx_insn *insn = emit_insn (gen_push (gen_rtx_REG (word_mode, 0)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      ix86_emit_restore_reg_using_pop (gen_rtx_REG (word_mode, 0));
       emit_insn (gen_blockage ());
     }
 
diff --git a/gcc/testsuite/gcc.target/i386/stack-check-12.c b/gcc/testsuite/gcc.target/i386/stack-check-12.c
new file mode 100644
index 0000000..720951c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/stack-check-12.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-clash-protection -mtune=generic" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+__attribute__ ((noreturn)) void exit (int);
+
+__attribute__ ((noreturn)) void
+f (void)
+{
+  asm volatile ("nop" ::: "edi");
+  exit (1);
+}
+
+/* { dg-final { scan-assembler-not "or\[ql\]" } } */
+/* { dg-final { scan-assembler "push\[ql\]	%\[er\]ax" } } */
+/* { dg-final { scan-assembler "pop\[ql]	%\[er\]ax" } } */
+

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]