[PATCH] Use movmem optab to attempt inline expansion of __builtin_memmove()

Jeff Law law@redhat.com
Tue Oct 1 21:45:00 GMT 2019


On 9/27/19 12:23 PM, Aaron Sawdey wrote:
> This is the third piece of my effort to improve inline expansion of memmove. The
> first two parts I posted back in June fixed the names of the optab entries
> involved so that optab cpymem is used for memcpy() and optab movmem is used for
> memmove(). This piece adds support for actually attempting to invoke the movmem
> optab to do inline expansion of __builtin_memmove().
> 
> Because what needs to be done for memmove() is very similar to memcpy(), I have
> just added a bool parm "might_overlap" to several of the functions involved so
> the same functions can handle both. The name might_overlap comes from the fact
> that if we still have a memmove() call at expand, this means
> gimple_fold_builtin_memory_op() was not able to prove that the source and
> destination do not overlap.
> 
> There are a few places where might_overlap gets used to keep us from trying to
> use the by-pieces infrastructure or generate a copy loop, as neither of those
> things will work correctly if source and destination overlap.
> 
> I've restructured things slightly in emit_block_move_hints() so that we can
> try the pattern first if we already know that by-pieces won't work. This way
> we can bail out immediately in the might_overlap case.
> 
> Bootstrap/regtest passed on ppc64le, in progress on x86_64. If everything passes,
> is this ok for trunk?
> 
> 
> 2019-09-27  Aaron Sawdey <acsawdey@linux.ibm.com>
> 
> 	* builtins.c (expand_builtin_memory_copy_args): Add might_overlap parm.
> 	(expand_builtin_memcpy): Use might_overlap parm.
> 	(expand_builtin_mempcpy_args): Use might_overlap parm.
> 	(expand_builtin_memmove): Call expand_builtin_memory_copy_args.
> 	(expand_builtin_memory_copy_args): Add might_overlap parm.
> 	* expr.c (emit_block_move_via_cpymem): Rename to
> 	emit_block_move_via_pattern, add might_overlap parm, use cpymem
> 	or movmem optab as appropriate.
> 	(emit_block_move_hints): Add might_overlap parm, do the right
> 	thing for might_overlap==true.
> 	* expr.h (emit_block_move_hints): Update prototype.
> 
> 
> 
> 
> Index: gcc/builtins.c
> ===================================================================
> --- gcc/builtins.c	(revision 276131)
> +++ gcc/builtins.c	(working copy)
> @@ -3894,10 +3897,11 @@
>  			&probable_max_size);
>    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
> +  /* 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.  I'm not sure if the by pieces
> +     method works if src/dest are overlapping, so avoid that case.  */
> +  if (src_str && !might_overlap
I don't think you need the check here.  c_getstr, when it returns
somethign useful is going to be returning a string constant.  Think read
only literals here.  I'm pretty sure overlap isn't going to be possible.

>        && CONST_INT_P (len_rtx)
>        && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
>        && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
> @@ -3922,7 +3926,7 @@
>        && (retmode == RETURN_BEGIN || target == const0_rtx))
>      method = BLOCK_OP_TAILCALL;
>    bool use_mempcpy_call = (targetm.libc_has_fast_function (BUILT_IN_MEMPCPY)
> -			   && retmode == RETURN_END
> +			   && retmode == RETURN_END && !might_overlap
Put the && !might_overlap on its own line for readability.


> Index: gcc/expr.c
> ===================================================================
> --- gcc/expr.c	(revision 276131)
> +++ gcc/expr.c	(working copy)
> @@ -1622,13 +1624,29 @@
>        set_mem_size (y, const_size);
>      }
> 
> -  if (CONST_INT_P (size) && can_move_by_pieces (INTVAL (size), align))
> +  bool pieces_ok = can_move_by_pieces (INTVAL (size), align);
> +  bool pattern_ok = false;
> +
> +  if (!CONST_INT_P (size) || !pieces_ok || might_overlap)
> +    {
> +      pattern_ok =
> +	emit_block_move_via_pattern (x, y, size, align,
> +				     expected_align, expected_size,
> +				     min_size, max_size, probable_max_size,
> +				     might_overlap);
> +      if (!pattern_ok && might_overlap)
> +	{
> +	  /* Do not try any of the other methods below as they are not safe
> +	     for overlapping moves.  */
> +	  *is_move_done = false;
> +	  return retval;
> +	}
> +    }
> +
> +  if (pattern_ok) ;
Drop the semi-colon down to its own line like

if (whatever)
  ;
else if (...)
  something
else if (...)
  something else

With the changes noted above, this is fine for th trunk.

jeff



More information about the Gcc-patches mailing list