From 831e688af50c5f77a2daa3cd3bfd0f27d54d5d72 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 12 Jul 2019 10:03:10 +0000 Subject: [PATCH] fold-const.h (get_array_ctor_element_at_index): Adjust. 2019-07-12 Richard Biener * fold-const.h (get_array_ctor_element_at_index): Adjust. * fold-const.c (get_array_ctor_element_at_index): Add ctor_idx output parameter informing the caller where in the constructor the element was (not) found. Add early exit for when the ctor is sorted. * gimple-fold.c (fold_array_ctor_reference): Support constant folding across multiple array elements. * gcc.dg/tree-ssa/vector-7.c: New testcase. From-SVN: r273435 --- gcc/ChangeLog | 10 +++ gcc/fold-const.c | 36 +++++++--- gcc/fold-const.h | 3 +- gcc/gimple-fold.c | 91 ++++++++++++++++++++++-- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gcc.dg/tree-ssa/vector-7.c | 39 ++++++++++ 6 files changed, 167 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vector-7.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e75e1ec8da6..bd47dddc524 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2019-07-12 Richard Biener + + * fold-const.h (get_array_ctor_element_at_index): Adjust. + * fold-const.c (get_array_ctor_element_at_index): Add + ctor_idx output parameter informing the caller where in + the constructor the element was (not) found. Add early exit + for when the ctor is sorted. + * gimple-fold.c (fold_array_ctor_reference): Support constant + folding across multiple array elements. + 2019-07-12 Eric Botcazou * cfgexpand.c (expand_gimple_stmt_1) : If the statement diff --git a/gcc/fold-const.c b/gcc/fold-const.c index edb23fd1b84..74544bfe5c2 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -11839,10 +11839,15 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, } /* Gets the element ACCESS_INDEX from CTOR, which must be a CONSTRUCTOR - of an array (or vector). */ + of an array (or vector). *CTOR_IDX if non-NULL is updated with the + constructor element index of the value returned. If the element is + not found NULL_TREE is returned and *CTOR_IDX is updated to + the index of the element after the ACCESS_INDEX position (which + may be outside of the CTOR array). */ tree -get_array_ctor_element_at_index (tree ctor, offset_int access_index) +get_array_ctor_element_at_index (tree ctor, offset_int access_index, + unsigned *ctor_idx) { tree index_type = NULL_TREE; offset_int low_bound = 0; @@ -11869,7 +11874,7 @@ get_array_ctor_element_at_index (tree ctor, offset_int access_index) TYPE_SIGN (index_type)); offset_int max_index; - unsigned HOST_WIDE_INT cnt; + unsigned cnt; tree cfield, cval; FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval) @@ -11897,11 +11902,26 @@ get_array_ctor_element_at_index (tree ctor, offset_int access_index) max_index = index; } - /* Do we have match? */ - if (wi::cmpu (access_index, index) >= 0 - && wi::cmpu (access_index, max_index) <= 0) - return cval; - } + /* Do we have match? */ + if (wi::cmpu (access_index, index) >= 0) + { + if (wi::cmpu (access_index, max_index) <= 0) + { + if (ctor_idx) + *ctor_idx = cnt; + return cval; + } + } + else if (in_gimple_form) + /* We're past the element we search for. Note during parsing + the elements might not be sorted. + ??? We should use a binary search and a flag on the + CONSTRUCTOR as to whether elements are sorted in declaration + order. */ + break; + } + if (ctor_idx) + *ctor_idx = cnt; return NULL_TREE; } diff --git a/gcc/fold-const.h b/gcc/fold-const.h index 2a69bf9163d..eab2b47a260 100644 --- a/gcc/fold-const.h +++ b/gcc/fold-const.h @@ -67,7 +67,8 @@ extern tree fold_build_call_array_loc (location_t, tree, tree, int, tree *); #define fold_build_call_array_initializer(T1,T2,N,T4)\ fold_build_call_array_initializer_loc (UNKNOWN_LOCATION, T1, T2, N, T4) extern tree fold_build_call_array_initializer_loc (location_t, tree, tree, int, tree *); -extern tree get_array_ctor_element_at_index (tree, offset_int); +extern tree get_array_ctor_element_at_index (tree, offset_int, + unsigned * = NULL); extern bool fold_convertible_p (const_tree, const_tree); #define fold_convert(T1,T2)\ fold_convert_loc (UNKNOWN_LOCATION, T1, T2) diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 118718a59ee..be83620deee 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -6716,14 +6716,13 @@ fold_array_ctor_reference (tree type, tree ctor, elt_size = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor)))); /* When TYPE is non-null, verify that it specifies a constant-sized - accessed not larger than size of array element. Avoid division + access of a multiple of the array element size. Avoid division by zero below when ELT_SIZE is zero, such as with the result of an initializer for a zero-length array or an empty struct. */ if (elt_size == 0 || (type && (!TYPE_SIZE_UNIT (type) - || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST - || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type))))) + || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST))) return NULL_TREE; /* Compute the array index we look for. */ @@ -6734,10 +6733,88 @@ fold_array_ctor_reference (tree type, tree ctor, /* And offset within the access. */ inner_offset = offset % (elt_size.to_uhwi () * BITS_PER_UNIT); - /* See if the array field is large enough to span whole access. We do not - care to fold accesses spanning multiple array indexes. */ - if (inner_offset + size > elt_size.to_uhwi () * BITS_PER_UNIT) - return NULL_TREE; + if (size > elt_size.to_uhwi () * BITS_PER_UNIT) + { + /* native_encode_expr constraints. */ + if (size > MAX_BITSIZE_MODE_ANY_MODE + || size % BITS_PER_UNIT != 0 + || inner_offset % BITS_PER_UNIT != 0) + return NULL_TREE; + + unsigned ctor_idx; + tree val = get_array_ctor_element_at_index (ctor, access_index, + &ctor_idx); + if (!val && ctor_idx >= CONSTRUCTOR_NELTS (ctor)) + return build_zero_cst (type); + + /* native-encode adjacent ctor elements. */ + unsigned char buf[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT]; + unsigned bufoff = 0; + offset_int index = 0; + offset_int max_index = access_index; + constructor_elt *elt = CONSTRUCTOR_ELT (ctor, ctor_idx); + if (!val) + val = build_zero_cst (TREE_TYPE (TREE_TYPE (ctor))); + else if (!CONSTANT_CLASS_P (val)) + return NULL_TREE; + if (!elt->index) + ; + else if (TREE_CODE (elt->index) == RANGE_EXPR) + { + index = wi::to_offset (TREE_OPERAND (elt->index, 0)); + max_index = wi::to_offset (TREE_OPERAND (elt->index, 1)); + } + else + index = max_index = wi::to_offset (elt->index); + index = wi::umax (index, access_index); + do + { + int len = native_encode_expr (val, buf + bufoff, + elt_size.to_uhwi (), + inner_offset / BITS_PER_UNIT); + if (len != elt_size - inner_offset / BITS_PER_UNIT) + return NULL_TREE; + inner_offset = 0; + bufoff += len; + + access_index += 1; + if (wi::cmpu (access_index, index) == 0) + val = elt->value; + else if (wi::cmpu (access_index, max_index) > 0) + { + ctor_idx++; + if (ctor_idx >= CONSTRUCTOR_NELTS (ctor)) + { + val = build_zero_cst (TREE_TYPE (TREE_TYPE (ctor))); + ++max_index; + } + else + { + elt = CONSTRUCTOR_ELT (ctor, ctor_idx); + index = 0; + max_index = access_index; + if (!elt->index) + ; + else if (TREE_CODE (elt->index) == RANGE_EXPR) + { + index = wi::to_offset (TREE_OPERAND (elt->index, 0)); + max_index = wi::to_offset (TREE_OPERAND (elt->index, 1)); + } + else + index = max_index = wi::to_offset (elt->index); + index = wi::umax (index, access_index); + if (wi::cmpu (access_index, index) == 0) + val = elt->value; + else + val = build_zero_cst (TREE_TYPE (TREE_TYPE (ctor))); + } + } + } + while (bufoff < size / BITS_PER_UNIT); + *suboff += size; + return native_interpret_expr (type, buf, size / BITS_PER_UNIT); + } + if (tree val = get_array_ctor_element_at_index (ctor, access_index)) { if (!size && TREE_CODE (val) != CONSTRUCTOR) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ed3165ee4a5..dfda37f912c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-07-12 Richard Biener + + * gcc.dg/tree-ssa/vector-7.c: New testcase. + 2019-07-12 Jakub Jelinek * c-c++-common/gomp/order-1.c: New test. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vector-7.c b/gcc/testsuite/gcc.dg/tree-ssa/vector-7.c new file mode 100644 index 00000000000..ebfe15dcfc8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vector-7.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fdump-tree-optimized" } */ + +typedef __INT8_TYPE__ v16qi __attribute__((vector_size(16),may_alias,aligned(1))); +typedef __INT32_TYPE__ v4si __attribute__((vector_size(16),may_alias,aligned(1))); + +const __INT32_TYPE__ x[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; +const __INT8_TYPE__ y[32] + = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; +const __INT32_TYPE__ z[8] = { [3] = 3, [1] = 1 }; + +int +main() +{ + v4si v1 = *(v4si *)(x + 1); + for (unsigned i = 0; i < 4; ++i) + if (v1[i] != (v4si) { 2, 3, 4, 5 }[i]) + __builtin_abort (); + v4si v2 = *(v4si *)z; + for (unsigned i = 0; i < 4; ++i) + if (v2[i] != (v4si) { 0, 1, 0, 3 }[i]) + __builtin_abort (); + v4si v3 = *(v4si *)(y + 1); + for (unsigned i = 0; i < 4; ++i) + if (v3[i] != +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + (v4si) { 0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f01 }[i] +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + (v4si) { 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d }[i] +#else + v3[i] +#endif + ) + __builtin_abort (); + return 0; +} + +/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */ -- 2.30.2