-
- /* 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);
-}
-\f
-
-/* Given a boolean expression ARG, return a tree representing an increment
- or decrement (as indicated by CODE) of ARG. The front end must check for
- invalid cases (e.g., decrement in C++). */
-tree
-boolean_increment (enum tree_code code, tree arg)
-{
- tree val;
- tree true_res = boolean_true_node;
-
- arg = stabilize_reference (arg);
- switch (code)
- {
- case PREINCREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
- break;
- case POSTINCREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
- arg = save_expr (arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
- break;
- case PREDECREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
- break;
- case POSTDECREMENT_EXPR:
- val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
- arg = save_expr (arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
- val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
- break;
- default:
- abort ();
- }
- TREE_SIDE_EFFECTS (val) = 1;
- return val;