diff options
Diffstat (limited to 'gcc/loop.c')
-rw-r--r-- | gcc/loop.c | 125 |
1 files changed, 108 insertions, 17 deletions
diff --git a/gcc/loop.c b/gcc/loop.c index d7abe5ff654..284d891cf21 100644 --- a/gcc/loop.c +++ b/gcc/loop.c @@ -1,6 +1,6 @@ /* Perform various loop optimizations, including strength reduction. Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -326,10 +326,12 @@ static void update_reg_last_use PARAMS ((rtx, rtx)); static rtx next_insn_in_loop PARAMS ((const struct loop *, rtx)); static void loop_regs_scan PARAMS ((const struct loop *, int)); static int count_insns_in_loop PARAMS ((const struct loop *)); +static int find_mem_in_note_1 PARAMS ((rtx *, void *)); +static rtx find_mem_in_note PARAMS ((rtx)); static void load_mems PARAMS ((const struct loop *)); static int insert_loop_mem PARAMS ((rtx *, void *)); static int replace_loop_mem PARAMS ((rtx *, void *)); -static void replace_loop_mems PARAMS ((rtx, rtx, rtx)); +static void replace_loop_mems PARAMS ((rtx, rtx, rtx, int)); static int replace_loop_reg PARAMS ((rtx *, void *)); static void replace_loop_regs PARAMS ((rtx insn, rtx, rtx)); static void note_reg_stored PARAMS ((rtx, rtx, void *)); @@ -815,11 +817,17 @@ scan_loop (loop, flags) } } + /* Don't try to optimize a MODE_CC set with a constant + source. It probably will be combined with a conditional + jump. */ + if (GET_MODE_CLASS (GET_MODE (SET_DEST (set))) == MODE_CC + && CONSTANT_P (src)) + ; /* Don't try to optimize a register that was made by loop-optimization for an inner loop. We don't know its life-span, so we can't compute the benefit. */ - if (REGNO (SET_DEST (set)) >= max_reg_before_loop) + else if (REGNO (SET_DEST (set)) >= max_reg_before_loop) ; else if (/* The register is used in basic blocks other than the one where it is set (meaning that @@ -3277,7 +3285,7 @@ loop_invariant_p (loop, x) These have always been created by the unroller and are set in the loop, hence are never invariant. */ - if (REGNO (x) >= regs->num) + if (REGNO (x) >= (unsigned) regs->num) return 0; if (regs->array[REGNO (x)].set_in_loop < 0) @@ -4204,7 +4212,15 @@ emit_prefetch_instructions (loop) non-constant INIT_VAL to have the same mode as REG, which in this case we know to be Pmode. */ if (GET_MODE (init_val) != Pmode && !CONSTANT_P (init_val)) - init_val = convert_to_mode (Pmode, init_val, 0); + { + rtx seq; + + start_sequence (); + init_val = convert_to_mode (Pmode, init_val, 0); + seq = get_insns (); + end_sequence (); + loop_insn_emit_before (loop, 0, loop_start, seq); + } loop_iv_add_mult_emit_before (loop, init_val, info[i].giv->mult_val, add_val, reg, 0, loop_start); @@ -4761,6 +4777,9 @@ loop_givs_reduce (loop, bl) { rtx insert_before; + /* Skip if location is the same as a previous one. */ + if (tv->same) + continue; if (! auto_inc_opt) insert_before = NEXT_INSN (tv->insn); else if (auto_inc_opt == 1) @@ -5668,6 +5687,7 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location, v->always_computable = ! not_every_iteration; v->always_executed = ! not_every_iteration; v->maybe_multiple = maybe_multiple; + v->same = 0; /* Add this to the reg's iv_class, creating a class if this is the first incrementation of the reg. */ @@ -5705,6 +5725,17 @@ record_biv (loop, v, insn, dest_reg, inc_val, mult_val, location, /* Put it in the array of biv register classes. */ REG_IV_CLASS (ivs, REGNO (dest_reg)) = bl; } + else + { + /* Check if location is the same as a previous one. */ + struct induction *induction; + for (induction = bl->biv; induction; induction = induction->next_iv) + if (location == induction->location) + { + v->same = induction; + break; + } + } /* Update IV_CLASS entry for this biv. */ v->next_iv = bl->biv; @@ -7834,11 +7865,12 @@ loop_iv_add_mult_emit_before (loop, b, m, a, reg, before_bb, before_insn) update_reg_last_use (b, before_insn); update_reg_last_use (m, before_insn); - loop_insn_emit_before (loop, before_bb, before_insn, seq); - /* It is possible that the expansion created lots of new registers. - Iterate over the sequence we just created and record them all. */ + Iterate over the sequence we just created and record them all. We + must do this before inserting the sequence. */ loop_regs_update (loop, seq); + + loop_insn_emit_before (loop, before_bb, before_insn, seq); } @@ -7863,11 +7895,12 @@ loop_iv_add_mult_sink (loop, b, m, a, reg) update_reg_last_use (b, loop->sink); update_reg_last_use (m, loop->sink); - loop_insn_sink (loop, seq); - /* It is possible that the expansion created lots of new registers. - Iterate over the sequence we just created and record them all. */ + Iterate over the sequence we just created and record them all. We + must do this before inserting the sequence. */ loop_regs_update (loop, seq); + + loop_insn_sink (loop, seq); } @@ -7886,11 +7919,12 @@ loop_iv_add_mult_hoist (loop, b, m, a, reg) /* Use copy_rtx to prevent unexpected sharing of these rtx. */ seq = gen_add_mult (copy_rtx (b), copy_rtx (m), copy_rtx (a), reg); - loop_insn_hoist (loop, seq); - /* It is possible that the expansion created lots of new registers. - Iterate over the sequence we just created and record them all. */ + Iterate over the sequence we just created and record them all. We + must do this before inserting the sequence. */ loop_regs_update (loop, seq); + + loop_insn_hoist (loop, seq); } @@ -8624,11 +8658,12 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count) enum rtx_code code = GET_CODE (p); basic_block where_bb = 0; rtx where_insn = threshold >= insn_count ? 0 : p; + rtx note; /* If this is a libcall that sets a giv, skip ahead to its end. */ if (GET_RTX_CLASS (code) == 'i') { - rtx note = find_reg_note (p, REG_LIBCALL, NULL_RTX); + note = find_reg_note (p, REG_LIBCALL, NULL_RTX); if (note) { @@ -8646,6 +8681,8 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count) } } } + + /* Closely examine the insn if the biv is mentioned. */ if ((code == INSN || code == JUMP_INSN || code == CALL_INSN) && reg_mentioned_p (reg, PATTERN (p)) && ! maybe_eliminate_biv_1 (loop, PATTERN (p), p, bl, @@ -8657,6 +8694,12 @@ maybe_eliminate_biv (loop, bl, eliminate_p, threshold, insn_count) bl->regno, INSN_UID (p)); break; } + + /* If we are eliminating, kill REG_EQUAL notes mentioning the biv. */ + if (eliminate_p + && (note = find_reg_note (p, REG_EQUAL, NULL_RTX)) != NULL_RTX + && reg_mentioned_p (reg, XEXP (note, 0))) + remove_note (p, note); } if (p == loop->end) @@ -9972,7 +10015,7 @@ load_mems (loop) else /* Replace the memory reference with the shadow register. */ replace_loop_mems (p, loop_info->mems[i].mem, - loop_info->mems[i].reg); + loop_info->mems[i].reg, written); } if (GET_CODE (p) == CODE_LABEL @@ -10345,6 +10388,33 @@ try_swap_copy_prop (loop, replacement, regno) } } +/* Worker function for find_mem_in_note, called via for_each_rtx. */ + +static int +find_mem_in_note_1 (x, data) + rtx *x; + void *data; +{ + if (*x != NULL_RTX && GET_CODE (*x) == MEM) + { + rtx *res = (rtx *) data; + *res = *x; + return 1; + } + return 0; +} + +/* Returns the first MEM found in NOTE by depth-first search. */ + +static rtx +find_mem_in_note (note) + rtx note; +{ + if (note && for_each_rtx (¬e, find_mem_in_note_1, ¬e)) + return note; + return NULL_RTX; +} + /* Replace MEM with its associated pseudo register. This function is called from load_mems via for_each_rtx. DATA is actually a pointer to a structure describing the instruction currently being scanned @@ -10387,10 +10457,11 @@ replace_loop_mem (mem, data) } static void -replace_loop_mems (insn, mem, reg) +replace_loop_mems (insn, mem, reg, written) rtx insn; rtx mem; rtx reg; + int written; { loop_replace_args args; @@ -10399,6 +10470,26 @@ replace_loop_mems (insn, mem, reg) args.replacement = reg; for_each_rtx (&insn, replace_loop_mem, &args); + + /* If we hoist a mem write out of the loop, then REG_EQUAL + notes referring to the mem are no longer valid. */ + if (written) + { + rtx note, sub; + rtx *link; + + for (link = ®_NOTES (insn); (note = *link); link = &XEXP (note, 1)) + { + if (REG_NOTE_KIND (note) == REG_EQUAL + && (sub = find_mem_in_note (note)) + && true_dependence (mem, VOIDmode, sub, rtx_varies_p)) + { + /* Remove the note. */ + validate_change (NULL_RTX, link, XEXP (note, 1), 1); + break; + } + } + } } /* Replace one register with another. Called through for_each_rtx; PX points |