From 9563a3d30ac812f30d2997650f6156ab0e66ba4a Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 28 Aug 2017 12:16:06 +0000 Subject: [PATCH] backport: [multiple changes] 2017-08-28 Richard Biener Backport from mainline 2017-08-21 Richard Biener PR middle-end/81884 * tree-ssa-alias.c (stmt_kills_ref_p): Handle array accesses at struct end conservatively when comparing common bases. * g++.dg/torture/pr81884.C: New testcase. 2017-05-04 Richard Biener * tree.c (array_at_struct_end_p): Handle arrays at struct end with flexarrays more conservatively. Refactor and treat arrays of arrays or aggregates more strict. Fix VIEW_CONVERT_EXPR handling. Remove allow_compref argument. * tree.h (array_at_struct_end_p): Adjust prototype. * gimple-fold.c (get_range_strlen): Likewise. * tree-chkp.c (chkp_may_narrow_to_field): Likewise. From-SVN: r251379 --- gcc/ChangeLog | 19 ++++++++ gcc/gimple-fold.c | 2 +- gcc/testsuite/ChangeLog | 26 +++++++++++ gcc/testsuite/g++.dg/torture/pr81884.C | 39 ++++++++++++++++ gcc/tree-chkp.c | 2 +- gcc/tree-ssa-alias.c | 31 +++++++++---- gcc/tree.c | 63 +++++++++++++++++++------- gcc/tree.h | 10 ++-- 8 files changed, 159 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/pr81884.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7e4fb5e1fbf..c335097134d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2017-08-28 Richard Biener + + Backport from mainline + 2017-08-21 Richard Biener + + PR middle-end/81884 + * tree-ssa-alias.c (stmt_kills_ref_p): Handle array accesses + at struct end conservatively when comparing common bases. + + 2017-05-04 Richard Biener + + * tree.c (array_at_struct_end_p): Handle arrays at struct + end with flexarrays more conservatively. Refactor and treat + arrays of arrays or aggregates more strict. Fix + VIEW_CONVERT_EXPR handling. Remove allow_compref argument. + * tree.h (array_at_struct_end_p): Adjust prototype. + * gimple-fold.c (get_range_strlen): Likewise. + * tree-chkp.c (chkp_may_narrow_to_field): Likewise. + 2017-08-28 Richard Biener Backport from mainline diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 0f3227da4f4..bb993c28239 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -1236,7 +1236,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type, the NUL. Set *FLEXP to true if the array whose bound is being used is at the end of a struct. */ - if (array_at_struct_end_p (arg, true)) + if (array_at_struct_end_p (arg)) *flexp = true; arg = TREE_OPERAND (arg, 1); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 53cef0bd22f..739c10dc691 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,29 @@ +2017-08-28 Richard Biener + + Backport from mainline + 2017-08-21 Richard Biener + + PR middle-end/81884 + * g++.dg/torture/pr81884.C: New testcase. + +2017-08-28 Richard Biener + + Backport from mainline + 2017-08-01 Richard Biener + + PR tree-optimization/81181 + * gcc.dg/torture/pr81181.c: New testcase. + + 2017-08-08 Richard Biener + + PR tree-optimization/81723 + * gfortran.dg/pr81723.f: New testcase. + + 2017-08-24 Richard Biener + + PR target/81921 + * gcc/testsuite/gcc.target/i386/pr81921.c: New testcase. + 2017-05-19 Uros Bizjak Backport from mainline diff --git a/gcc/testsuite/g++.dg/torture/pr81884.C b/gcc/testsuite/g++.dg/torture/pr81884.C new file mode 100644 index 00000000000..f545355ce35 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr81884.C @@ -0,0 +1,39 @@ +/* { dg-do run } */ + +typedef unsigned long uint64_t; + +struct value_t { + uint64_t _count; + value_t(uint64_t c) : _count(c) {} +}; + +struct X { + value_t eventTime; + uint64_t arr[0]; +}; + +X* x; + +__attribute__((noclone, noinline)) +void initialize() +{ + x->arr[0] = 11; + x->arr[1] = 12; + x->eventTime = value_t(10); + x->arr[2] = 13; + x->arr[3] = 14; +} + +int main() +{ + char buffer[sizeof(X) + sizeof(uint64_t)*4]; + x = (X*)buffer; + x->eventTime = value_t(999); + x->arr[0] = 1; + x->arr[1] = 2; + x->arr[2] = 3; + x->arr[3] = 4; + initialize(); + if (x->arr[0] != 11 || x->arr[1] != 12 || x->arr[2] != 13 || x->arr[3] != 14) + __builtin_abort (); +} diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c index b1ff21851c6..23f5af98ae3 100644 --- a/gcc/tree-chkp.c +++ b/gcc/tree-chkp.c @@ -3277,7 +3277,7 @@ chkp_may_narrow_to_field (tree ref, tree field) return DECL_SIZE (field) && TREE_CODE (DECL_SIZE (field)) == INTEGER_CST && tree_to_uhwi (DECL_SIZE (field)) != 0 && !(flag_chkp_flexible_struct_trailing_arrays - && array_at_struct_end_p (ref, true)) + && array_at_struct_end_p (ref)) && (!DECL_FIELD_OFFSET (field) || TREE_CODE (DECL_FIELD_OFFSET (field)) == INTEGER_CST) && (!DECL_FIELD_BIT_OFFSET (field) diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 3f0c650475d..4cedcb2392f 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -2415,6 +2415,7 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) if (ref->ref) { tree base = ref->ref; + tree innermost_dropped_array_ref = NULL_TREE; if (handled_component_p (base)) { tree saved_lhs0 = NULL_TREE; @@ -2434,6 +2435,11 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) TREE_OPERAND (base, 0) = saved_base0; if (res) break; + /* Remember if we drop an array-ref that we need to + double-check not being at struct end. */ + if (TREE_CODE (base) == ARRAY_REF + || TREE_CODE (base) == ARRAY_RANGE_REF) + innermost_dropped_array_ref = base; /* Otherwise drop handled components of the access. */ base = saved_base0; } @@ -2442,15 +2448,22 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) TREE_OPERAND (lhs, 0) = saved_lhs0; } /* Finally check if the lhs has the same address and size as the - base candidate of the access. */ - if (lhs == base - || (((TYPE_SIZE (TREE_TYPE (lhs)) - == TYPE_SIZE (TREE_TYPE (base))) - || (TYPE_SIZE (TREE_TYPE (lhs)) - && TYPE_SIZE (TREE_TYPE (base)) - && operand_equal_p (TYPE_SIZE (TREE_TYPE (lhs)), - TYPE_SIZE (TREE_TYPE (base)), 0))) - && operand_equal_p (lhs, base, OEP_ADDRESS_OF))) + base candidate of the access. Watch out if we have dropped + an array-ref that was at struct end, this means ref->ref may + be outside of the TYPE_SIZE of its base. */ + if ((! innermost_dropped_array_ref + || ! array_at_struct_end_p (innermost_dropped_array_ref)) + && (lhs == base + || (((TYPE_SIZE (TREE_TYPE (lhs)) + == TYPE_SIZE (TREE_TYPE (base))) + || (TYPE_SIZE (TREE_TYPE (lhs)) + && TYPE_SIZE (TREE_TYPE (base)) + && operand_equal_p (TYPE_SIZE (TREE_TYPE (lhs)), + TYPE_SIZE (TREE_TYPE (base)), + 0))) + && operand_equal_p (lhs, base, + OEP_ADDRESS_OF + | OEP_MATCH_SIDE_EFFECTS)))) return true; } diff --git a/gcc/tree.c b/gcc/tree.c index ef9b292d773..d7d01bb4e52 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -13219,18 +13219,26 @@ array_ref_up_bound (tree exp) return NULL_TREE; } -/* Returns true if REF is an array reference to an array at the end of - a structure. If this is the case, the array may be allocated larger - than its upper bound implies. When ALLOW_COMPREF is true considers - REF when it's a COMPONENT_REF in addition ARRAY_REF and - ARRAY_RANGE_REF. */ +/* Returns true if REF is an array reference or a component reference + to an array at the end of a structure. + If this is the case, the array may be allocated larger + than its upper bound implies. */ bool -array_at_struct_end_p (tree ref, bool allow_compref) +array_at_struct_end_p (tree ref) { - if (TREE_CODE (ref) != ARRAY_REF - && TREE_CODE (ref) != ARRAY_RANGE_REF - && (!allow_compref || TREE_CODE (ref) != COMPONENT_REF)) + tree atype; + + if (TREE_CODE (ref) == ARRAY_REF + || TREE_CODE (ref) == ARRAY_RANGE_REF) + { + atype = TREE_TYPE (TREE_OPERAND (ref, 0)); + ref = TREE_OPERAND (ref, 0); + } + else if (TREE_CODE (ref) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE) + atype = TREE_TYPE (TREE_OPERAND (ref, 1)); + else return false; while (handled_component_p (ref)) @@ -13238,19 +13246,42 @@ array_at_struct_end_p (tree ref, bool allow_compref) /* If the reference chain contains a component reference to a non-union type and there follows another field the reference is not at the end of a structure. */ - if (TREE_CODE (ref) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE) + if (TREE_CODE (ref) == COMPONENT_REF) { - tree nextf = DECL_CHAIN (TREE_OPERAND (ref, 1)); - while (nextf && TREE_CODE (nextf) != FIELD_DECL) - nextf = DECL_CHAIN (nextf); - if (nextf) - return false; + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE) + { + tree nextf = DECL_CHAIN (TREE_OPERAND (ref, 1)); + while (nextf && TREE_CODE (nextf) != FIELD_DECL) + nextf = DECL_CHAIN (nextf); + if (nextf) + return false; + } } + /* If we have a multi-dimensional array we do not consider + a non-innermost dimension as flex array if the whole + multi-dimensional array is at struct end. + Same for an array of aggregates with a trailing array + member. */ + else if (TREE_CODE (ref) == ARRAY_REF) + return false; + else if (TREE_CODE (ref) == ARRAY_RANGE_REF) + ; + /* If we view an underlying object as sth else then what we + gathered up to now is what we have to rely on. */ + else if (TREE_CODE (ref) == VIEW_CONVERT_EXPR) + break; + else + gcc_unreachable (); ref = TREE_OPERAND (ref, 0); } + /* The array now is at struct end. Treat flexible arrays as + always subject to extend, even into just padding constrained by + an underlying decl. */ + if (! TYPE_SIZE (atype)) + return true; + tree size = NULL; if (TREE_CODE (ref) == MEM_REF diff --git a/gcc/tree.h b/gcc/tree.h index 0d805c0ca2a..375edcd4ba6 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4870,12 +4870,10 @@ extern tree array_ref_up_bound (tree); EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */ extern tree array_ref_low_bound (tree); -/* Returns true if REF is an array reference to an array at the end of - a structure. If this is the case, the array may be allocated larger - than its upper bound implies. When second argument is true considers - REF when it's a COMPONENT_REF in addition ARRAY_REF and - ARRAY_RANGE_REF. */ -extern bool array_at_struct_end_p (tree, bool = false); +/* Returns true if REF is an array reference or a component reference + to an array at the end of a structure. If this is the case, the array + may be allocated larger than its upper bound implies. */ +extern bool array_at_struct_end_p (tree); /* Return a tree representing the offset, in bytes, of the field referenced by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */