Commit 000ba23d by Kaveh R. Ghazi Committed by Kaveh Ghazi

re PR middle-end/20109 (printf optimizations and non-ASCII character sets)

	PR middle-end/20109
	PR middle-end/25120
	* builtins.c (init_target_chars): New.
	(expand_builtin_printf, expand_builtin_fprintf,
	expand_builtin_sprintf, fold_builtin_sprintf,
	maybe_emit_sprintf_chk_warning, fold_builtin_sprintf_chk,
	fold_builtin_snprintf_chk, fold_builtin_printf,
	fold_builtin_fprintf): Check for matching format strings using
	the target charset.
	
testsuite:
	* gcc.dg/charset/builtin2.c: New test.

From-SVN: r107652
parent 8fdb0857
2005-11-29 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
PR middle-end/20109
PR middle-end/25120
* builtins.c (init_target_chars): New.
(expand_builtin_printf, expand_builtin_fprintf,
expand_builtin_sprintf, fold_builtin_sprintf,
maybe_emit_sprintf_chk_warning, fold_builtin_sprintf_chk,
fold_builtin_snprintf_chk, fold_builtin_printf,
fold_builtin_fprintf): Check for matching format strings using
the target charset.
2005-11-29 Paul Brook <paul@codesourcery.com> 2005-11-29 Paul Brook <paul@codesourcery.com>
* config.gcc: Do not use fixproto on m68k-elf. * config.gcc: Do not use fixproto on m68k-elf.
......
...@@ -199,6 +199,15 @@ static tree fold_builtin_strncat_chk (tree, tree); ...@@ -199,6 +199,15 @@ static tree fold_builtin_strncat_chk (tree, tree);
static tree fold_builtin_sprintf_chk (tree, enum built_in_function); static tree fold_builtin_sprintf_chk (tree, enum built_in_function);
static tree fold_builtin_printf (tree, tree, bool, enum built_in_function); static tree fold_builtin_printf (tree, tree, bool, enum built_in_function);
static tree fold_builtin_fprintf (tree, tree, bool, enum built_in_function); static tree fold_builtin_fprintf (tree, tree, bool, enum built_in_function);
static bool init_target_chars (void);
static unsigned HOST_WIDE_INT target_newline;
static unsigned HOST_WIDE_INT target_percent;
static unsigned HOST_WIDE_INT target_c;
static unsigned HOST_WIDE_INT target_s;
static char target_percent_c[3];
static char target_percent_s[3];
static char target_percent_s_newline[4];
/* Return true if NODE should be considered for inline expansion regardless /* Return true if NODE should be considered for inline expansion regardless
of the optimization level. This means whenever a function is invoked with of the optimization level. This means whenever a function is invoked with
...@@ -4869,8 +4878,11 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, ...@@ -4869,8 +4878,11 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
if (fmt_str == NULL) if (fmt_str == NULL)
return 0; return 0;
if (!init_target_chars())
return 0;
/* If the format specifier was "%s\n", call __builtin_puts(arg). */ /* If the format specifier was "%s\n", call __builtin_puts(arg). */
if (strcmp (fmt_str, "%s\n") == 0) if (strcmp (fmt_str, target_percent_s_newline) == 0)
{ {
if (! arglist if (! arglist
|| ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist))) || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
...@@ -4879,7 +4891,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, ...@@ -4879,7 +4891,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
fn = fn_puts; fn = fn_puts;
} }
/* If the format specifier was "%c", call __builtin_putchar(arg). */ /* If the format specifier was "%c", call __builtin_putchar(arg). */
else if (strcmp (fmt_str, "%c") == 0) else if (strcmp (fmt_str, target_percent_c) == 0)
{ {
if (! arglist if (! arglist
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
...@@ -4890,7 +4902,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, ...@@ -4890,7 +4902,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
else else
{ {
/* We can't handle anything else with % args or %% ... yet. */ /* We can't handle anything else with % args or %% ... yet. */
if (strchr (fmt_str, '%')) if (strchr (fmt_str, target_percent))
return 0; return 0;
if (arglist) if (arglist)
...@@ -4913,7 +4925,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode, ...@@ -4913,7 +4925,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
{ {
/* If the format specifier was "string\n", call puts("string"). */ /* If the format specifier was "string\n", call puts("string"). */
size_t len = strlen (fmt_str); size_t len = strlen (fmt_str);
if (fmt_str[len - 1] == '\n') if ((unsigned char)fmt_str[len - 1] == target_newline)
{ {
/* Create a NUL-terminated string that's one char shorter /* Create a NUL-terminated string that's one char shorter
than the original, stripping off the trailing '\n'. */ than the original, stripping off the trailing '\n'. */
...@@ -4982,8 +4994,11 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, ...@@ -4982,8 +4994,11 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
if (fmt_str == NULL) if (fmt_str == NULL)
return 0; return 0;
if (!init_target_chars())
return 0;
/* If the format specifier was "%s", call __builtin_fputs(arg,fp). */ /* If the format specifier was "%s", call __builtin_fputs(arg,fp). */
if (strcmp (fmt_str, "%s") == 0) if (strcmp (fmt_str, target_percent_s) == 0)
{ {
if (! arglist if (! arglist
|| ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist))) || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
...@@ -4995,7 +5010,7 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, ...@@ -4995,7 +5010,7 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
fn = fn_fputs; fn = fn_fputs;
} }
/* If the format specifier was "%c", call __builtin_fputc(arg,fp). */ /* If the format specifier was "%c", call __builtin_fputc(arg,fp). */
else if (strcmp (fmt_str, "%c") == 0) else if (strcmp (fmt_str, target_percent_c) == 0)
{ {
if (! arglist if (! arglist
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
...@@ -5009,7 +5024,7 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode, ...@@ -5009,7 +5024,7 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
else else
{ {
/* We can't handle anything else with % args or %% ... yet. */ /* We can't handle anything else with % args or %% ... yet. */
if (strchr (fmt_str, '%')) if (strchr (fmt_str, target_percent))
return 0; return 0;
if (arglist) if (arglist)
...@@ -5071,8 +5086,11 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) ...@@ -5071,8 +5086,11 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
if (fmt_str == NULL) if (fmt_str == NULL)
return 0; return 0;
if (!init_target_chars())
return 0;
/* If the format doesn't contain % args or %%, use strcpy. */ /* If the format doesn't contain % args or %%, use strcpy. */
if (strchr (fmt_str, '%') == 0) if (strchr (fmt_str, target_percent) == 0)
{ {
tree fn = implicit_built_in_decls[BUILT_IN_STRCPY]; tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
tree exp; tree exp;
...@@ -5087,7 +5105,7 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) ...@@ -5087,7 +5105,7 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
return expand_expr (exp, target, mode, EXPAND_NORMAL); return expand_expr (exp, target, mode, EXPAND_NORMAL);
} }
/* If the format is "%s", use strcpy if the result isn't used. */ /* If the format is "%s", use strcpy if the result isn't used. */
else if (strcmp (fmt_str, "%s") == 0) else if (strcmp (fmt_str, target_percent_s) == 0)
{ {
tree fn, arg, len; tree fn, arg, len;
fn = implicit_built_in_decls[BUILT_IN_STRCPY]; fn = implicit_built_in_decls[BUILT_IN_STRCPY];
...@@ -9790,8 +9808,11 @@ fold_builtin_sprintf (tree arglist, int ignored) ...@@ -9790,8 +9808,11 @@ fold_builtin_sprintf (tree arglist, int ignored)
call = NULL_TREE; call = NULL_TREE;
retval = NULL_TREE; retval = NULL_TREE;
if (!init_target_chars())
return 0;
/* If the format doesn't contain % args or %%, use strcpy. */ /* If the format doesn't contain % args or %%, use strcpy. */
if (strchr (fmt_str, '%') == NULL) if (strchr (fmt_str, target_percent) == NULL)
{ {
tree fn = implicit_built_in_decls[BUILT_IN_STRCPY]; tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
...@@ -9808,7 +9829,7 @@ fold_builtin_sprintf (tree arglist, int ignored) ...@@ -9808,7 +9829,7 @@ fold_builtin_sprintf (tree arglist, int ignored)
} }
/* If the format is "%s", use strcpy if the result isn't used. */ /* If the format is "%s", use strcpy if the result isn't used. */
else if (fmt_str && strcmp (fmt_str, "%s") == 0) else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
{ {
tree fn, orig; tree fn, orig;
fn = implicit_built_in_decls[BUILT_IN_STRCPY]; fn = implicit_built_in_decls[BUILT_IN_STRCPY];
...@@ -10105,12 +10126,15 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode) ...@@ -10105,12 +10126,15 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
if (fmt_str == NULL) if (fmt_str == NULL)
return; return;
if (!init_target_chars())
return;
/* If the format doesn't contain % args or %%, we know its size. */ /* If the format doesn't contain % args or %%, we know its size. */
if (strchr (fmt_str, '%') == 0) if (strchr (fmt_str, target_percent) == 0)
len = build_int_cstu (size_type_node, strlen (fmt_str)); len = build_int_cstu (size_type_node, strlen (fmt_str));
/* If the format is "%s" and first ... argument is a string literal, /* If the format is "%s" and first ... argument is a string literal,
we know it too. */ we know it too. */
else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, "%s") == 0) else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0)
{ {
tree arg; tree arg;
...@@ -10565,19 +10589,22 @@ fold_builtin_sprintf_chk (tree arglist, enum built_in_function fcode) ...@@ -10565,19 +10589,22 @@ fold_builtin_sprintf_chk (tree arglist, enum built_in_function fcode)
len = NULL_TREE; len = NULL_TREE;
if (!init_target_chars())
return 0;
/* Check whether the format is a literal string constant. */ /* Check whether the format is a literal string constant. */
fmt_str = c_getstr (fmt); fmt_str = c_getstr (fmt);
if (fmt_str != NULL) if (fmt_str != NULL)
{ {
/* If the format doesn't contain % args or %%, we know the size. */ /* If the format doesn't contain % args or %%, we know the size. */
if (strchr (fmt_str, '%') == 0) if (strchr (fmt_str, target_percent) == 0)
{ {
if (fcode != BUILT_IN_SPRINTF_CHK || arglist == NULL_TREE) if (fcode != BUILT_IN_SPRINTF_CHK || arglist == NULL_TREE)
len = build_int_cstu (size_type_node, strlen (fmt_str)); len = build_int_cstu (size_type_node, strlen (fmt_str));
} }
/* If the format is "%s" and first ... argument is a string literal, /* If the format is "%s" and first ... argument is a string literal,
we know the size too. */ we know the size too. */
else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, "%s") == 0) else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0)
{ {
tree arg; tree arg;
...@@ -10606,7 +10633,7 @@ fold_builtin_sprintf_chk (tree arglist, enum built_in_function fcode) ...@@ -10606,7 +10633,7 @@ fold_builtin_sprintf_chk (tree arglist, enum built_in_function fcode)
{ {
if (fmt_str == NULL) if (fmt_str == NULL)
return 0; return 0;
if (strchr (fmt_str, '%') != NULL && strcmp (fmt_str, "%s")) if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s))
return 0; return 0;
} }
...@@ -10687,6 +10714,9 @@ fold_builtin_snprintf_chk (tree arglist, tree maxlen, ...@@ -10687,6 +10714,9 @@ fold_builtin_snprintf_chk (tree arglist, tree maxlen,
return 0; return 0;
} }
if (!init_target_chars())
return 0;
/* Only convert __{,v}snprintf_chk to {,v}snprintf if flag is 0 /* Only convert __{,v}snprintf_chk to {,v}snprintf if flag is 0
or if format doesn't contain % chars or is "%s". */ or if format doesn't contain % chars or is "%s". */
if (! integer_zerop (flag)) if (! integer_zerop (flag))
...@@ -10694,7 +10724,7 @@ fold_builtin_snprintf_chk (tree arglist, tree maxlen, ...@@ -10694,7 +10724,7 @@ fold_builtin_snprintf_chk (tree arglist, tree maxlen,
fmt_str = c_getstr (fmt); fmt_str = c_getstr (fmt);
if (fmt_str == NULL) if (fmt_str == NULL)
return 0; return 0;
if (strchr (fmt_str, '%') != NULL && strcmp (fmt_str, "%s")) if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s))
return 0; return 0;
} }
...@@ -10768,11 +10798,14 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore, ...@@ -10768,11 +10798,14 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore,
fn_puts = implicit_built_in_decls[BUILT_IN_PUTS]; fn_puts = implicit_built_in_decls[BUILT_IN_PUTS];
} }
if (strcmp (fmt_str, "%s") == 0 || strchr (fmt_str, '%') == NULL) if (!init_target_chars())
return 0;
if (strcmp (fmt_str, target_percent_s) == 0 || strchr (fmt_str, target_percent) == NULL)
{ {
const char *str; const char *str;
if (strcmp (fmt_str, "%s") == 0) if (strcmp (fmt_str, target_percent_s) == 0)
{ {
if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK) if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
return 0; return 0;
...@@ -10813,7 +10846,7 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore, ...@@ -10813,7 +10846,7 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore,
{ {
/* If the string was "string\n", call puts("string"). */ /* If the string was "string\n", call puts("string"). */
size_t len = strlen (str); size_t len = strlen (str);
if (str[len - 1] == '\n') if ((unsigned char)str[len - 1] == target_newline)
{ {
/* Create a NUL-terminated string that's one char shorter /* Create a NUL-terminated string that's one char shorter
than the original, stripping off the trailing '\n'. */ than the original, stripping off the trailing '\n'. */
...@@ -10837,7 +10870,7 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore, ...@@ -10837,7 +10870,7 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore,
return 0; return 0;
/* If the format specifier was "%s\n", call __builtin_puts(arg). */ /* If the format specifier was "%s\n", call __builtin_puts(arg). */
else if (strcmp (fmt_str, "%s\n") == 0) else if (strcmp (fmt_str, target_percent_s_newline) == 0)
{ {
if (! arglist if (! arglist
|| ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist))) || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
...@@ -10847,7 +10880,7 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore, ...@@ -10847,7 +10880,7 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore,
} }
/* If the format specifier was "%c", call __builtin_putchar(arg). */ /* If the format specifier was "%c", call __builtin_putchar(arg). */
else if (strcmp (fmt_str, "%c") == 0) else if (strcmp (fmt_str, target_percent_c) == 0)
{ {
if (! arglist if (! arglist
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
...@@ -10926,8 +10959,11 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore, ...@@ -10926,8 +10959,11 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore,
fn_fputs = implicit_built_in_decls[BUILT_IN_FPUTS]; fn_fputs = implicit_built_in_decls[BUILT_IN_FPUTS];
} }
if (!init_target_chars())
return 0;
/* If the format doesn't contain % args or %%, use strcpy. */ /* If the format doesn't contain % args or %%, use strcpy. */
if (strchr (fmt_str, '%') == NULL) if (strchr (fmt_str, target_percent) == NULL)
{ {
if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK
&& arglist) && arglist)
...@@ -10957,7 +10993,7 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore, ...@@ -10957,7 +10993,7 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore,
return 0; return 0;
/* If the format specifier was "%s", call __builtin_fputs (arg, fp). */ /* If the format specifier was "%s", call __builtin_fputs (arg, fp). */
else if (strcmp (fmt_str, "%s") == 0) else if (strcmp (fmt_str, target_percent_s) == 0)
{ {
if (! arglist if (! arglist
|| ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist))) || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
...@@ -10970,7 +11006,7 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore, ...@@ -10970,7 +11006,7 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore,
} }
/* If the format specifier was "%c", call __builtin_fputc (arg, fp). */ /* If the format specifier was "%c", call __builtin_fputc (arg, fp). */
else if (strcmp (fmt_str, "%c") == 0) else if (strcmp (fmt_str, target_percent_c) == 0)
{ {
if (! arglist if (! arglist
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
...@@ -10988,3 +11024,37 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore, ...@@ -10988,3 +11024,37 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore,
call = build_function_call_expr (fn, arglist); call = build_function_call_expr (fn, arglist);
return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call); return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call);
} }
/* Initialize format string characters in the target charset. */
static bool
init_target_chars (void)
{
static bool init;
if (!init)
{
target_newline = lang_hooks.to_target_charset ('\n');
target_percent = lang_hooks.to_target_charset ('%');
target_c = lang_hooks.to_target_charset ('c');
target_s = lang_hooks.to_target_charset ('s');
if (target_newline == 0 || target_percent == 0 || target_c == 0
|| target_s == 0)
return false;
target_percent_c[0] = target_percent;
target_percent_c[1] = target_c;
target_percent_c[2] = '\0';
target_percent_s[0] = target_percent;
target_percent_s[1] = target_s;
target_percent_s[2] = '\0';
target_percent_s_newline[0] = target_percent;
target_percent_s_newline[1] = target_s;
target_percent_s_newline[2] = target_newline;
target_percent_s_newline[3] = '\0';
init = true;
}
return true;
}
2005-11-29 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gcc.dg/charset/builtin2.c: New test.
2005-11-28 Jakub Jelinek <jakub@redhat.com> 2005-11-28 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/compat/struct-layout-1_generate.c: Add -w option * gcc.dg/compat/struct-layout-1_generate.c: Add -w option
/* Ensure that transformations of *printf are performed correctly
regardless of -fexec-charset. See PR 25120. */
/* { dg-do compile } */
/* { dg-require-iconv "IBM1047" } */
/* { dg-options "-O2 -fexec-charset=IBM1047" } */
/* { dg-final { scan-assembler-not "printf" } } */
/* { dg-final { scan-assembler-not "fprintf" } } */
/* { dg-final { scan-assembler-not "sprintf" } } */
#include <stdio.h>
void foo (char *dst, const char *src)
{
printf ("\n");
printf ("hello world\n");
printf ("%s", "\n");
printf ("%s", "hello world\n");
printf ("%c", '\n');
printf ("%s\n", "hello world");
printf ("%s\n", src);
fprintf (stdout, "\n");
fprintf (stdout, "hello world\n");
fprintf (stdout, "%s", "\n");
fprintf (stdout, "%s", "hello world\n");
fprintf (stdout, "%c", '\n');
fprintf (stdout, "%s", src);
sprintf (dst, "hello world\n");
sprintf (dst, "%s", src);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment