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]: Update patches for memset and memcmp builtins




Following Richard Kenner's patch to remove memory usage checking,
I'm resubmitting my two unreviewed patches to builtins.c against
the current mainline.  Hopefully this should make them easier to
review.

Specifically, this patch revises the following patches:

Optimize builtin memset with length zero.
http://gcc.gnu.org/ml/gcc-patches/2001-11/msg01599.html

Optimize memcmp builtin for length zero or one.
http://gcc.gnu.org/ml/gcc-patches/2001-12/msg00295.html


For details, please refer to the above postings.  This patch has
been bootstraped and checked on i686-pc-linux-gnu with no new
regressions.



2001-12-09  Roger Sayle <roger@eyesopen.com>
	* builtins.c (expand_builtin_memset, expand_builtin_memcpy,
	expand_builtin_strcpy): Additional arguments TARGET and MODE.
	(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.
	(expand_builtin_memcmp): No longer conditional on
	HAVE_cmpstrsi.  Take an additional mode parameter.  Optimize
	the cases where len is either constant zero or one.
	Optimize to call to memcpy, even if the memcpy isn't inlined.
	(expand_builtin_strncpy): Optimize to call memcpy, even if the
	memcpy isn't inlined.
	(expand_builtin_strcmp, expand_builtin_strncmp): Always attempt
	to optimize to a call to memcmp.
	(expand_builtin): expand_builtin_memcmp can always be called,
	and pass the required parameters to expand_builtin_memcmp,
        expand_builtin_memset, expand_builtin_memcpy and
        expand_builtin_strcpy.
	* gcc.c-torture/execute/string-opt-14.c: New test case.
	* gcc.c-torture/execute/string-opt-15.c: New test case.


*** gcc/gcc/builtins.c	Sun Dec  9 11:26:56 2001
--- patch8/gcc/builtins.c	Sun Dec  9 14:42:30 2001
*************** static rtx expand_builtin_next_arg	PARAM
*** 101,109 ****
  static rtx expand_builtin_va_start	PARAMS ((int, tree));
  static rtx expand_builtin_va_end	PARAMS ((tree));
  static rtx expand_builtin_va_copy	PARAMS ((tree));
! #ifdef HAVE_cmpstrsi
! static rtx expand_builtin_memcmp	PARAMS ((tree, tree, rtx));
! #endif
  static rtx expand_builtin_strcmp	PARAMS ((tree, rtx,
  						 enum machine_mode));
  static rtx expand_builtin_strncmp	PARAMS ((tree, rtx,
--- 101,108 ----
  static rtx expand_builtin_va_start	PARAMS ((int, tree));
  static rtx expand_builtin_va_end	PARAMS ((tree));
  static rtx expand_builtin_va_copy	PARAMS ((tree));
! static rtx expand_builtin_memcmp	PARAMS ((tree, tree, rtx,
!                                                  enum machine_mode));
  static rtx expand_builtin_strcmp	PARAMS ((tree, rtx,
  						 enum machine_mode));
  static rtx expand_builtin_strncmp	PARAMS ((tree, rtx,
*************** static rtx expand_builtin_strspn	PARAMS
*** 118,132 ****
  						 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
*** 1910,1920 ****
    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))
--- 1912,1927 ----
    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)
*** 1931,1940 ****
  	= 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);
--- 1938,1959 ----
  	= 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)
*** 1970,2002 ****
  }

  /* 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;

    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;
-   else
-     {
-       tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
-
-       if (len == 0)
- 	return 0;

!       len = size_binop (PLUS_EXPR, len, ssize_int (1));
!       chainon (arglist, build_tree_list (NULL_TREE, len));
!     }

!   result = expand_builtin_memcpy (arglist);

!   if (! result)
!     TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
!   return result;
  }

  /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
--- 1989,2022 ----
  }

  /* 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);
!   tree fn, len;

    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;

!   fn = built_in_decls[BUILT_IN_MEMCPY];
!   if (!fn)
!     return 0;

!   len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
!   if (len == 0)
!     return 0;

!   len = size_binop (PLUS_EXPR, len, ssize_int (1));
!   chainon (arglist, build_tree_list (NULL_TREE, len));
!   return expand_expr (build_function_call_expr (fn, arglist),
!                       target, mode, EXPAND_NORMAL);
  }

  /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
*************** expand_builtin_strncpy (arglist, target,
*** 2033,2038 ****
--- 2053,2059 ----
      {
        tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
        tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+       tree fn;

        /* We must be passed a constant len parameter.  */
        if (TREE_CODE (len) != INTEGER_CST)
*************** expand_builtin_strncpy (arglist, target,
*** 2081,2087 ****
  	}

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

--- 2102,2112 ----
  	}

        /* OK transform into builtin memcpy.  */
!       fn = built_in_decls[BUILT_IN_MEMCPY];
!       if (!fn)
!         return 0;
!       return expand_expr (build_function_call_expr (fn, arglist),
!                           target, mode, EXPAND_NORMAL);
      }
  }

*************** builtin_memset_read_str (data, offset, m
*** 2104,2114 ****
  }

  /* 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);

--- 2129,2143 ----
  }

  /* 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)
*** 2131,2136 ****
--- 2160,2174 ----
        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)
*** 2184,2226 ****
    size = TREE_VALUE (TREE_CHAIN (arglist));

    /* New argument list transforming bzero(ptr x, int y) to
!      memset(ptr x, int 0, size_t y).  */
!
    newarglist = build_tree_list (NULL_TREE, convert (sizetype, size));
    newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
    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;

    return result;
  }

- #ifdef HAVE_cmpstrsi
-
  /* Expand expression EXP, which is a call to the memcmp or the strcmp builtin.
     ARGLIST is the argument list for this call.  Return 0 if we failed and the
     caller should emit a normal call, otherwise try to get the result in
!    TARGET, if convenient.  */

  static rtx
! expand_builtin_memcmp (exp, arglist, target)
       tree exp;
       tree arglist;
       rtx target;
  {
    if (!validate_arglist (arglist,
  		      POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return 0;

    {
-     enum machine_mode mode;
-     tree arg1 = TREE_VALUE (arglist);
-     tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
-     tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
      rtx arg1_rtx, arg2_rtx, arg3_rtx;
      rtx result;
      rtx insn;
--- 2222,2296 ----
    size = TREE_VALUE (TREE_CHAIN (arglist));

    /* New argument list transforming bzero(ptr x, int y) to
!      memset(ptr x, int 0, size_t y).   This is done this way
!      so that if it isn't expanded inline, we fallback to
!      calling bzero instead of memset.  */
!
    newarglist = build_tree_list (NULL_TREE, convert (sizetype, size));
    newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
    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;

    return result;
  }

  /* Expand expression EXP, which is a call to the memcmp or the strcmp builtin.
     ARGLIST is the argument list for this call.  Return 0 if we failed and 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_memcmp (exp, arglist, target, mode)
       tree exp;
       tree arglist;
       rtx target;
+      enum machine_mode mode;
  {
+   tree arg1, arg2, len;
+
    if (!validate_arglist (arglist,
  		      POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return 0;

+   arg1 = TREE_VALUE (arglist);
+   arg2 = TREE_VALUE (TREE_CHAIN (arglist));
+   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+   /* If the len parameter is zero, return zero.  */
+   if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
+     {
+       /* Evaluate and ignore arg1 and arg2 in case they have
+          side-effects.  */
+       expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
+       expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
+       return const0_rtx;
+     }
+
+   /* If len parameter is one, return an expression corresponding to
+      (*(const unsigned char*)arg1 - (const unsigned char*)arg2).  */
+   if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
+     {
+       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
+       tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+       tree ind1 =
+       fold (build1 (CONVERT_EXPR, integer_type_node,
+                     build1 (INDIRECT_REF, cst_uchar_node,
+                             build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
+       tree ind2 =
+       fold (build1 (CONVERT_EXPR, integer_type_node,
+                     build1 (INDIRECT_REF, cst_uchar_node,
+                             build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
+       tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
+       return expand_expr (result, target, mode, EXPAND_NORMAL);
+     }
+
+ #ifdef HAVE_cmpstrsi
    {
      rtx arg1_rtx, arg2_rtx, arg3_rtx;
      rtx result;
      rtx insn;
*************** expand_builtin_memcmp (exp, arglist, tar
*** 2275,2282 ****
      else
        return convert_to_mode (mode, result, 0);
    }
! }
  #endif

  /* Expand expression EXP, which is a call to the strcmp builtin.  Return 0
     if we failed the caller should emit a normal call, otherwise try to get
--- 2345,2354 ----
      else
        return convert_to_mode (mode, result, 0);
    }
! #else
!   return 0;
  #endif
+ }

  /* Expand expression EXP, which is a call to the strcmp builtin.  Return 0
     if we failed the caller should emit a normal call, otherwise try to get
*************** expand_builtin_strcmp (exp, target, mode
*** 2289,2295 ****
       enum machine_mode mode;
  {
    tree arglist = TREE_OPERAND (exp, 1);
!   tree arg1, arg2;
    const char *p1, *p2;

    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
--- 2361,2367 ----
       enum machine_mode mode;
  {
    tree arglist = TREE_OPERAND (exp, 1);
!   tree arg1, arg2, len, len2, fn;
    const char *p1, *p2;

    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
*************** expand_builtin_strcmp (exp, target, mode
*** 2325,2382 ****
        return expand_expr (result, target, mode, EXPAND_NORMAL);
      }

! #ifdef HAVE_cmpstrsi
!   if (! HAVE_cmpstrsi)
!     return 0;

!   {
!     tree len = c_strlen (arg1);
!     tree len2 = c_strlen (arg2);
!     rtx result;

!     if (len)
!       len = size_binop (PLUS_EXPR, ssize_int (1), len);

!     if (len2)
!       len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);

!     /* If we don't have a constant length for the first, use the length
!        of the second, if we know it.  We don't require a constant for
!        this case; some cost analysis could be done if both are available
!        but neither is constant.  For now, assume they're equally cheap
!        unless one has side effects.
!
!        If both strings have constant lengths, use the smaller.  This
!        could arise if optimization results in strcpy being called with
!        two fixed strings, or if the code was machine-generated.  We should
!        add some code to the `memcmp' handler below to deal with such
!        situations, someday.  */

!     if (!len || TREE_CODE (len) != INTEGER_CST)
!       {
! 	if (len2 && !TREE_SIDE_EFFECTS (len2))
! 	  len = len2;
! 	else if (len == 0)
! 	  return 0;
!       }
!     else if (len2 && TREE_CODE (len2) == INTEGER_CST
! 	     && tree_int_cst_lt (len2, len))
!       len = len2;

!     /* If both arguments have side effects, we cannot optimize.  */
!     if (TREE_SIDE_EFFECTS (len))
!       return 0;

!     chainon (arglist, build_tree_list (NULL_TREE, len));
!     result = expand_builtin_memcmp (exp, arglist, target);
!     if (! result)
!       TREE_CHAIN (TREE_CHAIN (arglist)) = 0;

!     return result;
!   }
! #else
!   return 0;
! #endif
  }

  /* Expand expression EXP, which is a call to the strncmp builtin.  Return 0
--- 2397,2445 ----
        return expand_expr (result, target, mode, EXPAND_NORMAL);
      }

!   len = c_strlen (arg1);
!   len2 = c_strlen (arg2);

!   if (len)
!     len = size_binop (PLUS_EXPR, ssize_int (1), len);

!   if (len2)
!     len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);

!   /* If we don't have a constant length for the first, use the length
!      of the second, if we know it.  We don't require a constant for
!      this case; some cost analysis could be done if both are available
!      but neither is constant.  For now, assume they're equally cheap
!      unless one has side effects.

!      If both strings have constant lengths, use the smaller.  This
!      could arise if optimization results in strcpy being called with
!      two fixed strings, or if the code was machine-generated.  We should
!      add some code to the `memcmp' handler below to deal with such
!      situations, someday.  */

!   if (!len || TREE_CODE (len) != INTEGER_CST)
!     {
!       if (len2 && !TREE_SIDE_EFFECTS (len2))
!         len = len2;
!       else if (len == 0)
!         return 0;
!     }
!   else if (len2 && TREE_CODE (len2) == INTEGER_CST
!            && tree_int_cst_lt (len2, len))
!     len = len2;

!   /* If both arguments have side effects, we cannot optimize.  */
!   if (TREE_SIDE_EFFECTS (len))
!     return 0;

!   fn = built_in_decls[BUILT_IN_MEMCMP];
!   if (!fn)
!     return 0;

!   chainon (arglist, build_tree_list (NULL_TREE, len));
!   return expand_expr (build_function_call_expr (fn, arglist),
!                       target, mode, EXPAND_NORMAL);
  }

  /* Expand expression EXP, which is a call to the strncmp builtin.  Return 0
*************** expand_builtin_strncmp (exp, target, mod
*** 2390,2395 ****
--- 2453,2459 ----
       enum machine_mode mode;
  {
    tree arglist = TREE_OPERAND (exp, 1);
+   tree fn, newarglist, len = 0;
    tree arg1, arg2, arg3;
    const char *p1, *p2;

*************** expand_builtin_strncmp (exp, target, mod
*** 2442,2486 ****
        return expand_expr (result, target, mode, EXPAND_NORMAL);
      }

- #ifdef HAVE_cmpstrsi
    /* If c_strlen can determine an expression for one of the string
       lengths, and it doesn't have side effects, then call
       expand_builtin_memcmp() using length MIN(strlen(string)+1, arg3).  */
!   if (HAVE_cmpstrsi)
!     {
!       tree newarglist, len = 0;
!
!       /* Perhaps one of the strings is really constant, if so prefer
!          that constant length over the other string's length.  */
!       if (p1)
! 	len = c_strlen (arg1);
!       else if (p2)
! 	len = c_strlen (arg2);
!
!       /* If we still don't have a len, try either string arg as long
! 	 as they don't have side effects.  */
!       if (!len && !TREE_SIDE_EFFECTS (arg1))
! 	len = c_strlen (arg1);
!       if (!len && !TREE_SIDE_EFFECTS (arg2))
! 	len = c_strlen (arg2);
!       /* If we still don't have a length, punt.  */
!       if (!len)
! 	return 0;
!
!       /* Add one to the string length.  */
!       len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));

!       /* The actual new length parameter is MIN(len,arg3).  */
!       len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));

!       newarglist = build_tree_list (NULL_TREE, len);
!       newarglist = tree_cons (NULL_TREE, arg2, newarglist);
!       newarglist = tree_cons (NULL_TREE, arg1, newarglist);
!       return expand_builtin_memcmp (exp, newarglist, target);
!     }
! #endif
!
!   return 0;
  }

  /* Expand expression EXP, which is a call to the strcat builtin.
--- 2506,2547 ----
        return expand_expr (result, target, mode, EXPAND_NORMAL);
      }

    /* If c_strlen can determine an expression for one of the string
       lengths, and it doesn't have side effects, then call
       expand_builtin_memcmp() using length MIN(strlen(string)+1, arg3).  */
!
!   /* Perhaps one of the strings is really constant, if so prefer
!      that constant length over the other string's length.  */
!   if (p1)
!     len = c_strlen (arg1);
!   else if (p2)
!     len = c_strlen (arg2);
!
!   /* If we still don't have a len, try either string arg as long
!      as they don't have side effects.  */
!   if (!len && !TREE_SIDE_EFFECTS (arg1))
!     len = c_strlen (arg1);
!   if (!len && !TREE_SIDE_EFFECTS (arg2))
!     len = c_strlen (arg2);
!   /* If we still don't have a length, punt.  */
!   if (!len)
!     return 0;
!
!   fn = built_in_decls[BUILT_IN_MEMCMP];
!   if (!fn)
!     return 0;
!
!   /* Add one to the string length.  */
!   len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));

!   /* The actual new length parameter is MIN(len,arg3).  */
!   len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));

!   newarglist = build_tree_list (NULL_TREE, len);
!   newarglist = tree_cons (NULL_TREE, arg2, newarglist);
!   newarglist = tree_cons (NULL_TREE, arg1, newarglist);
!   return expand_expr (build_function_call_expr (fn, newarglist),
!                       target, mode, EXPAND_NORMAL);
  }

  /* Expand expression EXP, which is a call to the strcat builtin.
*************** expand_builtin (exp, target, subtarget,
*** 3639,3645 ****
        break;

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

      case BUILT_IN_STRCPY:
!       target = expand_builtin_strcpy (exp, target, mode);
        if (target)
  	return target;
        break;
*************** expand_builtin (exp, target, subtarget,
*** 3701,3713 ****
        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;
--- 3762,3774 ----
        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;
*************** expand_builtin (exp, target, subtarget,
*** 3730,3750 ****
  	return target;
        break;

- /* These comparison functions need an instruction that returns an actual
-    index.  An ordinary compare that just sets the condition codes
-    is not enough.  */
- #ifdef HAVE_cmpstrsi
      case BUILT_IN_BCMP:
      case BUILT_IN_MEMCMP:
!       target = expand_builtin_memcmp (exp, arglist, target);
        if (target)
  	return target;
        break;
- #else
-     case BUILT_IN_BCMP:
-     case BUILT_IN_MEMCMP:
-       break;
- #endif

      case BUILT_IN_SETJMP:
        target = expand_builtin_setjmp (arglist, target);
--- 3791,3802 ----
  	return target;
        break;

      case BUILT_IN_BCMP:
      case BUILT_IN_MEMCMP:
!       target = expand_builtin_memcmp (exp, arglist, target, mode);
        if (target)
  	return target;
        break;

      case BUILT_IN_SETJMP:
        target = expand_builtin_setjmp (arglist, target);
*** /dev/null	Tue May  5 14:32:27 1998
--- string-opt-14.c	Sun Dec  9 13:42:54 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
+
*** /dev/null	Tue May  5 14:32:27 1998
--- string-opt-15.c	Mon Dec  3 14:21:38 2001
***************
*** 0 ****
--- 1,46 ----
+ /* Copyright (C) 2001  Free Software Foundation.
+
+    Ensure that short builtin memcmp are optimized and perform correctly.
+    On architectures with a cmpstrsi instruction, this test doesn't determine
+    which optimization is being performed, but it does check for correctness.
+
+    Written by Roger Sayle, 12/02/2001.  */
+
+ extern void abort (void);
+ typedef __SIZE_TYPE__ size_t;
+ extern int memcmp (const void *, const void *, size_t);
+ extern char *strcpy (char *, const char *);
+
+ int
+ main ()
+ {
+   char str[8];
+
+   strcpy (str, "3141");
+
+   if ( memcmp (str, str+2, 0) != 0 )
+     abort ();
+   if ( memcmp (str+1, str+3, 0) != 0 )
+     abort ();
+
+   if ( memcmp (str+1, str+3, 1) != 0 )
+     abort ();
+   if ( memcmp (str, str+2, 1) >= 0 )
+     abort ();
+   if ( memcmp (str+2, str, 1) <= 0 )
+     abort ();
+
+   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 int
+ memcmp (const char *p1, const char *p2, size_t len)
+ {
+   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]