{
if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
return NULL_RTX;
- else
- {
- struct expand_operand ops[4];
- rtx pat;
- tree len;
- tree src = CALL_EXPR_ARG (exp, 0);
- rtx src_reg;
- rtx_insn *before_strlen;
- machine_mode insn_mode;
- enum insn_code icode = CODE_FOR_nothing;
- unsigned int align;
- /* If the length can be computed at compile-time, return it. */
- len = c_strlen (src, 0);
- if (len)
- return expand_expr (len, target, target_mode, EXPAND_NORMAL);
-
- /* If the length can be computed at compile-time and is constant
- integer, but there are side-effects in src, evaluate
- src for side-effects, then return len.
- E.g. x = strlen (i++ ? "xfoo" + 1 : "bar");
- can be optimized into: i++; x = 3; */
- len = c_strlen (src, 1);
- if (len && TREE_CODE (len) == INTEGER_CST)
- {
- expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
- return expand_expr (len, target, target_mode, EXPAND_NORMAL);
- }
+ struct expand_operand ops[4];
+ rtx pat;
+ tree len;
+ tree src = CALL_EXPR_ARG (exp, 0);
+ rtx src_reg;
+ rtx_insn *before_strlen;
+ machine_mode insn_mode;
+ enum insn_code icode = CODE_FOR_nothing;
+ unsigned int align;
- align = get_pointer_alignment (src) / BITS_PER_UNIT;
+ /* If the length can be computed at compile-time, return it. */
+ len = c_strlen (src, 0);
+ if (len)
+ return expand_expr (len, target, target_mode, EXPAND_NORMAL);
- /* If SRC is not a pointer type, don't do this operation inline. */
- if (align == 0)
- return NULL_RTX;
+ /* If the length can be computed at compile-time and is constant
+ integer, but there are side-effects in src, evaluate
+ src for side-effects, then return len.
+ E.g. x = strlen (i++ ? "xfoo" + 1 : "bar");
+ can be optimized into: i++; x = 3; */
+ len = c_strlen (src, 1);
+ if (len && TREE_CODE (len) == INTEGER_CST)
+ {
+ expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ return expand_expr (len, target, target_mode, EXPAND_NORMAL);
+ }
- /* Bail out if we can't compute strlen in the right mode. */
- FOR_EACH_MODE_FROM (insn_mode, target_mode)
- {
- icode = optab_handler (strlen_optab, insn_mode);
- if (icode != CODE_FOR_nothing)
- break;
- }
- if (insn_mode == VOIDmode)
- return NULL_RTX;
+ align = get_pointer_alignment (src) / BITS_PER_UNIT;
+
+ /* If SRC is not a pointer type, don't do this operation inline. */
+ if (align == 0)
+ return NULL_RTX;
- /* Make a place to hold the source address. We will not expand
- the actual source until we are sure that the expansion will
- not fail -- there are trees that cannot be expanded twice. */
- src_reg = gen_reg_rtx (Pmode);
+ /* Bail out if we can't compute strlen in the right mode. */
+ FOR_EACH_MODE_FROM (insn_mode, target_mode)
+ {
+ icode = optab_handler (strlen_optab, insn_mode);
+ if (icode != CODE_FOR_nothing)
+ break;
+ }
+ if (insn_mode == VOIDmode)
+ return NULL_RTX;
- /* Mark the beginning of the strlen sequence so we can emit the
- source operand later. */
- before_strlen = get_last_insn ();
+ /* Make a place to hold the source address. We will not expand
+ the actual source until we are sure that the expansion will
+ not fail -- there are trees that cannot be expanded twice. */
+ src_reg = gen_reg_rtx (Pmode);
- create_output_operand (&ops[0], target, insn_mode);
- create_fixed_operand (&ops[1], gen_rtx_MEM (BLKmode, src_reg));
- create_integer_operand (&ops[2], 0);
- create_integer_operand (&ops[3], align);
- if (!maybe_expand_insn (icode, 4, ops))
- return NULL_RTX;
+ /* Mark the beginning of the strlen sequence so we can emit the
+ source operand later. */
+ before_strlen = get_last_insn ();
- /* Check to see if the argument was declared attribute nonstring
- and if so, issue a warning since at this point it's not known
- to be nul-terminated. */
- maybe_warn_nonstring_arg (TREE_OPERAND (CALL_EXPR_FN (exp), 0), exp);
+ create_output_operand (&ops[0], target, insn_mode);
+ create_fixed_operand (&ops[1], gen_rtx_MEM (BLKmode, src_reg));
+ create_integer_operand (&ops[2], 0);
+ create_integer_operand (&ops[3], align);
+ if (!maybe_expand_insn (icode, 4, ops))
+ return NULL_RTX;
- /* Now that we are assured of success, expand the source. */
- start_sequence ();
- pat = expand_expr (src, src_reg, Pmode, EXPAND_NORMAL);
- if (pat != src_reg)
- {
+ /* Check to see if the argument was declared attribute nonstring
+ and if so, issue a warning since at this point it's not known
+ to be nul-terminated. */
+ maybe_warn_nonstring_arg (get_callee_fndecl (exp), exp);
+
+ /* Now that we are assured of success, expand the source. */
+ start_sequence ();
+ pat = expand_expr (src, src_reg, Pmode, EXPAND_NORMAL);
+ if (pat != src_reg)
+ {
#ifdef POINTERS_EXTEND_UNSIGNED
- if (GET_MODE (pat) != Pmode)
- pat = convert_to_mode (Pmode, pat,
- POINTERS_EXTEND_UNSIGNED);
+ if (GET_MODE (pat) != Pmode)
+ pat = convert_to_mode (Pmode, pat,
+ POINTERS_EXTEND_UNSIGNED);
#endif
- emit_move_insn (src_reg, pat);
- }
- pat = get_insns ();
- end_sequence ();
+ emit_move_insn (src_reg, pat);
+ }
+ pat = get_insns ();
+ end_sequence ();
- if (before_strlen)
- emit_insn_after (pat, before_strlen);
- else
- emit_insn_before (pat, get_insns ());
+ if (before_strlen)
+ emit_insn_after (pat, before_strlen);
+ else
+ emit_insn_before (pat, get_insns ());
- /* Return the value in the proper mode for this function. */
- if (GET_MODE (ops[0].value) == target_mode)
- target = ops[0].value;
- else if (target != 0)
- convert_move (target, ops[0].value, 0);
- else
- target = convert_to_mode (target_mode, ops[0].value, 0);
+ /* Return the value in the proper mode for this function. */
+ if (GET_MODE (ops[0].value) == target_mode)
+ target = ops[0].value;
+ else if (target != 0)
+ convert_move (target, ops[0].value, 0);
+ else
+ target = convert_to_mode (target_mode, ops[0].value, 0);
- return target;
- }
+ return target;
}
/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
insn_code cmpstr_icode = direct_optab_handler (cmpstr_optab, SImode);
insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
- if (cmpstr_icode != CODE_FOR_nothing || cmpstrn_icode != CODE_FOR_nothing)
- {
- rtx arg1_rtx, arg2_rtx;
- tree fndecl, fn;
- tree arg1 = CALL_EXPR_ARG (exp, 0);
- tree arg2 = CALL_EXPR_ARG (exp, 1);
- rtx result = NULL_RTX;
+ if (cmpstr_icode == CODE_FOR_nothing && cmpstrn_icode == CODE_FOR_nothing)
+ return NULL_RTX;
- unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
- unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
+ tree arg1 = CALL_EXPR_ARG (exp, 0);
+ tree arg2 = CALL_EXPR_ARG (exp, 1);
- /* If we don't have POINTER_TYPE, call the function. */
- if (arg1_align == 0 || arg2_align == 0)
- return NULL_RTX;
+ unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
+ unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
- /* Stabilize the arguments in case gen_cmpstr(n)si fail. */
- arg1 = builtin_save_expr (arg1);
- arg2 = builtin_save_expr (arg2);
+ /* If we don't have POINTER_TYPE, call the function. */
+ if (arg1_align == 0 || arg2_align == 0)
+ return NULL_RTX;
- arg1_rtx = get_memory_rtx (arg1, NULL);
- arg2_rtx = get_memory_rtx (arg2, NULL);
+ /* Stabilize the arguments in case gen_cmpstr(n)si fail. */
+ arg1 = builtin_save_expr (arg1);
+ arg2 = builtin_save_expr (arg2);
- /* Try to call cmpstrsi. */
- if (cmpstr_icode != CODE_FOR_nothing)
- result = expand_cmpstr (cmpstr_icode, target, arg1_rtx, arg2_rtx,
- MIN (arg1_align, arg2_align));
+ rtx arg1_rtx = get_memory_rtx (arg1, NULL);
+ rtx arg2_rtx = get_memory_rtx (arg2, NULL);
- /* Try to determine at least one length and call cmpstrnsi. */
- if (!result && cmpstrn_icode != CODE_FOR_nothing)
- {
- tree len;
- rtx arg3_rtx;
-
- 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;
+ rtx result = NULL_RTX;
+ /* Try to call cmpstrsi. */
+ if (cmpstr_icode != CODE_FOR_nothing)
+ result = expand_cmpstr (cmpstr_icode, target, arg1_rtx, arg2_rtx,
+ MIN (arg1_align, arg2_align));
- /* If both arguments have side effects, we cannot optimize. */
- if (len && !TREE_SIDE_EFFECTS (len))
- {
- arg3_rtx = expand_normal (len);
- result = expand_cmpstrn_or_cmpmem
- (cmpstrn_icode, target, arg1_rtx, arg2_rtx, TREE_TYPE (len),
- arg3_rtx, MIN (arg1_align, arg2_align));
- }
- }
+ /* Try to determine at least one length and call cmpstrnsi. */
+ if (!result && cmpstrn_icode != CODE_FOR_nothing)
+ {
+ tree len;
+ rtx arg3_rtx;
+
+ 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 (result)
+ /* If both arguments have side effects, we cannot optimize. */
+ if (len && !TREE_SIDE_EFFECTS (len))
{
- /* Return the value in the proper mode for this function. */
- machine_mode 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;
+ arg3_rtx = expand_normal (len);
+ result = expand_cmpstrn_or_cmpmem
+ (cmpstrn_icode, target, arg1_rtx, arg2_rtx, TREE_TYPE (len),
+ arg3_rtx, MIN (arg1_align, arg2_align));
}
+ }
- /* Expand the library call ourselves using a stabilized argument
- list to avoid re-evaluating the function's arguments twice. */
- fndecl = get_callee_fndecl (exp);
- fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
- gcc_assert (TREE_CODE (fn) == CALL_EXPR);
- CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
- return expand_call (fn, target, target == const0_rtx);
+ /* Check to see if the argument was declared attribute nonstring
+ and if so, issue a warning since at this point it's not known
+ to be nul-terminated. */
+ tree fndecl = get_callee_fndecl (exp);
+ maybe_warn_nonstring_arg (fndecl, exp);
+
+ if (result)
+ {
+ /* Return the value in the proper mode for this function. */
+ machine_mode 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 NULL_RTX;
+
+ /* Expand the library call ourselves using a stabilized argument
+ list to avoid re-evaluating the function's arguments twice. */
+ tree fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
+ gcc_assert (TREE_CODE (fn) == CALL_EXPR);
+ CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
+ return expand_call (fn, target, target == const0_rtx);
}
/* Expand expression EXP, which is a call to the strncmp builtin. Return
expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
ATTRIBUTE_UNUSED machine_mode mode)
{
- location_t loc ATTRIBUTE_UNUSED = EXPR_LOCATION (exp);
-
if (!validate_arglist (exp,
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
return NULL_RTX;
lengths, and it doesn't have side effects, then emit cmpstrnsi
using length MIN(strlen(string)+1, arg3). */
insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
- if (cmpstrn_icode != CODE_FOR_nothing)
- {
- tree len, len1, len2, len3;
- rtx arg1_rtx, arg2_rtx, arg3_rtx;
- rtx result;
- tree fndecl, fn;
- tree arg1 = CALL_EXPR_ARG (exp, 0);
- tree arg2 = CALL_EXPR_ARG (exp, 1);
- tree arg3 = CALL_EXPR_ARG (exp, 2);
-
- unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
- unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
-
- len1 = c_strlen (arg1, 1);
- len2 = c_strlen (arg2, 1);
-
- if (len1)
- len1 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len1);
- if (len2)
- len2 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len2);
-
- len3 = fold_convert_loc (loc, sizetype, arg3);
-
- /* If we don't have a constant length for the first, use the length
- of the second, if we know it. If neither string is constant length,
- use the given length argument. 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 && !len2)
- len = len3;
- else 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 are not using the given length, we must incorporate it here.
- The actual new length parameter will be MIN(len,arg3) in this case. */
- if (len != len3)
- len = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (len), len, len3);
- arg1_rtx = get_memory_rtx (arg1, len);
- arg2_rtx = get_memory_rtx (arg2, len);
- arg3_rtx = expand_normal (len);
- result = expand_cmpstrn_or_cmpmem (cmpstrn_icode, target, arg1_rtx,
- arg2_rtx, TREE_TYPE (len), arg3_rtx,
- MIN (arg1_align, arg2_align));
- if (result)
- {
- /* 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;
- }
+ if (cmpstrn_icode == CODE_FOR_nothing)
+ return NULL_RTX;
- /* Expand the library call ourselves using a stabilized argument
- list to avoid re-evaluating the function's arguments twice. */
- fndecl = get_callee_fndecl (exp);
- fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 3,
- arg1, arg2, len);
- gcc_assert (TREE_CODE (fn) == CALL_EXPR);
- CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
- return expand_call (fn, target, target == const0_rtx);
- }
- return NULL_RTX;
+ tree len;
+
+ tree arg1 = CALL_EXPR_ARG (exp, 0);
+ tree arg2 = CALL_EXPR_ARG (exp, 1);
+ tree arg3 = CALL_EXPR_ARG (exp, 2);
+
+ unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
+ unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
+
+ tree len1 = c_strlen (arg1, 1);
+ tree len2 = c_strlen (arg2, 1);
+
+ location_t loc = EXPR_LOCATION (exp);
+
+ if (len1)
+ len1 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len1);
+ if (len2)
+ len2 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len2);
+
+ tree len3 = fold_convert_loc (loc, sizetype, arg3);
+
+ /* If we don't have a constant length for the first, use the length
+ of the second, if we know it. If neither string is constant length,
+ use the given length argument. 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 && !len2)
+ len = len3;
+ else 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 are not using the given length, we must incorporate it here.
+ The actual new length parameter will be MIN(len,arg3) in this case. */
+ if (len != len3)
+ len = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (len), len, len3);
+ rtx arg1_rtx = get_memory_rtx (arg1, len);
+ rtx arg2_rtx = get_memory_rtx (arg2, len);
+ rtx arg3_rtx = expand_normal (len);
+ rtx result = expand_cmpstrn_or_cmpmem (cmpstrn_icode, target, arg1_rtx,
+ arg2_rtx, TREE_TYPE (len), arg3_rtx,
+ MIN (arg1_align, arg2_align));
+
+ /* Check to see if the argument was declared attribute nonstring
+ and if so, issue a warning since at this point it's not known
+ to be nul-terminated. */
+ tree fndecl = get_callee_fndecl (exp);
+ maybe_warn_nonstring_arg (fndecl, exp);
+
+ if (result)
+ {
+ /* 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. */
+ tree fn = build_call_nofold_loc (loc, fndecl, 3, arg1, arg2, len);
+ gcc_assert (TREE_CODE (fn) == CALL_EXPR);
+ CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
+ return expand_call (fn, target, target == const0_rtx);
}
/* Expand a call to __builtin_saveregs, generating the result in TARGET,