diff options
Diffstat (limited to 'contrib/gcc/builtins.c')
-rw-r--r-- | contrib/gcc/builtins.c | 241 |
1 files changed, 73 insertions, 168 deletions
diff --git a/contrib/gcc/builtins.c b/contrib/gcc/builtins.c index d088274..4c5650a 100644 --- a/contrib/gcc/builtins.c +++ b/contrib/gcc/builtins.c @@ -1344,12 +1344,7 @@ expand_builtin_apply (function, arguments, argsize) OK_DEFER_POP; /* Return the address of the result block. */ - result = copy_addr_to_reg (XEXP (result, 0)); -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (result) != ptr_mode) - result = convert_memory_address (ptr_mode, result); -#endif - return result; + return copy_addr_to_reg (XEXP (result, 0)); } /* Perform an untyped return. */ @@ -2353,7 +2348,7 @@ expand_builtin_bzero (exp) return result; } -/* Expand expression EXP, which is a call to the memcmp built-in function. +/* Expand expression EXP, which is a call to the memcmp or the strcmp builtin. 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). */ @@ -2490,7 +2485,7 @@ expand_builtin_strcmp (exp, target, mode) enum machine_mode mode; { tree arglist = TREE_OPERAND (exp, 1); - tree arg1, arg2; + tree arg1, arg2, len, len2, fn; const char *p1, *p2; if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) @@ -2526,89 +2521,51 @@ expand_builtin_strcmp (exp, target, mode) return expand_expr (result, target, mode, EXPAND_NORMAL); } -#ifdef HAVE_cmpstrsi - if (HAVE_cmpstrsi) - { - tree len, len1, len2; - rtx arg1_rtx, arg2_rtx, arg3_rtx; - rtx result, insn; - - 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; - - 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; + len = c_strlen (arg1); + len2 = c_strlen (arg2); - /* If both arguments have side effects, we cannot optimize. */ - if (!len || TREE_SIDE_EFFECTS (len)) - return 0; + if (len) + len = size_binop (PLUS_EXPR, ssize_int (1), len); - /* If we don't have POINTER_TYPE, call the function. */ - if (arg1_align == 0 || arg2_align == 0) - return 0; + if (len2) + len2 = size_binop (PLUS_EXPR, ssize_int (1), 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 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. - 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) + 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 (!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; - emit_insn (insn); + /* If both arguments have side effects, we cannot optimize. */ + if (TREE_SIDE_EFFECTS (len)) + return 0; - /* 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; + fn = built_in_decls[BUILT_IN_MEMCMP]; + if (!fn) + return 0; + + arglist = build_tree_list (NULL_TREE, len); + arglist = tree_cons (NULL_TREE, arg2, arglist); + arglist = tree_cons (NULL_TREE, arg1, arglist); + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); } /* Expand expression EXP, which is a call to the strncmp builtin. Return 0 @@ -2622,6 +2579,7 @@ 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; @@ -2675,94 +2633,41 @@ 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 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; - - 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; - - 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 both arguments have side effects, we cannot optimize. */ - if (!len || TREE_SIDE_EFFECTS (len)) - return 0; - - /* 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; + 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; - /* 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); + fn = built_in_decls[BUILT_IN_MEMCMP]; + if (!fn) + 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; + /* Add one to the string length. */ + len = fold (size_binop (PLUS_EXPR, len, ssize_int (1))); - emit_insn (insn); + /* The actual new length parameter is MIN(len,arg3). */ + len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3)); - /* 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; + 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); } /* Expand expression EXP, which is a call to the strcat builtin. |