This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] PR24265, loop-invariant.c fixes (1/2)
- From: Steven Bosscher <stevenb at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Zdenek Dvorak <rakdver at atrey dot karlin dot mff dot cuni dot cz>, mark at codesourcery dot com
- Date: Thu, 10 Nov 2005 21:33:45 +0100
- Subject: [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
}