Hello!

Attached patch prevents red-zone with -fPIC for leaf functions on
i686. The idea is to mark when set_got is expanded as a call to a pc
thunk, and use this flag to prevent red-zone in the current function.

Please note that using red-zone with i686 violates all known ABIs, but
some future ABI can trip on this limitation. The failure mode is quite
tricky, so IMO it warrants a couple of lines as a safety net.

The testcase is not suitable for the testsuite (it uses -mred-zone for
i686 target), but I have checked that the testcase works OK when
compiled with the patched compiler even when -mred-zone is used
together with -fPIC.

Jakub, HJ -  what do you think?

2016-03-01  Uros Bizjak  <ubiz...@gmail.com>

    PR target/70064
    * config/i386/i386.h (machine_function): Add
    pc_thunk_call_expanded flag.
    (ix86_pc_thunk_call_expanded): New define.
    * config/i386/i386.md (set_got, set_got_labelled): New expanders.
    (*set_got): Rename insn pattern from set_got.
    (*set_got_labelled): Rename inst pattern from set_got_labelled.
    * config/i386/i386.c (ix86_compute_frame_layout): Use
    ix86_pc_thunk_call_expanded to prevent red-zone.

The patch is bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.

Uros.
Index: i386.c
===================================================================
--- i386.c      (revision 234014)
+++ i386.c      (working copy)
@@ -11524,6 +11524,7 @@ ix86_compute_frame_layout (struct ix86_frame *fram
   if (ix86_using_red_zone ()
       && crtl->sp_is_unchanging
       && crtl->is_leaf
+      && !ix86_pc_thunk_call_expanded
       && !ix86_current_function_calls_tls_descriptor)
     {
       frame->red_zone_size = to_allocate;
Index: i386.h
===================================================================
--- i386.h      (revision 234014)
+++ i386.h      (working copy)
@@ -2494,6 +2494,10 @@ struct GTY(()) machine_function {
      expander to determine the style used.  */
   BOOL_BITFIELD use_fast_prologue_epilogue : 1;
 
+  /* Nonzero if the current function calls pc thunk and
+     must not use the red zone.  */
+  BOOL_BITFIELD pc_thunk_call_expanded : 1;
+
   /* If true, the current function needs the default PIC register, not
      an alternate register (on x86) and must not use the red zone (on
      x86_64), even if it's a leaf function.  We don't want the
@@ -2533,6 +2537,7 @@ struct GTY(()) machine_function {
 #define ix86_varargs_fpr_size (cfun->machine->varargs_fpr_size)
 #define ix86_optimize_mode_switching (cfun->machine->optimize_mode_switching)
 #define ix86_current_function_needs_cld (cfun->machine->needs_cld)
+#define ix86_pc_thunk_call_expanded (cfun->machine->pc_thunk_call_expanded)
 #define ix86_tls_descriptor_calls_expanded_in_cfun \
   (cfun->machine->tls_descriptor_call_expanded_p)
 /* Since tls_descriptor_call_expanded is not cleared, even if all TLS
Index: i386.md
===================================================================
--- i386.md     (revision 234014)
+++ i386.md     (working copy)
@@ -12470,7 +12470,18 @@
   ""
   "ix86_expand_prologue (); DONE;")
 
-(define_insn "set_got"
+(define_expand "set_got"
+  [(parallel
+     [(set (match_operand:SI 0 "register_operand" "=r")
+          (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
+      (clobber (reg:CC FLAGS_REG))])]
+  "!TARGET_64BIT"
+{
+  if (flag_pic && !TARGET_VXWORKS_RTP)
+    ix86_pc_thunk_call_expanded = true;
+})
+
+(define_insn "*set_got"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
    (clobber (reg:CC FLAGS_REG))]
@@ -12479,7 +12490,19 @@
   [(set_attr "type" "multi")
    (set_attr "length" "12")])
 
-(define_insn "set_got_labelled"
+(define_expand "set_got_labelled"
+  [(parallel
+     [(set (match_operand:SI 0 "register_operand" "=r")
+          (unspec:SI [(label_ref (match_operand 1))]
+                     UNSPEC_SET_GOT))
+      (clobber (reg:CC FLAGS_REG))])]
+  "!TARGET_64BIT"
+{
+  if (flag_pic && !TARGET_VXWORKS_RTP)
+    ix86_pc_thunk_call_expanded = true;
+})
+
+(define_insn "*set_got_labelled"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (unspec:SI [(label_ref (match_operand 1))]
         UNSPEC_SET_GOT))

Reply via email to