From 1e41d0e2b4276e36c7faf2b28c00c6607c894f45 Mon Sep 17 00:00:00 2001
From: rakdver <rakdver@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Mon, 13 Mar 2006 12:28:09 +0000
Subject: [PATCH] 	PR rtl-optimization/26254 	* loop-invariant.c
 (seq_insns_valid_p): New function. 	(move_invariant_reg): Only emit new
 code if it is valid.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111998 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog        |  6 +++++
 gcc/loop-invariant.c | 58 +++++++++++++++++++++++++++++++++++---------
 2 files changed, 52 insertions(+), 12 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5b60dade9d53..ab470b709cda 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2006-03-13  Zdenek Dvorak <dvorakz@suse.cz>
+
+	PR rtl-optimization/26254
+	* loop-invariant.c (seq_insns_valid_p): New function.
+	(move_invariant_reg): Only emit new code if it is valid.
+
 2006-03-13  Zdenek Dvorak <dvorakz@suse.cz>
 
 	* cfgrtl.c (last_loop_beg_note, back_edge_of_syntactic_loop_p):
diff --git a/gcc/loop-invariant.c b/gcc/loop-invariant.c
index 2185d189a264..026af40822ce 100644
--- a/gcc/loop-invariant.c
+++ b/gcc/loop-invariant.c
@@ -1109,22 +1109,38 @@ find_invariants_to_move (void)
     }
 }
 
-/* Move invariant INVNO out of the LOOP.  */
+/* Returns true if all insns in SEQ are valid.  */
 
-static void
+static bool
+seq_insns_valid_p (rtx seq)
+{
+  rtx x;
+
+  for (x = seq; x; x = NEXT_INSN (x))
+    if (insn_invalid_p (x))
+      return false;
+
+  return true;
+}
+
+/* Move invariant INVNO out of the LOOP.  Returns true if this succeeds, false
+   otherwise.  */
+
+static bool
 move_invariant_reg (struct loop *loop, unsigned invno)
 {
   struct invariant *inv = VEC_index (invariant_p, invariants, invno);
   struct invariant *repr = VEC_index (invariant_p, invariants, inv->eqto);
   unsigned i;
   basic_block preheader = loop_preheader_edge (loop)->src;
-  rtx reg, set, seq, op;
+  rtx reg, set, dest, seq, op;
   struct use *use;
   bitmap_iterator bi;
 
-  if (inv->reg
-      || !repr->move)
-    return;
+  if (inv->reg)
+    return true;
+  if (!repr->move)
+    return false;
 
   /* If this is a representative of the class of equivalent invariants,
      really move the invariant.  Otherwise just replace its use with
@@ -1135,7 +1151,8 @@ move_invariant_reg (struct loop *loop, unsigned invno)
 	{
 	  EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, i, bi)
 	    {
-	      move_invariant_reg (loop, i);
+	      if (!move_invariant_reg (loop, i))
+		goto fail;
 	    }
 	}
 
@@ -1145,14 +1162,15 @@ move_invariant_reg (struct loop *loop, unsigned invno)
 	 would not be dominated by it, we may just move it (TODO).  Otherwise we
 	 need to create a temporary register.  */
       set = single_set (inv->insn);
-      reg = gen_reg_rtx (GET_MODE (SET_DEST (set)));
-      emit_insn_after (gen_move_insn (SET_DEST (set), reg), inv->insn);
+      dest = SET_DEST (set);
+      reg = gen_reg_rtx (GET_MODE (dest));
 
-      /* If the SET_DEST of the invariant insn is a reg, we can just move
+      /* If the SET_DEST of the invariant insn is a pseudo, we can just move
 	 the insn out of the loop.  Otherwise, we have to use gen_move_insn
 	 to let emit_move_insn produce a valid instruction stream.  */
-      if (REG_P (SET_DEST (set)))
+      if (REG_P (dest) && !HARD_REGISTER_P (dest))
 	{
+	  emit_insn_after (gen_move_insn (dest, reg), inv->insn);
 	  SET_DEST (set) = reg;
 	  reorder_insns (inv->insn, inv->insn, BB_END (preheader));
 	}
@@ -1165,13 +1183,18 @@ move_invariant_reg (struct loop *loop, unsigned invno)
 	  seq = get_insns ();
 	  end_sequence ();
 
+	  if (!seq_insns_valid_p (seq))
+	    goto fail;
 	  emit_insn_after (seq, BB_END (preheader));
+      
+	  emit_insn_after (gen_move_insn (dest, reg), inv->insn);
 	  delete_insn (inv->insn);
 	}
     }
   else
     {
-      move_invariant_reg (loop, repr->invno);
+      if (!move_invariant_reg (loop, repr->invno))
+	goto fail;
       reg = repr->reg;
       set = single_set (inv->insn);
       emit_insn_after (gen_move_insn (SET_DEST (set), reg), inv->insn);
@@ -1188,6 +1211,17 @@ move_invariant_reg (struct loop *loop, unsigned invno)
       for (use = inv->def->uses; use; use = use->next)
 	*use->pos = reg;
     }
+
+  return true;
+
+fail:
+  /* If we failed, clear move flag, so that we do not try to move inv
+     again.  */
+  if (dump_file)
+    fprintf (dump_file, "Failed to move invariant %d\n", invno);
+  inv->move = false;
+  inv->reg = NULL_RTX;
+  return false;
 }
 
 /* Move selected invariant out of the LOOP.  Newly created regs are marked
-- 
GitLab