diff options
author | Richard Biener <rguenther@suse.de> | 2014-08-18 14:51:04 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2014-08-18 14:51:04 +0000 |
commit | d7e78447084450a8961172d8670f3add9a439d3c (patch) | |
tree | bee237c22bc9fb7e476ab299631bf10e912e77cd /gcc | |
parent | 040292e700e79d48385da73a976e3ea7d7e4b913 (diff) | |
download | gcc-d7e78447084450a8961172d8670f3add9a439d3c.zip gcc-d7e78447084450a8961172d8670f3add9a439d3c.tar.gz gcc-d7e78447084450a8961172d8670f3add9a439d3c.tar.bz2 |
re PR middle-end/62090 (ice in compute_may_aliases)
2014-08-18 Richard Biener <rguenther@suse.de>
PR tree-optimization/62090
* builtins.c (fold_builtin_snprintf): Move to gimple-fold.c.
(fold_builtin_3): Do not fold snprintf.
(fold_builtin_4): Likewise.
* gimple-fold.c (gimple_fold_builtin_snprintf): New function
moved from builtins.c.
(gimple_fold_builtin_with_strlen): Fold snprintf and sprintf.
(gimple_fold_builtin): Do not fold sprintf here.
* gcc.dg/pr62090-2.c: New testcase.
From-SVN: r214105
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/builtins.c | 127 | ||||
-rw-r--r-- | gcc/gimple-fold.c | 187 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr62090-2.c | 24 |
5 files changed, 209 insertions, 145 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f471e2c..75591f4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,16 @@ 2014-08-18 Richard Biener <rguenther@suse.de> + PR tree-optimization/62090 + * builtins.c (fold_builtin_snprintf): Move to gimple-fold.c. + (fold_builtin_3): Do not fold snprintf. + (fold_builtin_4): Likewise. + * gimple-fold.c (gimple_fold_builtin_snprintf): New function + moved from builtins.c. + (gimple_fold_builtin_with_strlen): Fold snprintf and sprintf. + (gimple_fold_builtin): Do not fold sprintf here. + +2014-08-18 Richard Biener <rguenther@suse.de> + * gimple-fold.c (maybe_fold_reference): Move re-gimplification code to ... (maybe_canonicalize_mem_ref_addr): ... this function. diff --git a/gcc/builtins.c b/gcc/builtins.c index 8468568..29ddde8 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -190,7 +190,6 @@ static tree fold_builtin_strrchr (location_t, tree, tree, tree); static tree fold_builtin_strncat (location_t, tree, tree, tree); static tree fold_builtin_strspn (location_t, tree, tree); static tree fold_builtin_strcspn (location_t, tree, tree); -static tree fold_builtin_snprintf (location_t, tree, tree, tree, tree, int); static rtx expand_builtin_object_size (tree); static rtx expand_builtin_memory_chk (tree, rtx, enum machine_mode, @@ -10309,9 +10308,6 @@ fold_builtin_3 (location_t loc, tree fndecl, case BUILT_IN_MEMCMP: return fold_builtin_memcmp (loc, arg0, arg1, arg2);; - case BUILT_IN_SNPRINTF: - return fold_builtin_snprintf (loc, arg0, arg1, arg2, NULL_TREE, ignore); - case BUILT_IN_STRCAT_CHK: return fold_builtin_strcat_chk (loc, fndecl, arg0, arg1, arg2); @@ -10364,9 +10360,6 @@ fold_builtin_4 (location_t loc, tree fndecl, case BUILT_IN_STRNCAT_CHK: return fold_builtin_strncat_chk (loc, fndecl, arg0, arg1, arg2, arg3); - case BUILT_IN_SNPRINTF: - return fold_builtin_snprintf (loc, arg0, arg1, arg2, arg3, ignore); - case BUILT_IN_FPRINTF_CHK: case BUILT_IN_VFPRINTF_CHK: if (!validate_arg (arg1, INTEGER_TYPE) @@ -11230,126 +11223,6 @@ fold_builtin_next_arg (tree exp, bool va_start_p) } -/* Simplify a call to the snprintf builtin with arguments DEST, DESTSIZE, - FMT, and ORIG. ORIG may be null if this is a 3-argument call. We don't - attempt to simplify calls with more than 4 arguments. - - Return NULL_TREE if no simplification was possible, otherwise return the - simplified form of the call as a tree. If IGNORED is true, it means that - the caller does not use the returned value of the function. */ - -static tree -fold_builtin_snprintf (location_t loc, tree dest, tree destsize, tree fmt, - tree orig, int ignored) -{ - tree call, retval; - const char *fmt_str = NULL; - unsigned HOST_WIDE_INT destlen; - - /* Verify the required arguments in the original call. We deal with two - types of snprintf() calls: 'snprintf (str, cst, fmt)' and - 'snprintf (dest, cst, "%s", orig)'. */ - if (!validate_arg (dest, POINTER_TYPE) - || !validate_arg (destsize, INTEGER_TYPE) - || !validate_arg (fmt, POINTER_TYPE)) - return NULL_TREE; - if (orig && !validate_arg (orig, POINTER_TYPE)) - return NULL_TREE; - - if (!tree_fits_uhwi_p (destsize)) - return NULL_TREE; - - /* Check whether the format is a literal string constant. */ - fmt_str = c_getstr (fmt); - if (fmt_str == NULL) - return NULL_TREE; - - call = NULL_TREE; - retval = NULL_TREE; - - if (!init_target_chars ()) - return NULL_TREE; - - destlen = tree_to_uhwi (destsize); - - /* If the format doesn't contain % args or %%, use strcpy. */ - if (strchr (fmt_str, target_percent) == NULL) - { - tree fn = builtin_decl_implicit (BUILT_IN_STRCPY); - size_t len = strlen (fmt_str); - - /* Don't optimize snprintf (buf, 4, "abc", ptr++). */ - if (orig) - return NULL_TREE; - - /* We could expand this as - memcpy (str, fmt, cst - 1); str[cst - 1] = '\0'; - or to - memcpy (str, fmt_with_nul_at_cstm1, cst); - but in the former case that might increase code size - and in the latter case grow .rodata section too much. - So punt for now. */ - if (len >= destlen) - return NULL_TREE; - - if (!fn) - return NULL_TREE; - - /* Convert snprintf (str, cst, fmt) into strcpy (str, fmt) when - 'format' is known to contain no % formats and - strlen (fmt) < cst. */ - call = build_call_expr_loc (loc, fn, 2, dest, fmt); - - if (!ignored) - retval = build_int_cst (integer_type_node, strlen (fmt_str)); - } - - /* If the format is "%s", use strcpy if the result isn't used. */ - else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0) - { - tree fn = builtin_decl_implicit (BUILT_IN_STRCPY); - unsigned HOST_WIDE_INT origlen; - - /* Don't crash on snprintf (str1, cst, "%s"). */ - if (!orig) - return NULL_TREE; - - retval = c_strlen (orig, 1); - if (!retval || !tree_fits_uhwi_p (retval)) - return NULL_TREE; - - origlen = tree_to_uhwi (retval); - /* We could expand this as - memcpy (str1, str2, cst - 1); str1[cst - 1] = '\0'; - or to - memcpy (str1, str2_with_nul_at_cstm1, cst); - but in the former case that might increase code size - and in the latter case grow .rodata section too much. - So punt for now. */ - if (origlen >= destlen) - return NULL_TREE; - - /* Convert snprintf (str1, cst, "%s", str2) into - strcpy (str1, str2) if strlen (str2) < cst. */ - if (!fn) - return NULL_TREE; - - call = build_call_expr_loc (loc, fn, 2, dest, orig); - - if (ignored) - retval = NULL_TREE; - } - - if (call && retval) - { - tree fn = builtin_decl_explicit (BUILT_IN_SNPRINTF); - retval = fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fn)), retval); - return build2 (COMPOUND_EXPR, TREE_TYPE (retval), call, retval); - } - else - return call; -} - /* Expand a call EXP to __builtin_object_size. */ static rtx diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index d34be0a..f432baf07 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -2091,7 +2091,7 @@ gimple_fold_builtin_sprintf_chk (gimple_stmt_iterator *gsi, the caller does not use the returned value of the function. */ static bool -gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi) +gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi, tree orig_len) { gimple stmt = gsi_stmt (*gsi); tree dest = gimple_call_arg (stmt, 0); @@ -2169,11 +2169,11 @@ gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi) if (!orig) return false; - tree len = NULL_TREE; - if (gimple_call_lhs (stmt)) + if (gimple_call_lhs (stmt) + && !orig_len) { - len = c_strlen (orig, 1); - if (!len) + orig_len = c_strlen (orig, 1); + if (!orig_len) return false; } @@ -2183,9 +2183,10 @@ gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi) gimple_seq_add_stmt_without_update (&stmts, repl); if (gimple_call_lhs (stmt)) { - if (!useless_type_conversion_p (integer_type_node, TREE_TYPE (len))) - len = fold_convert (integer_type_node, len); - repl = gimple_build_assign (gimple_call_lhs (stmt), len); + if (!useless_type_conversion_p (integer_type_node, + TREE_TYPE (orig_len))) + orig_len = fold_convert (integer_type_node, orig_len); + repl = gimple_build_assign (gimple_call_lhs (stmt), orig_len); gimple_seq_add_stmt_without_update (&stmts, repl); gsi_replace_with_seq_vops (gsi, stmts); /* gsi now points at the assignment to the lhs, get a @@ -2206,7 +2207,147 @@ gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi) return false; } +/* Simplify a call to the snprintf builtin with arguments DEST, DESTSIZE, + FMT, and ORIG. ORIG may be null if this is a 3-argument call. We don't + attempt to simplify calls with more than 4 arguments. + Return NULL_TREE if no simplification was possible, otherwise return the + simplified form of the call as a tree. If IGNORED is true, it means that + the caller does not use the returned value of the function. */ + +static bool +gimple_fold_builtin_snprintf (gimple_stmt_iterator *gsi, tree orig_len) +{ + gimple stmt = gsi_stmt (*gsi); + tree dest = gimple_call_arg (stmt, 0); + tree destsize = gimple_call_arg (stmt, 1); + tree fmt = gimple_call_arg (stmt, 2); + tree orig = NULL_TREE; + const char *fmt_str = NULL; + + if (gimple_call_num_args (stmt) > 4) + return false; + + if (gimple_call_num_args (stmt) == 4) + orig = gimple_call_arg (stmt, 3); + + if (!tree_fits_uhwi_p (destsize)) + return false; + unsigned HOST_WIDE_INT destlen = tree_to_uhwi (destsize); + + /* Check whether the format is a literal string constant. */ + fmt_str = c_getstr (fmt); + if (fmt_str == NULL) + return false; + + if (!init_target_chars ()) + return false; + + /* If the format doesn't contain % args or %%, use strcpy. */ + if (strchr (fmt_str, target_percent) == NULL) + { + tree fn = builtin_decl_implicit (BUILT_IN_STRCPY); + if (!fn) + return false; + + /* Don't optimize snprintf (buf, 4, "abc", ptr++). */ + if (orig) + return false; + + /* We could expand this as + memcpy (str, fmt, cst - 1); str[cst - 1] = '\0'; + or to + memcpy (str, fmt_with_nul_at_cstm1, cst); + but in the former case that might increase code size + and in the latter case grow .rodata section too much. + So punt for now. */ + size_t len = strlen (fmt_str); + if (len >= destlen) + return false; + + gimple_seq stmts = NULL; + gimple repl = gimple_build_call (fn, 2, dest, fmt); + gimple_seq_add_stmt_without_update (&stmts, repl); + if (gimple_call_lhs (stmt)) + { + repl = gimple_build_assign (gimple_call_lhs (stmt), + build_int_cst (integer_type_node, len)); + gimple_seq_add_stmt_without_update (&stmts, repl); + gsi_replace_with_seq_vops (gsi, stmts); + /* gsi now points at the assignment to the lhs, get a + stmt iterator to the memcpy call. + ??? We can't use gsi_for_stmt as that doesn't work when the + CFG isn't built yet. */ + gimple_stmt_iterator gsi2 = *gsi; + gsi_prev (&gsi2); + fold_stmt (&gsi2); + } + else + { + gsi_replace_with_seq_vops (gsi, stmts); + fold_stmt (gsi); + } + return true; + } + + /* If the format is "%s", use strcpy if the result isn't used. */ + else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0) + { + tree fn = builtin_decl_implicit (BUILT_IN_STRCPY); + if (!fn) + return false; + + /* Don't crash on snprintf (str1, cst, "%s"). */ + if (!orig) + return false; + + if (!orig_len) + { + orig_len = c_strlen (orig, 1); + if (!orig_len) + return false; + } + + /* We could expand this as + memcpy (str1, str2, cst - 1); str1[cst - 1] = '\0'; + or to + memcpy (str1, str2_with_nul_at_cstm1, cst); + but in the former case that might increase code size + and in the latter case grow .rodata section too much. + So punt for now. */ + if (compare_tree_int (orig_len, destlen) >= 0) + return false; + + /* Convert snprintf (str1, cst, "%s", str2) into + strcpy (str1, str2) if strlen (str2) < cst. */ + gimple_seq stmts = NULL; + gimple repl = gimple_build_call (fn, 2, dest, orig); + gimple_seq_add_stmt_without_update (&stmts, repl); + if (gimple_call_lhs (stmt)) + { + if (!useless_type_conversion_p (integer_type_node, + TREE_TYPE (orig_len))) + orig_len = fold_convert (integer_type_node, orig_len); + repl = gimple_build_assign (gimple_call_lhs (stmt), orig_len); + gimple_seq_add_stmt_without_update (&stmts, repl); + gsi_replace_with_seq_vops (gsi, stmts); + /* gsi now points at the assignment to the lhs, get a + stmt iterator to the memcpy call. + ??? We can't use gsi_for_stmt as that doesn't work when the + CFG isn't built yet. */ + gimple_stmt_iterator gsi2 = *gsi; + gsi_prev (&gsi2); + fold_stmt (&gsi2); + } + else + { + gsi_replace_with_seq_vops (gsi, stmts); + fold_stmt (gsi); + } + return true; + } + return false; +} /* Fold a call to __builtin_strlen with known length LEN. */ @@ -2232,7 +2373,7 @@ static bool gimple_fold_builtin_with_strlen (gimple_stmt_iterator *gsi) { gimple stmt = gsi_stmt (*gsi); - tree val[3]; + tree val[4]; tree a; int arg_idx, type; bitmap visited; @@ -2276,23 +2417,32 @@ gimple_fold_builtin_with_strlen (gimple_stmt_iterator *gsi) arg_idx = 1; type = 2; break; + case BUILT_IN_SPRINTF: + arg_idx = 2; + type = 0; + break; + case BUILT_IN_SNPRINTF: + arg_idx = 3; + type = 0; + break; default: return false; } int nargs = gimple_call_num_args (stmt); - if (arg_idx >= nargs) - return false; /* Try to use the dataflow information gathered by the CCP process. */ visited = BITMAP_ALLOC (NULL); bitmap_clear (visited); memset (val, 0, sizeof (val)); - a = gimple_call_arg (stmt, arg_idx); - if (!get_maxval_strlen (a, &val[arg_idx], visited, type) - || !is_gimple_val (val[arg_idx])) - val[arg_idx] = NULL_TREE; + if (arg_idx < nargs) + { + a = gimple_call_arg (stmt, arg_idx); + if (!get_maxval_strlen (a, &val[arg_idx], visited, type) + || !is_gimple_val (val[arg_idx])) + val[arg_idx] = NULL_TREE; + } BITMAP_FREE (visited); @@ -2364,7 +2514,10 @@ gimple_fold_builtin_with_strlen (gimple_stmt_iterator *gsi) case BUILT_IN_VSNPRINTF_CHK: return gimple_fold_builtin_snprintf_chk (gsi, val[1], DECL_FUNCTION_CODE (callee)); - + case BUILT_IN_SNPRINTF: + return gimple_fold_builtin_snprintf (gsi, val[3]); + case BUILT_IN_SPRINTF: + return gimple_fold_builtin_sprintf (gsi, val[2]); default: gcc_unreachable (); } @@ -2414,8 +2567,6 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi) case BUILT_IN_SPRINTF_CHK: case BUILT_IN_VSPRINTF_CHK: return gimple_fold_builtin_sprintf_chk (gsi, DECL_FUNCTION_CODE (callee)); - case BUILT_IN_SPRINTF: - return gimple_fold_builtin_sprintf (gsi); default:; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e43e295..89d164c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-08-18 Richard Biener <rguenther@suse.de> + + PR tree-optimization/62090 + * gcc.dg/pr62090-2.c: New testcase. + 2014-08-18 Ilya Enkovich <ilya.enkovich@intel.com> * g++.dg/ipa/pr61800.C: New. diff --git a/gcc/testsuite/gcc.dg/pr62090-2.c b/gcc/testsuite/gcc.dg/pr62090-2.c new file mode 100644 index 0000000..5bddc53 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr62090-2.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef long unsigned int size_t; +extern __inline __attribute__ ((__always_inline__)) +__attribute__ ((__gnu_inline__)) int +snprintf (char *__restrict __s, size_t __n, const char *__restrict __fmt, ...) +{ + return __builtin___snprintf_chk (__s, __n, 2 - 1, + __builtin_object_size (__s, 2 > 1), + __fmt, __builtin_va_arg_pack ()); +} +typedef struct apacket apacket; +struct apacket { + unsigned char data[4096]; +}; +static size_t fill_connect_data(char *buf, size_t bufsize) +{ + return snprintf(buf, bufsize, "host::") + 1; +} +unsigned send_connect(apacket *cp) +{ + return fill_connect_data((char *)cp->data, sizeof(cp->data)); +} |