aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2014-08-18 14:51:04 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2014-08-18 14:51:04 +0000
commitd7e78447084450a8961172d8670f3add9a439d3c (patch)
treebee237c22bc9fb7e476ab299631bf10e912e77cd
parent040292e700e79d48385da73a976e3ea7d7e4b913 (diff)
downloadgcc-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
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/builtins.c127
-rw-r--r--gcc/gimple-fold.c187
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/pr62090-2.c24
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));
+}