diff options
author | Roger Sayle <roger@eyesopen.com> | 2003-07-24 21:04:12 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2003-07-24 21:04:12 +0000 |
commit | 868b8cda7b2c89629d7c642db03dae1e913fdd3c (patch) | |
tree | b05c49149bd1ed00301b62af2657b2f3d047bc0d /gcc | |
parent | 2a868ea448b0730a00817462c13182b1c1d52c22 (diff) | |
download | gcc-868b8cda7b2c89629d7c642db03dae1e913fdd3c.zip gcc-868b8cda7b2c89629d7c642db03dae1e913fdd3c.tar.gz gcc-868b8cda7b2c89629d7c642db03dae1e913fdd3c.tar.bz2 |
builtins.def (BUILT_IN_PRINTF, [...]): Changed from front-end builtins to normal builtins, using DEF_LIB_BUILTIN.
* builtins.def (BUILT_IN_PRINTF, BUILT_IN_FPRINTF): Changed from
front-end builtins to normal builtins, using DEF_LIB_BUILTIN.
(BUILT_IN_PRINTF_UNLOCKED, BUILT_IN_FPRINTF_UNLOCKED): Changed
from front-end to normal builtins, using DEF_EXT_LIB_BUILTIN.
(DEF_FRONT_END_LIB_BUILTIN): Delete.
(DEF_EXT_FRONT_END_LIB_BUILTIN): Delete.
(BUILT_IN_FWRITE_UNLOCKED): Wrap long line.
* builtins.c (build_string_literal): New function to construct
a char* pointer to a string literal.
(expand_builtin_fputs): Change 2nd argument from "int ignore" to
"rtx target" to be consistent with other expand_builtin_* functions.
Change 3rd argument from "int unlocked" to "bool unlocked".
(expand_builtin_printf): Rewrite of c_expand_builtin_printf from
c-common.c to avoid front-end dependencies. Optimize printf("")
as a no-op when the result isn't required. Handle embedded NULs
in format string.
(expand_builtin_fprintf): A rewrite of c_expand_builtin_fprintf
from c-common.c to avoid front-end dependencies. Likewise, optimize
fprintf(fp,"") as a no-op when the result isn't required, evaluating
fp for side-effects. Handle embedded NULs in format string.
(expand_builtin_sprintf): Fix typo.
(expand_builtin): Don't expand BUILT_IN_FPRINT{,_UNLOCKED} when not
optimizing. Adjust calls of expand_builtin_fputs to match the API
change. Expand BUILT_IN_PRINTF and BUILT_IN_PRINTF_UNLOCKED using
expand_builtin_printf. Likewise, expand BUILT_IN_FPRINTF_UNLOCKED
and BUILT_IN_FPRINTF using expand_builtin_fprintf.
* c-common.c (is_valid_printf_arglist): Delete.
(c_expand_builtin): Delete.
(c_expand_builtin_printf): Moved to builtins.c. Delete.
(c_expand_builtin_fprintf): Moved to builtins.c. Delete.
(c_expand_expr): No longer treat CALL_EXPRs specially.
(CALLED_AS_BUILT_IN): Delete.
From-SVN: r69760
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 37 | ||||
-rw-r--r-- | gcc/builtins.c | 272 | ||||
-rw-r--r-- | gcc/builtins.def | 53 | ||||
-rw-r--r-- | gcc/c-common.c | 296 |
4 files changed, 317 insertions, 341 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0a4b1a3..4a68dfb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,40 @@ +2003-07-24 Roger Sayle <roger@eyesopen.com> + + * builtins.def (BUILT_IN_PRINTF, BUILT_IN_FPRINTF): Changed from + front-end builtins to normal builtins, using DEF_LIB_BUILTIN. + (BUILT_IN_PRINTF_UNLOCKED, BUILT_IN_FPRINTF_UNLOCKED): Changed + from front-end to normal builtins, using DEF_EXT_LIB_BUILTIN. + (DEF_FRONT_END_LIB_BUILTIN): Delete. + (DEF_EXT_FRONT_END_LIB_BUILTIN): Delete. + (BUILT_IN_FWRITE_UNLOCKED): Wrap long line. + + * builtins.c (build_string_literal): New function to construct + a char* pointer to a string literal. + (expand_builtin_fputs): Change 2nd argument from "int ignore" to + "rtx target" to be consistent with other expand_builtin_* functions. + Change 3rd argument from "int unlocked" to "bool unlocked". + (expand_builtin_printf): Rewrite of c_expand_builtin_printf from + c-common.c to avoid front-end dependencies. Optimize printf("") + as a no-op when the result isn't required. Handle embedded NULs + in format string. + (expand_builtin_fprintf): A rewrite of c_expand_builtin_fprintf + from c-common.c to avoid front-end dependencies. Likewise, optimize + fprintf(fp,"") as a no-op when the result isn't required, evaluating + fp for side-effects. Handle embedded NULs in format string. + (expand_builtin_sprintf): Fix typo. + (expand_builtin): Don't expand BUILT_IN_FPRINT{,_UNLOCKED} when not + optimizing. Adjust calls of expand_builtin_fputs to match the API + change. Expand BUILT_IN_PRINTF and BUILT_IN_PRINTF_UNLOCKED using + expand_builtin_printf. Likewise, expand BUILT_IN_FPRINTF_UNLOCKED + and BUILT_IN_FPRINTF using expand_builtin_fprintf. + + * c-common.c (is_valid_printf_arglist): Delete. + (c_expand_builtin): Delete. + (c_expand_builtin_printf): Moved to builtins.c. Delete. + (c_expand_builtin_fprintf): Moved to builtins.c. Delete. + (c_expand_expr): No longer treat CALL_EXPRs specially. + (CALLED_AS_BUILT_IN): Delete. + 2003-07-24 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz> PR optimization/11631 diff --git a/gcc/builtins.c b/gcc/builtins.c index 0a44edf..a8c1d47 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -90,6 +90,7 @@ static const char *c_getstr (tree); static rtx c_readstr (const char *, enum machine_mode); static int target_char_cast (tree, char *); static rtx get_memory_rtx (tree); +static tree build_string_literal (int, const char *); static int apply_args_size (void); static int apply_result_size (void); #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return) @@ -140,7 +141,9 @@ static rtx expand_builtin_strrchr (tree, rtx, enum machine_mode); static rtx expand_builtin_alloca (tree, rtx); static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab); static rtx expand_builtin_frame_address (tree, tree); -static rtx expand_builtin_fputs (tree, int, int); +static rtx expand_builtin_fputs (tree, rtx, bool); +static rtx expand_builtin_printf (tree, rtx, enum machine_mode, bool); +static rtx expand_builtin_fprintf (tree, rtx, enum machine_mode, bool); static rtx expand_builtin_sprintf (tree, rtx, enum machine_mode); static tree stabilize_va_list (tree, int); static rtx expand_builtin_expect (tree, rtx); @@ -820,10 +823,10 @@ expand_builtin_prefetch (tree arglist) if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate) (op0, insn_data[(int) CODE_FOR_prefetch].operand[0].mode)) - || (GET_MODE(op0) != Pmode)) + || (GET_MODE (op0) != Pmode)) { #ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE(op0) != Pmode) + if (GET_MODE (op0) != Pmode) op0 = convert_memory_address (Pmode, op0); #endif op0 = force_reg (Pmode, op0); @@ -2137,7 +2140,7 @@ expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n) val = (n < 0) ? -n : n; - memset (cache, 0, sizeof(cache)); + memset (cache, 0, sizeof (cache)); cache[1] = x; result = expand_powi_1 (mode, (n < 0) ? -n : n, cache); @@ -4258,7 +4261,7 @@ expand_builtin_unop (enum machine_mode target_mode, tree arglist, rtx target, long, we attempt to transform this call into __builtin_fputc(). */ static rtx -expand_builtin_fputs (tree arglist, int ignore, int unlocked) +expand_builtin_fputs (tree arglist, rtx target, bool unlocked) { tree len, fn; tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED] @@ -4268,7 +4271,7 @@ expand_builtin_fputs (tree arglist, int ignore, int unlocked) /* If the return value is used, or the replacement _DECL isn't initialized, don't do the transformation. */ - if (!ignore || !fn_fputc || !fn_fwrite) + if (target != const0_rtx || !fn_fputc || !fn_fwrite) return 0; /* Verify the arguments in the original call. */ @@ -4330,8 +4333,7 @@ expand_builtin_fputs (tree arglist, int ignore, int unlocked) } return expand_expr (build_function_call_expr (fn, arglist), - (ignore ? const0_rtx : NULL_RTX), - VOIDmode, EXPAND_NORMAL); + const0_rtx, VOIDmode, EXPAND_NORMAL); } /* Expand a call to __builtin_expect. We return our argument and emit a @@ -4551,6 +4553,227 @@ expand_builtin_cabs (tree arglist, rtx target) return expand_complex_abs (mode, op0, target, 0); } +/* Create a new constant string literal and return a char* pointer to it. + The STRING_CST value is the LEN characters at STR. */ +static tree +build_string_literal (int len, const char *str) +{ + tree t, elem, index, type; + + t = build_string (len, str); + elem = build_type_variant (char_type_node, 1, 0); + index = build_index_type (build_int_2 (len - 1, 0)); + type = build_array_type (elem, index); + TREE_TYPE (t) = type; + TREE_CONSTANT (t) = 1; + TREE_READONLY (t) = 1; + TREE_STATIC (t) = 1; + + type = build_pointer_type (type); + t = build1 (ADDR_EXPR, type, t); + + type = build_pointer_type (elem); + t = build1 (NOP_EXPR, type, t); + return t; +} + +/* Expand a call to printf or printf_unlocked with argument list ARGLIST. + Return 0 if a normal call should be emitted rather than transforming + the function inline. If convenient, the result should be placed in + TARGET with mode MODE. UNLOCKED indicates this is a printf_unlocked + call. */ +static rtx +expand_builtin_printf (tree arglist, rtx target, enum machine_mode mode, + bool unlocked) +{ + tree fn_putchar = unlocked + ? implicit_built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED] + : implicit_built_in_decls[BUILT_IN_PUTCHAR]; + tree fn_puts = unlocked ? implicit_built_in_decls[BUILT_IN_PUTS_UNLOCKED] + : implicit_built_in_decls[BUILT_IN_PUTS]; + const char *fmt_str; + tree fn, fmt, arg; + + /* If the return value is used, don't do the transformation. */ + if (target != const0_rtx) + return 0; + + /* Verify the required arguments in the original call. */ + if (! arglist) + return 0; + fmt = TREE_VALUE (arglist); + if (TREE_CODE (TREE_TYPE (fmt)) != POINTER_TYPE) + return 0; + arglist = TREE_CHAIN (arglist); + + /* Check whether the format is a literal string constant. */ + fmt_str = c_getstr (fmt); + if (fmt_str == NULL) + return 0; + + /* If the format specifier was "%s\n", call __builtin_puts(arg). */ + if (strcmp (fmt_str, "%s\n") == 0) + { + if (! arglist + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE + || TREE_CHAIN (arglist)) + return 0; + fn = fn_puts; + } + /* If the format specifier was "%c", call __builtin_putchar(arg). */ + else if (strcmp (fmt_str, "%c") == 0) + { + if (! arglist + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE + || TREE_CHAIN (arglist)) + return 0; + fn = fn_putchar; + } + else + { + /* We can't handle anything else with % args or %% ... yet. */ + if (strchr (fmt_str, '%')) + return 0; + + if (arglist) + return 0; + + /* If the format specifier was "", printf does nothing. */ + if (fmt_str[0] == '\0') + return const0_rtx; + /* If the format specifier has length of 1, call putchar. */ + if (fmt_str[1] == '\0') + { + /* Given printf("c"), (where c is any one character,) + convert "c"[0] to an int and pass that to the replacement + function. */ + arg = build_int_2 (fmt_str[0], 0); + arglist = build_tree_list (NULL_TREE, arg); + fn = fn_putchar; + } + else + { + /* If the format specifier was "string\n", call puts("string"). */ + size_t len = strlen (fmt_str); + if (fmt_str[len - 1] == '\n') + { + /* Create a NUL-terminalted string that's one char shorter + than the original, stripping off the trailing '\n'. */ + char *newstr = (char *) alloca (len); + memcpy (newstr, fmt_str, len - 1); + newstr[len - 1] = 0; + + arg = build_string_literal (len, newstr); + arglist = build_tree_list (NULL_TREE, arg); + fn = fn_puts; + } + else + /* We'd like to arrange to call fputs(string,stdout) here, + but we need stdout and don't have a way to get it yet. */ + return 0; + } + } + + if (!fn) + return 0; + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); +} + +/* Expand a call to fprintf or fprintf_unlocked with argument list ARGLIST. + Return 0 if a normal call should be emitted rather than transforming + the function inline. If convenient, the result should be placed in + TARGET with mode MODE. UNLOCKED indicates this is a fprintf_unlocked + call. */ +static rtx +expand_builtin_fprintf (tree arglist, rtx target, enum machine_mode mode, + bool unlocked) +{ + tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED] + : implicit_built_in_decls[BUILT_IN_FPUTC]; + tree fn_fputs = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTS_UNLOCKED] + : implicit_built_in_decls[BUILT_IN_FPUTS]; + const char *fmt_str; + tree fn, fmt, fp, arg; + + /* If the return value is used, don't do the transformation. */ + if (target != const0_rtx) + return 0; + + /* Verify the required arguments in the original call. */ + if (! arglist) + return 0; + fp = TREE_VALUE (arglist); + if (TREE_CODE (TREE_TYPE (fp)) != POINTER_TYPE) + return 0; + arglist = TREE_CHAIN (arglist); + if (! arglist) + return 0; + fmt = TREE_VALUE (arglist); + if (TREE_CODE (TREE_TYPE (fmt)) != POINTER_TYPE) + return 0; + arglist = TREE_CHAIN (arglist); + + /* Check whether the format is a literal string constant. */ + fmt_str = c_getstr (fmt); + if (fmt_str == NULL) + return 0; + + /* If the format specifier was "%s", call __builtin_fputs(arg,fp). */ + if (strcmp (fmt_str, "%s") == 0) + { + if (! arglist + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE + || TREE_CHAIN (arglist)) + return 0; + arg = TREE_VALUE (arglist); + arglist = build_tree_list (NULL_TREE, fp); + arglist = tree_cons (NULL_TREE, arg, arglist); + fn = fn_fputs; + } + /* If the format specifier was "%c", call __builtin_fputc(arg,fp). */ + else if (strcmp (fmt_str, "%c") == 0) + { + if (! arglist + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE + || TREE_CHAIN (arglist)) + return 0; + arg = TREE_VALUE (arglist); + arglist = build_tree_list (NULL_TREE, fp); + arglist = tree_cons (NULL_TREE, arg, arglist); + fn = fn_fputc; + } + else + { + /* We can't handle anything else with % args or %% ... yet. */ + if (strchr (fmt_str, '%')) + return 0; + + if (arglist) + return 0; + + /* If the format specifier was "", fprintf does nothing. */ + if (fmt_str[0] == '\0') + { + /* Evaluate and ignore FILE* argument for side-effects. */ + expand_expr (fp, const0_rtx, VOIDmode, EXPAND_NORMAL); + return const0_rtx; + } + + /* When "string" doesn't contain %, replace all cases of + fprintf(stream,string) with fputs(string,stream). The fputs + builtin will take care of special cases like length == 1. */ + arglist = build_tree_list (NULL_TREE, fp); + arglist = tree_cons (NULL_TREE, fmt, arglist); + fn = fn_fputs; + } + + if (!fn) + return 0; + return expand_expr (build_function_call_expr (fn, arglist), + target, mode, EXPAND_NORMAL); +} + /* Expand a call to sprintf with argument list ARGLIST. Return 0 if a normal call should be emitted rather than expanding the function inline. If convenient, the result should be placed in TARGET with @@ -4574,7 +4797,7 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) if (! arglist) return 0; fmt = TREE_VALUE (arglist); - if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE) + if (TREE_CODE (TREE_TYPE (fmt)) != POINTER_TYPE) return 0; arglist = TREE_CHAIN (arglist); @@ -4721,12 +4944,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, case BUILT_IN_FPUTC: case BUILT_IN_FPUTS: case BUILT_IN_FWRITE: + case BUILT_IN_FPRINTF: case BUILT_IN_PUTCHAR_UNLOCKED: case BUILT_IN_PUTS_UNLOCKED: case BUILT_IN_PRINTF_UNLOCKED: case BUILT_IN_FPUTC_UNLOCKED: case BUILT_IN_FPUTS_UNLOCKED: case BUILT_IN_FWRITE_UNLOCKED: + case BUILT_IN_FPRINTF_UNLOCKED: case BUILT_IN_FLOOR: case BUILT_IN_FLOORF: case BUILT_IN_FLOORL: @@ -5167,13 +5392,38 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, expand_builtin_trap (); return const0_rtx; + case BUILT_IN_PRINTF: + target = expand_builtin_printf (arglist, target, mode, false); + if (target) + return target; + break; + + case BUILT_IN_PRINTF_UNLOCKED: + target = expand_builtin_printf (arglist, target, mode, true); + if (target) + return target; + break; + case BUILT_IN_FPUTS: - target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 0); + target = expand_builtin_fputs (arglist, target, false); if (target) return target; break; + case BUILT_IN_FPUTS_UNLOCKED: - target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 1); + target = expand_builtin_fputs (arglist, target, true); + if (target) + return target; + break; + + case BUILT_IN_FPRINTF: + target = expand_builtin_fprintf (arglist, target, mode, false); + if (target) + return target; + break; + + case BUILT_IN_FPRINTF_UNLOCKED: + target = expand_builtin_fprintf (arglist, target, mode, true); if (target) return target; break; diff --git a/gcc/builtins.def b/gcc/builtins.def index 0eaba88..e05795d 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -70,9 +70,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, TYPE, BT_LAST, \ false, false, false, ATTRS, true) - /* A fallback builtin is a builtin (like __builtin_puts) that falls - back to the corresopnding library function if necessary -- but + back to the corresponding library function if necessary -- but for which we should not introduce the non-`__builtin' variant of the name. */ #undef DEF_FALLBACK_BUILTIN @@ -124,21 +123,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ true, true, !flag_isoc99, ATTRS, TARGET_C99_FUNCTIONS) -/* Like DEF_LIB_BUILTIN, except that the function is expanded in the - front-end. */ -#undef DEF_FRONT_END_LIB_BUILTIN -#define DEF_FRONT_END_LIB_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ - DEF_BUILTIN (ENUM, NAME, BUILT_IN_FRONTEND, TYPE, TYPE, \ - true, true, false, ATTRS, true) - -/* Like DEF_FRONT_END_LIB_BUILTIN, except that the function is not one - that is specified by ANSI/ISO C. So, when we're being fully - conformant we ignore the version of these builtins that does not - begin with __builtin. */ -#undef DEF_EXT_FRONT_END_LIB_BUILTIN -#define DEF_EXT_FRONT_END_LIB_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ - DEF_BUILTIN (ENUM, NAME, BUILT_IN_FRONTEND, TYPE, TYPE, \ - true, true, true, ATTRS, true) DEF_EXT_LIB_BUILTIN(BUILT_IN_ALLOCA, "__builtin_alloca", @@ -769,10 +753,10 @@ DEF_GCC_BUILTIN(BUILT_IN_PREFETCH, /* stdio.h builtins (without FILE *). */ -DEF_FRONT_END_LIB_BUILTIN(BUILT_IN_PRINTF, - "__builtin_printf", - BT_FN_INT_CONST_STRING_VAR, - ATTR_FORMAT_PRINTF_1_2) +DEF_LIB_BUILTIN(BUILT_IN_PRINTF, + "__builtin_printf", + BT_FN_INT_CONST_STRING_VAR, + ATTR_FORMAT_PRINTF_1_2) DEF_LIB_BUILTIN(BUILT_IN_PUTCHAR, "__builtin_putchar", BT_FN_INT_INT, @@ -840,10 +824,10 @@ DEF_FALLBACK_BUILTIN(BUILT_IN_FWRITE, "__builtin_fwrite", BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR, ATTR_NOTHROW_NONNULL_1_4) -DEF_FRONT_END_LIB_BUILTIN(BUILT_IN_FPRINTF, - "__builtin_fprintf", - BT_FN_INT_PTR_CONST_STRING_VAR, - ATTR_FORMAT_PRINTF_2_3) +DEF_LIB_BUILTIN(BUILT_IN_FPRINTF, + "__builtin_fprintf", + BT_FN_INT_PTR_CONST_STRING_VAR, + ATTR_FORMAT_PRINTF_2_3) /* stdio unlocked builtins (without FILE *). */ @@ -853,10 +837,10 @@ DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_PUTCHAR_UNLOCKED, DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_PUTS_UNLOCKED, "__builtin_puts_unlocked", BT_FN_INT_CONST_STRING, ATTR_NOTHROW_NONNULL_1) -DEF_EXT_FRONT_END_LIB_BUILTIN(BUILT_IN_PRINTF_UNLOCKED, - "__builtin_printf_unlocked", - BT_FN_INT_CONST_STRING_VAR, - ATTR_FORMAT_PRINTF_1_2) +DEF_EXT_LIB_BUILTIN(BUILT_IN_PRINTF_UNLOCKED, + "__builtin_printf_unlocked", + BT_FN_INT_CONST_STRING_VAR, + ATTR_FORMAT_PRINTF_1_2) /* stdio unlocked builtins (with FILE *). */ @@ -876,11 +860,12 @@ DEF_BUILTIN (BUILT_IN_FPUTS_UNLOCKED, true, true, true, ATTR_NOTHROW_NONNULL_1_2, true) DEF_EXT_FALLBACK_BUILTIN(BUILT_IN_FWRITE_UNLOCKED, "__builtin_fwrite_unlocked", - BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR, ATTR_NOTHROW_NONNULL_1_4) -DEF_EXT_FRONT_END_LIB_BUILTIN(BUILT_IN_FPRINTF_UNLOCKED, - "__builtin_fprintf_unlocked", - BT_FN_INT_PTR_CONST_STRING_VAR, - ATTR_FORMAT_PRINTF_2_3) + BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR, + ATTR_NOTHROW_NONNULL_1_4) +DEF_EXT_LIB_BUILTIN(BUILT_IN_FPRINTF_UNLOCKED, + "__builtin_fprintf_unlocked", + BT_FN_INT_PTR_CONST_STRING_VAR, + ATTR_FORMAT_PRINTF_2_3) /* ISO C99 floating point unordered comparisons. */ DEF_GCC_BUILTIN(BUILT_IN_ISGREATER, diff --git a/gcc/c-common.c b/gcc/c-common.c index 685ec2c..2e985c2 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -1175,14 +1175,6 @@ fix_string_type (tree value) return value; } -static int is_valid_printf_arglist (tree); -static rtx c_expand_builtin (tree, rtx, enum machine_mode, - enum expand_modifier); -static rtx c_expand_builtin_printf (tree, rtx, enum machine_mode, - enum expand_modifier, int, int); -static rtx c_expand_builtin_fprintf (tree, rtx, enum machine_mode, - enum expand_modifier, int, int); - /* Print a warning if a constant expression had overflow in folding. Invoke this function on every expression that the language requires to be a constant expression. @@ -4053,20 +4045,6 @@ c_expand_expr (tree exp, rtx target, enum machine_mode tmode, int modifier) } break; - case CALL_EXPR: - { - if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR - && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) - == FUNCTION_DECL) - && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) - && (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) - == BUILT_IN_FRONTEND)) - return c_expand_builtin (exp, target, tmode, modifier); - else - abort (); - } - break; - case COMPOUND_LITERAL_EXPR: { /* Initialize the anonymous variable declared in the compound @@ -4135,280 +4113,6 @@ c_staticp (tree exp) return 1; return 0; } - -#define CALLED_AS_BUILT_IN(NODE) \ - (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10)) - -static rtx -c_expand_builtin (tree exp, rtx target, enum machine_mode tmode, - enum expand_modifier modifier) -{ - tree type = TREE_TYPE (exp); - tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); - tree arglist = TREE_OPERAND (exp, 1); - enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); - enum tree_code code = TREE_CODE (exp); - const int ignore = (target == const0_rtx - || ((code == NON_LVALUE_EXPR || code == NOP_EXPR - || code == CONVERT_EXPR || code == REFERENCE_EXPR - || code == COND_EXPR) - && TREE_CODE (type) == VOID_TYPE)); - - if (! optimize && ! CALLED_AS_BUILT_IN (fndecl)) - return expand_call (exp, target, ignore); - - switch (fcode) - { - case BUILT_IN_PRINTF: - target = c_expand_builtin_printf (arglist, target, tmode, - modifier, ignore, /*unlocked=*/ 0); - if (target) - return target; - break; - - case BUILT_IN_PRINTF_UNLOCKED: - target = c_expand_builtin_printf (arglist, target, tmode, - modifier, ignore, /*unlocked=*/ 1); - if (target) - return target; - break; - - case BUILT_IN_FPRINTF: - target = c_expand_builtin_fprintf (arglist, target, tmode, - modifier, ignore, /*unlocked=*/ 0); - if (target) - return target; - break; - - case BUILT_IN_FPRINTF_UNLOCKED: - target = c_expand_builtin_fprintf (arglist, target, tmode, - modifier, ignore, /*unlocked=*/ 1); - 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))); - } - - /* The switch statement above can drop through to cause the function - to be called normally. */ - return expand_call (exp, target, ignore); -} - -/* 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 (tree arglist) -{ - /* Save this value so we can restore it later. */ - const int SAVE_pedantic = pedantic; - int diagnostic_occurred = 0; - tree attrs; - - /* 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. */ - attrs = tree_cons (get_identifier ("format"), - tree_cons (NULL_TREE, - get_identifier ("printf"), - tree_cons (NULL_TREE, - integer_one_node, - tree_cons (NULL_TREE, - build_int_2 (2, 0), - NULL_TREE))), - NULL_TREE); - check_function_format (&diagnostic_occurred, attrs, 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 -c_expand_builtin_printf (tree arglist, rtx target, enum machine_mode tmode, - enum expand_modifier modifier, int ignore, - int unlocked) -{ - tree fn_putchar = unlocked ? - implicit_built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED] : implicit_built_in_decls[BUILT_IN_PUTCHAR]; - tree fn_puts = unlocked ? - implicit_built_in_decls[BUILT_IN_PUTS_UNLOCKED] : implicit_built_in_decls[BUILT_IN_PUTS]; - tree fn, 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; - } - /* If the resulting constant was "string\n", call - __builtin_puts("string"). Ensure "string" has at least one - character besides the trailing \n. Note, TREE_STRING_LENGTH - includes the terminating NULL in its count. */ - else if (TREE_STRING_LENGTH (stripped_string) > 2 - && TREE_STRING_POINTER (stripped_string) - [TREE_STRING_LENGTH (stripped_string) - 2] == '\n') - { - /* Create a NULL-terminated string that's one char shorter - than the original, stripping off the trailing '\n'. */ - const int newlen = TREE_STRING_LENGTH (stripped_string) - 1; - char *newstr = alloca (newlen); - memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1); - newstr[newlen - 1] = 0; - - arglist = fix_string_type (build_string (newlen, newstr)); - arglist = build_tree_list (NULL_TREE, arglist); - fn = fn_puts; - } - 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; - } - - return expand_expr (build_function_call (fn, arglist), - (ignore ? const0_rtx : target), - tmode, modifier); -} - -/* If the arguments passed to fprintf are suitable for optimizations, - we attempt to transform the call. */ -static rtx -c_expand_builtin_fprintf (tree arglist, rtx target, enum machine_mode tmode, - enum expand_modifier modifier, int ignore, - int unlocked) -{ - tree fn_fputc = unlocked ? - implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED] : implicit_built_in_decls[BUILT_IN_FPUTC]; - tree fn_fputs = unlocked ? - implicit_built_in_decls[BUILT_IN_FPUTS_UNLOCKED] : implicit_built_in_decls[BUILT_IN_FPUTS]; - tree fn, 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_fputc || !fn_fputs) - 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)); - 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", call __builtin_fputs(arg3, arg1). */ - if (strcmp (TREE_STRING_POINTER (stripped_string), "%s") == 0) - { - tree newarglist = build_tree_list (NULL_TREE, TREE_VALUE (arglist)); - arglist = tree_cons (NULL_TREE, - TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))), - newarglist); - fn = fn_fputs; - } - /* If the format specifier was "%c", call __builtin_fputc (arg3, arg1). */ - else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0) - { - tree newarglist = build_tree_list (NULL_TREE, TREE_VALUE (arglist)); - arglist = tree_cons (NULL_TREE, - TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))), - newarglist); - fn = fn_fputc; - } - else - { - /* We can't handle anything else with % args or %% ... yet. */ - if (strchr (TREE_STRING_POINTER (stripped_string), '%')) - return 0; - - /* When "string" doesn't contain %, replace all cases of - fprintf(stream,string) with fputs(string,stream). The fputs - builtin will take take of special cases like length==1. */ - arglist = tree_cons (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)), - build_tree_list (NULL_TREE, TREE_VALUE (arglist))); - fn = fn_fputs; - } - - return expand_expr (build_function_call (fn, arglist), - (ignore ? const0_rtx : target), - tmode, modifier); -} /* Given a boolean expression ARG, return a tree representing an increment |