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] |
Hi! This patch optimizes sprintf (x, "%s", y) into strcpy (x, y) and also sprintf (x, "foowithoutpercentcharacter") into strcpy (x, "foo...."). While writing the testcase, I noticed format checker would not check some format arguments which c_getstr handles, so I've added them in. Bootstrapped on i386-redhat-linux, no regressions. Ok for mainline? 2001-04-06 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. * 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. * gcc.c-torture/execute/string-opt-13.c: New test. --- gcc/builtins.def.jj Fri Mar 30 11:44:42 2001 +++ gcc/builtins.def Fri Apr 6 18:38:26 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/c-common.c.jj Fri Mar 30 11:44:42 2001 +++ gcc/c-common.c Fri Apr 6 19:22:18 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,13 +3330,15 @@ 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); - builtin_function_2 ("__builtin_strncpy", "strncpy", - string_ftype_string_cstring_sizet, - string_ftype_string_cstring_sizet, - BUILT_IN_STRNCPY, 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); + built_in_decls[BUILT_IN_STRNCPY] = + builtin_function_2 ("__builtin_strncpy", "strncpy", + string_ftype_string_cstring_sizet, + string_ftype_string_cstring_sizet, + BUILT_IN_STRNCPY, BUILT_IN_NORMAL, 1, 0, 0); built_in_decls[BUILT_IN_STRCAT] = builtin_function_2 ("__builtin_strcat", "strcat", string_ftype_string_cstring, @@ -3423,6 +3428,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"); @@ -4227,6 +4235,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 +4457,65 @@ 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); + } + 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 Fri Apr 6 20:16:46 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/expr.h.jj Thu Apr 5 00:12:39 2001 +++ gcc/expr.h Fri Apr 6 19:23:37 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-format.c.jj Mon Mar 12 11:44:59 2001 +++ gcc/c-format.c Fri Apr 6 20:16:46 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/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 Fri Apr 6 19:05:34 2001 @@ -0,0 +1,51 @@ +/* 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 (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, "oobarz", 7 != 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 Jakub
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |