This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] PR24265, loop-invariant.c fixes (1/2)


Hi,

This patch makes sure that a reg-reg move exists for hard regs on the
left hand side of loop invariant SET insns.  Under the right conditions
(i.e. hacked to move all loop invariants) loop-invariant.c would try to
hoist things like the right hand side of the i386 "cld" instruction out
of a loop.  The "cld" insn is:

(set (reg:SI DIRFLAG_REG) (const_int 0))

and because I told loop-invariant.c to move everything, it woudl try
to move "(const_int 0)" into a reg outside of the loop, and produce a

(set (reg:SI DIRFLAG_REG) (reg_outside_loop))

pattern.  This is not a valid instruction, so we got an unrecognizable
insn.

This kind of thing may also happen in a non-hacked loop-invariant.c on
some targets.  The attached patch avoids this problem by making sure a
reg-reg move really exists for hard registers.

This is only part one of the fix.  The second part will follow in the
next post.

This was bootstrapped and tested on {i686,x86_64,ppc}-suse-linux-gnu.
OK for mainline?

Gr.
Steven


        * loop-invariant.c (may_assign_reg_p): Make sure a reg-reg move
        exists when the target reg is a hard register.
        (find_invariant_insn): Do the cheapest check, may_assign_reg_p,
        before check_maybe_invariant.
        (move_loop_invariants): Clear the new static global test_insn
        every time this function is called.  If checking is enabled, do
        internal consistency checks after completing the pass.
	* loop-invariant.c (may_assign_reg_p): Make sure a reg-reg move
	exists when the target reg is a hard register.
	(find_invariant_insn): Do the cheapest check, may_assign_reg_p,
	before check_maybe_invariant.
	(move_loop_invariants): Clear the new static global test_insn
	every time this function is called.  If checking is enabled, do
	internal consistency checks after completing the pass.

Index: loop-invariant.c
===================================================================
--- loop-invariant.c	(revision 106748)
+++ loop-invariant.c	(working copy)
@@ -286,12 +286,44 @@ find_exits (struct loop *loop, basic_blo
   LOOP_DATA (loop)->has_call = has_call;
 }
 
+/* Test instruction to see if a hard_reg <- reg move exists.  A new
+   insn is created for each time this pass runs, hence no GTY marker.  */
+static rtx test_insn;
+
 /* Check whether we may assign a value to X from a register.  */
 
 static bool
 may_assign_reg_p (rtx x)
 {
-  return can_copy_p (GET_MODE (x));
+  int insn_code;
+  int num_clobbers = 0;
+
+  /* If this is not a machine mode with a reg-reg move, we're finished.  */
+  if (!can_copy_p (GET_MODE (x)))
+    return false;
+
+  if (!HARD_REGISTER_P (x))
+    return true;
+
+  /* For hard registers, make sure that a reg-reg move for it exists by
+     actually trying to recognize such an instruction.  This is needed
+     for i386's std and cld instructions, for example.  */
+
+  /* Initialize our test instruction if we haven't already.  */
+  if (!test_insn)
+    {
+      rtx fake_reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
+      test_insn = make_insn_raw (gen_rtx_SET (VOIDmode, x, fake_reg));
+      NEXT_INSN (test_insn) = PREV_INSN (test_insn) = 0;
+    }
+
+  /* Build an assignment to X and see if it can be recognized.  */
+  SET_DEST (PATTERN (test_insn)) = x;
+  PUT_MODE (SET_SRC (PATTERN (test_insn)), GET_MODE (x));
+  insn_code = recog (PATTERN (test_insn), test_insn, &num_clobbers);
+  return (insn_code >= 0
+	  && (num_clobbers == 0
+	      || ! added_clobbers_hard_reg_p (insn_code)));
 }
 
 /* Finds definitions that may correspond to invariants in LOOP with body BODY.
@@ -436,8 +468,8 @@ find_invariant_insn (rtx insn, bool alwa
       || HARD_REGISTER_P (dest))
     simple = false;
 
-  if (!check_maybe_invariant (SET_SRC (set))
-      || !may_assign_reg_p (SET_DEST (set)))
+  if (!may_assign_reg_p (SET_DEST (set))
+      || !check_maybe_invariant (SET_SRC (set)))
     return;
 
   if (may_trap_p (PATTERN (insn)))
@@ -901,6 +933,10 @@ move_loop_invariants (struct loops *loop
   struct loop *loop;
   unsigned i;
   struct df *df = df_init ();
+  
+  /* ??? We could GTY test_insn, but I really don't think it's worth it.
+     just make sure it is nullified every time this pass runs.  */
+  test_insn = NULL;
 
   /* Process the loops, innermost first.  */
   loop = loops->tree_root;
@@ -926,4 +962,8 @@ move_loop_invariants (struct loops *loop
       free_loop_data (loops->parray[i]);
 
   df_finish (df);
+
+#ifdef ENABLE_CHECKING
+  verify_flow_info ();
+#endif
 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]