aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2006-11-28 15:20:04 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2006-11-28 14:20:04 +0000
commita1da787df346866e3a1f32b089a2ad5b68be53c8 (patch)
treea2ae7775885321a113a1991e85285ed724e4f17d /gcc
parentda3377842035d62be5c11845397232c0ebc58c99 (diff)
downloadgcc-a1da787df346866e3a1f32b089a2ad5b68be53c8.zip
gcc-a1da787df346866e3a1f32b089a2ad5b68be53c8.tar.gz
gcc-a1da787df346866e3a1f32b089a2ad5b68be53c8.tar.bz2
builtins.c: Include tree-flow.h.
* builtins.c: Include tree-flow.h. (fold_builtin_memory_op): Be more aggressive on converting memcpy to assignment; convert memmove to memcpy for sizes greater than 1 where alignment of operands prohibit the partial overlap. From-SVN: r119292
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/builtins.c92
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/memcpy-1.c251
4 files changed, 312 insertions, 42 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 19d2f44..af11461 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,12 @@
2006-11-28 Jan Hubicka <jh@suse.cz>
+ * builtins.c: Include tree-flow.h.
+ (fold_builtin_memory_op): Be more aggressive on converting memcpy to
+ assignment; convert memmove to memcpy for sizes greater than 1 where
+ alignment of operands prohibit the partial overlap.
+
+2006-11-28 Jan Hubicka <jh@suse.cz>
+
* invoke.texi (large-stack-frame, large-stack-frame-growth): New params.
* cgraph.c (dump_cgraph_node): Dump stack usage.
* cgraph.h (cgraph_local_info): Add estimated_self_stack_size.
diff --git a/gcc/builtins.c b/gcc/builtins.c
index d610198..f3c1623 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -47,6 +47,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "langhooks.h"
#include "basic-block.h"
#include "tree-mudflap.h"
+#include "tree-flow.h"
#ifndef PAD_VARARGS_DOWN
#define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
@@ -8142,7 +8143,6 @@ static tree
fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp)
{
tree dest, src, len, destvar, srcvar, expr;
- unsigned HOST_WIDE_INT length;
if (! validate_arglist (arglist,
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
@@ -8162,12 +8162,12 @@ fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp)
expr = len;
else
{
+ tree srctype, desttype;
if (endp == 3)
{
- unsigned int src_align
- = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
- unsigned int dest_align
- = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+ int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+ int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+
/* Both DEST and SRC must be pointer types.
??? This is what old code did. Is the testing for pointer types
really mandatory?
@@ -8175,64 +8175,72 @@ fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp)
If either SRC is readonly or length is 1, we can use memcpy. */
if (dest_align && src_align
&& (readonly_data_expr (src)
- || integer_onep (len)))
+ || (host_integerp (len, 1)
+ && (MIN (src_align, dest_align) / BITS_PER_UNIT <=
+ tree_low_cst (len, 1)))))
{
tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
if (!fn)
return 0;
return build_function_call_expr (fn, arglist);
}
+ return 0;
}
- if (! host_integerp (len, 1))
- return 0;
-
- if (TREE_SIDE_EFFECTS (dest) || TREE_SIDE_EFFECTS (src))
- return 0;
-
- destvar = dest;
- STRIP_NOPS (destvar);
- if (TREE_CODE (destvar) != ADDR_EXPR)
- return 0;
- destvar = TREE_OPERAND (destvar, 0);
- if (TREE_THIS_VOLATILE (destvar))
+ if (!host_integerp (len, 0))
return 0;
-
- if (!INTEGRAL_TYPE_P (TREE_TYPE (destvar))
- && !POINTER_TYPE_P (TREE_TYPE (destvar))
- && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (destvar)))
+ /* FIXME:
+ This logic lose for arguments like (type *)malloc (sizeof (type)),
+ since we strip the casts of up to VOID return value from malloc.
+ Perhaps we ought to inherit type from non-VOID argument here? */
+ STRIP_NOPS (src);
+ STRIP_NOPS (dest);
+ srctype = TREE_TYPE (TREE_TYPE (src));
+ desttype = TREE_TYPE (TREE_TYPE (dest));
+ if (!srctype || !desttype
+ || !TYPE_SIZE_UNIT (srctype)
+ || !TYPE_SIZE_UNIT (desttype)
+ || TREE_CODE (TYPE_SIZE_UNIT (srctype)) != INTEGER_CST
+ || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST
+ || !operand_equal_p (TYPE_SIZE_UNIT (srctype), len, 0)
+ || !operand_equal_p (TYPE_SIZE_UNIT (desttype), len, 0))
return 0;
- if (! var_decl_component_p (destvar))
+ if (get_pointer_alignment (dest, BIGGEST_ALIGNMENT)
+ < (int) TYPE_ALIGN (desttype)
+ || (get_pointer_alignment (src, BIGGEST_ALIGNMENT)
+ < (int) TYPE_ALIGN (srctype)))
return 0;
- srcvar = src;
- STRIP_NOPS (srcvar);
- if (TREE_CODE (srcvar) != ADDR_EXPR)
- return 0;
+ if (!ignore)
+ dest = builtin_save_expr (dest);
- srcvar = TREE_OPERAND (srcvar, 0);
+ srcvar = build_fold_indirect_ref (src);
if (TREE_THIS_VOLATILE (srcvar))
return 0;
-
- if (!INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
- && !POINTER_TYPE_P (TREE_TYPE (srcvar))
- && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (srcvar)))
+ /* With memcpy, it is possible to bypass aliasing rules, so without
+ this check i. e. execute/20060930-2.c would be misoptimized, because
+ it use conflicting alias set to hold argument for the memcpy call.
+ This check is probably unnecesary with -fno-strict-aliasing.
+ Similarly for destvar. See also PR29286. */
+ if (!var_decl_component_p (srcvar)
+ /* Accept: memcpy (*char_var, "test", 1); that simplify
+ to char_var='t'; */
+ || is_gimple_min_invariant (srcvar)
+ || readonly_data_expr (src))
return 0;
- if (! var_decl_component_p (srcvar))
+ destvar = build_fold_indirect_ref (dest);
+ if (TREE_THIS_VOLATILE (destvar))
return 0;
-
- length = tree_low_cst (len, 1);
- if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (destvar))) != length
- || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
- < (int) length
- || GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (srcvar))) != length
- || get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
- < (int) length)
+ if (!var_decl_component_p (destvar))
return 0;
- if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
+ if (srctype == desttype
+ || (in_ssa_p
+ && tree_ssa_useless_type_conversion_1 (desttype, srctype)))
+ expr = srcvar;
+ else if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
|| POINTER_TYPE_P (TREE_TYPE (srcvar)))
&& (INTEGRAL_TYPE_P (TREE_TYPE (destvar))
|| POINTER_TYPE_P (TREE_TYPE (destvar))))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b08954b..8d9d9e4 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2006-11-28 Jan Hubicka <jh@suse.cz>
+
+ * gcc.dg/memcpy-1.c: New test.
+
2006-11-28 Jakub Jelinek <jakub@redhat.com>
PR c++/29735
diff --git a/gcc/testsuite/gcc.dg/memcpy-1.c b/gcc/testsuite/gcc.dg/memcpy-1.c
new file mode 100644
index 0000000..bfc19dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/memcpy-1.c
@@ -0,0 +1,251 @@
+From gcc-patches-return-180556-listarch-gcc-patches=gcc dot gnu dot org at gcc dot gnu dot org Thu Oct 26 21:28:07 2006
+Return-Path: <gcc-patches-return-180556-listarch-gcc-patches=gcc dot gnu dot org at gcc dot gnu dot org>
+Delivered-To: listarch-gcc-patches at gcc dot gnu dot org
+Received: (qmail 19726 invoked by alias); 26 Oct 2006 21:28:06 -0000
+Received: (qmail 19713 invoked by uid 22791); 26 Oct 2006 21:28:05 -0000
+X-Spam-Check-By: sourceware.org
+Received: from nikam-dmz.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.31) with ESMTP; Thu, 26 Oct 2006 21:28:02 +0000
+Received: from occam.ms.mff.cuni.cz (occam.ms.mff.cuni.cz [195.113.18.121]) by nikam.ms.mff.cuni.cz (Postfix) with SMTP id F07CC5BA3F for <gcc-patches@gcc.gnu.org>; Thu, 26 Oct 2006 23:27:59 +0200 (CEST)
+Received: by occam.ms.mff.cuni.cz (sSMTP sendmail emulation); Thu, 26 Oct 2006 23:27:59 +0200
+Date: Thu, 26 Oct 2006 23:27:59 +0200
+From: Jan Hubicka <jh at suse dot cz>
+To: gcc-patches at gcc dot gnu dot org
+Subject: More memcpy folding
+Message-ID: <20061026212759.GD6035@kam.mff.cuni.cz>
+Mime-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+User-Agent: Mutt/1.5.9i
+Mailing-List: contact gcc-patches-help at gcc dot gnu dot org; run by ezmlm
+Precedence: bulk
+List-Archive: <http://gcc.gnu.org/ml/gcc-patches/>
+List-Post: <mailto:gcc-patches at gcc dot gnu dot org>
+List-Help: <mailto:gcc-patches-help at gcc dot gnu dot org>
+Sender: gcc-patches-owner at gcc dot gnu dot org
+Delivered-To: mailing list gcc-patches at gcc dot gnu dot org
+
+Hi,
+this patch extends Jakub's code to fold memcpy into assignment to case of
+structures to make GCC understand common low-level C idiom of
+memcpy (&a, &b, sizeof (*a))
+for copying structures. This is of less academic interested as my previous
+memmove folding since it matches quite few times during GCC bootstrap
+and during SPEC build. The transfomration often kills last place taking
+address of the argument thus allowing SRA and other optimizations.
+
+I tried to cover as many cases as possible. Unforutnately there are
+aliasing issues as shown by execute/20060930-2.c, so I need to check
+var_decl_component_p. With little help from PTA we should be probably
+able to do better here.
+
+Bootstrapped/regtested i686-linux, OK?
+:ADDPATCH middle-end:
+
+Honza
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times "nasty_local" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
+struct a {int a,b,c;} a;
+int test(struct a a)
+{
+struct a nasty_local;
+memcpy (&nasty_local,&a, sizeof(a));
+return nasty_local.a;
+}
+ * builtins.c: Include tree-flow.h.
+ (fold_builtin_memory_op): Be more aggressive on converting memcpy to
+ assignment; convert memmove to memcpy for sizes greater than 1 where
+ alignment of operands prohibit the partial overlap.
+Index: builtins.c
+===================================================================
+*** builtins.c (revision 118067)
+--- builtins.c (working copy)
+*************** Software Foundation, 51 Franklin Street,
+*** 47,52 ****
+--- 47,53 ----
+ #include "langhooks.h"
+ #include "basic-block.h"
+ #include "tree-mudflap.h"
++ #include "tree-flow.h"
+
+ #ifndef PAD_VARARGS_DOWN
+ #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
+*************** static tree
+*** 8029,8035 ****
+ fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp)
+ {
+ tree dest, src, len, destvar, srcvar, expr;
+- unsigned HOST_WIDE_INT length;
+
+ if (! validate_arglist (arglist,
+ POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+--- 8030,8035 ----
+*************** fold_builtin_memory_op (tree arglist, tr
+*** 8049,8060 ****
+ expr = len;
+ else
+ {
+ if (endp == 3)
+ {
+! unsigned int src_align
+! = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+! unsigned int dest_align
+! = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+ /* Both DEST and SRC must be pointer types.
+ ??? This is what old code did. Is the testing for pointer types
+ really mandatory?
+--- 8049,8060 ----
+ expr = len;
+ else
+ {
++ tree srctype, desttype;
+ if (endp == 3)
+ {
+! int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+! int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+!
+ /* Both DEST and SRC must be pointer types.
+ ??? This is what old code did. Is the testing for pointer types
+ really mandatory?
+*************** fold_builtin_memory_op (tree arglist, tr
+*** 8062,8125 ****
+ If either SRC is readonly or length is 1, we can use memcpy. */
+ if (dest_align && src_align
+ && (readonly_data_expr (src)
+! || integer_onep (len)))
+ {
+ tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ if (!fn)
+ return 0;
+ return build_function_call_expr (fn, arglist);
+ }
+ }
+- if (! host_integerp (len, 1))
+- return 0;
+-
+- if (TREE_SIDE_EFFECTS (dest) || TREE_SIDE_EFFECTS (src))
+- return 0;
+-
+- destvar = dest;
+- STRIP_NOPS (destvar);
+- if (TREE_CODE (destvar) != ADDR_EXPR)
+- return 0;
+-
+- destvar = TREE_OPERAND (destvar, 0);
+- if (TREE_THIS_VOLATILE (destvar))
+- return 0;
+
+! if (!INTEGRAL_TYPE_P (TREE_TYPE (destvar))
+! && !POINTER_TYPE_P (TREE_TYPE (destvar))
+! && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (destvar)))
+ return 0;
+!
+! if (! var_decl_component_p (destvar))
+ return 0;
+
+! srcvar = src;
+! STRIP_NOPS (srcvar);
+! if (TREE_CODE (srcvar) != ADDR_EXPR)
+! return 0;
+
+! srcvar = TREE_OPERAND (srcvar, 0);
+ if (TREE_THIS_VOLATILE (srcvar))
+ return 0;
+!
+! if (!INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
+! && !POINTER_TYPE_P (TREE_TYPE (srcvar))
+! && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (srcvar)))
+ return 0;
+
+! if (! var_decl_component_p (srcvar))
+ return 0;
+!
+! length = tree_low_cst (len, 1);
+! if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (destvar))) != length
+! || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
+! < (int) length
+! || GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (srcvar))) != length
+! || get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
+! < (int) length)
+ return 0;
+
+! if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
+ || POINTER_TYPE_P (TREE_TYPE (srcvar)))
+ && (INTEGRAL_TYPE_P (TREE_TYPE (destvar))
+ || POINTER_TYPE_P (TREE_TYPE (destvar))))
+--- 8062,8133 ----
+ If either SRC is readonly or length is 1, we can use memcpy. */
+ if (dest_align && src_align
+ && (readonly_data_expr (src)
+! || (host_integerp (len, 1)
+! && (MIN (src_align, dest_align) / BITS_PER_UNIT <=
+! tree_low_cst (len, 1)))))
+ {
+ tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ if (!fn)
+ return 0;
+ return build_function_call_expr (fn, arglist);
+ }
++ return 0;
+ }
+
+! if (!host_integerp (len, 0))
+ return 0;
+! /* FIXME:
+! This logic lose for arguments like (type *)malloc (sizeof (type)),
+! since we strip the casts of up to VOID return value from malloc.
+! Perhaps we ought to inherit type from non-VOID argument here? */
+! STRIP_NOPS (src);
+! STRIP_NOPS (dest);
+! srctype = TREE_TYPE (TREE_TYPE (src));
+! desttype = TREE_TYPE (TREE_TYPE (dest));
+! if (!srctype || !desttype
+! || !TYPE_SIZE_UNIT (srctype)
+! || !TYPE_SIZE_UNIT (desttype)
+! || TREE_CODE (TYPE_SIZE_UNIT (srctype)) != INTEGER_CST
+! || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST
+! || !operand_equal_p (TYPE_SIZE_UNIT (srctype), len, 0)
+! || !operand_equal_p (TYPE_SIZE_UNIT (desttype), len, 0))
+! return 0;
+!
+! if (get_pointer_alignment (dest, BIGGEST_ALIGNMENT)
+! < (int) TYPE_ALIGN (desttype)
+! || (get_pointer_alignment (src, BIGGEST_ALIGNMENT)
+! < (int) TYPE_ALIGN (srctype)))
+ return 0;
+
+! if (!ignore)
+! dest = builtin_save_expr (dest);
+
+! srcvar = build_fold_indirect_ref (src);
+ if (TREE_THIS_VOLATILE (srcvar))
+ return 0;
+! /* With memcpy, it is possible to bypass aliasing rules, so without
+! this check i. e. execute/20060930-2.c would be misoptimized, because
+! it use conflicting alias set to hold argument for the memcpy call.
+! This check is probably unnecesary with -fno-strict-aliasing.
+! Similarly for destvar. See also PR29286. */
+! if (!var_decl_component_p (srcvar)
+! /* Accept: memcpy (*char_var, "test", 1); that simplify
+! to char_var='t'; */
+! || is_gimple_min_invariant (srcvar)
+! || readonly_data_expr (src))
+ return 0;
+
+! destvar = build_fold_indirect_ref (dest);
+! if (TREE_THIS_VOLATILE (destvar))
+ return 0;
+! if (!var_decl_component_p (destvar))
+ return 0;
+
+! if (srctype == desttype
+! || (in_ssa_p
+! && tree_ssa_useless_type_conversion_1 (desttype, srctype)))
+! expr = srcvar;
+! else if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
+ || POINTER_TYPE_P (TREE_TYPE (srcvar)))
+ && (INTEGRAL_TYPE_P (TREE_TYPE (destvar))
+ || POINTER_TYPE_P (TREE_TYPE (destvar))))
+