Commit b2505143 by Richard Biener Committed by Richard Biener

re PR middle-end/61762 (failure to optimize memcpy from constant string)

2014-07-25  Richard Biener  <rguenther@suse.de>

	PR middle-end/61762
	PR middle-end/61894
	* fold-const.c (native_encode_int): Add and handle offset
	parameter to do partial encodings of expr.
	(native_encode_fixed): Likewise.
	(native_encode_real): Likewise.
	(native_encode_complex): Likewise.
	(native_encode_vector): Likewise.
	(native_encode_string): Likewise.
	(native_encode_expr): Likewise.
	* fold-const.c (native_encode_expr): Add offset parameter
	defaulting to -1.
	* gimple-fold.c (fold_string_cst_ctor_reference): Remove.
	(fold_ctor_reference): Handle all reads from tcc_constant
	ctors.

	* gcc.dg/pr61762.c: New testcase.
	* gcc.dg/fold-cstring.c: Likewise.
	* gcc.dg/fold-cvect.c: Likewise.

From-SVN: r213045
parent 1ed85d52
2014-07-25 Richard Biener <rguenther@suse.de>
PR middle-end/61762
PR middle-end/61894
* fold-const.c (native_encode_int): Add and handle offset
parameter to do partial encodings of expr.
(native_encode_fixed): Likewise.
(native_encode_real): Likewise.
(native_encode_complex): Likewise.
(native_encode_vector): Likewise.
(native_encode_string): Likewise.
(native_encode_expr): Likewise.
* fold-const.c (native_encode_expr): Add offset parameter
defaulting to -1.
* gimple-fold.c (fold_string_cst_ctor_reference): Remove.
(fold_ctor_reference): Handle all reads from tcc_constant
ctors.
2014-07-25 Richard Biener <rguenther@suse.de>
* tree-inline.c (estimate_move_cost): Mark speed_p argument
as possibly unused.
......
......@@ -7240,15 +7240,18 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code code, tree type,
upon failure. */
static int
native_encode_int (const_tree expr, unsigned char *ptr, int len)
native_encode_int (const_tree expr, unsigned char *ptr, int len, int off)
{
tree type = TREE_TYPE (expr);
int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
int byte, offset, word, words;
unsigned char value;
if (total_bytes > len)
if ((off == -1 && total_bytes > len)
|| off >= total_bytes)
return 0;
if (off == -1)
off = 0;
words = total_bytes / UNITS_PER_WORD;
for (byte = 0; byte < total_bytes; byte++)
......@@ -7271,9 +7274,11 @@ native_encode_int (const_tree expr, unsigned char *ptr, int len)
}
else
offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
ptr[offset] = value;
if (offset >= off
&& offset - off < len)
ptr[offset - off] = value;
}
return total_bytes;
return MIN (len, total_bytes - off);
}
......@@ -7283,7 +7288,7 @@ native_encode_int (const_tree expr, unsigned char *ptr, int len)
upon failure. */
static int
native_encode_fixed (const_tree expr, unsigned char *ptr, int len)
native_encode_fixed (const_tree expr, unsigned char *ptr, int len, int off)
{
tree type = TREE_TYPE (expr);
enum machine_mode mode = TYPE_MODE (type);
......@@ -7303,7 +7308,7 @@ native_encode_fixed (const_tree expr, unsigned char *ptr, int len)
value = TREE_FIXED_CST (expr);
i_value = double_int_to_tree (i_type, value.data);
return native_encode_int (i_value, ptr, len);
return native_encode_int (i_value, ptr, len, off);
}
......@@ -7313,7 +7318,7 @@ native_encode_fixed (const_tree expr, unsigned char *ptr, int len)
upon failure. */
static int
native_encode_real (const_tree expr, unsigned char *ptr, int len)
native_encode_real (const_tree expr, unsigned char *ptr, int len, int off)
{
tree type = TREE_TYPE (expr);
int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
......@@ -7325,8 +7330,11 @@ native_encode_real (const_tree expr, unsigned char *ptr, int len)
up to 192 bits. */
long tmp[6];
if (total_bytes > len)
if ((off == -1 && total_bytes > len)
|| off >= total_bytes)
return 0;
if (off == -1)
off = 0;
words = (32 / BITS_PER_UNIT) / UNITS_PER_WORD;
real_to_target (tmp, TREE_REAL_CST_PTR (expr), TYPE_MODE (type));
......@@ -7350,9 +7358,12 @@ native_encode_real (const_tree expr, unsigned char *ptr, int len)
}
else
offset = BYTES_BIG_ENDIAN ? 3 - byte : byte;
ptr[offset + ((bitpos / BITS_PER_UNIT) & ~3)] = value;
offset = offset + ((bitpos / BITS_PER_UNIT) & ~3);
if (offset >= off
&& offset - off < len)
ptr[offset - off] = value;
}
return total_bytes;
return MIN (len, total_bytes - off);
}
/* Subroutine of native_encode_expr. Encode the COMPLEX_CST
......@@ -7361,18 +7372,22 @@ native_encode_real (const_tree expr, unsigned char *ptr, int len)
upon failure. */
static int
native_encode_complex (const_tree expr, unsigned char *ptr, int len)
native_encode_complex (const_tree expr, unsigned char *ptr, int len, int off)
{
int rsize, isize;
tree part;
part = TREE_REALPART (expr);
rsize = native_encode_expr (part, ptr, len);
if (rsize == 0)
rsize = native_encode_expr (part, ptr, len, off);
if (off == -1
&& rsize == 0)
return 0;
part = TREE_IMAGPART (expr);
isize = native_encode_expr (part, ptr+rsize, len-rsize);
if (isize != rsize)
if (off != -1)
off = MAX (0, off - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (part))));
isize = native_encode_expr (part, ptr+rsize, len-rsize, off);
if (off == -1
&& isize != rsize)
return 0;
return rsize + isize;
}
......@@ -7384,7 +7399,7 @@ native_encode_complex (const_tree expr, unsigned char *ptr, int len)
upon failure. */
static int
native_encode_vector (const_tree expr, unsigned char *ptr, int len)
native_encode_vector (const_tree expr, unsigned char *ptr, int len, int off)
{
unsigned i, count;
int size, offset;
......@@ -7396,10 +7411,21 @@ native_encode_vector (const_tree expr, unsigned char *ptr, int len)
size = GET_MODE_SIZE (TYPE_MODE (itype));
for (i = 0; i < count; i++)
{
if (off >= size)
{
off -= size;
continue;
}
elem = VECTOR_CST_ELT (expr, i);
if (native_encode_expr (elem, ptr+offset, len-offset) != size)
int res = native_encode_expr (elem, ptr+offset, len-offset, off);
if ((off == -1 && res != size)
|| res == 0)
return 0;
offset += size;
offset += res;
if (offset >= len)
return offset;
if (off != -1)
off = 0;
}
return offset;
}
......@@ -7411,7 +7437,7 @@ native_encode_vector (const_tree expr, unsigned char *ptr, int len)
upon failure. */
static int
native_encode_string (const_tree expr, unsigned char *ptr, int len)
native_encode_string (const_tree expr, unsigned char *ptr, int len, int off)
{
tree type = TREE_TYPE (expr);
HOST_WIDE_INT total_bytes;
......@@ -7422,47 +7448,56 @@ native_encode_string (const_tree expr, unsigned char *ptr, int len)
|| !tree_fits_shwi_p (TYPE_SIZE_UNIT (type)))
return 0;
total_bytes = tree_to_shwi (TYPE_SIZE_UNIT (type));
if (total_bytes > len)
if ((off == -1 && total_bytes > len)
|| off >= total_bytes)
return 0;
if (TREE_STRING_LENGTH (expr) < total_bytes)
if (off == -1)
off = 0;
if (TREE_STRING_LENGTH (expr) - off < MIN (total_bytes, len))
{
memcpy (ptr, TREE_STRING_POINTER (expr), TREE_STRING_LENGTH (expr));
memset (ptr + TREE_STRING_LENGTH (expr), 0,
total_bytes - TREE_STRING_LENGTH (expr));
int written = 0;
if (off < TREE_STRING_LENGTH (expr))
{
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));
}
else
memcpy (ptr, TREE_STRING_POINTER (expr), total_bytes);
return total_bytes;
memcpy (ptr, TREE_STRING_POINTER (expr) + off, MIN (total_bytes, len));
return MIN (total_bytes - off, len);
}
/* Subroutine of fold_view_convert_expr. Encode the INTEGER_CST,
REAL_CST, COMPLEX_CST or VECTOR_CST specified by EXPR into the
buffer PTR of length LEN bytes. Return the number of bytes
placed in the buffer, or zero upon failure. */
buffer PTR of length LEN bytes. If OFF is not -1 then start
the encoding at byte offset OFF and encode at most LEN bytes.
Return the number of bytes placed in the buffer, or zero upon failure. */
int
native_encode_expr (const_tree expr, unsigned char *ptr, int len)
native_encode_expr (const_tree expr, unsigned char *ptr, int len, int off)
{
switch (TREE_CODE (expr))
{
case INTEGER_CST:
return native_encode_int (expr, ptr, len);
return native_encode_int (expr, ptr, len, off);
case REAL_CST:
return native_encode_real (expr, ptr, len);
return native_encode_real (expr, ptr, len, off);
case FIXED_CST:
return native_encode_fixed (expr, ptr, len);
return native_encode_fixed (expr, ptr, len, off);
case COMPLEX_CST:
return native_encode_complex (expr, ptr, len);
return native_encode_complex (expr, ptr, len, off);
case VECTOR_CST:
return native_encode_vector (expr, ptr, len);
return native_encode_vector (expr, ptr, len, off);
case STRING_CST:
return native_encode_string (expr, ptr, len);
return native_encode_string (expr, ptr, len, off);
default:
return 0;
......
......@@ -25,7 +25,7 @@ along with GCC; see the file COPYING3. If not see
extern int folding_initializer;
/* Convert between trees and native memory representation. */
extern int native_encode_expr (const_tree, unsigned char *, int);
extern int native_encode_expr (const_tree, unsigned char *, int, int off = -1);
extern tree native_interpret_expr (tree, const unsigned char *, int);
/* Fold constants as much as possible in an expression.
......
......@@ -2881,41 +2881,6 @@ get_base_constructor (tree base, HOST_WIDE_INT *bit_offset,
}
}
/* CTOR is STRING_CST. Fold reference of type TYPE and size SIZE
to the memory at bit OFFSET.
We do only simple job of folding byte accesses. */
static tree
fold_string_cst_ctor_reference (tree type, tree ctor,
unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT size)
{
if (INTEGRAL_TYPE_P (type)
&& (TYPE_MODE (type)
== TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
&& (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
== MODE_INT)
&& GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1
&& size == BITS_PER_UNIT
&& !(offset % BITS_PER_UNIT))
{
offset /= BITS_PER_UNIT;
if (offset < (unsigned HOST_WIDE_INT) TREE_STRING_LENGTH (ctor))
return build_int_cst_type (type, (TREE_STRING_POINTER (ctor)
[offset]));
/* Folding
const char a[20]="hello";
return a[10];
might lead to offset greater than string length. In this case we
know value is either initialized to 0 or out of bounds. Return 0
in both cases. */
return build_zero_cst (type);
}
return NULL_TREE;
}
/* CTOR is CONSTRUCTOR of an array type. Fold reference of type TYPE and size
SIZE to the memory at bit OFFSET. */
......@@ -3107,8 +3072,19 @@ fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
STRIP_NOPS (ret);
return ret;
}
if (TREE_CODE (ctor) == STRING_CST)
return fold_string_cst_ctor_reference (type, ctor, offset, size);
/* For constants and byte-aligned/sized reads try to go through
native_encode/interpret. */
if (CONSTANT_CLASS_P (ctor)
&& BITS_PER_UNIT == 8
&& offset % BITS_PER_UNIT == 0
&& size % BITS_PER_UNIT == 0
&& size <= MAX_BITSIZE_MODE_ANY_MODE)
{
unsigned char buf[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT];
if (native_encode_expr (ctor, buf, size / BITS_PER_UNIT,
offset / BITS_PER_UNIT) > 0)
return native_interpret_expr (type, buf, size / BITS_PER_UNIT);
}
if (TREE_CODE (ctor) == CONSTRUCTOR)
{
......
2014-07-25 Richard Biener <rguenther@suse.de>
PR middle-end/61762
PR middle-end/61894
* gcc.dg/pr61762.c: New testcase.
* gcc.dg/fold-cstring.c: Likewise.
* gcc.dg/fold-cvect.c: Likewise.
2014-07-24 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
* gcc.target/powerpc/ppc64-abi-warn-3.c: New test.
......
/* { dg-do run } */
/* { dg-options "-O" } */
/* The following are testcases for native_interpret_int,
native_interpret_complex and native_interpret_vector decoding
pieces of a string constant encoded by native_encode_string. */
extern void abort (void);
/* We should fold all reads from xconstant and eliminate it, removing
the reference to blah which cannot be resolved at link time. */
extern int blah;
static const struct {
int *y;
const char x[32] __attribute__((aligned(32)));
} xconstant = { &blah, "01234567899876543210123456789000" };
typedef int v4si __attribute__((vector_size(16)));
int main()
{
if (sizeof (int) != 4)
return 0;
if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
{
if (*(int *)&xconstant.x[4] != 0x34353637)
abort ();
if ((*(v4si *)&xconstant.x[16])[1] != 0x31323334)
abort ();
if (__imag (*(_Complex int *)&xconstant.x[8]) != 0x37363534)
abort ();
}
else if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
{
if (*(int *)&xconstant.x[4] != 0x37363534)
abort ();
if ((*(v4si *)&xconstant.x[16])[1] != 0x34333231)
abort ();
if (__imag (*(_Complex int *)&xconstant.x[8]) != 0x34353637)
abort ();
}
return 0;
}
/* { dg-do run } */
/* { dg-options "-O" } */
extern void abort (void);
/* We should fold all reads from xconstant and eliminate it, removing
the reference to blah which cannot be resolved at link time. */
extern int blah;
typedef int v4si __attribute__((vector_size(16)));
static const struct {
int *y;
const v4si x[2] __attribute__((aligned(32)));
} xconstant = { &blah, { { 0, 1, 2, 3 }, { 2, 3, 4, 5 } } };
int main()
{
if (sizeof (int) != 4)
return 0;
if (*(int *)&xconstant.x[0][0] != 0)
abort ();
if (*(int *)&xconstant.x[0][1] != 1)
abort ();
if (*(int *)&xconstant.x[0][2] != 2)
abort ();
if (*(int *)&xconstant.x[0][3] != 3)
abort ();
if (*(int *)&xconstant.x[1][0] != 2)
abort ();
if (*(int *)&xconstant.x[1][1] != 3)
abort ();
if (*(int *)&xconstant.x[1][2] != 4)
abort ();
if (*(int *)&xconstant.x[1][3] != 5)
abort ();
return 0;
}
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-release_ssa" } */
unsigned int f()
{
static const char string[] = "Private";
unsigned int priv;
__builtin_memcpy(&priv, &string[0], sizeof(priv));
return priv;
}
/* We should have removed the static string and simplified the
memcpy to a store from an integer constant. CCP
already performs the simplification but only after release_ssa
the unused local static is removed. */
/* { dg-final { scan-tree-dump-not "Private" "release_ssa" } } */
/* { dg-final { cleanup-tree-dump "release_ssa" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment