Patch to add transformations to builtin strcmp/strncmp
Kaveh R. Ghazi
ghazi@caip.rutgers.edu
Fri Dec 1 13:16:00 GMT 2000
This patch adds some more transformations to builtin strcmp/strncmp:
strcmp (s1, s2) -> *(const unsigned char*)s1 - *(const unsigned char*)s2)
(when one of s1 or s2 is "")
(I fold() the expression so *s1-'\0' or '\0'-*s2 should get reduced.)
strncmp (s1, s2, n) -> *(const unsigned char*)s1 - *(const unsigned char*)s2)
(when n == 1, or (s1 or s2 is "") and n >= 1)
(I fold() the expression so further reduction occurs.)
strncmp (s1, "string", n) -> expand_builtin_memcmp()
strncmp ("string", s2, n) -> expand_builtin_memcmp()
(when n is constant. Use a length parameter of MIN(n, strlen("string")+1))
(This only happens if HAVE_cmpstrsi is true.)
It also changes expand_builtin_strcmp to use const*_rtx instead of
expanding trees when calculating the result at compile-time.
Tested with "make all" and compiling at -O0/-O2 the affected testcases
on i686-pc-linux-gnu (HAVE_cmpstrsi) and sparc-sun-solaris2.7
(!HAVE_cmpstrsi). Assuming full bootstrap on solaris completes, okay
to install?
Thanks,
--Kaveh
2000-12-01 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* builtins.c (expand_builtin_strcmp): Use const*_rtx when
expanding strcmp at compile-time. Add another transformation.
(expand_builtin_strncmp): Add more transformations. Call
expand_builtin_memcmp, not expand_builtin_strcmp, under
appropriate conditions if HAVE_cmpstrsi.
testsuite:
gcc.c-torture/execute/string-opt-3.c: Add more strcmp checks.
gcc.c-torture/execute/string-opt-8.c: Add more strncmp checks.
diff -rup orig/egcs-CVS20001201/gcc/builtins.c egcs-CVS20001201/gcc/builtins.c
--- orig/egcs-CVS20001201/gcc/builtins.c Wed Nov 29 16:26:31 2000
+++ egcs-CVS20001201/gcc/builtins.c Fri Dec 1 15:47:25 2000
@@ -2169,14 +2169,22 @@ expand_builtin_strcmp (exp, target, mode
if (p1 && p2)
{
- int i = strcmp (p1, p2);
-
- return expand_expr (i < 0 ? build_int_2 (-1, -1)
- : i == 0 ? integer_zero_node
- : integer_one_node,
- target, mode, EXPAND_NORMAL);
+ const int i = strcmp (p1, p2);
+ return (i < 0 ? constm1_rtx : (i > 0 ? const1_rtx : const0_rtx));
}
+ /* If either arg is "", return an expression corresponding to
+ (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */
+ if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
+ {
+ tree const_uchar_type_node =
+ build_type_variant (unsigned_char_type_node, 1, 0);
+ tree ind1 = build1 (INDIRECT_REF, const_uchar_type_node, arg1);
+ tree ind2 = build1 (INDIRECT_REF, const_uchar_type_node, arg2);
+ tree result = build (MINUS_EXPR, integer_type_node, ind1, ind2);
+ return expand_expr (fold (result), target, mode, EXPAND_NORMAL);
+ }
+
#ifdef HAVE_cmpstrsi
if (! HAVE_cmpstrsi)
return 0;
@@ -2285,25 +2293,45 @@ expand_builtin_strncmp (exp, target, mod
return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
}
- /* If either string parameter is constant and its strlen is strictly
- less than the length parameter, call expand_builtin_strcmp(). */
- if ((p1 && compare_tree_int (arg3, strlen (p1)) > 0)
- || (p2 && compare_tree_int (arg3, strlen (p2)) > 0))
- {
- tree newarglist =
- tree_cons (NULL_TREE, arg1, build_tree_list (NULL_TREE, arg2));
- rtx result;
+ /* If len == 1 or (either string parameter is "" and (len >= 1)),
+ return (*(u_char*)arg1 - *(u_char*)arg2). */
+ if (compare_tree_int (arg3, 1) == 0
+ || (compare_tree_int (arg3, 1) > 0
+ && ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))))
+ {
+ tree const_uchar_type_node =
+ build_type_variant (unsigned_char_type_node, 1, 0);
+ tree ind1 = build1 (INDIRECT_REF, const_uchar_type_node, arg1);
+ tree ind2 = build1 (INDIRECT_REF, const_uchar_type_node, arg2);
+ tree result = build (MINUS_EXPR, integer_type_node, ind1, ind2);
+ return expand_expr (fold (result), target, mode, EXPAND_NORMAL);
+ }
- /* Call expand_builtin_strcmp with the modified newarglist. If
- the expansion does not occur, do not allow strncmp to expand to
- strcmp since strcmp requires that both strings be NULL
- terminated whereas strncmp does not. */
- TREE_OPERAND (exp, 1) = newarglist;
- result = expand_builtin_strcmp (exp, target, mode);
- /* Always restore the original arguments. */
- TREE_OPERAND (exp, 1) = arglist;
- return result;
- }
+#ifdef HAVE_cmpstrsi
+ /* If the length parameter is constant (checked above) and either
+ string parameter is constant, call expand_builtin_memcmp() using
+ a length parameter equal to the lesser of the given length and
+ the strlen+1 of the constant string. */
+ if (HAVE_cmpstrsi && (p1 || p2))
+ {
+ /* Exactly one of the strings is constant at this point, because
+ if both were then we'd have expanded this at compile-time. */
+ tree string_len = p1 ? c_strlen (arg1) : c_strlen (arg2);
+
+ string_len = size_binop (PLUS_EXPR, string_len, ssize_int (1));
+
+ if (tree_int_cst_lt (string_len, arg3))
+ {
+ /* The strlen+1 is strictly shorter, use it. */
+ tree newarglist = build_tree_list (NULL_TREE, string_len);
+ newarglist = tree_cons (NULL_TREE, arg2, newarglist);
+ newarglist = tree_cons (NULL_TREE, arg1, newarglist);
+ return expand_builtin_memcmp (exp, newarglist, target);
+ }
+ else
+ return expand_builtin_memcmp (exp, arglist, target);
+ }
+#endif
return 0;
}
diff -rup orig/egcs-CVS20001201/gcc/testsuite/gcc.c-torture/execute/string-opt-3.c egcs-CVS20001201/gcc/testsuite/gcc.c-torture/execute/string-opt-3.c
--- orig/egcs-CVS20001201/gcc/testsuite/gcc.c-torture/execute/string-opt-3.c Sun Nov 12 21:08:03 2000
+++ egcs-CVS20001201/gcc/testsuite/gcc.c-torture/execute/string-opt-3.c Fri Dec 1 14:44:46 2000
@@ -37,6 +37,18 @@ int main()
abort ();
if (strcmp (10 + foo, "dx") >= 0)
abort ();
+ if (strcmp (bar, "") <= 0)
+ abort ();
+ if (strcmp ("", bar) >= 0)
+ abort ();
+ if (strcmp (bar+8, "") != 0)
+ abort ();
+ if (strcmp ("", bar+8) != 0)
+ abort ();
+ if (strcmp (bar+(--x), "") <= 0 || x != 6)
+ abort ();
+ if (strcmp ("", bar+(++x)) >= 0 || x != 7)
+ abort ();
if (strrchr (foo, 'x'))
abort ();
if (strrchr (foo, 'o') != foo + 7)
diff -rup orig/egcs-CVS20001201/gcc/testsuite/gcc.c-torture/execute/string-opt-8.c egcs-CVS20001201/gcc/testsuite/gcc.c-torture/execute/string-opt-8.c
--- orig/egcs-CVS20001201/gcc/testsuite/gcc.c-torture/execute/string-opt-8.c Sun Nov 26 23:51:15 2000
+++ egcs-CVS20001201/gcc/testsuite/gcc.c-torture/execute/string-opt-8.c Fri Dec 1 16:09:55 2000
@@ -44,6 +44,103 @@ int main ()
s2 = s1; s3 = s1+4;
if (strncmp (++s2, ++s3, 0) != 0 || s2 != s1+1 || s3 != s1+5)
abort();
+ s2 = s1;
+ if (strncmp (++s2, "", 1) <= 0 || s2 != s1+1)
+ abort();
+ if (strncmp ("", ++s2, 1) >= 0 || s2 != s1+2)
+ abort();
+ if (strncmp (++s2, "", 100) <= 0 || s2 != s1+3)
+ abort();
+ if (strncmp ("", ++s2, 100) >= 0 || s2 != s1+4)
+ abort();
+ if (strncmp (++s2+6, "", 100) != 0 || s2 != s1+5)
+ abort();
+ if (strncmp ("", ++s2+5, 100) != 0 || s2 != s1+6)
+ abort();
+ if (strncmp ("ozz", ++s2, 1) != 0 || s2 != s1+7)
+ abort();
+ if (strncmp (++s2, "rzz", 1) != 0 || s2 != s1+8)
+ abort();
+ s2 = s1; s3 = s1+4;
+ if (strncmp (++s2, ++s3+2, 1) >= 0 || s2 != s1+1 || s3 != s1+5)
+ abort();
+#if defined(__i386__)
+ /* These tests work on platforms which support cmpstrsi. */
+ s2 = s1;
+ if (strncmp (++s2, "ello", 3) != 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("ello", ++s2, 3) != 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp (++s2, "ello", 4) != 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("ello", ++s2, 4) != 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp (++s2, "ello", 5) <= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("ello", ++s2, 5) >= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp (++s2, "ello", 6) <= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("ello", ++s2, 6) >= 0 || s2 != s1+1)
+ abort();
+
+ s2 = s1;
+ if (strncmp (++s2, "zllo", 3) >= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("zllo", ++s2, 3) <= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp (++s2, "zllo", 4) >= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("zllo", ++s2, 4) <= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp (++s2, "zllo", 5) >= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("zllo", ++s2, 5) <= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp (++s2, "zllo", 6) >= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("zllo", ++s2, 6) <= 0 || s2 != s1+1)
+ abort();
+
+ s2 = s1;
+ if (strncmp (++s2, "allo", 3) <= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("allo", ++s2, 3) >= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp (++s2, "allo", 4) <= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("allo", ++s2, 4) >= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp (++s2, "allo", 5) <= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("allo", ++s2, 5) >= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp (++s2, "allo", 6) <= 0 || s2 != s1+1)
+ abort();
+ s2 = s1;
+ if (strncmp ("allo", ++s2, 6) >= 0 || s2 != s1+1)
+ abort();
+#endif
return 0;
}
More information about the Gcc-patches
mailing list