aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2013-04-19 13:39:16 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2013-04-19 13:39:16 +0000
commitf6b64c35014ca111711e753be85bb99280a1e115 (patch)
treecfb5aede3dc10b27de8a955ca7bcb7bff5699aa4 /gcc
parent01d8bf070a2ca6a10c66a81f1b5e1c00856b5bc4 (diff)
downloadgcc-f6b64c35014ca111711e753be85bb99280a1e115.zip
gcc-f6b64c35014ca111711e753be85bb99280a1e115.tar.gz
gcc-f6b64c35014ca111711e753be85bb99280a1e115.tar.bz2
re PR tree-optimization/56982 (Bad optimization with setjmp())
2013-04-19 Richard Biener <rguenther@suse.de> PR tree-optimization/56982 * builtins.def (BUILT_IN_LONGJMP): longjmp is not a leaf function. * gimplify.c (gimplify_call_expr): Notice special calls. (gimplify_modify_expr): Likewise. * tree-cfg.c (make_abnormal_goto_edges): Handle setjmp-like abnormal control flow receivers. (call_can_make_abnormal_goto): Handle cfun->calls_setjmp in the same way as cfun->has_nonlocal_labels. (gimple_purge_dead_abnormal_call_edges): Likewise. (stmt_starts_bb_p): Make setjmp-like abnormal control flow receivers start a basic-block. * gcc.c-torture/execute/pr56982.c: New testcase. From-SVN: r198096
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/builtins.def2
-rw-r--r--gcc/gimplify.c2
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr56982.c43
-rw-r--r--gcc/tree-cfg.c51
6 files changed, 100 insertions, 18 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8bdf2a9..e2aca32 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,20 @@
2013-04-19 Richard Biener <rguenther@suse.de>
+ PR tree-optimization/56982
+ * builtins.def (BUILT_IN_LONGJMP): longjmp is not a leaf
+ function.
+ * gimplify.c (gimplify_call_expr): Notice special calls.
+ (gimplify_modify_expr): Likewise.
+ * tree-cfg.c (make_abnormal_goto_edges): Handle setjmp-like
+ abnormal control flow receivers.
+ (call_can_make_abnormal_goto): Handle cfun->calls_setjmp
+ in the same way as cfun->has_nonlocal_labels.
+ (gimple_purge_dead_abnormal_call_edges): Likewise.
+ (stmt_starts_bb_p): Make setjmp-like abnormal control flow
+ receivers start a basic-block.
+
+2013-04-19 Richard Biener <rguenther@suse.de>
+
* tree-vectorizer.h (struct _slp_instance): Move load_permutation
member ...
(struct _slp_tree): ... here. Make it a vector of unsigned ints.
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 4f378fa..b26eb24 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -715,7 +715,7 @@ DEF_GCC_BUILTIN (BUILT_IN_ISLESSGREATER, "islessgreater", BT_FN_INT_VAR,
DEF_GCC_BUILTIN (BUILT_IN_ISUNORDERED, "isunordered", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
DEF_LIB_BUILTIN (BUILT_IN_LABS, "labs", BT_FN_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_C99_BUILTIN (BUILT_IN_LLABS, "llabs", BT_FN_LONGLONG_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
-DEF_GCC_BUILTIN (BUILT_IN_LONGJMP, "longjmp", BT_FN_VOID_PTR_INT, ATTR_NORETURN_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_LONGJMP, "longjmp", BT_FN_VOID_PTR_INT, ATTR_NORETURN_NOTHROW_LIST)
/* [trans-mem]: Adjust BUILT_IN_TM_MALLOC if BUILT_IN_MALLOC is changed. */
DEF_LIB_BUILTIN (BUILT_IN_MALLOC, "malloc", BT_FN_PTR_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_NEXT_ARG, "next_arg", BT_FN_PTR_VAR, ATTR_LEAF_LIST)
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index a93ce7c..3a90588 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -2729,6 +2729,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
gimple_stmt_iterator gsi;
call = gimple_build_call_from_tree (*expr_p);
gimple_call_set_fntype (call, TREE_TYPE (fnptrtype));
+ notice_special_calls (call);
gimplify_seq_add_stmt (pre_p, call);
gsi = gsi_last (*pre_p);
fold_stmt (&gsi);
@@ -4968,6 +4969,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p));
assign = gimple_build_call_from_tree (*from_p);
gimple_call_set_fntype (assign, TREE_TYPE (fnptrtype));
+ notice_special_calls (assign);
if (!gimple_call_noreturn_p (assign))
gimple_call_set_lhs (assign, *to_p);
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 58b0fca..a31889a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2013-04-19 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/56982
+ * gcc.c-torture/execute/pr56982.c: New testcase.
+
2013-04-19 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/56718
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr56982.c b/gcc/testsuite/gcc.c-torture/execute/pr56982.c
new file mode 100644
index 0000000..371a91c
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr56982.c
@@ -0,0 +1,43 @@
+#include <stdlib.h>
+#include <setjmp.h>
+
+static sigjmp_buf env;
+void *stderr;
+void baz (void)
+{
+ __asm__ volatile ("" : : : "memory");
+}
+
+static inline int g(int x)
+{
+ if (x)
+ {
+ baz();
+ return 0;
+ }
+ else
+ {
+ baz();
+ return 1;
+ }
+}
+
+int f(int *e)
+{
+ if (*e)
+ return 1;
+
+ int x = setjmp(env);
+ int n = g(x);
+ if (n == 0)
+ exit(0);
+ if (x)
+ abort();
+ longjmp(env, 42);
+}
+
+int main(int argc, char** argv)
+{
+ int v = 0;
+ return f(&v);
+}
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 8a36976..05bac43 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -967,25 +967,35 @@ make_abnormal_goto_edges (basic_block bb, bool for_call)
gimple_stmt_iterator gsi;
FOR_EACH_BB (target_bb)
- for (gsi = gsi_start_bb (target_bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gimple label_stmt = gsi_stmt (gsi);
- tree target;
+ {
+ for (gsi = gsi_start_bb (target_bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple label_stmt = gsi_stmt (gsi);
+ tree target;
- if (gimple_code (label_stmt) != GIMPLE_LABEL)
- break;
+ if (gimple_code (label_stmt) != GIMPLE_LABEL)
+ break;
- target = gimple_label_label (label_stmt);
+ target = gimple_label_label (label_stmt);
- /* Make an edge to every label block that has been marked as a
- potential target for a computed goto or a non-local goto. */
- if ((FORCED_LABEL (target) && !for_call)
- || (DECL_NONLOCAL (target) && for_call))
- {
+ /* Make an edge to every label block that has been marked as a
+ potential target for a computed goto or a non-local goto. */
+ if ((FORCED_LABEL (target) && !for_call)
+ || (DECL_NONLOCAL (target) && for_call))
+ {
+ make_edge (bb, target_bb, EDGE_ABNORMAL);
+ break;
+ }
+ }
+ if (!gsi_end_p (gsi))
+ {
+ /* Make an edge to every setjmp-like call. */
+ gimple call_stmt = gsi_stmt (gsi);
+ if (is_gimple_call (call_stmt)
+ && (gimple_call_flags (call_stmt) & ECF_RETURNS_TWICE))
make_edge (bb, target_bb, EDGE_ABNORMAL);
- break;
- }
- }
+ }
+ }
}
/* Create edges for a goto statement at block BB. */
@@ -2147,7 +2157,8 @@ call_can_make_abnormal_goto (gimple t)
{
/* If the function has no non-local labels, then a call cannot make an
abnormal transfer of control. */
- if (!cfun->has_nonlocal_label)
+ if (!cfun->has_nonlocal_label
+ && !cfun->calls_setjmp)
return false;
/* Likewise if the call has no side effects. */
@@ -2302,6 +2313,11 @@ stmt_starts_bb_p (gimple stmt, gimple prev_stmt)
else
return true;
}
+ else if (gimple_code (stmt) == GIMPLE_CALL
+ && gimple_call_flags (stmt) & ECF_RETURNS_TWICE)
+ /* setjmp acts similar to a nonlocal GOTO target and thus should
+ start a new block. */
+ return true;
return false;
}
@@ -7532,7 +7548,8 @@ gimple_purge_dead_abnormal_call_edges (basic_block bb)
edge_iterator ei;
gimple stmt = last_stmt (bb);
- if (!cfun->has_nonlocal_label)
+ if (!cfun->has_nonlocal_label
+ && !cfun->calls_setjmp)
return false;
if (stmt && stmt_can_make_abnormal_goto (stmt))