This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH]: Optimize builtin memset with length zero.



The following patch implements a suggestion on the GCC projects page
under the section "Better builtin string functions".  This patch
optimizes away a "memset" when the length is known to be zero at
compile time.  It also does the same for "memcpy" in all cases where
the length is known to be zero.

The reason for the additional size of this patch is that the TARGET
and MODE parameters can now be usefully used in several more functions.

Tested by "make bootstrap" and "make check-gcc" on i686-pc-linux-gnu
with no new regressions.  The patch also includes a new testcase,
gcc-c.torture/execute/string-opt-14.c, to ensure both optimizations
are being applied.

If accepted, I'll submit a follow-up patch to update the appropriate
section of projects.html, removing the optimizations that have already
been implemented in GCC 3.1.


2001-11-23  Roger Sayle <roger@eyesopen.com>
	* builtins.c (expand_builtin_memset, expand_builtin_memcpy,
	expand_builtin_strcpy): Additional arguments TARGET and MODE.
	(expand_builtin, expand_builtin_bzero, expand_builtin_strcpy,
	expand_builtin_strncpy, expand_builtin_bzero): Pass additional
	TARGET and MODE parameters to the above functions.
	(expand_builtin_memset, expand_builtin_memcpy): Optimize the
	case where the LEN parameter is constant zero.
	* string-opt-14.c: New testcase.


diff -c3pr gcc/gcc/builtins.c patch1/gcc/builtins.c
*** gcc/gcc/builtins.c	Sun Nov 18 10:33:50 2001
--- patch1/gcc/builtins.c	Fri Nov 23 14:24:29 2001
*************** static rtx expand_builtin_strspn	PARAMS
*** 117,131 ****
  						 enum machine_mode));
  static rtx expand_builtin_strcspn	PARAMS ((tree, rtx,
  						 enum machine_mode));
! static rtx expand_builtin_memcpy	PARAMS ((tree));
! static rtx expand_builtin_strcpy	PARAMS ((tree));
  static rtx builtin_strncpy_read_str	PARAMS ((PTR, HOST_WIDE_INT,
  						 enum machine_mode));
  static rtx expand_builtin_strncpy	PARAMS ((tree, rtx,
  						 enum machine_mode));
  static rtx builtin_memset_read_str	PARAMS ((PTR, HOST_WIDE_INT,
  						 enum machine_mode));
! static rtx expand_builtin_memset	PARAMS ((tree));
  static rtx expand_builtin_bzero		PARAMS ((tree));
  static rtx expand_builtin_strlen	PARAMS ((tree, rtx));
  static rtx expand_builtin_strstr	PARAMS ((tree, rtx,
--- 117,134 ----
  						 enum machine_mode));
  static rtx expand_builtin_strcspn	PARAMS ((tree, rtx,
  						 enum machine_mode));
! static rtx expand_builtin_memcpy	PARAMS ((tree, rtx,
!                                                  enum machine_mode));
! static rtx expand_builtin_strcpy	PARAMS ((tree, rtx,
!                                                  enum machine_mode));
  static rtx builtin_strncpy_read_str	PARAMS ((PTR, HOST_WIDE_INT,
  						 enum machine_mode));
  static rtx expand_builtin_strncpy	PARAMS ((tree, rtx,
  						 enum machine_mode));
  static rtx builtin_memset_read_str	PARAMS ((PTR, HOST_WIDE_INT,
  						 enum machine_mode));
! static rtx expand_builtin_memset	PARAMS ((tree, rtx,
!                                                  enum machine_mode));
  static rtx expand_builtin_bzero		PARAMS ((tree));
  static rtx expand_builtin_strlen	PARAMS ((tree, rtx));
  static rtx expand_builtin_strstr	PARAMS ((tree, rtx,
*************** builtin_memcpy_read_str (data, offset, m
*** 1840,1850 ****
    return c_readstr (str + offset, mode);
  }

! /* Expand a call to the memcpy builtin, with arguments in ARGLIST.  */

  static rtx
! expand_builtin_memcpy (arglist)
       tree arglist;
  {
    if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
--- 1843,1858 ----
    return c_readstr (str + 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).  */

  static rtx
! expand_builtin_memcpy (arglist, target, mode)
       tree arglist;
+      rtx target;
+      enum machine_mode mode;
  {
    if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
*************** expand_builtin_memcpy (arglist)
*** 1861,1870 ****
  	= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
        rtx dest_mem, src_mem, dest_addr, len_rtx;

!       /* If either SRC or DEST is not a pointer type, don't do
! 	 this operation in-line.  */
!       if (src_align == 0 || dest_align == 0)
! 	return 0;

        dest_mem = get_memory_rtx (dest);
        set_mem_align (dest_mem, dest_align);
--- 1869,1890 ----
  	= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
        rtx dest_mem, src_mem, dest_addr, len_rtx;

!       /* If DEST is not a pointer type, call the normal function.  */
!       if (dest_align == 0)
!         return 0;
!
!       /* If the LEN parameter is zero, return DEST.  */
!       if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
!         {
!           /* 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);
!         }
!
!       /* If either SRC is not a pointer type, don't do this
!          operation in-line.  */
!       if (src_align == 0)
!         return 0;

        dest_mem = get_memory_rtx (dest);
        set_mem_align (dest_mem, dest_align);
*************** expand_builtin_memcpy (arglist)
*** 1908,1918 ****
  }

  /* Expand expression EXP, which is a call to the strcpy builtin.  Return 0
!    if we failed the caller should emit a normal call.  */

  static rtx
! expand_builtin_strcpy (exp)
       tree exp;
  {
    tree arglist = TREE_OPERAND (exp, 1);
    rtx result;
--- 1928,1942 ----
  }

  /* Expand expression EXP, which is a call to the strcpy builtin.  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).  */

  static rtx
! expand_builtin_strcpy (exp, target, mode)
       tree exp;
+      rtx target;
+      enum machine_mode mode;
  {
    tree arglist = TREE_OPERAND (exp, 1);
    rtx result;
*************** expand_builtin_strcpy (exp)
*** 1930,1936 ****
        chainon (arglist, build_tree_list (NULL_TREE, len));
      }

!   result = expand_builtin_memcpy (arglist);

    if (! result)
      TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
--- 1954,1960 ----
        chainon (arglist, build_tree_list (NULL_TREE, len));
      }

!   result = expand_builtin_memcpy (arglist, target, mode);

    if (! result)
      TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
*************** expand_builtin_strncpy (arglist, target,
*** 2019,2025 ****
  	}

        /* OK transform into builtin memcpy.  */
!       return expand_builtin_memcpy (arglist);
      }
  }

--- 2043,2049 ----
  	}

        /* OK transform into builtin memcpy.  */
!       return expand_builtin_memcpy (arglist, target, mode);
      }
  }

*************** builtin_memset_read_str (data, offset, m
*** 2042,2052 ****
  }

  /* Expand expression EXP, which is a call to the memset builtin.  Return 0
!    if we failed the caller should emit a normal call.  */

  static rtx
! expand_builtin_memset (exp)
       tree exp;
  {
    tree arglist = TREE_OPERAND (exp, 1);

--- 2066,2080 ----
  }

  /* Expand expression EXP, which is a call to the memset builtin.  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).  */

  static rtx
! expand_builtin_memset (exp, target, mode)
       tree exp;
+      rtx target;
+      enum machine_mode mode;
  {
    tree arglist = TREE_OPERAND (exp, 1);

*************** expand_builtin_memset (exp)
*** 2069,2074 ****
--- 2097,2110 ----
        if (dest_align == 0)
  	return 0;

+       /* If the LEN parameter is zero, return DEST.  */
+       if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
+         {
+           /* Evaluate and ignore VAL in case it has side-effects.  */
+           expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 	  return expand_expr (dest, target, mode, EXPAND_NORMAL);
+         }
+
        if (TREE_CODE (val) != INTEGER_CST)
  	return 0;

*************** expand_builtin_bzero (exp)
*** 2140,2146 ****
    newarglist = tree_cons (NULL_TREE, dest, newarglist);

    TREE_OPERAND (exp, 1) = newarglist;
!   result = expand_builtin_memset(exp);

    /* Always restore the original arguments.  */
    TREE_OPERAND (exp, 1) = arglist;
--- 2176,2182 ----
    newarglist = tree_cons (NULL_TREE, dest, newarglist);

    TREE_OPERAND (exp, 1) = newarglist;
!   result = expand_builtin_memset(exp, const0_rtx, VOIDmode);

    /* Always restore the original arguments.  */
    TREE_OPERAND (exp, 1) = arglist;
*************** expand_builtin (exp, target, subtarget,
*** 3617,3623 ****
        break;

      case BUILT_IN_STRCPY:
!       target = expand_builtin_strcpy (exp);
        if (target)
  	return target;
        break;
--- 3653,3659 ----
        break;

      case BUILT_IN_STRCPY:
!       target = expand_builtin_strcpy (exp, target, mode);
        if (target)
  	return target;
        break;
*************** expand_builtin (exp, target, subtarget,
*** 3679,3691 ****
        break;

      case BUILT_IN_MEMCPY:
!       target = expand_builtin_memcpy (arglist);
        if (target)
  	return target;
        break;

      case BUILT_IN_MEMSET:
!       target = expand_builtin_memset (exp);
        if (target)
  	return target;
        break;
--- 3715,3727 ----
        break;

      case BUILT_IN_MEMCPY:
!       target = expand_builtin_memcpy (arglist, target, mode);
        if (target)
  	return target;
        break;

      case BUILT_IN_MEMSET:
!       target = expand_builtin_memset (exp, target, mode);
        if (target)
  	return target;
        break;
*** /dev/null	Tue May  5 14:32:27 1998
--- string-opt-14.c	Fri Nov 23 16:39:47 2001
***************
*** 0 ****
--- 1,40 ----
+ /* Copyright (C) 2001  Free Software Foundation.
+
+    Ensure builtin memset and memcpy are optimized away correctly.
+
+    Written by Roger Sayle, 11/23/2001.  */
+
+ extern void abort (void);
+ typedef __SIZE_TYPE__ size_t;
+ extern void *memset (void *s, int c, size_t n);
+ extern void *memcpy (void *dest, const void *src, size_t n);
+
+ char dst[32];
+ char src[32];
+
+ int
+ main ()
+ {
+     memset (src, 0, 0);
+     memcpy (dst, src, 0);
+     return 0;
+ }
+
+ #ifdef __OPTIMIZE__
+ /* When optimizing, all the above cases should be transformed into
+    something else.  So any remaining calls to the original function
+    should abort.  */
+
+ static void *
+ memset (void *s, int c, size_t n)
+ {
+   abort ();
+ }
+
+ static void *
+ memcpy (void *dest, const void *src, size_t n)
+ {
+   abort ();
+ }
+ #endif
+

Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-438-3470


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]