This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Optimize memset(x, ' ', 8)
- To: rth at redhat dot com, ghazi at caip dot rutgers dot edu
- Subject: [PATCH] Optimize memset(x, ' ', 8)
- From: Jakub Jelinek <jakub at redhat dot com>
- Date: Fri, 1 Dec 2000 11:09:09 +0100
- Cc: gcc-patches at gcc dot gnu dot org
- Reply-To: Jakub Jelinek <jakub at redhat dot com>
Hi!
This patch does 2 things: tries to optimize memset with non-zero argument
using store_by_pieces (as suggested by Kaveh) and also for functions which
take int argument where char is really meant (strchr, strrchr, memset) they
cast the constants to target char and check whether it fits into host char,
so that if the target has e.g. 32bit char the optimization does not break
something.
I'll bootstrap this together with other changes later today, ok to commit if
it succeeds without regressions?
2000-12-01 Jakub Jelinek <jakub@redhat.com>
* builtins.c (expand_builtin_strchr): Cast second argument to
target char and see if it fits into host char first.
(expand_builtin_strrchr): Likewise.
(builtin_memset_read_str): New function.
(expand_builtin_memset): Cast second argument to target char
and see if it fits into host char first. Try to optimize memset
with second argument non-zero using store_by_pieces.
* gcc.c-torture/execute/string-opt-5.c: Add some memset tests.
--- gcc/builtins.c.jj Wed Nov 29 19:15:29 2000
+++ gcc/builtins.c Fri Dec 1 10:39:30 2000
@@ -116,6 +116,8 @@ static rtx builtin_strncpy_read_str PARA
enum machine_mode));
static rtx expand_builtin_strncpy PARAMS ((tree, rtx,
enum machine_mode));
+static rtx builtin_memset_read_str PARAMS ((PTR, HOST_WIDE_INT,
+ enum machine_mode));
static rtx expand_builtin_memset PARAMS ((tree));
static rtx expand_builtin_bzero PARAMS ((tree));
static rtx expand_builtin_strlen PARAMS ((tree, rtx));
@@ -1583,7 +1585,20 @@ expand_builtin_strchr (arglist, target,
p1 = c_getstr (s1);
if (p1 != NULL)
{
- const char *r = strchr (p1, (char) TREE_INT_CST_LOW (s2));
+ rtx cst;
+ const char *r;
+
+ /* Cast s2 to target char, see if it fits into host char. */
+ cst = immed_double_const (TREE_INT_CST_LOW (s2),
+ TREE_INT_CST_HIGH (s2),
+ mode_for_size (CHAR_TYPE_SIZE,
+ MODE_INT, 0));
+ if (GET_CODE (cst) != CONST_INT
+ || (INTVAL (cst) != (char) INTVAL (cst)
+ && INTVAL (cst) != (unsigned char) INTVAL (cst)))
+ return 0;
+
+ r = strchr (p1, (char) INTVAL (cst));
if (r == NULL)
return const0_rtx;
@@ -1628,7 +1643,20 @@ expand_builtin_strrchr (arglist, target,
p1 = c_getstr (s1);
if (p1 != NULL)
{
- const char *r = strrchr (p1, (char) TREE_INT_CST_LOW (s2));
+ rtx cst;
+ const char *r;
+
+ /* Cast s2 to target char, see if it fits into host char. */
+ cst = immed_double_const (TREE_INT_CST_LOW (s2),
+ TREE_INT_CST_HIGH (s2),
+ mode_for_size (CHAR_TYPE_SIZE,
+ MODE_INT, 0));
+ if (GET_CODE (cst) != CONST_INT
+ || (INTVAL (cst) != (char) INTVAL (cst)
+ && INTVAL (cst) != (unsigned char) INTVAL (cst)))
+ return 0;
+
+ r = strrchr (p1, (char) INTVAL (cst));
if (r == NULL)
return const0_rtx;
@@ -1945,6 +1973,24 @@ expand_builtin_strncpy (arglist, target,
}
}
+/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
+ bytes from constant string DATA + OFFSET and return it as target
+ constant. */
+
+static rtx
+builtin_memset_read_str (data, offset, mode)
+ PTR data;
+ HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
+ enum machine_mode mode;
+{
+ const char *c = (const char *) data;
+ char *p = alloca (GET_MODE_SIZE (mode));
+
+ memset (p, *c, GET_MODE_SIZE (mode));
+
+ return c_readstr (p, mode);
+}
+
/* Expand expression EXP, which is a call to the memset builtin. Return 0
if we failed the caller should emit a normal call. */
@@ -1971,6 +2017,7 @@ expand_builtin_memset (exp)
tree dest = TREE_VALUE (arglist);
tree val = TREE_VALUE (TREE_CHAIN (arglist));
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ rtx cst;
int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
rtx dest_mem, dest_addr, len_rtx;
@@ -1980,18 +2027,36 @@ expand_builtin_memset (exp)
if (dest_align == 0)
return 0;
- /* If the arguments have side-effects, then we can only evaluate
- them at most once. The following code evaluates them twice if
- they are not constants because we break out to expand_call
- in that case. They can't be constants if they have side-effects
- so we can check for that first. Alternatively, we could call
- save_expr to make multiple evaluation safe. */
- if (TREE_SIDE_EFFECTS (val) || TREE_SIDE_EFFECTS (len))
+ if (TREE_CODE (val) != INTEGER_CST)
return 0;
-
- /* If VAL is not 0, don't do this operation in-line. */
- if (expand_expr (val, NULL_RTX, VOIDmode, 0) != const0_rtx)
+
+ /* Cast val to target char, see if it fits into host char. */
+ cst = immed_double_const (TREE_INT_CST_LOW (val),
+ TREE_INT_CST_HIGH (val),
+ mode_for_size (CHAR_TYPE_SIZE, MODE_INT, 0));
+ if (GET_CODE (cst) != CONST_INT
+ || (INTVAL (cst) != (char) INTVAL (cst)
+ && INTVAL (cst) != (unsigned char) INTVAL (cst)))
return 0;
+
+ if (INTVAL (cst))
+ {
+ char c = INTVAL (cst);
+
+ if (TREE_CODE (len) != INTEGER_CST || TREE_INT_CST_HIGH (len))
+ return 0;
+ if (current_function_check_memory_usage
+ || !can_store_by_pieces (TREE_INT_CST_LOW (len),
+ builtin_memset_read_str,
+ (PTR) &c, dest_align))
+ return 0;
+
+ dest_mem = get_memory_rtx (dest);
+ store_by_pieces (dest_mem, TREE_INT_CST_LOW (len),
+ builtin_memset_read_str,
+ (PTR) &c, dest_align);
+ return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+ }
len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
--- gcc/testsuite/gcc.c-torture/execute/string-opt-5.c.jj Wed Nov 29 01:05:24 2000
+++ gcc/testsuite/gcc.c-torture/execute/string-opt-5.c Fri Dec 1 11:02:15 2000
@@ -17,6 +17,7 @@ extern int memcmp (const void *, const v
int x = 6;
int y = 1;
char *bar = "hi world";
+char buf [64];
int main()
{
@@ -79,7 +80,28 @@ int main()
abort ();
memset (dst, ' ', sizeof dst);
if (strncpy (dst, "hello", 8) != dst || memcmp (dst, "hello\0\0\0 ", 9))
- abort();
+ abort ();
+ x = '!';
+ memset (buf, ' ', sizeof buf);
+ if (memset (buf, x++, ++y) != buf
+ || x != '!' + 1
+ || y != 3
+ || memcmp (buf, "!!!", 3))
+ abort ();
+ if (memset (buf + y++, '-', 8) != buf + 3
+ || y != 4
+ || memcmp (buf, "!!!--------", 11))
+ abort ();
+ x = 10;
+ if (memset (buf + ++x, 0, y++) != buf + 11
+ || x != 11
+ || y != 5
+ || memcmp (buf + 8, "---\0\0\0", 7))
+ abort ();
+ if (memset (buf + (x += 4), 0, 6) != buf + 15
+ || x != 15
+ || memcmp (buf + 10, "-\0\0\0\0\0\0\0\0\0", 11))
+ abort ();
return 0;
}
Jakub