i386: Avoid stack realignment if possible
authorH.J. Lu <hongjiu.lu@intel.com>
Tue, 5 Sep 2017 16:39:24 +0000 (16:39 +0000)
committerH.J. Lu <hjl@gcc.gnu.org>
Tue, 5 Sep 2017 16:39:24 +0000 (09:39 -0700)
ix86_finalize_stack_frame_flags has been extended to eliminate frame
pointer when the new stack frame isn't needed with and without
-maccumulate-outgoing-args as well as -fomit-frame-pointer.  Since stack
access with larger alignment may be optimized out, to decide if stack
realignment is needed, we need to not only check for stack frame access,
but also verify the alignment of stack frame access.  Since alignment of
memory access via arg_pointer is set up by caller, not by callee, we
should find the maximum stack alignment from the stack frame access
instructions via stack pointer and frame pointrer to avoid stack
realignment when stack alignment needed is less than incoming stack
boundary.

gcc/

PR target/59501
PR target/81624
PR target/81769
* config/i386/i386.c (ix86_finalize_stack_frame_flags): Don't
realign stack if stack alignment needed is less than incoming
stack boundary.

gcc/testsuite/

PR target/59501
PR target/81624
PR target/81769
* gcc.target/i386/pr59501-4a.c: Remove xfail.
* gcc.target/i386/pr81769-1a.c: New test.
* gcc.target/i386/pr81769-1b.c: Likewise.
* gcc.target/i386/pr81769-2.c: Likewise.

From-SVN: r251718

gcc/ChangeLog
gcc/config/i386/i386.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr59501-4a.c
gcc/testsuite/gcc.target/i386/pr81769-1a.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr81769-1b.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr81769-2.c [new file with mode: 0644]

index 2f6983ffa9ecdfa6cb6d5609f297406eb295c786..fa34e13bc4e65bbd183f0622183e57a591071214 100644 (file)
@@ -1,3 +1,12 @@
+2017-09-05  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR target/59501
+       PR target/81624
+       PR target/81769
+       * config/i386/i386.c (ix86_finalize_stack_frame_flags): Don't
+       realign stack if stack alignment needed is less than incoming
+       stack boundary.
+
 2017-09-05  Marek Polacek  <polacek@redhat.com>
 
        PR sanitizer/82072
index 6fdc9fd54b1d6a9e77e1070887c0b2763acec1f5..74064510c631e79ba6caab31f7985edd84ff59bf 100644 (file)
@@ -14303,6 +14303,11 @@ ix86_finalize_stack_frame_flags (void)
       add_to_hard_reg_set (&set_up_by_prologue, Pmode, ARG_POINTER_REGNUM);
       add_to_hard_reg_set (&set_up_by_prologue, Pmode,
                           HARD_FRAME_POINTER_REGNUM);
+
+      /* The preferred stack alignment is the minimum stack alignment.  */
+      unsigned int stack_alignment = crtl->preferred_stack_boundary;
+      bool require_stack_frame = false;
+
       FOR_EACH_BB_FN (bb, cfun)
         {
           rtx_insn *insn;
@@ -14311,79 +14316,107 @@ ix86_finalize_stack_frame_flags (void)
                && requires_stack_frame_p (insn, prologue_used,
                                           set_up_by_prologue))
              {
-               if (crtl->stack_realign_needed != stack_realign)
-                 recompute_frame_layout_p = true;
-               crtl->stack_realign_needed = stack_realign;
-               crtl->stack_realign_finalized = true;
-               if (recompute_frame_layout_p)
-                 ix86_compute_frame_layout ();
-               return;
+               require_stack_frame = true;
+
+               if (stack_realign)
+                 {
+                   /* Find the maximum stack alignment.  */
+                   subrtx_iterator::array_type array;
+                   FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL)
+                     if (MEM_P (*iter)
+                         && (reg_mentioned_p (stack_pointer_rtx,
+                                              *iter)
+                             || reg_mentioned_p (frame_pointer_rtx,
+                                                 *iter)))
+                       {
+                         unsigned int alignment = MEM_ALIGN (*iter);
+                         if (alignment > stack_alignment)
+                           stack_alignment = alignment;
+                       }
+                 }
              }
        }
 
-      /* If drap has been set, but it actually isn't live at the start
-        of the function, there is no reason to set it up.  */
-      if (crtl->drap_reg)
+      if (require_stack_frame)
        {
-         basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
-         if (! REGNO_REG_SET_P (DF_LR_IN (bb), REGNO (crtl->drap_reg)))
+         /* Stack frame is required.  If stack alignment needed is less
+            than incoming stack boundary, don't realign stack.  */
+         stack_realign = incoming_stack_boundary < stack_alignment;
+         if (!stack_realign)
            {
-             crtl->drap_reg = NULL_RTX;
-             crtl->need_drap = false;
+             crtl->max_used_stack_slot_alignment
+               = incoming_stack_boundary;
+             crtl->stack_alignment_needed
+               = incoming_stack_boundary;
            }
        }
       else
-       cfun->machine->no_drap_save_restore = true;
-
-      frame_pointer_needed = false;
-      stack_realign = false;
-      crtl->max_used_stack_slot_alignment = incoming_stack_boundary;
-      crtl->stack_alignment_needed = incoming_stack_boundary;
-      crtl->stack_alignment_estimated = incoming_stack_boundary;
-      if (crtl->preferred_stack_boundary > incoming_stack_boundary)
-       crtl->preferred_stack_boundary = incoming_stack_boundary;
-      df_finish_pass (true);
-      df_scan_alloc (NULL);
-      df_scan_blocks ();
-      df_compute_regs_ever_live (true);
-      df_analyze ();
-
-      if (flag_var_tracking)
        {
-         /* Since frame pointer is no longer available, replace it with
-            stack pointer - UNITS_PER_WORD in debug insns.  */
-         df_ref ref, next;
-         for (ref = DF_REG_USE_CHAIN (HARD_FRAME_POINTER_REGNUM);
-              ref; ref = next)
+         /* If drap has been set, but it actually isn't live at the
+            start of the function, there is no reason to set it up.  */
+         if (crtl->drap_reg)
            {
-             rtx_insn *insn = DF_REF_INSN (ref);
-             /* Make sure the next ref is for a different instruction,
-                so that we're not affected by the rescan.  */
-             next = DF_REF_NEXT_REG (ref);
-             while (next && DF_REF_INSN (next) == insn)
-               next = DF_REF_NEXT_REG (next);
-
-             if (DEBUG_INSN_P (insn))
+             basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
+             if (! REGNO_REG_SET_P (DF_LR_IN (bb),
+                                    REGNO (crtl->drap_reg)))
+               {
+                 crtl->drap_reg = NULL_RTX;
+                 crtl->need_drap = false;
+               }
+           }
+         else
+           cfun->machine->no_drap_save_restore = true;
+
+         frame_pointer_needed = false;
+         stack_realign = false;
+         crtl->max_used_stack_slot_alignment = incoming_stack_boundary;
+         crtl->stack_alignment_needed = incoming_stack_boundary;
+         crtl->stack_alignment_estimated = incoming_stack_boundary;
+         if (crtl->preferred_stack_boundary > incoming_stack_boundary)
+           crtl->preferred_stack_boundary = incoming_stack_boundary;
+         df_finish_pass (true);
+         df_scan_alloc (NULL);
+         df_scan_blocks ();
+         df_compute_regs_ever_live (true);
+         df_analyze ();
+
+         if (flag_var_tracking)
+           {
+             /* Since frame pointer is no longer available, replace it with
+                stack pointer - UNITS_PER_WORD in debug insns.  */
+             df_ref ref, next;
+             for (ref = DF_REG_USE_CHAIN (HARD_FRAME_POINTER_REGNUM);
+                  ref; ref = next)
                {
-                 bool changed = false;
-                 for (; ref != next; ref = DF_REF_NEXT_REG (ref))
+                 rtx_insn *insn = DF_REF_INSN (ref);
+                 /* Make sure the next ref is for a different instruction,
+                    so that we're not affected by the rescan.  */
+                 next = DF_REF_NEXT_REG (ref);
+                 while (next && DF_REF_INSN (next) == insn)
+                   next = DF_REF_NEXT_REG (next);
+
+                 if (DEBUG_INSN_P (insn))
                    {
-                     rtx *loc = DF_REF_LOC (ref);
-                     if (*loc == hard_frame_pointer_rtx)
+                     bool changed = false;
+                     for (; ref != next; ref = DF_REF_NEXT_REG (ref))
                        {
-                         *loc = plus_constant (Pmode,
-                                               stack_pointer_rtx,
-                                               -UNITS_PER_WORD);
-                         changed = true;
+                         rtx *loc = DF_REF_LOC (ref);
+                         if (*loc == hard_frame_pointer_rtx)
+                           {
+                             *loc = plus_constant (Pmode,
+                                                   stack_pointer_rtx,
+                                                   -UNITS_PER_WORD);
+                             changed = true;
+                           }
                        }
+                     if (changed)
+                       df_insn_rescan (insn);
                    }
-                 if (changed)
-                   df_insn_rescan (insn);
                }
            }
-       }
 
-      recompute_frame_layout_p = true;
+         recompute_frame_layout_p = true;
+       }
     }
 
   if (crtl->stack_realign_needed != stack_realign)
index 623e41417f9f8043af4296e63072cefd9e613c8d..a34c6923a0e1b5a7b471017e2cb14d047967c803 100644 (file)
@@ -1,3 +1,13 @@
+2017-09-05  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR target/59501
+       PR target/81624
+       PR target/81769
+       * gcc.target/i386/pr59501-4a.c: Remove xfail.
+       * gcc.target/i386/pr81769-1a.c: New test.
+       * gcc.target/i386/pr81769-1b.c: Likewise.
+       * gcc.target/i386/pr81769-2.c: Likewise.
+
 2017-09-05  Marek Polacek  <polacek@redhat.com>
 
        PR sanitizer/82072
index 5c3cb683a2ebd7133077edbf21a00d1882627e12..908c7f457b6deef3dab0ed23bee7a15fcf84edc0 100644 (file)
@@ -5,4 +5,4 @@
 #include "pr59501-3a.c"
 
 /* Verify no dynamic realignment is performed.  */
-/* { dg-final { scan-assembler-not "and\[^\n\r]*sp" { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not "and\[^\n\r]*sp" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr81769-1a.c b/gcc/testsuite/gcc.target/i386/pr81769-1a.c
new file mode 100644 (file)
index 0000000..8ebe729
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O -mavx" } */
+
+typedef int v8si __attribute__ ((vector_size (32)));
+typedef unsigned long long int u64 __attribute__ ((aligned(64)));
+
+
+void
+#ifndef __x86_64__
+__attribute__((regparm(3)))
+#endif
+foo (u64 *idx, v8si *out_start, v8si *regions)
+{
+  if (*idx < 20 ) {
+    v8si base = regions[*idx];
+    *out_start = base;
+  }
+}
+
+/* Verify no dynamic realignment is performed.  */
+/* { dg-final { scan-assembler-not "and\[^\n\r]*sp" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr81769-1b.c b/gcc/testsuite/gcc.target/i386/pr81769-1b.c
new file mode 100644 (file)
index 0000000..6505a5f
--- /dev/null
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-O -mavx -fno-omit-frame-pointer" } */
+
+#include "pr81769-1a.c"
+
+/* Verify no dynamic realignment is performed.  */
+/* { dg-final { scan-assembler-not "and\[^\n\r]*sp" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr81769-2.c b/gcc/testsuite/gcc.target/i386/pr81769-2.c
new file mode 100644 (file)
index 0000000..e020db2
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O -mavx -fno-omit-frame-pointer" } */
+
+typedef unsigned long long int u64 __attribute__ ((aligned(64)));
+
+void
+#ifndef __x86_64__
+__attribute__((regparm(3)))
+#endif
+foo (u64 *idx, unsigned int *out_start, unsigned int *out_end,
+     unsigned int *regions)
+{
+  if (*idx < 20 ) {
+    unsigned int base = regions[*idx];
+    *out_start = base;
+    *out_end = base;
+  }
+}
+
+/* Verify no dynamic realignment is performed.  */
+/* { dg-final { scan-assembler-not "and\[^\n\r]*sp" } } */