From 8fd3cf4e17c97036b4f9cecbe2f438a2da920351 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 3 Jun 2003 10:57:55 +0200 Subject: [PATCH] builtins.c (expand_builtin_memcpy): Remove endp argument and endp != 0 handling. * builtins.c (expand_builtin_memcpy): Remove endp argument and endp != 0 handling. Pass 0 to store_by_pieces. (expand_builtin_mempcpy): Add endp argument. Don't call expand_builtin_memcpy, call store_by_pieces resp. move_by_pieces directly. If ignoring result, only do expand_call. (expand_builtin_stpcpy): Likewise. Call expand_builtin_mempcpy otherwise. (expand_builtin_strncpy, expand_builtin_memset): Adjust store_by_pices callers. (expand_builtin): Adjust expand_builtin_memcpy and expand_builtin_mempcpy callers. * expr.c (can_move_by_pieces): New function. (move_by_pieces): Add endp argument, return to resp. memory at end or one byte earlier depending on endp. (store_by_pieces): Likewise. (emit_block_move): Adjust call to move_by_pieces. (emit_push_insn): Adjust move_by_pieces caller. * expr.h (can_move_by_pieces): New prototype. (store_by_pieces): Adjust prototypes. * rtl.h (move_by_pieces): Adjust prototype. * config/mips/mips.c (expand_block_move): Adjust move_by_pieces caller. * gcc.c-torture/execute/builtins/string-4.c (main_test): Remove mempcpy test with post-increments. * gcc.c-torture/execute/string-opt-3.c: New test. * gcc.dg/string-opt-1.c: New test. From-SVN: r67358 --- gcc/ChangeLog | 25 +++ gcc/builtins.c | 177 ++++++++++-------- gcc/config/mips/mips.c | 2 +- gcc/expr.c | 98 +++++++++- gcc/expr.h | 16 +- gcc/rtl.h | 4 +- gcc/testsuite/ChangeLog | 7 + .../gcc.c-torture/execute/builtins/string-4.c | 4 +- .../gcc.c-torture/execute/string-opt-3.c | 166 ++++++++++++++++ gcc/testsuite/gcc.dg/string-opt-1.c | 11 ++ 10 files changed, 415 insertions(+), 95 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/string-opt-3.c create mode 100644 gcc/testsuite/gcc.dg/string-opt-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b1bf7f437e4..b628ed0649f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +2003-06-03 Jakub Jelinek + + * builtins.c (expand_builtin_memcpy): Remove endp argument and endp + != 0 handling. Pass 0 to store_by_pieces. + (expand_builtin_mempcpy): Add endp argument. Don't call + expand_builtin_memcpy, call store_by_pieces resp. move_by_pieces + directly. If ignoring result, only do expand_call. + (expand_builtin_stpcpy): Likewise. Call expand_builtin_mempcpy + otherwise. + (expand_builtin_strncpy, expand_builtin_memset): Adjust + store_by_pices callers. + (expand_builtin): Adjust expand_builtin_memcpy and + expand_builtin_mempcpy callers. + * expr.c (can_move_by_pieces): New function. + (move_by_pieces): Add endp argument, return to resp. memory at end + or one byte earlier depending on endp. + (store_by_pieces): Likewise. + (emit_block_move): Adjust call to move_by_pieces. + (emit_push_insn): Adjust move_by_pieces caller. + * expr.h (can_move_by_pieces): New prototype. + (store_by_pieces): Adjust prototypes. + * rtl.h (move_by_pieces): Adjust prototype. + * config/mips/mips.c (expand_block_move): Adjust move_by_pieces + caller. + 2003-06-03 Ben Elliston * doc/md.texi (Processor pipeline description): Improve wording. diff --git a/gcc/builtins.c b/gcc/builtins.c index eef1cce496c..557e397945c 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -125,9 +125,9 @@ static rtx expand_builtin_strspn PARAMS ((tree, rtx, static rtx expand_builtin_strcspn PARAMS ((tree, rtx, enum machine_mode)); static rtx expand_builtin_memcpy PARAMS ((tree, rtx, - enum machine_mode, int)); -static rtx expand_builtin_mempcpy PARAMS ((tree, rtx, enum machine_mode)); +static rtx expand_builtin_mempcpy PARAMS ((tree, rtx, + enum machine_mode, int)); static rtx expand_builtin_memmove PARAMS ((tree, rtx, enum machine_mode)); static rtx expand_builtin_bcopy PARAMS ((tree)); @@ -2274,16 +2274,12 @@ builtin_memcpy_read_str (data, offset, mode) /* Expand a call to the memcpy builtin, with arguments in ARGLIST. Return 0 if we failed, 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). If ENDP is 0 return the - destination pointer, if ENDP is 1 return the end pointer ala - mempcpy, and if ENDP is 2 return the end pointer minus one ala - stpcpy. */ + mode MODE if that's convenient). */ static rtx -expand_builtin_memcpy (arglist, target, mode, endp) +expand_builtin_memcpy (arglist, target, mode) tree arglist; rtx target; enum machine_mode mode; - int endp; { if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) @@ -2294,7 +2290,6 @@ expand_builtin_memcpy (arglist, target, mode, endp) tree src = TREE_VALUE (TREE_CHAIN (arglist)); tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); const char *src_str; - unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT); unsigned int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); @@ -2331,28 +2326,15 @@ expand_builtin_memcpy (arglist, target, mode, endp) && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str, (PTR) src_str, dest_align)) { - store_by_pieces (dest_mem, INTVAL (len_rtx), - builtin_memcpy_read_str, - (PTR) src_str, dest_align); + dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx), + builtin_memcpy_read_str, + (PTR) src_str, dest_align, 0); dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX); #ifdef POINTERS_EXTEND_UNSIGNED if (GET_MODE (dest_mem) != ptr_mode) dest_mem = convert_memory_address (ptr_mode, dest_mem); #endif - if (endp) - { - rtx result; - rtx delta = len_rtx; - - if (endp == 2) - delta = GEN_INT (INTVAL (delta) - 1); - - result = simplify_gen_binary (PLUS, GET_MODE (dest_mem), - dest_mem, delta); - return force_operand (result, NULL_RTX); - } - else - return dest_mem; + return dest_mem; } src_mem = get_memory_rtx (src); @@ -2370,61 +2352,112 @@ expand_builtin_memcpy (arglist, target, mode, endp) dest_addr = convert_memory_address (ptr_mode, dest_addr); #endif } - - if (endp) - { - rtx result = force_operand (len_rtx, NULL_RTX); - - if (endp == 2) - { - result = simplify_gen_binary (MINUS, GET_MODE (dest_addr), - result, const1_rtx); - result = force_operand (result, NULL_RTX); - } - - result = simplify_gen_binary (PLUS, GET_MODE (dest_addr), - dest_addr, result); - return force_operand (result, NULL_RTX); - } - else - return dest_addr; + return dest_addr; } } /* Expand a call to the mempcpy builtin, with arguments in ARGLIST. Return 0 if we failed 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). */ + mode MODE if that's convenient). If ENDP is 0 return the + destination pointer, if ENDP is 1 return the end pointer ala + mempcpy, and if ENDP is 2 return the end pointer minus one ala + stpcpy. */ static rtx -expand_builtin_mempcpy (arglist, target, mode) +expand_builtin_mempcpy (arglist, target, mode, endp) tree arglist; rtx target; enum machine_mode mode; + int endp; { if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) return 0; + /* If return value is ignored, transform mempcpy into memcpy. */ + else if (target == const0_rtx) + { + tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; + + if (!fn) + return 0; + + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); + } else { - /* If return value is ignored, transform mempcpy into memcpy. */ - if (target == const0_rtx) + tree dest = TREE_VALUE (arglist); + tree src = TREE_VALUE (TREE_CHAIN (arglist)); + tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + const char *src_str; + unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT); + unsigned int dest_align + = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); + rtx dest_mem, src_mem, len_rtx; + + /* If DEST is not a pointer type or LEN is not constant, + call the normal function. */ + if (dest_align == 0 || !host_integerp (len, 1)) + return 0; + + /* If the LEN parameter is zero, return DEST. */ + if (tree_low_cst (len, 1) == 0) { - tree fn; - rtx ret = expand_builtin_memcpy (arglist, target, mode, /*endp=*/0); - - if (ret) - return ret; - - fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; - if (!fn) - return 0; - - return expand_expr (build_function_call_expr (fn, arglist), - target, mode, EXPAND_NORMAL); + /* Evaluate and ignore SRC in case it has side-effects. */ + expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL); + return expand_expr (dest, target, mode, EXPAND_NORMAL); } - return expand_builtin_memcpy (arglist, target, mode, /*endp=*/1); + /* If either SRC is not a pointer type, don't do this + operation in-line. */ + if (src_align == 0) + return 0; + + len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); + src_str = c_getstr (src); + + /* If SRC is a string constant and block move would be done + by pieces, we can avoid loading the string from memory + and only stored the computed constants. */ + if (src_str + && GET_CODE (len_rtx) == CONST_INT + && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1 + && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str, + (PTR) src_str, dest_align)) + { + dest_mem = get_memory_rtx (dest); + set_mem_align (dest_mem, dest_align); + dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx), + builtin_memcpy_read_str, + (PTR) src_str, dest_align, endp); + dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX); +#ifdef POINTERS_EXTEND_UNSIGNED + if (GET_MODE (dest_mem) != ptr_mode) + dest_mem = convert_memory_address (ptr_mode, dest_mem); +#endif + return dest_mem; + } + + if (GET_CODE (len_rtx) == CONST_INT + && can_move_by_pieces (INTVAL (len_rtx), + MIN (dest_align, src_align))) + { + dest_mem = get_memory_rtx (dest); + set_mem_align (dest_mem, dest_align); + src_mem = get_memory_rtx (src); + set_mem_align (src_mem, src_align); + dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx), + MIN (dest_align, src_align), endp); + dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX); +#ifdef POINTERS_EXTEND_UNSIGNED + if (GET_MODE (dest_mem) != ptr_mode) + dest_mem = convert_memory_address (ptr_mode, dest_mem); +#endif + return dest_mem; + } + + return 0; } } @@ -2563,13 +2596,7 @@ expand_builtin_stpcpy (arglist, target, mode) /* If return value is ignored, transform stpcpy into strcpy. */ if (target == const0_rtx) { - tree fn; - rtx ret = expand_builtin_strcpy (arglist, target, mode); - - if (ret) - return ret; - - fn = implicit_built_in_decls[BUILT_IN_STRCPY]; + tree fn = implicit_built_in_decls[BUILT_IN_STRCPY]; if (!fn) return 0; @@ -2577,7 +2604,7 @@ expand_builtin_stpcpy (arglist, target, mode) target, mode, EXPAND_NORMAL); } - /* Ensure we get an actual string who length can be evaluated at + /* Ensure we get an actual string whose length can be evaluated at compile-time, not an expression containing a string. This is because the latter will potentially produce pessimized code when used to produce the return value. */ @@ -2588,7 +2615,7 @@ expand_builtin_stpcpy (arglist, target, mode) len = fold (size_binop (PLUS_EXPR, len, ssize_int (1))); newarglist = copy_list (arglist); chainon (newarglist, build_tree_list (NULL_TREE, len)); - return expand_builtin_memcpy (newarglist, target, mode, /*endp=*/2); + return expand_builtin_mempcpy (newarglist, target, mode, /*endp=*/2); } } @@ -2670,7 +2697,7 @@ expand_builtin_strncpy (arglist, target, mode) dest_mem = get_memory_rtx (dest); store_by_pieces (dest_mem, tree_low_cst (len, 1), builtin_strncpy_read_str, - (PTR) p, dest_align); + (PTR) p, dest_align, 0); dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX); #ifdef POINTERS_EXTEND_UNSIGNED if (GET_MODE (dest_mem) != ptr_mode) @@ -2798,7 +2825,7 @@ expand_builtin_memset (arglist, target, mode) dest_mem = get_memory_rtx (dest); store_by_pieces (dest_mem, tree_low_cst (len, 1), builtin_memset_gen_str, - (PTR) val_rtx, dest_align); + (PTR) val_rtx, dest_align, 0); dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX); #ifdef POINTERS_EXTEND_UNSIGNED if (GET_MODE (dest_mem) != ptr_mode) @@ -2822,7 +2849,7 @@ expand_builtin_memset (arglist, target, mode) dest_mem = get_memory_rtx (dest); store_by_pieces (dest_mem, tree_low_cst (len, 1), builtin_memset_read_str, - (PTR) &c, dest_align); + (PTR) &c, dest_align, 0); dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX); #ifdef POINTERS_EXTEND_UNSIGNED if (GET_MODE (dest_mem) != ptr_mode) @@ -4698,13 +4725,13 @@ expand_builtin (exp, target, subtarget, mode, ignore) break; case BUILT_IN_MEMCPY: - target = expand_builtin_memcpy (arglist, target, mode, /*endp=*/0); + target = expand_builtin_memcpy (arglist, target, mode); if (target) return target; break; case BUILT_IN_MEMPCPY: - target = expand_builtin_mempcpy (arglist, target, mode); + target = expand_builtin_mempcpy (arglist, target, mode, /*endp=*/ 1); if (target) return target; break; diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index e3921fbb764..0b216105e0a 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -3821,7 +3821,7 @@ expand_block_move (operands) else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES && align == (unsigned) UNITS_PER_WORD) - move_by_pieces (orig_dest, orig_src, bytes, align * BITS_PER_WORD); + move_by_pieces (orig_dest, orig_src, bytes, align * BITS_PER_WORD, 0); else if (constp && bytes <= (unsigned)2 * MAX_MOVE_BYTES) emit_insn (gen_movstrsi_internal (replace_equiv_address (orig_dest, diff --git a/gcc/expr.c b/gcc/expr.c index e3872e8e269..f340335515b 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -1456,6 +1456,18 @@ convert_modes (mode, oldmode, x, unsignedp) #define STORE_MAX_PIECES MIN (MOVE_MAX_PIECES, 2 * sizeof (HOST_WIDE_INT)) +/* Determine whether the LEN bytes can be moved by using several move + instructions. Return nonzero if a call to move_by_pieces should + succeed. */ + +int +can_move_by_pieces (len, align) + unsigned HOST_WIDE_INT len; + unsigned int align; +{ + return MOVE_BY_PIECES_P (len, align); +} + /* Generate several move instructions to copy LEN bytes from block FROM to block TO. (These are MEM rtx's with BLKmode). The caller must pass FROM and TO through protect_from_queue before calling. @@ -1463,13 +1475,18 @@ convert_modes (mode, oldmode, x, unsignedp) If PUSH_ROUNDING is defined and TO is NULL, emit_single_push_insn is used to push FROM to the stack. - ALIGN is maximum stack alignment we can assume. */ + ALIGN is maximum stack alignment we can assume. -void -move_by_pieces (to, from, len, align) + If ENDP is 0 return to, if ENDP is 1 return memory at the end ala + mempcpy, and if ENDP is 2 return memory the end minus one byte ala + stpcpy. */ + +rtx +move_by_pieces (to, from, len, align, endp) rtx to, from; unsigned HOST_WIDE_INT len; unsigned int align; + int endp; { struct move_by_pieces data; rtx to_addr, from_addr = XEXP (from, 0); @@ -1583,6 +1600,36 @@ move_by_pieces (to, from, len, align) /* The code above should have handled everything. */ if (data.len > 0) abort (); + + if (endp) + { + rtx to1; + + if (data.reverse) + abort (); + if (data.autinc_to) + { + if (endp == 2) + { + if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0) + emit_insn (gen_add2_insn (data.to_addr, constm1_rtx)); + else + data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr, + -1)); + } + to1 = adjust_automodify_address (data.to, QImode, data.to_addr, + data.offset); + } + else + { + if (endp == 2) + --data.offset; + to1 = adjust_address (data.to, QImode, data.offset); + } + return to1; + } + else + return data.to; } /* Return number of insns required to move L bytes by pieces. @@ -1760,7 +1807,7 @@ emit_block_move (x, y, size, method) } if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align)) - move_by_pieces (x, y, INTVAL (size), align); + move_by_pieces (x, y, INTVAL (size), align, 0); else if (emit_block_move_via_movstr (x, y, size, align)) ; else if (may_use_call) @@ -2014,7 +2061,7 @@ init_block_move_fn (asmspec) { if (!block_move_fn) { - tree fn, args; + tree args, fn; if (TARGET_MEM_FUNCTIONS) { @@ -2738,15 +2785,19 @@ can_store_by_pieces (len, constfun, constfundata, align) /* Generate several move instructions to store LEN bytes generated by CONSTFUN to block TO. (A MEM rtx with BLKmode). CONSTFUNDATA is a pointer which will be passed as argument in every CONSTFUN call. - ALIGN is maximum alignment we can assume. */ + ALIGN is maximum alignment we can assume. + If ENDP is 0 return to, if ENDP is 1 return memory at the end ala + mempcpy, and if ENDP is 2 return memory the end minus one byte ala + stpcpy. */ -void -store_by_pieces (to, len, constfun, constfundata, align) +rtx +store_by_pieces (to, len, constfun, constfundata, align, endp) rtx to; unsigned HOST_WIDE_INT len; rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode)); PTR constfundata; unsigned int align; + int endp; { struct store_by_pieces data; @@ -2758,6 +2809,35 @@ store_by_pieces (to, len, constfun, constfundata, align) data.len = len; data.to = to; store_by_pieces_1 (&data, align); + if (endp) + { + rtx to1; + + if (data.reverse) + abort (); + if (data.autinc_to) + { + if (endp == 2) + { + if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0) + emit_insn (gen_add2_insn (data.to_addr, constm1_rtx)); + else + data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr, + -1)); + } + to1 = adjust_automodify_address (data.to, QImode, data.to_addr, + data.offset); + } + else + { + if (endp == 2) + --data.offset; + to1 = adjust_address (data.to, QImode, data.offset); + } + return to1; + } + else + return data.to; } /* Generate several move instructions to clear LEN bytes of block TO. (A MEM @@ -3872,7 +3952,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra, && where_pad != none && where_pad != stack_direction) anti_adjust_stack (GEN_INT (extra)); - move_by_pieces (NULL, xinner, INTVAL (size) - used, align); + move_by_pieces (NULL, xinner, INTVAL (size) - used, align, 0); } else #endif /* PUSH_ROUNDING */ diff --git a/gcc/expr.h b/gcc/expr.h index 8b6e36ac291..8cf5a8e5a6c 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -450,6 +450,11 @@ extern void use_group_regs PARAMS ((rtx *, rtx)); If OBJECT has BLKmode, SIZE is its length in bytes. */ extern rtx clear_storage PARAMS ((rtx, rtx)); +/* Determine whether the LEN bytes can be moved by using several move + instructions. Return nonzero if a call to move_by_pieces should + succeed. */ +extern int can_move_by_pieces PARAMS ((unsigned HOST_WIDE_INT, unsigned int)); + /* Return nonzero if it is desirable to store LEN bytes generated by CONSTFUN with several move instructions by store_by_pieces function. CONSTFUNDATA is a pointer which will be passed as argument @@ -463,11 +468,12 @@ extern int can_store_by_pieces PARAMS ((unsigned HOST_WIDE_INT, /* Generate several move instructions to store LEN bytes generated by CONSTFUN to block TO. (A MEM rtx with BLKmode). CONSTFUNDATA is a pointer which will be passed as argument in every CONSTFUN call. - ALIGN is maximum alignment we can assume. */ -extern void store_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT, - rtx (*) (PTR, HOST_WIDE_INT, - enum machine_mode), - PTR, unsigned int)); + ALIGN is maximum alignment we can assume. + Returns TO + LEN. */ +extern rtx store_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT, + rtx (*) (PTR, HOST_WIDE_INT, + enum machine_mode), + PTR, unsigned int, int)); /* Emit insns to set X from Y. */ extern rtx emit_move_insn PARAMS ((rtx, rtx)); diff --git a/gcc/rtl.h b/gcc/rtl.h index ea0c9b38d5d..8a76fe2a267 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -2141,9 +2141,9 @@ extern void emit_jump PARAMS ((rtx)); extern int preserve_subexpressions_p PARAMS ((void)); /* In expr.c */ -extern void move_by_pieces PARAMS ((rtx, rtx, +extern rtx move_by_pieces PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT, - unsigned int)); + unsigned int, int)); /* In flow.c */ extern void recompute_reg_usage PARAMS ((rtx, int)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 67ba333fab3..5ab4e9a7807 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2003-06-03 Jakub Jelinek + + * gcc.c-torture/execute/builtins/string-4.c (main_test): Remove + mempcpy test with post-increments. + * gcc.c-torture/execute/string-opt-3.c: New test. + * gcc.dg/string-opt-1.c: New test. + 2003-06-03 David Billinghurst (David.Billinghurst@riotinto.com) PR fortran/10965 diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/string-4.c b/gcc/testsuite/gcc.c-torture/execute/builtins/string-4.c index 9c0ee5473fd..0d0544e3de2 100644 --- a/gcc/testsuite/gcc.c-torture/execute/builtins/string-4.c +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/string-4.c @@ -23,7 +23,6 @@ void main_test (void) { int i; - const char *s; if (stpcpy (p, "abcde") != p + 5 || memcmp (p, "abcde", 6)) abort (); @@ -47,9 +46,8 @@ main_test (void) if (stpcpy ((i++, p + 20 + 1), "23") != (p + 20 + 1 + 2) || i != 9 || memcmp (p + 20, "q23\0u", 6)) abort (); - s = s1; i = 3; memcpy (p + 25, "QRSTU", 6); - if (mempcpy (p + 25 + 1, s++, i++) != (p + 25 + 1 + 3) || i != 4 || s != s1 + 1 || memcmp (p + 25, "Q123U", 6)) + if (mempcpy (p + 25 + 1, s1, 3) != (p + 25 + 1 + 3) || memcmp (p + 25, "Q123U", 6)) abort (); if (stpcpy (stpcpy (p, "ABCD"), "EFG") != p + 7 || memcmp (p, "ABCDEFG", 8)) diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-3.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-3.c new file mode 100644 index 00000000000..71a41cdbf4e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/string-opt-3.c @@ -0,0 +1,166 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Ensure that builtin mempcpy and stpcpy perform correctly. + + Written by Jakub Jelinek, 21/05/2003. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern void *mempcpy (void *, const void *, size_t); +extern int memcmp (const void *, const void *, size_t); +extern char *stpcpy (char *, const char *); + +long buf1[64]; +char *buf2 = (char *) (buf1 + 32); +long buf5[20]; +char buf7[20]; + +int +__attribute__((noinline)) +test (long *buf3, char *buf4, char *buf6, int n) +{ + int i = 0; + + /* These should probably be handled by store_by_pieces on most arches. */ + if (mempcpy (buf1, "ABCDEFGHI", 9) != (char *) buf1 + 9 + || memcmp (buf1, "ABCDEFGHI\0", 11)) + abort (); + + if (mempcpy (buf1, "abcdefghijklmnopq", 17) != (char *) buf1 + 17 + || memcmp (buf1, "abcdefghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf3, "ABCDEF", 6) != (char *) buf1 + 6 + || memcmp (buf1, "ABCDEFghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf3, "a", 1) != (char *) buf1 + 1 + || memcmp (buf1, "aBCDEFghijklmnopq\0", 19)) + abort (); + + if (mempcpy ((char *) buf3 + 2, "bcd" + ++i, 2) != (char *) buf1 + 4 + || memcmp (buf1, "aBcdEFghijklmnopq\0", 19) + || i != 1) + abort (); + + /* These should probably be handled by move_by_pieces on most arches. */ + if (mempcpy ((char *) buf3 + 4, buf5, 6) != (char *) buf1 + 10 + || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, 1) + != (char *) buf1 + 11 + || memcmp (buf1, "aBcdRSTUVWSlmnopq\0", 19) + || i != 2) + abort (); + + if (mempcpy ((char *) buf3 + 14, buf6, 2) != (char *) buf1 + 16 + || memcmp (buf1, "aBcdRSTUVWSlmnrsq\0", 19)) + abort (); + + if (mempcpy (buf3, buf5, 8) != (char *) buf1 + 8 + || memcmp (buf1, "RSTUVWXYVWSlmnrsq\0", 19)) + abort (); + + if (mempcpy (buf3, buf5, 17) != (char *) buf1 + 17 + || memcmp (buf1, "RSTUVWXYZ01234567\0", 19)) + abort (); + + __builtin_memcpy (buf3, "aBcdEFghijklmnopq\0", 19); + + /* These should be handled either by movstrendM or mempcpy + call. */ + if (mempcpy ((char *) buf3 + 4, buf5, n + 6) != (char *) buf1 + 10 + || memcmp (buf1, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy ((char *) buf1 + ++i + 8, (char *) buf5 + 1, n + 1) + != (char *) buf1 + 12 + || memcmp (buf1, "aBcdRSTUVWkSmnopq\0", 19) + || i != 3) + abort (); + + if (mempcpy ((char *) buf3 + 14, buf6, n + 2) != (char *) buf1 + 16 + || memcmp (buf1, "aBcdRSTUVWkSmnrsq\0", 19)) + abort (); + + i = 1; + + /* These might be handled by store_by_pieces. */ + if (mempcpy (buf2, "ABCDEFGHI", 9) != buf2 + 9 + || memcmp (buf2, "ABCDEFGHI\0", 11)) + abort (); + + if (mempcpy (buf2, "abcdefghijklmnopq", 17) != buf2 + 17 + || memcmp (buf2, "abcdefghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf4, "ABCDEF", 6) != buf2 + 6 + || memcmp (buf2, "ABCDEFghijklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf4, "a", 1) != buf2 + 1 + || memcmp (buf2, "aBCDEFghijklmnopq\0", 19)) + abort (); + + if (mempcpy (buf4 + 2, "bcd" + i++, 2) != buf2 + 4 + || memcmp (buf2, "aBcdEFghijklmnopq\0", 19) + || i != 2) + abort (); + + /* These might be handled by move_by_pieces. */ + if (mempcpy (buf4 + 4, buf7, 6) != buf2 + 10 + || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf2 + i++ + 8, buf7 + 1, 1) + != buf2 + 11 + || memcmp (buf2, "aBcdRSTUVWSlmnopq\0", 19) + || i != 3) + abort (); + + if (mempcpy (buf4 + 14, buf6, 2) != buf2 + 16 + || memcmp (buf2, "aBcdRSTUVWSlmnrsq\0", 19)) + abort (); + + __builtin_memcpy (buf4, "aBcdEFghijklmnopq\0", 19); + + /* These should be handled either by movstrendM or mempcpy + call. */ + if (mempcpy (buf4 + 4, buf7, n + 6) != buf2 + 10 + || memcmp (buf2, "aBcdRSTUVWklmnopq\0", 19)) + abort (); + + if (__builtin_mempcpy (buf2 + i++ + 8, buf7 + 1, n + 1) + != buf2 + 12 + || memcmp (buf2, "aBcdRSTUVWkSmnopq\0", 19) + || i != 4) + abort (); + + if (mempcpy (buf4 + 14, buf6, n + 2) != buf2 + 16 + || memcmp (buf2, "aBcdRSTUVWkSmnrsq\0", 19)) + abort (); + + /* Now stpcpy tests. */ + if (stpcpy ((char *) buf3, "abcdefghijklmnop") != (char *) buf1 + 16 + || memcmp (buf1, "abcdefghijklmnop", 17)) + abort (); + + if (__builtin_stpcpy ((char *) buf3, "ABCDEFG") != (char *) buf1 + 7 + || memcmp (buf1, "ABCDEFG\0ijklmnop", 17)) + abort (); + + if (stpcpy ((char *) buf3 + i++, "x") != (char *) buf1 + 5 + || memcmp (buf1, "ABCDx\0G\0ijklmnop", 17)) + abort (); + + return 0; +} + +int +main () +{ + __builtin_memcpy (buf5, "RSTUVWXYZ0123456789", 20); + __builtin_memcpy (buf7, "RSTUVWXYZ0123456789", 20); + return test (buf1, buf2, "rstuvwxyz", 0); +} diff --git a/gcc/testsuite/gcc.dg/string-opt-1.c b/gcc/testsuite/gcc.dg/string-opt-1.c new file mode 100644 index 00000000000..bc0f30098fa --- /dev/null +++ b/gcc/testsuite/gcc.dg/string-opt-1.c @@ -0,0 +1,11 @@ +/* Ensure mempcpy is not "optimized" into memcpy followed by addition. */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +void * +fn (char *x, char *y, int z) +{ + return __builtin_mempcpy (x, y, z); +} + +/* { dg-final { scan-assembler-not "memcpy" } } */