This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Optimize sprintf into strcpy if possible (take 3)


Hi!

This is just slightly modified patch from April, 6th with incorporated
comments from Joseph (separate plus-1.c testcase and adding sprintf into
extend.texi).
Ok to commit?

2001-04-18  Jakub Jelinek  <jakub@redhat.com>

	* builtins.def (BUILT_IN_SPRINTF): Add.
	* c-common.c (c_expand_builtin_sprintf): New.
	(c_common_nodes_and_builtins): Set sprintf_ftype.
	Add __builtin_sprintf and sprintf builtins.
	(c_expand_builtin): Call c_expand_builtin_sprintf.
	(adjust_builtin_function_type): New.
	* c-common.h (adjust_builtin_function_type): New prototype.
	* builtins.c (c_strlen, c_getstr): Make non-static.
	Don't cast TREE_INT_CST_LOW to int without checking
	if it does not have upper bits set.
	* expr.h (c_strlen, c_getstr): Add prototypes.
	* c-format.c (check_format_info_recurse): Handle
	PLUS_EXPR for format string.
	* c-decl.c (duplicate_decls): Don't warn if a builtin
	is redeclared with int foo() style prototype under -traditional.
	Use adjust_builtin_function_type.
	* extend.texi (Other builtins): Add sprintf.

cp/
	* decl.c (duplicate_decls): Override builtin type if it new
	prototype is sufficiently similar instead of warning and
	throwing the builtin away.

testsuite/
	* gcc.c-torture/execute/string-opt-13.c: New test.
	* g++.old-deja/g++.other/string-opt-1.C: New test.
	* gcc.dg/format/plus-1.c: New test.
	* gcc.dg/builtins-1.c: New test.

--- gcc/cp/decl.c.jj	Tue Apr 10 17:42:46 2001
+++ gcc/cp/decl.c	Tue Apr 10 17:50:12 2001
@@ -3181,9 +3181,33 @@ duplicate_decls (newdecl, olddecl)
 
 	      if (TREE_PUBLIC (newdecl))
 		{
-		  cp_warning ("new declaration `%#D'", newdecl);
-		  cp_warning ("ambiguates built-in declaration `%#D'",
-			      olddecl);
+		  if (DECL_EXTERN_C_P (newdecl)
+		      && DECL_EXTERN_C_P (olddecl)
+		      && DECL_BUILT_IN (olddecl)
+		      && CP_DECL_CONTEXT (newdecl)
+			 == CP_DECL_CONTEXT (olddecl))
+		    {
+		      tree trytype
+			= adjust_builtin_function_type (TREE_TYPE (newdecl),
+							TREE_TYPE (olddecl));
+
+		      if (trytype)
+			{
+			  tree oldtype = TREE_TYPE (olddecl);
+
+			  TREE_TYPE (olddecl) = trytype;
+			  types_match = decls_match (newdecl, olddecl);
+			  if (!types_match)
+			    TREE_TYPE (olddecl) = oldtype;
+			}
+		    }
+
+		  if (!types_match)
+		    {
+		      cp_warning ("new declaration `%#D'", newdecl);
+		      cp_warning ("ambiguates built-in declaration `%#D'",
+				  olddecl);
+		    }
 		}
 	      else if (warn_shadow)
 		cp_warning ("shadowing %s function `%#D'",
--- gcc/testsuite/g++.old-deja/g++.other/string-opt-1.C.jj	Tue Apr 10 17:16:28 2001
+++ gcc/testsuite/g++.old-deja/g++.other/string-opt-1.C	Tue Apr 10 17:50:12 2001
@@ -0,0 +1,61 @@
+/* Copyright (C) 2001  Free Software Foundation.
+
+   Ensure all expected transformations of builtin sprintf occur and
+   perform correctly.
+
+   Written by Jakub Jelinek, 4/10/2001.  */
+
+extern "C" void abort (void);
+typedef __SIZE_TYPE__ size_t;
+namespace std {
+  extern "C" int sprintf (char *, const char *, ...);
+  extern "C" int memcmp (const void *, const void *, size_t);
+};
+
+char *foobar = "foobar";
+
+int main ()
+{
+  char dst[64], *d2;
+
+  std::sprintf (dst, "%s", "hello");
+  if (std::memcmp (dst, "hello", 6) != 0)
+    abort();
+  std::sprintf (dst + 5, "world");
+  if (std::memcmp (dst, "helloworld", 11) != 0)
+    abort();
+  d2 = dst + 6;
+  std::sprintf (++d2, "UVWX" + 2);
+  if (std::memcmp (dst, "hellowoWX", 10) != 0 || d2 != dst + 7)
+    abort();
+  std::sprintf (d2++, "%c", ' ');
+  if (std::memcmp (dst, "hellowo ", 9) != 0 || d2 != dst + 8)
+    abort();
+  std::sprintf (d2--, "%c", 65536 | '0');
+  if (std::memcmp (dst, "hellowo 0", 10) != 0 || d2 != dst + 7)
+    abort();
+  std::sprintf (dst, "%s", foobar + 1);
+  if (std::memcmp (dst, "oobar", 6) != 0)
+    abort();
+
+  /* Test at least one instance of the __builtin_ style.  We do this
+     to ensure that it works and that the prototype is correct.  */
+  __builtin_sprintf (--d2, "z");
+  if (std::memcmp (dst, "oobar\0z", 8) != 0 || d2 != dst + 6)
+    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.  */
+extern "C" {
+static int
+sprintf (char *s1, const char *s2, ...)
+{
+  abort();
+}
+};
+#endif
--- gcc/testsuite/gcc.c-torture/execute/string-opt-13.c.jj	Fri Apr  6 14:52:57 2001
+++ gcc/testsuite/gcc.c-torture/execute/string-opt-13.c	Tue Apr 10 17:50:12 2001
@@ -0,0 +1,57 @@
+/* Copyright (C) 2001  Free Software Foundation.
+
+   Ensure all expected transformations of builtin sprintf occur and
+   perform correctly.
+
+   Written by Jakub Jelinek, 4/6/2001.  */
+
+extern void abort (void);
+typedef __SIZE_TYPE__ size_t;
+extern int sprintf (char *, const char *, ...);
+extern int memcmp (const void *, const void *, size_t);
+
+char *foobar = "foobar";
+
+int main ()
+{
+  char dst[64], *d2;
+
+  sprintf (dst, "%s", "hello");
+  if (memcmp (dst, "hello", 6) != 0)
+    abort();
+  sprintf (dst + 5, "world");
+  if (memcmp (dst, "helloworld", 11) != 0)
+    abort();
+  d2 = dst + 6;
+  sprintf (++d2, "UVWX" + 2);
+  if (memcmp (dst, "hellowoWX", 10) != 0 || d2 != dst + 7)
+    abort();
+  sprintf (d2++, "%c", ' ');
+  if (memcmp (dst, "hellowo ", 9) != 0 || d2 != dst + 8)
+    abort();
+  sprintf (d2--, "%c", 65536 | '0');
+  if (memcmp (dst, "hellowo 0", 10) != 0 || d2 != dst + 7)
+    abort();
+  sprintf (dst, "%s", foobar + 1);
+  if (memcmp (dst, "oobar", 6) != 0)
+    abort();
+
+  /* Test at least one instance of the __builtin_ style.  We do this
+     to ensure that it works and that the prototype is correct.  */
+  __builtin_sprintf (--d2, "z");
+  if (memcmp (dst, "oobar\0z", 8) != 0 || d2 != dst + 6)
+    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 int
+sprintf (char *s1, const char *s2, ...)
+{
+  abort();
+}
+#endif
--- gcc/testsuite/gcc.dg/format/plus-1.c.jj	Wed Apr 18 16:51:46 2001
+++ gcc/testsuite/gcc.dg/format/plus-1.c	Wed Apr 18 17:06:40 2001
@@ -0,0 +1,19 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
--- gcc/testsuite/gcc.dg/builtins-1.c.jj	Tue Apr 10 17:07:09 2001
+++ gcc/testsuite/gcc.dg/builtins-1.c	Tue Apr 10 19:52:11 2001
@@ -0,0 +1,20 @@
+/* { dg-do compile { target i?86-*-* } } */
+/* { dg-options -traditional } */
+
+typedef struct {
+  int x;
+} FILE;
+
+/* SunOS has broken sprintf declaration, check whether we cope
+   with it without warning.  */
+char *sprintf ();
+int fprintf ();
+
+char buf[10];
+FILE *f;
+
+main()
+{
+  sprintf (buf, "%s", "foo");
+  fprintf (f, "%s", buf);
+}
--- gcc/builtins.def.jj	Fri Mar 30 11:44:42 2001
+++ gcc/builtins.def	Tue Apr 10 17:50:12 2001
@@ -80,6 +80,7 @@ DEF_BUILTIN(BUILT_IN_FPUTC)
 DEF_BUILTIN(BUILT_IN_FPUTS)
 DEF_BUILTIN(BUILT_IN_FWRITE)
 DEF_BUILTIN(BUILT_IN_FPRINTF)
+DEF_BUILTIN(BUILT_IN_SPRINTF)
 
   /* ISO C99 floating point unordered comparisons.  */
 DEF_BUILTIN(BUILT_IN_ISGREATER)
--- gcc/expr.h.jj	Thu Apr  5 00:12:39 2001
+++ gcc/expr.h	Tue Apr 10 17:50:12 2001
@@ -906,6 +906,8 @@ extern tree expand_tree_builtin PARAMS (
 extern void std_expand_builtin_va_start PARAMS ((int, tree, rtx));
 extern rtx std_expand_builtin_va_arg PARAMS ((tree, tree));
 extern rtx expand_builtin_va_arg PARAMS ((tree, tree));
+extern tree c_strlen PARAMS ((tree));
+extern const char *c_getstr PARAMS ((tree));
 #endif
 
 extern void expand_builtin_setjmp_setup PARAMS ((rtx, rtx));
--- gcc/c-decl.c.jj	Fri Mar 30 11:44:42 2001
+++ gcc/c-decl.c	Tue Apr 10 17:50:12 2001
@@ -1497,43 +1497,21 @@ duplicate_decls (newdecl, olddecl, diffe
 	}
       else if (!types_match)
 	{
-	  /* Accept the return type of the new declaration if same modes.  */
-	  tree oldreturntype = TREE_TYPE (oldtype);
-	  tree newreturntype = TREE_TYPE (newtype);
+	  tree trytype = adjust_builtin_function_type (newtype, oldtype);
 
-	  if (TYPE_MODE (oldreturntype) == TYPE_MODE (newreturntype))
-	    {
-	      /* Function types may be shared, so we can't just modify
-		 the return type of olddecl's function type.  */
-	      tree trytype
-		= build_function_type (newreturntype,
-				       TYPE_ARG_TYPES (oldtype));
+	  types_match = trytype && comptypes (newtype, trytype);
+	  if (types_match)
+	    oldtype = trytype;
+	  else if (flag_traditional && TYPE_ARG_TYPES (newtype) == 0
+		   && comptypes (TREE_TYPE (newtype),
+				 TREE_TYPE (trytype ? trytype : oldtype)))
+	    /* If the new type doesn't specify argument types and the
+	       types don't match while return types do (or at least
+	       their modes), throw away the builtin quietly.
+	       This means the built-in has variable number of arguments
+	       or arguments are affected by default promotions.  */
+	    return 0;
 
-              types_match = comptypes (newtype, trytype);
-	      if (types_match)
-		oldtype = trytype;
-	    }
-	  /* Accept harmless mismatch in first argument type also.
-	     This is for the ffs and fprintf builtins.  */
-	  if (TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0
-	      && TYPE_ARG_TYPES (oldtype) != 0
-	      && TREE_VALUE (TYPE_ARG_TYPES (newtype)) != 0
-	      && TREE_VALUE (TYPE_ARG_TYPES (oldtype)) != 0
-	      && (TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (newtype)))
-		  == TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (oldtype)))))
-	    {
-	      /* Function types may be shared, so we can't just modify
-		 the return type of olddecl's function type.  */
-	      tree trytype
-		= build_function_type (TREE_TYPE (oldtype),
-				       tree_cons (NULL_TREE,
-						  TREE_VALUE (TYPE_ARG_TYPES (newtype)),
-						  TREE_CHAIN (TYPE_ARG_TYPES (oldtype))));
-
-	      types_match = comptypes (newtype, trytype);
-	      if (types_match)
-		oldtype = trytype;
-	    }
 	  if (! different_binding_level)
 	    TREE_TYPE (olddecl) = oldtype;
 	}
--- gcc/c-common.c.jj	Fri Mar 30 11:44:42 2001
+++ gcc/c-common.c	Tue Apr 10 17:50:12 2001
@@ -1119,6 +1119,8 @@ static rtx c_expand_builtin_printf PARAM
 					    enum expand_modifier, int));
 static rtx c_expand_builtin_fprintf PARAMS ((tree, rtx, enum machine_mode,
 					     enum expand_modifier, int));
+static rtx c_expand_builtin_sprintf PARAMS ((tree, enum expand_modifier,
+					     int));
 
 /* Print a warning if a constant expression had overflow in folding.
    Invoke this function on every expression that the language
@@ -2718,9 +2720,10 @@ c_common_nodes_and_builtins ()
   tree memcpy_ftype, memset_ftype, strlen_ftype;
   tree bzero_ftype, bcmp_ftype, puts_ftype, printf_ftype;
   tree fputs_ftype, fputc_ftype, fwrite_ftype, fprintf_ftype;
+  tree sprintf_ftype;
   tree endlink, int_endlink, double_endlink, unsigned_endlink;
   tree cstring_endlink, sizetype_endlink;
-  tree ptr_ftype, ptr_ftype_unsigned;
+  tree ptr_ftype, ptr_ftype_unsigned, printf_endlink;
   tree void_ftype_any, void_ftype_int, int_ftype_any;
   tree double_ftype_double, double_ftype_double_double;
   tree float_ftype_float, ldouble_ftype_ldouble;
@@ -2918,6 +2921,7 @@ c_common_nodes_and_builtins ()
   double_endlink = tree_cons (NULL_TREE, double_type_node, endlink);
   unsigned_endlink = tree_cons (NULL_TREE, unsigned_type_node, endlink);
   cstring_endlink = tree_cons (NULL_TREE, const_string_type_node, endlink);
+  printf_endlink = tree_cons (NULL_TREE, const_string_type_node, NULL_TREE);
 
   ptr_ftype = build_function_type (ptr_type_node, NULL_TREE);
   ptr_ftype_unsigned = build_function_type (ptr_type_node, unsigned_endlink);
@@ -3100,10 +3104,7 @@ c_common_nodes_and_builtins ()
     = build_function_type (integer_type_node, cstring_endlink);
 
   /* Prototype for printf.  */
-  printf_ftype
-    = build_function_type (integer_type_node,
-			   tree_cons (NULL_TREE, const_string_type_node,
-				      NULL_TREE));
+  printf_ftype = build_function_type (integer_type_node, printf_endlink);
 
   /* These stdio prototypes are declared using void* in place of
      FILE*.  They are only used for __builtin_ style calls, regular
@@ -3132,10 +3133,12 @@ c_common_nodes_and_builtins ()
   /* Prototype for fprintf.  */
   fprintf_ftype
     = build_function_type (integer_type_node,
-			   tree_cons (NULL_TREE, ptr_type_node,
-				      tree_cons (NULL_TREE,
-						 const_string_type_node,
-						 NULL_TREE)));
+			   tree_cons (NULL_TREE, ptr_type_node, printf_endlink));
+
+  /* Prototype for sprintf.  */
+  sprintf_ftype
+    = build_function_type (integer_type_node,
+			   tree_cons (NULL_TREE, string_type_node, printf_endlink));
 
   builtin_function ("__builtin_constant_p", default_function_type,
 		    BUILT_IN_CONSTANT_P, BUILT_IN_NORMAL, NULL_PTR);
@@ -3327,9 +3330,10 @@ c_common_nodes_and_builtins ()
   builtin_function_2 ("__builtin_strrchr", "strrchr",
 		      string_ftype_cstring_int, string_ftype_cstring_int,
 		      BUILT_IN_STRRCHR, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_strcpy", "strcpy",
-		      string_ftype_string_cstring, string_ftype_string_cstring,
-		      BUILT_IN_STRCPY, BUILT_IN_NORMAL, 1, 0, 0);
+  built_in_decls[BUILT_IN_STRCPY] =
+    builtin_function_2 ("__builtin_strcpy", "strcpy",
+			string_ftype_string_cstring, string_ftype_string_cstring,
+			BUILT_IN_STRCPY, BUILT_IN_NORMAL, 1, 0, 0);
   builtin_function_2 ("__builtin_strncpy", "strncpy",
 		      string_ftype_string_cstring_sizet,
 		      string_ftype_string_cstring_sizet,
@@ -3423,6 +3427,9 @@ c_common_nodes_and_builtins ()
   builtin_function_2 ("__builtin_fprintf", "fprintf",
 		      fprintf_ftype, fprintf_ftype,
 		      BUILT_IN_FPRINTF, BUILT_IN_FRONTEND, 1, 0, 0);
+  builtin_function_2 ("__builtin_sprintf", "sprintf",
+		      sprintf_ftype, sprintf_ftype,
+		      BUILT_IN_SPRINTF, BUILT_IN_FRONTEND, 1, 0, 0);
   built_in_decls[BUILT_IN_FWRITE] =
     builtin_function ("__builtin_fwrite", fwrite_ftype,
 		      BUILT_IN_FWRITE, BUILT_IN_NORMAL, "fwrite");
@@ -3435,7 +3442,7 @@ c_common_nodes_and_builtins ()
      FILE* in the __builtin_ prototype supplied here.  */
   built_in_decls[BUILT_IN_FPUTS] =
     builtin_function_2 ("__builtin_fputs", "fputs",
-			fputs_ftype, int_ftype_any,
+			fputs_ftype, fputs_ftype,
 			BUILT_IN_FPUTS, BUILT_IN_NORMAL, 1, 0, 0);
 
   /* Declare these functions non-returning
@@ -3539,6 +3546,89 @@ builtin_function_2 (builtin_name, name, 
     }
   return (bdecl != 0 ? bdecl : decl);
 }
+
+
+/* Try to adjust type of built-in function OLDTYPE, so that it can be
+   compatible with NEWTYPE.  Returns a new type if it is desirable to
+   modify the built-in type or NULL_TREE if it cannot be adjusted.
+   This routine replaces the return type of OLDTYPE with return type
+   of NEWTYPE if they have same MODE, or replaces first argument in OLDTYPE
+   with first argument in NEWTYPE if they have same mode, or replaces
+   last argument in OLDTYPE with last argument in NEWTYPE if they are both
+   pointer types.  */
+tree
+adjust_builtin_function_type (newtype, oldtype)
+     tree newtype, oldtype;
+{
+  /* Accept the return type of the new declaration if same modes.  */
+  tree oldreturntype = TREE_TYPE (oldtype);
+  tree newreturntype = TREE_TYPE (newtype);
+  tree trytype = oldtype;
+
+  if (oldreturntype != newreturntype
+      && TYPE_MODE (oldreturntype) == TYPE_MODE (newreturntype))
+    /* Function types may be shared, so we can't just modify
+       the return type of olddecl's function type.  */
+    trytype = build_function_type (newreturntype,
+				   TYPE_ARG_TYPES (trytype));
+
+  /* Accept harmless mismatch in first argument type.
+     This is for the ffs and fprintf builtins.  */
+  if (TYPE_ARG_TYPES (newtype) != 0
+      && TYPE_ARG_TYPES (trytype) != 0
+      && TREE_VALUE (TYPE_ARG_TYPES (newtype)) != 0
+      && TREE_VALUE (TYPE_ARG_TYPES (trytype)) != 0
+      && TREE_VALUE (TYPE_ARG_TYPES (newtype))
+	 != TREE_VALUE (TYPE_ARG_TYPES (trytype))
+      && (TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (newtype)))
+	  == TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (trytype)))))
+    /* Function types may be shared, so we can't just modify
+       the return type of olddecl's function type.  */
+    trytype = build_function_type (TREE_TYPE (trytype),
+				tree_cons (NULL_TREE,
+					   TREE_VALUE (TYPE_ARG_TYPES (newtype)),
+					   TREE_CHAIN (TYPE_ARG_TYPES (trytype))));
+
+  /* And accept harmless mismatch in last argument type also.
+     This is for the fputs builtin.  */
+  if (TYPE_ARG_TYPES (newtype) != 0
+      && TYPE_ARG_TYPES (trytype) != 0)
+    {
+      tree newargs = TREE_CHAIN (TYPE_ARG_TYPES (newtype)), newnext;
+      tree oldargs = TREE_CHAIN (TYPE_ARG_TYPES (trytype)), oldnext;
+
+      while (newargs && oldargs)
+	{
+	  newnext = TREE_CHAIN (newargs);
+	  oldnext = TREE_CHAIN (oldargs);
+	  if (newnext && TREE_VALUE (newnext) == void_type_node
+	      && oldnext && TREE_VALUE (oldnext) == void_type_node)
+	    {
+	      if (TREE_VALUE (newargs) && TREE_VALUE (oldargs)
+		  && TREE_CODE (TREE_VALUE (newargs)) == POINTER_TYPE
+		  && TREE_VALUE (oldargs) == ptr_type_node)
+		{
+		  tree parms, tem, *p = &parms;
+
+		  for (tem = TYPE_ARG_TYPES (trytype); tem != oldargs;
+		       tem = TREE_CHAIN (tem))
+		    {
+		      *p = build_tree_list (NULL_TREE,
+					    TREE_VALUE (tem));
+		      p = &TREE_CHAIN (*p);
+		    }
+		  *p = newargs;
+		  return build_function_type (TREE_TYPE (trytype),
+					      parms);
+		}
+	    }
+	  newargs = newnext;
+	  oldargs = oldnext;
+	}
+    }
+
+  return trytype == oldtype ? NULL_TREE : trytype;
+}
 
 /* Given a type, apply default promotions wrt unnamed function arguments
    and return the new type.  Return NULL_TREE if no change.  */
@@ -4227,6 +4317,12 @@ c_expand_builtin (exp, target, tmode, mo
 	return target;
       break;
 
+    case BUILT_IN_SPRINTF:
+      target = c_expand_builtin_sprintf (arglist, modifier, ignore);
+      if (target)
+	return target;
+      break;
+
     default:			/* just do library call, if unknown builtin */
       error ("built-in function `%s' not currently supported",
 	     IDENTIFIER_POINTER (DECL_NAME (fndecl)));
@@ -4443,6 +4539,88 @@ c_expand_builtin_fprintf (arglist, targe
   return expand_expr (build_function_call (fn, arglist),
 		      (ignore ? const0_rtx : target),
 		      tmode, modifier);
+}
+
+/* If the arguments passed to sprintf are suitable for optimizations,
+   we attempt to transform the call. */
+static rtx
+c_expand_builtin_sprintf (arglist, modifier, ignore)
+     tree arglist;
+     enum expand_modifier modifier;
+     int ignore;
+{
+  tree fn = built_in_decls[BUILT_IN_STRCPY], format_arg;
+  const char *fmt;
+
+  /* If the return value is used, or the replacement _DECL isn't
+     initialized, don't do the transformation. */
+  if (!ignore || !fn)
+    return 0;
+
+  /* Verify the required arguments in the original call. */
+  if (arglist == 0
+      || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
+      || (TREE_CHAIN (arglist) == 0)
+      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) !=
+	  POINTER_TYPE))
+    return 0;
+  
+  /* Check the specifier vs. the parameters. */
+  if (!is_valid_printf_arglist (TREE_CHAIN (arglist)))
+    return 0;
+
+  format_arg = TREE_VALUE (TREE_CHAIN (arglist));
+  fmt = c_getstr (format_arg);
+
+  /* If the format specifier isn't a STRING_CST, punt.  */
+  if (fmt == NULL)
+    return 0;
+
+  /* OK!  We can attempt optimization.  */
+
+  /* If the format specifier was "%s", call __builtin_strcpy(arg1, arg3). */
+  if (strcmp (fmt, "%s") == 0)
+    {
+      tree newarglist
+	= build_tree_list (NULL_TREE,
+			   TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))));
+      arglist = tree_cons (NULL_TREE, TREE_VALUE (arglist), newarglist);
+    }
+  /* If the format specifier was "%c", optimize as
+     *(unsigned char *)arg1 = arg3; ((unsigned char *)arg1)[1] = '\0';  */
+  else if (strcmp (fmt, "%c") == 0)
+    {
+      tree dst, src, ptr;
+
+      ptr = save_expr (fold (build1 (NOP_EXPR, string_type_node,
+				     TREE_VALUE (arglist))));
+      dst = build1 (INDIRECT_REF, unsigned_char_type_node, ptr);
+      src = build1 (NOP_EXPR, unsigned_char_type_node,
+		    TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))));
+      expand_expr (fold (build (MODIFY_EXPR, unsigned_char_type_node,
+				dst, src)), const0_rtx, ptr_mode, modifier);
+      src = build_int_2 (1, 0);
+      TREE_TYPE (src) = string_type_node;
+      dst = build1 (INDIRECT_REF, unsigned_char_type_node,
+		    build (PLUS_EXPR, string_type_node, ptr, src));
+      src = build_int_2 (0, 0);
+      TREE_TYPE (src) = unsigned_char_type_node;
+      return expand_expr (fold (build (MODIFY_EXPR, unsigned_char_type_node,
+				       dst, src)), NULL_RTX, ptr_mode,
+				       modifier);
+    }
+  else
+    {
+     /* We can't handle anything else with % args or %% ... yet. */
+      if (strchr (fmt, '%'))
+	return 0;
+
+      /* When "string" doesn't contain %, replace all cases of
+         sprintf(x,string) with strcpy(x,string).  */
+    }
+
+  return expand_expr (build_function_call (fn, arglist), const0_rtx,
+		      ptr_mode, modifier);
 }
 
 
--- gcc/builtins.c.jj	Fri Mar 30 11:44:42 2001
+++ gcc/builtins.c	Tue Apr 10 17:50:12 2001
@@ -76,8 +76,6 @@ tree built_in_decls[(int) END_BUILTINS] 
 tree (*lang_type_promotes_to) PARAMS ((tree));
 
 static int get_pointer_alignment	PARAMS ((tree, unsigned));
-static tree c_strlen			PARAMS ((tree));
-static const char *c_getstr		PARAMS ((tree));
 static rtx c_readstr			PARAMS ((const char *,
 						 enum machine_mode));
 static int target_char_cast		PARAMS ((tree, char *)); 
@@ -225,12 +223,13 @@ get_pointer_alignment (exp, max_align)
    Unfortunately, string_constant can't access the values of const char
    arrays with initializers, so neither can we do so here.  */
 
-static tree
+tree
 c_strlen (src)
      tree src;
 {
   tree offset_node;
-  int offset, max;
+  int max;
+  HOST_WIDE_INT offset;
   const char *ptr;
 
   src = string_constant (src, &offset_node);
@@ -293,12 +292,13 @@ c_strlen (src)
 /* Return a char pointer for a C string if it is a string constant
    or sum of string constant and integer constant.  */
 
-static const char *
+const char *
 c_getstr (src)
      tree src;
 {
   tree offset_node;
-  int offset, max;
+  int max;
+  HOST_WIDE_INT offset;
   const char *ptr;
 
   src = string_constant (src, &offset_node);
@@ -310,15 +310,12 @@ c_getstr (src)
 
   if (!offset_node)
     offset = 0;
-  else if (TREE_CODE (offset_node) != INTEGER_CST)
+  else if (!host_integerp (offset_node, 1))
     return 0;
   else
     {
-      /* Did we get a long long offset?  If so, punt.  */
-      if (TREE_INT_CST_HIGH (offset_node) != 0)
-	return 0;
       offset = TREE_INT_CST_LOW (offset_node);
-      if (offset < 0 || offset > max)
+      if (offset > max)
 	return 0;
     }
 
@@ -3585,7 +3582,7 @@ expand_builtin (exp, target, subtarget, 
       if (target)
 	return target;
       break;
-      
+
       /* Various hooks for the DWARF 2 __throw routine.  */
     case BUILT_IN_UNWIND_INIT:
       expand_builtin_unwind_init ();
--- gcc/c-format.c.jj	Mon Mar 12 11:44:59 2001
+++ gcc/c-format.c	Tue Apr 10 17:50:12 2001
@@ -1500,6 +1500,7 @@ check_format_info_recurse (status, res, 
      int arg_num;
 {
   int format_length;
+  HOST_WIDE_INT offset;
   const char *format_chars;
   tree array_size = 0;
   tree array_init;
@@ -1589,6 +1590,35 @@ check_format_info_recurse (status, res, 
       return;
     }
 
+  offset = 0;
+  if (TREE_CODE (format_tree) == PLUS_EXPR)
+    {
+      tree arg0, arg1;
+
+      arg0 = TREE_OPERAND (format_tree, 0);
+      arg1 = TREE_OPERAND (format_tree, 1);
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+      if (TREE_CODE (arg1) == INTEGER_CST)
+	format_tree = arg0;
+      else if (TREE_CODE (arg0) == INTEGER_CST)
+	{
+	  format_tree = arg1;
+	  arg1 = arg0;
+	}
+      else
+	{
+	  res->number_non_literal++;
+	  return;
+	}
+      if (!host_integerp (arg1, 1))
+	{
+	  res->number_non_literal++;
+	  return;
+	}
+
+      offset = TREE_INT_CST_LOW (arg1);
+    }
   if (TREE_CODE (format_tree) != ADDR_EXPR)
     {
       res->number_non_literal++;
@@ -1631,6 +1661,16 @@ check_format_info_recurse (status, res, 
 	      && format_length > array_size_value)
 	    format_length = array_size_value;
 	}
+    }
+  if (offset)
+    {
+      if (offset >= format_length)
+	{
+	  res->number_non_literal++;
+	  return;
+	}
+      format_chars += offset;
+      format_length -= offset;
     }
   if (format_length < 1)
     {
--- gcc/c-common.h.jj	Fri Mar 30 11:44:42 2001
+++ gcc/c-common.h	Tue Apr 10 17:50:12 2001
@@ -478,6 +478,7 @@ extern tree (*make_fname_decl)          
 extern tree identifier_global_value		PARAMS ((tree));
 extern void record_builtin_type			PARAMS ((enum rid,
 							 const char *, tree));
+extern tree adjust_builtin_function_type	PARAMS ((tree, tree));
 extern tree build_void_list_node		PARAMS ((void));
 
 extern void declare_function_name		PARAMS ((void));
--- gcc/extend.texi.jj	Fri Mar 23 10:48:59 2001
+++ gcc/extend.texi	Wed Apr 18 16:46:26 2001
@@ -3634,6 +3634,7 @@ function as well.
 @findex sin
 @findex sinf
 @findex sinl
+@findex sprintf
 @findex sqrt
 @findex sqrtf
 @findex sqrtl
@@ -3693,8 +3694,8 @@ corresponding versions prefixed with @co
 The following ISO C89 functions are recognized as builtins unless
 @samp{-fno-builtin} is specified: @code{abs}, @code{cos}, @code{fabs},
 @code{fprintf}, @code{fputs}, @code{labs}, @code{memcmp}, @code{memcpy},
-@code{memset}, @code{printf}, @code{sin}, @code{sqrt}, @code{strcat},
-@code{strchr}, @code{strcmp}, @code{strcpy}, @code{strcspn},
+@code{memset}, @code{printf}, @code{sin}, @code{sprintf}, @code{sqrt},
+@code{strcat}, @code{strchr}, @code{strcmp}, @code{strcpy}, @code{strcspn},
 @code{strlen}, @code{strncat}, @code{strncmp}, @code{strncpy},
 @code{strpbrk}, @code{strrchr}, @code{strspn}, and @code{strstr}.  All
 of these functions have corresponding versions prefixed with

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]