diff options
author | uweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-07-12 09:20:21 +0000 |
---|---|---|
committer | uweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-07-12 09:20:21 +0000 |
commit | 6ac5504b880a3ab0799b38230a367d4ce46dc031 (patch) | |
tree | 958e94659cf1699b8af01c3da5cdf919e2da079f /gcc/builtins.c | |
parent | 88618d58bc2145a8cb7162936e3471d30a8f9a42 (diff) | |
download | ppe42-gcc-6ac5504b880a3ab0799b38230a367d4ce46dc031.tar.gz ppe42-gcc-6ac5504b880a3ab0799b38230a367d4ce46dc031.zip |
2005-07-12 Adrian Straetling <straetling@de.ibm.com>
* builtins.c: (expand_builtin_memcmp, expand_builtin_strncmp):
s/cmpstrsi/cmpstrnsi
(expand_builtin_strcmp): Rewrite to support both 'cmpstrsi' and
'cmpstrnsi'.
* optabs.c: (prepare_cmp_insn): Add availability of 'cmpstrn'.
(init_optabs): Initialize cmpstrn_optab.
* optabs.h: (enum insn_code cmpstrn_optab): Declare.
* genopinit.c: (optabs[]): Add 'cmpstrn' to initialisation.
* expr.c: (enum insn_code cmpstrn_optab): Declare.
* config/i386/i386.md: s/cmpstr/cmpstrn
* config/c4x/c4x.md: s/cmpstr/cmpstrn
* doc/md.texi: Update documentation.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@101916 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 235 |
1 files changed, 133 insertions, 102 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index f308f530c35..b032fc43784 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -3449,7 +3449,7 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, return expand_expr (result, target, mode, EXPAND_NORMAL); } -#if defined HAVE_cmpmemsi || defined HAVE_cmpstrsi +#if defined HAVE_cmpmemsi || defined HAVE_cmpstrnsi { tree arg1 = TREE_VALUE (arglist); tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); @@ -3469,9 +3469,9 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode; else #endif -#ifdef HAVE_cmpstrsi - if (HAVE_cmpstrsi) - insn_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; +#ifdef HAVE_cmpstrnsi + if (HAVE_cmpstrnsi) + insn_mode = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode; else #endif return 0; @@ -3504,10 +3504,10 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, GEN_INT (MIN (arg1_align, arg2_align))); else #endif -#ifdef HAVE_cmpstrsi - if (HAVE_cmpstrsi) - insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx, - GEN_INT (MIN (arg1_align, arg2_align))); +#ifdef HAVE_cmpstrnsi + if (HAVE_cmpstrnsi) + insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx, + GEN_INT (MIN (arg1_align, arg2_align))); else #endif gcc_unreachable (); @@ -3558,103 +3558,134 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode) return expand_expr (result, target, mode, EXPAND_NORMAL); } -#ifdef HAVE_cmpstrsi - if (HAVE_cmpstrsi) - { - tree arg1 = TREE_VALUE (arglist); - tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); - tree len, len1, len2; - rtx arg1_rtx, arg2_rtx, arg3_rtx; - rtx result, insn; - tree fndecl, fn; - - 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 defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi + if (cmpstr_optab[SImode] != CODE_FOR_nothing + || cmpstrn_optab[SImode] != CODE_FOR_nothing) + { + rtx arg1_rtx, arg2_rtx; + rtx result, insn = NULL_RTX; + tree fndecl, fn; + + tree arg1 = TREE_VALUE (arglist); + tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + int arg1_align + = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + int arg2_align + = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; + + /* If we don't have POINTER_TYPE, call the function. */ + if (arg1_align == 0 || arg2_align == 0) + return 0; - len1 = c_strlen (arg1, 1); - len2 = c_strlen (arg2, 1); + /* Stabilize the arguments in case gen_cmpstr(n)si fail. */ + arg1 = builtin_save_expr (arg1); + arg2 = builtin_save_expr (arg2); - if (len1) - len1 = size_binop (PLUS_EXPR, ssize_int (1), len1); - if (len2) - len2 = size_binop (PLUS_EXPR, ssize_int (1), len2); + arg1_rtx = get_memory_rtx (arg1); + arg2_rtx = get_memory_rtx (arg2); - /* 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; +#ifdef HAVE_cmpstrsi + /* Try to call cmpstrsi. */ + if (HAVE_cmpstrsi) + { + enum machine_mode insn_mode + = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; + + /* Make a place to write the result of the instruction. */ + result = target; + if (! (result != 0 + && REG_P (result) && GET_MODE (result) == insn_mode + && REGNO (result) >= FIRST_PSEUDO_REGISTER)) + result = gen_reg_rtx (insn_mode); + + insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, + GEN_INT (MIN (arg1_align, arg2_align))); + } +#endif +#if HAVE_cmpstrnsi + /* Try to determine at least one length and call cmpstrnsi. */ + if (!insn && HAVE_cmpstrnsi) + { + tree len; + rtx arg3_rtx; + + enum machine_mode insn_mode + = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode; + tree len1 = c_strlen (arg1, 1); + tree len2 = c_strlen (arg2, 1); + + 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 both arguments have side effects, we cannot optimize. */ - if (!len || TREE_SIDE_EFFECTS (len)) - return 0; + /* If both arguments have side effects, we cannot optimize. */ + if (!len || TREE_SIDE_EFFECTS (len)) + return 0; - /* If we don't have POINTER_TYPE, call the function. */ - if (arg1_align == 0 || arg2_align == 0) - return 0; + /* Stabilize the arguments in case gen_cmpstrnsi fails. */ + arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); - /* Make a place to write the result of the instruction. */ - result = target; - if (! (result != 0 - && REG_P (result) && GET_MODE (result) == insn_mode - && REGNO (result) >= FIRST_PSEUDO_REGISTER)) - result = gen_reg_rtx (insn_mode); + /* Make a place to write the result of the instruction. */ + result = target; + if (! (result != 0 + && REG_P (result) && GET_MODE (result) == insn_mode + && REGNO (result) >= FIRST_PSEUDO_REGISTER)) + result = gen_reg_rtx (insn_mode); - /* Stabilize the arguments in case gen_cmpstrsi fails. */ - arg1 = builtin_save_expr (arg1); - arg2 = builtin_save_expr (arg2); + insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx, + GEN_INT (MIN (arg1_align, arg2_align))); + } +#endif - 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) - { - emit_insn (insn); + if (insn) + { + 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; - } + /* 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; + } - /* Expand the library call ourselves using a stabilized argument - list to avoid re-evaluating the function's arguments twice. */ - arglist = build_tree_list (NULL_TREE, arg2); - arglist = tree_cons (NULL_TREE, arg1, arglist); - fndecl = get_callee_fndecl (exp); - fn = build_function_call_expr (fndecl, arglist); - if (TREE_CODE (fn) == CALL_EXPR) - CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); - return expand_call (fn, target, target == const0_rtx); - } + /* Expand the library call ourselves using a stabilized argument + list to avoid re-evaluating the function's arguments twice. */ + arglist = build_tree_list (NULL_TREE, arg2); + arglist = tree_cons (NULL_TREE, arg1, arglist); + fndecl = get_callee_fndecl (exp); + fn = build_function_call_expr (fndecl, arglist); + if (TREE_CODE (fn) == CALL_EXPR) + CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); + return expand_call (fn, target, target == const0_rtx); + } #endif return 0; } @@ -3679,10 +3710,10 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) } /* If c_strlen can determine an expression for one of the string - lengths, and it doesn't have side effects, then emit cmpstrsi + lengths, and it doesn't have side effects, then emit cmpstrnsi using length MIN(strlen(string)+1, arg3). */ -#ifdef HAVE_cmpstrsi - if (HAVE_cmpstrsi) +#ifdef HAVE_cmpstrnsi + if (HAVE_cmpstrnsi) { tree arg1 = TREE_VALUE (arglist); tree arg2 = TREE_VALUE (TREE_CHAIN (arglist)); @@ -3697,7 +3728,7 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) 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; + = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode; len1 = c_strlen (arg1, 1); len2 = c_strlen (arg2, 1); @@ -3750,7 +3781,7 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) && REGNO (result) >= FIRST_PSEUDO_REGISTER)) result = gen_reg_rtx (insn_mode); - /* Stabilize the arguments in case gen_cmpstrsi fails. */ + /* Stabilize the arguments in case gen_cmpstrnsi fails. */ arg1 = builtin_save_expr (arg1); arg2 = builtin_save_expr (arg2); len = builtin_save_expr (len); @@ -3758,8 +3789,8 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode 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))); + insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx, + GEN_INT (MIN (arg1_align, arg2_align))); if (insn) { emit_insn (insn); |