aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorRichard Henderson <rth@cygnus.com>2000-03-08 11:21:13 -0800
committerRichard Henderson <rth@gcc.gnu.org>2000-03-08 11:21:13 -0800
commitdd05e4fae90b9f885f20217bd5b18ed13030314c (patch)
treeb064edc6151023284dca585689e2a55c65ba133e /gcc/builtins.c
parentc5aa680d463b578fa3bc62a6b3f7952f4bcaad2a (diff)
downloadgcc-dd05e4fae90b9f885f20217bd5b18ed13030314c.zip
gcc-dd05e4fae90b9f885f20217bd5b18ed13030314c.tar.gz
gcc-dd05e4fae90b9f885f20217bd5b18ed13030314c.tar.bz2
builtins.c (expand_builtin_strlen): Be prepared for strlensi to fail.
* builtins.c (expand_builtin_strlen): Be prepared for strlensi to fail. Don't pre-expand the source operand. From-SVN: r32429
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c52
1 files changed, 30 insertions, 22 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index a38f3c4..c75d2fb4 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -1334,13 +1334,14 @@ expand_builtin_strlen (exp, target, mode)
return 0;
else
{
+ rtx pat;
tree src = TREE_VALUE (arglist);
tree len = c_strlen (src);
int align
= get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
- rtx result, src_rtx, char_rtx;
+ rtx result, src_reg, char_rtx, before_strlen;
enum machine_mode insn_mode = value_mode, char_mode;
enum insn_code icode = CODE_FOR_nothing;
@@ -1352,8 +1353,7 @@ expand_builtin_strlen (exp, target, mode)
if (align == 0)
return 0;
- /* Call a function if we can't compute strlen in the right mode. */
-
+ /* Bail out if we can't compute strlen in the right mode. */
while (insn_mode != VOIDmode)
{
icode = strlen_optab->handlers[(int) insn_mode].insn_code;
@@ -1373,21 +1373,19 @@ expand_builtin_strlen (exp, target, mode)
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
- /* Make sure the operands are acceptable to the predicates. */
-
- if (! (*insn_data[(int)icode].operand[0].predicate) (result, insn_mode))
- result = gen_reg_rtx (insn_mode);
- src_rtx = memory_address (BLKmode,
- expand_expr (src, NULL_RTX, ptr_mode,
- EXPAND_NORMAL));
+ /* 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);
- if (! (*insn_data[(int)icode].operand[1].predicate) (src_rtx, Pmode))
- src_rtx = copy_to_mode_reg (Pmode, src_rtx);
+ /* Mark the beginning of the strlen sequence so we can emit the
+ source operand later. */
+ before_strlen = get_last_insn();
/* Check the string is readable and has an end. */
if (current_function_check_memory_usage)
emit_library_call (chkr_check_str_libfunc, 1, VOIDmode, 2,
- src_rtx, Pmode,
+ src_reg, Pmode,
GEN_INT (MEMORY_USE_RO),
TYPE_MODE (integer_type_node));
@@ -1396,20 +1394,30 @@ expand_builtin_strlen (exp, target, mode)
if (! (*insn_data[(int)icode].operand[2].predicate) (char_rtx, char_mode))
char_rtx = copy_to_mode_reg (char_mode, char_rtx);
- emit_insn (GEN_FCN (icode) (result,
- gen_rtx_MEM (BLKmode, src_rtx),
- char_rtx, GEN_INT (align)));
+ pat = GEN_FCN (icode) (result, gen_rtx_MEM (BLKmode, src_reg),
+ char_rtx, GEN_INT (align));
+ if (! pat)
+ return 0;
+ emit_insn (pat);
+
+ /* Now that we are assured of success, expand the source. */
+ start_sequence ();
+ pat = expand_expr (src, src_reg, ptr_mode, EXPAND_SUM);
+ if (pat != src_reg)
+ emit_move_insn (src_reg, pat);
+ pat = gen_sequence ();
+ end_sequence ();
+ emit_insn_after (pat, before_strlen);
/* Return the value in the proper mode for this function. */
if (GET_MODE (result) == value_mode)
- return result;
+ target = result;
else if (target != 0)
- {
- convert_move (target, result, 0);
- return target;
- }
+ convert_move (target, result, 0);
else
- return convert_to_mode (value_mode, result, 0);
+ target = convert_to_mode (value_mode, result, 0);
+
+ return target;
}
}