memmove folding tweek

Jan Hubicka jh@suse.cz
Sun Oct 22 19:49:00 GMT 2006


Hi,
this patch moves code translating memmove into memcpy from expander to folder
so it can happen early (and other optimizations can take place).
The original code tested operands to be pointers for both transformations, I
can't see how it is neccesary, but I kept it around to be safe.

I also dropped the code to copy around the tailcall information: while at
expansion time we would always lose tailcall oppurtunity, in the new
implementation this can happen only in the case TER+folding of operands
introduce possibility for this that is not terribly likely and we don't do it
on other places either (and want to move away from TER anyway).

This is first patch from my stringops merge project - basically I am shooting
for adding histogram profiling for operand size of stringop and machinery to
use it on expansion time (ie chose libcall or inline variant) and to rewrite
x86 expansion to take advantage of it.  While working on this, I did few other
transformations but apparently Jakub beaten me in many cases.  I will try to
break out other bits that are still missing in next patches.

Bootstrapped/regtested i686-linux, OK?

Honza

/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
/* { dg-final { scan-tree-dump-times "memmove" 0 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
static const char a[100]={1,2,3,4};
char b[1000];
int i,i1;
static inline
void *memmove (void *dest, const void *src, long n);
__attribute__ ((always_inline))
domem (void *dest, const void *src, int len)
{
	memmove (dest, src, len);
}
t()
{
	domem (b,a,100);
	domem (b+i1,(const void *)b,1);
}
Index: builtins.c
===================================================================
*** builtins.c	(revision 117938)
--- builtins.c	(working copy)
*************** static rtx expand_builtin_strspn (tree, 
*** 111,117 ****
  static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
  static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode);
  static rtx expand_builtin_mempcpy (tree, tree, rtx, enum machine_mode, int);
! static rtx expand_builtin_memmove (tree, tree, rtx, enum machine_mode, tree);
  static rtx expand_builtin_bcopy (tree);
  static rtx expand_builtin_strcpy (tree, tree, rtx, enum machine_mode);
  static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
--- 111,117 ----
  static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
  static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode);
  static rtx expand_builtin_mempcpy (tree, tree, rtx, enum machine_mode, int);
! static rtx expand_builtin_memmove (tree, tree, rtx, enum machine_mode);
  static rtx expand_builtin_bcopy (tree);
  static rtx expand_builtin_strcpy (tree, tree, rtx, enum machine_mode);
  static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
*************** expand_builtin_mempcpy (tree arglist, tr
*** 3089,3108 ****
  
  static rtx
  expand_builtin_memmove (tree arglist, tree type, rtx target,
! 			enum machine_mode mode, tree orig_exp)
  {
    if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return 0;
    else
      {
-       tree dest = TREE_VALUE (arglist);
-       tree src = TREE_VALUE (TREE_CHAIN (arglist));
-       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
- 
-       unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
-       unsigned int dest_align
- 	= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
        tree result = fold_builtin_memory_op (arglist, type, false, /*endp=*/3);
  
        if (result)
--- 3089,3101 ----
  
  static rtx
  expand_builtin_memmove (tree arglist, tree type, rtx target,
! 			enum machine_mode mode)
  {
    if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return 0;
    else
      {
        tree result = fold_builtin_memory_op (arglist, type, false, /*endp=*/3);
  
        if (result)
*************** expand_builtin_memmove (tree arglist, tr
*** 3116,3153 ****
  	  return expand_expr (result, target, mode, EXPAND_NORMAL);
  	}
  
-       /* If DEST is not a pointer type, call the normal function.  */
-       if (dest_align == 0)
- 	return 0;
- 
-       /* If either SRC is not a pointer type, don't do this
- 	 operation in-line.  */
-       if (src_align == 0)
- 	return 0;
- 
-       /* If src is categorized for a readonly section we can use
- 	 normal memcpy.  */
-       if (readonly_data_expr (src))
- 	{
- 	  tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
- 	  if (!fn)
- 	    return 0;
- 	  fn = build_function_call_expr (fn, arglist);
- 	  if (TREE_CODE (fn) == CALL_EXPR)
- 	    CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
- 	  return expand_expr (fn, target, mode, EXPAND_NORMAL);
- 	}
- 
-       /* If length is 1 and we can expand memcpy call inline,
- 	 it is ok to use memcpy as well.  */
-       if (integer_onep (len))
- 	{
- 	  rtx ret = expand_builtin_mempcpy (arglist, type, target, mode,
- 					    /*endp=*/0);
- 	  if (ret)
- 	    return ret;
- 	}
- 
        /* Otherwise, call the normal function.  */
        return 0;
     }
--- 3109,3114 ----
*************** expand_builtin_bcopy (tree exp)
*** 3180,3186 ****
    newarglist = tree_cons (NULL_TREE, src, newarglist);
    newarglist = tree_cons (NULL_TREE, dest, newarglist);
  
!   return expand_builtin_memmove (newarglist, type, const0_rtx, VOIDmode, exp);
  }
  
  #ifndef HAVE_movstr
--- 3141,3147 ----
    newarglist = tree_cons (NULL_TREE, src, newarglist);
    newarglist = tree_cons (NULL_TREE, dest, newarglist);
  
!   return expand_builtin_memmove (newarglist, type, const0_rtx, VOIDmode);
  }
  
  #ifndef HAVE_movstr
*************** expand_builtin (tree exp, rtx target, rt
*** 6073,6079 ****
  
      case BUILT_IN_MEMMOVE:
        target = expand_builtin_memmove (arglist, TREE_TYPE (exp), target,
! 				       mode, exp);
        if (target)
  	return target;
        break;
--- 6034,6040 ----
  
      case BUILT_IN_MEMMOVE:
        target = expand_builtin_memmove (arglist, TREE_TYPE (exp), target,
! 				       mode);
        if (target)
  	return target;
        break;
*************** fold_builtin_memory_op (tree arglist, tr
*** 8146,8151 ****
--- 8107,8133 ----
      expr = len;
    else
      {
+       if (endp == 3)
+ 	{
+           unsigned int src_align
+ 	     = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+           unsigned int dest_align
+ 	     = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+ 	  /* Both DEST and SRC must be pointer types. 
+ 	     ??? This is what old code did.  Is the testing for pointer types
+ 	     really mandatory?
+ 
+ 	     If either SRC is readonly or length is 1, we can use memcpy.  */
+ 	  if (dest_align && src_align
+ 	      && (readonly_data_expr (src)
+ 		  || integer_onep (len)))
+ 	    {
+ 	      tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ 	      if (!fn)
+ 		return 0;
+ 	      return build_function_call_expr (fn, arglist);
+ 	    }
+ 	}
        if (! host_integerp (len, 1))
  	return 0;
  



More information about the Gcc-patches mailing list