diff gcc/cselib.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
line wrap: on
line diff
--- a/gcc/cselib.c	Fri Oct 27 22:46:09 2017 +0900
+++ b/gcc/cselib.c	Thu Oct 25 07:37:49 2018 +0900
@@ -1,5 +1,5 @@
 /* Common subexpression elimination library for GNU compiler.
-   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+   Copyright (C) 1987-2018 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -54,7 +54,8 @@
 static cselib_val *new_cselib_val (unsigned int, machine_mode, rtx);
 static void add_mem_for_addr (cselib_val *, cselib_val *, rtx);
 static cselib_val *cselib_lookup_mem (rtx, int);
-static void cselib_invalidate_regno (unsigned int, machine_mode);
+static void cselib_invalidate_regno (unsigned int, machine_mode,
+				     const_rtx = NULL);
 static void cselib_invalidate_mem (rtx);
 static void cselib_record_set (rtx, cselib_val *, cselib_val *);
 static void cselib_record_sets (rtx_insn *);
@@ -805,14 +806,14 @@
       if (memmode == VOIDmode)
 	return x;
 
-      *off = GEN_INT (-GET_MODE_SIZE (memmode));
+      *off = gen_int_mode (-GET_MODE_SIZE (memmode), GET_MODE (x));
       return XEXP (x, 0);
 
     case PRE_INC:
       if (memmode == VOIDmode)
 	return x;
 
-      *off = GEN_INT (GET_MODE_SIZE (memmode));
+      *off = gen_int_mode (GET_MODE_SIZE (memmode), GET_MODE (x));
       return XEXP (x, 0);
 
     case PRE_MODIFY:
@@ -987,6 +988,11 @@
 	    return 0;
 	  break;
 
+	case 'p':
+	  if (maybe_ne (SUBREG_BYTE (x), SUBREG_BYTE (y)))
+	    return 0;
+	  break;
+
 	case 'V':
 	case 'E':
 	  /* Two vectors must have the same length.  */
@@ -1063,6 +1069,7 @@
 cselib_hash_rtx (rtx x, int create, machine_mode memmode)
 {
   cselib_val *e;
+  poly_int64 offset;
   int i, j;
   enum rtx_code code;
   const char *fmt;
@@ -1128,6 +1135,15 @@
 	hash += CONST_WIDE_INT_ELT (x, i);
       return hash;
 
+    case CONST_POLY_INT:
+      {
+	inchash::hash h;
+	h.add_int (hash);
+	for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+	  h.add_wide_int (CONST_POLY_INT_COEFFS (x)[i]);
+	return h.end ();
+      }
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
 	 the integers representing the constant.  */
@@ -1149,11 +1165,11 @@
 	int units;
 	rtx elt;
 
-	units = CONST_VECTOR_NUNITS (x);
+	units = const_vector_encoded_nelts (x);
 
 	for (i = 0; i < units; ++i)
 	  {
-	    elt = CONST_VECTOR_ELT (x, i);
+	    elt = CONST_VECTOR_ENCODED_ELT (x, i);
 	    hash += cselib_hash_rtx (elt, 0, memmode);
 	  }
 
@@ -1189,14 +1205,15 @@
     case PRE_INC:
       /* We can't compute these without knowing the MEM mode.  */
       gcc_assert (memmode != VOIDmode);
-      i = GET_MODE_SIZE (memmode);
+      offset = GET_MODE_SIZE (memmode);
       if (code == PRE_DEC)
-	i = -i;
+	offset = -offset;
       /* Adjust the hash so that (mem:MEMMODE (pre_* (reg))) hashes
 	 like (mem:MEMMODE (plus (reg) (const_int I))).  */
       hash += (unsigned) PLUS - (unsigned)code
 	+ cselib_hash_rtx (XEXP (x, 0), create, memmode)
-	+ cselib_hash_rtx (GEN_INT (i), create, memmode);
+	+ cselib_hash_rtx (gen_int_mode (offset, GET_MODE (x)),
+			   create, memmode);
       return hash ? hash : 1 + (unsigned) PLUS;
 
     case PRE_MODIFY:
@@ -1269,6 +1286,10 @@
 	  hash += XINT (x, i);
 	  break;
 
+	case 'p':
+	  hash += constant_lower_bound (SUBREG_BYTE (x));
+	  break;
+
 	case '0':
 	case 't':
 	  /* unused */
@@ -1641,6 +1662,7 @@
       /* SCRATCH must be shared because they represent distinct values.  */
       return orig;
     case CLOBBER:
+    case CLOBBER_HIGH:
       if (REG_P (XEXP (orig, 0)) && HARD_REGISTER_NUM_P (REGNO (XEXP (orig, 0))))
 	return orig;
       break;
@@ -1853,6 +1875,7 @@
   struct elt_list *l;
   rtx copy = x;
   int i;
+  poly_int64 offset;
 
   switch (code)
     {
@@ -1889,11 +1912,11 @@
     case PRE_DEC:
     case PRE_INC:
       gcc_assert (memmode != VOIDmode);
-      i = GET_MODE_SIZE (memmode);
+      offset = GET_MODE_SIZE (memmode);
       if (code == PRE_DEC)
-	i = -i;
+	offset = -offset;
       return cselib_subst_to_values (plus_constant (GET_MODE (x),
-						    XEXP (x, 0), i),
+						    XEXP (x, 0), offset),
 				     memmode);
 
     case PRE_MODIFY:
@@ -2142,7 +2165,8 @@
    invalidating call clobbered registers across a call.  */
 
 static void
-cselib_invalidate_regno (unsigned int regno, machine_mode mode)
+cselib_invalidate_regno (unsigned int regno, machine_mode mode,
+			 const_rtx setter)
 {
   unsigned int endregno;
   unsigned int i;
@@ -2165,6 +2189,9 @@
 	i = regno - max_value_regs;
 
       endregno = end_hard_regno (mode, regno);
+
+      if (setter && GET_CODE (setter) == CLOBBER_HIGH)
+	gcc_assert (endregno == regno + 1);
     }
   else
     {
@@ -2197,6 +2224,19 @@
 	      continue;
 	    }
 
+	  /* Ignore if clobber high and the register isn't clobbered.  */
+	  if (setter && GET_CODE (setter) == CLOBBER_HIGH)
+	    {
+	      gcc_assert (endregno == regno + 1);
+	      const_rtx x = XEXP (setter, 0);
+	      if (!reg_is_clobbered_by_clobber_high (i, GET_MODE (v->val_rtx),
+						     x))
+		{
+		  l = &(*l)->next;
+		  continue;
+		}
+	    }
+
 	  /* We have an overlap.  */
 	  if (*l == REG_VALUES (i))
 	    {
@@ -2331,10 +2371,10 @@
   *vp = &dummy_val;
 }
 
-/* Invalidate DEST, which is being assigned to or clobbered.  */
+/* Invalidate DEST, which is being assigned to or clobbered by SETTER.  */
 
 void
-cselib_invalidate_rtx (rtx dest)
+cselib_invalidate_rtx (rtx dest, const_rtx setter)
 {
   while (GET_CODE (dest) == SUBREG
 	 || GET_CODE (dest) == ZERO_EXTRACT
@@ -2342,7 +2382,7 @@
     dest = XEXP (dest, 0);
 
   if (REG_P (dest))
-    cselib_invalidate_regno (REGNO (dest), GET_MODE (dest));
+    cselib_invalidate_regno (REGNO (dest), GET_MODE (dest), setter);
   else if (MEM_P (dest))
     cselib_invalidate_mem (dest);
 }
@@ -2350,10 +2390,10 @@
 /* A wrapper for cselib_invalidate_rtx to be called via note_stores.  */
 
 static void
-cselib_invalidate_rtx_note_stores (rtx dest, const_rtx ignore ATTRIBUTE_UNUSED,
+cselib_invalidate_rtx_note_stores (rtx dest, const_rtx setter,
 				   void *data ATTRIBUTE_UNUSED)
 {
-  cselib_invalidate_rtx (dest);
+  cselib_invalidate_rtx (dest, setter);
 }
 
 /* Record the result of a SET instruction.  DEST is being set; the source
@@ -2481,6 +2521,7 @@
   rtx body = PATTERN (insn);
   rtx cond = 0;
   int n_sets_before_autoinc;
+  int n_strict_low_parts = 0;
   struct cselib_record_autoinc_data data;
 
   body = PATTERN (insn);
@@ -2535,6 +2576,7 @@
   for (i = 0; i < n_sets; i++)
     {
       rtx dest = sets[i].dest;
+      rtx orig = dest;
 
       /* A STRICT_LOW_PART can be ignored; we'll record the equivalence for
          the low part after invalidating any knowledge about larger modes.  */
@@ -2560,6 +2602,55 @@
 	  else
 	    sets[i].dest_addr_elt = 0;
 	}
+
+      /* Improve handling of STRICT_LOW_PART if the current value is known
+	 to be const0_rtx, then the low bits will be set to dest and higher
+	 bits will remain zero.  Used in code like:
+
+	 {di:SI=0;clobber flags:CC;}
+	 flags:CCNO=cmp(bx:SI,0)
+	 strict_low_part(di:QI)=flags:CCNO<=0
+
+	 where we can note both that di:QI=flags:CCNO<=0 and
+	 also that because di:SI is known to be 0 and strict_low_part(di:QI)
+	 preserves the upper bits that di:SI=zero_extend(flags:CCNO<=0).  */
+      scalar_int_mode mode;
+      if (dest != orig
+	  && cselib_record_sets_hook
+	  && REG_P (dest)
+	  && HARD_REGISTER_P (dest)
+	  && is_a <scalar_int_mode> (GET_MODE (dest), &mode)
+	  && n_sets + n_strict_low_parts < MAX_SETS)
+	{
+	  opt_scalar_int_mode wider_mode_iter;
+	  FOR_EACH_WIDER_MODE (wider_mode_iter, mode)
+	    {
+	      scalar_int_mode wider_mode = wider_mode_iter.require ();
+	      if (GET_MODE_PRECISION (wider_mode) > BITS_PER_WORD)
+		break;
+
+	      rtx reg = gen_lowpart (wider_mode, dest);
+	      if (!REG_P (reg))
+		break;
+
+	      cselib_val *v = cselib_lookup (reg, wider_mode, 0, VOIDmode);
+	      if (!v)
+		continue;
+
+	      struct elt_loc_list *l;
+	      for (l = v->locs; l; l = l->next)
+		if (l->loc == const0_rtx)
+		  break;
+
+	      if (!l)
+		continue;
+
+	      sets[n_sets + n_strict_low_parts].dest = reg;
+	      sets[n_sets + n_strict_low_parts].src = dest;
+	      sets[n_sets + n_strict_low_parts++].src_elt = sets[i].src_elt;
+	      break;
+	    }
+	}
     }
 
   if (cselib_record_sets_hook)
@@ -2604,6 +2695,20 @@
 	  || (MEM_P (dest) && cselib_record_memory))
 	cselib_record_set (dest, sets[i].src_elt, sets[i].dest_addr_elt);
     }
+
+  /* And deal with STRICT_LOW_PART.  */
+  for (i = 0; i < n_strict_low_parts; i++)
+    {
+      if (! PRESERVED_VALUE_P (sets[n_sets + i].src_elt->val_rtx))
+	continue;
+      machine_mode dest_mode = GET_MODE (sets[n_sets + i].dest);
+      cselib_val *v
+	= cselib_lookup (sets[n_sets + i].dest, dest_mode, 1, VOIDmode);
+      cselib_preserve_value (v);
+      rtx r = gen_rtx_ZERO_EXTEND (dest_mode,
+				   sets[n_sets + i].src_elt->val_rtx);
+      cselib_add_permanent_equiv (v, r, insn);
+    }
 }
 
 /* Return true if INSN in the prologue initializes hard_frame_pointer_rtx.  */
@@ -2689,9 +2794,12 @@
   if (CALL_P (insn))
     {
       for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
-	if (GET_CODE (XEXP (x, 0)) == CLOBBER)
-	  cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
-      /* Flush evertything on setjmp.  */
+	{
+	  gcc_assert (GET_CODE (XEXP (x, 0)) != CLOBBER_HIGH);
+	  if (GET_CODE (XEXP (x, 0)) == CLOBBER)
+	    cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
+	}
+      /* Flush everything on setjmp.  */
       if (cselib_preserve_constants
 	  && find_reg_note (insn, REG_SETJMP, NULL))
 	{