re PR target/65697 (__atomic memory barriers not strong enough for __sync builtins)
[gcc.git] / gcc / cse.c
index 8806197730ca6214fef7a32fee520a32be051712..100c9c83e769faf920d15c98bb614c35b80e8b5d 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -26,11 +26,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "hard-reg-set.h"
 #include "regs.h"
 #include "predict.h"
-#include "vec.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "input.h"
 #include "function.h"
 #include "dominance.h"
 #include "cfg.h"
@@ -42,10 +37,18 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-config.h"
 #include "recog.h"
 #include "symtab.h"
+#include "alias.h"
+#include "tree.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"
 #include "diagnostic-core.h"
 #include "toplev.h"
-#include "ggc.h"
 #include "except.h"
 #include "target.h"
 #include "params.h"
@@ -266,7 +269,6 @@ struct qty_table_elem
 /* The table of all qtys, indexed by qty number.  */
 static struct qty_table_elem *qty_table;
 
-#ifdef HAVE_cc0
 /* For machines that have a CC0, we do not record its value in the hash
    table since its use is guaranteed to be the insn immediately following
    its definition and any other insn is presumed to invalidate it.
@@ -278,7 +280,6 @@ static struct qty_table_elem *qty_table;
 
 static rtx this_insn_cc0, prev_insn_cc0;
 static machine_mode this_insn_cc0_mode, prev_insn_cc0_mode;
-#endif
 
 /* Insn being scanned.  */
 
@@ -869,9 +870,7 @@ new_basic_block (void)
        }
     }
 
-#ifdef HAVE_cc0
   prev_insn_cc0 = 0;
-#endif
 }
 
 /* Say that register REG contains a quantity in mode MODE not in any
@@ -1792,6 +1791,8 @@ merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
            }
          new_elt = insert (exp, class1, hash, mode);
          new_elt->in_memory = hash_arg_in_memory;
+         if (GET_CODE (exp) == ASM_OPERANDS && elt->cost == MAX_COST)
+           new_elt->cost = MAX_COST;
        }
     }
 }
@@ -1881,7 +1882,7 @@ invalidate (rtx x, machine_mode full_mode)
          {
            HOST_WIDE_INT in_table
              = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
-           unsigned int endregno = END_HARD_REGNO (x);
+           unsigned int endregno = END_REGNO (x);
            unsigned int tregno, tendregno, rn;
            struct table_elt *p, *next;
 
@@ -1907,7 +1908,7 @@ invalidate (rtx x, machine_mode full_mode)
                      continue;
 
                    tregno = REGNO (p->exp);
-                   tendregno = END_HARD_REGNO (p->exp);
+                   tendregno = END_REGNO (p->exp);
                    if (tendregno > regno && tregno < endregno)
                      remove_from_table (p, hash);
                  }
@@ -1967,6 +1968,22 @@ invalidate (rtx x, machine_mode full_mode)
       gcc_unreachable ();
     }
 }
+
+/* Invalidate DEST.  Used when DEST is not going to be added
+   into the hash table for some reason, e.g. do_not_record
+   flagged on it.  */
+
+static void
+invalidate_dest (rtx dest)
+{
+  if (REG_P (dest)
+      || GET_CODE (dest) == SUBREG
+      || MEM_P (dest))
+    invalidate (dest, VOIDmode);
+  else if (GET_CODE (dest) == STRICT_LOW_PART
+          || GET_CODE (dest) == ZERO_EXTRACT)
+    invalidate (XEXP (dest, 0), GET_MODE (dest));
+}
 \f
 /* Remove all expressions that refer to register REGNO,
    since they are already invalid, and we are about to
@@ -2110,7 +2127,7 @@ invalidate_for_call (void)
            continue;
 
          regno = REGNO (p->exp);
-         endregno = END_HARD_REGNO (p->exp);
+         endregno = END_REGNO (p->exp);
 
          for (i = regno; i < endregno; i++)
            if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
@@ -3117,6 +3134,15 @@ fold_rtx (rtx x, rtx_insn *insn)
     {
     case MEM:
     case SUBREG:
+    /* The first operand of a SIGN/ZERO_EXTRACT has a different meaning
+       than it would in other contexts.  Basically its mode does not
+       signify the size of the object read.  That information is carried
+       by size operand.    If we happen to have a MEM of the appropriate
+       mode in our tables with a constant value we could simplify the
+       extraction incorrectly if we allowed substitution of that value
+       for the MEM.   */
+    case ZERO_EXTRACT:
+    case SIGN_EXTRACT:
       if ((new_rtx = equiv_constant (x)) != NULL_RTX)
         return new_rtx;
       return x;
@@ -3133,10 +3159,8 @@ fold_rtx (rtx x, rtx_insn *insn)
     case EXPR_LIST:
       return x;
 
-#ifdef HAVE_cc0
     case CC0:
       return prev_insn_cc0;
-#endif
 
     case ASM_OPERANDS:
       if (insn)
@@ -3147,12 +3171,10 @@ fold_rtx (rtx x, rtx_insn *insn)
        }
       return x;
 
-#ifdef NO_FUNCTION_CSE
     case CALL:
-      if (CONSTANT_P (XEXP (XEXP (x, 0), 0)))
+      if (NO_FUNCTION_CSE && CONSTANT_P (XEXP (XEXP (x, 0), 0)))
        return x;
       break;
-#endif
 
     /* Anything else goes through the loop below.  */
     default:
@@ -3190,7 +3212,6 @@ fold_rtx (rtx x, rtx_insn *insn)
            const_arg = folded_arg;
            break;
 
-#ifdef HAVE_cc0
          case CC0:
            /* The cc0-user and cc0-setter may be in different blocks if
               the cc0-setter potentially traps.  In that case PREV_INSN_CC0
@@ -3214,7 +3235,6 @@ fold_rtx (rtx x, rtx_insn *insn)
                const_arg = equiv_constant (folded_arg);
              }
            break;
-#endif
 
          default:
            folded_arg = fold_rtx (folded_arg, insn);
@@ -4260,7 +4280,7 @@ find_sets_in_insn (rtx_insn *insn, struct set **psets)
     {
       int i, lim = XVECLEN (x, 0);
 
-      /* Go over the epressions of the PARALLEL in forward order, to
+      /* Go over the expressions of the PARALLEL in forward order, to
         put them in the same order in the SETS array.  */
       for (i = 0; i < lim; i++)
        {
@@ -4489,11 +4509,9 @@ cse_insn (rtx_insn *insn)
     sets = XALLOCAVEC (struct set, XVECLEN (x, 0));
 
   this_insn = insn;
-#ifdef HAVE_cc0
   /* Records what this insn does to set CC0.  */
   this_insn_cc0 = 0;
   this_insn_cc0_mode = VOIDmode;
-#endif
 
   /* Find all regs explicitly clobbered in this insn,
      to ensure they are not replaced with any other regs
@@ -4636,12 +4654,27 @@ cse_insn (rtx_insn *insn)
          && REGNO (dest) >= FIRST_PSEUDO_REGISTER)
        sets[i].src_volatile = 1;
 
-      /* Also do not record result of a non-volatile inline asm with
-        more than one result or with clobbers, we do not want CSE to
-        break the inline asm apart.  */
       else if (GET_CODE (src) == ASM_OPERANDS
               && GET_CODE (x) == PARALLEL)
-       sets[i].src_volatile = 1;
+       {
+         /* Do not record result of a non-volatile inline asm with
+            more than one result.  */
+         if (n_sets > 1)
+           sets[i].src_volatile = 1;
+
+         int j, lim = XVECLEN (x, 0);
+         for (j = 0; j < lim; j++)
+           {
+             rtx y = XVECEXP (x, 0, j);
+             /* And do not record result of a non-volatile inline asm
+                with "memory" clobber.  */
+             if (GET_CODE (y) == CLOBBER && MEM_P (XEXP (y, 0)))
+               {
+                 sets[i].src_volatile = 1;
+                 break;
+               }
+           }
+       }
 
 #if 0
       /* It is no longer clear why we used to do this, but it doesn't
@@ -5232,8 +5265,8 @@ cse_insn (rtx_insn *insn)
            ;
 
          /* Look for a substitution that makes a valid insn.  */
-         else if (validate_unshare_change
-                    (insn, &SET_SRC (sets[i].rtl), trial, 0))
+         else if (validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
+                                           trial, 0))
            {
              rtx new_rtx = canon_reg (SET_SRC (sets[i].rtl), insn);
 
@@ -5447,7 +5480,7 @@ cse_insn (rtx_insn *insn)
             and hope for the best.  */
          if (n_sets == 1)
            {
-             rtx_insn *new_rtx;
+             rtx_jump_insn *new_rtx;
              rtx note;
 
              new_rtx = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
@@ -5478,20 +5511,21 @@ cse_insn (rtx_insn *insn)
 
       else if (do_not_record)
        {
-         if (REG_P (dest) || GET_CODE (dest) == SUBREG)
-           invalidate (dest, VOIDmode);
-         else if (MEM_P (dest))
-           invalidate (dest, VOIDmode);
-         else if (GET_CODE (dest) == STRICT_LOW_PART
-                  || GET_CODE (dest) == ZERO_EXTRACT)
-           invalidate (XEXP (dest, 0), GET_MODE (dest));
+         invalidate_dest (dest);
          sets[i].rtl = 0;
        }
 
       if (sets[i].rtl != 0 && dest != SET_DEST (sets[i].rtl))
-       sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
+       {
+         do_not_record = 0;
+         sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
+         if (do_not_record)
+           {
+             invalidate_dest (SET_DEST (sets[i].rtl));
+             sets[i].rtl = 0;
+           }
+       }
 
-#ifdef HAVE_cc0
       /* If setting CC0, record what it was set to, or a constant, if it
         is equivalent to a constant.  If it is being set to a floating-point
         value, make a COMPARE with the appropriate constant of 0.  If we
@@ -5506,7 +5540,6 @@ cse_insn (rtx_insn *insn)
            this_insn_cc0 = gen_rtx_COMPARE (VOIDmode, this_insn_cc0,
                                             CONST0_RTX (mode));
        }
-#endif
     }
 
   /* Now enter all non-volatile source expressions in the hash table
@@ -5595,6 +5628,12 @@ cse_insn (rtx_insn *insn)
                  }
                elt = insert (src, classp, sets[i].src_hash, mode);
                elt->in_memory = sets[i].src_in_memory;
+               /* If inline asm has any clobbers, ensure we only reuse
+                  existing inline asms and never try to put the ASM_OPERANDS
+                  into an insn that isn't inline asm.  */
+               if (GET_CODE (src) == ASM_OPERANDS
+                   && GET_CODE (x) == PARALLEL)
+                 elt->cost = MAX_COST;
                sets[i].src_elt = classp = elt;
              }
            if (sets[i].src_const && sets[i].src_const_elt == 0
@@ -5908,6 +5947,9 @@ cse_insn (rtx_insn *insn)
                      }
                    src_elt = insert (new_src, classp, src_hash, new_mode);
                    src_elt->in_memory = elt->in_memory;
+                   if (GET_CODE (new_src) == ASM_OPERANDS
+                       && elt->cost == MAX_COST)
+                     src_elt->cost = MAX_COST;
                  }
                else if (classp && classp != src_elt->first_same_value)
                  /* Show that two things that we've seen before are
@@ -6468,8 +6510,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
                  && check_for_label_ref (insn))
                recorded_label_ref = true;
 
-#ifdef HAVE_cc0
-             if (NONDEBUG_INSN_P (insn))
+             if (HAVE_cc0 && NONDEBUG_INSN_P (insn))
                {
                  /* If the previous insn sets CC0 and this insn no
                     longer references CC0, delete the previous insn.
@@ -6496,7 +6537,6 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
                      prev_insn_cc0_mode = this_insn_cc0_mode;
                    }
                }
-#endif
            }
        }
 
@@ -6545,11 +6585,9 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
          record_jump_equiv (insn, taken);
        }
 
-#ifdef HAVE_cc0
       /* Clear the CC0-tracking related insns, they can't provide
         useful information across basic block boundaries.  */
       prev_insn_cc0 = 0;
-#endif
     }
 
   gcc_assert (next_qty <= max_qty);
@@ -6800,21 +6838,17 @@ static bool
 set_live_p (rtx set, rtx_insn *insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0.  */
            int *counts)
 {
-#ifdef HAVE_cc0
-  rtx tem;
-#endif
+  rtx_insn *tem;
 
   if (set_noop_p (set))
     ;
 
-#ifdef HAVE_cc0
   else if (GET_CODE (SET_DEST (set)) == CC0
           && !side_effects_p (SET_SRC (set))
           && ((tem = next_nonnote_nondebug_insn (insn)) == NULL_RTX
               || !INSN_P (tem)
               || !reg_referenced_p (cc0_rtx, PATTERN (tem))))
     return false;
-#endif
   else if (!is_dead_reg (SET_DEST (set), counts)
           || side_effects_p (SET_SRC (set)))
     return true;
@@ -7085,7 +7119,7 @@ delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 
 static void
 cse_change_cc_mode (subrtx_ptr_iterator::array_type &array,
-                   rtx *loc, rtx insn, rtx newreg)
+                   rtx *loc, rtx_insn *insn, rtx newreg)
 {
   FOR_EACH_SUBRTX_PTR (iter, array, loc, NONCONST)
     {