From ad3fd36f73012aa44ee7f55d09a2a2b87ce9dd6e Mon Sep 17 00:00:00 2001 From: "Kaveh R. Ghazi" Date: Tue, 19 Sep 2000 18:19:44 +0000 Subject: [PATCH] builtins.c (is_valid_printf_arglist, [...]): New functions. * builtins.c (is_valid_printf_arglist, expand_builtin_printf): New functions. (expand_builtin_fputs): Set `target' parameter for `expand_expr'. (expand_builtin): Handle BUILT_IN_PUTCHAR, BUILT_IN_PUTS and BUILT_IN_PRINTF. * builtins.def (BUILT_IN_PUTCHAR, BUILT_IN_PUTS, BUILT_IN_PRINTF): New entries. * c-common.c (init_function_format_info): Handle __builtin_printf. Set `check_function_format_ptr'. (c_common_nodes_and_builtins): Set `puts_ftype' and `printf_ftype'. Declare __builtin_putchar, __builtin_puts, __builtin_printf and printf. * tree.c, tree.h (check_function_format_ptr): Declare. testsuite: * g++.old-deja/g++.other/virtual8.C: Declare printf correctly. From-SVN: r36540 --- gcc/ChangeLog | 19 +++ gcc/builtins.c | 131 +++++++++++++++++- gcc/builtins.def | 3 + gcc/c-common.c | 28 +++- gcc/testsuite/ChangeLog | 4 + .../g++.old-deja/g++.other/virtual8.C | 2 +- gcc/tree.c | 4 + gcc/tree.h | 3 + 8 files changed, 190 insertions(+), 4 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 26a280150e7..35b182249f0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2000-09-19 Kaveh R. Ghazi + + * builtins.c (is_valid_printf_arglist, expand_builtin_printf): New + functions. + (expand_builtin_fputs): Set `target' parameter for `expand_expr'. + (expand_builtin): Handle BUILT_IN_PUTCHAR, BUILT_IN_PUTS and + BUILT_IN_PRINTF. + + * builtins.def (BUILT_IN_PUTCHAR, BUILT_IN_PUTS, BUILT_IN_PRINTF): + New entries. + + * c-common.c (init_function_format_info): Handle __builtin_printf. + Set `check_function_format_ptr'. + (c_common_nodes_and_builtins): Set `puts_ftype' and + `printf_ftype'. Declare __builtin_putchar, __builtin_puts, + __builtin_printf and printf. + + * tree.c, tree.h (check_function_format_ptr): Declare. + Tue 19-Sep-2000 18:26:57 BST Neil Booth * cppfiles.c (read_include_file): Take no special action for diff --git a/gcc/builtins.c b/gcc/builtins.c index 2983b2bdbcc..05297230825 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -111,6 +111,8 @@ static rtx expand_builtin_strlen PARAMS ((tree, rtx, static rtx expand_builtin_alloca PARAMS ((tree, rtx)); static rtx expand_builtin_ffs PARAMS ((tree, rtx, rtx)); static rtx expand_builtin_frame_address PARAMS ((tree)); +static int is_valid_printf_arglist PARAMS ((tree)); +static rtx expand_builtin_printf PARAMS ((tree, int)); static rtx expand_builtin_fputs PARAMS ((tree, int)); static tree stabilize_va_list PARAMS ((tree, int)); static rtx expand_builtin_expect PARAMS ((tree, rtx)); @@ -2367,7 +2369,122 @@ expand_builtin_fputs (arglist, ignore) call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), call_expr, newarglist, NULL_TREE); TREE_SIDE_EFFECTS (call_expr) = 1; - return expand_expr (call_expr, NULL_RTX, VOIDmode, 0); + return expand_expr (call_expr, (ignore ? const0_rtx : NULL_RTX), + VOIDmode, EXPAND_NORMAL); +} + +/* Check an arglist to *printf for problems. The arglist should start + at the format specifier, with the remaining arguments immediately + following it. */ +static int +is_valid_printf_arglist (arglist) + tree arglist; +{ + /* Save this value so we can restore it later. */ + const int SAVE_pedantic = pedantic; + int diagnostic_occurred = 0; + + /* If we can't check the format, be safe and return false. */ + if (!check_function_format_ptr) + return 0; + + /* Set this to a known value so the user setting won't affect code + generation. */ + pedantic = 1; + /* Check to make sure there are no format specifier errors. */ + check_function_format_ptr (&diagnostic_occurred, + maybe_get_identifier("printf"), + NULL_TREE, arglist); + + /* Restore the value of `pedantic'. */ + pedantic = SAVE_pedantic; + + /* If calling `check_function_format_ptr' produces a warning, we + return false, otherwise we return true. */ + return ! diagnostic_occurred; +} + +/* If the arguments passed to printf are suitable for optimizations, + we attempt to transform the call. */ +static rtx +expand_builtin_printf (arglist, ignore) + tree arglist; + int ignore; +{ + tree fn_putchar = built_in_decls[BUILT_IN_PUTCHAR], + fn_puts = built_in_decls[BUILT_IN_PUTS]; + tree call_expr, fn; + tree format_arg, stripped_string; + + /* If the return value is used, or the replacement _DECL isn't + initialized, don't do the transformation. */ + if (!ignore || !fn_putchar || !fn_puts) + return 0; + + /* Verify the required arguments in the original call. */ + if (arglist == 0 + || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)) + return 0; + + /* Check the specifier vs. the parameters. */ + if (!is_valid_printf_arglist (arglist)) + return 0; + + format_arg = TREE_VALUE (arglist); + stripped_string = format_arg; + STRIP_NOPS (stripped_string); + if (stripped_string && TREE_CODE (stripped_string) == ADDR_EXPR) + stripped_string = TREE_OPERAND (stripped_string, 0); + + /* If the format specifier isn't a STRING_CST, punt. */ + if (TREE_CODE (stripped_string) != STRING_CST) + return 0; + + /* OK! We can attempt optimization. */ + + /* If the format specifier was "%s\n", call __builtin_puts(arg2). */ + if (strcmp (TREE_STRING_POINTER (stripped_string), "%s\n") == 0) + { + arglist = TREE_CHAIN (arglist); + fn = fn_puts; + } + /* If the format specifier was "%c", call __builtin_putchar (arg2). */ + else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0) + { + arglist = TREE_CHAIN (arglist); + fn = fn_putchar; + } + else + { + /* We can't handle anything else with % args or %% ... yet. */ + if (strchr (TREE_STRING_POINTER (stripped_string), '%')) + return 0; + + /* If the resulting constant string has a length of 1, call + putchar. Note, TREE_STRING_LENGTH includes the terminating + NULL in its count. */ + if (TREE_STRING_LENGTH (stripped_string) == 2) + { + /* Given printf("c"), (where c is any one character,) + convert "c"[0] to an int and pass that to the replacement + function. */ + arglist = build_int_2 (TREE_STRING_POINTER (stripped_string)[0], 0); + arglist = build_tree_list (NULL_TREE, arglist); + + fn = fn_putchar; + } + else + /* We'd like to arrange to call fputs(string) here, but we + need stdout and don't have a way to get it ... yet. */ + return 0; + } + + call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn); + call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), + call_expr, arglist, NULL_TREE); + TREE_SIDE_EFFECTS (call_expr) = 1; + return expand_expr (call_expr, (ignore ? const0_rtx : NULL_RTX), + VOIDmode, EXPAND_NORMAL); } /* Expand a call to __builtin_expect. We return our argument and @@ -2444,7 +2561,9 @@ expand_builtin (exp, target, subtarget, mode, ignore) || fcode == BUILT_IN_BCMP || fcode == BUILT_IN_BZERO || fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY || fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS - || fcode == BUILT_IN_FPUTC || fcode == BUILT_IN_FPUTS)) + || fcode == BUILT_IN_PUTCHAR || fcode == BUILT_IN_PUTS + || fcode == BUILT_IN_PRINTF || fcode == BUILT_IN_FPUTC + || fcode == BUILT_IN_FPUTS)) return expand_call (exp, target, ignore); switch (fcode) @@ -2657,6 +2776,8 @@ expand_builtin (exp, target, subtarget, mode, ignore) emit_barrier (); return const0_rtx; + case BUILT_IN_PUTCHAR: + case BUILT_IN_PUTS: case BUILT_IN_FPUTC: break; @@ -2666,6 +2787,12 @@ expand_builtin (exp, target, subtarget, mode, ignore) return target; break; + case BUILT_IN_PRINTF: + target = expand_builtin_printf (arglist, ignore); + if (target) + return target; + break; + /* Various hooks for the DWARF 2 __throw routine. */ case BUILT_IN_UNWIND_INIT: expand_builtin_unwind_init (); diff --git a/gcc/builtins.def b/gcc/builtins.def index 40ae59c3d73..7220cf9124c 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -59,6 +59,9 @@ DEF_BUILTIN(BUILT_IN_LONGJMP) DEF_BUILTIN(BUILT_IN_TRAP) /* Stdio builtins. */ +DEF_BUILTIN(BUILT_IN_PUTCHAR) +DEF_BUILTIN(BUILT_IN_PUTS) +DEF_BUILTIN(BUILT_IN_PRINTF) DEF_BUILTIN(BUILT_IN_FPUTC) DEF_BUILTIN(BUILT_IN_FPUTS) diff --git a/gcc/c-common.c b/gcc/c-common.c index 5ede422d311..fec74eb69ef 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -1566,6 +1566,8 @@ init_function_format_info () /* Functions from ISO/IEC 9899:1990. */ record_function_format (get_identifier ("printf"), NULL_TREE, printf_format_type, 1, 2); + record_function_format (get_identifier ("__builtin_printf"), NULL_TREE, + printf_format_type, 1, 2); record_function_format (get_identifier ("fprintf"), NULL_TREE, printf_format_type, 2, 3); record_function_format (get_identifier ("sprintf"), NULL_TREE, @@ -1608,6 +1610,8 @@ init_function_format_info () record_international_format (get_identifier ("dgettext"), NULL_TREE, 2); record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2); } + + check_function_format_ptr = check_function_format; } /* Record information for argument format checking. FUNCTION_IDENT is @@ -4006,7 +4010,7 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins) { tree temp; tree memcpy_ftype, memset_ftype, strlen_ftype; - tree bzero_ftype, bcmp_ftype; + tree bzero_ftype, bcmp_ftype, puts_ftype, printf_ftype; tree endlink, int_endlink, double_endlink, unsigned_endlink; tree sizetype_endlink; tree ptr_ftype, ptr_ftype_unsigned; @@ -4162,6 +4166,18 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins) traditional_cptr_type_node, traditional_len_endlink))); + /* Prototype for puts. */ + puts_ftype + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, const_string_type_node, + endlink)); + + /* Prototype for printf. */ + printf_ftype + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, const_string_type_node, + NULL_TREE)); + builtin_function ("__builtin_constant_p", default_function_type, BUILT_IN_CONSTANT_P, BUILT_IN_NORMAL, NULL_PTR); @@ -4348,6 +4364,14 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins) BUILT_IN_COS, BUILT_IN_NORMAL, "cos"); builtin_function ("__builtin_cosl", ldouble_ftype_ldouble, BUILT_IN_COS, BUILT_IN_NORMAL, "cosl"); + built_in_decls[BUILT_IN_PUTCHAR] = + builtin_function ("__builtin_putchar", int_ftype_int, + BUILT_IN_PUTCHAR, BUILT_IN_NORMAL, "putchar"); + built_in_decls[BUILT_IN_PUTS] = + builtin_function ("__builtin_puts", puts_ftype, + BUILT_IN_PUTS, BUILT_IN_NORMAL, "puts"); + builtin_function ("__builtin_printf", printf_ftype, + BUILT_IN_PRINTF, BUILT_IN_NORMAL, "printf"); /* We declare these without argument so that the initial declaration for these identifiers is a builtin. That allows us to redeclare them later with argument without worrying about the explicit @@ -4402,6 +4426,8 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins) BUILT_IN_NORMAL, NULL_PTR); builtin_function ("cosl", ldouble_ftype_ldouble, BUILT_IN_COS, BUILT_IN_NORMAL, NULL_PTR); + builtin_function ("printf", printf_ftype, BUILT_IN_PRINTF, + BUILT_IN_NORMAL, NULL_PTR); /* We declare these without argument so that the initial declaration for these identifiers is a builtin. That allows us to redeclare them later with argument without worrying diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 34c2553cdca..d32659ba898 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2000-09-19 Kaveh R. Ghazi + + * g++.old-deja/g++.other/virtual8.C: Declare printf correctly. + 2000-09-19 Richard Henderson * gcc.dg/compare2.c (case 10): XFAIL. diff --git a/gcc/testsuite/g++.old-deja/g++.other/virtual8.C b/gcc/testsuite/g++.old-deja/g++.other/virtual8.C index 9f32ca082fc..32c8e54cc28 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/virtual8.C +++ b/gcc/testsuite/g++.old-deja/g++.other/virtual8.C @@ -1,4 +1,4 @@ -extern "C" void printf (const char*, ...); +extern "C" int printf (const char*, ...); struct A { diff --git a/gcc/tree.c b/gcc/tree.c index 3f8d7c67c3f..ef27a78a17f 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -246,6 +246,10 @@ static int next_decl_uid; /* Unique id for next type created. */ static int next_type_uid = 1; +/* Pointer to function to check the format of printf, etc. This is + used by the backend, e.g. builtins.c. */ +void (*check_function_format_ptr) PARAMS ((int *, tree, tree, tree)) = 0; + /* Here is how primitive or already-canonicalized types' hash codes are made. */ #define TYPE_HASH(TYPE) ((unsigned long) (TYPE) & 0777777) diff --git a/gcc/tree.h b/gcc/tree.h index 2c5ad0aee73..f55b4b640e3 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2441,6 +2441,9 @@ extern const char * const language_string; extern tree builtin_function PARAMS ((const char *, tree, int, enum built_in_class, const char *)); +/* Pointer to function to check the format of printf, etc. This is + used by the backend, e.g. builtins.c. */ +extern void (*check_function_format_ptr) PARAMS ((int *, tree, tree, tree)); /* In tree.c */ extern char *perm_calloc PARAMS ((int, long)); -- 2.30.2