diff mbox

patch to fix PR79282

Message ID 0f3b3264-771e-549b-c811-9fca0578b3d7@redhat.com
State New
Headers show

Commit Message

Vladimir Makarov Feb. 14, 2017, 10:17 p.m. UTC
The following patch fixes

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79282

   The patch was bootstrapped and tested on x86-64 and tested on ARM.

   Committed as rev. 245459
diff mbox

Patch

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 245458)
+++ ChangeLog	(working copy)
@@ -1,3 +1,19 @@ 
+2017-02-14  Vladimir Makarov  <vmakarov@redhat.com>
+
+	PR target/79282
+	* lra-int.h (struct lra_operand_data, struct lra_insn_reg): Add
+	member early_clobber_alts.
+	* lra-lives.c (reg_early_clobber_p): New.
+	(process_bb_lives): Use it.
+	* lra.c (new_insn_reg): New arg early_clobber_alts.  Use it.
+	(debug_operand_data): Initialize early_clobber_alts.
+	(setup_operand_alternative): Set up early_clobber_alts.
+	(collect_non_operand_hard_regs): Ditto.  Pass early clobber
+	alternatives to new_insn_reg.
+	(add_regs_to_insn_regno_info): Add arg early_clobber_alts.  Use
+	it.
+	(lra_update_insn_regno_info): Pass the new arg.
+
 2017-02-14  Jakub Jelinek  <jakub@redhat.com>
 
 	PR middle-end/79505
Index: lra-int.h
===================================================================
--- lra-int.h	(revision 245338)
+++ lra-int.h	(working copy)
@@ -130,6 +130,8 @@  struct lra_operand_data
 {
   /* The machine description constraint string of the operand.	*/
   const char *constraint;
+  /* Alternatives for which early_clobber can be true.  */
+  alternative_mask early_clobber_alts;
   /* It is taken only from machine description (which is different
      from recog_data.operand_mode) and can be of VOIDmode.  */
   ENUM_BITFIELD(machine_mode) mode : 16;
@@ -150,6 +152,8 @@  struct lra_operand_data
 /* Info about register occurrence in an insn.  */
 struct lra_insn_reg
 {
+  /* Alternatives for which early_clobber can be true.  */
+  alternative_mask early_clobber_alts;
   /* The biggest mode through which the insn refers to the register
      occurrence (remember the register can be accessed through a
      subreg in the insn).  */
Index: lra-lives.c
===================================================================
--- lra-lives.c	(revision 245338)
+++ lra-lives.c	(working copy)
@@ -586,6 +586,16 @@  check_pseudos_live_through_calls (int re
   SET_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs);
 }
 
+/* Return true if insn REG is an early clobber operand in alternative
+   NALT.  Negative NALT means that we don't know the current insn
+   alternative.  So assume the worst.  */
+static inline bool
+reg_early_clobber_p (const struct lra_insn_reg *reg, int n_alt)
+{
+  return (reg->early_clobber
+	  && (n_alt < 0 || TEST_BIT (reg->early_clobber_alts, n_alt)));
+}
+
 /* Process insns of the basic block BB to update pseudo live ranges,
    pseudo hard register conflicts, and insn notes.  We do it on
    backward scan of BB insns.  CURR_POINT is the program point where
@@ -638,7 +648,7 @@  process_bb_lives (basic_block bb, int &c
   FOR_BB_INSNS_REVERSE_SAFE (bb, curr_insn, next)
     {
       bool call_p;
-      int dst_regno, src_regno;
+      int n_alt, dst_regno, src_regno;
       rtx set;
       struct lra_insn_reg *reg;
 
@@ -647,9 +657,10 @@  process_bb_lives (basic_block bb, int &c
 
       curr_id = lra_get_insn_recog_data (curr_insn);
       curr_static_id = curr_id->insn_static_data;
+      n_alt = curr_id->used_insn_alternative;
       if (lra_dump_file != NULL)
-	fprintf (lra_dump_file, "   Insn %u: point = %d\n",
-		 INSN_UID (curr_insn), curr_point);
+	fprintf (lra_dump_file, "   Insn %u: point = %d, n_alt = %d\n",
+		 INSN_UID (curr_insn), curr_point, n_alt);
 
       set = single_set (curr_insn);
 
@@ -818,13 +829,15 @@  process_bb_lives (basic_block bb, int &c
 
       /* See which defined values die here.  */
       for (reg = curr_id->regs; reg != NULL; reg = reg->next)
-	if (reg->type == OP_OUT && ! reg->early_clobber && ! reg->subreg_p)
+	if (reg->type == OP_OUT
+	    && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
 	  need_curr_point_incr
 	    |= mark_regno_dead (reg->regno, reg->biggest_mode,
 				curr_point);
 
       for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
-	if (reg->type == OP_OUT && ! reg->early_clobber && ! reg->subreg_p)
+	if (reg->type == OP_OUT
+	    && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
 	  make_hard_regno_dead (reg->regno);
 
       if (curr_id->arg_hard_regs != NULL)
@@ -901,13 +914,15 @@  process_bb_lives (basic_block bb, int &c
 
       /* Mark early clobber outputs dead.  */
       for (reg = curr_id->regs; reg != NULL; reg = reg->next)
-	if (reg->type == OP_OUT && reg->early_clobber && ! reg->subreg_p)
+	if (reg->type == OP_OUT
+	    && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
 	  need_curr_point_incr
 	    |= mark_regno_dead (reg->regno, reg->biggest_mode,
 				curr_point);
 
       for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
-	if (reg->type == OP_OUT && reg->early_clobber && ! reg->subreg_p)
+	if (reg->type == OP_OUT
+	    && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
 	  make_hard_regno_dead (reg->regno);
 
       if (need_curr_point_incr)
Index: lra.c
===================================================================
--- lra.c	(revision 245338)
+++ lra.c	(working copy)
@@ -529,15 +529,19 @@  lra_update_dups (lra_insn_recog_data_t i
 /* Pools for insn reg info.  */
 object_allocator<lra_insn_reg> lra_insn_reg_pool ("insn regs");
 
-/* Create LRA insn related info about a reference to REGNO in INSN with
-   TYPE (in/out/inout), biggest reference mode MODE, flag that it is
-   reference through subreg (SUBREG_P), flag that is early clobbered
-   in the insn (EARLY_CLOBBER), and reference to the next insn reg
-   info (NEXT).	 */
+/* Create LRA insn related info about a reference to REGNO in INSN
+   with TYPE (in/out/inout), biggest reference mode MODE, flag that it
+   is reference through subreg (SUBREG_P), flag that is early
+   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.  */
 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, struct lra_insn_reg *next)
+	      bool subreg_p, bool early_clobber,
+	      alternative_mask early_clobber_alts,
+	      struct lra_insn_reg *next)
 {
   lra_insn_reg *ir = lra_insn_reg_pool.allocate ();
   ir->type = type;
@@ -547,6 +551,7 @@  new_insn_reg (rtx_insn *insn, int regno,
     lra_reg_info[regno].biggest_mode = mode;
   ir->subreg_p = subreg_p;
   ir->early_clobber = early_clobber;
+  ir->early_clobber_alts = early_clobber_alts;
   ir->regno = regno;
   ir->next = next;
   return ir;
@@ -590,6 +595,7 @@  struct lra_static_insn_data *insn_code_d
 static struct lra_operand_data debug_operand_data =
   {
     NULL, /* alternative  */
+    0, /* early_clobber_alts */
     VOIDmode, /* We are not interesting in the operand mode.  */
     OP_IN,
     0, 0, 0, 0
@@ -771,6 +777,7 @@  setup_operand_alternative (lra_insn_reco
   static_data->operand_alternative = op_alt;
   for (i = 0; i < nop; i++)
     {
+      static_data->operand[i].early_clobber_alts = 0;
       static_data->operand[i].early_clobber = false;
       static_data->operand[i].is_address = false;
       if (static_data->operand[i].constraint[0] == '%')
@@ -788,6 +795,8 @@  setup_operand_alternative (lra_insn_reco
     for (i = 0; i < nop; i++, op_alt++)
       {
 	static_data->operand[i].early_clobber |= op_alt->earlyclobber;
+	if (op_alt->earlyclobber)
+	  static_data->operand[i].early_clobber_alts |= (alternative_mask) 1 << j;
 	static_data->operand[i].is_address |= op_alt->is_address;
       }
 }
@@ -847,8 +856,11 @@  collect_non_operand_hard_regs (rtx *x, l
 	      {
 		if (curr->type != type)
 		  curr->type = OP_INOUT;
-		if (curr->early_clobber != early_clobber)
-		  curr->early_clobber = true;
+		if (early_clobber)
+		  {
+		    curr->early_clobber = true;
+		    curr->early_clobber_alts = ALL_ALTERNATIVES;
+		  }
 		break;
 	      }
 	  if (curr == NULL)
@@ -864,7 +876,8 @@  collect_non_operand_hard_regs (rtx *x, l
 			 && regno <= LAST_STACK_REG));
 #endif
 	      list = new_insn_reg (data->insn, regno, type, mode, subreg_p,
-				   early_clobber, list);
+				   early_clobber,
+				   early_clobber ? ALL_ALTERNATIVES : 0, list);
 	    }
 	}
       return list;
@@ -1395,10 +1408,13 @@  lra_get_copy (int n)
 
 /* Process X of insn UID recursively and add info (operand type is
    given by TYPE, flag of that it is early clobber is EARLY_CLOBBER)
-   about registers in X to the insn DATA.  */
+   about registers in X to the insn DATA.  If X can be early clobbered,
+   alternatives in which it can be early clobbered are given by
+   EARLY_CLOBBER_ALTS.  */
 static void
 add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
-			     enum op_type type, bool early_clobber)
+			     enum op_type type, bool early_clobber,
+			     alternative_mask early_clobber_alts)
 {
   int i, j, regno;
   bool subreg_p;
@@ -1430,7 +1446,8 @@  add_regs_to_insn_regno_info (lra_insn_re
       if (bitmap_set_bit (&lra_reg_info[regno].insn_bitmap, uid))
 	{
 	  data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p,
-				     early_clobber, data->regs);
+				     early_clobber, early_clobber_alts,
+				     data->regs);
 	  return;
 	}
       else
@@ -1443,13 +1460,14 @@  add_regs_to_insn_regno_info (lra_insn_re
 		     structure.  */
 		  data->regs = new_insn_reg (data->insn, regno, type, mode,
 					     subreg_p, early_clobber,
-					     data->regs);
+					     early_clobber_alts, data->regs);
 		else
 		  {
 		    if (curr->type != type)
 		      curr->type = OP_INOUT;
 		    if (curr->early_clobber != early_clobber)
 		      curr->early_clobber = true;
+		    curr->early_clobber_alts |= early_clobber_alts;
 		  }
 		return;
 	      }
@@ -1460,20 +1478,20 @@  add_regs_to_insn_regno_info (lra_insn_re
   switch (code)
     {
     case SET:
-      add_regs_to_insn_regno_info (data, SET_DEST (x), uid, OP_OUT, false);
-      add_regs_to_insn_regno_info (data, SET_SRC (x), uid, OP_IN, false);
+      add_regs_to_insn_regno_info (data, SET_DEST (x), uid, OP_OUT, false, 0);
+      add_regs_to_insn_regno_info (data, SET_SRC (x), uid, OP_IN, false, 0);
       break;
     case CLOBBER:
       /* We treat clobber of non-operand hard registers as early
 	 clobber (the behavior is expected from asm).  */
-      add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_OUT, true);
+      add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_OUT, true, ALL_ALTERNATIVES);
       break;
     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);
+      add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_INOUT, false, 0);
       break;
     case PRE_MODIFY: case POST_MODIFY:
-      add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_INOUT, false);
-      add_regs_to_insn_regno_info (data, XEXP (x, 1), uid, OP_IN, false);
+      add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_INOUT, false, 0);
+      add_regs_to_insn_regno_info (data, XEXP (x, 1), uid, OP_IN, false, 0);
       break;
     default:
       if ((code != PARALLEL && code != EXPR_LIST) || type != OP_OUT)
@@ -1494,12 +1512,12 @@  add_regs_to_insn_regno_info (lra_insn_re
       for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
 	{
 	  if (fmt[i] == 'e')
-	    add_regs_to_insn_regno_info (data, XEXP (x, i), uid, type, false);
+	    add_regs_to_insn_regno_info (data, XEXP (x, i), uid, type, false, 0);
 	  else if (fmt[i] == 'E')
 	    {
 	      for (j = XVECLEN (x, i) - 1; j >= 0; j--)
 		add_regs_to_insn_regno_info (data, XVECEXP (x, i, j), uid,
-					     type, false);
+					     type, false, 0);
 	    }
 	}
     }
@@ -1590,10 +1608,11 @@  lra_update_insn_regno_info (rtx_insn *in
   for (i = static_data->n_operands - 1; i >= 0; i--)
     add_regs_to_insn_regno_info (data, *data->operand_loc[i], uid,
 				 static_data->operand[i].type,
-				 static_data->operand[i].early_clobber);
+				 static_data->operand[i].early_clobber,
+				 static_data->operand[i].early_clobber_alts);
   if ((code = GET_CODE (PATTERN (insn))) == CLOBBER || code == USE)
     add_regs_to_insn_regno_info (data, XEXP (PATTERN (insn), 0), uid,
-				 code == USE ? OP_IN : OP_OUT, false);
+				 code == USE ? OP_IN : OP_OUT, false, 0);
   if (CALL_P (insn))
     /* On some targets call insns can refer to pseudos in memory in
        CALL_INSN_FUNCTION_USAGE list.  Process them in order to
@@ -1605,7 +1624,7 @@  lra_update_insn_regno_info (rtx_insn *in
       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), uid,
-				     code == USE ? OP_IN : OP_OUT, false);
+				     code == USE ? OP_IN : OP_OUT, false, 0);
   if (NONDEBUG_INSN_P (insn))
     setup_insn_reg_info (data, freq);
 }