Commit 27916b83 by Richard Sandiford Committed by Richard Henderson

re PR rtl-optimization/13299 (Unsafe treatment of extended givs)

        PR rtl-opt/13299
        * loop.c (get_monotonic_increment, biased_biv_fits_mode_p,
        biv_fits_mode_p, extension_within_bounds_p): New functions.
        (check_ext_dependent_givs): Use them.

From-SVN: r93000
parent 4ab80063
2005-01-06 Richard Sandiford <rsandifo@redhat.com>
PR rtl-opt/13299
* loop.c (get_monotonic_increment, biased_biv_fits_mode_p,
biv_fits_mode_p, extension_within_bounds_p): New functions.
(check_ext_dependent_givs): Use them.
2005-01-06 Roger Sayle <roger@eyesopen.com> 2005-01-06 Roger Sayle <roger@eyesopen.com>
* cfgrtl.c (rtl_delete_block): A basic block may be followed by * cfgrtl.c (rtl_delete_block): A basic block may be followed by
......
...@@ -653,6 +653,14 @@ static void record_giv (const struct loop *, struct induction *, rtx, rtx, ...@@ -653,6 +653,14 @@ static void record_giv (const struct loop *, struct induction *, rtx, rtx,
rtx, rtx, rtx, rtx, int, enum g_types, int, int, rtx, rtx, rtx, rtx, int, enum g_types, int, int,
rtx *); rtx *);
static void update_giv_derive (const struct loop *, rtx); static void update_giv_derive (const struct loop *, rtx);
static HOST_WIDE_INT get_monotonic_increment (struct iv_class *);
static bool biased_biv_fits_mode_p (const struct loop *, struct iv_class *,
HOST_WIDE_INT, enum machine_mode,
unsigned HOST_WIDE_INT);
static bool biv_fits_mode_p (const struct loop *, struct iv_class *,
HOST_WIDE_INT, enum machine_mode, bool);
static bool extension_within_bounds_p (const struct loop *, struct iv_class *,
HOST_WIDE_INT, rtx);
static void check_ext_dependent_givs (const struct loop *, struct iv_class *); static void check_ext_dependent_givs (const struct loop *, struct iv_class *);
static int basic_induction_var (const struct loop *, rtx, enum machine_mode, static int basic_induction_var (const struct loop *, rtx, enum machine_mode,
rtx, rtx, rtx *, rtx *, rtx **); rtx, rtx, rtx *, rtx *, rtx **);
...@@ -8608,192 +8616,204 @@ combine_givs_p (struct induction *g1, struct induction *g2) ...@@ -8608,192 +8616,204 @@ combine_givs_p (struct induction *g1, struct induction *g2)
return NULL_RTX; return NULL_RTX;
} }
/* Check each extension dependent giv in this class to see if its /* See if BL is monotonic and has a constant per-iteration increment.
root biv is safe from wrapping in the interior mode, which would Return the increment if so, otherwise return 0. */
make the giv illegal. */
static void static HOST_WIDE_INT
check_ext_dependent_givs (const struct loop *loop, struct iv_class *bl) get_monotonic_increment (struct iv_class *bl)
{ {
struct loop_info *loop_info = LOOP_INFO (loop);
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 = 0;
unsigned HOST_WIDE_INT u_start_val = 0;
rtx incr = pc_rtx;
struct induction *v; struct induction *v;
rtx incr;
/* Get the total increment and check that it is constant. */
incr = biv_total_increment (bl);
if (incr == 0 || GET_CODE (incr) != CONST_INT)
return 0;
for (v = bl->biv; v != 0; v = v->next_iv)
{
if (GET_CODE (v->add_val) != CONST_INT)
return 0;
if (INTVAL (v->add_val) < 0 && INTVAL (incr) >= 0)
return 0;
if (INTVAL (v->add_val) > 0 && INTVAL (incr) <= 0)
return 0;
}
return INTVAL (incr);
}
/* Subroutine of biv_fits_mode_p. Return true if biv BL, when biased by
BIAS, will never exceed the unsigned range of MODE. LOOP is the loop
to which the biv belongs and INCR is its per-iteration increment. */
static bool
biased_biv_fits_mode_p (const struct loop *loop, struct iv_class *bl,
HOST_WIDE_INT incr, enum machine_mode mode,
unsigned HOST_WIDE_INT bias)
{
unsigned HOST_WIDE_INT initial, maximum, span, delta;
/* We need to be able to manipulate MODE-size constants. */
if (HOST_BITS_PER_WIDE_INT < GET_MODE_BITSIZE (mode))
return false;
/* The number of loop iterations must be constant. */
if (LOOP_INFO (loop)->n_iterations == 0)
return false;
/* So must the biv's initial value. */
if (bl->initial_value == 0 || GET_CODE (bl->initial_value) != CONST_INT)
return false;
initial = bias + INTVAL (bl->initial_value);
maximum = GET_MODE_MASK (mode);
/* Make sure that the initial value is within range. */
if (initial > maximum)
return false;
/* Set up DELTA and SPAN such that the number of iterations * DELTA
(calculated to arbitrary precision) must be <= SPAN. */
if (incr < 0)
{
delta = -incr;
span = initial;
}
else
{
delta = incr;
/* Handle the special case in which MAXIMUM is the largest
unsigned HOST_WIDE_INT and INITIAL is 0. */
if (maximum + 1 == initial)
span = LOOP_INFO (loop)->n_iterations * delta;
else
span = maximum + 1 - initial;
}
return (span / LOOP_INFO (loop)->n_iterations >= delta);
}
/* Return true if biv BL will never exceed the bounds of MODE. LOOP is
the loop to which BL belongs and INCR is its per-iteration increment.
UNSIGNEDP is true if the biv should be treated as unsigned. */
static bool
biv_fits_mode_p (const struct loop *loop, struct iv_class *bl,
HOST_WIDE_INT incr, enum machine_mode mode, bool unsignedp)
{
struct loop_info *loop_info;
unsigned HOST_WIDE_INT bias;
/* A biv's value will always be limited to its natural mode.
Larger modes will observe the same wrap-around. */
if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (bl->biv->src_reg)))
mode = GET_MODE (bl->biv->src_reg);
loop_info = LOOP_INFO (loop);
bias = (unsignedp ? 0 : (GET_MODE_MASK (mode) >> 1) + 1);
if (biased_biv_fits_mode_p (loop, bl, incr, mode, bias))
return true;
/* Make sure the iteration data is available. We must have if (mode == GET_MODE (bl->biv->src_reg)
constants in order to be certain of no overflow. */ && bl->biv->src_reg == loop_info->iteration_var
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 arithmetic 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 arithmetic 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 arithmetic 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;
}
}
}
/* If we know the BIV is compared at run-time against an
invariant value, and the increment is +/- 1, we may also
be able to prove that the BIV cannot overflow. */
else if (bl->biv->src_reg == loop_info->iteration_var
&& loop_info->comparison_value && loop_info->comparison_value
&& loop_invariant_p (loop, loop_info->comparison_value) && loop_invariant_p (loop, loop_info->comparison_value))
&& (incr = biv_total_increment (bl))
&& GET_CODE (incr) == CONST_INT)
{ {
/* If the increment is +1, and the exit test is a <, /* If the increment is +1, and the exit test is a <, the BIV
the BIV cannot overflow. (For <=, we have the cannot overflow. (For <=, we have the problematic case that
problematic case that the comparison value might the comparison value might be the maximum value of the range.) */
be the maximum value of the range.) */ if (incr == 1)
if (INTVAL (incr) == 1)
{ {
if (loop_info->comparison_code == LT) if (loop_info->comparison_code == LT)
se_ok = ze_ok = 1; return true;
else if (loop_info->comparison_code == LTU) if (loop_info->comparison_code == LTU && unsignedp)
ze_ok = 1; return true;
} }
/* Likewise for increment -1 and exit test >. */ /* Likewise for increment -1 and exit test >. */
if (INTVAL (incr) == -1) if (incr == -1)
{ {
if (loop_info->comparison_code == GT) if (loop_info->comparison_code == GT)
se_ok = ze_ok = 1; return true;
else if (loop_info->comparison_code == GTU) if (loop_info->comparison_code == GTU && unsignedp)
ze_ok = 1; return true;
} }
} }
return false;
}
/* Invalidate givs that fail the tests. */
for (v = bl->giv; v; v = v->next_iv)
if (v->ext_dependent)
{
enum rtx_code code = GET_CODE (v->ext_dependent);
int ok = 0;
switch (code) /* Given that X is an extension or truncation of BL, return true
if it is unaffected by overflow. LOOP is the loop to which
BL belongs and INCR is its per-iteration increment. */
static bool
extension_within_bounds_p (const struct loop *loop, struct iv_class *bl,
HOST_WIDE_INT incr, rtx x)
{
enum machine_mode mode;
bool signedp, unsignedp;
switch (GET_CODE (x))
{ {
case SIGN_EXTEND: case SIGN_EXTEND:
ok = se_ok;
break;
case ZERO_EXTEND: case ZERO_EXTEND:
ok = ze_ok; mode = GET_MODE (XEXP (x, 0));
signedp = (GET_CODE (x) == SIGN_EXTEND);
unsignedp = (GET_CODE (x) == ZERO_EXTEND);
break; break;
case TRUNCATE: case TRUNCATE:
/* We don't know whether this value is being used as either /* We don't know whether this value is being used as signed
signed or unsigned, so to safely truncate we must satisfy or unsigned, so check the conditions for both. */
both. The initial check here verifies the BIV itself; mode = GET_MODE (x);
once that is successful we may check its range wrt the signedp = unsignedp = true;
derived GIV. This works only if we were able to determine
constant start and end values above. */
if (se_ok && ze_ok && info_ok)
{
enum machine_mode outer_mode = GET_MODE (v->ext_dependent);
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; break;
default: default:
abort (); abort ();
} }
if (ok) return ((!signedp || biv_fits_mode_p (loop, bl, incr, mode, false))
&& (!unsignedp || biv_fits_mode_p (loop, bl, incr, mode, true)));
}
/* Check each extension dependent 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_dependent_givs (const struct loop *loop, struct iv_class *bl)
{
struct induction *v;
HOST_WIDE_INT incr;
incr = get_monotonic_increment (bl);
/* Invalidate givs that fail the tests. */
for (v = bl->giv; v; v = v->next_iv)
if (v->ext_dependent)
{ {
if (loop_dump_stream) if (incr != 0
&& extension_within_bounds_p (loop, bl, incr, v->ext_dependent))
{ {
if (loop_dump_stream)
fprintf (loop_dump_stream, fprintf (loop_dump_stream,
"Verified ext dependent giv at %d of reg %d\n", "Verified ext dependent giv at %d of reg %d\n",
INSN_UID (v->insn), bl->regno); INSN_UID (v->insn), bl->regno);
} }
}
else else
{ {
if (loop_dump_stream) 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, fprintf (loop_dump_stream,
"Failed ext dependent giv at %d, %s\n", "Failed ext dependent giv at %d\n",
INSN_UID (v->insn), why); INSN_UID (v->insn));
}
v->ignore = 1; v->ignore = 1;
bl->all_reduced = 0; bl->all_reduced = 0;
} }
......
/* "i" overflows in f(). Check that x[i] is not treated as a giv. */
#include <limits.h>
#if CHAR_BIT == 8
void f (unsigned int *x)
{
unsigned char i;
int j;
i = 0x10;
for (j = 0; j < 0x10; j++)
{
i += 0xe8;
x[i] = 0;
i -= 0xe7;
}
}
int main ()
{
unsigned int x[256];
int i;
for (i = 0; i < 256; i++)
x[i] = 1;
f (x);
for (i = 0; i < 256; i++)
if (x[i] != (i >= 0x08 && i < 0xf8))
abort ();
exit (0);
}
#else
int main () { exit (0); }
#endif
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