diff options
author | Roger Sayle <roger@eyesopen.com> | 2003-04-23 13:09:36 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2003-04-23 13:09:36 +0000 |
commit | 2be3b5ce222dcf49dcca9e9bf3f1f7eb77b64566 (patch) | |
tree | 230395e871566201655181b395a35db7db6d6141 /gcc | |
parent | d8c3061141850f24406d79172265410ce93fe2e3 (diff) | |
download | gcc-2be3b5ce222dcf49dcca9e9bf3f1f7eb77b64566.zip gcc-2be3b5ce222dcf49dcca9e9bf3f1f7eb77b64566.tar.gz gcc-2be3b5ce222dcf49dcca9e9bf3f1f7eb77b64566.tar.bz2 |
re PR rtl-optimization/10339 ([sparc,ppc,ppc64] Invalid optimization: replacing strncmp by memcmp)
PR optimization/10339
* builtins.c (expand_builtin_strcmp): Try to emit cmpstrsi insn
directly instead of unsafely transforming call into a memcmp.
(expand_builtin_strncmp): Likewise.
From-SVN: r65985
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/builtins.c | 228 |
2 files changed, 166 insertions, 69 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c552233..ce22865 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2003-04-23 Roger Sayle <roger@eyesopen.com> + + PR optimization/10339 + * builtins.c (expand_builtin_strcmp): Try to emit cmpstrsi insn + directly instead of unsafely transforming call into a memcmp. + (expand_builtin_strncmp): Likewise. + 2003-04-22 Roger Sayle <roger@eyesopen.com> * alias.c (mark_constant_function): Check for constancy and diff --git a/gcc/builtins.c b/gcc/builtins.c index 87437d0..b24ecd3 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -2715,7 +2715,7 @@ expand_builtin_bzero (exp) return result; } -/* Expand expression EXP, which is a call to the memcmp or the strcmp builtin. +/* Expand expression EXP, which is a call to the memcmp built-in function. ARGLIST is the argument list for this call. Return 0 if we failed and the caller should emit a normal call, otherwise try to get the result in TARGET, if convenient (and in mode MODE, if that's convenient). */ @@ -2852,7 +2852,7 @@ expand_builtin_strcmp (exp, target, mode) enum machine_mode mode; { tree arglist = TREE_OPERAND (exp, 1); - tree arg1, arg2, len, len2, fn; + tree arg1, arg2; const char *p1, *p2; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) @@ -2888,49 +2888,88 @@ expand_builtin_strcmp (exp, target, mode) return expand_expr (result, target, mode, EXPAND_NORMAL); } - len = c_strlen (arg1); - len2 = c_strlen (arg2); +#ifdef HAVE_cmpstrsi + if (HAVE_cmpstrsi) + { + tree len, len1, len2; + rtx arg1_rtx, arg2_rtx, arg3_rtx; + rtx result, insn; - if (len) - len = size_binop (PLUS_EXPR, ssize_int (1), len); + int arg1_align + = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + int arg2_align + = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + enum machine_mode insn_mode + = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; - if (len2) - len2 = size_binop (PLUS_EXPR, ssize_int (1), len2); + len1 = c_strlen (arg1); + len2 = c_strlen (arg2); + + if (len1) + len1 = size_binop (PLUS_EXPR, ssize_int (1), len1); + if (len2) + len2 = size_binop (PLUS_EXPR, ssize_int (1), len2); + + /* If we don't have a constant length for the first, use the length + of the second, if we know it. We don't require a constant for + this case; some cost analysis could be done if both are available + but neither is constant. For now, assume they're equally cheap, + unless one has side effects. If both strings have constant lengths, + use the smaller. */ + + if (!len1) + len = len2; + else if (!len2) + len = len1; + else if (TREE_SIDE_EFFECTS (len1)) + len = len2; + else if (TREE_SIDE_EFFECTS (len2)) + len = len1; + else if (TREE_CODE (len1) != INTEGER_CST) + len = len2; + else if (TREE_CODE (len2) != INTEGER_CST) + len = len1; + else if (tree_int_cst_lt (len1, len2)) + len = len1; + else + len = len2; - /* If we don't have a constant length for the first, use the length - of the second, if we know it. We don't require a constant for - this case; some cost analysis could be done if both are available - but neither is constant. For now, assume they're equally cheap - unless one has side effects. + /* If both arguments have side effects, we cannot optimize. */ + if (!len || TREE_SIDE_EFFECTS (len)) + return 0; - If both strings have constant lengths, use the smaller. This - could arise if optimization results in strcpy being called with - two fixed strings, or if the code was machine-generated. We should - add some code to the `memcmp' handler below to deal with such - situations, someday. */ + /* If we don't have POINTER_TYPE, call the function. */ + if (arg1_align == 0 || arg2_align == 0) + return 0; - if (!len || TREE_CODE (len) != INTEGER_CST) - { - if (len2 && !TREE_SIDE_EFFECTS (len2)) - len = len2; - else if (len == 0) - return 0; - } - else if (len2 && TREE_CODE (len2) == INTEGER_CST - && tree_int_cst_lt (len2, len)) - len = len2; + /* Make a place to write the result of the instruction. */ + result = target; + if (! (result != 0 + && GET_CODE (result) == REG && GET_MODE (result) == insn_mode + && REGNO (result) >= FIRST_PSEUDO_REGISTER)) + result = gen_reg_rtx (insn_mode); - /* If both arguments have side effects, we cannot optimize. */ - if (TREE_SIDE_EFFECTS (len)) - return 0; + arg1_rtx = get_memory_rtx (arg1); + arg2_rtx = get_memory_rtx (arg2); + arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); + insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx, + GEN_INT (MIN (arg1_align, arg2_align))); + if (!insn) + return 0; - fn = implicit_built_in_decls[BUILT_IN_MEMCMP]; - if (!fn) - return 0; + emit_insn (insn); - chainon (arglist, build_tree_list (NULL_TREE, len)); - return expand_expr (build_function_call_expr (fn, arglist), - target, mode, EXPAND_NORMAL); + /* Return the value in the proper mode for this function. */ + mode = TYPE_MODE (TREE_TYPE (exp)); + if (GET_MODE (result) == mode) + return result; + if (target == 0) + return convert_to_mode (mode, result, 0); + convert_move (target, result, 0); + return target; + } +#endif + return 0; } /* Expand expression EXP, which is a call to the strncmp builtin. Return 0 @@ -2944,7 +2983,6 @@ expand_builtin_strncmp (exp, target, mode) enum machine_mode mode; { tree arglist = TREE_OPERAND (exp, 1); - tree fn, newarglist, len = 0; tree arg1, arg2, arg3; const char *p1, *p2; @@ -2998,41 +3036,93 @@ expand_builtin_strncmp (exp, target, mode) } /* If c_strlen can determine an expression for one of the string - lengths, and it doesn't have side effects, then call - expand_builtin_memcmp() using length MIN(strlen(string)+1, arg3). */ - - /* Perhaps one of the strings is really constant, if so prefer - that constant length over the other string's length. */ - if (p1) - len = c_strlen (arg1); - else if (p2) - len = c_strlen (arg2); - - /* If we still don't have a len, try either string arg as long - as they don't have side effects. */ - if (!len && !TREE_SIDE_EFFECTS (arg1)) - len = c_strlen (arg1); - if (!len && !TREE_SIDE_EFFECTS (arg2)) - len = c_strlen (arg2); - /* If we still don't have a length, punt. */ - if (!len) - return 0; + lengths, and it doesn't have side effects, then emit cmpstrsi + using length MIN(strlen(string)+1, arg3). */ +#ifdef HAVE_cmpstrsi + if (HAVE_cmpstrsi) + { + tree len, len1, len2; + rtx arg1_rtx, arg2_rtx, arg3_rtx; + rtx result, insn; - fn = implicit_built_in_decls[BUILT_IN_MEMCMP]; - if (!fn) - return 0; + int arg1_align + = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + int arg2_align + = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + enum machine_mode insn_mode + = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; - /* Add one to the string length. */ - len = fold (size_binop (PLUS_EXPR, len, ssize_int (1))); + len1 = c_strlen (arg1); + len2 = c_strlen (arg2); + + if (len1) + len1 = size_binop (PLUS_EXPR, ssize_int (1), len1); + if (len2) + len2 = size_binop (PLUS_EXPR, ssize_int (1), len2); + + /* If we don't have a constant length for the first, use the length + of the second, if we know it. We don't require a constant for + this case; some cost analysis could be done if both are available + but neither is constant. For now, assume they're equally cheap, + unless one has side effects. If both strings have constant lengths, + use the smaller. */ + + if (!len1) + len = len2; + else if (!len2) + len = len1; + else if (TREE_SIDE_EFFECTS (len1)) + len = len2; + else if (TREE_SIDE_EFFECTS (len2)) + len = len1; + else if (TREE_CODE (len1) != INTEGER_CST) + len = len2; + else if (TREE_CODE (len2) != INTEGER_CST) + len = len1; + else if (tree_int_cst_lt (len1, len2)) + len = len1; + else + len = len2; - /* The actual new length parameter is MIN(len,arg3). */ - len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3)); + /* If both arguments have side effects, we cannot optimize. */ + if (!len || TREE_SIDE_EFFECTS (len)) + return 0; - newarglist = build_tree_list (NULL_TREE, len); - newarglist = tree_cons (NULL_TREE, arg2, newarglist); - newarglist = tree_cons (NULL_TREE, arg1, newarglist); - return expand_expr (build_function_call_expr (fn, newarglist), - target, mode, EXPAND_NORMAL); + /* The actual new length parameter is MIN(len,arg3). */ + len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3)); + + /* If we don't have POINTER_TYPE, call the function. */ + if (arg1_align == 0 || arg2_align == 0) + return 0; + + /* Make a place to write the result of the instruction. */ + result = target; + if (! (result != 0 + && GET_CODE (result) == REG && GET_MODE (result) == insn_mode + && REGNO (result) >= FIRST_PSEUDO_REGISTER)) + result = gen_reg_rtx (insn_mode); + + arg1_rtx = get_memory_rtx (arg1); + arg2_rtx = get_memory_rtx (arg2); + arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); + insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx, + GEN_INT (MIN (arg1_align, arg2_align))); + if (!insn) + return 0; + + emit_insn (insn); + + /* Return the value in the proper mode for this function. */ + mode = TYPE_MODE (TREE_TYPE (exp)); + if (GET_MODE (result) == mode) + return result; + if (target == 0) + return convert_to_mode (mode, result, 0); + convert_move (target, result, 0); + return target; + } +#endif + return 0; } /* Expand expression EXP, which is a call to the strcat builtin. |