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]

Patch to add bzero, bcmp and strncmp builtins


	I've written a patch to create new builtins for bzero, bcmp
and strncmp.  Bzero is written in terms of memset, and bcmp/strncmp
are written in terms of memcmp.  I tested it on i686-pc-linux-gnu and
found no bootstrap or testsuite problems after the i386.md bugfix
posted at http://gcc.gnu.org/ml/gcc-patches/2000-02/msg00744.html

By putting some diagnostics in it, I found that bootstrapping gcc gave
the following number of hits for these builtins:

 >  140 bzero
 >  114 strncmp
 >   20 bcmp

(I was surprised by how many strncmp hits there were given that in
order to execute the builtin, one of the string parameters and the
length parameter must be constants.)

Anyway, the only part I'm not satisfied with is the builtin prototypes
for the functions.  I currently do this (pseudo coded):

 > if (traditional)
 >   extern int strncmp (const char *, const char *, int);
 >   extern void bzero (char *, int);
 >   extern int bcmp (const char *, const char *, int);
 > else
 >   extern int strncmp (const char *, const char *, size_t);
 >   extern void bzero (void *, size_t);
 >   extern int bcmp (const void *, const void *, size_t);
 > endif

But I'm not sure this will work for all systems, in fact I'm pretty
sure it blathers warnings on alpha-osf4 even though I set
DECL_BUILT_IN_NONANSI on the b* functions.

Another solution would be to do the following always, regardless of
traditional/ansi setting:

 > extern int strncmp (const char *, const char *, size_t);
 > extern void bzero ();
 > extern int bcmp ();

but I don't think the blank arguments will work for C++ (which I can
live with.)  That'll conflict with the headers always, since in C++
blank arguments means "void" instead of "i'm not telling you".  But
then I might have to promote the length parameters to size_t myself?
Anyway, comments/suggestions WRT the prototypes welcome.

Okay to install?

		Thanks,
		--Kaveh

2000-02-21  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

	* builtins.c (expand_builtin_strncmp, expand_builtin_bzero): New
	functions.
	(expand_builtin): Handle builtin bzero, bcmp and strncmp.

	* c-common.c (c_common_nodes_and_builtins): Provide builtin
	prototypes/functions for bzero, bcmp and strncmp.

	* tree.h (built_in_function): Add BUILT_IN_BZERO, BUILT_IN_BCMP
	and BUILT_IN_STRNCMP.

diff -rup orig/egcs-CVS20000221/gcc/builtins.c egcs-CVS20000221/gcc/builtins.c
--- orig/egcs-CVS20000221/gcc/builtins.c	Tue Feb  1 16:23:37 2000
+++ egcs-CVS20000221/gcc/builtins.c	Mon Feb 21 12:23:25 2000
@@ -80,10 +80,12 @@ static rtx expand_builtin_va_copy	PARAMS
 #ifdef HAVE_cmpstrsi
 static rtx expand_builtin_memcmp	PARAMS ((tree, tree, rtx));
 static rtx expand_builtin_strcmp	PARAMS ((tree, rtx));
+static rtx expand_builtin_strncmp	PARAMS ((tree, rtx));
 #endif
 static rtx expand_builtin_memcpy	PARAMS ((tree));
 static rtx expand_builtin_strcpy	PARAMS ((tree));
 static rtx expand_builtin_memset	PARAMS ((tree));
+static rtx expand_builtin_bzero		PARAMS ((tree));
 static rtx expand_builtin_strlen	PARAMS ((tree, rtx, enum machine_mode));
 static rtx expand_builtin_alloca	PARAMS ((tree, rtx));
 static rtx expand_builtin_ffs		PARAMS ((tree, rtx, rtx));
@@ -1536,6 +1538,38 @@ expand_builtin_memset (exp)
     }
 }
 
+/* Expand expression EXP, which is a call to the bzero builtin.  Return 0
+   if we failed the caller should emit a normal call.  */
+static rtx
+expand_builtin_bzero (exp)
+     tree exp;
+{
+  tree arglist = TREE_OPERAND (exp, 1);
+
+  if (arglist == 0
+      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
+      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
+      || TREE_CHAIN (arglist) == 0
+      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
+	  != INTEGER_TYPE))
+    return 0;
+  else
+    {
+      tree val = build_tree_list (NULL_TREE, integer_zero_node);
+      rtx result;
+
+      /* Insert a zero parameter to convert bzero(x,y) -> memset(x,0,y).  */
+      TREE_CHAIN (val) = TREE_CHAIN (arglist);
+      TREE_CHAIN (arglist) = val;
+      result = expand_builtin_memset(exp);
+
+      /* If the above call fails, delete the zero parameter.  */
+      if (result == 0)
+	TREE_CHAIN (arglist) = TREE_CHAIN (TREE_CHAIN (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
@@ -1670,6 +1704,88 @@ expand_builtin_strcmp (exp, target)
     return result;
   }
 }
+
+/* Expand expression EXP, which is a call to the strncmp builtin.  Return 0
+   if we failed the caller should emit a normal call, otherwise try to get
+   the result in TARGET, if convenient.  */
+static rtx
+expand_builtin_strncmp (exp, target)
+     tree exp;
+     rtx target;
+{
+  tree arglist = TREE_OPERAND (exp, 1);
+
+  /* If we need to check memory accesses, call the library function.  */
+  if (current_function_check_memory_usage)
+    return 0;
+
+  if (arglist == 0
+      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
+      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
+      || TREE_CHAIN (arglist) == 0
+      || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
+      || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
+      || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
+    return 0;
+  else if (!HAVE_cmpstrsi)
+    return 0;
+  {
+    tree arg1 = TREE_VALUE (arglist);
+    tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
+    tree arg3 = TREE_CHAIN (TREE_CHAIN (arglist));
+    tree len, len2;
+    rtx result;
+    len = c_strlen (arg1);
+    if (len)
+      len = size_binop (PLUS_EXPR, integer_one_node, len);
+    len2 = c_strlen (arg2);
+    if (len2)
+      len2 = size_binop (PLUS_EXPR, integer_one_node, 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.
+
+       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)
+	  len = len2;
+	else if (len == 0)
+	  return 0;
+      }
+    else if (len2 && TREE_CODE (len2) == INTEGER_CST)
+      {
+	if (tree_int_cst_lt (len2, len))
+	  len = len2;
+      }
+
+    /* If the max length to check is not constant, punt.  */
+    if (!arg3 || TREE_CODE (TREE_VALUE (arg3)) != INTEGER_CST)
+      return 0;
+    
+    /* If arg3 is less than either string length, clamp at arg3.  */
+    if (tree_int_cst_lt (TREE_VALUE (arg3), len))
+      len = arg3;
+    else
+      len = build_tree_list (NULL_TREE, len);
+    
+    TREE_CHAIN (TREE_CHAIN (arglist)) = len;
+    TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))) = 0;
+
+    result = expand_builtin_memcmp (exp, arglist, target);
+
+    /* Restore original arg3 if builtin memcmp failed.  */
+    if (! result)
+      TREE_CHAIN (TREE_CHAIN (arglist)) = arg3;
+    return result;
+  }
+}
 #endif
 
 /* Expand a call to __builtin_saveregs, generating the result in TARGET,
@@ -2270,8 +2386,10 @@ expand_builtin (exp, target, subtarget, 
       && (fcode == BUILT_IN_SIN || fcode == BUILT_IN_COS
 	  || fcode == BUILT_IN_FSQRT || fcode == BUILT_IN_MEMSET
 	  || fcode == BUILT_IN_MEMCPY || fcode == BUILT_IN_MEMCMP
+	  || fcode == BUILT_IN_BZERO || fcode == BUILT_IN_BCMP
 	  || fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY
-	  || fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS))
+	  || fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_STRNCMP
+	  || fcode == BUILT_IN_FFS))
     return expand_call (exp, target, ignore);
 
   switch (fcode)
@@ -2407,6 +2525,12 @@ expand_builtin (exp, target, subtarget, 
 	return target;
       break;
 
+    case BUILT_IN_BZERO:
+      target = expand_builtin_bzero (exp);
+      if (target)
+	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.  */
@@ -2417,6 +2541,13 @@ expand_builtin (exp, target, subtarget, 
 	return target;
       break;
 
+    case BUILT_IN_STRNCMP:
+      target = expand_builtin_strncmp (exp, target);
+      if (target)
+	return target;
+      break;
+
+    case BUILT_IN_BCMP:
     case BUILT_IN_MEMCMP:
       target = expand_builtin_memcmp (exp, arglist, target);
       if (target)
@@ -2424,6 +2555,8 @@ expand_builtin (exp, target, subtarget, 
       break;
 #else
     case BUILT_IN_STRCMP:
+    case BUILT_IN_STRNCMP:
+    case BUILT_IN_BCMP:
     case BUILT_IN_MEMCMP:
       break;
 #endif
diff -rup orig/egcs-CVS20000221/gcc/c-common.c egcs-CVS20000221/gcc/c-common.c
--- orig/egcs-CVS20000221/gcc/c-common.c	Sun Feb 20 08:36:17 2000
+++ egcs-CVS20000221/gcc/c-common.c	Mon Feb 21 12:38:33 2000
@@ -3519,6 +3519,7 @@ c_common_nodes_and_builtins (cplus_mode,
 {
   tree temp;
   tree memcpy_ftype, memset_ftype, strlen_ftype;
+  tree bzero_ftype, bcmp_ftype, strncmp_ftype;
   tree endlink, int_endlink, double_endlink, unsigned_endlink;
   tree sizetype_endlink;
   tree ptr_ftype, ptr_ftype_unsigned;
@@ -3530,6 +3531,9 @@ c_common_nodes_and_builtins (cplus_mode,
   tree long_ftype_long;
   /* Either char* or void*.  */
   tree traditional_ptr_type_node;
+  tree traditional_cptr_type_node;
+  tree traditional_len_type_node;
+  tree traditional_len_endlink;
   tree va_list_ptr_type_node;
   tree va_list_arg_type_node;
 
@@ -3616,15 +3620,29 @@ c_common_nodes_and_builtins (cplus_mode,
 						 const_string_type_node,
 						 endlink)));
 
+  traditional_len_type_node = (flag_traditional && ! cplus_mode
+			       ? integer_type_node : sizetype);
+  traditional_len_endlink = tree_cons (NULL_TREE, traditional_len_type_node,
+				       endlink);
+
+  /* Prototype for strncmp.  */
+  strncmp_ftype
+    = build_function_type (integer_type_node,
+			   tree_cons (NULL_TREE, const_string_type_node,
+				      tree_cons (NULL_TREE,
+						 const_string_type_node,
+						 traditional_len_endlink)));
+
   /* Prototype for strlen.  */
   strlen_ftype
-    = build_function_type ((flag_traditional && ! cplus_mode
-			    ? integer_type_node : sizetype),
+    = build_function_type (traditional_len_type_node,
 			   tree_cons (NULL_TREE, const_string_type_node,
 				      endlink));
 
   traditional_ptr_type_node = (flag_traditional && ! cplus_mode
 			       ? string_type_node : ptr_type_node);
+  traditional_cptr_type_node = (flag_traditional && ! cplus_mode
+			       ? const_string_type_node : const_ptr_type_node);
 
   /* Prototype for memcpy.  */
   memcpy_ftype
@@ -3642,6 +3660,20 @@ c_common_nodes_and_builtins (cplus_mode,
 							    sizetype,
 							    endlink))));
 
+  /* Prototype for bzero.  */
+  bzero_ftype
+    = build_function_type (void_type_node,
+			   tree_cons (NULL_TREE, traditional_ptr_type_node,
+				      traditional_len_endlink));
+
+  /* Prototype for bcmp.  */
+  bcmp_ftype
+    = build_function_type (integer_type_node,
+			   tree_cons (NULL_TREE, traditional_cptr_type_node,
+				      tree_cons (NULL_TREE,
+						 traditional_cptr_type_node,
+						 traditional_len_endlink)));
+
   builtin_function ("__builtin_constant_p", default_function_type,
 		    BUILT_IN_CONSTANT_P, BUILT_IN_NORMAL, NULL_PTR);
 
@@ -3655,6 +3687,10 @@ c_common_nodes_and_builtins (cplus_mode,
 		    BUILT_IN_ALLOCA, BUILT_IN_NORMAL, "alloca");
   builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS,
 		    BUILT_IN_NORMAL, NULL_PTR);
+  builtin_function ("__builtin_bzero", bzero_ftype, BUILT_IN_BZERO,
+		    BUILT_IN_NORMAL, "bzero");
+  builtin_function ("__builtin_bcmp", bcmp_ftype, BUILT_IN_BCMP,
+		    BUILT_IN_NORMAL, "bcmp");
   /* Define alloca, ffs as builtins.
      Declare _exit just to mark it as volatile.  */
   if (! no_builtins && ! no_nonansi_builtins)
@@ -3675,6 +3711,13 @@ c_common_nodes_and_builtins (cplus_mode,
       TREE_SIDE_EFFECTS (temp) = 1;
       /* Suppress error if redefined as a non-function.  */
       DECL_BUILT_IN_NONANSI (temp) = 1;
+
+      temp = builtin_function ("bzero", bzero_ftype, BUILT_IN_BZERO,
+			       BUILT_IN_NORMAL, NULL_PTR);
+      DECL_BUILT_IN_NONANSI (temp) = 1;
+      temp = builtin_function ("bcmp", bcmp_ftype, BUILT_IN_BCMP,
+			       BUILT_IN_NORMAL, NULL_PTR);
+      DECL_BUILT_IN_NONANSI (temp) = 1;
     }
 
   builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS,
@@ -3782,6 +3825,8 @@ c_common_nodes_and_builtins (cplus_mode,
 		    BUILT_IN_NORMAL, "memset");
   builtin_function ("__builtin_strcmp", int_ftype_string_string,
 		    BUILT_IN_STRCMP, BUILT_IN_NORMAL, "strcmp");
+  builtin_function ("__builtin_strncmp", strncmp_ftype,
+		    BUILT_IN_STRNCMP, BUILT_IN_NORMAL, "strncmp");
   builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
 		    BUILT_IN_STRCPY, BUILT_IN_NORMAL, "strcpy");
   builtin_function ("__builtin_strlen", strlen_ftype,
@@ -3824,6 +3869,8 @@ c_common_nodes_and_builtins (cplus_mode,
       builtin_function ("memset", memset_ftype, BUILT_IN_MEMSET,
 			BUILT_IN_NORMAL, NULL_PTR);
       builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP,
+			BUILT_IN_NORMAL, NULL_PTR);
+      builtin_function ("strncmp", strncmp_ftype, BUILT_IN_STRNCMP,
 			BUILT_IN_NORMAL, NULL_PTR);
       builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
 			BUILT_IN_NORMAL, NULL_PTR);
diff -rup orig/egcs-CVS20000221/gcc/tree.h egcs-CVS20000221/gcc/tree.h
--- orig/egcs-CVS20000221/gcc/tree.h	Sun Feb 20 08:36:28 2000
+++ egcs-CVS20000221/gcc/tree.h	Mon Feb 21 11:17:30 2000
@@ -95,8 +95,11 @@ enum built_in_function
   BUILT_IN_MEMCPY,
   BUILT_IN_MEMCMP,
   BUILT_IN_MEMSET,
+  BUILT_IN_BZERO,
+  BUILT_IN_BCMP,
   BUILT_IN_STRCPY,
   BUILT_IN_STRCMP,
+  BUILT_IN_STRNCMP,
   BUILT_IN_STRLEN,
   BUILT_IN_FSQRT,
   BUILT_IN_SIN,

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