This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Optimize sprintf into strcpy if possible (take 3)
- To: gcc-patches at gcc dot gnu dot org
- Subject: [PATCH] Optimize sprintf into strcpy if possible (take 3)
- From: Jakub Jelinek <jakub at redhat dot com>
- Date: Wed, 18 Apr 2001 16:04:17 +0200
- Reply-To: Jakub Jelinek <jakub at redhat dot com>
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