This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] for PR 26254
- From: Zdenek Dvorak <rakdver at atrey dot karlin dot mff dot cuni dot cz>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 13 Feb 2006 20:49:08 +0100
- Subject: [patch] for PR 26254
Hello,
on sh4, the only possible target of assignment of result of a compare
is a fixed hard register, which makes it impossible to store the result
to a temporary pseudoregister using standard functions. There seems to
be no easy way how to handle this, except for verifying that the
produced insns are correct and failing if they are not. While there
are other possible solutions (like implementing a new target hook as in
the second patch proposed for this PR), it seems likely that there are
similar special cases that are not handled by force_operand and
emit_move_insn; so this solution seems safer to me.
Bootstrapped & regtested on i686. Verified to fix the ICE on sh4-linux
from crosscompiler.
Zdenek
PR rtl-optimization/26254
* loop-invariant.c (find_identical_invariants): Fix dump format.
(seq_insns_valid_p): New function.
(move_invariant_reg): Only emit new code if it is valid.
Index: loop-invariant.c
===================================================================
*** loop-invariant.c (revision 110912)
--- loop-invariant.c (working copy)
*************** find_identical_invariants (htab_t eq, st
*** 465,471 ****
if (dump_file && inv->eqto != inv->invno)
fprintf (dump_file,
! "Invariant %d is equivalent to invariant %d.\n ",
inv->invno, inv->eqto);
}
--- 465,471 ----
if (dump_file && inv->eqto != inv->invno)
fprintf (dump_file,
! "Invariant %d is equivalent to invariant %d.\n",
inv->invno, inv->eqto);
}
*************** find_invariants_to_move (void)
*** 1066,1087 ****
}
}
! /* Move invariant INVNO out of the LOOP. */
! static void
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;
struct use *use;
bitmap_iterator bi;
! if (inv->reg
! || !repr->move)
! return;
/* If this is a representative of the class of equivalent invariants,
really move the invariant. Otherwise just replace its use with
--- 1066,1103 ----
}
}
! /* Returns true if all insns in SEQ are valid. */
! 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, dest, seq, op;
struct use *use;
bitmap_iterator bi;
! 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
*************** move_invariant_reg (struct loop *loop, u
*** 1092,1098 ****
{
EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, i, bi)
{
! move_invariant_reg (loop, i);
}
}
--- 1108,1115 ----
{
EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, i, bi)
{
! if (!move_invariant_reg (loop, i))
! goto fail;
}
}
*************** move_invariant_reg (struct loop *loop, u
*** 1102,1115 ****
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);
! /* If the SET_DEST of the invariant insn is a reg, 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)))
{
SET_DEST (set) = reg;
reorder_insns (inv->insn, inv->insn, BB_END (preheader));
}
--- 1119,1133 ----
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);
! dest = SET_DEST (set);
! reg = gen_reg_rtx (GET_MODE (dest));
! /* 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 (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));
}
*************** move_invariant_reg (struct loop *loop, u
*** 1122,1134 ****
seq = get_insns ();
end_sequence ();
emit_insn_after (seq, BB_END (preheader));
delete_insn (inv->insn);
}
}
else
{
! move_invariant_reg (loop, repr->invno);
reg = repr->reg;
set = single_set (inv->insn);
emit_insn_after (gen_move_insn (SET_DEST (set), reg), inv->insn);
--- 1140,1157 ----
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
{
! 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);
*************** move_invariant_reg (struct loop *loop, u
*** 1145,1150 ****
--- 1168,1184 ----
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