re PR tree-optimization/27865 (tree check failure building FreePOOMA)

PR tree-optimization/27865
	* tree-vrp.c (adjust_range_with_scev): Do not use TYPE_{MIN,MAX}_VALUE
	for pointer types.
	* tree-scalar-evolution.c (fold_used_pointer_cast, pointer_offset_p,
	fold_used_pointer, pointer_used_p): New functions.
	(analyze_scalar_evolution_1): Use fold_used_pointer.
	* tree-chrec.c (convert_affine_scev): Convert no-op casts correctly.
	* tree-ssa-loop-ivopts.c (generic_type_for): Return integral type
	for pointers.

From-SVN: r116213
This commit is contained in:
Zdenek Dvorak 2006-08-17 10:22:05 +02:00 committed by Zdenek Dvorak
parent b646edb85c
commit 2052721560
5 changed files with 231 additions and 20 deletions

View File

@ -1,3 +1,15 @@
2006-08-16 Zdenek Dvorak <dvorakz@suse.cz>
PR tree-optimization/27865
* tree-vrp.c (adjust_range_with_scev): Do not use TYPE_{MIN,MAX}_VALUE
for pointer types.
* tree-scalar-evolution.c (fold_used_pointer_cast, pointer_offset_p,
fold_used_pointer, pointer_used_p): New functions.
(analyze_scalar_evolution_1): Use fold_used_pointer.
* tree-chrec.c (convert_affine_scev): Convert no-op casts correctly.
* tree-ssa-loop-ivopts.c (generic_type_for): Return integral type
for pointers.
2006-08-17 Paolo Bonzini <bonzini@gnu.org>
PR c++/28573

View File

@ -1162,7 +1162,10 @@ convert_affine_scev (struct loop *loop, tree type,
-- must_check_src_overflow is true, and the range of TYPE is superset
of the range of CT -- i.e., in all cases except if CT signed and
TYPE unsigned.
-- both CT and TYPE have the same precision and signedness. */
-- both CT and TYPE have the same precision and signedness, and we
verify instead that the source does not overflow (this may be
easier than verifying it for the result, as we may use the
information about the semantics of overflow in CT). */
if (must_check_src_overflow)
{
if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (ct))
@ -1172,7 +1175,10 @@ convert_affine_scev (struct loop *loop, tree type,
}
else if (TYPE_UNSIGNED (ct) == TYPE_UNSIGNED (type)
&& TYPE_PRECISION (ct) == TYPE_PRECISION (type))
must_check_rslt_overflow = false;
{
must_check_rslt_overflow = false;
must_check_src_overflow = true;
}
else
must_check_rslt_overflow = true;
}

View File

@ -1718,6 +1718,184 @@ compute_scalar_evolution_in_loop (struct loop *wrto_loop,
return analyze_scalar_evolution_1 (wrto_loop, res, chrec_not_analyzed_yet);
}
/* Folds EXPR, if it is a cast to pointer, assuming that the created
polynomial_chrec does not wrap. */
static tree
fold_used_pointer_cast (tree expr)
{
tree op;
tree type, inner_type;
if (TREE_CODE (expr) != NOP_EXPR && TREE_CODE (expr) != CONVERT_EXPR)
return expr;
op = TREE_OPERAND (expr, 0);
if (TREE_CODE (op) != POLYNOMIAL_CHREC)
return expr;
type = TREE_TYPE (expr);
inner_type = TREE_TYPE (op);
if (!INTEGRAL_TYPE_P (inner_type)
|| TYPE_PRECISION (inner_type) != TYPE_PRECISION (type))
return expr;
return build_polynomial_chrec (CHREC_VARIABLE (op),
chrec_convert (type, CHREC_LEFT (op), NULL_TREE),
chrec_convert (type, CHREC_RIGHT (op), NULL_TREE));
}
/* Returns true if EXPR is an expression corresponding to offset of pointer
in p + offset. */
static bool
pointer_offset_p (tree expr)
{
if (TREE_CODE (expr) == INTEGER_CST)
return true;
if ((TREE_CODE (expr) == NOP_EXPR || TREE_CODE (expr) == CONVERT_EXPR)
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0))))
return true;
return false;
}
/* EXPR is a scalar evolution of a pointer that is dereferenced or used in
comparison. This means that it must point to a part of some object in
memory, which enables us to argue about overflows and possibly simplify
the EXPR. Returns the simplified value.
Currently, for
int i, n;
int *p;
for (i = -n; i < n; i++)
*(p + i) = ...;
We generate the following code (assuming that size of int and size_t is
4 bytes):
for (i = -n; i < n; i++)
{
size_t tmp1, tmp2;
int *tmp3, *tmp4;
tmp1 = (size_t) i; (1)
tmp2 = 4 * tmp1; (2)
tmp3 = (int *) tmp2; (3)
tmp4 = p + tmp3; (4)
*tmp4 = ...;
}
We in general assume that pointer arithmetics does not overflow (since its
behavior is undefined in that case). One of the problems is that our
translation does not capture this property very well -- (int *) is
considered unsigned, hence the computation in (4) does overflow if i is
negative.
This impreciseness creates complications in scev analysis. The scalar
evolution of i is [-n, +, 1]. Since int and size_t have the same precision
(in this example), and size_t is unsigned (so we do not care about
overflows), we succeed to derive that scev of tmp1 is [(size_t) -n, +, 1]
and scev of tmp2 is [4 * (size_t) -n, +, 4]. With tmp3, we run into
problem -- [(int *) (4 * (size_t) -n), +, 4] wraps, and since we on several
places assume that this is not the case for scevs with pointer type, we
cannot use this scev for tmp3; hence, its scev is
(int *) [(4 * (size_t) -n), +, 4], and scev of tmp4 is
p + (int *) [(4 * (size_t) -n), +, 4]. Most of the optimizers are unable to
work with scevs of this shape.
However, since tmp4 is dereferenced, all its values must belong to a single
object, and taking into account that the precision of int * and size_t is
the same, it is impossible for its scev to wrap. Hence, we can derive that
its evolution is [p + (int *) (4 * (size_t) -n), +, 4], which the optimizers
can work with.
??? Maybe we should use different representation for pointer arithmetics,
however that is a long-term project with a lot of potential for creating
bugs. */
static tree
fold_used_pointer (tree expr)
{
tree op0, op1, new0, new1;
enum tree_code code = TREE_CODE (expr);
if (code == PLUS_EXPR
|| code == MINUS_EXPR)
{
op0 = TREE_OPERAND (expr, 0);
op1 = TREE_OPERAND (expr, 1);
if (pointer_offset_p (op1))
{
new0 = fold_used_pointer (op0);
new1 = fold_used_pointer_cast (op1);
}
else if (code == PLUS_EXPR && pointer_offset_p (op0))
{
new0 = fold_used_pointer_cast (op0);
new1 = fold_used_pointer (op1);
}
else
return expr;
if (new0 == op0 && new1 == op1)
return expr;
if (code == PLUS_EXPR)
expr = chrec_fold_plus (TREE_TYPE (expr), new0, new1);
else
expr = chrec_fold_minus (TREE_TYPE (expr), new0, new1);
return expr;
}
else
return fold_used_pointer_cast (expr);
}
/* Returns true if PTR is dereferenced, or used in comparison. */
static bool
pointer_used_p (tree ptr)
{
use_operand_p use_p;
imm_use_iterator imm_iter;
tree stmt, rhs;
struct ptr_info_def *pi = get_ptr_info (ptr);
var_ann_t v_ann = var_ann (SSA_NAME_VAR (ptr));
/* Check whether the pointer has a memory tag; if it does, it is
(or at least used to be) dereferenced. */
if ((pi != NULL && pi->name_mem_tag != NULL)
|| v_ann->symbol_mem_tag)
return true;
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, ptr)
{
stmt = USE_STMT (use_p);
if (TREE_CODE (stmt) == COND_EXPR)
return true;
if (TREE_CODE (stmt) != MODIFY_EXPR)
continue;
rhs = TREE_OPERAND (stmt, 1);
if (!COMPARISON_CLASS_P (rhs))
continue;
if (TREE_OPERAND (stmt, 0) == ptr
|| TREE_OPERAND (stmt, 1) == ptr)
return true;
}
return false;
}
/* Helper recursive function. */
static tree
@ -1766,6 +1944,11 @@ analyze_scalar_evolution_1 (struct loop *loop, tree var, tree res)
{
case MODIFY_EXPR:
res = interpret_rhs_modify_expr (loop, def, TREE_OPERAND (def, 1), type);
if (POINTER_TYPE_P (type)
&& !automatically_generated_chrec_p (res)
&& pointer_used_p (var))
res = fold_used_pointer (res);
break;
case PHI_NODE:

View File

@ -1925,14 +1925,14 @@ strip_offset (tree expr, unsigned HOST_WIDE_INT *offset)
}
/* Returns variant of TYPE that can be used as base for different uses.
For integer types, we return unsigned variant of the type, which
avoids problems with overflows. For pointer types, we return void *. */
We return unsigned type with the same precision, which avoids problems
with overflows. */
static tree
generic_type_for (tree type)
{
if (POINTER_TYPE_P (type))
return ptr_type_node;
return unsigned_type_for (type);
if (TYPE_UNSIGNED (type))
return type;

View File

@ -2015,7 +2015,7 @@ static void
adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
tree var)
{
tree init, step, chrec;
tree init, step, chrec, tmin, tmax, min, max, type;
enum ev_direction dir;
/* TODO. Don't adjust anti-ranges. An anti-range may provide
@ -2049,13 +2049,23 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
true))
return;
if (!POINTER_TYPE_P (TREE_TYPE (init))
&& (vr->type == VR_VARYING || vr->type == VR_UNDEFINED))
type = TREE_TYPE (var);
if (POINTER_TYPE_P (type) || !TYPE_MIN_VALUE (type))
tmin = lower_bound_in_type (type, type);
else
tmin = TYPE_MIN_VALUE (type);
if (POINTER_TYPE_P (type) || !TYPE_MAX_VALUE (type))
tmax = upper_bound_in_type (type, type);
else
tmax = TYPE_MAX_VALUE (type);
if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
{
min = tmin;
max = tmax;
/* For VARYING or UNDEFINED ranges, just about anything we get
from scalar evolutions should be better. */
tree min = TYPE_MIN_VALUE (TREE_TYPE (init));
tree max = TYPE_MAX_VALUE (TREE_TYPE (init));
if (dir == EV_DIR_DECREASES)
max = init;
@ -2064,7 +2074,8 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
/* If we would create an invalid range, then just assume we
know absolutely nothing. This may be over-conservative,
but it's clearly safe. */
but it's clearly safe, and should happen only in unreachable
parts of code, or for invalid programs. */
if (compare_values (min, max) == 1)
return;
@ -2072,8 +2083,8 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
}
else if (vr->type == VR_RANGE)
{
tree min = vr->min;
tree max = vr->max;
min = vr->min;
max = vr->max;
if (dir == EV_DIR_DECREASES)
{
@ -2084,10 +2095,11 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
max = init;
/* If we just created an invalid range with the minimum
greater than the maximum, take the minimum all the
way to -INF. */
greater than the maximum, we fail conservatively.
This should happen only in unreachable
parts of code, or for invalid programs. */
if (compare_values (min, max) == 1)
min = TYPE_MIN_VALUE (TREE_TYPE (min));
return;
}
}
else
@ -2097,11 +2109,9 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
{
min = init;
/* If we just created an invalid range with the minimum
greater than the maximum, take the maximum all the
way to +INF. */
/* Again, avoid creating invalid range by failing. */
if (compare_values (min, max) == 1)
max = TYPE_MAX_VALUE (TREE_TYPE (max));
return;
}
}