]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/lower-subreg.c
rs6000: New iterator CCEITHER
[thirdparty/gcc.git] / gcc / lower-subreg.c
index e93dbd66e1f0b6c4aaf237671b20b679f46cbd9d..4f68a7381b750fe160bb5436b2601d4ec572cc7c 100644 (file)
@@ -1,5 +1,5 @@
 /* Decompose multiword subregs.
-   Copyright (C) 2007-2017 Free Software Foundation, Inc.
+   Copyright (C) 2007-2019 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>
                  Ian Lance Taylor <iant@google.com>
 
@@ -79,7 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 static bitmap decomposable_context;
 
 /* Bit N in this bitmap is set if regno N is used in a context in
-   which it can not be decomposed.  */
+   which it cannot be decomposed.  */
 static bitmap non_decomposable_context;
 
 /* Bit N in this bitmap is set if regno N is used in a subreg
@@ -103,6 +103,19 @@ struct target_lower_subreg *this_target_lower_subreg
 #define choices \
   this_target_lower_subreg->x_choices
 
+/* Return true if MODE is a mode we know how to lower.  When returning true,
+   store its byte size in *BYTES and its word size in *WORDS.  */
+
+static inline bool
+interesting_mode_p (machine_mode mode, unsigned int *bytes,
+                   unsigned int *words)
+{
+  if (!GET_MODE_SIZE (mode).is_constant (bytes))
+    return false;
+  *words = CEIL (*bytes, UNITS_PER_WORD);
+  return true;
+}
+
 /* RTXes used while computing costs.  */
 struct cost_rtxes {
   /* Source and target registers.  */
@@ -129,7 +142,7 @@ shift_cost (bool speed_p, struct cost_rtxes *rtxes, enum rtx_code code,
   PUT_CODE (rtxes->shift, code);
   PUT_MODE (rtxes->shift, mode);
   PUT_MODE (rtxes->source, mode);
-  XEXP (rtxes->shift, 1) = GEN_INT (op1);
+  XEXP (rtxes->shift, 1) = gen_int_shift_amount (mode, op1);
   return set_src_cost (rtxes->shift, mode, speed_p);
 }
 
@@ -199,10 +212,10 @@ compute_costs (bool speed_p, struct cost_rtxes *rtxes)
   for (i = 0; i < MAX_MACHINE_MODE; i++)
     {
       machine_mode mode = (machine_mode) i;
-      int factor = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
-      if (factor > 1)
+      unsigned int size, factor;
+      if (interesting_mode_p (mode, &size, &factor) && factor > 1)
        {
-         int mode_move_cost;
+         unsigned int mode_move_cost;
 
          PUT_MODE (rtxes->target, mode);
          PUT_MODE (rtxes->source, mode);
@@ -307,6 +320,24 @@ simple_move_operand (rtx x)
   return true;
 }
 
+/* If X is an operator that can be treated as a simple move that we
+   can split, then return the operand that is operated on.  */
+
+static rtx
+operand_for_swap_move_operator (rtx x)
+{
+  /* A word sized rotate of a register pair is equivalent to swapping
+     the registers in the register pair.  */
+  if (GET_CODE (x) == ROTATE
+      && GET_MODE (x) == twice_word_mode
+      && simple_move_operand (XEXP (x, 0))
+      && CONST_INT_P (XEXP (x, 1))
+      && INTVAL (XEXP (x, 1)) == BITS_PER_WORD)
+    return XEXP (x, 0);
+
+  return NULL_RTX;
+}
+
 /* If INSN is a single set between two objects that we want to split,
    return the single set.  SPEED_P says whether we are optimizing
    INSN for speed or size.
@@ -317,7 +348,7 @@ simple_move_operand (rtx x)
 static rtx
 simple_move (rtx_insn *insn, bool speed_p)
 {
-  rtx x;
+  rtx x, op;
   rtx set;
   machine_mode mode;
 
@@ -335,6 +366,9 @@ simple_move (rtx_insn *insn, bool speed_p)
     return NULL_RTX;
 
   x = SET_SRC (set);
+  if ((op = operand_for_swap_move_operator (x)) != NULL_RTX)
+    x = op;
+
   if (x != recog_data.operand[0] && x != recog_data.operand[1])
     return NULL_RTX;
   /* For the src we can handle ASM_OPERANDS, and it is beneficial for
@@ -373,9 +407,13 @@ find_pseudo_copy (rtx set)
 {
   rtx dest = SET_DEST (set);
   rtx src = SET_SRC (set);
+  rtx op;
   unsigned int rd, rs;
   bitmap b;
 
+  if ((op = operand_for_swap_move_operator (src)) != NULL_RTX)
+    src = op;
+
   if (!REG_P (dest) || !REG_P (src))
     return false;
 
@@ -469,10 +507,10 @@ find_decomposable_subregs (rtx *loc, enum classify_move_insn *pcmi)
              continue;
            }
 
-         outer_size = GET_MODE_SIZE (GET_MODE (x));
-         inner_size = GET_MODE_SIZE (GET_MODE (inner));
-         outer_words = (outer_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
-         inner_words = (inner_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+         if (!interesting_mode_p (GET_MODE (x), &outer_size, &outer_words)
+             || !interesting_mode_p (GET_MODE (inner), &inner_size,
+                                     &inner_words))
+           continue;
 
          /* We only try to decompose single word subregs of multi-word
             registers.  When we find one, we return -1 to avoid iterating
@@ -484,7 +522,16 @@ find_decomposable_subregs (rtx *loc, enum classify_move_insn *pcmi)
             were the same number and size of pieces.  Hopefully this
             doesn't happen much.  */
 
-         if (outer_words == 1 && inner_words > 1)
+         if (outer_words == 1
+             && inner_words > 1
+             /* Don't allow to decompose floating point subregs of
+                multi-word pseudos if the floating point mode does
+                not have word size, because otherwise we'd generate
+                a subreg with that floating mode from a different
+                sized integral pseudo which is not allowed by
+                validate_subreg.  */
+             && (!FLOAT_MODE_P (GET_MODE (x))
+                 || outer_size == UNITS_PER_WORD))
            {
              bitmap_set_bit (decomposable_context, regno);
              iter.skip_subrtxes ();
@@ -507,14 +554,14 @@ find_decomposable_subregs (rtx *loc, enum classify_move_insn *pcmi)
        }
       else if (REG_P (x))
        {
-         unsigned int regno;
+         unsigned int regno, size, words;
 
          /* We will see an outer SUBREG before we see the inner REG, so
             when we see a plain REG here it means a direct reference to
             the register.
 
             If this is not a simple copy from one location to another,
-            then we can not decompose this register.  If this is a simple
+            then we cannot decompose this register.  If this is a simple
             copy we want to decompose, and the mode is right,
             then we mark the register as decomposable.
             Otherwise we don't say anything about this register --
@@ -527,7 +574,8 @@ find_decomposable_subregs (rtx *loc, enum classify_move_insn *pcmi)
 
          regno = REGNO (x);
          if (!HARD_REGISTER_NUM_P (regno)
-             && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
+             && interesting_mode_p (GET_MODE (x), &size, &words)
+             && words > 1)
            {
              switch (*pcmi)
                {
@@ -567,15 +615,15 @@ static void
 decompose_register (unsigned int regno)
 {
   rtx reg;
-  unsigned int words, i;
+  unsigned int size, words, i;
   rtvec v;
 
   reg = regno_reg_rtx[regno];
 
   regno_reg_rtx[regno] = NULL_RTX;
 
-  words = GET_MODE_SIZE (GET_MODE (reg));
-  words = (words + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+  if (!interesting_mode_p (GET_MODE (reg), &size, &words))
+    gcc_unreachable ();
 
   v = rtvec_alloc (words);
   for (i = 0; i < words; ++i)
@@ -596,40 +644,44 @@ decompose_register (unsigned int regno)
 /* Get a SUBREG of a CONCATN.  */
 
 static rtx
-simplify_subreg_concatn (machine_mode outermode, rtx op,
-                        unsigned int byte)
+simplify_subreg_concatn (machine_mode outermode, rtx op, poly_uint64 orig_byte)
 {
-  unsigned int inner_size;
+  unsigned int outer_size, outer_words, inner_size, inner_words;
   machine_mode innermode, partmode;
   rtx part;
   unsigned int final_offset;
+  unsigned int byte;
+
+  innermode = GET_MODE (op);
+  if (!interesting_mode_p (outermode, &outer_size, &outer_words)
+      || !interesting_mode_p (innermode, &inner_size, &inner_words))
+    gcc_unreachable ();
 
+  /* Must be constant if interesting_mode_p passes.  */
+  byte = orig_byte.to_constant ();
   gcc_assert (GET_CODE (op) == CONCATN);
-  gcc_assert (byte % GET_MODE_SIZE (outermode) == 0);
+  gcc_assert (byte % outer_size == 0);
 
-  innermode = GET_MODE (op);
-  gcc_assert (byte < GET_MODE_SIZE (innermode));
-  if (GET_MODE_SIZE (outermode) > GET_MODE_SIZE (innermode))
+  gcc_assert (byte < inner_size);
+  if (outer_size > inner_size)
     return NULL_RTX;
 
-  inner_size = GET_MODE_SIZE (innermode) / XVECLEN (op, 0);
+  inner_size /= XVECLEN (op, 0);
   part = XVECEXP (op, 0, byte / inner_size);
   partmode = GET_MODE (part);
 
+  final_offset = byte % inner_size;
+  if (final_offset + outer_size > inner_size)
+    return NULL_RTX;
+
   /* VECTOR_CSTs in debug expressions are expanded into CONCATN instead of
      regular CONST_VECTORs.  They have vector or integer modes, depending
      on the capabilities of the target.  Cope with them.  */
   if (partmode == VOIDmode && VECTOR_MODE_P (innermode))
     partmode = GET_MODE_INNER (innermode);
   else if (partmode == VOIDmode)
-    {
-      enum mode_class mclass = GET_MODE_CLASS (innermode);
-      partmode = mode_for_size (inner_size * BITS_PER_UNIT, mclass, 0);
-    }
-
-  final_offset = byte % inner_size;
-  if (final_offset + GET_MODE_SIZE (outermode) > inner_size)
-    return NULL_RTX;
+    partmode = mode_for_size (inner_size * BITS_PER_UNIT,
+                             GET_MODE_CLASS (innermode), 0).require ();
 
   return simplify_gen_subreg (outermode, part, partmode, final_offset);
 }
@@ -650,9 +702,9 @@ simplify_gen_subreg_concatn (machine_mode outermode, rtx op,
     {
       rtx op2;
 
-      if ((GET_MODE_SIZE (GET_MODE (op))
-          == GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
-         && SUBREG_BYTE (op) == 0)
+      if (known_eq (GET_MODE_SIZE (GET_MODE (op)),
+                   GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
+         && known_eq (SUBREG_BYTE (op), 0))
        return simplify_gen_subreg_concatn (outermode, SUBREG_REG (op),
                                            GET_MODE (SUBREG_REG (op)), byte);
 
@@ -803,9 +855,10 @@ can_decompose_p (rtx x)
 
       if (HARD_REGISTER_NUM_P (regno))
        {
-         unsigned int byte, num_bytes;
+         unsigned int byte, num_bytes, num_words;
 
-         num_bytes = GET_MODE_SIZE (GET_MODE (x));
+         if (!interesting_mode_p (GET_MODE (x), &num_bytes, &num_words))
+           return false;
          for (byte = 0; byte < num_bytes; byte += UNITS_PER_WORD)
            if (simplify_subreg_regno (regno, GET_MODE (x), byte, word_mode) < 0)
              return false;
@@ -818,6 +871,21 @@ can_decompose_p (rtx x)
   return true;
 }
 
+/* OPND is a concatn operand this is used with a simple move operator.
+   Return a new rtx with the concatn's operands swapped.  */
+
+static rtx
+resolve_operand_for_swap_move_operator (rtx opnd)
+{
+  gcc_assert (GET_CODE (opnd) == CONCATN);
+  rtx concatn = copy_rtx (opnd);
+  rtx op0 = XVECEXP (concatn, 0, 0);
+  rtx op1 = XVECEXP (concatn, 0, 1);
+  XVECEXP (concatn, 0, 0) = op1;
+  XVECEXP (concatn, 0, 1) = op0;
+  return concatn;
+}
+
 /* Decompose the registers used in a simple move SET within INSN.  If
    we don't change anything, return INSN, otherwise return the start
    of the sequence of moves.  */
@@ -825,17 +893,18 @@ can_decompose_p (rtx x)
 static rtx_insn *
 resolve_simple_move (rtx set, rtx_insn *insn)
 {
-  rtx src, dest, real_dest;
+  rtx src, dest, real_dest, src_op;
   rtx_insn *insns;
   machine_mode orig_mode, dest_mode;
-  unsigned int words;
+  unsigned int orig_size, words;
   bool pushing;
 
   src = SET_SRC (set);
   dest = SET_DEST (set);
   orig_mode = GET_MODE (dest);
 
-  words = (GET_MODE_SIZE (orig_mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+  if (!interesting_mode_p (orig_mode, &orig_size, &words))
+    gcc_unreachable ();
   gcc_assert (words > 1);
 
   start_sequence ();
@@ -847,11 +916,27 @@ resolve_simple_move (rtx set, rtx_insn *insn)
 
   real_dest = NULL_RTX;
 
+  if ((src_op = operand_for_swap_move_operator (src)) != NULL_RTX)
+    {
+      if (resolve_reg_p (dest))
+       {
+         /* DEST is a CONCATN, so swap its operands and strip
+            SRC's operator.  */
+         dest = resolve_operand_for_swap_move_operator (dest);
+         src = src_op;
+       }
+      else if (resolve_reg_p (src_op))
+       {
+         /* SRC is an operation on a CONCATN, so strip the operator and
+            swap the CONCATN's operands.  */
+         src = resolve_operand_for_swap_move_operator (src_op);
+       }
+    }
+
   if (GET_CODE (src) == SUBREG
       && resolve_reg_p (SUBREG_REG (src))
-      && (SUBREG_BYTE (src) != 0
-         || (GET_MODE_SIZE (orig_mode)
-             != GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))))
+      && (maybe_ne (SUBREG_BYTE (src), 0)
+         || maybe_ne (orig_size, GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))))
     {
       real_dest = dest;
       dest = gen_reg_rtx (orig_mode);
@@ -864,9 +949,9 @@ resolve_simple_move (rtx set, rtx_insn *insn)
 
   if (GET_CODE (dest) == SUBREG
       && resolve_reg_p (SUBREG_REG (dest))
-      && (SUBREG_BYTE (dest) != 0
-         || (GET_MODE_SIZE (orig_mode)
-             != GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))))
+      && (maybe_ne (SUBREG_BYTE (dest), 0)
+         || maybe_ne (orig_size,
+                      GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))))
     {
       rtx reg, smove;
       rtx_insn *minsn;
@@ -897,7 +982,7 @@ resolve_simple_move (rtx set, rtx_insn *insn)
   /* It's possible for the code to use a subreg of a decomposed
      register while forming an address.  We need to handle that before
      passing the address to emit_move_insn.  We pass NULL_RTX as the
-     insn parameter to resolve_subreg_use because we can not validate
+     insn parameter to resolve_subreg_use because we cannot validate
      the insn yet.  */
   if (MEM_P (src) || MEM_P (dest))
     {
@@ -956,11 +1041,7 @@ resolve_simple_move (rtx set, rtx_insn *insn)
       if (real_dest == NULL_RTX)
        real_dest = dest;
       if (!SCALAR_INT_MODE_P (dest_mode))
-       {
-         dest_mode = mode_for_size (GET_MODE_SIZE (dest_mode) * BITS_PER_UNIT,
-                                    MODE_INT, 0);
-         gcc_assert (dest_mode != BLKmode);
-       }
+       dest_mode = int_mode_for_mode (dest_mode).require ();
       dest = gen_reg_rtx (dest_mode);
       if (REG_P (real_dest))
        REG_ATTRS (dest) = REG_ATTRS (real_dest);
@@ -970,7 +1051,7 @@ resolve_simple_move (rtx set, rtx_insn *insn)
     {
       unsigned int i, j, jinc;
 
-      gcc_assert (GET_MODE_SIZE (orig_mode) % UNITS_PER_WORD == 0);
+      gcc_assert (orig_size % UNITS_PER_WORD == 0);
       gcc_assert (GET_CODE (XEXP (dest, 0)) != PRE_MODIFY);
       gcc_assert (GET_CODE (XEXP (dest, 0)) != POST_MODIFY);
 
@@ -1065,7 +1146,7 @@ resolve_clobber (rtx pat, rtx_insn *insn)
 {
   rtx reg;
   machine_mode orig_mode;
-  unsigned int words, i;
+  unsigned int orig_size, words, i;
   int ret;
 
   reg = XEXP (pat, 0);
@@ -1073,8 +1154,8 @@ resolve_clobber (rtx pat, rtx_insn *insn)
     return false;
 
   orig_mode = GET_MODE (reg);
-  words = GET_MODE_SIZE (orig_mode);
-  words = (words + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+  if (!interesting_mode_p (orig_mode, &orig_size, &words))
+    gcc_unreachable ();
 
   ret = validate_change (NULL_RTX, &XEXP (pat, 0),
                         simplify_gen_subreg_concatn (word_mode, reg,
@@ -1338,12 +1419,13 @@ dump_shift_choices (enum rtx_code code, bool *splitting)
 static void
 dump_choices (bool speed_p, const char *description)
 {
-  unsigned int i;
+  unsigned int size, factor, i;
 
   fprintf (dump_file, "Choices when optimizing for %s:\n", description);
 
   for (i = 0; i < MAX_MACHINE_MODE; i++)
-    if (GET_MODE_SIZE ((machine_mode) i) > UNITS_PER_WORD)
+    if (interesting_mode_p ((machine_mode) i, &size, &factor)
+       && factor > 1)
       fprintf (dump_file, "  %s mode %s for copy lowering.\n",
               choices[speed_p].move_modes_to_split[i]
               ? "Splitting"