Commit 12bd5a1e by Richard Guenther Committed by Richard Biener

re PR tree-optimization/43270 (array-bounds false negative)

2010-04-07  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/43270
	* tree-vrp.c (check_array_ref): Fix flexible array member
	detection.
	* tree-ssa-sccvn.h (fully_constant_vn_reference_p): Declare.
	* tree-ssa-pre.c (phi_translate_1): Adjust.
	(fully_constant_expression): Split out vn_reference handling to ...
	* tree-ssa-sccvn.c (fully_constant_vn_reference_p): ... here.
	Fold reads from constant strings.
	(vn_reference_lookup): Handle fully constant references.
	(vn_reference_lookup_pieces): Likewise.
	* Makefile.in (expmed.o-warn): Add -Wno-error.

	* g++.dg/warn/Warray-bounds-4.C: New testcase.
	* gcc.dg/Warray-bounds-7.c: Likewise.

From-SVN: r158058
parent a7752396
2010-04-07 Richard Guenther <rguenther@suse.de>
PR tree-optimization/43270
* tree-vrp.c (check_array_ref): Fix flexible array member
detection.
* tree-ssa-sccvn.h (fully_constant_vn_reference_p): Declare.
* tree-ssa-pre.c (phi_translate_1): Adjust.
(fully_constant_expression): Split out vn_reference handling to ...
* tree-ssa-sccvn.c (fully_constant_vn_reference_p): ... here.
Fold reads from constant strings.
(vn_reference_lookup): Handle fully constant references.
(vn_reference_lookup_pieces): Likewise.
* Makefile.in (expmed.o-warn): Add -Wno-error.
2010-04-07 Martin Jambor <mjambor@suse.cz> 2010-04-07 Martin Jambor <mjambor@suse.cz>
* tree-sra.c (find_param_candidates): Allow scalar va_list types. * tree-sra.c (find_param_candidates): Allow scalar va_list types.
......
...@@ -183,6 +183,7 @@ GCC_WARN_CXXFLAGS = $(LOOSE_WARN) $($(@D)-warn) $(NOCOMMON_FLAG) $($@-warn) ...@@ -183,6 +183,7 @@ GCC_WARN_CXXFLAGS = $(LOOSE_WARN) $($(@D)-warn) $(NOCOMMON_FLAG) $($@-warn)
build/gengtype-lex.o-warn = -Wno-error build/gengtype-lex.o-warn = -Wno-error
# mips-tfile.c contains -Wcast-qual warnings. # mips-tfile.c contains -Wcast-qual warnings.
mips-tfile.o-warn = -Wno-error mips-tfile.o-warn = -Wno-error
expmed.o-warn = -Wno-error
# All warnings have to be shut off in stage1 if the compiler used then # All warnings have to be shut off in stage1 if the compiler used then
# isn't gcc; configure determines that. WARN_CFLAGS will be either # isn't gcc; configure determines that. WARN_CFLAGS will be either
......
2010-04-07 Richard Guenther <rguenther@suse.de>
PR tree-optimization/43270
* g++.dg/warn/Warray-bounds-4.C: New testcase.
* gcc.dg/Warray-bounds-7.c: Likewise.
2010-04-07 Eric Botcazou <ebotcazou@adacore.com> 2010-04-07 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/bit_packed_array.ad[sb]: Rename into... * gnat.dg/bit_packed_array.ad[sb]: Rename into...
......
// { dg-do compile }
// { dg-options "-O2 -Warray-bounds" }
class String
{
public:
virtual unsigned long length() const = 0;
virtual char get(unsigned long index) const = 0;
virtual void set(unsigned long index, char value) = 0;
virtual char& operator[] (unsigned long value) = 0;
virtual ~String() {};
};
template<unsigned long size> class FixedString : public String
{
private:
char contents[size];
public:
virtual unsigned long length() const { return size; }
virtual char get(unsigned long index) const { return contents[index]; }
virtual void set(unsigned long index, char value) { contents[index] = value; }
virtual char& operator[] (unsigned long index) { return contents[index]; }
FixedString() { contents[0] = '\0'; } // { dg-warning "above array bounds" }
};
void print_length (const String& string);
int main()
{
const FixedString<0> empty;
print_length(empty);
return 0;
}
/* { dg-do compile } */
/* { dg-options "-O2 -Warray-bounds" } */
char *p;
int main()
{
p = "";
if (p[0] == 0
|| (p[0] == '_' && p[1] == 0)) /* { dg-bogus "array bounds" "" } */
return 0;
return 1;
}
...@@ -1231,49 +1231,11 @@ do_unary: ...@@ -1231,49 +1231,11 @@ do_unary:
case REFERENCE: case REFERENCE:
{ {
vn_reference_t ref = PRE_EXPR_REFERENCE (e); vn_reference_t ref = PRE_EXPR_REFERENCE (e);
VEC (vn_reference_op_s, heap) *operands = ref->operands; tree folded;
vn_reference_op_t op; if ((folded = fully_constant_vn_reference_p (ref)))
return get_or_alloc_expr_for_constant (folded);
/* Try to simplify the translated expression if it is return e;
a call to a builtin function with at most two arguments. */ }
op = VEC_index (vn_reference_op_s, operands, 0);
if (op->opcode == CALL_EXPR
&& TREE_CODE (op->op0) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (op->op0, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (op->op0, 0))
&& VEC_length (vn_reference_op_s, operands) >= 2
&& VEC_length (vn_reference_op_s, operands) <= 3)
{
vn_reference_op_t arg0, arg1 = NULL;
bool anyconst = false;
arg0 = VEC_index (vn_reference_op_s, operands, 1);
if (VEC_length (vn_reference_op_s, operands) > 2)
arg1 = VEC_index (vn_reference_op_s, operands, 2);
if (TREE_CODE_CLASS (arg0->opcode) == tcc_constant
|| (arg0->opcode == ADDR_EXPR
&& is_gimple_min_invariant (arg0->op0)))
anyconst = true;
if (arg1
&& (TREE_CODE_CLASS (arg1->opcode) == tcc_constant
|| (arg1->opcode == ADDR_EXPR
&& is_gimple_min_invariant (arg1->op0))))
anyconst = true;
if (anyconst)
{
tree folded = build_call_expr (TREE_OPERAND (op->op0, 0),
arg1 ? 2 : 1,
arg0->op0,
arg1 ? arg1->op0 : NULL);
if (folded
&& TREE_CODE (folded) == NOP_EXPR)
folded = TREE_OPERAND (folded, 0);
if (folded
&& is_gimple_min_invariant (folded))
return get_or_alloc_expr_for_constant (folded);
}
}
return e;
}
default: default:
return e; return e;
} }
...@@ -1702,7 +1664,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, ...@@ -1702,7 +1664,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
ref->type, ref->type,
newoperands, newoperands,
&newref, true); &newref, true);
if (newref) if (result)
VEC_free (vn_reference_op_s, heap, newoperands); VEC_free (vn_reference_op_s, heap, newoperands);
if (result && is_gimple_min_invariant (result)) if (result && is_gimple_min_invariant (result))
......
...@@ -889,6 +889,76 @@ vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **ops, ...@@ -889,6 +889,76 @@ vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **ops,
*i_p = i; *i_p = i;
} }
/* Optimize the reference REF to a constant if possible or return
NULL_TREE if not. */
tree
fully_constant_vn_reference_p (vn_reference_t ref)
{
VEC (vn_reference_op_s, heap) *operands = ref->operands;
vn_reference_op_t op;
/* Try to simplify the translated expression if it is
a call to a builtin function with at most two arguments. */
op = VEC_index (vn_reference_op_s, operands, 0);
if (op->opcode == CALL_EXPR
&& TREE_CODE (op->op0) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (op->op0, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (op->op0, 0))
&& VEC_length (vn_reference_op_s, operands) >= 2
&& VEC_length (vn_reference_op_s, operands) <= 3)
{
vn_reference_op_t arg0, arg1 = NULL;
bool anyconst = false;
arg0 = VEC_index (vn_reference_op_s, operands, 1);
if (VEC_length (vn_reference_op_s, operands) > 2)
arg1 = VEC_index (vn_reference_op_s, operands, 2);
if (TREE_CODE_CLASS (arg0->opcode) == tcc_constant
|| (arg0->opcode == ADDR_EXPR
&& is_gimple_min_invariant (arg0->op0)))
anyconst = true;
if (arg1
&& (TREE_CODE_CLASS (arg1->opcode) == tcc_constant
|| (arg1->opcode == ADDR_EXPR
&& is_gimple_min_invariant (arg1->op0))))
anyconst = true;
if (anyconst)
{
tree folded = build_call_expr (TREE_OPERAND (op->op0, 0),
arg1 ? 2 : 1,
arg0->op0,
arg1 ? arg1->op0 : NULL);
if (folded
&& TREE_CODE (folded) == NOP_EXPR)
folded = TREE_OPERAND (folded, 0);
if (folded
&& is_gimple_min_invariant (folded))
return folded;
}
}
/* Simplify reads from constant strings. */
else if (op->opcode == ARRAY_REF
&& TREE_CODE (op->op0) == INTEGER_CST
&& integer_zerop (op->op1)
&& VEC_length (vn_reference_op_s, operands) == 2)
{
vn_reference_op_t arg0;
arg0 = VEC_index (vn_reference_op_s, operands, 1);
if (arg0->opcode == STRING_CST
&& (TYPE_MODE (op->type)
== TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0->op0))))
&& GET_MODE_CLASS (TYPE_MODE (op->type)) == MODE_INT
&& GET_MODE_SIZE (TYPE_MODE (op->type)) == 1
&& compare_tree_int (op->op0, TREE_STRING_LENGTH (arg0->op0)) < 0)
return build_int_cst_type (op->type,
(TREE_STRING_POINTER (arg0->op0)
[TREE_INT_CST_LOW (op->op0)]));
}
return NULL_TREE;
}
/* Transform any SSA_NAME's in a vector of vn_reference_op_s /* Transform any SSA_NAME's in a vector of vn_reference_op_s
structures into their value numbers. This is done in-place, and structures into their value numbers. This is done in-place, and
the vector passed in is returned. */ the vector passed in is returned. */
...@@ -1194,6 +1264,7 @@ vn_reference_lookup_pieces (tree vuse, alias_set_type set, tree type, ...@@ -1194,6 +1264,7 @@ vn_reference_lookup_pieces (tree vuse, alias_set_type set, tree type,
{ {
struct vn_reference_s vr1; struct vn_reference_s vr1;
vn_reference_t tmp; vn_reference_t tmp;
tree cst;
if (!vnresult) if (!vnresult)
vnresult = &tmp; vnresult = &tmp;
...@@ -1212,8 +1283,10 @@ vn_reference_lookup_pieces (tree vuse, alias_set_type set, tree type, ...@@ -1212,8 +1283,10 @@ vn_reference_lookup_pieces (tree vuse, alias_set_type set, tree type,
vr1.type = type; vr1.type = type;
vr1.set = set; vr1.set = set;
vr1.hashcode = vn_reference_compute_hash (&vr1); vr1.hashcode = vn_reference_compute_hash (&vr1);
vn_reference_lookup_1 (&vr1, vnresult); if ((cst = fully_constant_vn_reference_p (&vr1)))
return cst;
vn_reference_lookup_1 (&vr1, vnresult);
if (!*vnresult if (!*vnresult
&& maywalk && maywalk
&& vr1.vuse) && vr1.vuse)
...@@ -1246,6 +1319,7 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk, ...@@ -1246,6 +1319,7 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk,
{ {
VEC (vn_reference_op_s, heap) *operands; VEC (vn_reference_op_s, heap) *operands;
struct vn_reference_s vr1; struct vn_reference_s vr1;
tree cst;
if (vnresult) if (vnresult)
*vnresult = NULL; *vnresult = NULL;
...@@ -1255,6 +1329,8 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk, ...@@ -1255,6 +1329,8 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk,
vr1.type = TREE_TYPE (op); vr1.type = TREE_TYPE (op);
vr1.set = get_alias_set (op); vr1.set = get_alias_set (op);
vr1.hashcode = vn_reference_compute_hash (&vr1); vr1.hashcode = vn_reference_compute_hash (&vr1);
if ((cst = fully_constant_vn_reference_p (&vr1)))
return cst;
if (maywalk if (maywalk
&& vr1.vuse) && vr1.vuse)
......
...@@ -204,4 +204,5 @@ unsigned int get_next_value_id (void); ...@@ -204,4 +204,5 @@ unsigned int get_next_value_id (void);
unsigned int get_constant_value_id (tree); unsigned int get_constant_value_id (tree);
unsigned int get_or_alloc_constant_value_id (tree); unsigned int get_or_alloc_constant_value_id (tree);
bool value_id_constant_p (unsigned int); bool value_id_constant_p (unsigned int);
tree fully_constant_vn_reference_p (vn_reference_t);
#endif /* TREE_SSA_SCCVN_H */ #endif /* TREE_SSA_SCCVN_H */
...@@ -4998,23 +4998,46 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one) ...@@ -4998,23 +4998,46 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one)
{ {
value_range_t* vr = NULL; value_range_t* vr = NULL;
tree low_sub, up_sub; tree low_sub, up_sub;
tree low_bound, up_bound = array_ref_up_bound (ref); tree low_bound, up_bound, up_bound_p1;
tree base;
if (TREE_NO_WARNING (ref))
return;
low_sub = up_sub = TREE_OPERAND (ref, 1); low_sub = up_sub = TREE_OPERAND (ref, 1);
up_bound = array_ref_up_bound (ref);
if (!up_bound || TREE_NO_WARNING (ref) /* Can not check flexible arrays. */
|| TREE_CODE (up_bound) != INTEGER_CST if (!up_bound
/* Can not check flexible arrays. */ || TREE_CODE (up_bound) != INTEGER_CST)
|| (TYPE_SIZE (TREE_TYPE (ref)) == NULL_TREE
&& TYPE_DOMAIN (TREE_TYPE (ref)) != NULL_TREE
&& TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (ref))) == NULL_TREE)
/* Accesses after the end of arrays of size 0 (gcc
extension) and 1 are likely intentional ("struct
hack"). */
|| compare_tree_int (up_bound, 1) <= 0)
return; return;
/* Accesses to trailing arrays via pointers may access storage
beyond the types array bounds. */
base = get_base_address (ref);
if (base
&& INDIRECT_REF_P (base))
{
tree cref, next = NULL_TREE;
if (TREE_CODE (TREE_OPERAND (ref, 0)) != COMPONENT_REF)
return;
cref = TREE_OPERAND (ref, 0);
if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 0))) == RECORD_TYPE)
for (next = TREE_CHAIN (TREE_OPERAND (cref, 1));
next && TREE_CODE (next) != FIELD_DECL;
next = TREE_CHAIN (next))
;
/* If this is the last field in a struct type or a field in a
union type do not warn. */
if (!next)
return;
}
low_bound = array_ref_low_bound (ref); low_bound = array_ref_low_bound (ref);
up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound, integer_one_node, 0);
if (TREE_CODE (low_sub) == SSA_NAME) if (TREE_CODE (low_sub) == SSA_NAME)
{ {
...@@ -5039,14 +5062,11 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one) ...@@ -5039,14 +5062,11 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one)
} }
} }
else if (TREE_CODE (up_sub) == INTEGER_CST else if (TREE_CODE (up_sub) == INTEGER_CST
&& tree_int_cst_lt (up_bound, up_sub) && (ignore_off_by_one
&& !tree_int_cst_equal (up_bound, up_sub) ? (tree_int_cst_lt (up_bound, up_sub)
&& (!ignore_off_by_one && !tree_int_cst_equal (up_bound_p1, up_sub))
|| !tree_int_cst_equal (int_const_binop (PLUS_EXPR, : (tree_int_cst_lt (up_bound, up_sub)
up_bound, || tree_int_cst_equal (up_bound_p1, up_sub))))
integer_one_node,
0),
up_sub)))
{ {
warning_at (location, OPT_Warray_bounds, warning_at (location, OPT_Warray_bounds,
"array subscript is above array bounds"); "array subscript is above array bounds");
......
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