From e8cb4873840fae2708dc58c13fbb9ff1e7bc1bc9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 7 Sep 2000 15:26:37 -0700 Subject: [PATCH] loop.c (strength_reduce): Call check_ext_dependant_givs. * loop.c (strength_reduce): Call check_ext_dependant_givs. Properly extend the biv initial value for the giv. (record_biv): Zero ext_dependant. (record_giv): New argument ext_val. Update all callers. (general_induction_var): Likewise. (consec_sets_giv): Likewise. (simplify_giv_expr): Likewise. Fill in ext_val if we find a sign-extend, zero-extend, or truncate. (combine_givs_p): Make sure modes are compatible. (check_ext_dependant_givs): New. (extend_value_for_giv): New. * loop.h (struct induction): Add ext_dependant. * unroll.c (iteration_info): Extend the biv initial value for the giv. (find_splittable_givs): Likewise. (final_giv_value): Likewise. From-SVN: r36250 --- gcc/ChangeLog | 28 +++- gcc/loop.c | 377 ++++++++++++++++++++++++++++++++++++++++++-------- gcc/loop.h | 5 +- gcc/unroll.c | 11 +- 4 files changed, 356 insertions(+), 65 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 628f6c78e9f..94d91d799e8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2000-09-07 Richard Henderson + + * loop.c (strength_reduce): Call check_ext_dependant_givs. + Properly extend the biv initial value for the giv. + (record_biv): Zero ext_dependant. + (record_giv): New argument ext_val. Update all callers. + (general_induction_var): Likewise. + (consec_sets_giv): Likewise. + (simplify_giv_expr): Likewise. Fill in ext_val if we find + a sign-extend, zero-extend, or truncate. + (combine_givs_p): Make sure modes are compatible. + (check_ext_dependant_givs): New. + (extend_value_for_giv): New. + * loop.h (struct induction): Add ext_dependant. + * unroll.c (iteration_info): Extend the biv initial value for the giv. + (find_splittable_givs): Likewise. + (final_giv_value): Likewise. + 2000-09-07 Zack Weinberg * c-pragma.h: Define HANDLE_GENERIC_PRAGMAS if @@ -64,9 +82,9 @@ Thu 07-Sep-2000 21:29:00 BST Neil Booth 2000-09-07 Catherine Moore - * unroll.c (unroll_loop): Check for unconditional jumps - to loop continuation. Delete if n_iterations is 1. - (ujump_to_loop_cont): New routine. + * unroll.c (unroll_loop): Check for unconditional jumps + to loop continuation. Delete if n_iterations is 1. + (ujump_to_loop_cont): New routine. 2000-09-07 Bernd Schmidt @@ -151,7 +169,7 @@ Thu 07-Sep-2000 21:29:00 BST Neil Booth 2000-09-06 Herman A.J. ten Brugge - * flow.c (insn_dead_p): Detect dead memory stores with auto increments. + * flow.c (insn_dead_p): Detect dead memory stores with auto increments. 2000-09-06 Kazu Hirata @@ -159,7 +177,7 @@ Thu 07-Sep-2000 21:29:00 BST Neil Booth 2000-09-06 Graham Stott - * config/i386/i386.h (ADDRESS_COST): Fix typo. + * config/i386/i386.h (ADDRESS_COST): Fix typo. 2000-09-06 Zack Weinberg diff --git a/gcc/loop.c b/gcc/loop.c index ce3494bd415..a7bba71cbe6 100644 --- a/gcc/loop.c +++ b/gcc/loop.c @@ -270,17 +270,20 @@ static void record_biv PARAMS ((struct induction *, rtx, rtx, rtx, rtx, rtx *, static void check_final_value PARAMS ((const struct loop *, struct induction *)); static void record_giv PARAMS ((const struct loop *, struct induction *, - rtx, rtx, rtx, rtx, rtx, int, enum g_types, - int, int, rtx *)); + rtx, rtx, rtx, rtx, rtx, rtx, int, + enum g_types, int, int, rtx *)); static void update_giv_derive PARAMS ((const struct loop *, rtx)); +static void check_ext_dependant_givs PARAMS ((struct iv_class *, + struct loop_info *)); static int basic_induction_var PARAMS ((const struct loop *, rtx, enum machine_mode, rtx, rtx, rtx *, rtx *, rtx **)); -static rtx simplify_giv_expr PARAMS ((const struct loop *, rtx, int *)); +static rtx simplify_giv_expr PARAMS ((const struct loop *, rtx, rtx *, int *)); static int general_induction_var PARAMS ((const struct loop *loop, rtx, rtx *, - rtx *, rtx *, int, int *, enum machine_mode)); + rtx *, rtx *, rtx *, int, int *, + enum machine_mode)); static int consec_sets_giv PARAMS ((const struct loop *, int, rtx, - rtx, rtx, rtx *, rtx *, rtx *)); + rtx, rtx, rtx *, rtx *, rtx *, rtx *)); static int check_dbra_loop PARAMS ((struct loop *, int)); static rtx express_from_1 PARAMS ((rtx, rtx, rtx)); static rtx combine_givs_p PARAMS ((struct induction *, struct induction *)); @@ -4412,6 +4415,10 @@ strength_reduce (loop, insn_count, flags) } } + /* Check each extension dependant giv in this class to see if its + root biv is safe from wrapping in the interior mode. */ + check_ext_dependant_givs (bl, loop_info); + /* Combine all giv's for this iv_class. */ combine_givs (bl); @@ -4733,8 +4740,9 @@ strength_reduce (loop, insn_count, flags) /* Add code at loop start to initialize giv's reduced reg. */ - emit_iv_add_mult (bl->initial_value, v->mult_val, - v->add_val, v->new_reg, loop_start); + emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value), + v->mult_val, v->add_val, v->new_reg, + loop_start); } } @@ -4799,8 +4807,9 @@ strength_reduce (loop, insn_count, flags) not replaceable. The correct final value is the same as the value that the giv starts the reversed loop with. */ if (bl->reversed && ! v->replaceable) - emit_iv_add_mult (bl->initial_value, v->mult_val, - v->add_val, v->dest_reg, end_insert_before); + emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value), + v->mult_val, v->add_val, v->dest_reg, + end_insert_before); else if (v->final_value) { rtx insert_before; @@ -5057,6 +5066,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple) rtx dest_reg; rtx add_val; rtx mult_val; + rtx ext_val; int benefit; rtx regnote = 0; rtx last_consec_insn; @@ -5067,11 +5077,11 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple) if (/* SET_SRC is a giv. */ (general_induction_var (loop, SET_SRC (set), &src_reg, &add_val, - &mult_val, 0, &benefit, VOIDmode) + &mult_val, &ext_val, 0, &benefit, VOIDmode) /* Equivalent expression is a giv. */ || ((regnote = find_reg_note (p, REG_EQUAL, NULL_RTX)) && general_induction_var (loop, XEXP (regnote, 0), &src_reg, - &add_val, &mult_val, 0, + &add_val, &mult_val, &ext_val, 0, &benefit, VOIDmode))) /* Don't try to handle any regs made by loop optimization. We have nothing on them in regno_first_uid, etc. */ @@ -5083,7 +5093,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple) /* or all sets must be consecutive and make a giv. */ || (benefit = consec_sets_giv (loop, benefit, p, src_reg, dest_reg, - &add_val, &mult_val, + &add_val, &mult_val, &ext_val, &last_consec_insn)))) { struct induction *v @@ -5098,7 +5108,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple) p = last_consec_insn; record_giv (loop, v, p, src_reg, dest_reg, mult_val, add_val, - benefit, DEST_REG, not_every_iteration, + ext_val, benefit, DEST_REG, not_every_iteration, maybe_multiple, NULL_PTR); } @@ -5202,6 +5212,7 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple) rtx src_reg; rtx add_val; rtx mult_val; + rtx ext_val; int benefit; /* This code used to disable creating GIVs with mult_val == 1 and @@ -5210,15 +5221,16 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple) this one would not be seen. */ if (general_induction_var (loop, XEXP (x, 0), &src_reg, &add_val, - &mult_val, 1, &benefit, GET_MODE (x))) + &mult_val, &ext_val, 1, &benefit, + GET_MODE (x))) { /* Found one; record it. */ struct induction *v = (struct induction *) oballoc (sizeof (struct induction)); record_giv (loop, v, insn, src_reg, addr_placeholder, mult_val, - add_val, benefit, DEST_ADDR, not_every_iteration, - maybe_multiple, &XEXP (x, 0)); + add_val, ext_val, benefit, DEST_ADDR, + not_every_iteration, maybe_multiple, &XEXP (x, 0)); v->mem_mode = GET_MODE (x); } @@ -5277,6 +5289,7 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location, v->dest_reg = dest_reg; v->mult_val = mult_val; v->add_val = inc_val; + v->ext_dependant = NULL_RTX; v->location = location; v->mode = GET_MODE (dest_reg); v->always_computable = ! not_every_iteration; @@ -5360,14 +5373,14 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location, LOCATION points to the place where this giv's value appears in INSN. */ static void -record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit, - type, not_every_iteration, maybe_multiple, location) +record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val, + benefit, type, not_every_iteration, maybe_multiple, location) const struct loop *loop; struct induction *v; rtx insn; rtx src_reg; rtx dest_reg; - rtx mult_val, add_val; + rtx mult_val, add_val, ext_val; int benefit; enum g_types type; int not_every_iteration, maybe_multiple; @@ -5389,6 +5402,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit, v->dest_reg = dest_reg; v->mult_val = mult_val; v->add_val = add_val; + v->ext_dependant = ext_val; v->benefit = benefit; v->location = location; v->cant_derive = 0; @@ -5577,6 +5591,24 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit, if (v->no_const_addval) fprintf (loop_dump_stream, " ncav"); + if (v->ext_dependant) + { + switch (GET_CODE (v->ext_dependant)) + { + case SIGN_EXTEND: + fprintf (loop_dump_stream, " ext se"); + break; + case ZERO_EXTEND: + fprintf (loop_dump_stream, " ext ze"); + break; + case TRUNCATE: + fprintf (loop_dump_stream, " ext tr"); + break; + default: + abort (); + } + } + if (GET_CODE (mult_val) == CONST_INT) { fprintf (loop_dump_stream, " mult "); @@ -5825,20 +5857,21 @@ update_giv_derive (loop, p) be able to compute a compensation. */ else if (biv->insn == p) { - tem = 0; + rtx ext_val_dummy; + tem = 0; if (biv->mult_val == const1_rtx) tem = simplify_giv_expr (loop, gen_rtx_MULT (giv->mode, biv->add_val, giv->mult_val), - &dummy); + &ext_val_dummy, &dummy); if (tem && giv->derive_adjustment) tem = simplify_giv_expr (loop, gen_rtx_PLUS (giv->mode, tem, giv->derive_adjustment), - &dummy); + &ext_val_dummy, &dummy); if (tem) giv->derive_adjustment = tem; @@ -6058,13 +6091,14 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location) such that the value of X is biv * mult + add; */ static int -general_induction_var (loop, x, src_reg, add_val, mult_val, is_addr, - pbenefit, addr_mode) +general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val, + is_addr, pbenefit, addr_mode) const struct loop *loop; rtx x; rtx *src_reg; rtx *add_val; rtx *mult_val; + rtx *ext_val; int is_addr; int *pbenefit; enum machine_mode addr_mode; @@ -6080,7 +6114,8 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, is_addr, Mark our place on the obstack in case we don't find a giv. */ storage = (char *) oballoc (0); *pbenefit = 0; - x = simplify_giv_expr (loop, x, pbenefit); + *ext_val = NULL_RTX; + x = simplify_giv_expr (loop, x, ext_val, pbenefit); if (x == 0) { obfree (storage); @@ -6177,9 +6212,10 @@ static int cmp_combine_givs_stats PARAMS ((const PTR, const PTR)); static int cmp_recombine_givs_stats PARAMS ((const PTR, const PTR)); static rtx -simplify_giv_expr (loop, x, benefit) +simplify_giv_expr (loop, x, ext_val, benefit) const struct loop *loop; rtx x; + rtx *ext_val; int *benefit; { enum machine_mode mode = GET_MODE (x); @@ -6196,8 +6232,8 @@ simplify_giv_expr (loop, x, benefit) switch (GET_CODE (x)) { case PLUS: - arg0 = simplify_giv_expr (loop, XEXP (x, 0), benefit); - arg1 = simplify_giv_expr (loop, XEXP (x, 1), benefit); + arg0 = simplify_giv_expr (loop, XEXP (x, 0), ext_val, benefit); + arg1 = simplify_giv_expr (loop, XEXP (x, 1), ext_val, benefit); if (arg0 == 0 || arg1 == 0) return NULL_RTX; @@ -6249,7 +6285,7 @@ simplify_giv_expr (loop, x, benefit) gen_rtx_PLUS (mode, XEXP (arg0, 1), arg1)), - benefit); + ext_val, benefit); default: abort (); @@ -6275,7 +6311,7 @@ simplify_giv_expr (loop, x, benefit) gen_rtx_PLUS (mode, arg0, XEXP (arg1, 0)), XEXP (arg1, 1)), - benefit); + ext_val, benefit); /* Now must have MULT + MULT. Distribute if same biv, else not giv. */ if (GET_CODE (arg0) != MULT || GET_CODE (arg1) != MULT) @@ -6290,7 +6326,7 @@ simplify_giv_expr (loop, x, benefit) gen_rtx_PLUS (mode, XEXP (arg0, 1), XEXP (arg1, 1))), - benefit); + ext_val, benefit); case MINUS: /* Handle "a - b" as "a + b * (-1)". */ @@ -6300,11 +6336,11 @@ simplify_giv_expr (loop, x, benefit) gen_rtx_MULT (mode, XEXP (x, 1), constm1_rtx)), - benefit); + ext_val, benefit); case MULT: - arg0 = simplify_giv_expr (loop, XEXP (x, 0), benefit); - arg1 = simplify_giv_expr (loop, XEXP (x, 1), benefit); + arg0 = simplify_giv_expr (loop, XEXP (x, 0), ext_val, benefit); + arg1 = simplify_giv_expr (loop, XEXP (x, 1), ext_val, benefit); if (arg0 == 0 || arg1 == 0) return NULL_RTX; @@ -6350,7 +6386,7 @@ simplify_giv_expr (loop, x, benefit) XEXP (arg0, 1), arg1)), - benefit); + ext_val, benefit); } /* Porpagate the MULT expressions to the intermost nodes. */ else if (GET_CODE (arg0) == PLUS) @@ -6366,7 +6402,7 @@ simplify_giv_expr (loop, x, benefit) XEXP (arg0, 1), arg1)), - benefit); + ext_val, benefit); } return gen_rtx_USE (mode, gen_rtx_MULT (mode, arg0, arg1)); @@ -6378,7 +6414,7 @@ simplify_giv_expr (loop, x, benefit) gen_rtx_MULT (mode, XEXP (arg0, 1), arg1)), - benefit); + ext_val, benefit); case PLUS: /* (a + invar_1) * invar_2. Distribute. */ @@ -6390,7 +6426,7 @@ simplify_giv_expr (loop, x, benefit) gen_rtx_MULT (mode, XEXP (arg0, 1), arg1)), - benefit); + ext_val, benefit); default: abort (); @@ -6407,13 +6443,13 @@ simplify_giv_expr (loop, x, benefit) XEXP (x, 0), GEN_INT ((HOST_WIDE_INT) 1 << INTVAL (XEXP (x, 1)))), - benefit); + ext_val, benefit); case NEG: /* "-a" is "a * (-1)" */ return simplify_giv_expr (loop, gen_rtx_MULT (mode, XEXP (x, 0), constm1_rtx), - benefit); + ext_val, benefit); case NOT: /* "~a" is "-a - 1". Silly, but easy. */ @@ -6421,13 +6457,30 @@ simplify_giv_expr (loop, x, benefit) gen_rtx_MINUS (mode, gen_rtx_NEG (mode, XEXP (x, 0)), const1_rtx), - benefit); + ext_val, benefit); case USE: /* Already in proper form for invariant. */ return x; - case REG: + case SIGN_EXTEND: + case ZERO_EXTEND: + case TRUNCATE: + /* Conditionally recognize extensions of simple IVs. After we've + computed loop traversal counts and verified the range of the + source IV, we'll reevaluate this as a GIV. */ + if (*ext_val == NULL_RTX) + { + arg0 = simplify_giv_expr (loop, XEXP (x, 0), ext_val, benefit); + if (arg0 && *ext_val == NULL_RTX && GET_CODE (arg0) == REG) + { + *ext_val = gen_rtx_fmt_e (GET_CODE (x), mode, arg0); + return arg0; + } + } + goto do_default; + + case REG: /* If this is a new register, we can't deal with it. */ if (REGNO (x) >= max_reg_before_loop) return 0; @@ -6466,10 +6519,22 @@ simplify_giv_expr (loop, x, benefit) if (v->derive_adjustment) tem = gen_rtx_MINUS (mode, tem, v->derive_adjustment); - return simplify_giv_expr (loop, tem, benefit); + arg0 = simplify_giv_expr (loop, tem, ext_val, benefit); + if (*ext_val) + { + if (!v->ext_dependant) + return arg0; + } + else + { + *ext_val = v->ext_dependant; + return arg0; + } + return 0; } default: + do_default: /* If it isn't an induction variable, and it is invariant, we may be able to simplify things further by looking through the bits we just moved outside the loop. */ @@ -6486,7 +6551,7 @@ simplify_giv_expr (loop, x, benefit) this one is going away. */ if (m->match) return simplify_giv_expr (loop, m->match->set_dest, - benefit); + ext_val, benefit); /* If consec is non-zero, this is a member of a group of instructions that were moved together. We handle this @@ -6520,7 +6585,8 @@ simplify_giv_expr (loop, x, benefit) || GET_CODE (tem) == CONST_INT || GET_CODE (tem) == SYMBOL_REF) { - tem = simplify_giv_expr (loop, tem, benefit); + tem = simplify_giv_expr (loop, tem, ext_val, + benefit); if (tem) return tem; } @@ -6530,7 +6596,7 @@ simplify_giv_expr (loop, x, benefit) && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT) { tem = simplify_giv_expr (loop, XEXP (tem, 0), - benefit); + ext_val, benefit); if (tem) return tem; } @@ -6635,7 +6701,7 @@ sge_plus (mode, x, y) static int consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg, - add_val, mult_val, last_consec_insn) + add_val, mult_val, ext_val, last_consec_insn) const struct loop *loop; int first_benefit; rtx p; @@ -6643,6 +6709,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg, rtx dest_reg; rtx *add_val; rtx *mult_val; + rtx *ext_val; rtx *last_consec_insn; { int count; @@ -6666,6 +6733,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg, v->benefit = first_benefit; v->cant_derive = 0; v->derive_adjustment = 0; + v->ext_dependant = NULL_RTX; REG_IV_TYPE (REGNO (dest_reg)) = GENERAL_INDUCT; REG_IV_INFO (REGNO (dest_reg)) = v; @@ -6686,12 +6754,13 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg, && GET_CODE (SET_DEST (set)) == REG && SET_DEST (set) == dest_reg && (general_induction_var (loop, SET_SRC (set), &src_reg, - add_val, mult_val, 0, &benefit, VOIDmode) + add_val, mult_val, ext_val, 0, + &benefit, VOIDmode) /* Giv created by equivalent expression. */ || ((temp = find_reg_note (p, REG_EQUAL, NULL_RTX)) && general_induction_var (loop, XEXP (temp, 0), &src_reg, - add_val, mult_val, 0, &benefit, - VOIDmode))) + add_val, mult_val, ext_val, 0, + &benefit, VOIDmode))) && src_reg == v->src_reg) { if (find_reg_note (p, REG_RETVAL, NULL_RTX)) @@ -6921,25 +6990,36 @@ static rtx combine_givs_p (g1, g2) struct induction *g1, *g2; { - rtx tem = express_from (g1, g2); + rtx comb, ret; + + /* With the introduction of ext dependant givs, we must care for modes. + G2 must not use a wider mode than G1. */ + if (GET_MODE_SIZE (g1->mode) < GET_MODE_SIZE (g2->mode)) + return NULL_RTX; + + ret = comb = express_from (g1, g2); + if (comb == NULL_RTX) + return NULL_RTX; + if (g1->mode != g2->mode) + ret = gen_lowpart (g2->mode, comb); /* If these givs are identical, they can be combined. We use the results of express_from because the addends are not in a canonical form, so rtx_equal_p is a weaker test. */ /* But don't combine a DEST_REG giv with a DEST_ADDR giv; we want the combination to be the other way round. */ - if (tem == g1->dest_reg + if (comb == g1->dest_reg && (g1->giv_type == DEST_REG || g2->giv_type == DEST_ADDR)) { - return g1->dest_reg; + return ret; } /* If G2 can be expressed as a function of G1 and that function is valid as an address and no more expensive than using a register for G2, the expression of G2 in terms of G1 can be used. */ - if (tem != NULL_RTX + if (ret != NULL_RTX && g2->giv_type == DEST_ADDR - && memory_address_p (g2->mem_mode, tem) + && memory_address_p (g2->mem_mode, ret) /* ??? Looses, especially with -fforce-addr, where *g2->location will always be a register, and so anything more complicated gets discarded. */ @@ -6952,12 +7032,197 @@ combine_givs_p (g1, g2) #endif ) { - return tem; + return ret; } return NULL_RTX; } +/* Check each extension dependant giv in this class to see if its + root biv is safe from wrapping in the interior mode, which would + make the giv illegal. */ + +static void +check_ext_dependant_givs (bl, loop_info) + struct iv_class *bl; + struct loop_info *loop_info; +{ + int ze_ok = 0, se_ok = 0, info_ok = 0; + enum machine_mode biv_mode = GET_MODE (bl->biv->src_reg); + HOST_WIDE_INT start_val; + unsigned HOST_WIDE_INT u_end_val, u_start_val; + rtx incr = pc_rtx; + struct induction *v; + + /* Make sure the iteration data is available. We must have + constants in order to be certain of no overflow. */ + /* ??? An unknown iteration count with an increment of +-1 + combined with friendly exit tests of against an invariant + value is also ameanable to optimization. Not implemented. */ + if (loop_info->n_iterations > 0 + && bl->initial_value + && GET_CODE (bl->initial_value) == CONST_INT + && (incr = biv_total_increment (bl)) + && GET_CODE (incr) == CONST_INT + /* Make sure the host can represent the arithmetic. */ + && HOST_BITS_PER_WIDE_INT >= GET_MODE_BITSIZE (biv_mode)) + { + unsigned HOST_WIDE_INT abs_incr, total_incr; + HOST_WIDE_INT s_end_val; + int neg_incr; + + info_ok = 1; + start_val = INTVAL (bl->initial_value); + u_start_val = start_val; + + neg_incr = 0, abs_incr = INTVAL (incr); + if (INTVAL (incr) < 0) + neg_incr = 1, abs_incr = -abs_incr; + total_incr = abs_incr * loop_info->n_iterations; + + /* Check for host arithmatic overflow. */ + if (total_incr / loop_info->n_iterations == abs_incr) + { + unsigned HOST_WIDE_INT u_max; + HOST_WIDE_INT s_max; + + u_end_val = start_val + (neg_incr ? -total_incr : total_incr); + s_end_val = u_end_val; + u_max = GET_MODE_MASK (biv_mode); + s_max = u_max >> 1; + + /* Check zero extension of biv ok. */ + if (start_val >= 0 + /* Check for host arithmatic overflow. */ + && (neg_incr + ? u_end_val < u_start_val + : u_end_val > u_start_val) + /* Check for target arithmetic overflow. */ + && (neg_incr + ? 1 /* taken care of with host overflow */ + : u_end_val <= u_max)) + { + ze_ok = 1; + } + + /* Check sign extension of biv ok. */ + /* ??? While it is true that overflow with signed and pointer + arithmetic is undefined, I fear too many programmers don't + keep this fact in mind -- myself included on occasion. + So leave alone with the signed overflow optimizations. */ + if (start_val >= -s_max - 1 + /* Check for host arithmatic overflow. */ + && (neg_incr + ? s_end_val < start_val + : s_end_val > start_val) + /* Check for target arithmetic overflow. */ + && (neg_incr + ? s_end_val >= -s_max - 1 + : s_end_val <= s_max)) + { + se_ok = 1; + } + } + } + + /* Invalidate givs that fail the tests. */ + for (v = bl->giv; v; v = v->next_iv) + if (v->ext_dependant) + { + enum rtx_code code = GET_CODE (v->ext_dependant); + int ok = 0; + + switch (code) + { + case SIGN_EXTEND: + ok = se_ok; + break; + case ZERO_EXTEND: + ok = ze_ok; + break; + + case TRUNCATE: + /* We don't know whether this value is being used as either + signed or unsigned, so to safely truncate we must satisfy + both. The initial check here verifies the BIV itself; + once that is successful we may check its range wrt the + derived GIV. */ + if (se_ok && ze_ok) + { + enum machine_mode outer_mode = GET_MODE (v->ext_dependant); + unsigned HOST_WIDE_INT max = GET_MODE_MASK (outer_mode) >> 1; + + /* We know from the above that both endpoints are nonnegative, + and that there is no wrapping. Verify that both endpoints + are within the (signed) range of the outer mode. */ + if (u_start_val <= max && u_end_val <= max) + ok = 1; + } + break; + + default: + abort (); + } + + if (ok) + { + if (loop_dump_stream) + { + fprintf(loop_dump_stream, + "Verified ext dependant giv at %d of reg %d\n", + INSN_UID (v->insn), bl->regno); + } + } + else + { + if (loop_dump_stream) + { + const char *why; + + if (info_ok) + why = "biv iteration values overflowed"; + else + { + if (incr == pc_rtx) + incr = biv_total_increment (bl); + if (incr == const1_rtx) + why = "biv iteration info incomplete; incr by 1"; + else + why = "biv iteration info incomplete"; + } + + fprintf(loop_dump_stream, + "Failed ext dependant giv at %d, %s\n", + INSN_UID (v->insn), why); + } + v->ignore = 1; + } + } +} + +/* Generate a version of VALUE in a mode appropriate for initializing V. */ + +rtx +extend_value_for_giv (v, value) + struct induction *v; + rtx value; +{ + rtx ext_dep = v->ext_dependant; + + if (! ext_dep) + return value; + + /* Recall that check_ext_dependant_givs verified that the known bounds + of a biv did not overflow or wrap with respect to the extension for + the giv. Therefore, constants need no additional adjustment. */ + if (CONSTANT_P (value) && GET_MODE (value) == VOIDmode) + return value; + + /* Otherwise, we must adjust the value to compensate for the + differing modes of the biv and the giv. */ + return gen_rtx_fmt_e (GET_CODE (ext_dep), GET_MODE (ext_dep), value); +} + struct combine_givs_stats { int giv_number; diff --git a/gcc/loop.h b/gcc/loop.h index 7d4c7cea41a..1bc9a35ae63 100644 --- a/gcc/loop.h +++ b/gcc/loop.h @@ -115,6 +115,8 @@ struct induction subtracted from add_val when this giv derives another. This occurs when the giv spans a biv update by incrementation. */ + rtx ext_dependant; /* If nonzero, is a sign or zero extension + if a biv on which this giv is dependant. */ struct induction *next_iv; /* For givs, links together all givs that are based on the same biv. For bivs, links together all biv entries that refer to the @@ -238,6 +240,7 @@ int loop_invariant_p PARAMS ((const struct loop *, rtx)); rtx get_condition_for_loop PARAMS ((const struct loop *, rtx)); void emit_iv_add_mult PARAMS ((rtx, rtx, rtx, rtx, rtx)); rtx express_from PARAMS ((struct induction *, struct induction *)); +rtx extend_value_for_giv PARAMS ((struct induction *, rtx)); void unroll_loop PARAMS ((struct loop *, int, rtx, int)); rtx biv_total_increment PARAMS ((struct iv_class *)); @@ -251,7 +254,7 @@ void emit_unrolled_add PARAMS ((rtx, rtx, rtx)); int back_branch_in_range_p PARAMS ((const struct loop *, rtx)); int loop_insn_first_p PARAMS ((rtx, rtx)); -typedef rtx (*loop_insn_callback ) PARAMS ((struct loop *, rtx, int, int)); +typedef rtx (*loop_insn_callback) PARAMS ((struct loop *, rtx, int, int)); void for_each_insn_in_loop PARAMS ((struct loop *, loop_insn_callback)); /* Forward declarations for non-static functions declared in doloop.c. */ diff --git a/gcc/unroll.c b/gcc/unroll.c index 36e6c57b9f8..51a469dcb48 100644 --- a/gcc/unroll.c +++ b/gcc/unroll.c @@ -2495,6 +2495,7 @@ iteration_info (loop, iteration_var, initial_value, increment) { HOST_WIDE_INT offset = 0; struct induction *v = REG_IV_INFO (REGNO (iteration_var)); + rtx biv_initial_value; if (REGNO (v->src_reg) >= max_reg_before_loop) abort (); @@ -2527,11 +2528,13 @@ iteration_info (loop, iteration_var, initial_value, increment) fprintf (loop_dump_stream, "Loop unrolling: Giv iterator, initial value bias %ld.\n", (long) offset); + /* Initial value is mult_val times the biv's initial value plus add_val. Only useful if it is a constant. */ + biv_initial_value = extend_value_for_giv (v, bl->initial_value); *initial_value = fold_rtx_mult_add (v->mult_val, - plus_constant (bl->initial_value, offset), + plus_constant (biv_initial_value, offset), v->add_val, v->mode); } else @@ -2895,6 +2898,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number) loop->start); biv_initial_value = tem; } + biv_initial_value = extend_value_for_giv (v, biv_initial_value); value = fold_rtx_mult_add (v->mult_val, biv_initial_value, v->add_val, v->mode); } @@ -3456,10 +3460,11 @@ final_giv_value (loop, v) insert_before = NEXT_INSN (loop_end); /* Put the final biv value in tem. */ - tem = gen_reg_rtx (bl->biv->mode); + tem = gen_reg_rtx (v->mode); record_base_value (REGNO (tem), bl->biv->add_val, 0); emit_iv_add_mult (increment, GEN_INT (n_iterations), - bl->initial_value, tem, insert_before); + extend_value_for_giv (v, bl->initial_value), + tem, insert_before); /* Subtract off extra increments as we find them. */ for (insn = NEXT_INSN (v->insn); insn != loop_end;