This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch to add bzero, bcmp and strncmp builtins
- To: egcs-patches at egcs dot cygnus dot com
- Subject: Patch to add bzero, bcmp and strncmp builtins
- From: "Kaveh R. Ghazi" <ghazi at caip dot rutgers dot edu>
- Date: Wed, 23 Feb 2000 21:49:07 -0500 (EST)
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,