diff mbox

[lra] patch to use equiv for restoring values around calls

Message ID 4E726676.5090707@redhat.com
State New
Headers show

Commit Message

Vladimir Makarov Sept. 15, 2011, 8:56 p.m. UTC
The following patch permits to use equivalences to restore pseudo values 
around the call.

As side effect the patch solves SPECFP2000 art degradation on x86-64 and 
possibly on ppc64 (unfortunately the score results for art is too 
unstable on power7).

The patch was successfully bootstrapped on x86-64 and ppc64.

2011-09-15  Vladimir Makarov <vmakarov@redhat.com>

         * lra.c (remove_scratches): Rescan changed insns.
         (lra): Call df_analyze after lr_save_restore if necessary.

         * lra-int.h (lr_save_restore): Change the prototype.

         * lra-saves.c (struct save_regs): Rename mem_reg to saved_value.
         Add new member equiv_p.
         (equiv_for_save): New function.
         (update_live_info_p): New static variable.
         (setup_save_regs): Add code to regno equivalence.
         (insert_save_restore): Ditto.
         (lra_save_restore): Return true if need to update live info.
diff mbox

Patch

Index: lra.c
===================================================================
--- lra.c	(revision 178734)
+++ lra.c	(working copy)
@@ -1791,6 +1791,7 @@  static void
 remove_scratches (void)
 {
   int i;
+  bool insn_changed_p;
   basic_block bb;
   rtx insn, reg;
   loc_t loc;
@@ -1806,10 +1807,12 @@  remove_scratches (void)
       {
 	id = lra_get_insn_recog_data (insn);
 	static_id = id->insn_static_data;
+	insn_changed_p = false;
 	for (i = 0; i < static_id->n_operands; i++)
 	  if (GET_CODE (*id->operand_loc[i]) == SCRATCH
 	      && GET_MODE (*id->operand_loc[i]) != VOIDmode)
 	    {
+	      insn_changed_p = true;
 	      *id->operand_loc[i] = reg
 		= lra_create_new_reg (static_id->operand[i].mode,
 				      *id->operand_loc[i], ALL_REGS, NULL);
@@ -1826,6 +1829,10 @@  remove_scratches (void)
 		fprintf (lra_dump_file, "Removing SCRATCH in insn #%u (nop %d)\n",
 			 INSN_UID (insn), i);
 	    }
+	if (insn_changed_p)
+	  /* Because we might use DF right after caller-saves sub-pass
+	     we need to keep DF info up to date.  */
+	  df_insn_rescan (insn);
       }
 }
 
@@ -2105,7 +2112,10 @@  lra (FILE *f)
 	df_set_regs_ever_live (i, true);
 
   if (flag_caller_saves)
-    lra_save_restore ();
+    {
+      if (lra_save_restore ())
+	df_analyze ();
+    }
 
   /* We don't DF from now and avoid its using because it is to
      expensive when a lot of RTL changes are made.  */
Index: lra-int.h
===================================================================
--- lra-int.h	(revision 178734)
+++ lra-int.h	(working copy)
@@ -328,7 +328,7 @@  extern void lra_coalesce (void);
 
 /* lra-saves.c: */
 
-extern void lra_save_restore (void);
+extern bool lra_save_restore (void);
 
 /* lra-spills.c:  */
 
Index: lra-saves.c
===================================================================
--- lra-saves.c	(revision 178734)
+++ lra-saves.c	(working copy)
@@ -161,9 +161,12 @@  mark_pseudo_store (rtx reg, const_rtx se
 /* Info about save/restore code for a pseudo.  */
 struct save_regs
 {
-  /* A spilled pseudo which hold value of the corresponding
-     saved/restored pseudo around calls.  */
-  rtx mem_reg;
+  /* True if MEM_REG is actually an equivalence of the corresponding
+     saved pseudo.  */
+  bool equiv_p;
+  /* A spilled pseudo or equivalence which hold value of the
+     corresponding saved/restored pseudo around calls.  */
+  rtx saved_value;
   /* Saving/restoring of a pseudo could be done in a mode different
      from the pseudo mode.  The following is the pseudo or a subreg of
      the pseudo and is used in save/restore code.  */
@@ -175,71 +178,125 @@  struct save_regs
 /* Map: regno -> info about save/restore for REGNO.  */
 static struct save_regs *save_regs;
 
-/* Set up if necessary saved_reg and mem_reg for REGNO.  */
+/* Return equivalence value we can use for restoring.  NULL,
+   otherwise.  ??? Should we use and is it worth to invariants with
+   caller saved hard registers.  */
+static rtx
+equiv_for_save (int regno)
+{
+  return ira_reg_equiv[regno].constant;
+}
+
+/* Set to true if changes in live info are too complex to update it
+   here.  */
+static bool update_live_info_p;
+
+/* Set up if necessary equiv_p, saved_value, and saved_reg for REGNO.  */
 static void
 setup_save_regs (int regno)
 {
-  if (save_regs[regno].mem_reg == NULL_RTX)
+  if (save_regs[regno].saved_value == NULL_RTX)
     {
       enum machine_mode mode;
-      rtx saved_reg = regno_reg_rtx[regno];
-      int hard_regno = reg_renumber[regno];
+      int hard_regno;
+      rtx equiv, saved_reg = regno_reg_rtx[regno];
 
-      gcc_assert (hard_regno >= 0);
-      mode = (HARD_REGNO_CALLER_SAVE_MODE
-	      (hard_regno,
-	       hard_regno_nregs[hard_regno][PSEUDO_REGNO_MODE (regno)],
-	       PSEUDO_REGNO_MODE (regno)));
-      if (mode != PSEUDO_REGNO_MODE (regno))
-	saved_reg = gen_rtx_SUBREG (mode, saved_reg, 0);
-      save_regs[regno].mem_reg
-	= lra_create_new_reg (VOIDmode, saved_reg, NO_REGS, NULL);
+      equiv = ira_reg_equiv[regno].defined_p ? equiv_for_save (regno) : NULL_RTX;
+      if (equiv != NULL_RTX)
+	{
+	  save_regs[regno].saved_value = equiv;
+	  update_live_info_p = true;
+	}
+      else
+	{
+	  hard_regno = reg_renumber[regno];
+	  gcc_assert (hard_regno >= 0);
+	  mode = (HARD_REGNO_CALLER_SAVE_MODE
+		  (hard_regno,
+		   hard_regno_nregs[hard_regno][PSEUDO_REGNO_MODE (regno)],
+		   PSEUDO_REGNO_MODE (regno)));
+	  if (mode != PSEUDO_REGNO_MODE (regno))
+	    saved_reg = gen_rtx_SUBREG (mode, saved_reg, 0);
+	  save_regs[regno].saved_value
+	    = lra_create_new_reg (VOIDmode, saved_reg, NO_REGS, NULL);
+	}
       save_regs[regno].saved_reg = saved_reg;
+      save_regs[regno].equiv_p = equiv != NULL_RTX;
     }
 }
 
 /* Insert save (if SAVE_P) or restore code for REGNO before (if
-   BEFORE_P) or after INSN.  */
+   BEFORE_P) or after INSN.  Use equivalence for restoring if it is
+   possible.  */
 static void
 insert_save_restore (rtx insn, bool before_p, int regno, bool save_p)
 {
-  rtx x, mem_reg;
+  rtx x, saved_value;
   int to_regno, from_regno;
   rtx saved_reg;
 
   setup_save_regs (regno);
-  mem_reg = save_regs[regno].mem_reg;
+  saved_value = save_regs[regno].saved_value;
   saved_reg = save_regs[regno].saved_reg;
+  if (save_regs[regno].equiv_p)
+    {
+      if (save_p)
+	/* Do nothing -- the pseudo always holds the same value.  */
+	return;
+      start_sequence ();
+      emit_move_insn (saved_reg, saved_value);
+      x = get_insns ();
+      end_sequence ();
+      if (lra_dump_file != NULL)
+	{
+	  fprintf (lra_dump_file, "Inserting %s i%u bb%d\n",
+		   before_p ? "before" : "after", INSN_UID (insn),
+		   BLOCK_FOR_INSN (insn)->index);
+	  print_rtl_slim (lra_dump_file, x, x, -1, 0);
+	}
+      ira_reg_equiv[regno].init_insns
+	= gen_rtx_INSN_LIST (VOIDmode, x, ira_reg_equiv[regno].init_insns);
+      if (before_p)
+	emit_insn_before (x, insn); 
+      else
+	emit_insn_after (x, insn); 
+      return;
+    }
   start_sequence ();
   if (save_p)
     {
-      to_regno = REGNO (mem_reg);
+      gcc_assert (REG_P (saved_value));
+      to_regno = REGNO (saved_value);
       from_regno = regno;
-      emit_move_insn (mem_reg, saved_reg);
+      emit_move_insn (saved_value, saved_reg);
     }
   else
     {
       to_regno = regno;
-      from_regno = REGNO (mem_reg);
-      emit_move_insn (saved_reg, mem_reg);
+      from_regno = REGNO (saved_value);
+      emit_move_insn (saved_reg, saved_value);
     }
   x = get_insns ();
   end_sequence ();
   if (before_p || ! save_p || ! CALL_P (insn))
-    add_reg_note (x, REG_DEAD, regno_reg_rtx[from_regno]);
+    {
+      if (! update_live_info_p)
+	add_reg_note (x, REG_DEAD, regno_reg_rtx[from_regno]);
+    }
   else
     {
       /* A special case: saving a pseudo used in a call.  Put saving
 	 insn before the call and attach the note to the call.  */
       before_p = true;
-      add_reg_note (insn, REG_DEAD, regno_reg_rtx[from_regno]);
+      if (! update_live_info_p)
+	add_reg_note (insn, REG_DEAD, regno_reg_rtx[from_regno]);
     }
   ira_update_equiv_info_by_shuffle_insn (to_regno, from_regno, x);
   if (lra_dump_file != NULL)
     fprintf (lra_dump_file, "Inserting insn %u %d:=%d %s i%u bb%d\n",
 	     INSN_UID (x),
-	     save_p ? (int) REGNO (mem_reg) : regno,
-	     save_p ? regno : (int) REGNO (mem_reg),
+	     save_p ? (int) REGNO (saved_value) : regno,
+	     save_p ? regno : (int) REGNO (saved_value),
 	     before_p ? "before" : "after", INSN_UID (insn),
 	     BLOCK_FOR_INSN (insn)->index);
   if (before_p)
@@ -380,8 +437,12 @@  insert_saves_restores (void)
 	      bitmap_clear_bit (DF_LR_IN (bb), regno);
 	      bitmap_clear_bit (DF_LR_OUT (prev_bb), regno);
 	      setup_save_regs (regno);
-	      bitmap_set_bit (DF_LR_IN (bb), REGNO (save_regs[regno].mem_reg));
-	      bitmap_set_bit (DF_LR_OUT (prev_bb), REGNO (save_regs[regno].mem_reg));
+	      if (update_live_info_p)
+		break;
+	      bitmap_set_bit (DF_LR_IN (bb),
+			      REGNO (save_regs[regno].saved_value));
+	      bitmap_set_bit (DF_LR_OUT (prev_bb),
+			      REGNO (save_regs[regno].saved_value));
 	    }
 	}
     }
@@ -392,8 +453,9 @@  insert_saves_restores (void)
 /* Major function to insert save/restore code.  The function needs
    correct DFA info and REG_N_REFS & REG_N_CALLS_CROSSED before the
    function work.  It keeps correct bb live info and live related insn
-   notes.  */
-void
+   notes.  Return true if we need to update live info because the
+   changes are too complex to do it here.  */
+bool
 lra_save_restore (void)
 {
   int i, hard_regno, max_regno_before;
@@ -403,6 +465,7 @@  lra_save_restore (void)
   if (lra_dump_file != NULL)
     fprintf (lra_dump_file, "\n********** Caller saves: **********\n\n");
 
+  update_live_info_p = false;
   consideration_pseudos = BITMAP_ALLOC (&reg_obstack);
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno_before; i++)
     if (REG_N_REFS (i) != 0
@@ -422,4 +485,5 @@  lra_save_restore (void)
       BITMAP_FREE (live_pseudos);
     }
   BITMAP_FREE (consideration_pseudos);
+  return update_live_info_p;
 }