summaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2020-01-10 22:18:22 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2020-01-10 22:18:22 +0100
commitea69031c5facc70e4a96df83cd58702900fd54b6 (patch)
tree879c6e151d192e9ac99c83999572027edc8d0517 /gcc/fold-const.c
parent974bb8a4dcbf51a153ab72da91a7256a296e7fa1 (diff)
re PR tree-optimization/93210 (Sub-optimal code optimization on struct/combound constexpr (gcc vs. clang))
PR tree-optimization/93210 * fold-const.h (native_encode_initializer, can_native_interpret_type_p): Declare. * fold-const.c (native_encode_string): Fix up handling with off != -1, simplify. (native_encode_initializer): New function, moved from dwarf2out.c. Adjust to native_encode_expr compatible arguments, including dry-run and partial extraction modes. Don't handle STRING_CST. (can_native_interpret_type_p): No longer static. * gimple-fold.c (fold_ctor_reference): For native_encode_expr, verify offset / BITS_PER_UNIT fits into int and don't call it if can_native_interpret_type_p fails. If suboff is NULL and for CONSTRUCTOR fold_{,non}array_ctor_reference returns NULL, retry with native_encode_initializer. (fold_const_aggregate_ref_1): Formatting fix. * dwarf2out.c (native_encode_initializer): Moved to fold-const.c. (tree_add_const_value_attribute): Adjust caller. * gcc.dg/pr93210.c: New test. * g++.dg/opt/pr93210.C: New test. From-SVN: r280141
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c219
1 files changed, 212 insertions, 7 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 37c3432d4dd..aefa91666e2 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -7837,9 +7837,10 @@ native_encode_string (const_tree expr, unsigned char *ptr, int len, int off)
return 0;
if (off == -1)
off = 0;
+ len = MIN (total_bytes - off, len);
if (ptr == NULL)
/* Dry run. */;
- else if (TREE_STRING_LENGTH (expr) - off < MIN (total_bytes, len))
+ else
{
int written = 0;
if (off < TREE_STRING_LENGTH (expr))
@@ -7847,12 +7848,9 @@ native_encode_string (const_tree expr, unsigned char *ptr, int len, int off)
written = MIN (len, TREE_STRING_LENGTH (expr) - off);
memcpy (ptr, TREE_STRING_POINTER (expr) + off, written);
}
- memset (ptr + written, 0,
- MIN (total_bytes - written, len - written));
+ memset (ptr + written, 0, len - written);
}
- else
- memcpy (ptr, TREE_STRING_POINTER (expr) + off, MIN (total_bytes, len));
- return MIN (total_bytes - off, len);
+ return len;
}
@@ -7895,6 +7893,213 @@ native_encode_expr (const_tree expr, unsigned char *ptr, int len, int off)
}
}
+/* Similar to native_encode_expr, but also handle CONSTRUCTORs, VCEs,
+ NON_LVALUE_EXPRs and nops. */
+
+int
+native_encode_initializer (tree init, unsigned char *ptr, int len,
+ int off)
+{
+ /* We don't support starting at negative offset and -1 is special. */
+ if (off < -1 || init == NULL_TREE)
+ return 0;
+
+ STRIP_NOPS (init);
+ switch (TREE_CODE (init))
+ {
+ case VIEW_CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ return native_encode_initializer (TREE_OPERAND (init, 0), ptr, len, off);
+ default:
+ return native_encode_expr (init, ptr, len, off);
+ case CONSTRUCTOR:
+ tree type = TREE_TYPE (init);
+ HOST_WIDE_INT total_bytes = int_size_in_bytes (type);
+ if (total_bytes < 0)
+ return 0;
+ if ((off == -1 && total_bytes > len) || off >= total_bytes)
+ return 0;
+ int o = off == -1 ? 0 : off;
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ HOST_WIDE_INT min_index;
+ unsigned HOST_WIDE_INT cnt;
+ HOST_WIDE_INT curpos = 0, fieldsize;
+ constructor_elt *ce;
+
+ if (TYPE_DOMAIN (type) == NULL_TREE
+ || !tree_fits_shwi_p (TYPE_MIN_VALUE (TYPE_DOMAIN (type))))
+ return 0;
+
+ fieldsize = int_size_in_bytes (TREE_TYPE (type));
+ if (fieldsize <= 0)
+ return 0;
+
+ min_index = tree_to_shwi (TYPE_MIN_VALUE (TYPE_DOMAIN (type)));
+ if (ptr != NULL)
+ memset (ptr, '\0', MIN (total_bytes - off, len));
+
+ FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (init), cnt, ce)
+ {
+ tree val = ce->value;
+ tree index = ce->index;
+ HOST_WIDE_INT pos = curpos, count = 0;
+ bool full = false;
+ if (index && TREE_CODE (index) == RANGE_EXPR)
+ {
+ if (!tree_fits_shwi_p (TREE_OPERAND (index, 0))
+ || !tree_fits_shwi_p (TREE_OPERAND (index, 1)))
+ return 0;
+ pos = (tree_to_shwi (TREE_OPERAND (index, 0)) - min_index)
+ * fieldsize;
+ count = (tree_to_shwi (TREE_OPERAND (index, 1))
+ - tree_to_shwi (TREE_OPERAND (index, 0)));
+ }
+ else if (index)
+ {
+ if (!tree_fits_shwi_p (index))
+ return 0;
+ pos = (tree_to_shwi (index) - min_index) * fieldsize;
+ }
+
+ curpos = pos;
+ if (val)
+ do
+ {
+ if (off == -1
+ || (curpos >= off
+ && (curpos + fieldsize
+ <= (HOST_WIDE_INT) off + len)))
+ {
+ if (full)
+ {
+ if (ptr)
+ memcpy (ptr + (curpos - o), ptr + (pos - o),
+ fieldsize);
+ }
+ else if (!native_encode_initializer (val,
+ ptr
+ ? ptr + curpos - o
+ : NULL,
+ fieldsize,
+ off == -1 ? -1
+ : 0))
+ return 0;
+ else
+ {
+ full = true;
+ pos = curpos;
+ }
+ }
+ else if (curpos + fieldsize > off
+ && curpos < (HOST_WIDE_INT) off + len)
+ {
+ /* Partial overlap. */
+ unsigned char *p = NULL;
+ int no = 0;
+ int l;
+ if (curpos >= off)
+ {
+ if (ptr)
+ p = ptr + curpos - off;
+ l = MIN ((HOST_WIDE_INT) off + len - curpos,
+ fieldsize);
+ }
+ else
+ {
+ p = ptr;
+ no = off - curpos;
+ l = len;
+ }
+ if (!native_encode_initializer (val, p, l, no))
+ return 0;
+ }
+ curpos += fieldsize;
+ }
+ while (count-- != 0);
+ }
+ return MIN (total_bytes - off, len);
+ }
+ else if (TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == UNION_TYPE)
+ {
+ unsigned HOST_WIDE_INT cnt;
+ constructor_elt *ce;
+
+ if (ptr != NULL)
+ memset (ptr, '\0', MIN (total_bytes - off, len));
+ FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (init), cnt, ce)
+ {
+ tree field = ce->index;
+ tree val = ce->value;
+ HOST_WIDE_INT pos, fieldsize;
+
+ if (field == NULL_TREE)
+ return 0;
+
+ pos = int_byte_position (field);
+ if (off != -1 && (HOST_WIDE_INT) off + len <= pos)
+ continue;
+
+ if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+ && TYPE_DOMAIN (TREE_TYPE (field))
+ && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
+ return 0;
+ if (DECL_SIZE_UNIT (field) == NULL_TREE
+ || !tree_fits_shwi_p (DECL_SIZE_UNIT (field)))
+ return 0;
+ fieldsize = tree_to_shwi (DECL_SIZE_UNIT (field));
+ if (fieldsize == 0)
+ continue;
+
+ if (off != -1 && pos + fieldsize <= off)
+ continue;
+
+ if (DECL_BIT_FIELD (field))
+ return 0;
+
+ if (val == NULL_TREE)
+ continue;
+
+ if (off == -1
+ || (pos >= off
+ && (pos + fieldsize <= (HOST_WIDE_INT) off + len)))
+ {
+ if (!native_encode_initializer (val, ptr ? ptr + pos - o
+ : NULL,
+ fieldsize,
+ off == -1 ? -1 : 0))
+ return 0;
+ }
+ else
+ {
+ /* Partial overlap. */
+ unsigned char *p = NULL;
+ int no = 0;
+ int l;
+ if (pos >= off)
+ {
+ if (ptr)
+ p = ptr + pos - off;
+ l = MIN ((HOST_WIDE_INT) off + len - pos,
+ fieldsize);
+ }
+ else
+ {
+ p = ptr;
+ no = off - pos;
+ l = len;
+ }
+ if (!native_encode_initializer (val, p, l, no))
+ return 0;
+ }
+ }
+ return MIN (total_bytes - off, len);
+ }
+ return 0;
+ }
+}
+
/* Subroutine of native_interpret_expr. Interpret the contents of
the buffer PTR of length LEN as an INTEGER_CST of type TYPE.
@@ -8129,7 +8334,7 @@ native_interpret_expr (tree type, const unsigned char *ptr, int len)
/* Returns true if we can interpret the contents of a native encoding
as TYPE. */
-static bool
+bool
can_native_interpret_type_p (tree type)
{
switch (TREE_CODE (type))