coarray_data_1.f90: Link against libatomic if target libatomic_available.
[gcc.git] / gcc / combine-stack-adj.c
index 25039b98c6b30e668ae8d44ca1bfa1c1ee3770aa..3638a1b10ee4c81d2cba803355bbb588eb37405f 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,31 +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.  */
@@ -86,7 +73,6 @@ static struct csa_reflist *record_one_stack_ref (rtx_insn *, rtx *,
 static int try_apply_stack_adjustment (rtx_insn *, struct csa_reflist *,
                                       HOST_WIDE_INT, HOST_WIDE_INT);
 static void combine_stack_adjustments_for_block (basic_block);
-static int record_stack_refs (rtx *, void *);
 
 
 /* Main entry point for stack adjustment combination.  */
@@ -147,6 +133,7 @@ single_set_for_csa (rtx_insn *insn)
          && SET_SRC (this_rtx) == SET_DEST (this_rtx))
        ;
       else if (GET_CODE (this_rtx) != CLOBBER
+              && GET_CODE (this_rtx) != CLOBBER_HIGH
               && GET_CODE (this_rtx) != USE)
        return NULL_RTX;
     }
@@ -190,6 +177,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.  */
@@ -237,61 +263,63 @@ try_apply_stack_adjustment (rtx_insn *insn, struct csa_reflist *reflist,
     return 0;
 }
 
-/* Called via for_each_rtx and used to record all stack memory and other
-   references in the insn and discard all other stack pointer references.  */
-struct record_stack_refs_data
-{
-  rtx_insn *insn;
-  struct csa_reflist *reflist;
-};
+/* For non-debug insns, record all stack memory references in INSN
+   and return true if there were no other (unrecorded) references to the
+   stack pointer.  For debug insns, record all stack references regardless
+   of context and unconditionally return true.  */
 
-static int
-record_stack_refs (rtx *xp, void *data)
+static bool
+record_stack_refs (rtx_insn *insn, struct csa_reflist **reflist)
 {
-  rtx x = *xp;
-  struct record_stack_refs_data *d =
-    (struct record_stack_refs_data *) data;
-  if (!x)
-    return 0;
-  switch (GET_CODE (x))
+  subrtx_ptr_iterator::array_type array;
+  FOR_EACH_SUBRTX_PTR (iter, array, &PATTERN (insn), NONCONST)
     {
-    case MEM:
-      if (!reg_mentioned_p (stack_pointer_rtx, x))
-       return -1;
-      /* We are not able to handle correctly all possible memrefs containing
-         stack pointer, so this check is necessary.  */
-      if (stack_memref_p (x))
-       {
-         d->reflist = record_one_stack_ref (d->insn, xp, d->reflist);
-         return -1;
-       }
-      /* Try harder for DEBUG_INSNs, handle e.g. (mem (mem (sp + 16) + 4).  */
-      return !DEBUG_INSN_P (d->insn);
-    case REG:
-      /* ??? We want be able to handle non-memory stack pointer
-        references later.  For now just discard all insns referring to
-        stack pointer outside mem expressions.  We would probably
-        want to teach validate_replace to simplify expressions first.
-
-        We can't just compare with STACK_POINTER_RTX because the
-        reference to the stack pointer might be in some other mode.
-        In particular, an explicit clobber in an asm statement will
-        result in a QImode clobber.
-
-        In DEBUG_INSNs, we want to replace all occurrences, otherwise
-        they will cause -fcompare-debug failures.  */
-      if (REGNO (x) == STACK_POINTER_REGNUM)
+      rtx *loc = *iter;
+      rtx x = *loc;
+      switch (GET_CODE (x))
        {
-         if (!DEBUG_INSN_P (d->insn))
-           return 1;
-         d->reflist = record_one_stack_ref (d->insn, xp, d->reflist);
-         return -1;
+       case MEM:
+         if (!reg_mentioned_p (stack_pointer_rtx, x))
+           iter.skip_subrtxes ();
+         /* We are not able to handle correctly all possible memrefs
+            containing stack pointer, so this check is necessary.  */
+         else if (stack_memref_p (x))
+           {
+             *reflist = record_one_stack_ref (insn, loc, *reflist);
+             iter.skip_subrtxes ();
+           }
+         /* Try harder for DEBUG_INSNs, handle e.g.
+            (mem (mem (sp + 16) + 4).  */
+         else if (!DEBUG_INSN_P (insn))
+           return false;
+         break;
+
+       case REG:
+         /* ??? We want be able to handle non-memory stack pointer
+            references later.  For now just discard all insns referring to
+            stack pointer outside mem expressions.  We would probably
+            want to teach validate_replace to simplify expressions first.
+
+            We can't just compare with STACK_POINTER_RTX because the
+            reference to the stack pointer might be in some other mode.
+            In particular, an explicit clobber in an asm statement will
+            result in a QImode clobber.
+
+            In DEBUG_INSNs, we want to replace all occurrences, otherwise
+            they will cause -fcompare-debug failures.  */
+         if (REGNO (x) == STACK_POINTER_REGNUM)
+           {
+             if (!DEBUG_INSN_P (insn))
+               return false;
+             *reflist = record_one_stack_ref (insn, loc, *reflist);
+           }
+         break;
+
+       default:
+         break;
        }
-      break;
-    default:
-      break;
     }
-  return 0;
+  return true;
 }
 
 /* If INSN has a REG_ARGS_SIZE note, move it to LAST.
@@ -318,6 +346,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 *
@@ -432,7 +498,6 @@ combine_stack_adjustments_for_block (basic_block bb)
   struct csa_reflist *reflist = NULL;
   rtx_insn *insn, *next;
   rtx set;
-  struct record_stack_refs_data data;
   bool end_of_block = false;
 
   for (insn = BB_HEAD (bb); !end_of_block ; insn = next)
@@ -444,6 +509,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);
@@ -473,7 +540,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
@@ -490,12 +557,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;
@@ -507,12 +577,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;
@@ -527,9 +600,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
@@ -549,11 +623,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
@@ -583,15 +657,9 @@ combine_stack_adjustments_for_block (basic_block bb)
            }
        }
 
-      data.insn = insn;
-      data.reflist = reflist;
       if (!CALL_P (insn) && last_sp_set
-         && !for_each_rtx (&PATTERN (insn), record_stack_refs, &data))
-       {
-          reflist = data.reflist;
-          continue;
-       }
-      reflist = data.reflist;
+         && record_stack_refs (insn, &reflist))
+       continue;
 
       /* Otherwise, we were not able to process the instruction.
         Do not continue collecting data across such a one.  */