lra support for clobber_high
authorAlan Hayward <alan.hayward@arm.com>
Mon, 6 Aug 2018 09:51:01 +0000 (09:51 +0000)
committerAlan Hayward <alahay01@gcc.gnu.org>
Mon, 6 Aug 2018 09:51:01 +0000 (09:51 +0000)
gcc/
* lra-eliminations.c (lra_eliminate_regs_1): Check for clobber high.
(mark_not_eliminable): Likewise.
* lra-int.h (struct lra_insn_reg): Add clobber high marker.
* lra-lives.c (process_bb_lives): Check for clobber high.
* lra.c (new_insn_reg): Remember clobber highs.
(collect_non_operand_hard_regs): Check for clobber high.
(lra_set_insn_recog_data): Likewise.
(add_regs_to_insn_regno_info): Likewise.
(lra_update_insn_regno_info): Likewise.

From-SVN: r263329

gcc/ChangeLog
gcc/lra-eliminations.c
gcc/lra-int.h
gcc/lra-lives.c
gcc/lra.c

index 36f604d76fcae4bb0fc106107fb72e6d731c8bc4..8d9b158861d667bf917bd50361ce68ea09fbd5d0 100644 (file)
@@ -1,3 +1,15 @@
+2018-08-06  Alan Hayward  <alan.hayward@arm.com>
+
+       * lra-eliminations.c (lra_eliminate_regs_1): Check for clobber high.
+       (mark_not_eliminable): Likewise.
+       * lra-int.h (struct lra_insn_reg): Add clobber high marker.
+       * lra-lives.c (process_bb_lives): Check for clobber high.
+       * lra.c (new_insn_reg): Remember clobber highs.
+       (collect_non_operand_hard_regs): Check for clobber high.
+       (lra_set_insn_recog_data): Likewise.
+       (add_regs_to_insn_regno_info): Likewise.
+       (lra_update_insn_regno_info): Likewise.
+
 2018-08-06  Alan Hayward  <alan.hayward@arm.com>
 
        * rtl.h (reg_is_clobbered_by_clobber_high): Add declarations.
index f5f104020b34438da30509cd9d6413e02838a625..d0cfaa8714a8400a6db5da1ffef58b6225f743bd 100644 (file)
@@ -654,6 +654,7 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode,
       return x;
 
     case CLOBBER:
+    case CLOBBER_HIGH:
     case SET:
       gcc_unreachable ();
 
@@ -806,6 +807,16 @@ mark_not_eliminable (rtx x, machine_mode mem_mode)
            setup_can_eliminate (ep, false);
       return;
 
+    case CLOBBER_HIGH:
+      gcc_assert (REG_P (XEXP (x, 0)));
+      gcc_assert (REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER);
+      for (ep = reg_eliminate;
+          ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
+          ep++)
+       if (reg_is_clobbered_by_clobber_high (ep->to_rtx, XEXP (x, 0)))
+         setup_can_eliminate (ep, false);
+      return;
+
     case SET:
       if (SET_DEST (x) == stack_pointer_rtx
          && GET_CODE (SET_SRC (x)) == PLUS
index 86e103b748000e80890f8e070bd89213582fe705..5267b53c5e321526fb7eaae05f869dc0019e923f 100644 (file)
@@ -168,6 +168,8 @@ struct lra_insn_reg
   /* True if there is an early clobber alternative for this
      operand.  */
   unsigned int early_clobber : 1;
+  /* True if the reg is clobber highed by the operand.  */
+  unsigned int clobber_high : 1;
   /* The corresponding regno of the register.  */
   int regno;
   /* Next reg info of the same insn.  */
index 920fd02b997f8d6e6497e8f82f36406115bd424a..433c819d9e3fcdae0bd6b67aa64ddfc878acbbe9 100644 (file)
@@ -658,7 +658,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
       bool call_p;
       int n_alt, dst_regno, src_regno;
       rtx set;
-      struct lra_insn_reg *reg;
+      struct lra_insn_reg *reg, *hr;
 
       if (!NONDEBUG_INSN_P (curr_insn))
        continue;
@@ -690,11 +690,12 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
                break;
              }
          for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
-           if (reg->type != OP_IN)
+           if (reg->type != OP_IN && !reg->clobber_high)
              {
                remove_p = false;
                break;
              }
+
          if (remove_p && ! volatile_refs_p (PATTERN (curr_insn)))
            {
              dst_regno = REGNO (SET_DEST (set));
@@ -812,14 +813,24 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
         unused values because they still conflict with quantities
         that are live at the time of the definition.  */
       for (reg = curr_id->regs; reg != NULL; reg = reg->next)
-       if (reg->type != OP_IN)
-         {
-           need_curr_point_incr
-             |= mark_regno_live (reg->regno, reg->biggest_mode,
-                                 curr_point);
-           check_pseudos_live_through_calls (reg->regno,
-                                             last_call_used_reg_set);
-         }
+       {
+         if (reg->type != OP_IN)
+           {
+             need_curr_point_incr
+               |= mark_regno_live (reg->regno, reg->biggest_mode,
+                                   curr_point);
+             check_pseudos_live_through_calls (reg->regno,
+                                               last_call_used_reg_set);
+           }
+
+         if (reg->regno >= FIRST_PSEUDO_REGISTER)
+           for (hr = curr_static_id->hard_regs; hr != NULL; hr = hr->next)
+             if (hr->clobber_high
+                 && maybe_gt (GET_MODE_SIZE (PSEUDO_REGNO_MODE (reg->regno)),
+                              GET_MODE_SIZE (hr->biggest_mode)))
+               SET_HARD_REG_BIT (lra_reg_info[reg->regno].conflict_hard_regs,
+                                 hr->regno);
+       }
 
       for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
        if (reg->type != OP_IN)
index b410b90f126e50594b43de7e0f36804983785947..aa768fb2a23196625d5b284560902a345a7595ea 100644 (file)
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -535,13 +535,14 @@ object_allocator<lra_insn_reg> lra_insn_reg_pool ("insn regs");
    clobbered in the insn (EARLY_CLOBBER), and reference to the next
    insn reg info (NEXT).  If REGNO can be early clobbered,
    alternatives in which it can be early clobbered are given by
-   EARLY_CLOBBER_ALTS.  */
+   EARLY_CLOBBER_ALTS.  CLOBBER_HIGH marks if reference is a clobber
+   high.  */
 static struct lra_insn_reg *
 new_insn_reg (rtx_insn *insn, int regno, enum op_type type,
              machine_mode mode,
              bool subreg_p, bool early_clobber,
              alternative_mask early_clobber_alts,
-             struct lra_insn_reg *next)
+             struct lra_insn_reg *next, bool clobber_high)
 {
   lra_insn_reg *ir = lra_insn_reg_pool.allocate ();
   ir->type = type;
@@ -552,6 +553,7 @@ new_insn_reg (rtx_insn *insn, int regno, enum op_type type,
   ir->subreg_p = subreg_p;
   ir->early_clobber = early_clobber;
   ir->early_clobber_alts = early_clobber_alts;
+  ir->clobber_high = clobber_high;
   ir->regno = regno;
   ir->next = next;
   return ir;
@@ -821,12 +823,13 @@ setup_operand_alternative (lra_insn_recog_data_t data,
    not the insn operands, in X with TYPE (in/out/inout) and flag that
    it is early clobbered in the insn (EARLY_CLOBBER) and add the info
    to LIST.  X is a part of insn given by DATA.         Return the result
-   list.  */
+   list.  CLOBBER_HIGH marks if X is a clobber high.  */
 static struct lra_insn_reg *
 collect_non_operand_hard_regs (rtx_insn *insn, rtx *x,
                               lra_insn_recog_data_t data,
                               struct lra_insn_reg *list,
-                              enum op_type type, bool early_clobber)
+                              enum op_type type, bool early_clobber,
+                              bool clobber_high)
 {
   int i, j, regno, last;
   bool subreg_p;
@@ -890,7 +893,8 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x,
 #endif
              list = new_insn_reg (data->insn, regno, type, mode, subreg_p,
                                   early_clobber,
-                                  early_clobber ? ALL_ALTERNATIVES : 0, list);
+                                  early_clobber ? ALL_ALTERNATIVES : 0, list,
+                                  clobber_high);
            }
        }
       return list;
@@ -899,24 +903,31 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x,
     {
     case SET:
       list = collect_non_operand_hard_regs (insn, &SET_DEST (op), data,
-                                           list, OP_OUT, false);
+                                           list, OP_OUT, false, false);
       list = collect_non_operand_hard_regs (insn, &SET_SRC (op), data,
-                                           list, OP_IN, false);
+                                           list, OP_IN, false, false);
       break;
     case CLOBBER:
       /* We treat clobber of non-operand hard registers as early clobber.  */
       list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data,
-                                           list, OP_OUT, true);
+                                           list, OP_OUT, true, false);
+      break;
+    case CLOBBER_HIGH:
+      /* Clobber high should always span exactly one register.  */
+      gcc_assert (REG_NREGS (XEXP (op, 0)) == 1);
+      /* We treat clobber of non-operand hard registers as early clobber.  */
+      list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data,
+                                           list, OP_OUT, true, true);
       break;
     case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC:
       list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data,
-                                           list, OP_INOUT, false);
+                                           list, OP_INOUT, false, false);
       break;
     case PRE_MODIFY: case POST_MODIFY:
       list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data,
-                                           list, OP_INOUT, false);
+                                           list, OP_INOUT, false, false);
       list = collect_non_operand_hard_regs (insn, &XEXP (op, 1), data,
-                                           list, OP_IN, false);
+                                           list, OP_IN, false, false);
       break;
     default:
       fmt = GET_RTX_FORMAT (code);
@@ -924,11 +935,12 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x,
        {
          if (fmt[i] == 'e')
            list = collect_non_operand_hard_regs (insn, &XEXP (op, i), data,
-                                                 list, OP_IN, false);
+                                                 list, OP_IN, false, false);
          else if (fmt[i] == 'E')
            for (j = XVECLEN (op, i) - 1; j >= 0; j--)
              list = collect_non_operand_hard_regs (insn, &XVECEXP (op, i, j),
-                                                   data, list, OP_IN, false);
+                                                   data, list, OP_IN, false,
+                                                   false);
        }
     }
   return list;
@@ -1081,7 +1093,7 @@ lra_set_insn_recog_data (rtx_insn *insn)
   else
     insn_static_data->hard_regs
       = collect_non_operand_hard_regs (insn, &PATTERN (insn), data,
-                                      NULL, OP_IN, false);
+                                      NULL, OP_IN, false, false);
   data->arg_hard_regs = NULL;
   if (CALL_P (insn))
     {
@@ -1107,6 +1119,11 @@ lra_set_insn_recog_data (rtx_insn *insn)
              arg_hard_regs[n_hard_regs++]
                = regno + i + (use_p ? 0 : FIRST_PSEUDO_REGISTER);
          }
+       else if (GET_CODE (XEXP (link, 0)) == CLOBBER_HIGH)
+         /* We could support CLOBBER_HIGH and treat it in the same way as
+            HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet.  */
+         gcc_unreachable ();
+
       if (n_hard_regs != 0)
        {
          arg_hard_regs[n_hard_regs++] = -1;
@@ -1469,7 +1486,7 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x,
        {
          data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p,
                                     early_clobber, early_clobber_alts,
-                                    data->regs);
+                                    data->regs, false);
          return;
        }
       else
@@ -1482,7 +1499,8 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x,
                     structure.  */
                  data->regs = new_insn_reg (data->insn, regno, type, mode,
                                             subreg_p, early_clobber,
-                                            early_clobber_alts, data->regs);
+                                            early_clobber_alts, data->regs,
+                                            false);
                else
                  {
                    if (curr->type != type)
@@ -1509,6 +1527,8 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x,
       add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_OUT,
                                   true, ALL_ALTERNATIVES);
       break;
+    case CLOBBER_HIGH:
+      gcc_unreachable ();
     case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC:
       add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_INOUT, false, 0);
       break;
@@ -1643,10 +1663,16 @@ lra_update_insn_regno_info (rtx_insn *insn)
     for (link = CALL_INSN_FUNCTION_USAGE (insn);
         link != NULL_RTX;
         link = XEXP (link, 1))
-      if (((code = GET_CODE (XEXP (link, 0))) == USE || code == CLOBBER)
-         && MEM_P (XEXP (XEXP (link, 0), 0)))
-       add_regs_to_insn_regno_info (data, XEXP (XEXP (link, 0), 0), insn,
-                                    code == USE ? OP_IN : OP_OUT, false, 0);
+      {
+       code = GET_CODE (XEXP (link, 0));
+       /* We could support CLOBBER_HIGH and treat it in the same way as
+          HARD_REGNO_CALL_PART_CLOBBERED, but no port needs that yet.  */
+       gcc_assert (code != CLOBBER_HIGH);
+       if ((code == USE || code == CLOBBER)
+           && MEM_P (XEXP (XEXP (link, 0), 0)))
+         add_regs_to_insn_regno_info (data, XEXP (XEXP (link, 0), 0), insn,
+                                      code == USE ? OP_IN : OP_OUT, false, 0);
+      }
   if (NONDEBUG_INSN_P (insn))
     setup_insn_reg_info (data, freq);
 }