OSDN Git Service

* builtins.c (expand_builtin_strncmp, expand_builtin_strncpy): New
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 27 Nov 2000 05:00:06 +0000 (05:00 +0000)
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 27 Nov 2000 05:00:06 +0000 (05:00 +0000)
functions.
(expand_builtin): Handle BUILT_IN_STRNCPY and BUILT_IN_STRNCMP.

* builtins.def (BUILT_IN_STRNCPY, BUILT_IN_STRNCMP): New entries.

* c-common.c (c_common_nodes_and_builtins): Declare builtin
strncpy and strncmp.

* extend.texi (strncmp, strncpy): Document new builtins.

testsuite:
* gcc.c-torture/execute/string-opt-7.c: New test.
* gcc.c-torture/execute/string-opt-8.c: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@37777 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/builtins.c
gcc/builtins.def
gcc/c-common.c
gcc/extend.texi
gcc/testsuite/gcc.c-torture/execute/string-opt-7.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/string-opt-8.c [new file with mode: 0644]

index b6e8264..44ad079 100644 (file)
@@ -1,3 +1,16 @@
+2000-11-26  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * builtins.c (expand_builtin_strncmp, expand_builtin_strncpy): New
+       functions.
+       (expand_builtin): Handle BUILT_IN_STRNCPY and BUILT_IN_STRNCMP.
+
+       * builtins.def (BUILT_IN_STRNCPY, BUILT_IN_STRNCMP): New entries.
+
+       * c-common.c (c_common_nodes_and_builtins): Declare builtin
+       strncpy and strncmp.
+
+       * extend.texi (strncmp, strncpy): Document new builtins.
+
 2000-11-26  Mark Mitchell  <mark@codesourcery.com>
 
        * config/elfos.h (ASM_OUTPUT_SECTION_NAME): Use a hash table, not
index 221cba6..7db9b26 100644 (file)
@@ -104,8 +104,12 @@ 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,
+                                                enum machine_mode));
 static rtx expand_builtin_memcpy       PARAMS ((tree));
 static rtx expand_builtin_strcpy       PARAMS ((tree));
+static rtx expand_builtin_strncpy      PARAMS ((tree, rtx,
+                                                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));
@@ -1770,6 +1774,63 @@ expand_builtin_strcpy (exp)
   return result;
 }
 
+/* Expand expression EXP, which is a call to the strncpy builtin.  Return 0
+   if we failed the caller should emit a normal call.  */
+
+static rtx
+expand_builtin_strncpy (arglist, target, mode)
+     tree arglist;
+     rtx target;
+     enum machine_mode mode;
+{
+  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
+    {
+      tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
+      tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+      /* We must be passed a constant len parameter.  */
+      if (TREE_CODE (len) != INTEGER_CST)
+       return 0;
+
+      /* If the len parameter is zero, return the dst parameter.  */
+      if (compare_tree_int (len, 0) == 0)
+        {
+       /* Evaluate and ignore the src argument in case it has
+           side-effects.  */
+         expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
+                      VOIDmode, EXPAND_NORMAL);
+         /* Return the dst parameter.  */                     
+         return expand_expr (TREE_VALUE (arglist), target, mode,
+                             EXPAND_NORMAL);
+       }
+      
+      /* Now, we must be passed a constant src ptr parameter.  */
+      if (slen == 0)
+       return 0;
+
+      slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
+
+      /* We're required to pad with trailing zeros if the requested
+         len is greater than strlen(s2)+1, so in that case punt.  */
+      if (tree_int_cst_lt (slen, len))
+       return 0;
+      
+      /* OK transform into builtin memcpy.  */
+      return expand_builtin_memcpy (arglist);
+    }
+}
+
 /* Expand expression EXP, which is a call to the memset builtin.  Return 0
    if we failed the caller should emit a normal call.  */
 
@@ -2051,6 +2112,83 @@ expand_builtin_strcmp (exp, target, mode)
 #endif
 }
 
+/* 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, mode)
+     tree exp;
+     rtx target;
+     enum machine_mode mode;
+{
+  tree arglist = TREE_OPERAND (exp, 1);
+  tree arg1, arg2, arg3;
+  const char *p1, *p2;
+
+  /* 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;
+
+  arg1 = TREE_VALUE (arglist);
+  arg2 = TREE_VALUE (TREE_CHAIN (arglist));
+  arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+  /* We must be passed a constant len parameter.  */
+  if (TREE_CODE (arg3) != INTEGER_CST)
+    return 0;
+  
+  /* If the len parameter is zero, return zero.  */
+  if (compare_tree_int (arg3, 0) == 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;
+  }
+
+  p1 = c_getstr (arg1);
+  p2 = c_getstr (arg2);
+
+  /* If all arguments are constant, evaluate at compile-time.  */
+  if (p1 && p2)
+  {
+    const int r = strncmp (p1, p2, TREE_INT_CST_LOW (arg3));
+    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;
+
+    /* 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;
+  }
+  
+  return 0;
+}
+
 /* Expand a call to __builtin_saveregs, generating the result in TARGET,
    if that's convenient.  */
 
@@ -2752,6 +2890,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
          || fcode == BUILT_IN_INDEX || fcode == BUILT_IN_RINDEX
          || fcode == BUILT_IN_STRCHR || fcode == BUILT_IN_STRRCHR
          || fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY
+         || fcode == BUILT_IN_STRNCPY || fcode == BUILT_IN_STRNCMP
          || fcode == BUILT_IN_STRSTR || fcode == BUILT_IN_STRPBRK
          || fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS
          || fcode == BUILT_IN_PUTCHAR || fcode == BUILT_IN_PUTS
@@ -2881,6 +3020,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        return target;
       break;
       
+    case BUILT_IN_STRNCPY:
+      target = expand_builtin_strncpy (arglist, target, mode);
+      if (target)
+       return target;
+      break;
+      
     case BUILT_IN_STRSTR:
       target = expand_builtin_strstr (arglist, target, mode);
       if (target)
@@ -2931,6 +3076,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        return target;
       break;
 
+    case BUILT_IN_STRNCMP:
+      target = expand_builtin_strncmp (exp, target, mode);
+      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.  */
index 1920282..ec43252 100644 (file)
@@ -39,7 +39,9 @@ DEF_BUILTIN(BUILT_IN_BCMP)
 DEF_BUILTIN(BUILT_IN_INDEX)
 DEF_BUILTIN(BUILT_IN_RINDEX)
 DEF_BUILTIN(BUILT_IN_STRCPY)
+DEF_BUILTIN(BUILT_IN_STRNCPY)
 DEF_BUILTIN(BUILT_IN_STRCMP)
+DEF_BUILTIN(BUILT_IN_STRNCMP)
 DEF_BUILTIN(BUILT_IN_STRLEN)
 DEF_BUILTIN(BUILT_IN_STRSTR)
 DEF_BUILTIN(BUILT_IN_STRPBRK)
index e839ae5..d59386d 100644 (file)
@@ -4887,6 +4887,7 @@ c_common_nodes_and_builtins ()
   tree int_ftype_cptr_cptr_sizet;
   tree int_ftype_string_string, string_ftype_ptr_ptr;
   tree string_ftype_string_int, string_ftype_string_string;
+  tree string_ftype_string_cstring_sizet, int_ftype_cstring_cstring_sizet;
   tree long_ftype_long;
   tree longlong_ftype_longlong;
   /* Either char* or void*.  */
@@ -4987,6 +4988,14 @@ c_common_nodes_and_builtins ()
                                                 const_string_type_node,
                                                 endlink)));
 
+  /* Prototype for strncpy.  */
+  string_ftype_string_cstring_sizet
+    = build_function_type (string_type_node,
+                          tree_cons (NULL_TREE, string_type_node,
+                                     tree_cons (NULL_TREE,
+                                                const_string_type_node,
+                                                sizetype_endlink)));
+
   traditional_len_type_node = ((flag_traditional && 
                                c_language != clk_cplusplus)
                               ? integer_type_node : sizetype);
@@ -5001,6 +5010,14 @@ c_common_nodes_and_builtins ()
                                                 const_string_type_node,
                                                 endlink)));
 
+  /* Prototype for strncmp.  */
+  int_ftype_cstring_cstring_sizet
+    = build_function_type (integer_type_node,
+                          tree_cons (NULL_TREE, const_string_type_node,
+                                     tree_cons (NULL_TREE,
+                                                const_string_type_node,
+                                                sizetype_endlink)));
+
   /* Prototype for strstr, strpbrk, etc.  */
   string_ftype_string_string
     = build_function_type (string_type_node,
@@ -5246,8 +5263,11 @@ c_common_nodes_and_builtins ()
                    BUILT_IN_INDEX, BUILT_IN_NORMAL, "index");
   builtin_function ("__builtin_rindex", string_ftype_string_int,
                    BUILT_IN_RINDEX, BUILT_IN_NORMAL, "rindex");
-  builtin_function ("__builtin_strcmp", int_ftype_string_string,
-                   BUILT_IN_STRCMP, BUILT_IN_NORMAL, "strcmp");
+  built_in_decls[BUILT_IN_STRCMP] =
+    builtin_function ("__builtin_strcmp", int_ftype_string_string,
+                     BUILT_IN_STRCMP, BUILT_IN_NORMAL, "strcmp");
+  builtin_function ("__builtin_strncmp", int_ftype_cstring_cstring_sizet,
+                   BUILT_IN_STRNCMP, BUILT_IN_NORMAL, "strncmp");
   builtin_function ("__builtin_strstr", string_ftype_string_string,
                    BUILT_IN_STRSTR, BUILT_IN_NORMAL, "strstr");
   builtin_function ("__builtin_strpbrk", string_ftype_string_string,
@@ -5259,6 +5279,8 @@ c_common_nodes_and_builtins ()
                    BUILT_IN_STRRCHR, BUILT_IN_NORMAL, "strrchr");
   builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
                    BUILT_IN_STRCPY, BUILT_IN_NORMAL, "strcpy");
+  builtin_function ("__builtin_strncpy", string_ftype_string_cstring_sizet,
+                   BUILT_IN_STRNCPY, BUILT_IN_NORMAL, "strncpy");
   builtin_function ("__builtin_strlen", strlen_ftype,
                    BUILT_IN_STRLEN, BUILT_IN_NORMAL, "strlen");
   builtin_function ("__builtin_sqrtf", float_ftype_float,
@@ -5325,6 +5347,8 @@ c_common_nodes_and_builtins ()
                        BUILT_IN_NORMAL, NULL_PTR);
       builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP,
                        BUILT_IN_NORMAL, NULL_PTR);
+      builtin_function ("strncmp", int_ftype_cstring_cstring_sizet,
+                       BUILT_IN_STRNCMP, BUILT_IN_NORMAL, NULL_PTR);
       builtin_function ("strstr", string_ftype_string_string, BUILT_IN_STRSTR,
                        BUILT_IN_NORMAL, NULL_PTR);
       builtin_function ("strchr", string_ftype_string_int, BUILT_IN_STRCHR,
@@ -5335,6 +5359,8 @@ c_common_nodes_and_builtins ()
                        BUILT_IN_NORMAL, NULL_PTR);
       builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
                        BUILT_IN_NORMAL, NULL_PTR);
+      builtin_function ("strncpy", string_ftype_string_cstring_sizet,
+                       BUILT_IN_STRNCPY, BUILT_IN_NORMAL, NULL_PTR);
       builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN,
                        BUILT_IN_NORMAL, NULL_PTR);
       builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT,
index 0d88bdf..0efab12 100644 (file)
@@ -3294,6 +3294,8 @@ function as well.
 @findex strcmp
 @findex strcpy
 @findex strlen
+@findex strncmp
+@findex strncpy
 @findex strpbrk
 @findex strrchr
 @findex strstr
@@ -3338,10 +3340,11 @@ The following ISO C89 functions are recognized as builtins unless
 @samp{-fno-builtin} is specified: @code{abs}, @code{cos}, @code{fabs},
 @code{fputs}, @code{labs}, @code{memcmp}, @code{memcpy}, @code{memset},
 @code{printf}, @code{sin}, @code{sqrt}, @code{strchr}, @code{strcmp},
-@code{strcpy}, @code{strlen}, @code{strpbrk}, @code{strrchr}, and
-@code{strstr}.  All of these functions have corresponding versions
-prefixed with @code{__builtin_}, except that the version for @code{sqrt}
-is called @code{__builtin_fsqrt}.
+@code{strcpy}, @code{strlen}, @code{strncmp}, @code{strncpy},
+@code{strpbrk}, @code{strrchr}, and @code{strstr}.  All of these
+functions have corresponding versions prefixed with @code{__builtin_},
+except that the version for @code{sqrt} is called
+@code{__builtin_fsqrt}.
 
 GNU CC provides builtin versions of the ISO C99 floating point
 comparison macros (that avoid raising exceptions for unordered
diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-7.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-7.c
new file mode 100644 (file)
index 0000000..105b3dc
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2000  Free Software Foundation.
+
+   Ensure all expected transformations of builtin strncpy occur and
+   perform correctly.
+
+   Written by Kaveh R. Ghazi, 11/25/2000.  */
+
+extern void abort (void);
+typedef __SIZE_TYPE__ size_t;
+extern char *strncpy (char *, const char *, size_t);
+extern int strcmp (const char *, const char *);
+extern int strncmp (const char *, const char *, size_t);
+extern void *memset (void *, int, size_t);
+
+int main ()
+{
+  const char *const src = "hello world";
+  const char *src2;
+  char dst[64], *dst2;
+  
+  memset (dst, 0, sizeof (dst));
+  if (strncpy (dst, src, 4) != dst || strncmp (dst, src, 4))
+    abort();
+
+  memset (dst, 0, sizeof (dst));
+  if (strncpy (dst+16, src, 4) != dst+16 || strncmp (dst+16, src, 4))
+    abort();
+
+  memset (dst, 0, sizeof (dst));
+  if (strncpy (dst+32, src+5, 4) != dst+32 || strncmp (dst+32, src+5, 4))
+    abort();
+
+  memset (dst, 0, sizeof (dst));
+  dst2 = dst;
+  if (strncpy (++dst2, src+5, 4) != dst+1 || strncmp (dst2, src+5, 4)
+      || dst2 != dst+1)
+    abort();
+
+  memset (dst, 0, sizeof (dst));
+  if (strncpy (dst, src, 0) != dst || strcmp (dst, ""))
+    abort();
+  
+  memset (dst, 0, sizeof (dst));
+  dst2 = dst; src2 = src;
+  if (strncpy (++dst2, ++src2, 0) != dst+1 || strcmp (dst2, "")
+      || dst2 != dst+1 || src2 != src+1)
+    abort();
+
+  memset (dst, 0, sizeof (dst));
+  dst2 = dst; src2 = src;
+  if (strncpy (++dst2+5, ++src2+5, 0) != dst+6 || strcmp (dst2+5, "")
+      || dst2 != dst+1 || src2 != src+1)
+    abort();
+
+  memset (dst, 0, sizeof (dst));
+  if (strncpy (dst, src, 12) != dst || strcmp (dst, src))
+    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 char *
+strncpy(char *s1, const char *s2, size_t n)
+{
+  abort();
+}
+#endif
diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-8.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-8.c
new file mode 100644 (file)
index 0000000..ca386f0
--- /dev/null
@@ -0,0 +1,60 @@
+/* Copyright (C) 2000  Free Software Foundation.
+
+   Ensure all expected transformations of builtin strncmp occur and
+   perform correctly.
+
+   Written by Kaveh R. Ghazi, 11/26/2000.  */
+
+extern void abort (void);
+typedef __SIZE_TYPE__ size_t;
+extern int strncmp (const char *, const char *, size_t);
+
+int main ()
+{
+  const char *const s1 = "hello world";
+  const char *s2, *s3;
+  
+  if (strncmp (s1, "hello world", 12) != 0)
+    abort();
+  if (strncmp ("hello world", s1, 12) != 0)
+    abort();
+  if (strncmp ("hello", "hello", 6) != 0)
+    abort();
+  if (strncmp ("hello", "hello", 2) != 0)
+    abort();
+  if (strncmp ("hello", "hello", 100) != 0)
+    abort();
+  if (strncmp (s1+10, "d", 100) != 0)
+    abort();
+  if (strncmp (10+s1, "d", 100) != 0)
+    abort();
+  if (strncmp ("d", s1+10, 1) != 0)
+    abort();
+  if (strncmp ("d", 10+s1, 1) != 0)
+    abort();
+  if (strncmp ("hello", "aaaaa", 100) <= 0)
+    abort();
+  if (strncmp ("aaaaa", "hello", 100) >= 0)
+    abort();
+  if (strncmp ("hello", "aaaaa", 1) <= 0)
+    abort();
+  if (strncmp ("aaaaa", "hello", 1) >= 0)
+    abort();
+
+  s2 = s1; s3 = s1+4;
+  if (strncmp (++s2, ++s3, 0) != 0 || s2 != s1+1 || s3 != s1+5)
+    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 char *
+strncmp(const char *s1, const char *s2, size_t n)
+{
+  abort();
+}
+#endif