X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Floop-invariant.c;h=cf2294950153a2a519fc392fc43eb9175c4a9af6;hb=d0460211e30b928810a676d86cf4f043dfc388f4;hp=a57857d3831dfd6bac62ddad19e15624b6b4de26;hpb=5df640f646860cf0e8bd0dcf7a7b3eb4f7576fd3;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/loop-invariant.c b/gcc/loop-invariant.c index a57857d3831..cf229495015 100644 --- a/gcc/loop-invariant.c +++ b/gcc/loop-invariant.c @@ -52,6 +52,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "flags.h" #include "df.h" #include "hashtab.h" +#include "except.h" /* The data stored for the loop. */ @@ -232,6 +233,9 @@ invariant_for_use (struct df_ref *use) struct df_ref *def; basic_block bb = BLOCK_FOR_INSN (use->insn), def_bb; + if (use->flags & DF_REF_READ_WRITE) + return NULL; + defs = DF_REF_CHAIN (use); if (!defs || defs->next) return NULL; @@ -475,7 +479,7 @@ find_identical_invariants (htab_t eq, struct invariant *inv) if (dump_file && inv->eqto != inv->invno) fprintf (dump_file, - "Invariant %d is equivalent to invariant %d.\n ", + "Invariant %d is equivalent to invariant %d.\n", inv->invno, inv->eqto); } @@ -681,7 +685,8 @@ record_use (struct def *def, rtx *use, rtx insn) } /* Finds the invariants INSN depends on and store them to the DEPENDS_ON - bitmap. */ + bitmap. Returns true if all dependencies of INSN are known to be + loop invariants, false otherwise. */ static bool check_dependencies (rtx insn, bitmap depends_on) @@ -694,6 +699,9 @@ check_dependencies (rtx insn, bitmap depends_on) for (use = DF_INSN_GET (df, insn)->uses; use; use = use->next_ref) { + if (use->flags & DF_REF_READ_WRITE) + return false; + defs = DF_REF_CHAIN (use); if (!defs) continue; @@ -761,16 +769,14 @@ find_invariant_insn (rtx insn, bool always_reached, bool always_executed) || !check_maybe_invariant (SET_SRC (set))) return; - if (may_trap_p (PATTERN (insn))) - { - if (!always_reached) - return; + /* If the insn can throw exception, we cannot move it at all without changing + cfg. */ + if (can_throw_internal (insn)) + return; - /* Unless the exceptions are handled, the behavior is undefined - if the trap occurs. */ - if (flag_non_call_exceptions) - return; - } + /* We cannot make trapping insn executed, unless it was executed before. */ + if (may_trap_after_code_motion_p (PATTERN (insn)) && !always_reached) + return; depends_on = BITMAP_ALLOC (NULL); if (!check_dependencies (insn, depends_on)) @@ -926,6 +932,32 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed) (*regs_needed)++; (*comp_cost) += inv->cost; +#ifdef STACK_REGS + { + /* Hoisting constant pool constants into stack regs may cost more than + just single register. On x87, the balance is affected both by the + small number of FP registers, and by its register stack organization, + that forces us to add compensation code in and around the loop to + shuffle the operands to the top of stack before use, and pop them + from the stack after the loop finishes. + + To model this effect, we increase the number of registers needed for + stack registers by two: one register push, and one register pop. + This usually has the effect that FP constant loads from the constant + pool are not moved out of the loop. + + Note that this also means that dependent invariants can not be moved. + However, the primary purpose of this pass is to move loop invariant + address arithmetic out of loops, and address arithmetic that depends + on floating point constants is unlikely to ever occur. */ + rtx set = single_set (inv->insn); + if (set + && IS_STACK_MODE (GET_MODE (SET_SRC (set))) + && constant_pool_constant_p (SET_SRC (set))) + (*regs_needed) += 2; + } +#endif + EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, depno, bi) { dep = VEC_index (invariant_p, invariants, depno); @@ -1077,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 @@ -1103,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; } } @@ -1113,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)); } @@ -1128,18 +1178,28 @@ move_invariant_reg (struct loop *loop, unsigned invno) { start_sequence (); op = force_operand (SET_SRC (set), reg); + if (!op) + { + end_sequence (); + goto fail; + } if (op != reg) emit_move_insn (reg, op); 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); @@ -1156,6 +1216,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