On 5/10/19 11:21 AM, Jakub Jelinek wrote: > On Fri, May 10, 2019 at 11:04:12AM +0200, Martin Liška wrote: >> --- a/gcc/config/i386/i386.h >> +++ b/gcc/config/i386/i386.h >> @@ -1906,6 +1906,9 @@ typedef struct ix86_args { >> >> #define CLEAR_RATIO(speed) ((speed) ? MIN (6, ix86_cost->move_ratio) : 2) >> >> +/* C library provides fast implementation of mempcpy function. */ >> +#define TARGET_HAS_FAST_MEMPCPY_ROUTINE 1 >> + > > 1) we shouldn't be adding further target macros, but target hooks
Done. > 2) I don't think this is a property of the x86 target, but of x86 glibc, > so you should set it on x86 glibc only (i.e. i?86/x86_64 linux and hurd > when using glibc, not newlib, nor bionic/android, nor uclibc, nor musl) I've implemented the in i386.c with DEFAULT_LIBC == LIBC_GLIBC. Hope it's correct? > >> --- a/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy.c >> +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/mempcpy.c >> @@ -56,9 +56,8 @@ main_test (void) >> if (__builtin_mempcpy (p, "ABCDE", 6) != p + 6 || memcmp (p, "ABCDE", 6)) >> abort (); >> >> - /* If the result of mempcpy is ignored, gcc should use memcpy. >> - This should be optimized always, so set inside_main again. */ >> - inside_main = 1; >> + /* Set inside main in order to not abort because of usafe of mempcpy. */ >> + inside_main = 0; >> mempcpy (p + 5, s3, 1); >> if (memcmp (p, "ABCDEFg", 8)) >> abort (); > > Why this? Do you mean mempcpy is called here, even when the lhs is unused? > We should be calling memcpy in that case. Yes, that's a stupid mistake. I'm attaching updated version of the patch that works fine in x86_64-linux-gnu. Martin > > Jakub >
>From 05b36e6a04e061b46638ec6f23ad2027f033caf9 Mon Sep 17 00:00:00 2001 From: marxin <mli...@suse.cz> Date: Mon, 29 Apr 2019 13:46:25 +0200 Subject: [PATCH] Come up with has_fast_mempcpy_routine hook (PR middle-end/90263). gcc/ChangeLog: 2019-05-13 Martin Liska <mli...@suse.cz> PR middle-end/90263 * builtins.c (expand_builtin_memory_copy_args): When having a target with fast mempcpy implementation do now use memcpy. * config/i386/i386.c (glibc_has_fast_mempcpy_routine): New. (TARGET_HAS_FAST_MEMPCPY_ROUTINE): Likewise. * doc/tm.texi: Likewise. * doc/tm.texi.in: Likewise. * target.def: Likewise. * expr.c (emit_block_move_hints): Add 2 new arguments. * expr.h (emit_block_move_hints): Bail out when libcall to memcpy would be used. gcc/testsuite/ChangeLog: 2019-05-13 Martin Liska <mli...@suse.cz> PR middle-end/90263 * gcc.c-torture/pr90263.c: New test. --- gcc/builtins.c | 17 +++++++++++++++-- gcc/config/i386/i386.c | 10 ++++++++++ gcc/doc/tm.texi | 4 ++++ gcc/doc/tm.texi.in | 2 ++ gcc/expr.c | 13 ++++++++++++- gcc/expr.h | 4 +++- gcc/target.def | 6 ++++++ gcc/testsuite/gcc.c-torture/pr90263.c | 9 +++++++++ 8 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/pr90263.c diff --git a/gcc/builtins.c b/gcc/builtins.c index d37d73fc4a0..06b19b62b43 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -3839,6 +3839,8 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len, unsigned HOST_WIDE_INT max_size; unsigned HOST_WIDE_INT probable_max_size; + bool is_move_done; + /* If DEST is not a pointer type, call the normal function. */ if (dest_align == 0) return NULL_RTX; @@ -3888,11 +3890,22 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len, if (CALL_EXPR_TAILCALL (exp) && (retmode == RETURN_BEGIN || target == const0_rtx)) method = BLOCK_OP_TAILCALL; - if (retmode == RETURN_END && target != const0_rtx) + bool use_mempcpy_call = (targetm.has_fast_mempcpy_routine () + && retmode == RETURN_END + && target != const0_rtx); + if (use_mempcpy_call) method = BLOCK_OP_NO_LIBCALL_RET; dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx, method, expected_align, expected_size, - min_size, max_size, probable_max_size); + min_size, max_size, probable_max_size, + use_mempcpy_call, &is_move_done); + + /* Bail out when a mempcpy call would be expanded as libcall and when + we have a target that provides a fast implementation + of mempcpy routine. */ + if (!is_move_done) + return NULL_RTX; + if (dest_addr == pc_rtx) return NULL_RTX; diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index cc0ae3fcfd3..a0fc9786568 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -23056,6 +23056,16 @@ ix86_run_selftests (void) #define TARGET_GET_MULTILIB_ABI_NAME \ ix86_get_multilib_abi_name +#if DEFAULT_LIBC == LIBC_GLIBC +static bool glibc_has_fast_mempcpy_routine (void) +{ + return true; +} + +#undef TARGET_HAS_FAST_MEMPCPY_ROUTINE +#define TARGET_HAS_FAST_MEMPCPY_ROUTINE glibc_has_fast_mempcpy_routine +#endif + #if CHECKING_P #undef TARGET_RUN_TARGET_SELFTESTS #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 8c8978bb13a..dbe1ef7f4a1 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -1935,6 +1935,10 @@ call_2 may be NULL or a call insn. This hook returns name of multilib ABI name. @end deftypefn +@deftypefn {Target Hook} bool TARGET_HAS_FAST_MEMPCPY_ROUTINE (void) +Return true if a target has a fast mempcpy routine. +@end deftypefn + @findex fixed_regs @findex call_used_regs @findex global_regs diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index fe1194ef91a..a64205c221b 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -1713,6 +1713,8 @@ of @code{CALL_USED_REGISTERS}. @hook TARGET_GET_MULTILIB_ABI_NAME +@hook TARGET_HAS_FAST_MEMPCPY_ROUTINE + @findex fixed_regs @findex call_used_regs @findex global_regs diff --git a/gcc/expr.c b/gcc/expr.c index fa15b7eceae..c78bc74c0d9 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -1561,12 +1561,16 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, unsigned int expected_align, HOST_WIDE_INT expected_size, unsigned HOST_WIDE_INT min_size, unsigned HOST_WIDE_INT max_size, - unsigned HOST_WIDE_INT probable_max_size) + unsigned HOST_WIDE_INT probable_max_size, + bool bail_out_libcall, bool *is_move_done) { int may_use_call; rtx retval = 0; unsigned int align; + if (is_move_done) + *is_move_done = true; + gcc_assert (size); if (CONST_INT_P (size) && INTVAL (size) == 0) return 0; @@ -1628,6 +1632,13 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x)) && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (y))) { + if (bail_out_libcall) + { + if (is_move_done) + *is_move_done = false; + return retval; + } + if (may_use_call < 0) return pc_rtx; diff --git a/gcc/expr.h b/gcc/expr.h index 17c3962436a..6eb70bf12f1 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -114,7 +114,9 @@ extern rtx emit_block_move_hints (rtx, rtx, rtx, enum block_op_methods, unsigned int, HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, - unsigned HOST_WIDE_INT); + unsigned HOST_WIDE_INT, + bool bail_out_libcall = false, + bool *is_move_done = NULL); extern rtx emit_block_cmp_hints (rtx, rtx, rtx, tree, rtx, bool, by_pieces_constfn, void *); extern bool emit_storent_insn (rtx to, rtx from); diff --git a/gcc/target.def b/gcc/target.def index 66cee075018..7bff5cbd313 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -5797,6 +5797,12 @@ DEFHOOK const char *, (void), hook_constcharptr_void_null) +DEFHOOK +(has_fast_mempcpy_routine, + "Return true if a target has a fast mempcpy routine.", + bool, (void), + hook_bool_void_false) + DEFHOOK (remove_extra_call_preserved_regs, "This hook removes registers from the set of call-clobbered registers\n\ diff --git a/gcc/testsuite/gcc.c-torture/pr90263.c b/gcc/testsuite/gcc.c-torture/pr90263.c new file mode 100644 index 00000000000..a348f6265d3 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/pr90263.c @@ -0,0 +1,9 @@ +/* PR middle-end/90263 */ + +int *f (int *p, int *q, long n) +{ + return __builtin_mempcpy (p, q, n); +} + +/* { dg-final { scan-assembler "mempcpy" { target { i?86-*-* x86_64-*-* } } } } */ +/* { dg-final { scan-assembler "memcpy" { target { ! { i?86-*-* x86_64-*-* } } } } } */ -- 2.21.0