diff mbox

[lra] patch to fix bootstrap on ARM

Message ID 4F359895.3050506@redhat.com
State New
Headers show

Commit Message

Vladimir Makarov Feb. 10, 2012, 10:22 p.m. UTC
The following patch fixes arm bootstrap for LRA. The problem was in 
pseudo live
range splitting and wrong assignment to multi-registers pseudos with the 
same value.

The patch was successfully bootstrapped on x86/x86-64 and ARM.

Committed as rev. 184109.

2012-02-10 Vladimir Makarov <vmakarov@redhat.com>

* lra-int.h (struct lra_reg): New member call_p.

* lra-lives.c (lra_create_live_ranges): Clear call_p for the pseudo.
(process_bb_lives): Setup call_p.

* lra-assigns.c (find_hard_regno_for): Add code to setup and use
impossible_start_hard_regs.
(setup_live_pseudos_and_spill_after_risky): Consider
conflict_hard_regs to.
(lra_assign): Add checking pseudos crossing calls and using call
used hard regs.

* lra-constraints.c (extract_loc_address_regs): Fix the typo in
using code1 instead of code0.
(exchange_plus_ops): New function.
(process_address): Use it.
(split_pseudo): Rename and change semantics of the first
parameter.
(inherit_in_ebb): Process only output non-subreg pseudos as
a definition for the split. In this case don't invalidate usages
for splitting. Always add usage insn for splitting in case of
used pseudos or defined subregs of multi-reg pseudos.
diff mbox

Patch

Index: lra-assigns.c
===================================================================
--- lra-assigns.c	(revision 183639)
+++ lra-assigns.c	(working copy)
@@ -304,11 +304,14 @@  find_hard_regno_for (int regno, int *cos
   int best_cost = INT_MAX, best_bank = INT_MAX, best_usage = INT_MAX;
   lra_live_range_t r;
   int p, i, j, rclass_size, best_hard_regno, bank, hard_regno;
+  int hr, conflict_hr, nregs;
+  enum machine_mode biggest_mode;
   unsigned int k, conflict_regno;
   int val;
   enum reg_class rclass;
   bitmap_iterator bi;
   bool *rclass_intersect_p;
+  HARD_REG_SET impossible_start_hard_regs;
 
   COPY_HARD_REG_SET (conflict_set, lra_no_alloc_regs);
   rclass = regno_allocno_class_array[regno];
@@ -317,6 +320,7 @@  find_hard_regno_for (int regno, int *cos
   sparseset_clear (conflict_reload_and_inheritance_pseudos);
   sparseset_clear (live_range_hard_reg_pseudos);
   IOR_HARD_REG_SET (conflict_set, lra_reg_info[regno].conflict_hard_regs);
+  biggest_mode = lra_reg_info[regno].biggest_mode;
   for (r = lra_reg_info[regno].live_ranges; r != NULL; r = r->next)
     {
       EXECUTE_IF_SET_IN_BITMAP (&live_hard_reg_pseudos[r->start], 0, k, bi)
@@ -370,8 +374,26 @@  find_hard_regno_for (int regno, int *cos
 #endif
   sparseset_clear_bit (conflict_reload_and_inheritance_pseudos, regno);
   val = lra_reg_info[regno].val;
+  CLEAR_HARD_REG_SET (impossible_start_hard_regs);
   EXECUTE_IF_SET_IN_SPARSESET (live_range_hard_reg_pseudos, conflict_regno)
-    if (val != lra_reg_info[conflict_regno].val)
+    if (val == lra_reg_info[conflict_regno].val)
+      {
+	conflict_hr = live_pseudos_reg_renumber[conflict_regno];
+	nregs = (hard_regno_nregs[conflict_hr]
+		 [lra_reg_info[conflict_regno].biggest_mode]);
+	/* Remember about multi-register pseudos.  For example, 2 hard
+	   register pseudos can start on the same hard register but can
+	   not start on HR and HR+1/HR-1.  */ 
+	for (hr = conflict_hr + 1;
+	     hr < FIRST_PSEUDO_REGISTER && hr < conflict_hr + nregs;
+	     hr++)
+	  SET_HARD_REG_BIT (impossible_start_hard_regs, hr);
+	for (hr = conflict_hr - 1;
+	     hr >= 0 && hr + hard_regno_nregs[hr][biggest_mode] > conflict_hr;
+	     hr--)
+	  SET_HARD_REG_BIT (impossible_start_hard_regs, hr);
+      }
+    else
       {
 	lra_add_hard_reg_set (live_pseudos_reg_renumber[conflict_regno],
 			      lra_reg_info[conflict_regno].biggest_mode,
@@ -424,7 +446,8 @@  find_hard_regno_for (int regno, int *cos
 					     conflict_set)
 	  /* We can not use prohibited_class_mode_regs because it is
 	     defined not for all classes.  */
-	  && HARD_REGNO_MODE_OK (hard_regno, PSEUDO_REGNO_MODE (regno)))
+	  && HARD_REGNO_MODE_OK (hard_regno, PSEUDO_REGNO_MODE (regno))
+	  && ! TEST_HARD_REG_BIT (impossible_start_hard_regs, hard_regno))
 	{
 	  if (hard_regno_costs_check[hard_regno]
 	      != curr_hard_regno_costs_check)
@@ -881,9 +904,13 @@  setup_live_pseudos_and_spill_after_risky
 	    }
 	}
       COPY_HARD_REG_SET (conflict_set, lra_no_alloc_regs);
+      IOR_HARD_REG_SET (conflict_set, lra_reg_info[regno].conflict_hard_regs);
       val = lra_reg_info[regno].val;
       EXECUTE_IF_SET_IN_SPARSESET (live_range_hard_reg_pseudos, conflict_regno)
-	if (val != lra_reg_info[conflict_regno].val)
+	if (val != lra_reg_info[conflict_regno].val
+	    /* If it is multi-register pseudos they should start on
+	       the same hard register.  */
+	    || hard_regno != reg_renumber[conflict_regno])
 	  lra_add_hard_reg_set (reg_renumber[conflict_regno],
 				lra_reg_info[conflict_regno].biggest_mode,
 				&conflict_set);
@@ -893,7 +920,6 @@  setup_live_pseudos_and_spill_after_risky
 	  continue;
 	}
       bitmap_set_bit (spilled_pseudo_bitmap, regno);
-      hard_regno = reg_renumber[regno];
       for (j = 0;
 	   j < hard_regno_nregs[hard_regno][PSEUDO_REGNO_MODE (regno)];
 	   j++)
@@ -1154,6 +1180,15 @@  lra_assign (void)
   init_regno_assign_info ();
   bitmap_initialize (&all_spilled_pseudos, &reg_obstack);
   setup_live_pseudos_and_spill_after_risky_transforms (&all_spilled_pseudos);
+#ifdef ENABLE_CHECKING
+  for (i = FIRST_PSEUDO_REGISTER; i < max_reg_num (); i++)
+    if (lra_reg_info[i].nrefs != 0 && reg_renumber[i] >= 0
+	&& lra_reg_info[i].call_p
+	&& lra_hard_reg_set_intersection_p (reg_renumber[i],
+					    PSEUDO_REGNO_MODE (i),
+					    call_used_reg_set))
+      gcc_unreachable ();
+#endif
   /* Setup insns to process.  */
   bitmap_initialize (&changed_pseudo_bitmap, &reg_obstack);
   init_live_reload_and_inheritance_pseudos ();
Index: lra-constraints.c
===================================================================
--- lra-constraints.c	(revision 183639)
+++ lra-constraints.c	(working copy)
@@ -477,7 +477,7 @@  extract_loc_address_regs (bool top_p, en
 	  {
 	    extract_loc_address_regs (false, mode, arg0_loc, true, PLUS, code1,
 				      modify_p, ad);
-	    if (code1 == MULT)
+	    if (code0 == MULT)
 	      ad->index_loc = arg0_loc;
 	    extract_loc_address_regs (false, mode, arg1_loc, false, PLUS,
 				      code0, modify_p, ad);
@@ -2363,6 +2363,18 @@  equiv_address_substitution (struct addre
   return change_p;
 }
 
+/* Exchange operands of plus X. */
+static void
+exchange_plus_ops (rtx x)
+{
+  rtx op0;
+
+  gcc_assert (GET_CODE (x) == PLUS);
+  op0 = XEXP (x, 0);
+  XEXP (x, 0) = XEXP (x, 1);
+  XEXP (x, 1) = op0;
+}
+
 /* Major function to make reloads for address in operand NOP.  Add to
    reloads to the list *BEFORE and *AFTER.  We might need to add
    reloads to *AFTER because of inc/dec, {pre, post} modify in the
@@ -2489,6 +2501,14 @@  process_address (int nop, rtx *before, r
 	  if (CONSTANT_P (XEXP (*addr_loc, 1)))
 	    XEXP (*addr_loc, 1) = XEXP (*addr_loc, 0);
 	  XEXP (*addr_loc, 0) = new_reg;
+	  /* Some targets like ARM, accept address operands in
+	     specific order -- try exchange them if necessary.  */
+	  if (! valid_address_p (mode, *addr_loc, as))
+	    {
+	      exchange_plus_ops (*addr_loc);
+	      if (! valid_address_p (mode, *addr_loc, as))
+		exchange_plus_ops (*addr_loc);
+	    }
 	}
     }
   else if (ad.index_reg_loc == NULL)
@@ -2505,6 +2525,14 @@  process_address (int nop, rtx *before, r
       /* base + scale * index + disp => new base + scale * index  */
       new_reg = base_plus_disp_to_reg (mode, &ad);
       *addr_loc = gen_rtx_PLUS (Pmode, new_reg, *ad.index_loc);
+      if (! valid_address_p (mode, *addr_loc, as))
+	{
+	  /* Some targets like ARM, accept address operands in
+	     specific order -- try exchange them if necessary.  */
+	  exchange_plus_ops (*addr_loc);
+	  if (! valid_address_p (mode, *addr_loc, as))
+	    exchange_plus_ops (*addr_loc);
+	}
     }
   *before = get_insns ();
   end_sequence ();
@@ -3790,7 +3818,7 @@  choose_split_class (enum reg_class alloc
 #endif
 }
 
-/* Do split transformation for insn INSN defining (if DEF_P) or
+/* Do split transformation for insn INSN defining or
    using ORIGINAL_REGNO where the subsequent insn(s) in EBB (remember
    we traverse insns in the backward direction) for the original regno
    is NEXT_USAGE_INSNS.  The transformations look like
@@ -3808,10 +3836,10 @@  choose_split_class (enum reg_class alloc
      <- ... p ...         <- ... p ...
 
    where p is an original pseudo got a hard register and s is a new
-   split pseudo.  Return true if we succeed in such
-   transformation.  */
+   split pseudo.  The save is put before INSN if BEFORE_P is true.
+   Return true if we succeed in such transformation.  */
 static bool
-split_pseudo (bool def_p, int original_regno, rtx insn, rtx next_usage_insns)
+split_pseudo (bool before_p, int original_regno, rtx insn, rtx next_usage_insns)
 {
   enum reg_class rclass = lra_get_allocno_class (original_regno);
   rtx original_reg = regno_reg_rtx[original_regno];
@@ -3855,6 +3883,7 @@  split_pseudo (bool def_p, int original_r
     }
   if (NEXT_INSN (save) != NULL_RTX)
     {
+      gcc_assert (! call_save_p);
       if (lra_dump_file != NULL)
 	{
 	  fprintf (lra_dump_file,
@@ -3877,6 +3906,7 @@  split_pseudo (bool def_p, int original_r
     }
   if (NEXT_INSN (restore) != NULL_RTX)
     {
+      gcc_assert (! call_save_p);
       if (lra_dump_file != NULL)
 	{
 	  fprintf (lra_dump_file,
@@ -3890,15 +3920,6 @@  split_pseudo (bool def_p, int original_r
       return false;
     }
   after_p = usage_insns[original_regno].after_p;
-  if (! def_p)
-    {
-      /* We now have a new usage insn for original regno.  */
-      usage_insns[original_regno].check = curr_usage_insns_check;
-      usage_insns[original_regno].insns = save;
-      usage_insns[original_regno].reloads_num = reloads_num;
-      usage_insns[original_regno].calls_num = calls_num;
-      usage_insns[original_regno].after_p = false;
-    }
   lra_reg_info[REGNO (new_reg)].restore_regno = original_regno;
   bitmap_set_bit (&check_only_pseudos, REGNO (new_reg));
   bitmap_set_bit (&check_only_pseudos, original_regno);
@@ -3923,14 +3944,14 @@  split_pseudo (bool def_p, int original_r
 			  -1, 0);
 	}
     }
-  gcc_assert ((usage_insn != insn || (after_p && ! def_p))
-	      && NONDEBUG_INSN_P (usage_insn));
+  gcc_assert (NONDEBUG_INSN_P (usage_insn));
+  gcc_assert (usage_insn != insn || (after_p && before_p));
   lra_process_new_insns (usage_insn, after_p ? NULL_RTX : restore,
 			 after_p ? restore : NULL_RTX,
 			 call_save_p
 			 ?  "Add pseudo<-save" : "Add pseudo<-split");
-  lra_process_new_insns (insn, def_p ? NULL_RTX : save,
-			 def_p ? save : NULL_RTX,
+  lra_process_new_insns (insn, before_p ? save : NULL_RTX,
+			 before_p ? NULL_RTX : save,
 			 call_save_p
 			 ?  "Add save<-pseudo" : "Add split<-pseudo");
   if (lra_dump_file != NULL)
@@ -4311,28 +4332,23 @@  inherit_in_ebb (rtx head, rtx tail)
 		  }
 		/* We can not process one pseudo twice here
 		   because of usage_insns invalidation.  */
-		if (reg_renumber[dst_regno] >= 0)
+		if (reg_renumber[dst_regno] >= 0 && ! reg->subreg_p
+		    && reg->type == OP_OUT)
 		  {
+		    HARD_REG_SET s;
+		    
 		    if (need_for_split_p (potential_reload_hard_regs,
 					  dst_regno)
-			&& split_pseudo (true, dst_regno, curr_insn,
+			&& split_pseudo (false, dst_regno, curr_insn,
 					 next_usage_insns))
-		      {
-			if (reg->subreg_p)
-			  lra_risky_transformations_p = true;
-			change_p = true;
-		      }
-		    if (! reg->subreg_p)
-		      {
-			HARD_REG_SET s;
-			
-			CLEAR_HARD_REG_SET (s);
-			lra_add_hard_reg_set (reg_renumber[dst_regno],
-					      PSEUDO_REGNO_MODE (dst_regno),
-					      &s);
-			AND_COMPL_HARD_REG_SET (live_hard_regs, s);
-		      }
+		      change_p = true;
+		    CLEAR_HARD_REG_SET (s);
+		    lra_add_hard_reg_set (reg_renumber[dst_regno],
+					  PSEUDO_REGNO_MODE (dst_regno), &s);
+		    AND_COMPL_HARD_REG_SET (live_hard_regs, s);
 		  }
+		if (reg_renumber[dst_regno] < 0
+		    || (reg->type == OP_OUT && ! reg->subreg_p))
 		/* Invalidate.  */
 		usage_insns[dst_regno].check = 0;
 	      }
@@ -4357,18 +4373,17 @@  inherit_in_ebb (rtx head, rtx tail)
 			    = usage_insns[src_regno].insns) != NULL_RTX
 			&& NONDEBUG_INSN_P (curr_insn))
 		      add_to_inherit (src_regno, next_usage_insns);
-		    /* Add usages.  */
 		    else
+		      /* Add usages.  */
 		      add_next_usage_insn (src_regno, curr_insn, reloads_num);
 		  }
 		else if (reg_renumber[src_regno] >= 0)
 		  {
-		    bool ok_p = false;
-		    
+		    rtx use_insn = curr_insn;
+
 		    if (usage_insns[src_regno].check == curr_usage_insns_check
 			&& (next_usage_insns
 			    = usage_insns[src_regno].insns) != NULL_RTX
-			&& reg->type == OP_IN
 			/* To avoid processing the pseudo twice or
 			   more.  */
 			&& ((GET_CODE (next_usage_insns) != INSN_LIST
@@ -4379,19 +4394,23 @@  inherit_in_ebb (rtx head, rtx tail)
 			&& need_for_split_p (potential_reload_hard_regs,
 					     src_regno)
 			&& NONDEBUG_INSN_P (curr_insn)
-			&& split_pseudo (false, src_regno, curr_insn,
+			&& split_pseudo (CALL_P (curr_insn) && reg->type == OP_IN,
+					 src_regno, curr_insn,
 					 next_usage_insns))
 		      {
 			if (reg->subreg_p)
 			  lra_risky_transformations_p = true;
-			ok_p = change_p = true;
+			change_p = true;
+			/* Invalidate.  */
+			usage_insns[src_regno].check = 0;
+			if (CALL_P (curr_insn) && reg->type == OP_IN)
+			  use_insn = PREV_INSN (curr_insn);
 		      }
 		    if (NONDEBUG_INSN_P (curr_insn))
 		      lra_add_hard_reg_set (reg_renumber[src_regno],
 					    PSEUDO_REGNO_MODE (src_regno),
 					    &live_hard_regs);
-		    if (! ok_p)
-		      add_next_usage_insn (src_regno, curr_insn, reloads_num);
+		      add_next_usage_insn (src_regno, use_insn, reloads_num);
 		  }
 	      }
 	  for (i = 0; i < to_inherit_num; i++)
@@ -4442,7 +4461,8 @@  inherit_in_ebb (rtx head, rtx tail)
 				 "  ----------------------------------\n");
 			head_p = false;
 		      }
-		    if (split_pseudo (false, j, first_insn, next_usage_insns))
+		    if (split_pseudo (true, j, first_insn,
+				      next_usage_insns))
 		      change_p = true;
 		  }
 		usage_insns[j].check = 0;
Index: lra-int.h
===================================================================
--- lra-int.h	(revision 183639)
+++ lra-int.h	(working copy)
@@ -107,6 +107,12 @@  struct lra_reg
   /* True if the pseudo should not be assigned to a stack register.  */
   bool no_stack_p;
 #endif
+#ifdef ENABLE_CHECKING
+  /* True if the pseudo crosses a call.  It is setup in lra-lives.c
+     and used to check that the pseudo crossing a call did not get a
+     call used hard register.  */
+  bool call_p;
+#endif
   /* Number of references and execution frequencies of the register in
      *non-debug* insns.  */
   int nrefs, freq;
Index: lra-lives.c
===================================================================
--- lra-lives.c	(revision 183637)
+++ lra-lives.c	(working copy)
@@ -608,6 +608,9 @@  process_bb_lives (basic_block bb)
 		SET_HARD_REG_SET (lra_reg_info[i].conflict_hard_regs);
 	      IOR_HARD_REG_SET (lra_reg_info[i].conflict_hard_regs,
 				call_used_reg_set);
+#ifdef ENABLE_CHECKING
+	      lra_reg_info[i].call_p = true;
+#endif
 	    }
 	}
       
@@ -931,6 +934,9 @@  lra_create_live_ranges (bool all_p)
 	lra_reg_info[i].biggest_mode = GET_MODE (regno_reg_rtx[i]);
       else
 	lra_reg_info[i].biggest_mode = VOIDmode;
+#ifdef ENABLE_CHECKING
+      lra_reg_info[i].call_p = false;
+#endif
       if (i >= FIRST_PSEUDO_REGISTER
 	  && lra_reg_info[i].nrefs != 0 && (hard_regno = reg_renumber[i]) >= 0)
 	lra_hard_reg_usage[hard_regno] += lra_reg_info[i].freq;