aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.c
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2019-07-12 10:03:10 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2019-07-12 10:03:10 +0000
commit831e688af50c5f77a2daa3cd3bfd0f27d54d5d72 (patch)
treeea4a80650c7c4334d9576ee571c395e345cfec8a /gcc/gimple-fold.c
parente067f9924bad423bf6265b75414d3160e6cf660a (diff)
downloadgcc-831e688af50c5f77a2daa3cd3bfd0f27d54d5d72.zip
gcc-831e688af50c5f77a2daa3cd3bfd0f27d54d5d72.tar.gz
gcc-831e688af50c5f77a2daa3cd3bfd0f27d54d5d72.tar.bz2
fold-const.h (get_array_ctor_element_at_index): Adjust.
2019-07-12 Richard Biener <rguenther@suse.de> * 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
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r--gcc/gimple-fold.c91
1 files changed, 84 insertions, 7 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 118718a..be83620 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)