X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gcc%2Fgimple-fold.c;h=c91f218c218ca4a90d1b9ef403f0a7ae1b2908ee;hb=6f2d72e0e1038dbd57131bdeee8569c4397ad706;hp=8e0c9e055ef82e82cd2a1397586a455fa923a3e2;hpb=538dd0b78f4b3998a1719a282811cb0caa1b035a;p=gcc.git diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 8e0c9e055ef..c91f218c218 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -1,5 +1,5 @@ /* Statement simplification on GIMPLE. - Copyright (C) 2010-2014 Free Software Foundation, Inc. + Copyright (C) 2010-2015 Free Software Foundation, Inc. Split out from tree-ssa-ccp.c. This file is part of GCC. @@ -22,19 +22,36 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tm.h" +#include "hash-set.h" +#include "machmode.h" +#include "vec.h" +#include "double-int.h" +#include "input.h" +#include "alias.h" +#include "symtab.h" +#include "wide-int.h" +#include "inchash.h" #include "tree.h" +#include "fold-const.h" #include "stringpool.h" -#include "expr.h" -#include "stmt.h" -#include "stor-layout.h" -#include "flags.h" #include "hashtab.h" -#include "hash-set.h" -#include "vec.h" -#include "machmode.h" #include "hard-reg-set.h" -#include "input.h" #include "function.h" +#include "rtl.h" +#include "flags.h" +#include "statistics.h" +#include "real.h" +#include "fixed-value.h" +#include "insn-config.h" +#include "expmed.h" +#include "dojump.h" +#include "explow.h" +#include "calls.h" +#include "emit-rtl.h" +#include "varasm.h" +#include "stmt.h" +#include "expr.h" +#include "stor-layout.h" #include "dumpfile.h" #include "bitmap.h" #include "predict.h" @@ -254,8 +271,7 @@ get_symbol_constant_value (tree sym) have zero as the initializer if they may not be overridden at link or run time. */ if (!val - && (INTEGRAL_TYPE_P (TREE_TYPE (sym)) - || SCALAR_FLOAT_TYPE_P (TREE_TYPE (sym)))) + && is_gimple_reg_type (TREE_TYPE (sym))) return build_zero_cst (TREE_TYPE (sym)); } @@ -753,7 +769,7 @@ var_decl_component_p (tree var) } /* Fold function call to builtin mem{{,p}cpy,move}. Return - NULL_TREE if no simplification can be made. + false if no simplification can be made. If ENDP is 0, return DEST (like memcpy). If ENDP is 1, return DEST+LEN (like mempcpy). If ENDP is 2, return DEST+LEN-1 (like stpcpy). @@ -861,8 +877,7 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi, srcmem = make_ssa_name (TREE_TYPE (srcmem), new_stmt); else - srcmem = create_tmp_reg (TREE_TYPE (srcmem), - NULL); + srcmem = create_tmp_reg (TREE_TYPE (srcmem)); gimple_assign_set_lhs (new_stmt, srcmem); gimple_set_vuse (new_stmt, gimple_vuse (stmt)); gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); @@ -1147,7 +1162,7 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi, if (gimple_in_ssa_p (cfun)) srcvar = make_ssa_name (TREE_TYPE (srcvar), new_stmt); else - srcvar = create_tmp_reg (TREE_TYPE (srcvar), NULL); + srcvar = create_tmp_reg (TREE_TYPE (srcvar)); gimple_assign_set_lhs (new_stmt, srcvar); gimple_set_vuse (new_stmt, gimple_vuse (stmt)); gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); @@ -1555,9 +1570,9 @@ gimple_fold_builtin_strcat (gimple_stmt_iterator *gsi, tree dst, tree src) gimple repl = gimple_build_call (strlen_fn, 1, dst); gimple_set_location (repl, loc); if (gimple_in_ssa_p (cfun)) - newdst = make_ssa_name (size_type_node, NULL); + newdst = make_ssa_name (size_type_node); else - newdst = create_tmp_reg (size_type_node, NULL); + newdst = create_tmp_reg (size_type_node); gimple_call_set_lhs (repl, newdst); gimple_seq_add_stmt_without_update (&stmts, repl); @@ -1630,6 +1645,46 @@ gimple_fold_builtin_strcat_chk (gimple_stmt_iterator *gsi) return true; } +/* Simplify a call to the strncat builtin. */ + +static bool +gimple_fold_builtin_strncat (gimple_stmt_iterator *gsi) +{ + gcall *stmt = as_a (gsi_stmt (*gsi)); + tree dst = gimple_call_arg (stmt, 0); + tree src = gimple_call_arg (stmt, 1); + tree len = gimple_call_arg (stmt, 2); + + const char *p = c_getstr (src); + + /* If the requested length is zero, or the src parameter string + length is zero, return the dst parameter. */ + if (integer_zerop (len) || (p && *p == '\0')) + { + replace_call_with_value (gsi, dst); + return true; + } + + /* If the requested len is greater than or equal to the string + length, call strcat. */ + if (TREE_CODE (len) == INTEGER_CST && p + && compare_tree_int (len, strlen (p)) >= 0) + { + tree fn = builtin_decl_implicit (BUILT_IN_STRCAT); + + /* If the replacement _DECL isn't initialized, don't do the + transformation. */ + if (!fn) + return false; + + gcall *repl = gimple_build_call (fn, 2, dst, src); + replace_call_with_call_and_fold (gsi, repl); + return true; + } + + return false; +} + /* Fold a call to the __strncat_chk builtin with arguments DEST, SRC, LEN, and SIZE. */ @@ -2014,6 +2069,70 @@ gimple_fold_builtin_stxncpy_chk (gimple_stmt_iterator *gsi, return true; } +/* Fold function call to builtin stpcpy with arguments DEST and SRC. + Return NULL_TREE if no simplification can be made. */ + +static bool +gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi) +{ + gcall *stmt = as_a (gsi_stmt (*gsi)); + location_t loc = gimple_location (stmt); + tree dest = gimple_call_arg (stmt, 0); + tree src = gimple_call_arg (stmt, 1); + tree fn, len, lenp1; + + /* If the result is unused, replace stpcpy with strcpy. */ + if (gimple_call_lhs (stmt) == NULL_TREE) + { + tree fn = builtin_decl_implicit (BUILT_IN_STRCPY); + if (!fn) + return false; + gimple_call_set_fndecl (stmt, fn); + fold_stmt (gsi); + return true; + } + + len = c_strlen (src, 1); + if (!len + || TREE_CODE (len) != INTEGER_CST) + return false; + + if (optimize_function_for_size_p (cfun) + /* If length is zero it's small enough. */ + && !integer_zerop (len)) + return false; + + /* If the source has a known length replace stpcpy with memcpy. */ + fn = builtin_decl_implicit (BUILT_IN_MEMCPY); + if (!fn) + return false; + + gimple_seq stmts = NULL; + tree tem = gimple_convert (&stmts, loc, size_type_node, len); + lenp1 = gimple_build (&stmts, loc, PLUS_EXPR, size_type_node, + tem, build_int_cst (size_type_node, 1)); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + gcall *repl = gimple_build_call (fn, 3, dest, src, lenp1); + gimple_set_vuse (repl, gimple_vuse (stmt)); + gimple_set_vdef (repl, gimple_vdef (stmt)); + if (gimple_vdef (repl) + && TREE_CODE (gimple_vdef (repl)) == SSA_NAME) + SSA_NAME_DEF_STMT (gimple_vdef (repl)) = repl; + gsi_insert_before (gsi, repl, GSI_SAME_STMT); + /* Replace the result with dest + len. */ + stmts = NULL; + tem = gimple_convert (&stmts, loc, sizetype, len); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + gassign *ret = gimple_build_assign (gimple_call_lhs (stmt), + POINTER_PLUS_EXPR, dest, tem); + gsi_replace (gsi, ret, true); + /* Finally fold the memcpy call. */ + gimple_stmt_iterator gsi2 = *gsi; + gsi_prev (&gsi2); + fold_stmt (&gsi2); + return true; +} + /* Fold a call EXP to {,v}snprintf having NARGS passed as ARGS. Return NULL_TREE if a normal call should be emitted rather than expanding the function inline. FCODE is either BUILT_IN_SNPRINTF_CHK or @@ -2455,6 +2574,270 @@ gimple_fold_builtin_snprintf (gimple_stmt_iterator *gsi) return false; } +/* Fold a call to the {,v}fprintf{,_unlocked} and __{,v}printf_chk builtins. + FP, FMT, and ARG are the arguments to the call. We don't fold calls with + more than 3 arguments, and ARG may be null in the 2-argument case. + + Return NULL_TREE if no simplification was possible, otherwise return the + simplified form of the call as a tree. FCODE is the BUILT_IN_* + code of the function to be simplified. */ + +static bool +gimple_fold_builtin_fprintf (gimple_stmt_iterator *gsi, + tree fp, tree fmt, tree arg, + enum built_in_function fcode) +{ + gcall *stmt = as_a (gsi_stmt (*gsi)); + tree fn_fputc, fn_fputs; + const char *fmt_str = NULL; + + /* If the return value is used, don't do the transformation. */ + if (gimple_call_lhs (stmt) != NULL_TREE) + return false; + + /* Check whether the format is a literal string constant. */ + fmt_str = c_getstr (fmt); + if (fmt_str == NULL) + return false; + + if (fcode == BUILT_IN_FPRINTF_UNLOCKED) + { + /* If we're using an unlocked function, assume the other + unlocked functions exist explicitly. */ + fn_fputc = builtin_decl_explicit (BUILT_IN_FPUTC_UNLOCKED); + fn_fputs = builtin_decl_explicit (BUILT_IN_FPUTS_UNLOCKED); + } + else + { + fn_fputc = builtin_decl_implicit (BUILT_IN_FPUTC); + fn_fputs = builtin_decl_implicit (BUILT_IN_FPUTS); + } + + if (!init_target_chars ()) + return false; + + /* If the format doesn't contain % args or %%, use strcpy. */ + if (strchr (fmt_str, target_percent) == NULL) + { + if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK + && arg) + return false; + + /* If the format specifier was "", fprintf does nothing. */ + if (fmt_str[0] == '\0') + { + replace_call_with_value (gsi, NULL_TREE); + return true; + } + + /* When "string" doesn't contain %, replace all cases of + fprintf (fp, string) with fputs (string, fp). The fputs + builtin will take care of special cases like length == 1. */ + if (fn_fputs) + { + gcall *repl = gimple_build_call (fn_fputs, 2, fmt, fp); + replace_call_with_call_and_fold (gsi, repl); + return true; + } + } + + /* The other optimizations can be done only on the non-va_list variants. */ + else if (fcode == BUILT_IN_VFPRINTF || fcode == BUILT_IN_VFPRINTF_CHK) + return false; + + /* If the format specifier was "%s", call __builtin_fputs (arg, fp). */ + else if (strcmp (fmt_str, target_percent_s) == 0) + { + if (!arg || ! POINTER_TYPE_P (TREE_TYPE (arg))) + return false; + if (fn_fputs) + { + gcall *repl = gimple_build_call (fn_fputs, 2, arg, fp); + replace_call_with_call_and_fold (gsi, repl); + return true; + } + } + + /* If the format specifier was "%c", call __builtin_fputc (arg, fp). */ + else if (strcmp (fmt_str, target_percent_c) == 0) + { + if (!arg + || ! useless_type_conversion_p (integer_type_node, TREE_TYPE (arg))) + return false; + if (fn_fputc) + { + gcall *repl = gimple_build_call (fn_fputc, 2, arg, fp); + replace_call_with_call_and_fold (gsi, repl); + return true; + } + } + + return false; +} + +/* Fold a call to the {,v}printf{,_unlocked} and __{,v}printf_chk builtins. + FMT and ARG are the arguments to the call; we don't fold cases with + more than 2 arguments, and ARG may be null if this is a 1-argument case. + + Return NULL_TREE if no simplification was possible, otherwise return the + simplified form of the call as a tree. FCODE is the BUILT_IN_* + code of the function to be simplified. */ + +static bool +gimple_fold_builtin_printf (gimple_stmt_iterator *gsi, tree fmt, + tree arg, enum built_in_function fcode) +{ + gcall *stmt = as_a (gsi_stmt (*gsi)); + tree fn_putchar, fn_puts, newarg; + const char *fmt_str = NULL; + + /* If the return value is used, don't do the transformation. */ + if (gimple_call_lhs (stmt) != NULL_TREE) + return false; + + /* Check whether the format is a literal string constant. */ + fmt_str = c_getstr (fmt); + if (fmt_str == NULL) + return false; + + if (fcode == BUILT_IN_PRINTF_UNLOCKED) + { + /* If we're using an unlocked function, assume the other + unlocked functions exist explicitly. */ + fn_putchar = builtin_decl_explicit (BUILT_IN_PUTCHAR_UNLOCKED); + fn_puts = builtin_decl_explicit (BUILT_IN_PUTS_UNLOCKED); + } + else + { + fn_putchar = builtin_decl_implicit (BUILT_IN_PUTCHAR); + fn_puts = builtin_decl_implicit (BUILT_IN_PUTS); + } + + if (!init_target_chars ()) + return false; + + if (strcmp (fmt_str, target_percent_s) == 0 + || strchr (fmt_str, target_percent) == NULL) + { + const char *str; + + if (strcmp (fmt_str, target_percent_s) == 0) + { + if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK) + return false; + + if (!arg || ! POINTER_TYPE_P (TREE_TYPE (arg))) + return false; + + str = c_getstr (arg); + if (str == NULL) + return false; + } + else + { + /* The format specifier doesn't contain any '%' characters. */ + if (fcode != BUILT_IN_VPRINTF && fcode != BUILT_IN_VPRINTF_CHK + && arg) + return false; + str = fmt_str; + } + + /* If the string was "", printf does nothing. */ + if (str[0] == '\0') + { + replace_call_with_value (gsi, NULL_TREE); + return true; + } + + /* If the string has length of 1, call putchar. */ + if (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. */ + newarg = build_int_cst (integer_type_node, str[0]); + if (fn_putchar) + { + gcall *repl = gimple_build_call (fn_putchar, 1, newarg); + replace_call_with_call_and_fold (gsi, repl); + return true; + } + } + else + { + /* If the string was "string\n", call puts("string"). */ + size_t len = strlen (str); + if ((unsigned char)str[len - 1] == target_newline + && (size_t) (int) len == len + && (int) len > 0) + { + char *newstr; + tree offset_node, string_cst; + + /* Create a NUL-terminated string that's one char shorter + than the original, stripping off the trailing '\n'. */ + newarg = build_string_literal (len, str); + string_cst = string_constant (newarg, &offset_node); + gcc_checking_assert (string_cst + && (TREE_STRING_LENGTH (string_cst) + == (int) len) + && integer_zerop (offset_node) + && (unsigned char) + TREE_STRING_POINTER (string_cst)[len - 1] + == target_newline); + /* build_string_literal creates a new STRING_CST, + modify it in place to avoid double copying. */ + newstr = CONST_CAST (char *, TREE_STRING_POINTER (string_cst)); + newstr[len - 1] = '\0'; + if (fn_puts) + { + gcall *repl = gimple_build_call (fn_puts, 1, newarg); + replace_call_with_call_and_fold (gsi, repl); + return true; + } + } + 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 false; + } + } + + /* The other optimizations can be done only on the non-va_list variants. */ + else if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK) + return false; + + /* If the format specifier was "%s\n", call __builtin_puts(arg). */ + else if (strcmp (fmt_str, target_percent_s_newline) == 0) + { + if (!arg || ! POINTER_TYPE_P (TREE_TYPE (arg))) + return false; + if (fn_puts) + { + gcall *repl = gimple_build_call (fn_puts, 1, arg); + replace_call_with_call_and_fold (gsi, repl); + return true; + } + } + + /* If the format specifier was "%c", call __builtin_putchar(arg). */ + else if (strcmp (fmt_str, target_percent_c) == 0) + { + if (!arg || ! useless_type_conversion_p (integer_type_node, + TREE_TYPE (arg))) + return false; + if (fn_putchar) + { + gcall *repl = gimple_build_call (fn_putchar, 1, arg); + replace_call_with_call_and_fold (gsi, repl); + return true; + } + } + + return false; +} + + /* Fold a call to __builtin_strlen with known length LEN. */ @@ -2485,7 +2868,9 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi) if (avoid_folding_inline_builtin (callee)) return false; - switch (DECL_FUNCTION_CODE (callee)) + unsigned n = gimple_call_num_args (stmt); + enum built_in_function fcode = DECL_FUNCTION_CODE (callee); + switch (fcode) { case BUILT_IN_BZERO: return gimple_fold_builtin_memset (gsi, integer_zero_node, @@ -2508,7 +2893,7 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi) gimple_call_arg (stmt, 1), 3); case BUILT_IN_SPRINTF_CHK: case BUILT_IN_VSPRINTF_CHK: - return gimple_fold_builtin_sprintf_chk (gsi, DECL_FUNCTION_CODE (callee)); + return gimple_fold_builtin_sprintf_chk (gsi, fcode); case BUILT_IN_STRCAT_CHK: return gimple_fold_builtin_strcat_chk (gsi); case BUILT_IN_STRNCAT_CHK: @@ -2527,6 +2912,8 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi) case BUILT_IN_STRCAT: return gimple_fold_builtin_strcat (gsi, gimple_call_arg (stmt, 0), gimple_call_arg (stmt, 1)); + case BUILT_IN_STRNCAT: + return gimple_fold_builtin_strncat (gsi); case BUILT_IN_FPUTS: return gimple_fold_builtin_fputs (gsi, gimple_call_arg (stmt, 0), gimple_call_arg (stmt, 1), false); @@ -2542,14 +2929,16 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi) gimple_call_arg (stmt, 1), gimple_call_arg (stmt, 2), gimple_call_arg (stmt, 3), - DECL_FUNCTION_CODE (callee)); + fcode); + case BUILT_IN_STPCPY: + return gimple_fold_builtin_stpcpy (gsi); case BUILT_IN_STRCPY_CHK: case BUILT_IN_STPCPY_CHK: return gimple_fold_builtin_stxcpy_chk (gsi, gimple_call_arg (stmt, 0), gimple_call_arg (stmt, 1), gimple_call_arg (stmt, 2), - DECL_FUNCTION_CODE (callee)); + fcode); case BUILT_IN_STRNCPY_CHK: case BUILT_IN_STPNCPY_CHK: return gimple_fold_builtin_stxncpy_chk (gsi, @@ -2557,15 +2946,53 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi) gimple_call_arg (stmt, 1), gimple_call_arg (stmt, 2), gimple_call_arg (stmt, 3), - DECL_FUNCTION_CODE (callee)); + fcode); case BUILT_IN_SNPRINTF_CHK: case BUILT_IN_VSNPRINTF_CHK: - return gimple_fold_builtin_snprintf_chk (gsi, - DECL_FUNCTION_CODE (callee)); + return gimple_fold_builtin_snprintf_chk (gsi, fcode); case BUILT_IN_SNPRINTF: return gimple_fold_builtin_snprintf (gsi); case BUILT_IN_SPRINTF: return gimple_fold_builtin_sprintf (gsi); + case BUILT_IN_FPRINTF: + case BUILT_IN_FPRINTF_UNLOCKED: + case BUILT_IN_VFPRINTF: + if (n == 2 || n == 3) + return gimple_fold_builtin_fprintf (gsi, + gimple_call_arg (stmt, 0), + gimple_call_arg (stmt, 1), + n == 3 + ? gimple_call_arg (stmt, 2) + : NULL_TREE, + fcode); + break; + case BUILT_IN_FPRINTF_CHK: + case BUILT_IN_VFPRINTF_CHK: + if (n == 3 || n == 4) + return gimple_fold_builtin_fprintf (gsi, + gimple_call_arg (stmt, 0), + gimple_call_arg (stmt, 2), + n == 4 + ? gimple_call_arg (stmt, 3) + : NULL_TREE, + fcode); + break; + case BUILT_IN_PRINTF: + case BUILT_IN_PRINTF_UNLOCKED: + case BUILT_IN_VPRINTF: + if (n == 1 || n == 2) + return gimple_fold_builtin_printf (gsi, gimple_call_arg (stmt, 0), + n == 2 + ? gimple_call_arg (stmt, 1) + : NULL_TREE, fcode); + break; + case BUILT_IN_PRINTF_CHK: + case BUILT_IN_VPRINTF_CHK: + if (n == 2 || n == 3) + return gimple_fold_builtin_printf (gsi, gimple_call_arg (stmt, 1), + n == 3 + ? gimple_call_arg (stmt, 2) + : NULL_TREE, fcode); default:; } @@ -2686,13 +3113,14 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace) { if (TREE_CODE (lhs) == SSA_NAME) { - tree var = create_tmp_var (TREE_TYPE (lhs), NULL); + tree var = create_tmp_var (TREE_TYPE (lhs)); tree def = get_or_create_ssa_default_def (cfun, var); gimple new_stmt = gimple_build_assign (lhs, def); gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); } gimple_call_set_lhs (stmt, NULL_TREE); } + maybe_remove_unused_call_args (cfun, stmt); } else { @@ -2701,7 +3129,7 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace) gimple_set_location (new_stmt, gimple_location (stmt)); if (lhs && TREE_CODE (lhs) == SSA_NAME) { - tree var = create_tmp_var (TREE_TYPE (lhs), NULL); + tree var = create_tmp_var (TREE_TYPE (lhs)); tree def = get_or_create_ssa_default_def (cfun, var); /* To satisfy condition for @@ -3001,8 +3429,9 @@ replace_stmt_with_simplification (gimple_stmt_iterator *gsi, if (gimple_has_lhs (stmt)) { tree lhs = gimple_get_lhs (stmt); - maybe_push_res_to_seq (rcode, TREE_TYPE (lhs), - ops, seq, lhs); + if (!maybe_push_res_to_seq (rcode, TREE_TYPE (lhs), + ops, seq, lhs)) + return false; if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "gimple_simplified to "); @@ -3062,7 +3491,8 @@ maybe_canonicalize_mem_ref_addr (tree *t) accessed is a decl that has the same access semantics as the MEM_REF. */ if (TREE_CODE (*t) == MEM_REF && TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR - && integer_zerop (TREE_OPERAND (*t, 1))) + && integer_zerop (TREE_OPERAND (*t, 1)) + && MR_DEPENDENCE_CLIQUE (*t) == 0) { tree decl = TREE_OPERAND (TREE_OPERAND (*t, 0), 0); tree alias_type = TREE_TYPE (TREE_OPERAND (*t, 1)); @@ -3191,7 +3621,8 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, tree (*valueize) (tree)) gimple_seq seq = NULL; code_helper rcode; tree ops[3] = {}; - if (gimple_simplify (stmt, &rcode, ops, inplace ? NULL : &seq, valueize)) + if (gimple_simplify (stmt, &rcode, ops, inplace ? NULL : &seq, + valueize, valueize)) { if (replace_stmt_with_simplification (gsi, rcode, ops, &seq, inplace)) changed = true; @@ -3415,7 +3846,7 @@ canonicalize_bool (tree expr, bool invert) else if (TREE_CODE (expr) == SSA_NAME) return fold_build2 (EQ_EXPR, boolean_type_node, expr, build_int_cst (TREE_TYPE (expr), 0)); - else if (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_comparison) + else if (COMPARISON_CLASS_P (expr)) return fold_build2 (invert_tree_comparison (TREE_CODE (expr), false), boolean_type_node, TREE_OPERAND (expr, 0), @@ -3434,7 +3865,7 @@ canonicalize_bool (tree expr, bool invert) else if (TREE_CODE (expr) == SSA_NAME) return fold_build2 (NE_EXPR, boolean_type_node, expr, build_int_cst (TREE_TYPE (expr), 0)); - else if (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_comparison) + else if (COMPARISON_CLASS_P (expr)) return fold_build2 (TREE_CODE (expr), boolean_type_node, TREE_OPERAND (expr, 0), @@ -3515,12 +3946,12 @@ same_bool_result_p (const_tree op1, const_tree op2) /* Check the cases where at least one of the operands is a comparison. These are a bit smarter than operand_equal_p in that they apply some identifies on SSA_NAMEs. */ - if (TREE_CODE_CLASS (TREE_CODE (op2)) == tcc_comparison + if (COMPARISON_CLASS_P (op2) && same_bool_comparison_p (op1, TREE_CODE (op2), TREE_OPERAND (op2, 0), TREE_OPERAND (op2, 1))) return true; - if (TREE_CODE_CLASS (TREE_CODE (op1)) == tcc_comparison + if (COMPARISON_CLASS_P (op1) && same_bool_comparison_p (op2, TREE_CODE (op1), TREE_OPERAND (op1, 0), TREE_OPERAND (op1, 1))) @@ -4498,7 +4929,7 @@ gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree), edges if there are intermediate VARYING defs. For this reason do not follow SSA edges here even though SCCVN can technically just deal fine with that. */ - if (gimple_simplify (stmt, &rcode, ops, NULL, gvalueize) + if (gimple_simplify (stmt, &rcode, ops, NULL, gvalueize, valueize) && rcode.is_tree_code () && (TREE_CODE_LENGTH ((tree_code) rcode) == 0 || ((tree_code) rcode) == ADDR_EXPR) @@ -4745,14 +5176,13 @@ gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree), TREE_OPERAND (fn, 0))) { tree *args = XALLOCAVEC (tree, gimple_call_num_args (stmt)); - tree call, retval; + tree retval; unsigned i; for (i = 0; i < gimple_call_num_args (stmt); ++i) args[i] = (*valueize) (gimple_call_arg (stmt, i)); - call = build_call_array_loc (loc, + retval = fold_builtin_call_array (loc, gimple_call_return_type (call_stmt), fn, gimple_call_num_args (stmt), args); - retval = fold_call_expr (EXPR_LOCATION (call), call, false); if (retval) { /* fold_call_expr wraps the result inside a NOP_EXPR. */ @@ -4787,10 +5217,6 @@ gimple_fold_stmt_to_constant (gimple stmt, tree (*valueize) (tree)) /* The following set of functions are supposed to fold references using their constant initializers. */ -static tree fold_ctor_reference (tree type, tree ctor, - unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size, tree); - /* See if we can find constructor defining value of BASE. When we know the consructor with constant offset (such as base is array[40] and we do know constructor of array), then @@ -5026,7 +5452,7 @@ fold_nonarray_ctor_reference (tree type, tree ctor, /* CTOR is value initializing memory, fold reference of type TYPE and size SIZE to the memory at bit OFFSET. */ -static tree +tree fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size, tree from_decl) { @@ -5047,7 +5473,7 @@ fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset, ret = canonicalize_constructor_val (unshare_expr (ctor), from_decl); ret = fold_unary (VIEW_CONVERT_EXPR, type, ret); if (ret) - STRIP_NOPS (ret); + STRIP_USELESS_TYPE_CONVERSION (ret); return ret; } /* For constants and byte-aligned/sized reads try to go through @@ -5092,7 +5518,7 @@ fold_const_aggregate_ref_1 (tree t, tree (*valueize) (tree)) if (TREE_THIS_VOLATILE (t)) return NULL_TREE; - if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration) + if (DECL_P (t)) return get_symbol_constant_value (t); tem = fold_read_from_constant_string (t); @@ -5225,7 +5651,6 @@ gimple_get_virt_method_for_vtable (HOST_WIDE_INT token, if (TREE_CODE (v) != VAR_DECL || !DECL_VIRTUAL_P (v)) { - gcc_assert (in_lto_p); /* Pass down that we lost track of the target. */ if (can_refer) *can_refer = false; @@ -5425,7 +5850,7 @@ gimple_val_nonnegative_real_p (tree val) CASE_FLT_FN (BUILT_IN_SQRT): /* sqrt(-0.0) is -0.0, and sqrt is not defined over other nonnegative inputs. */ - if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (val)))) + if (!HONOR_SIGNED_ZEROS (val)) return true; break; @@ -5647,40 +6072,48 @@ rewrite_to_defined_overflow (gimple stmt) if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) gimple_assign_set_rhs_code (stmt, PLUS_EXPR); gimple_seq_add_stmt (&stmts, stmt); - gimple cvt = gimple_build_assign_with_ops (NOP_EXPR, lhs, - gimple_assign_lhs (stmt)); + gimple cvt = gimple_build_assign (lhs, NOP_EXPR, gimple_assign_lhs (stmt)); gimple_seq_add_stmt (&stmts, cvt); return stmts; } +/* The valueization hook we use for the gimple_build API simplification. + This makes us match fold_buildN behavior by only combining with + statements in the sequence(s) we are currently building. */ + +static tree +gimple_build_valueize (tree op) +{ + if (gimple_bb (SSA_NAME_DEF_STMT (op)) == NULL) + return op; + return NULL_TREE; +} + /* Build the expression CODE OP0 of type TYPE with location LOC, - simplifying it first if possible using VALUEIZE if not NULL. - OP0 is expected to be valueized already. Returns the built + simplifying it first if possible. Returns the built expression value and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, - enum tree_code code, tree type, tree op0, - tree (*valueize)(tree)) + enum tree_code code, tree type, tree op0) { - tree res = gimple_simplify (code, type, op0, seq, valueize); + tree res = gimple_simplify (code, type, op0, seq, gimple_build_valueize); if (!res) { if (gimple_in_ssa_p (cfun)) - res = make_ssa_name (type, NULL); + res = make_ssa_name (type); else - res = create_tmp_reg (type, NULL); + res = create_tmp_reg (type); gimple stmt; if (code == REALPART_EXPR || code == IMAGPART_EXPR || code == VIEW_CONVERT_EXPR) - stmt = gimple_build_assign_with_ops (code, res, - build1 (code, type, op0)); + stmt = gimple_build_assign (res, code, build1 (code, type, op0)); else - stmt = gimple_build_assign_with_ops (code, res, op0); + stmt = gimple_build_assign (res, code, op0); gimple_set_location (stmt, loc); gimple_seq_add_stmt_without_update (seq, stmt); } @@ -5688,24 +6121,22 @@ gimple_build (gimple_seq *seq, location_t loc, } /* Build the expression OP0 CODE OP1 of type TYPE with location LOC, - simplifying it first if possible using VALUEIZE if not NULL. - OP0 and OP1 are expected to be valueized already. Returns the built + simplifying it first if possible. Returns the built expression value and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, - enum tree_code code, tree type, tree op0, tree op1, - tree (*valueize)(tree)) + enum tree_code code, tree type, tree op0, tree op1) { - tree res = gimple_simplify (code, type, op0, op1, seq, valueize); + tree res = gimple_simplify (code, type, op0, op1, seq, gimple_build_valueize); if (!res) { if (gimple_in_ssa_p (cfun)) - res = make_ssa_name (type, NULL); + res = make_ssa_name (type); else - res = create_tmp_reg (type, NULL); - gimple stmt = gimple_build_assign_with_ops (code, res, op0, op1); + res = create_tmp_reg (type); + gimple stmt = gimple_build_assign (res, code, op0, op1); gimple_set_location (stmt, loc); gimple_seq_add_stmt_without_update (seq, stmt); } @@ -5713,31 +6144,28 @@ gimple_build (gimple_seq *seq, location_t loc, } /* Build the expression (CODE OP0 OP1 OP2) of type TYPE with location LOC, - simplifying it first if possible using VALUEIZE if not NULL. - OP0, OP1 and OP2 are expected to be valueized already. Returns the built + simplifying it first if possible. Returns the built expression value and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, - enum tree_code code, tree type, tree op0, tree op1, tree op2, - tree (*valueize)(tree)) + enum tree_code code, tree type, tree op0, tree op1, tree op2) { tree res = gimple_simplify (code, type, op0, op1, op2, - seq, valueize); + seq, gimple_build_valueize); if (!res) { if (gimple_in_ssa_p (cfun)) - res = make_ssa_name (type, NULL); + res = make_ssa_name (type); else - res = create_tmp_reg (type, NULL); + res = create_tmp_reg (type); gimple stmt; if (code == BIT_FIELD_REF) - stmt = gimple_build_assign_with_ops (code, res, - build3 (BIT_FIELD_REF, type, - op0, op1, op2)); + stmt = gimple_build_assign (res, code, + build3 (code, type, op0, op1, op2)); else - stmt = gimple_build_assign_with_ops (code, res, op0, op1, op2); + stmt = gimple_build_assign (res, code, op0, op1, op2); gimple_set_location (stmt, loc); gimple_seq_add_stmt_without_update (seq, stmt); } @@ -5746,17 +6174,15 @@ gimple_build (gimple_seq *seq, location_t loc, /* Build the call FN (ARG0) with a result of type TYPE (or no result if TYPE is void) with location LOC, - simplifying it first if possible using VALUEIZE if not NULL. - ARG0 is expected to be valueized already. Returns the built + simplifying it first if possible. Returns the built expression value (or NULL_TREE if TYPE is void) and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, - enum built_in_function fn, tree type, tree arg0, - tree (*valueize)(tree)) + enum built_in_function fn, tree type, tree arg0) { - tree res = gimple_simplify (fn, type, arg0, seq, valueize); + tree res = gimple_simplify (fn, type, arg0, seq, gimple_build_valueize); if (!res) { tree decl = builtin_decl_implicit (fn); @@ -5764,9 +6190,9 @@ gimple_build (gimple_seq *seq, location_t loc, if (!VOID_TYPE_P (type)) { if (gimple_in_ssa_p (cfun)) - res = make_ssa_name (type, NULL); + res = make_ssa_name (type); else - res = create_tmp_reg (type, NULL); + res = create_tmp_reg (type); gimple_call_set_lhs (stmt, res); } gimple_set_location (stmt, loc); @@ -5777,17 +6203,15 @@ gimple_build (gimple_seq *seq, location_t loc, /* Build the call FN (ARG0, ARG1) with a result of type TYPE (or no result if TYPE is void) with location LOC, - simplifying it first if possible using VALUEIZE if not NULL. - ARG0 is expected to be valueized already. Returns the built + simplifying it first if possible. Returns the built expression value (or NULL_TREE if TYPE is void) and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, - enum built_in_function fn, tree type, tree arg0, tree arg1, - tree (*valueize)(tree)) + enum built_in_function fn, tree type, tree arg0, tree arg1) { - tree res = gimple_simplify (fn, type, arg0, arg1, seq, valueize); + tree res = gimple_simplify (fn, type, arg0, arg1, seq, gimple_build_valueize); if (!res) { tree decl = builtin_decl_implicit (fn); @@ -5795,9 +6219,9 @@ gimple_build (gimple_seq *seq, location_t loc, if (!VOID_TYPE_P (type)) { if (gimple_in_ssa_p (cfun)) - res = make_ssa_name (type, NULL); + res = make_ssa_name (type); else - res = create_tmp_reg (type, NULL); + res = create_tmp_reg (type); gimple_call_set_lhs (stmt, res); } gimple_set_location (stmt, loc); @@ -5808,18 +6232,17 @@ gimple_build (gimple_seq *seq, location_t loc, /* Build the call FN (ARG0, ARG1, ARG2) with a result of type TYPE (or no result if TYPE is void) with location LOC, - simplifying it first if possible using VALUEIZE if not NULL. - ARG0 is expected to be valueized already. Returns the built + simplifying it first if possible. Returns the built expression value (or NULL_TREE if TYPE is void) and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, enum built_in_function fn, tree type, - tree arg0, tree arg1, tree arg2, - tree (*valueize)(tree)) + tree arg0, tree arg1, tree arg2) { - tree res = gimple_simplify (fn, type, arg0, arg1, arg2, seq, valueize); + tree res = gimple_simplify (fn, type, arg0, arg1, arg2, + seq, gimple_build_valueize); if (!res) { tree decl = builtin_decl_implicit (fn); @@ -5827,9 +6250,9 @@ gimple_build (gimple_seq *seq, location_t loc, if (!VOID_TYPE_P (type)) { if (gimple_in_ssa_p (cfun)) - res = make_ssa_name (type, NULL); + res = make_ssa_name (type); else - res = create_tmp_reg (type, NULL); + res = create_tmp_reg (type); gimple_call_set_lhs (stmt, res); } gimple_set_location (stmt, loc);