]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/emit-rtl.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / emit-rtl.c
index 4b0aa7cee061a7778eeb760e561f3649ab735ead..e6158f243c00676dbfd3c1a578966f1a0b6b4b42 100644 (file)
@@ -1,5 +1,5 @@
 /* Emit RTL for the GCC expander.
-   Copyright (C) 1987-2019 Free Software Foundation, Inc.
+   Copyright (C) 1987-2021 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -54,13 +54,15 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "explow.h"
 #include "expr.h"
-#include "params.h"
 #include "builtins.h"
 #include "rtl-iter.h"
 #include "stor-layout.h"
 #include "opts.h"
 #include "predict.h"
 #include "rtx-vector-builder.h"
+#include "gimple.h"
+#include "gimple-ssa.h"
+#include "gimplify.h"
 
 struct target_rtl default_target_rtl;
 #if SWITCHABLE_TARGET
@@ -121,7 +123,6 @@ rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
 rtx pc_rtx;
 rtx ret_rtx;
 rtx simple_return_rtx;
-rtx cc0_rtx;
 
 /* Marker used for denoting an INSN, which should never be accessed (i.e.,
    this pointer should normally never be dereferenced), but is required to be
@@ -348,7 +349,7 @@ const_fixed_hasher::equal (rtx x, rtx y)
 /* Return true if the given memory attributes are equal.  */
 
 bool
-mem_attrs_eq_p (const struct mem_attrs *p, const struct mem_attrs *q)
+mem_attrs_eq_p (const class mem_attrs *p, const class mem_attrs *q)
 {
   if (p == q)
     return true;
@@ -463,6 +464,17 @@ set_mode_and_regno (rtx x, machine_mode mode, unsigned int regno)
   set_regno_raw (x, regno, nregs);
 }
 
+/* Initialize a fresh REG rtx with mode MODE and register REGNO.  */
+
+rtx
+init_raw_REG (rtx x, machine_mode mode, unsigned int regno)
+{
+  set_mode_and_regno (x, mode, regno);
+  REG_ATTRS (x) = NULL;
+  ORIGINAL_REGNO (x) = regno;
+  return x;
+}
+
 /* Generate a new REG rtx.  Make sure ORIGINAL_REGNO is set properly, and
    don't attempt to share with the various global pieces of rtl (such as
    frame_pointer_rtx).  */
@@ -471,9 +483,7 @@ rtx
 gen_raw_REG (machine_mode mode, unsigned int regno)
 {
   rtx x = rtx_alloc (REG MEM_STAT_INFO);
-  set_mode_and_regno (x, mode, regno);
-  REG_ATTRS (x) = NULL;
-  ORIGINAL_REGNO (x) = regno;
+  init_raw_REG (x, mode, regno);
   return x;
 }
 
@@ -928,11 +938,13 @@ validate_subreg (machine_mode omode, machine_mode imode,
           && GET_MODE_INNER (imode) == omode)
     ;
   /* ??? x86 sse code makes heavy use of *paradoxical* vector subregs,
-     i.e. (subreg:V4SF (reg:SF) 0).  This surely isn't the cleanest way to
-     represent this.  It's questionable if this ought to be represented at
-     all -- why can't this all be hidden in post-reload splitters that make
-     arbitrarily mode changes to the registers themselves.  */
-  else if (VECTOR_MODE_P (omode) && GET_MODE_INNER (omode) == imode)
+     i.e. (subreg:V4SF (reg:SF) 0) or (subreg:V4SF (reg:V2SF) 0).  This
+     surely isn't the cleanest way to represent this.  It's questionable
+     if this ought to be represented at all -- why can't this all be hidden
+     in post-reload splitters that make arbitrarily mode changes to the
+     registers themselves.  */
+  else if (VECTOR_MODE_P (omode)
+          && GET_MODE_INNER (omode) == GET_MODE_INNER (imode))
     ;
   /* Subregs involving floating point modes are not allowed to
      change size.  Therefore (subreg:DI (reg:DF) 0) is fine, but
@@ -1613,19 +1625,22 @@ gen_highpart (machine_mode mode, rtx x)
   gcc_assert (known_le (msize, (unsigned int) UNITS_PER_WORD)
              || known_eq (msize, GET_MODE_UNIT_SIZE (GET_MODE (x))));
 
-  result = simplify_gen_subreg (mode, x, GET_MODE (x),
-                               subreg_highpart_offset (mode, GET_MODE (x)));
-  gcc_assert (result);
-
-  /* simplify_gen_subreg is not guaranteed to return a valid operand for
-     the target if we have a MEM.  gen_highpart must return a valid operand,
-     emitting code if necessary to do so.  */
-  if (MEM_P (result))
+  /* gen_lowpart_common handles a lot of special cases due to needing to handle
+     paradoxical subregs; it only calls simplify_gen_subreg when certain that
+     it will produce something meaningful.  The only case we need to handle
+     specially here is MEM.  */
+  if (MEM_P (x))
     {
-      result = validize_mem (result);
-      gcc_assert (result);
+      poly_int64 offset = subreg_highpart_offset (mode, GET_MODE (x));
+      return adjust_address (x, mode, offset);
     }
 
+  result = simplify_gen_subreg (mode, x, GET_MODE (x),
+                               subreg_highpart_offset (mode, GET_MODE (x)));
+  /* Since we handle MEM directly above, we should never get a MEM back
+     from simplify_gen_subreg.  */
+  gcc_assert (result && !MEM_P (result));
+
   return result;
 }
 
@@ -1921,7 +1936,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
 {
   poly_int64 apply_bitpos = 0;
   tree type;
-  struct mem_attrs attrs, *defattrs, *refattrs;
+  class mem_attrs attrs, *defattrs, *refattrs;
   addr_space_t as;
 
   /* It can happen that type_for_mode was given a mode for which there
@@ -2054,8 +2069,10 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
          new_size = DECL_SIZE_UNIT (t);
        }
 
-      /* ???  If we end up with a constant here do record a MEM_EXPR.  */
-      else if (CONSTANT_CLASS_P (t))
+      /* ???  If we end up with a constant or a descriptor do not
+        record a MEM_EXPR.  */
+      else if (CONSTANT_CLASS_P (t)
+              || TREE_CODE (t) == CONSTRUCTOR)
        ;
 
       /* If this is a field reference, record it.  */
@@ -2069,65 +2086,39 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
            new_size = DECL_SIZE_UNIT (TREE_OPERAND (t, 1));
        }
 
-      /* If this is an array reference, look for an outer field reference.  */
-      else if (TREE_CODE (t) == ARRAY_REF)
-       {
-         tree off_tree = size_zero_node;
-         /* We can't modify t, because we use it at the end of the
-            function.  */
-         tree t2 = t;
-
-         do
-           {
-             tree index = TREE_OPERAND (t2, 1);
-             tree low_bound = array_ref_low_bound (t2);
-             tree unit_size = array_ref_element_size (t2);
-
-             /* We assume all arrays have sizes that are a multiple of a byte.
-                First subtract the lower bound, if any, in the type of the
-                index, then convert to sizetype and multiply by the size of
-                the array element.  */
-             if (! integer_zerop (low_bound))
-               index = fold_build2 (MINUS_EXPR, TREE_TYPE (index),
-                                    index, low_bound);
-
-             off_tree = size_binop (PLUS_EXPR,
-                                    size_binop (MULT_EXPR,
-                                                fold_convert (sizetype,
-                                                              index),
-                                                unit_size),
-                                    off_tree);
-             t2 = TREE_OPERAND (t2, 0);
-           }
-         while (TREE_CODE (t2) == ARRAY_REF);
-
-         if (DECL_P (t2)
-             || (TREE_CODE (t2) == COMPONENT_REF
-                 /* For trailing arrays t2 doesn't have a size that
-                    covers all valid accesses.  */
-                 && ! array_at_struct_end_p (t)))
-           {
-             attrs.expr = t2;
-             attrs.offset_known_p = false;
-             if (poly_int_tree_p (off_tree, &attrs.offset))
-               {
-                 attrs.offset_known_p = true;
-                 apply_bitpos = bitpos;
-               }
-           }
-         /* Else do not record a MEM_EXPR.  */
-       }
-
-      /* If this is an indirect reference, record it.  */
-      else if (TREE_CODE (t) == MEM_REF 
-              || TREE_CODE (t) == TARGET_MEM_REF)
+      /* Else record it.  */
+      else
        {
+         gcc_assert (handled_component_p (t)
+                     || TREE_CODE (t) == MEM_REF
+                     || TREE_CODE (t) == TARGET_MEM_REF);
          attrs.expr = t;
          attrs.offset_known_p = true;
          attrs.offset = 0;
          apply_bitpos = bitpos;
        }
 
+      /* If this is a reference based on a partitioned decl replace the
+        base with a MEM_REF of the pointer representative we created
+        during stack slot partitioning.  */
+      if (attrs.expr
+         && VAR_P (base)
+         && ! is_global_var (base)
+         && cfun->gimple_df->decls_to_pointers != NULL)
+       {
+         tree *namep = cfun->gimple_df->decls_to_pointers->get (base);
+         if (namep)
+           {
+             attrs.expr = unshare_expr (attrs.expr);
+             tree *orig_base = &attrs.expr;
+             while (handled_component_p (*orig_base))
+               orig_base = &TREE_OPERAND (*orig_base, 0);
+             tree aptrt = reference_alias_ptr_type (*orig_base);
+             *orig_base = build2 (MEM_REF, TREE_TYPE (*orig_base), *namep,
+                                  build_int_cst (aptrt, 0));
+           }
+       }
+
       /* Compute the alignment.  */
       unsigned int obj_align;
       unsigned HOST_WIDE_INT obj_bitpos;
@@ -2310,7 +2301,7 @@ change_address (rtx memref, machine_mode mode, rtx addr)
 {
   rtx new_rtx = change_address_1 (memref, mode, addr, 1, false);
   machine_mode mmode = GET_MODE (new_rtx);
-  struct mem_attrs *defattrs;
+  class mem_attrs *defattrs;
 
   mem_attrs attrs (*get_mem_attrs (memref));
   defattrs = mode_mem_attrs[(int) mmode];
@@ -2354,7 +2345,7 @@ adjust_address_1 (rtx memref, machine_mode mode, poly_int64 offset,
   rtx addr = XEXP (memref, 0);
   rtx new_rtx;
   scalar_int_mode address_mode;
-  struct mem_attrs attrs (*get_mem_attrs (memref)), *defattrs;
+  class mem_attrs attrs (*get_mem_attrs (memref)), *defattrs;
   unsigned HOST_WIDE_INT max_align;
 #ifdef POINTERS_EXTEND_UNSIGNED
   scalar_int_mode pointer_mode
@@ -2500,7 +2491,7 @@ offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2)
 {
   rtx new_rtx, addr = XEXP (memref, 0);
   machine_mode address_mode;
-  struct mem_attrs *defattrs;
+  class mem_attrs *defattrs;
 
   mem_attrs attrs (*get_mem_attrs (memref));
   address_mode = get_address_mode (memref);
@@ -2729,15 +2720,15 @@ set_new_first_and_last_insn (rtx_insn *first, rtx_insn *last)
   set_last_insn (last);
   cur_insn_uid = 0;
 
-  if (MIN_NONDEBUG_INSN_UID || MAY_HAVE_DEBUG_INSNS)
+  if (param_min_nondebug_insn_uid || MAY_HAVE_DEBUG_INSNS)
     {
       int debug_count = 0;
 
-      cur_insn_uid = MIN_NONDEBUG_INSN_UID - 1;
+      cur_insn_uid = param_min_nondebug_insn_uid - 1;
       cur_debug_insn_uid = 0;
 
       for (insn = first; insn; insn = NEXT_INSN (insn))
-       if (INSN_UID (insn) < MIN_NONDEBUG_INSN_UID)
+       if (INSN_UID (insn) < param_min_nondebug_insn_uid)
          cur_debug_insn_uid = MAX (cur_debug_insn_uid, INSN_UID (insn));
        else
          {
@@ -2747,7 +2738,7 @@ set_new_first_and_last_insn (rtx_insn *first, rtx_insn *last)
          }
 
       if (debug_count)
-       cur_debug_insn_uid = MIN_NONDEBUG_INSN_UID + debug_count;
+       cur_debug_insn_uid = param_min_nondebug_insn_uid + debug_count;
       else
        cur_debug_insn_uid++;
     }
@@ -2858,15 +2849,13 @@ verify_rtx_sharing (rtx orig, rtx insn)
     case LABEL_REF:
     case CODE_LABEL:
     case PC:
-    case CC0:
     case RETURN:
     case SIMPLE_RETURN:
     case SCRATCH:
       /* SCRATCH must be shared because they represent distinct values.  */
       return;
     case CLOBBER:
-    case CLOBBER_HIGH:
-      /* Share clobbers of hard registers (like cc0), but do not share pseudo reg
+      /* Share clobbers of hard registers, but do not share pseudo reg
          clobbers or clobbers of hard registers that originated as pseudos.
          This is needed to allow safe register renaming.  */
       if (REG_P (XEXP (x, 0))
@@ -3112,15 +3101,13 @@ repeat:
     case LABEL_REF:
     case CODE_LABEL:
     case PC:
-    case CC0:
     case RETURN:
     case SIMPLE_RETURN:
     case SCRATCH:
       /* SCRATCH must be shared because they represent distinct values.  */
       return;
     case CLOBBER:
-    case CLOBBER_HIGH:
-      /* Share clobbers of hard registers (like cc0), but do not share pseudo reg
+      /* Share clobbers of hard registers, but do not share pseudo reg
          clobbers or clobbers of hard registers that originated as pseudos.
          This is needed to allow safe register renaming.  */
       if (REG_P (XEXP (x, 0))
@@ -3236,7 +3223,6 @@ repeat:
     case SYMBOL_REF:
     case CODE_LABEL:
     case PC:
-    case CC0:
     case RETURN:
     case SIMPLE_RETURN:
       return;
@@ -3414,10 +3400,10 @@ get_max_insn_count (void)
      differences due to debug insns, and not be affected by
      -fmin-insn-uid, to avoid excessive table size and to simplify
      debugging of -fcompare-debug failures.  */
-  if (cur_debug_insn_uid > MIN_NONDEBUG_INSN_UID)
+  if (cur_debug_insn_uid > param_min_nondebug_insn_uid)
     n -= cur_debug_insn_uid;
   else
-    n -= MIN_NONDEBUG_INSN_UID;
+    n -= param_min_nondebug_insn_uid;
 
   return n;
 }
@@ -3730,50 +3716,6 @@ prev_active_insn (rtx_insn *insn)
   return insn;
 }
 \f
-/* Return the next insn that uses CC0 after INSN, which is assumed to
-   set it.  This is the inverse of prev_cc0_setter (i.e., prev_cc0_setter
-   applied to the result of this function should yield INSN).
-
-   Normally, this is simply the next insn.  However, if a REG_CC_USER note
-   is present, it contains the insn that uses CC0.
-
-   Return 0 if we can't find the insn.  */
-
-rtx_insn *
-next_cc0_user (rtx_insn *insn)
-{
-  rtx note = find_reg_note (insn, REG_CC_USER, NULL_RTX);
-
-  if (note)
-    return safe_as_a <rtx_insn *> (XEXP (note, 0));
-
-  insn = next_nonnote_insn (insn);
-  if (insn && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
-    insn = as_a <rtx_sequence *> (PATTERN (insn))->insn (0);
-
-  if (insn && INSN_P (insn) && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
-    return insn;
-
-  return 0;
-}
-
-/* Find the insn that set CC0 for INSN.  Unless INSN has a REG_CC_SETTER
-   note, it is the previous insn.  */
-
-rtx_insn *
-prev_cc0_setter (rtx_insn *insn)
-{
-  rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
-
-  if (note)
-    return safe_as_a <rtx_insn *> (XEXP (note, 0));
-
-  insn = prev_nonnote_insn (insn);
-  gcc_assert (sets_cc0_p (PATTERN (insn)));
-
-  return insn;
-}
-
 /* Find a RTX_AUTOINC class rtx which matches DATA.  */
 
 static int
@@ -3835,10 +3777,6 @@ try_split (rtx pat, rtx_insn *trial, int last)
   int njumps = 0;
   rtx_insn *call_insn = NULL;
 
-  /* We're not good at redistributing frame information.  */
-  if (RTX_FRAME_RELATED_P (trial))
-    return trial;
-
   if (any_condjump_p (trial)
       && (note = find_reg_note (trial, REG_BR_PROB, 0)))
     split_branch_probability
@@ -3855,6 +3793,7 @@ try_split (rtx pat, rtx_insn *trial, int last)
   if (!seq)
     return trial;
 
+  int split_insn_count = 0;
   /* Avoid infinite loop if any insn of the result matches
      the original pattern.  */
   insn_last = seq;
@@ -3863,11 +3802,25 @@ try_split (rtx pat, rtx_insn *trial, int last)
       if (INSN_P (insn_last)
          && rtx_equal_p (PATTERN (insn_last), pat))
        return trial;
+      split_insn_count++;
       if (!NEXT_INSN (insn_last))
        break;
       insn_last = NEXT_INSN (insn_last);
     }
 
+  /* We're not good at redistributing frame information if
+     the split occurs before reload or if it results in more
+     than one insn.  */
+  if (RTX_FRAME_RELATED_P (trial))
+    {
+      if (!reload_completed || split_insn_count != 1)
+        return trial;
+
+      rtx_insn *new_insn = seq;
+      rtx_insn *old_insn = trial;
+      copy_frame_info_to_split_insn (old_insn, new_insn);
+    }
+
   /* We will be adding the new sequence to the function.  The splitters
      may have introduced invalid RTL sharing, so unshare the sequence now.  */
   unshare_all_rtl_in_chain (seq);
@@ -3940,6 +3893,7 @@ try_split (rtx pat, rtx_insn *trial, int last)
          break;
 
        case REG_NON_LOCAL_GOTO:
+       case REG_LABEL_TARGET:
          for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
            {
              if (JUMP_P (insn))
@@ -3965,6 +3919,7 @@ try_split (rtx pat, rtx_insn *trial, int last)
          break;
 
        case REG_CALL_DECL:
+       case REG_UNTYPED_CALL:
          gcc_assert (call_insn != NULL_RTX);
          add_reg_note (call_insn, REG_NOTE_KIND (note), XEXP (note, 0));
          break;
@@ -3992,7 +3947,7 @@ try_split (rtx pat, rtx_insn *trial, int last)
   before = PREV_INSN (trial);
   after = NEXT_INSN (trial);
 
-  tem = emit_insn_after_setloc (seq, trial, INSN_LOCATION (trial));
+  emit_insn_after_setloc (seq, trial, INSN_LOCATION (trial));
 
   delete_insn (trial);
 
@@ -4053,7 +4008,7 @@ make_debug_insn_raw (rtx pattern)
 
   insn = as_a <rtx_debug_insn *> (rtx_alloc (DEBUG_INSN));
   INSN_UID (insn) = cur_debug_insn_uid++;
-  if (cur_debug_insn_uid > MIN_NONDEBUG_INSN_UID)
+  if (cur_debug_insn_uid > param_min_nondebug_insn_uid)
     INSN_UID (insn) = cur_insn_uid++;
 
   PATTERN (insn) = pattern;
@@ -5687,13 +5642,11 @@ copy_insn_1 (rtx orig)
     case SYMBOL_REF:
     case CODE_LABEL:
     case PC:
-    case CC0:
     case RETURN:
     case SIMPLE_RETURN:
       return orig;
     case CLOBBER:
-    case CLOBBER_HIGH:
-      /* Share clobbers of hard registers (like cc0), but do not share pseudo reg
+      /* Share clobbers of hard registers, but do not share pseudo reg
          clobbers or clobbers of hard registers that originated as pseudos.
          This is needed to allow safe register renaming.  */
       if (REG_P (XEXP (orig, 0))
@@ -5829,8 +5782,8 @@ init_emit (void)
 {
   set_first_insn (NULL);
   set_last_insn (NULL);
-  if (MIN_NONDEBUG_INSN_UID)
-    cur_insn_uid = MIN_NONDEBUG_INSN_UID;
+  if (param_min_nondebug_insn_uid)
+    cur_insn_uid = param_min_nondebug_insn_uid;
   else
     cur_insn_uid = 1;
   cur_debug_insn_uid = 1;
@@ -5951,6 +5904,7 @@ bool
 valid_for_const_vector_p (machine_mode, rtx x)
 {
   return (CONST_SCALAR_INT_P (x)
+         || CONST_POLY_INT_P (x)
          || CONST_DOUBLE_AS_FLOAT_P (x)
          || CONST_FIXED_P (x));
 }
@@ -6413,7 +6367,6 @@ init_emit_once (void)
   pc_rtx = gen_rtx_fmt_ (PC, VOIDmode);
   ret_rtx = gen_rtx_fmt_ (RETURN, VOIDmode);
   simple_return_rtx = gen_rtx_fmt_ (SIMPLE_RETURN, VOIDmode);
-  cc0_rtx = gen_rtx_fmt_ (CC0, VOIDmode);
   invalid_insn_rtx = gen_rtx_INSN (VOIDmode,
                                   /*prev_insn=*/NULL,
                                   /*next_insn=*/NULL,
@@ -6504,21 +6457,6 @@ gen_hard_reg_clobber (machine_mode mode, unsigned int regno)
            gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (mode, regno)));
 }
 
-static GTY((deletable)) rtx
-hard_reg_clobbers_high[NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];
-
-/* Return a CLOBBER_HIGH expression for register REGNO that clobbers MODE,
-   caching into HARD_REG_CLOBBERS_HIGH.  */
-rtx
-gen_hard_reg_clobber_high (machine_mode mode, unsigned int regno)
-{
-  if (hard_reg_clobbers_high[mode][regno])
-    return hard_reg_clobbers_high[mode][regno];
-  else
-    return (hard_reg_clobbers_high[mode][regno]
-           = gen_rtx_CLOBBER_HIGH (VOIDmode, gen_rtx_REG (mode, regno)));
-}
-
 location_t prologue_location;
 location_t epilogue_location;
 
@@ -6557,6 +6495,18 @@ curr_insn_location (void)
   return curr_location;
 }
 
+/* Set the location of the insn chain starting at INSN to LOC.  */
+void
+set_insn_locations (rtx_insn *insn, location_t loc)
+{
+  while (insn)
+    {
+      if (INSN_P (insn))
+       INSN_LOCATION (insn) = loc;
+      insn = NEXT_INSN (insn);
+    }
+}
+
 /* Return lexical scope block insn belongs to.  */
 tree
 insn_scope (const rtx_insn *insn)