runtime: mark go-context.S as no-executable-stack and split-stack supported
[gcc.git] / gcc / combine-stack-adj.c
index aebdf87d80752e927e457da1a88eac3afa09cf77..d14d59abced05b34309f3241f18ab0190a335ca4 100644 (file)
@@ -1,5 +1,5 @@
 /* Combine stack adjustments.
-   Copyright (C) 1987-2014 Free Software Foundation, Inc.
+   Copyright (C) 1987-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -41,32 +41,18 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
 #include "rtl.h"
-#include "tm_p.h"
+#include "df.h"
 #include "insn-config.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
 #include "recog.h"
-#include "regs.h"
-#include "hard-reg-set.h"
-#include "flags.h"
-#include "function.h"
-#include "expr.h"
-#include "basic-block.h"
-#include "df.h"
-#include "except.h"
-#include "reload.h"
+#include "cfgrtl.h"
 #include "tree-pass.h"
 #include "rtl-iter.h"
 
 \f
-/* Turn STACK_GROWS_DOWNWARD into a boolean.  */
-#ifdef STACK_GROWS_DOWNWARD
-#undef STACK_GROWS_DOWNWARD
-#define STACK_GROWS_DOWNWARD 1
-#else
-#define STACK_GROWS_DOWNWARD 0
-#endif
-
 /* This structure records two kinds of stack references between stack
    adjusting instructions: stack references in memory addresses for
    regular insns and all stack references for debug insns.  */
@@ -190,6 +176,45 @@ record_one_stack_ref (rtx_insn *insn, rtx *ref, struct csa_reflist *next_reflist
   return ml;
 }
 
+/* We only know how to adjust the CFA; no other frame-related changes
+   may appear in any insn to be deleted.  */
+
+static bool
+no_unhandled_cfa (rtx_insn *insn)
+{
+  if (!RTX_FRAME_RELATED_P (insn))
+    return true;
+
+  /* No CFA notes at all is a legacy interpretation like
+     FRAME_RELATED_EXPR, and is context sensitive within
+     the prologue state machine.  We can't handle that here.  */
+  bool has_cfa_adjust = false;
+
+  for (rtx link = REG_NOTES (insn); link; link = XEXP (link, 1))
+    switch (REG_NOTE_KIND (link))
+      {
+      default:
+        break;
+      case REG_CFA_ADJUST_CFA:
+       has_cfa_adjust = true;
+       break;
+
+      case REG_FRAME_RELATED_EXPR:
+      case REG_CFA_DEF_CFA:
+      case REG_CFA_OFFSET:
+      case REG_CFA_REGISTER:
+      case REG_CFA_EXPRESSION:
+      case REG_CFA_RESTORE:
+      case REG_CFA_SET_VDRAP:
+      case REG_CFA_WINDOW_SAVE:
+      case REG_CFA_FLUSH_QUEUE:
+      case REG_CFA_TOGGLE_RA_MANGLE:
+       return false;
+      }
+
+  return has_cfa_adjust;
+}
+
 /* Attempt to apply ADJUST to the stack adjusting insn INSN, as well
    as each of the memories and stack references in REFLIST.  Return true
    on success.  */
@@ -320,6 +345,44 @@ maybe_move_args_size_note (rtx_insn *last, rtx_insn *insn, bool after)
     add_reg_note (last, REG_ARGS_SIZE, XEXP (note, 0));
 }
 
+/* Merge any REG_CFA_ADJUST_CFA note from SRC into DST.
+   AFTER is true iff DST follows SRC in the instruction stream.  */
+
+static void
+maybe_merge_cfa_adjust (rtx_insn *dst, rtx_insn *src, bool after)
+{
+  rtx snote = NULL, dnote = NULL;
+  rtx sexp, dexp;
+  rtx exp1, exp2;
+
+  if (RTX_FRAME_RELATED_P (src))
+    snote = find_reg_note (src, REG_CFA_ADJUST_CFA, NULL_RTX);
+  if (snote == NULL)
+    return;
+  sexp = XEXP (snote, 0);
+
+  if (RTX_FRAME_RELATED_P (dst))
+    dnote = find_reg_note (dst, REG_CFA_ADJUST_CFA, NULL_RTX);
+  if (dnote == NULL)
+    {
+      add_reg_note (dst, REG_CFA_ADJUST_CFA, sexp);
+      return;
+    }
+  dexp = XEXP (dnote, 0);
+
+  gcc_assert (GET_CODE (sexp) == SET);
+  gcc_assert (GET_CODE (dexp) == SET);
+
+  if (after)
+    exp1 = dexp, exp2 = sexp;
+  else
+    exp1 = sexp, exp2 = dexp;
+
+  SET_SRC (exp1) = simplify_replace_rtx (SET_SRC (exp1), SET_DEST (exp2),
+                                        SET_SRC (exp2));
+  XEXP (dnote, 0) = exp1;
+}
+
 /* Return the next (or previous) active insn within BB.  */
 
 static rtx_insn *
@@ -445,6 +508,8 @@ combine_stack_adjustments_for_block (basic_block bb)
        continue;
 
       set = single_set_for_csa (insn);
+      if (set && find_reg_note (insn, REG_STACK_CHECK, NULL_RTX))
+       set = NULL_RTX;
       if (set)
        {
          rtx dest = SET_DEST (set);
@@ -474,7 +539,7 @@ combine_stack_adjustments_for_block (basic_block bb)
                 Also we need to be careful to not move stack pointer
                 such that we create stack accesses outside the allocated
                 area.  We can combine an allocation into the first insn,
-                or a deallocation into the second insn.  We can not
+                or a deallocation into the second insn.  We cannot
                 combine an allocation followed by a deallocation.
 
                 The only somewhat frequent occurrence of the later is when
@@ -491,12 +556,15 @@ combine_stack_adjustments_for_block (basic_block bb)
              /* Combine an allocation into the first instruction.  */
              if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
                {
-                 if (try_apply_stack_adjustment (last_sp_set, reflist,
-                                                 last_sp_adjust + this_adjust,
-                                                 this_adjust))
+                 if (no_unhandled_cfa (insn)
+                     && try_apply_stack_adjustment (last_sp_set, reflist,
+                                                    last_sp_adjust
+                                                    + this_adjust,
+                                                    this_adjust))
                    {
                      /* It worked!  */
                      maybe_move_args_size_note (last_sp_set, insn, false);
+                     maybe_merge_cfa_adjust (last_sp_set, insn, false);
                      delete_insn (insn);
                      last_sp_adjust += this_adjust;
                      continue;
@@ -508,12 +576,15 @@ combine_stack_adjustments_for_block (basic_block bb)
              else if (STACK_GROWS_DOWNWARD
                       ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
                {
-                 if (try_apply_stack_adjustment (insn, reflist,
-                                                 last_sp_adjust + this_adjust,
-                                                 -last_sp_adjust))
+                 if (no_unhandled_cfa (last_sp_set)
+                     && try_apply_stack_adjustment (insn, reflist,
+                                                    last_sp_adjust
+                                                    + this_adjust,
+                                                    -last_sp_adjust))
                    {
                      /* It worked!  */
                      maybe_move_args_size_note (insn, last_sp_set, true);
+                     maybe_merge_cfa_adjust (insn, last_sp_set, true);
                      delete_insn (last_sp_set);
                      last_sp_set = insn;
                      last_sp_adjust += this_adjust;
@@ -528,9 +599,10 @@ combine_stack_adjustments_for_block (basic_block bb)
                 delete the old deallocation insn.  */
              if (last_sp_set)
                {
-                 if (last_sp_adjust == 0)
+                 if (last_sp_adjust == 0 && no_unhandled_cfa (last_sp_set))
                    {
                      maybe_move_args_size_note (insn, last_sp_set, true);
+                     maybe_merge_cfa_adjust (insn, last_sp_set, true);
                      delete_insn (last_sp_set);
                    }
                  else
@@ -550,11 +622,11 @@ combine_stack_adjustments_for_block (basic_block bb)
          if (MEM_P (dest)
              && ((STACK_GROWS_DOWNWARD
                   ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC
-                     && last_sp_adjust
-                        == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest)))
+                     && known_eq (last_sp_adjust,
+                                  GET_MODE_SIZE (GET_MODE (dest))))
                   : (GET_CODE (XEXP (dest, 0)) == PRE_INC
-                     && last_sp_adjust
-                        == -(HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest))))
+                     && known_eq (-last_sp_adjust,
+                                  GET_MODE_SIZE (GET_MODE (dest)))))
                  || ((STACK_GROWS_DOWNWARD
                       ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
                      && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY