aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorKaveh R. Ghazi <ghazi@caip.rutgers.edu>2000-09-19 18:19:44 +0000
committerKaveh Ghazi <ghazi@gcc.gnu.org>2000-09-19 18:19:44 +0000
commitad3fd36f73012aa44ee7f55d09a2a2b87ce9dd6e (patch)
tree61dfe2eae6401356a44aaf263dd08431cc930e4e /gcc
parent6f3d20a02285d63fa46862f6fffda3153956f246 (diff)
downloadgcc-ad3fd36f73012aa44ee7f55d09a2a2b87ce9dd6e.zip
gcc-ad3fd36f73012aa44ee7f55d09a2a2b87ce9dd6e.tar.gz
gcc-ad3fd36f73012aa44ee7f55d09a2a2b87ce9dd6e.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog19
-rw-r--r--gcc/builtins.c131
-rw-r--r--gcc/builtins.def3
-rw-r--r--gcc/c-common.c28
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/virtual8.C2
-rw-r--r--gcc/tree.c4
-rw-r--r--gcc/tree.h3
8 files changed, 190 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 26a2801..35b1822 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,22 @@
+2000-09-19 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * 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 <NeilB@earthling.net>
* cppfiles.c (read_include_file): Take no special action for
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 2983b2b..0529723 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 40ae59c..7220cf9 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 5ede422..fec74eb 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 34c2553..d32659b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2000-09-19 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * g++.old-deja/g++.other/virtual8.C: Declare printf correctly.
+
2000-09-19 Richard Henderson <rth@cygnus.com>
* 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 9f32ca0..32c8e54 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 3f8d7c6..ef27a78 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 2c5ad0a..f55b4b6 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));