This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch to create builtin strncmp
- To: egcs-patches at egcs dot cygnus dot com
- Subject: Patch to create builtin strncmp
- From: "Kaveh R. Ghazi" <ghazi at caip dot rutgers dot edu>
- Date: Wed, 22 Mar 2000 11:32:28 -0500 (EST)
This patch creates a new builtin strncmp. It operates
similarly to the strcmp builtin except that it also clamps on the
third arg (which must be a constant.) This patch depends on
http://gcc.gnu.org/ml/gcc-patches/2000-03/msg00745.html
Bootstrapped on i686-pc-linux-gnu and sparc-sun-solaris2.7, no regressions.
Okay to install?
--Kaveh
2000-03-21 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* builtins.c (expand_builtin_strncmp): New function.
(expand_builtin): Handle strncmp.
* builtins.def: Add BUILT_IN_STRNCMP.
* c-common.c (c_common_nodes_and_builtins): Provide builtin
prototype & function for strncmp.
diff -rup orig/egcs-CVS20000321/gcc/builtins.c egcs-CVS20000321/gcc/builtins.c
--- orig/egcs-CVS20000321/gcc/builtins.c Tue Mar 21 21:51:05 2000
+++ egcs-CVS20000321/gcc/builtins.c Tue Mar 21 22:10:54 2000
@@ -92,6 +92,7 @@ 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));
@@ -1712,6 +1713,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, ssize_int(1), len);
+ len2 = c_strlen (arg2);
+ 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.
+
+ 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,
@@ -2314,7 +2397,8 @@ expand_builtin (exp, target, subtarget,
|| fcode == BUILT_IN_FSQRT || fcode == BUILT_IN_MEMSET
|| fcode == BUILT_IN_MEMCPY || fcode == BUILT_IN_MEMCMP
|| 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)
@@ -2460,6 +2544,12 @@ 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_MEMCMP:
target = expand_builtin_memcmp (exp, arglist, target);
if (target)
@@ -2467,6 +2557,7 @@ expand_builtin (exp, target, subtarget,
break;
#else
case BUILT_IN_STRCMP:
+ case BUILT_IN_STRNCMP:
case BUILT_IN_MEMCMP:
break;
#endif
diff -rup orig/egcs-CVS20000321/gcc/builtins.def egcs-CVS20000321/gcc/builtins.def
--- orig/egcs-CVS20000321/gcc/builtins.def Tue Mar 21 21:51:05 2000
+++ egcs-CVS20000321/gcc/builtins.def Tue Mar 21 21:52:04 2000
@@ -35,6 +35,7 @@ DEF_BUILTIN(BUILT_IN_MEMCMP)
DEF_BUILTIN(BUILT_IN_MEMSET)
DEF_BUILTIN(BUILT_IN_STRCPY)
DEF_BUILTIN(BUILT_IN_STRCMP)
+DEF_BUILTIN(BUILT_IN_STRNCMP)
DEF_BUILTIN(BUILT_IN_STRLEN)
DEF_BUILTIN(BUILT_IN_FSQRT)
DEF_BUILTIN(BUILT_IN_SIN)
diff -rup orig/egcs-CVS20000321/gcc/c-common.c egcs-CVS20000321/gcc/c-common.c
--- orig/egcs-CVS20000321/gcc/c-common.c Tue Mar 21 16:21:35 2000
+++ egcs-CVS20000321/gcc/c-common.c Tue Mar 21 22:00:31 2000
@@ -3464,6 +3464,7 @@ c_common_nodes_and_builtins (cplus_mode,
{
tree temp;
tree memcpy_ftype, memset_ftype, strlen_ftype;
+ tree strncmp_ftype;
tree endlink, int_endlink, double_endlink, unsigned_endlink;
tree sizetype_endlink;
tree ptr_ftype, ptr_ftype_unsigned;
@@ -3475,6 +3476,8 @@ c_common_nodes_and_builtins (cplus_mode,
tree long_ftype_long;
/* Either char* or void*. */
tree traditional_ptr_type_node;
+ tree traditional_len_type_node;
+ tree traditional_len_endlink;
tree va_list_ptr_type_node;
tree va_list_arg_type_node;
@@ -3561,10 +3564,22 @@ 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));
@@ -3727,6 +3742,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,
@@ -3769,6 +3786,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);