diff gcc/rtlanal.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/gcc/rtlanal.c	Thu Oct 25 07:37:49 2018 +0900
+++ b/gcc/rtlanal.c	Thu Feb 13 11:34:05 2020 +0900
@@ -1,5 +1,5 @@
 /* Analyze RTL for GNU compiler.
-   Copyright (C) 1987-2018 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -36,6 +36,7 @@
 #include "addresses.h"
 #include "rtl-iter.h"
 #include "hard-reg-set.h"
+#include "function-abi.h"
 
 /* Forward declarations */
 static void set_of_1 (rtx, const_rtx, void *);
@@ -359,10 +360,10 @@
   if (to == from)
     return 0;
 
-  /* It is not safe to call INITIAL_ELIMINATION_OFFSET
-     before the reload pass.  We need to give at least
-     an estimation for the resulting frame size.  */
-  if (! reload_completed)
+  /* It is not safe to call INITIAL_ELIMINATION_OFFSET before the epilogue
+     is completed, but we need to give at least an estimate for the stack
+     pointer based on the frame size.  */
+  if (!epilogue_completed)
     {
       offset1 = crtl->outgoing_args_size + get_frame_size ();
 #if !STACK_GROWS_DOWNWARD
@@ -521,7 +522,7 @@
 
 	  return (!known_size_p (decl_size) || known_eq (decl_size, 0)
 		  ? maybe_ne (offset, 0)
-		  : maybe_gt (offset + size, decl_size));
+		  : !known_subrange_p (offset, size, 0, decl_size));
         }
 
       return 0;
@@ -811,10 +812,9 @@
 /* Return the CALL in X if there is one.  */
 
 rtx
-get_call_rtx_from (rtx x)
-{
-  if (INSN_P (x))
-    x = PATTERN (x);
+get_call_rtx_from (const rtx_insn *insn)
+{
+  rtx x = PATTERN (insn);
   if (GET_CODE (x) == PARALLEL)
     x = XVECEXP (x, 0, 0);
   if (GET_CODE (x) == SET)
@@ -823,6 +823,24 @@
     return x;
   return NULL_RTX;
 }
+
+/* Get the declaration of the function called by INSN.  */
+
+tree
+get_call_fndecl (const rtx_insn *insn)
+{
+  rtx note, datum;
+
+  note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX);
+  if (note == NULL_RTX)
+    return NULL_TREE;
+
+  datum = XEXP (note, 0);
+  if (datum != NULL_RTX)
+    return SYMBOL_REF_DECL (datum);
+
+  return NULL_TREE;
+}
 
 /* Return the value of the integer term in X, if one is apparent;
    otherwise return 0.
@@ -1198,10 +1216,6 @@
 	  return 1;
       return 0;
 
-    case CLOBBER_HIGH:
-      gcc_assert (REG_P (XEXP (body, 0)));
-      return 0;
-
     case COND_EXEC:
       if (reg_overlap_mentioned_p (x, COND_EXEC_TEST (body)))
 	return 1;
@@ -1253,8 +1267,8 @@
 	  || (CALL_P (insn)
 	      && ((REG_P (reg)
 		   && REGNO (reg) < FIRST_PSEUDO_REGISTER
-		   && overlaps_hard_reg_set_p (regs_invalidated_by_call,
-					       GET_MODE (reg), REGNO (reg)))
+		   && (insn_callee_abi (as_a<const rtx_insn *> (insn))
+		       .clobbers_reg_p (GET_MODE (reg), REGNO (reg))))
 		  || MEM_P (reg)
 		  || find_reg_fusage (insn, CLOBBER, reg)))))
     return true;
@@ -1424,11 +1438,7 @@
 {
   struct set_of_data *const data = (struct set_of_data *) (data1);
   if (rtx_equal_p (x, data->pat)
-      || (GET_CODE (pat) == CLOBBER_HIGH
-	  && REGNO(data->pat) == REGNO(XEXP (pat, 0))
-	  && reg_is_clobbered_by_clobber_high (data->pat, XEXP (pat, 0)))
-      || (GET_CODE (pat) != CLOBBER_HIGH && !MEM_P (x)
-	  && reg_overlap_mentioned_p (data->pat, x)))
+      || (!MEM_P (x) && reg_overlap_mentioned_p (data->pat, x)))
     data->found = pat;
 }
 
@@ -1440,7 +1450,7 @@
   struct set_of_data data;
   data.found = NULL_RTX;
   data.pat = pat;
-  note_stores (INSN_P (insn) ? PATTERN (insn) : insn, set_of_1, &data);
+  note_pattern_stores (INSN_P (insn) ? PATTERN (insn) : insn, set_of_1, &data);
   return data.found;
 }
 
@@ -1469,22 +1479,20 @@
 }
 
 /* Examine INSN, and compute the set of hard registers written by it.
-   Store it in *PSET.  Should only be called after reload.  */
+   Store it in *PSET.  Should only be called after reload.
+
+   IMPLICIT is true if we should include registers that are fully-clobbered
+   by calls.  This should be used with caution, since it doesn't include
+   partially-clobbered registers.  */
 void
 find_all_hard_reg_sets (const rtx_insn *insn, HARD_REG_SET *pset, bool implicit)
 {
   rtx link;
 
   CLEAR_HARD_REG_SET (*pset);
-  note_stores (PATTERN (insn), record_hard_reg_sets, pset);
-  if (CALL_P (insn))
-    {
-      if (implicit)
-	IOR_HARD_REG_SET (*pset, call_used_reg_set);
-
-      for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
-	record_hard_reg_sets (XEXP (link, 0), NULL, pset);
-    }
+  note_stores (insn, record_hard_reg_sets, pset);
+  if (CALL_P (insn) && implicit)
+    *pset |= insn_callee_abi (insn).full_reg_clobbers ();
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     if (REG_NOTE_KIND (link) == REG_INC)
       record_hard_reg_sets (XEXP (link, 0), NULL, pset);
@@ -1517,7 +1525,6 @@
 	    {
 	    case USE:
 	    case CLOBBER:
-	    case CLOBBER_HIGH:
 	      break;
 
 	    case SET:
@@ -1671,9 +1678,7 @@
 	{
 	  rtx tem = XVECEXP (pat, 0, i);
 
-	  if (GET_CODE (tem) == USE
-	      || GET_CODE (tem) == CLOBBER
-	      || GET_CODE (tem) == CLOBBER_HIGH)
+	  if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER)
 	    continue;
 
 	  if (GET_CODE (tem) != SET || ! set_noop_p (tem))
@@ -1806,7 +1811,7 @@
 {
   unsigned int regno, endregno;
 
-  /* If either argument is a constant, then modifying X can not
+  /* If either argument is a constant, then modifying X cannot
      affect IN.  Here we look at IN, we can profitably combine
      CONSTANT_P (x) with the switch statement below.  */
   if (CONSTANT_P (in))
@@ -1899,16 +1904,15 @@
   the SUBREG will be passed.  */
 
 void
-note_stores (const_rtx x, void (*fun) (rtx, const_rtx, void *), void *data)
+note_pattern_stores (const_rtx x,
+		     void (*fun) (rtx, const_rtx, void *), void *data)
 {
   int i;
 
   if (GET_CODE (x) == COND_EXEC)
     x = COND_EXEC_CODE (x);
 
-  if (GET_CODE (x) == SET
-      || GET_CODE (x) == CLOBBER
-      || GET_CODE (x) == CLOBBER_HIGH)
+  if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
     {
       rtx dest = SET_DEST (x);
 
@@ -1933,7 +1937,22 @@
 
   else if (GET_CODE (x) == PARALLEL)
     for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
-      note_stores (XVECEXP (x, 0, i), fun, data);
+      note_pattern_stores (XVECEXP (x, 0, i), fun, data);
+}
+
+/* Same, but for an instruction.  If the instruction is a call, include
+   any CLOBBERs in its CALL_INSN_FUNCTION_USAGE.  */
+
+void
+note_stores (const rtx_insn *insn,
+	     void (*fun) (rtx, const_rtx, void *), void *data)
+{
+  if (CALL_P (insn))
+    for (rtx link = CALL_INSN_FUNCTION_USAGE (insn);
+	 link; link = XEXP (link, 1))
+      if (GET_CODE (XEXP (link, 0)) == CLOBBER)
+	note_pattern_stores (XEXP (link, 0), fun, data);
+  note_pattern_stores (PATTERN (insn), fun, data);
 }
 
 /* Like notes_stores, but call FUN for each expression that is being
@@ -2846,10 +2865,28 @@
     case UMOD:
       if (HONOR_SNANS (x))
 	return 1;
-      if (SCALAR_FLOAT_MODE_P (GET_MODE (x)))
+      if (FLOAT_MODE_P (GET_MODE (x)))
 	return flag_trapping_math;
       if (!CONSTANT_P (XEXP (x, 1)) || (XEXP (x, 1) == const0_rtx))
 	return 1;
+      if (GET_CODE (XEXP (x, 1)) == CONST_VECTOR)
+	{
+	  /* For CONST_VECTOR, return 1 if any element is or might be zero.  */
+	  unsigned int n_elts;
+	  rtx op = XEXP (x, 1);
+	  if (!GET_MODE_NUNITS (GET_MODE (op)).is_constant (&n_elts))
+	    {
+	      if (!CONST_VECTOR_DUPLICATE_P (op))
+		return 1;
+	      for (unsigned i = 0; i < (unsigned int) XVECLEN (op, 0); i++)
+		if (CONST_VECTOR_ENCODED_ELT (op, i) == const0_rtx)
+		  return 1;
+	    }
+	  else
+	    for (unsigned i = 0; i < n_elts; i++)
+	      if (CONST_VECTOR_ELT (op, i) == const0_rtx)
+		return 1;
+	}
       break;
 
     case EXPR_LIST:
@@ -2898,12 +2935,16 @@
     case NEG:
     case ABS:
     case SUBREG:
+    case VEC_MERGE:
+    case VEC_SELECT:
+    case VEC_CONCAT:
+    case VEC_DUPLICATE:
       /* These operations don't trap even with floating point.  */
       break;
 
     default:
       /* Any floating arithmetic may trap.  */
-      if (SCALAR_FLOAT_MODE_P (GET_MODE (x)) && flag_trapping_math)
+      if (FLOAT_MODE_P (GET_MODE (x)) && flag_trapping_math)
 	return 1;
     }
 
@@ -2980,64 +3021,6 @@
   return may_trap_p_1 (x, 1);
 }
 
-/* Return nonzero if X contains a comparison that is not either EQ or NE,
-   i.e., an inequality.  */
-
-int
-inequality_comparisons_p (const_rtx x)
-{
-  const char *fmt;
-  int len, i;
-  const enum rtx_code code = GET_CODE (x);
-
-  switch (code)
-    {
-    case REG:
-    case SCRATCH:
-    case PC:
-    case CC0:
-    CASE_CONST_ANY:
-    case CONST:
-    case LABEL_REF:
-    case SYMBOL_REF:
-      return 0;
-
-    case LT:
-    case LTU:
-    case GT:
-    case GTU:
-    case LE:
-    case LEU:
-    case GE:
-    case GEU:
-      return 1;
-
-    default:
-      break;
-    }
-
-  len = GET_RTX_LENGTH (code);
-  fmt = GET_RTX_FORMAT (code);
-
-  for (i = 0; i < len; i++)
-    {
-      if (fmt[i] == 'e')
-	{
-	  if (inequality_comparisons_p (XEXP (x, i)))
-	    return 1;
-	}
-      else if (fmt[i] == 'E')
-	{
-	  int j;
-	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-	    if (inequality_comparisons_p (XVECEXP (x, i, j)))
-	      return 1;
-	}
-    }
-
-  return 0;
-}
-
 /* Replace any occurrence of FROM in X with TO.  The function does
    not enter into CONST_DOUBLE for the replace.
 
@@ -3250,6 +3233,23 @@
   return true;
 }
 
+/* For INSN known to satisfy tablejump_p, determine if it actually is a
+   CASESI.  Return the insn pattern if so, NULL_RTX otherwise.  */
+
+rtx
+tablejump_casesi_pattern (const rtx_insn *insn)
+{
+  rtx tmp;
+
+  if ((tmp = single_set (insn)) != NULL
+      && SET_DEST (tmp) == pc_rtx
+      && GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE
+      && GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF)
+    return tmp;
+
+  return NULL_RTX;
+}
+
 /* A subroutine of computed_jump_p, return 1 if X contains a REG or MEM or
    constant that is not in the constant pool and not in the condition
    of an IF_THEN_ELSE.  */
@@ -3589,23 +3589,31 @@
   return 0;
 }
 
-/* Helper function for subreg_lsb.  Given a subreg's OUTER_MODE, INNER_MODE,
-   and SUBREG_BYTE, return the bit offset where the subreg begins
-   (counting from the least significant bit of the operand).  */
+/* Reinterpret a subreg as a bit extraction from an integer and return
+   the position of the least significant bit of the extracted value.
+   In other words, if the extraction were performed as a shift right
+   and mask, return the number of bits to shift right.
+
+   The outer value of the subreg has OUTER_BYTES bytes and starts at
+   byte offset SUBREG_BYTE within an inner value of INNER_BYTES bytes.  */
 
 poly_uint64
-subreg_lsb_1 (machine_mode outer_mode,
-	      machine_mode inner_mode,
-	      poly_uint64 subreg_byte)
+subreg_size_lsb (poly_uint64 outer_bytes,
+		 poly_uint64 inner_bytes,
+		 poly_uint64 subreg_byte)
 {
   poly_uint64 subreg_end, trailing_bytes, byte_pos;
 
   /* A paradoxical subreg begins at bit position 0.  */
-  if (paradoxical_subreg_p (outer_mode, inner_mode))
-    return 0;
-
-  subreg_end = subreg_byte + GET_MODE_SIZE (outer_mode);
-  trailing_bytes = GET_MODE_SIZE (inner_mode) - subreg_end;
+  gcc_checking_assert (ordered_p (outer_bytes, inner_bytes));
+  if (maybe_gt (outer_bytes, inner_bytes))
+    {
+      gcc_checking_assert (known_eq (subreg_byte, 0U));
+      return 0;
+    }
+
+  subreg_end = subreg_byte + outer_bytes;
+  trailing_bytes = inner_bytes - subreg_end;
   if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
     byte_pos = trailing_bytes;
   else if (!WORDS_BIG_ENDIAN && !BYTES_BIG_ENDIAN)
@@ -3943,9 +3951,7 @@
   /* Give the backend a chance to disallow the mode change.  */
   if (GET_MODE_CLASS (xmode) != MODE_COMPLEX_INT
       && GET_MODE_CLASS (xmode) != MODE_COMPLEX_FLOAT
-      && !REG_CAN_CHANGE_MODE_P (xregno, xmode, ymode)
-      /* We can use mode change in LRA for some transformations.  */
-      && ! lra_in_progress)
+      && !REG_CAN_CHANGE_MODE_P (xregno, xmode, ymode))
     return -1;
 
   /* We shouldn't simplify stack-related registers.  */
@@ -4101,7 +4107,7 @@
       if (INSN_P (before))
 	{
 	  int nregs_old = parm.nregs;
-	  note_stores (PATTERN (before), parms_set, &parm);
+	  note_stores (before, parms_set, &parm);
 	  /* If we found something that did not set a parameter reg,
 	     we're done.  Do not keep going, as that might result
 	     in hoisting an insn before the setting of a pseudo
@@ -4485,12 +4491,12 @@
      might be nonzero in its own mode, taking into account the fact that, on
      CISC machines, accessing an object in a wider mode generally causes the
      high-order bits to become undefined, so they are not known to be zero.
-     We extend this reasoning to RISC machines for rotate operations since the
-     semantics of the operations in the larger mode is not well defined.  */
+     We extend this reasoning to RISC machines for operations that might not
+     operate on the full registers.  */
   if (mode_width > xmode_width
       && xmode_width <= BITS_PER_WORD
       && xmode_width <= HOST_BITS_PER_WIDE_INT
-      && (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT))
+      && !(WORD_REGISTER_OPERATIONS && word_register_operation_p (x)))
     {
       nonzero &= cached_nonzero_bits (x, xmode,
 				      known_x, known_mode, known_ret);
@@ -4758,17 +4764,20 @@
 	  nonzero &= cached_nonzero_bits (SUBREG_REG (x), mode,
 					  known_x, known_mode, known_ret);
 
-          /* On many CISC machines, accessing an object in a wider mode
+          /* On a typical CISC machine, accessing an object in a wider mode
 	     causes the high-order bits to become undefined.  So they are
-	     not known to be zero.  */
+	     not known to be zero.
+
+	     On a typical RISC machine, we only have to worry about the way
+	     loads are extended.  Otherwise, if we get a reload for the inner
+	     part, it may be loaded from the stack, and then we may lose all
+	     the zero bits that existed before the store to the stack.  */
 	  rtx_code extend_op;
 	  if ((!WORD_REGISTER_OPERATIONS
-	       /* If this is a typical RISC machine, we only have to worry
-		  about the way loads are extended.  */
 	       || ((extend_op = load_extend_op (inner_mode)) == SIGN_EXTEND
 		   ? val_signbit_known_set_p (inner_mode, nonzero)
 		   : extend_op != ZERO_EXTEND)
-	       || (!MEM_P (SUBREG_REG (x)) && !REG_P (SUBREG_REG (x))))
+	       || !MEM_P (SUBREG_REG (x)))
 	      && xmode_width > inner_width)
 	    nonzero
 	      |= (GET_MODE_MASK (GET_MODE (x)) & ~GET_MODE_MASK (inner_mode));
@@ -5025,10 +5034,9 @@
     {
       /* If this machine does not do all register operations on the entire
 	 register and MODE is wider than the mode of X, we can say nothing
-	 at all about the high-order bits.  We extend this reasoning to every
-	 machine for rotate operations since the semantics of the operations
-	 in the larger mode is not well defined.  */
-      if (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT)
+	 at all about the high-order bits.  We extend this reasoning to RISC
+	 machines for operations that might not operate on full registers.  */
+      if (!(WORD_REGISTER_OPERATIONS && word_register_operation_p (x)))
 	return 1;
 
       /* Likewise on machines that do, if the mode of the object is smaller
@@ -5107,13 +5115,12 @@
 	  /* For paradoxical SUBREGs on machines where all register operations
 	     affect the entire register, just look inside.  Note that we are
 	     passing MODE to the recursive call, so the number of sign bit
-	     copies will remain relative to that mode, not the inner mode.  */
-
-	  /* This works only if loads sign extend.  Otherwise, if we get a
+	     copies will remain relative to that mode, not the inner mode.
+
+	     This works only if loads sign extend.  Otherwise, if we get a
 	     reload for the inner part, it may be loaded from the stack, and
 	     then we lose all sign bit copies that existed before the store
 	     to the stack.  */
-
 	  if (WORD_REGISTER_OPERATIONS
 	      && load_extend_op (inner_mode) == SIGN_EXTEND
 	      && paradoxical_subreg_p (x)
@@ -6550,6 +6557,20 @@
   return false;
 }
 
+/* Return true if RTL X contains a constant pool address.  */
+
+bool
+contains_constant_pool_address_p (const_rtx x)
+{
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, ALL)
+    if (SYMBOL_REF_P (*iter) && CONSTANT_POOL_ADDRESS_P (*iter))
+      return true;
+
+  return false;
+}
+
+
 /* Return true if X contains a thread-local symbol.  */
 
 bool
@@ -6564,32 +6585,3 @@
       return true;
   return false;
 }
-
-/* Return true if reg REGNO with mode REG_MODE would be clobbered by the
-   clobber_high operand in CLOBBER_HIGH_OP.  */
-
-bool
-reg_is_clobbered_by_clobber_high (unsigned int regno, machine_mode reg_mode,
-				  const_rtx clobber_high_op)
-{
-  unsigned int clobber_regno = REGNO (clobber_high_op);
-  machine_mode clobber_mode = GET_MODE (clobber_high_op);
-  unsigned char regno_nregs = hard_regno_nregs (regno, reg_mode);
-
-  /* Clobber high should always span exactly one register.  */
-  gcc_assert (REG_NREGS (clobber_high_op) == 1);
-
-  /* Clobber high needs to match with one of the registers in X.  */
-  if (clobber_regno < regno || clobber_regno >= regno + regno_nregs)
-    return false;
-
-  gcc_assert (reg_mode != BLKmode && clobber_mode != BLKmode);
-
-  if (reg_mode == VOIDmode)
-    return clobber_mode != VOIDmode;
-
-  /* Clobber high will clobber if its size might be greater than the size of
-     register regno.  */
-  return maybe_gt (exact_div (GET_MODE_SIZE (reg_mode), regno_nregs),
-		 GET_MODE_SIZE (clobber_mode));
-}