]> gcc.gnu.org Git - gcc.git/commitdiff
builtins.c (expand_builtin_mathfn_2): Use tree_cons to build up the stabilized argume...
authorRoger Sayle <roger@eyesopen.com>
Mon, 23 Jun 2003 00:52:24 +0000 (00:52 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Mon, 23 Jun 2003 00:52:24 +0000 (00:52 +0000)
* builtins.c (expand_builtin_mathfn_2): Use tree_cons to build
up the stabilized argument list, not build_tree_list.
(expand_builtin_strcpy): Construct new argument list manually
instead of using chainon to modify the original argument list.
(expand_builtin_stpcpy): Construct new argument list manually
instead of using copy_list and chainon.
(expand_builtin_sprintf): New function.  Optimize calls to
sprintf when the format is "%s" or doesn't contain a '%'.
(expand_builtin): Expand BUILT_IN_SPRINTF using the new function
expand_builtin_sprintf.

* gcc.c-torture/execute/string-opt-16.c: New test case.

From-SVN: r68355

gcc/ChangeLog
gcc/builtins.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/string-opt-16.c [new file with mode: 0644]

index 2c2994363ae462876269bde6dcae3f8fc00a6b86..a35f9616597d427b158b647a9d3c08a688813ebc 100644 (file)
@@ -1,3 +1,16 @@
+2003-06-22  Roger Sayle  <roger@eyesopen.com>
+
+       * builtins.c (expand_builtin_mathfn_2): Use tree_cons to build
+       up the stabilized argument list, not build_tree_list.
+       (expand_builtin_strcpy): Construct new argument list manually
+       instead of using chainon to modify the original argument list.
+       (expand_builtin_stpcpy): Construct new argument list manually
+       instead of using copy_list and chainon.
+       (expand_builtin_sprintf): New function.  Optimize calls to
+       sprintf when the format is "%s" or doesn't contain a '%'.
+       (expand_builtin): Expand BUILT_IN_SPRINTF using the new function
+       expand_builtin_sprintf.
+
 2003-06-22  Andreas Schwab  <schwab@suse.de>
 
        * function.c (set_insn_locators): Mark as unused.
index 8f278aa06455b0d2b4e9c7e67438778381320de4..80a06f7e92e4601a4820bd9421429139fc04d9d5 100644 (file)
@@ -141,6 +141,7 @@ static rtx expand_builtin_alloca (tree, rtx);
 static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
 static rtx expand_builtin_frame_address (tree, tree);
 static rtx expand_builtin_fputs (tree, int, int);
+static rtx expand_builtin_sprintf (tree, rtx, enum machine_mode);
 static tree stabilize_va_list (tree, int);
 static rtx expand_builtin_expect (tree, rtx);
 static tree fold_builtin_constant_p (tree);
@@ -1891,13 +1892,13 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
        case SAVE_EXPR:
        case REAL_CST:
          if (! stable)
-           arglist = build_tree_list (temp, arg0);
+           arglist = tree_cons (NULL_TREE, arg0, temp);
          break;
 
        default:
          stable = false;
          arg0 = save_expr (arg0);
-         arglist = build_tree_list (temp, arg0);
+         arglist = tree_cons (NULL_TREE, arg0, temp);
          break;
        }
 
@@ -2529,7 +2530,7 @@ expand_builtin_bcopy (tree arglist)
 static rtx
 expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode)
 {
-  tree fn, len;
+  tree fn, len, src, dst;
 
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
@@ -2538,12 +2539,16 @@ expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode)
   if (!fn)
     return 0;
 
-  len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
+  src = TREE_VALUE (TREE_CHAIN (arglist));
+  len = c_strlen (src);
   if (len == 0)
     return 0;
 
+  dst = TREE_VALUE (arglist);
   len = size_binop (PLUS_EXPR, len, ssize_int (1));
-  chainon (arglist, build_tree_list (NULL_TREE, len));
+  arglist = build_tree_list (NULL_TREE, len);
+  arglist = tree_cons (NULL_TREE, src, arglist);
+  arglist = tree_cons (NULL_TREE, dst, arglist);
   return expand_expr (build_function_call_expr (fn, arglist),
                      target, mode, EXPAND_NORMAL);
 }
@@ -2560,8 +2565,7 @@ expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode)
     return 0;
   else
     {
-      tree newarglist;
-      tree src, len;
+      tree dst, src, len;
 
       /* If return value is ignored, transform stpcpy into strcpy.  */
       if (target == const0_rtx)
@@ -2582,10 +2586,12 @@ expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode)
       if (! c_getstr (src) || ! (len = c_strlen (src)))
        return 0;
 
+      dst = TREE_VALUE (arglist);
       len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
-      newarglist = copy_list (arglist);
-      chainon (newarglist, build_tree_list (NULL_TREE, len));
-      return expand_builtin_mempcpy (newarglist, target, mode, /*endp=*/2);
+      arglist = build_tree_list (NULL_TREE, len);
+      arglist = tree_cons (NULL_TREE, src, arglist);
+      arglist = tree_cons (NULL_TREE, dst, arglist);
+      return expand_builtin_mempcpy (arglist, target, mode, /*endp=*/2);
     }
 }
 
@@ -4259,6 +4265,97 @@ expand_builtin_cabs (tree arglist, rtx target)
   return expand_complex_abs (mode, op0, target, 0);
 }
 
+/* Expand a call to sprintf with argument list ARGLIST.  Return 0 if
+   a normal call should be emitted rather than expanding the function
+   inline.  If convenient, the result should be placed in TARGET with
+   mode MODE.  */
+
+static rtx
+expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
+{
+  tree dest, fmt, stripped;
+  tree orig_arglist;
+
+  orig_arglist = arglist;
+
+  /* Verify the required arguments in the original call.  */
+  if (! arglist)
+    return 0;
+  dest = TREE_VALUE (arglist);
+  if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE)
+    return 0;
+  arglist = TREE_CHAIN (arglist);
+  if (! arglist)
+    return 0;
+  fmt = TREE_VALUE (arglist);
+  if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE)
+    return 0;
+  arglist = TREE_CHAIN (arglist);
+
+  /* Check whether the format is a literal string constant.  */
+  stripped = fmt;
+  STRIP_NOPS (stripped);
+  if (stripped && TREE_CODE (stripped) == ADDR_EXPR)
+    stripped = TREE_OPERAND (stripped, 0);
+  if (TREE_CODE (stripped) != STRING_CST)
+    return 0;
+
+  /* If the format doesn't contain % args or %%, use strcpy.  */
+  if (strchr (TREE_STRING_POINTER (stripped), '%') == 0)
+    {
+      tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+      tree exp;
+
+      if (arglist || !fn)
+       return 0;
+      expand_expr (build_function_call_expr (fn, orig_arglist),
+                  const0_rtx, VOIDmode, EXPAND_NORMAL);
+      if (target == const0_rtx)
+       return const0_rtx;
+      exp = build_int_2 (TREE_STRING_LENGTH (stripped) - 1, 0);
+      exp = fold (build1 (NOP_EXPR, integer_type_node, exp));
+      return expand_expr (exp, target, mode, EXPAND_NORMAL);
+    }
+  /* If the format is "%s", use strcpy and possibly strlen.  */
+  else if (strcmp (TREE_STRING_POINTER (stripped), "%s") == 0)
+    {
+      tree strcpy_fn, strlen_fn, exp, arg;
+      strcpy_fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+
+      if (! strcpy_fn)
+       return 0;
+
+      if (! arglist || TREE_CHAIN (arglist))
+       return 0;
+      arg = TREE_VALUE (arglist);
+      if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
+       return 0;
+
+      if (target != const0_rtx)
+       {
+         strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
+         if (! strlen_fn)
+           return 0;
+         arg = save_expr (arg);
+       }
+      else
+       strlen_fn = 0;
+
+      arglist = build_tree_list (NULL_TREE, arg);
+      arglist = tree_cons (NULL_TREE, dest, arglist);
+      expand_expr (build_function_call_expr (strcpy_fn, arglist),
+                  const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+      if (target == const0_rtx)
+       return const0_rtx;
+
+      exp = build_function_call_expr (strlen_fn, TREE_CHAIN (arglist));
+      exp = fold (build1 (NOP_EXPR, integer_type_node, exp));
+      return expand_expr (exp, target, mode, EXPAND_NORMAL);
+    }
+
+  return 0;
+}
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -4323,6 +4420,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       case BUILT_IN_BCOPY:
       case BUILT_IN_INDEX:
       case BUILT_IN_RINDEX:
+      case BUILT_IN_SPRINTF:
       case BUILT_IN_STPCPY:
       case BUILT_IN_STRCHR:
       case BUILT_IN_STRRCHR:
@@ -4794,6 +4892,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
+    case BUILT_IN_SPRINTF:
+      target = expand_builtin_sprintf (arglist, target, mode);
+      if (target)
+       return target;
+      break;
+
       /* Various hooks for the DWARF 2 __throw routine.  */
     case BUILT_IN_UNWIND_INIT:
       expand_builtin_unwind_init ();
index 4e3c4cf24fd7190173dc90cfae0ffce61049a3df..099c83060e2bd2e578c0a5007dc260087a11f9bf 100644 (file)
@@ -1,3 +1,7 @@
+2003-06-22  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.c-torture/execute/string-opt-16.c: New test case.
+
 2003-06-21  Gabriel Dos Reis <gdr@integrable-solutions.net>
 
         * g++.old-deja/g++.benjamin/16077.C: Add -Wconversion  option.
diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-16.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-16.c
new file mode 100644 (file)
index 0000000..82f3c41
--- /dev/null
@@ -0,0 +1,95 @@
+/* Copyright (C) 2003  Free Software Foundation.
+
+   Test sprintf optimizations don't break anything and return the
+   correct results.
+
+   Written by Roger Sayle, June 22, 2003.  */
+
+static char buffer[32];
+
+extern void abort ();
+typedef __SIZE_TYPE__ size_t;
+extern int sprintf(char*, const char*, ...);
+extern void *memset(void*, int, size_t);
+extern int memcmp(const void*, const void*, size_t);
+
+void test1()
+{
+  sprintf(buffer,"foo");
+}
+
+int test2()
+{
+  return sprintf(buffer,"foo");
+}
+
+void test3()
+{
+  sprintf(buffer,"%s","bar");
+}
+
+int test4()
+{
+  return sprintf(buffer,"%s","bar");
+}
+
+void test5(char *ptr)
+{
+  sprintf(buffer,"%s",ptr);
+}
+
+int test6(char *ptr)
+{
+  return sprintf(buffer,"%s",ptr);
+}
+
+int main()
+{
+  memset (buffer, 'A', 32);
+  test1 ();
+  if (memcmp(buffer, "foo", 4) || buffer[4] != 'A')
+    abort ();
+
+  memset (buffer, 'A', 32);
+  if (test2 () != 3)
+    abort ();
+  if (memcmp(buffer, "foo", 4) || buffer[4] != 'A')
+    abort ();
+
+  memset (buffer, 'A', 32);
+  test3 ();
+  if (memcmp(buffer, "bar", 4) || buffer[4] != 'A')
+    abort ();
+
+  memset (buffer, 'A', 32);
+  if (test4 () != 3)
+    abort ();
+  if (memcmp(buffer, "bar", 4) || buffer[4] != 'A')
+    abort ();
+
+  memset (buffer, 'A', 32);
+  test5 ("barf");
+  if (memcmp(buffer, "barf", 5) || buffer[5] != 'A')
+    abort ();
+
+  memset (buffer, 'A', 32);
+  if (test6 ("barf") != 4)
+    abort ();
+  if (memcmp(buffer, "barf", 5) || buffer[5] != 'A')
+    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.  */
+__attribute__ ((noinline))
+static int
+sprintf (char *buf, const char *fmt, ...)
+{
+  abort ();
+}
+#endif
+
This page took 0.124958 seconds and 5 git commands to generate.