Commit e8cb4873 by Richard Henderson

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
parent 8b97c5f8
2000-09-07 Richard Henderson <rth@cygnus.com>
* 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 <zack@wolery.cumb.org> 2000-09-07 Zack Weinberg <zack@wolery.cumb.org>
* c-pragma.h: Define HANDLE_GENERIC_PRAGMAS if * c-pragma.h: Define HANDLE_GENERIC_PRAGMAS if
...@@ -64,9 +82,9 @@ Thu 07-Sep-2000 21:29:00 BST Neil Booth <NeilB@earthling.net> ...@@ -64,9 +82,9 @@ Thu 07-Sep-2000 21:29:00 BST Neil Booth <NeilB@earthling.net>
2000-09-07 Catherine Moore <clm@redhat.com> 2000-09-07 Catherine Moore <clm@redhat.com>
* unroll.c (unroll_loop): Check for unconditional jumps * unroll.c (unroll_loop): Check for unconditional jumps
to loop continuation. Delete if n_iterations is 1. to loop continuation. Delete if n_iterations is 1.
(ujump_to_loop_cont): New routine. (ujump_to_loop_cont): New routine.
2000-09-07 Bernd Schmidt <bernds@redhat.co.uk> 2000-09-07 Bernd Schmidt <bernds@redhat.co.uk>
...@@ -151,7 +169,7 @@ Thu 07-Sep-2000 21:29:00 BST Neil Booth <NeilB@earthling.net> ...@@ -151,7 +169,7 @@ Thu 07-Sep-2000 21:29:00 BST Neil Booth <NeilB@earthling.net>
2000-09-06 Herman A.J. ten Brugge <Haj.Ten.Brugge@net.HCC.nl> 2000-09-06 Herman A.J. ten Brugge <Haj.Ten.Brugge@net.HCC.nl>
* 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 <kazu@hxi.com> 2000-09-06 Kazu Hirata <kazu@hxi.com>
...@@ -159,7 +177,7 @@ Thu 07-Sep-2000 21:29:00 BST Neil Booth <NeilB@earthling.net> ...@@ -159,7 +177,7 @@ Thu 07-Sep-2000 21:29:00 BST Neil Booth <NeilB@earthling.net>
2000-09-06 Graham Stott <grahams@cygnus.co.uk> 2000-09-06 Graham Stott <grahams@cygnus.co.uk>
* config/i386/i386.h (ADDRESS_COST): Fix typo. * config/i386/i386.h (ADDRESS_COST): Fix typo.
2000-09-06 Zack Weinberg <zack@wolery.cumb.org> 2000-09-06 Zack Weinberg <zack@wolery.cumb.org>
......
...@@ -270,17 +270,20 @@ static void record_biv PARAMS ((struct induction *, rtx, rtx, rtx, rtx, rtx *, ...@@ -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 *, static void check_final_value PARAMS ((const struct loop *,
struct induction *)); struct induction *));
static void record_giv 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, rtx, rtx, rtx, rtx, rtx, rtx, int,
int, int, rtx *)); enum g_types, int, int, rtx *));
static void update_giv_derive PARAMS ((const struct loop *, 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, static int basic_induction_var PARAMS ((const struct loop *, rtx,
enum machine_mode, rtx, rtx, enum machine_mode, rtx, rtx,
rtx *, 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 *, 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, 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 int check_dbra_loop PARAMS ((struct loop *, int));
static rtx express_from_1 PARAMS ((rtx, rtx, rtx)); static rtx express_from_1 PARAMS ((rtx, rtx, rtx));
static rtx combine_givs_p PARAMS ((struct induction *, struct induction *)); static rtx combine_givs_p PARAMS ((struct induction *, struct induction *));
...@@ -4412,6 +4415,10 @@ strength_reduce (loop, insn_count, flags) ...@@ -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 all giv's for this iv_class. */
combine_givs (bl); combine_givs (bl);
...@@ -4733,8 +4740,9 @@ strength_reduce (loop, insn_count, flags) ...@@ -4733,8 +4740,9 @@ strength_reduce (loop, insn_count, flags)
/* Add code at loop start to initialize giv's reduced reg. */ /* Add code at loop start to initialize giv's reduced reg. */
emit_iv_add_mult (bl->initial_value, v->mult_val, emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value),
v->add_val, v->new_reg, loop_start); v->mult_val, v->add_val, v->new_reg,
loop_start);
} }
} }
...@@ -4799,8 +4807,9 @@ strength_reduce (loop, insn_count, flags) ...@@ -4799,8 +4807,9 @@ strength_reduce (loop, insn_count, flags)
not replaceable. The correct final value is the same as the not replaceable. The correct final value is the same as the
value that the giv starts the reversed loop with. */ value that the giv starts the reversed loop with. */
if (bl->reversed && ! v->replaceable) if (bl->reversed && ! v->replaceable)
emit_iv_add_mult (bl->initial_value, v->mult_val, emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value),
v->add_val, v->dest_reg, end_insert_before); v->mult_val, v->add_val, v->dest_reg,
end_insert_before);
else if (v->final_value) else if (v->final_value)
{ {
rtx insert_before; rtx insert_before;
...@@ -5057,6 +5066,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple) ...@@ -5057,6 +5066,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
rtx dest_reg; rtx dest_reg;
rtx add_val; rtx add_val;
rtx mult_val; rtx mult_val;
rtx ext_val;
int benefit; int benefit;
rtx regnote = 0; rtx regnote = 0;
rtx last_consec_insn; rtx last_consec_insn;
...@@ -5067,11 +5077,11 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple) ...@@ -5067,11 +5077,11 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
if (/* SET_SRC is a giv. */ if (/* SET_SRC is a giv. */
(general_induction_var (loop, SET_SRC (set), &src_reg, &add_val, (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. */ /* Equivalent expression is a giv. */
|| ((regnote = find_reg_note (p, REG_EQUAL, NULL_RTX)) || ((regnote = find_reg_note (p, REG_EQUAL, NULL_RTX))
&& general_induction_var (loop, XEXP (regnote, 0), &src_reg, && general_induction_var (loop, XEXP (regnote, 0), &src_reg,
&add_val, &mult_val, 0, &add_val, &mult_val, &ext_val, 0,
&benefit, VOIDmode))) &benefit, VOIDmode)))
/* Don't try to handle any regs made by loop optimization. /* Don't try to handle any regs made by loop optimization.
We have nothing on them in regno_first_uid, etc. */ 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) ...@@ -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. */ /* or all sets must be consecutive and make a giv. */
|| (benefit = consec_sets_giv (loop, benefit, p, || (benefit = consec_sets_giv (loop, benefit, p,
src_reg, dest_reg, src_reg, dest_reg,
&add_val, &mult_val, &add_val, &mult_val, &ext_val,
&last_consec_insn)))) &last_consec_insn))))
{ {
struct induction *v struct induction *v
...@@ -5098,7 +5108,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple) ...@@ -5098,7 +5108,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
p = last_consec_insn; p = last_consec_insn;
record_giv (loop, v, p, src_reg, dest_reg, mult_val, add_val, 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); maybe_multiple, NULL_PTR);
} }
...@@ -5202,6 +5212,7 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple) ...@@ -5202,6 +5212,7 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
rtx src_reg; rtx src_reg;
rtx add_val; rtx add_val;
rtx mult_val; rtx mult_val;
rtx ext_val;
int benefit; int benefit;
/* This code used to disable creating GIVs with mult_val == 1 and /* 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) ...@@ -5210,15 +5221,16 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
this one would not be seen. */ this one would not be seen. */
if (general_induction_var (loop, XEXP (x, 0), &src_reg, &add_val, 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. */ /* Found one; record it. */
struct induction *v struct induction *v
= (struct induction *) oballoc (sizeof (struct induction)); = (struct induction *) oballoc (sizeof (struct induction));
record_giv (loop, v, insn, src_reg, addr_placeholder, mult_val, record_giv (loop, v, insn, src_reg, addr_placeholder, mult_val,
add_val, benefit, DEST_ADDR, not_every_iteration, add_val, ext_val, benefit, DEST_ADDR,
maybe_multiple, &XEXP (x, 0)); not_every_iteration, maybe_multiple, &XEXP (x, 0));
v->mem_mode = GET_MODE (x); v->mem_mode = GET_MODE (x);
} }
...@@ -5277,6 +5289,7 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location, ...@@ -5277,6 +5289,7 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
v->dest_reg = dest_reg; v->dest_reg = dest_reg;
v->mult_val = mult_val; v->mult_val = mult_val;
v->add_val = inc_val; v->add_val = inc_val;
v->ext_dependant = NULL_RTX;
v->location = location; v->location = location;
v->mode = GET_MODE (dest_reg); v->mode = GET_MODE (dest_reg);
v->always_computable = ! not_every_iteration; v->always_computable = ! not_every_iteration;
...@@ -5360,14 +5373,14 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location, ...@@ -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. */ LOCATION points to the place where this giv's value appears in INSN. */
static void static void
record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit, record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
type, not_every_iteration, maybe_multiple, location) benefit, type, not_every_iteration, maybe_multiple, location)
const struct loop *loop; const struct loop *loop;
struct induction *v; struct induction *v;
rtx insn; rtx insn;
rtx src_reg; rtx src_reg;
rtx dest_reg; rtx dest_reg;
rtx mult_val, add_val; rtx mult_val, add_val, ext_val;
int benefit; int benefit;
enum g_types type; enum g_types type;
int not_every_iteration, maybe_multiple; int not_every_iteration, maybe_multiple;
...@@ -5389,6 +5402,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit, ...@@ -5389,6 +5402,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
v->dest_reg = dest_reg; v->dest_reg = dest_reg;
v->mult_val = mult_val; v->mult_val = mult_val;
v->add_val = add_val; v->add_val = add_val;
v->ext_dependant = ext_val;
v->benefit = benefit; v->benefit = benefit;
v->location = location; v->location = location;
v->cant_derive = 0; v->cant_derive = 0;
...@@ -5577,6 +5591,24 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit, ...@@ -5577,6 +5591,24 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
if (v->no_const_addval) if (v->no_const_addval)
fprintf (loop_dump_stream, " ncav"); 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) if (GET_CODE (mult_val) == CONST_INT)
{ {
fprintf (loop_dump_stream, " mult "); fprintf (loop_dump_stream, " mult ");
...@@ -5825,20 +5857,21 @@ update_giv_derive (loop, p) ...@@ -5825,20 +5857,21 @@ update_giv_derive (loop, p)
be able to compute a compensation. */ be able to compute a compensation. */
else if (biv->insn == p) else if (biv->insn == p)
{ {
tem = 0; rtx ext_val_dummy;
tem = 0;
if (biv->mult_val == const1_rtx) if (biv->mult_val == const1_rtx)
tem = simplify_giv_expr (loop, tem = simplify_giv_expr (loop,
gen_rtx_MULT (giv->mode, gen_rtx_MULT (giv->mode,
biv->add_val, biv->add_val,
giv->mult_val), giv->mult_val),
&dummy); &ext_val_dummy, &dummy);
if (tem && giv->derive_adjustment) if (tem && giv->derive_adjustment)
tem = simplify_giv_expr tem = simplify_giv_expr
(loop, (loop,
gen_rtx_PLUS (giv->mode, tem, giv->derive_adjustment), gen_rtx_PLUS (giv->mode, tem, giv->derive_adjustment),
&dummy); &ext_val_dummy, &dummy);
if (tem) if (tem)
giv->derive_adjustment = tem; giv->derive_adjustment = tem;
...@@ -6058,13 +6091,14 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location) ...@@ -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; */ such that the value of X is biv * mult + add; */
static int static int
general_induction_var (loop, x, src_reg, add_val, mult_val, is_addr, general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
pbenefit, addr_mode) is_addr, pbenefit, addr_mode)
const struct loop *loop; const struct loop *loop;
rtx x; rtx x;
rtx *src_reg; rtx *src_reg;
rtx *add_val; rtx *add_val;
rtx *mult_val; rtx *mult_val;
rtx *ext_val;
int is_addr; int is_addr;
int *pbenefit; int *pbenefit;
enum machine_mode addr_mode; enum machine_mode addr_mode;
...@@ -6080,7 +6114,8 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, is_addr, ...@@ -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. */ Mark our place on the obstack in case we don't find a giv. */
storage = (char *) oballoc (0); storage = (char *) oballoc (0);
*pbenefit = 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) if (x == 0)
{ {
obfree (storage); obfree (storage);
...@@ -6177,9 +6212,10 @@ static int cmp_combine_givs_stats PARAMS ((const PTR, const PTR)); ...@@ -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 int cmp_recombine_givs_stats PARAMS ((const PTR, const PTR));
static rtx static rtx
simplify_giv_expr (loop, x, benefit) simplify_giv_expr (loop, x, ext_val, benefit)
const struct loop *loop; const struct loop *loop;
rtx x; rtx x;
rtx *ext_val;
int *benefit; int *benefit;
{ {
enum machine_mode mode = GET_MODE (x); enum machine_mode mode = GET_MODE (x);
...@@ -6196,8 +6232,8 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6196,8 +6232,8 @@ simplify_giv_expr (loop, x, benefit)
switch (GET_CODE (x)) switch (GET_CODE (x))
{ {
case PLUS: case PLUS:
arg0 = simplify_giv_expr (loop, XEXP (x, 0), benefit); arg0 = simplify_giv_expr (loop, XEXP (x, 0), ext_val, benefit);
arg1 = simplify_giv_expr (loop, XEXP (x, 1), benefit); arg1 = simplify_giv_expr (loop, XEXP (x, 1), ext_val, benefit);
if (arg0 == 0 || arg1 == 0) if (arg0 == 0 || arg1 == 0)
return NULL_RTX; return NULL_RTX;
...@@ -6249,7 +6285,7 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6249,7 +6285,7 @@ simplify_giv_expr (loop, x, benefit)
gen_rtx_PLUS (mode, gen_rtx_PLUS (mode,
XEXP (arg0, 1), XEXP (arg0, 1),
arg1)), arg1)),
benefit); ext_val, benefit);
default: default:
abort (); abort ();
...@@ -6275,7 +6311,7 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6275,7 +6311,7 @@ simplify_giv_expr (loop, x, benefit)
gen_rtx_PLUS (mode, arg0, gen_rtx_PLUS (mode, arg0,
XEXP (arg1, 0)), XEXP (arg1, 0)),
XEXP (arg1, 1)), XEXP (arg1, 1)),
benefit); ext_val, benefit);
/* Now must have MULT + MULT. Distribute if same biv, else not giv. */ /* Now must have MULT + MULT. Distribute if same biv, else not giv. */
if (GET_CODE (arg0) != MULT || GET_CODE (arg1) != MULT) if (GET_CODE (arg0) != MULT || GET_CODE (arg1) != MULT)
...@@ -6290,7 +6326,7 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6290,7 +6326,7 @@ simplify_giv_expr (loop, x, benefit)
gen_rtx_PLUS (mode, gen_rtx_PLUS (mode,
XEXP (arg0, 1), XEXP (arg0, 1),
XEXP (arg1, 1))), XEXP (arg1, 1))),
benefit); ext_val, benefit);
case MINUS: case MINUS:
/* Handle "a - b" as "a + b * (-1)". */ /* Handle "a - b" as "a + b * (-1)". */
...@@ -6300,11 +6336,11 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6300,11 +6336,11 @@ simplify_giv_expr (loop, x, benefit)
gen_rtx_MULT (mode, gen_rtx_MULT (mode,
XEXP (x, 1), XEXP (x, 1),
constm1_rtx)), constm1_rtx)),
benefit); ext_val, benefit);
case MULT: case MULT:
arg0 = simplify_giv_expr (loop, XEXP (x, 0), benefit); arg0 = simplify_giv_expr (loop, XEXP (x, 0), ext_val, benefit);
arg1 = simplify_giv_expr (loop, XEXP (x, 1), benefit); arg1 = simplify_giv_expr (loop, XEXP (x, 1), ext_val, benefit);
if (arg0 == 0 || arg1 == 0) if (arg0 == 0 || arg1 == 0)
return NULL_RTX; return NULL_RTX;
...@@ -6350,7 +6386,7 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6350,7 +6386,7 @@ simplify_giv_expr (loop, x, benefit)
XEXP (arg0, XEXP (arg0,
1), 1),
arg1)), arg1)),
benefit); ext_val, benefit);
} }
/* Porpagate the MULT expressions to the intermost nodes. */ /* Porpagate the MULT expressions to the intermost nodes. */
else if (GET_CODE (arg0) == PLUS) else if (GET_CODE (arg0) == PLUS)
...@@ -6366,7 +6402,7 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6366,7 +6402,7 @@ simplify_giv_expr (loop, x, benefit)
XEXP (arg0, XEXP (arg0,
1), 1),
arg1)), arg1)),
benefit); ext_val, benefit);
} }
return gen_rtx_USE (mode, gen_rtx_MULT (mode, arg0, arg1)); return gen_rtx_USE (mode, gen_rtx_MULT (mode, arg0, arg1));
...@@ -6378,7 +6414,7 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6378,7 +6414,7 @@ simplify_giv_expr (loop, x, benefit)
gen_rtx_MULT (mode, gen_rtx_MULT (mode,
XEXP (arg0, 1), XEXP (arg0, 1),
arg1)), arg1)),
benefit); ext_val, benefit);
case PLUS: case PLUS:
/* (a + invar_1) * invar_2. Distribute. */ /* (a + invar_1) * invar_2. Distribute. */
...@@ -6390,7 +6426,7 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6390,7 +6426,7 @@ simplify_giv_expr (loop, x, benefit)
gen_rtx_MULT (mode, gen_rtx_MULT (mode,
XEXP (arg0, 1), XEXP (arg0, 1),
arg1)), arg1)),
benefit); ext_val, benefit);
default: default:
abort (); abort ();
...@@ -6407,13 +6443,13 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6407,13 +6443,13 @@ simplify_giv_expr (loop, x, benefit)
XEXP (x, 0), XEXP (x, 0),
GEN_INT ((HOST_WIDE_INT) 1 GEN_INT ((HOST_WIDE_INT) 1
<< INTVAL (XEXP (x, 1)))), << INTVAL (XEXP (x, 1)))),
benefit); ext_val, benefit);
case NEG: case NEG:
/* "-a" is "a * (-1)" */ /* "-a" is "a * (-1)" */
return simplify_giv_expr (loop, return simplify_giv_expr (loop,
gen_rtx_MULT (mode, XEXP (x, 0), constm1_rtx), gen_rtx_MULT (mode, XEXP (x, 0), constm1_rtx),
benefit); ext_val, benefit);
case NOT: case NOT:
/* "~a" is "-a - 1". Silly, but easy. */ /* "~a" is "-a - 1". Silly, but easy. */
...@@ -6421,13 +6457,30 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6421,13 +6457,30 @@ simplify_giv_expr (loop, x, benefit)
gen_rtx_MINUS (mode, gen_rtx_MINUS (mode,
gen_rtx_NEG (mode, XEXP (x, 0)), gen_rtx_NEG (mode, XEXP (x, 0)),
const1_rtx), const1_rtx),
benefit); ext_val, benefit);
case USE: case USE:
/* Already in proper form for invariant. */ /* Already in proper form for invariant. */
return x; 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 this is a new register, we can't deal with it. */
if (REGNO (x) >= max_reg_before_loop) if (REGNO (x) >= max_reg_before_loop)
return 0; return 0;
...@@ -6466,10 +6519,22 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6466,10 +6519,22 @@ simplify_giv_expr (loop, x, benefit)
if (v->derive_adjustment) if (v->derive_adjustment)
tem = gen_rtx_MINUS (mode, tem, 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: default:
do_default:
/* If it isn't an induction variable, and it is invariant, we /* If it isn't an induction variable, and it is invariant, we
may be able to simplify things further by looking through may be able to simplify things further by looking through
the bits we just moved outside the loop. */ the bits we just moved outside the loop. */
...@@ -6486,7 +6551,7 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6486,7 +6551,7 @@ simplify_giv_expr (loop, x, benefit)
this one is going away. */ this one is going away. */
if (m->match) if (m->match)
return simplify_giv_expr (loop, m->match->set_dest, 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 /* If consec is non-zero, this is a member of a group of
instructions that were moved together. We handle this instructions that were moved together. We handle this
...@@ -6520,7 +6585,8 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6520,7 +6585,8 @@ simplify_giv_expr (loop, x, benefit)
|| GET_CODE (tem) == CONST_INT || GET_CODE (tem) == CONST_INT
|| GET_CODE (tem) == SYMBOL_REF) || GET_CODE (tem) == SYMBOL_REF)
{ {
tem = simplify_giv_expr (loop, tem, benefit); tem = simplify_giv_expr (loop, tem, ext_val,
benefit);
if (tem) if (tem)
return tem; return tem;
} }
...@@ -6530,7 +6596,7 @@ simplify_giv_expr (loop, x, benefit) ...@@ -6530,7 +6596,7 @@ simplify_giv_expr (loop, x, benefit)
&& GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT) && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)
{ {
tem = simplify_giv_expr (loop, XEXP (tem, 0), tem = simplify_giv_expr (loop, XEXP (tem, 0),
benefit); ext_val, benefit);
if (tem) if (tem)
return tem; return tem;
} }
...@@ -6635,7 +6701,7 @@ sge_plus (mode, x, y) ...@@ -6635,7 +6701,7 @@ sge_plus (mode, x, y)
static int static int
consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg, 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; const struct loop *loop;
int first_benefit; int first_benefit;
rtx p; rtx p;
...@@ -6643,6 +6709,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg, ...@@ -6643,6 +6709,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
rtx dest_reg; rtx dest_reg;
rtx *add_val; rtx *add_val;
rtx *mult_val; rtx *mult_val;
rtx *ext_val;
rtx *last_consec_insn; rtx *last_consec_insn;
{ {
int count; int count;
...@@ -6666,6 +6733,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg, ...@@ -6666,6 +6733,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
v->benefit = first_benefit; v->benefit = first_benefit;
v->cant_derive = 0; v->cant_derive = 0;
v->derive_adjustment = 0; v->derive_adjustment = 0;
v->ext_dependant = NULL_RTX;
REG_IV_TYPE (REGNO (dest_reg)) = GENERAL_INDUCT; REG_IV_TYPE (REGNO (dest_reg)) = GENERAL_INDUCT;
REG_IV_INFO (REGNO (dest_reg)) = v; REG_IV_INFO (REGNO (dest_reg)) = v;
...@@ -6686,12 +6754,13 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg, ...@@ -6686,12 +6754,13 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
&& GET_CODE (SET_DEST (set)) == REG && GET_CODE (SET_DEST (set)) == REG
&& SET_DEST (set) == dest_reg && SET_DEST (set) == dest_reg
&& (general_induction_var (loop, SET_SRC (set), &src_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. */ /* Giv created by equivalent expression. */
|| ((temp = find_reg_note (p, REG_EQUAL, NULL_RTX)) || ((temp = find_reg_note (p, REG_EQUAL, NULL_RTX))
&& general_induction_var (loop, XEXP (temp, 0), &src_reg, && general_induction_var (loop, XEXP (temp, 0), &src_reg,
add_val, mult_val, 0, &benefit, add_val, mult_val, ext_val, 0,
VOIDmode))) &benefit, VOIDmode)))
&& src_reg == v->src_reg) && src_reg == v->src_reg)
{ {
if (find_reg_note (p, REG_RETVAL, NULL_RTX)) if (find_reg_note (p, REG_RETVAL, NULL_RTX))
...@@ -6921,25 +6990,36 @@ static rtx ...@@ -6921,25 +6990,36 @@ static rtx
combine_givs_p (g1, g2) combine_givs_p (g1, g2)
struct induction *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 /* 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 of express_from because the addends are not in a canonical form, so
rtx_equal_p is a weaker test. */ rtx_equal_p is a weaker test. */
/* But don't combine a DEST_REG giv with a DEST_ADDR giv; we want the /* But don't combine a DEST_REG giv with a DEST_ADDR giv; we want the
combination to be the other way round. */ 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)) && (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 /* 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, as an address and no more expensive than using a register for G2,
the expression of G2 in terms of G1 can be used. */ the expression of G2 in terms of G1 can be used. */
if (tem != NULL_RTX if (ret != NULL_RTX
&& g2->giv_type == DEST_ADDR && 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 /* ??? Looses, especially with -fforce-addr, where *g2->location
will always be a register, and so anything more complicated will always be a register, and so anything more complicated
gets discarded. */ gets discarded. */
...@@ -6952,12 +7032,197 @@ combine_givs_p (g1, g2) ...@@ -6952,12 +7032,197 @@ combine_givs_p (g1, g2)
#endif #endif
) )
{ {
return tem; return ret;
} }
return NULL_RTX; 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 struct combine_givs_stats
{ {
int giv_number; int giv_number;
......
...@@ -115,6 +115,8 @@ struct induction ...@@ -115,6 +115,8 @@ struct induction
subtracted from add_val when this giv subtracted from add_val when this giv
derives another. This occurs when the derives another. This occurs when the
giv spans a biv update by incrementation. */ 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 struct induction *next_iv; /* For givs, links together all givs that are
based on the same biv. For bivs, links based on the same biv. For bivs, links
together all biv entries that refer to the together all biv entries that refer to the
...@@ -238,6 +240,7 @@ int loop_invariant_p PARAMS ((const struct loop *, rtx)); ...@@ -238,6 +240,7 @@ int loop_invariant_p PARAMS ((const struct loop *, rtx));
rtx get_condition_for_loop 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)); void emit_iv_add_mult PARAMS ((rtx, rtx, rtx, rtx, rtx));
rtx express_from PARAMS ((struct induction *, struct induction *)); 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)); void unroll_loop PARAMS ((struct loop *, int, rtx, int));
rtx biv_total_increment PARAMS ((struct iv_class *)); rtx biv_total_increment PARAMS ((struct iv_class *));
...@@ -251,7 +254,7 @@ void emit_unrolled_add PARAMS ((rtx, rtx, rtx)); ...@@ -251,7 +254,7 @@ void emit_unrolled_add PARAMS ((rtx, rtx, rtx));
int back_branch_in_range_p PARAMS ((const struct loop *, rtx)); int back_branch_in_range_p PARAMS ((const struct loop *, rtx));
int loop_insn_first_p PARAMS ((rtx, 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)); void for_each_insn_in_loop PARAMS ((struct loop *, loop_insn_callback));
/* Forward declarations for non-static functions declared in doloop.c. */ /* Forward declarations for non-static functions declared in doloop.c. */
......
...@@ -2495,6 +2495,7 @@ iteration_info (loop, iteration_var, initial_value, increment) ...@@ -2495,6 +2495,7 @@ iteration_info (loop, iteration_var, initial_value, increment)
{ {
HOST_WIDE_INT offset = 0; HOST_WIDE_INT offset = 0;
struct induction *v = REG_IV_INFO (REGNO (iteration_var)); struct induction *v = REG_IV_INFO (REGNO (iteration_var));
rtx biv_initial_value;
if (REGNO (v->src_reg) >= max_reg_before_loop) if (REGNO (v->src_reg) >= max_reg_before_loop)
abort (); abort ();
...@@ -2527,11 +2528,13 @@ iteration_info (loop, iteration_var, initial_value, increment) ...@@ -2527,11 +2528,13 @@ iteration_info (loop, iteration_var, initial_value, increment)
fprintf (loop_dump_stream, fprintf (loop_dump_stream,
"Loop unrolling: Giv iterator, initial value bias %ld.\n", "Loop unrolling: Giv iterator, initial value bias %ld.\n",
(long) offset); (long) offset);
/* Initial value is mult_val times the biv's initial value plus /* Initial value is mult_val times the biv's initial value plus
add_val. Only useful if it is a constant. */ add_val. Only useful if it is a constant. */
biv_initial_value = extend_value_for_giv (v, bl->initial_value);
*initial_value *initial_value
= fold_rtx_mult_add (v->mult_val, = fold_rtx_mult_add (v->mult_val,
plus_constant (bl->initial_value, offset), plus_constant (biv_initial_value, offset),
v->add_val, v->mode); v->add_val, v->mode);
} }
else else
...@@ -2895,6 +2898,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number) ...@@ -2895,6 +2898,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
loop->start); loop->start);
biv_initial_value = tem; 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, value = fold_rtx_mult_add (v->mult_val, biv_initial_value,
v->add_val, v->mode); v->add_val, v->mode);
} }
...@@ -3456,10 +3460,11 @@ final_giv_value (loop, v) ...@@ -3456,10 +3460,11 @@ final_giv_value (loop, v)
insert_before = NEXT_INSN (loop_end); insert_before = NEXT_INSN (loop_end);
/* Put the final biv value in tem. */ /* 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); record_base_value (REGNO (tem), bl->biv->add_val, 0);
emit_iv_add_mult (increment, GEN_INT (n_iterations), 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. */ /* Subtract off extra increments as we find them. */
for (insn = NEXT_INSN (v->insn); insn != loop_end; for (insn = NEXT_INSN (v->insn); insn != loop_end;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment