From ab937357527b7198b6345d935af5e51888567032 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 1 Dec 2000 18:53:07 +0100 Subject: [PATCH] builtins.c (target_char_cast): New function. * builtins.c (target_char_cast): New function. (expand_builtin_strchr): Use it. (expand_builtin_strrchr): Use it. (builtin_memset_read_str): New function. (expand_builtin_memset): Use target_char_cast. 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. From-SVN: r37918 --- gcc/ChangeLog | 10 ++ gcc/builtins.c | 97 ++++++++++++++++--- gcc/testsuite/ChangeLog | 4 + .../gcc.c-torture/execute/string-opt-5.c | 24 ++++- 4 files changed, 123 insertions(+), 12 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 86643d0cff4..024d701da75 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2000-12-01 Jakub Jelinek + + * builtins.c (target_char_cast): New function. + (expand_builtin_strchr): Use it. + (expand_builtin_strrchr): Use it. + (builtin_memset_read_str): New function. + (expand_builtin_memset): Use target_char_cast. + Try to optimize memset with second argument non-zero using + store_by_pieces. + 2000-11-30 Marek Michalkiewicz * install.texi (avr): Replace incomplete list of supported MCU diff --git a/gcc/builtins.c b/gcc/builtins.c index 07d10adf446..0e59904325e 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -83,6 +83,7 @@ static tree c_strlen PARAMS ((tree)); static const char *c_getstr PARAMS ((tree)); static rtx c_readstr PARAMS ((const char *, enum machine_mode)); +static int target_char_cast PARAMS ((tree, char *)); static rtx get_memory_rtx PARAMS ((tree)); static int apply_args_size PARAMS ((void)); static int apply_result_size PARAMS ((void)); @@ -116,6 +117,8 @@ static rtx builtin_strncpy_read_str PARAMS ((PTR, HOST_WIDE_INT, 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)); @@ -317,6 +320,7 @@ c_getstr (src) /* Return a CONST_INT or CONST_DOUBLE corresponding to target reading GET_MODE_BITSIZE (MODE) bits from string constant STR. */ + static rtx c_readstr (str, mode) const char *str; @@ -349,6 +353,36 @@ c_readstr (str, mode) return immed_double_const (c[0], c[1], mode); } +/* Cast a target constant CST to target CHAR and if that value fits into + host char type, return zero and put that value into variable pointed by + P. */ + +static int +target_char_cast (cst, p) + tree cst; + char *p; +{ + unsigned HOST_WIDE_INT val, hostval; + + if (TREE_CODE (cst) != INTEGER_CST + || CHAR_TYPE_SIZE > HOST_BITS_PER_WIDE_INT) + return 1; + + val = TREE_INT_CST_LOW (cst); + if (CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT) + val &= (((unsigned HOST_WIDE_INT) 1) << CHAR_TYPE_SIZE) - 1; + + hostval = val; + if (HOST_BITS_PER_CHAR < HOST_BITS_PER_WIDE_INT) + hostval &= (((unsigned HOST_WIDE_INT) 1) << HOST_BITS_PER_CHAR) - 1; + + if (val != hostval) + return 1; + + *p = hostval; + return 0; +} + /* Given TEM, a pointer to a stack frame, follow the dynamic chain COUNT times to get the address of either a higher stack frame, or a return address located within it (depending on FNDECL_CODE). */ @@ -1583,7 +1617,13 @@ expand_builtin_strchr (arglist, target, mode) p1 = c_getstr (s1); if (p1 != NULL) { - const char *r = strchr (p1, (char) TREE_INT_CST_LOW (s2)); + char c; + const char *r; + + if (target_char_cast (s2, &c)) + return 0; + + r = strchr (p1, c); if (r == NULL) return const0_rtx; @@ -1628,7 +1668,13 @@ expand_builtin_strrchr (arglist, target, mode) p1 = c_getstr (s1); if (p1 != NULL) { - const char *r = strrchr (p1, (char) TREE_INT_CST_LOW (s2)); + char c; + const char *r; + + if (target_char_cast (s2, &c)) + return 0; + + r = strrchr (p1, c); if (r == NULL) return const0_rtx; @@ -1945,6 +1991,24 @@ expand_builtin_strncpy (arglist, target, mode) } } +/* 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 +2035,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))); + char c; int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); rtx dest_mem, dest_addr, len_rtx; @@ -1980,19 +2045,29 @@ 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) + if (target_char_cast (val, &c)) return 0; + if (c) + { + 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); dest_mem = get_memory_rtx (dest); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index aae082d791f..4b7d5fba496 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2000-12-01 Jakub Jelinek + + * gcc.c-torture/execute/string-opt-5.c: Add some memset tests. + 2000-12-01 Nathan Sidwell * g++.old-deja/g++.other/cast6.C: New test. diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-5.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-5.c index 108c3ed4773..178812226dc 100644 --- a/gcc/testsuite/gcc.c-torture/execute/string-opt-5.c +++ b/gcc/testsuite/gcc.c-torture/execute/string-opt-5.c @@ -17,6 +17,7 @@ extern int memcmp (const void *, const void *, __SIZE_TYPE__); 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; } -- 2.30.2