From: rguenth Date: Wed, 7 Apr 2010 12:31:32 +0000 (+0000) Subject: 2010-04-07 Richard Guenther X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=commitdiff_plain;h=c26ce8a90a7c8ef9b6587959083d12f6edbc5e01 2010-04-07 Richard Guenther 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158058 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3121c996c35..ca2b7f6a4b6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2010-04-07 Richard Guenther + + 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 * tree-sra.c (find_param_candidates): Allow scalar va_list types. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index a1ad1d4a368..20529d0b2a0 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -183,6 +183,7 @@ GCC_WARN_CXXFLAGS = $(LOOSE_WARN) $($(@D)-warn) $(NOCOMMON_FLAG) $($@-warn) build/gengtype-lex.o-warn = -Wno-error # mips-tfile.c contains -Wcast-qual warnings. 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 # isn't gcc; configure determines that. WARN_CFLAGS will be either diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5f8db2c80a3..a2faaf5a818 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2010-04-07 Richard Guenther + + 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 * gnat.dg/bit_packed_array.ad[sb]: Rename into... diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-4.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-4.C new file mode 100644 index 00000000000..319038a73bf --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-4.C @@ -0,0 +1,37 @@ +// { 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 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; +} diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-7.c b/gcc/testsuite/gcc.dg/Warray-bounds-7.c new file mode 100644 index 00000000000..fdd95789aba --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-7.c @@ -0,0 +1,13 @@ +/* { 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; +} diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 24172f73188..2331e7b2249 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -1231,49 +1231,11 @@ do_unary: case REFERENCE: { vn_reference_t ref = PRE_EXPR_REFERENCE (e); - 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 get_or_alloc_expr_for_constant (folded); - } - } - return e; - } + tree folded; + if ((folded = fully_constant_vn_reference_p (ref))) + return get_or_alloc_expr_for_constant (folded); + return e; + } default: return e; } @@ -1702,7 +1664,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, ref->type, newoperands, &newref, true); - if (newref) + if (result) VEC_free (vn_reference_op_s, heap, newoperands); if (result && is_gimple_min_invariant (result)) diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index 5282978d173..f965c5134e5 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -889,6 +889,76 @@ vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **ops, *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 structures into their value numbers. This is done in-place, and the vector passed in is returned. */ @@ -1194,6 +1264,7 @@ vn_reference_lookup_pieces (tree vuse, alias_set_type set, tree type, { struct vn_reference_s vr1; vn_reference_t tmp; + tree cst; if (!vnresult) vnresult = &tmp; @@ -1212,8 +1283,10 @@ vn_reference_lookup_pieces (tree vuse, alias_set_type set, tree type, vr1.type = type; vr1.set = set; 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 && maywalk && vr1.vuse) @@ -1246,6 +1319,7 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk, { VEC (vn_reference_op_s, heap) *operands; struct vn_reference_s vr1; + tree cst; if (vnresult) *vnresult = NULL; @@ -1255,6 +1329,8 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk, vr1.type = TREE_TYPE (op); vr1.set = get_alias_set (op); vr1.hashcode = vn_reference_compute_hash (&vr1); + if ((cst = fully_constant_vn_reference_p (&vr1))) + return cst; if (maywalk && vr1.vuse) diff --git a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h index c60c28ac11a..8f93b0b2518 100644 --- a/gcc/tree-ssa-sccvn.h +++ b/gcc/tree-ssa-sccvn.h @@ -204,4 +204,5 @@ unsigned int get_next_value_id (void); unsigned int get_constant_value_id (tree); unsigned int get_or_alloc_constant_value_id (tree); bool value_id_constant_p (unsigned int); +tree fully_constant_vn_reference_p (vn_reference_t); #endif /* TREE_SSA_SCCVN_H */ diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index c84004e6be4..3b22948e39f 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -4998,23 +4998,46 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one) { value_range_t* vr = NULL; 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); + up_bound = array_ref_up_bound (ref); - if (!up_bound || TREE_NO_WARNING (ref) - || TREE_CODE (up_bound) != INTEGER_CST - /* Can not check flexible arrays. */ - || (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) + /* Can not check flexible arrays. */ + if (!up_bound + || TREE_CODE (up_bound) != INTEGER_CST) 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); + up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound, integer_one_node, 0); if (TREE_CODE (low_sub) == SSA_NAME) { @@ -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 - && tree_int_cst_lt (up_bound, up_sub) - && !tree_int_cst_equal (up_bound, up_sub) - && (!ignore_off_by_one - || !tree_int_cst_equal (int_const_binop (PLUS_EXPR, - up_bound, - integer_one_node, - 0), - up_sub))) + && (ignore_off_by_one + ? (tree_int_cst_lt (up_bound, up_sub) + && !tree_int_cst_equal (up_bound_p1, up_sub)) + : (tree_int_cst_lt (up_bound, up_sub) + || tree_int_cst_equal (up_bound_p1, up_sub)))) { warning_at (location, OPT_Warray_bounds, "array subscript is above array bounds");