diff mbox series

[4/7] : lra support for clobber_high

Message ID 143B2962-4720-42FC-9176-17786E5C0524@arm.com
State New
Headers show
Series [1/7] : SVE: Add CLOBBER_HIGH expression | expand

Commit Message

Alan Hayward Nov. 16, 2017, 12:35 p.m. UTC
This patch simply adds the lra specific changes for clobber_high.

Alan.


2017-11-16  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.
diff mbox series

Patch

diff --git a/gcc/lra-eliminations.c b/gcc/lra-eliminations.c
index bea8b023b7cb7a512f7482a2f014647c30462870..251e539530456722e3f4231b928c2124f9d602b6 100644
--- a/gcc/lra-eliminations.c
+++ b/gcc/lra-eliminations.c
@@ -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
diff --git a/gcc/lra-int.h b/gcc/lra-int.h
index 6c219eacee3940054ed480a44cda1ed07993ad16..be439b95e9cedb358e9ba6c63f8a9490af5c816d 100644
--- a/gcc/lra-int.h
+++ b/gcc/lra-int.h
@@ -166,6 +166,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.  */
diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c
index df7e2537dd09a4abd5ce517f4bb556cc32000fa0..82a1811f837b425a326753c0d956149382d752cb 100644
--- a/gcc/lra-lives.c
+++ b/gcc/lra-lives.c
@@ -655,7 +655,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;
@@ -687,11 +687,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));
@@ -809,14 +810,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
+		  && may_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)
diff --git a/gcc/lra.c b/gcc/lra.c
index 8d44c75b0b4f89ff9fe94d0b8dfb2e77d43fee26..d6775d629655700484760ab85f78b9fd16189ca0 100644
--- 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;
@@ -805,11 +807,12 @@  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 *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;
@@ -873,7 +876,8 @@  collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
 #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;
@@ -882,25 +886,32 @@  collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
     {
     case SET:
       list = collect_non_operand_hard_regs (&SET_DEST (op), data,
-					    list, OP_OUT, false);
+					    list, OP_OUT, false, false);
       list = collect_non_operand_hard_regs (&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 (the behavior is expected from asm).  */
       list = collect_non_operand_hard_regs (&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 (&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 (&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 (&XEXP (op, 0), data,
-					    list, OP_INOUT, false);
+					    list, OP_INOUT, false, false);
       list = collect_non_operand_hard_regs (&XEXP (op, 1), data,
-					    list, OP_IN, false);
+					    list, OP_IN, false, false);
       break;
     default:
       fmt = GET_RTX_FORMAT (code);
@@ -908,11 +919,11 @@  collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
 	{
 	  if (fmt[i] == 'e')
 	    list = collect_non_operand_hard_regs (&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 (&XVECEXP (op, i, j), data,
-						    list, OP_IN, false);
+						    list, OP_IN, false, false);
 	}
     }
   return list;
@@ -1056,7 +1067,7 @@  lra_set_insn_recog_data (rtx_insn *insn)
   else
     insn_static_data->hard_regs
       = collect_non_operand_hard_regs (&PATTERN (insn), data,
-				       NULL, OP_IN, false);
+				       NULL, OP_IN, false, false);
   data->arg_hard_regs = NULL;
   if (CALL_P (insn))
     {
@@ -1082,6 +1093,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;
@@ -1440,7 +1456,7 @@  add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
 	{
 	  data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p,
 				     early_clobber, early_clobber_alts,
-				     data->regs);
+				     data->regs, false);
 	  return;
 	}
       else
@@ -1453,7 +1469,8 @@  add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
 		     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)
@@ -1479,6 +1496,8 @@  add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
 	 clobber (the behavior is expected from asm).  */
       add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, 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), uid, OP_INOUT, false, 0);
       break;
@@ -1614,10 +1633,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)
+      {
+	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), uid,
-				     code == USE ? OP_IN : OP_OUT, false, 0);
+	  add_regs_to_insn_regno_info (data, XEXP (XEXP (link, 0), 0), uid,
+				       code == USE ? OP_IN : OP_OUT, false, 0);
+      }
   if (NONDEBUG_INSN_P (insn))
     setup_insn_reg_info (data, freq);
 }