This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] PATCH to tree-cfg.c to check TREE_NOTHROW
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 10 Sep 2003 16:47:02 -0400
- Subject: [tree-ssa] PATCH to tree-cfg.c to check TREE_NOTHROW
While looking at other tree-cfg.c problems, I noticed that we were ending a
block on a call to printf. This shouldn't happen, as we know that printf
can't throw. So I've added checks for TREE_NOTHROW in the appropriate
places.
Tested athlon-pc-linux-gnu, applied to tree-ssa. Test in
g++.dg/opt/nothrow1.C.
2003-09-10 Jason Merrill <jason@redhat.com>
* tree-cfg.c (make_call_expr_edges): Break out from...
(make_exit_edges): ...here. Check TREE_NOTHROW.
(is_ctrl_altering_stmt): Check TREE_NOTHROW.
*** tree-cfg.c.~1~ 2003-09-10 05:49:28.000000000 +0000
--- tree-cfg.c 2003-09-10 20:23:12.000000000 +0000
*************** static inline void set_parent_stmt (tree
*** 100,105 ****
--- 100,106 ----
static void make_edges (void);
static void make_ctrl_stmt_edges (basic_block);
static void make_exit_edges (basic_block);
+ static void make_call_expr_edges (basic_block, tree, tree);
static void make_cond_expr_edges (basic_block);
static void make_goto_expr_edges (basic_block);
static void make_case_label_edges (basic_block);
*************** make_blocks (tree *first_p, tree next_bl
*** 508,515 ****
{
start_new_block = true;
- /* Right now we only model exceptions which occur via calls.
- This will need to be generalized in the future. */
if (TREE_CODE (stmt) == CALL_EXPR
|| (TREE_CODE (stmt) == MODIFY_EXPR
&& TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
--- 509,514 ----
*************** make_ctrl_stmt_edges (basic_block bb)
*** 1167,1172 ****
--- 1166,1212 ----
}
}
+ /* A CALL_EXPR node here means that the last statement of the block
+ is a call to a non-returning function or a call that may throw. */
+
+ static void
+ make_call_expr_edges (basic_block bb, tree call, tree stmt)
+ {
+ /* If this function receives a nonlocal goto, then we need to
+ make edges from this call site to all the nonlocal goto
+ handlers. */
+ if (FUNCTION_RECEIVES_NONLOCAL_GOTO (current_function_decl))
+ make_goto_expr_edges (bb);
+
+ /* If this statement has reachable exception handlers, then
+ create abnormal edges to them. */
+ if (stmt_ann (stmt)->reachable_exception_handlers
+ && !TREE_NOTHROW (call))
+ {
+ tree t;
+
+ for (t = stmt_ann (stmt)->reachable_exception_handlers;
+ t;
+ t = TREE_CHAIN (t))
+ make_edge (bb, bb_for_stmt (TREE_VALUE (t)), EDGE_ABNORMAL);
+ }
+
+ /* Some calls are known not to return. For such calls we create
+ a fake edge.
+
+ We really need to revamp how we build edges so that it's not
+ such a bloody pain to avoid creating edges for this case since
+ all we do is remove these edges when we're done building the
+ CFG. */
+ if (call_expr_flags (call) & (ECF_NORETURN | ECF_LONGJMP))
+ {
+ make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
+ return;
+ }
+
+ /* Don't forget the fall-thru edge. */
+ make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
+ }
/* Create exit edges for statements in block BB that alter the flow of
control. Statements that alter the control flow are 'goto', 'return'
*************** make_exit_edges (basic_block bb)
*** 1195,1236 ****
make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL);
break;
- /* A CALL_EXPR node here means that the last statement of the block
- is a call to a non-returning function or a call that may throw. */
case CALL_EXPR:
! /* If this function receives a nonlocal goto, then we need to
! make edges from this call site to all the nonlocal goto
! handlers. */
! if (FUNCTION_RECEIVES_NONLOCAL_GOTO (current_function_decl))
! make_goto_expr_edges (bb);
!
! /* If this statement has reachable exception handlers, then
! create abnormal edges to them. */
! if (stmt_ann (last)->reachable_exception_handlers)
! {
! tree t;
!
! for (t = stmt_ann (last)->reachable_exception_handlers;
! t;
! t = TREE_CHAIN (t))
! make_edge (bb, bb_for_stmt (TREE_VALUE (t)), EDGE_ABNORMAL);
! }
!
! /* Some calls are known not to return. For such calls we create
! a fake edge.
!
! We really need to revamp how we build edges so that it's not
! such a bloody pain to avoid creating edges for this case since
! all we do is remove these edges when we're done building the
! CFG. */
! if (call_expr_flags (last) & (ECF_NORETURN | ECF_LONGJMP))
! {
! make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
! return;
! }
!
! /* Don't forget the fall-thru edge. */
! make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
break;
case RETURN_EXPR:
--- 1235,1242 ----
make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL);
break;
case CALL_EXPR:
! make_call_expr_edges (bb, last, last);
break;
case RETURN_EXPR:
*************** make_exit_edges (basic_block bb)
*** 1242,1265 ****
may have an abnormal edge. Search the RHS for this case and
create any required edges. */
if (TREE_CODE (TREE_OPERAND (last, 1)) == CALL_EXPR)
! {
! if (FUNCTION_RECEIVES_NONLOCAL_GOTO (current_function_decl))
! make_goto_expr_edges (bb);
!
! if (stmt_ann (last)->reachable_exception_handlers)
! {
! tree t;
- for (t = stmt_ann (last)->reachable_exception_handlers;
- t;
- t = TREE_CHAIN (t))
- make_edge (bb,
- bb_for_stmt (TREE_VALUE (t)),
- EDGE_ABNORMAL);
- }
-
- make_edge (bb, successor_block (bb), 0);
- }
if (flag_non_call_exceptions
&& (could_trap_p (TREE_OPERAND (last, 0))
|| could_trap_p (TREE_OPERAND (last, 1))))
--- 1248,1255 ----
may have an abnormal edge. Search the RHS for this case and
create any required edges. */
if (TREE_CODE (TREE_OPERAND (last, 1)) == CALL_EXPR)
! make_call_expr_edges (bb, TREE_OPERAND (last, 1), last);
if (flag_non_call_exceptions
&& (could_trap_p (TREE_OPERAND (last, 0))
|| could_trap_p (TREE_OPERAND (last, 1))))
*************** is_ctrl_altering_stmt (tree t)
*** 3049,3054 ****
--- 3039,3045 ----
/* A CALL_EXPR also alters flow control if it may throw. */
if (code == CALL_EXPR
+ && !TREE_NOTHROW (t)
&& (VARRAY_ACTIVE_SIZE (eh_stack) > 0
|| stmt_ann (t)->reachable_exception_handlers))
return true;
*************** is_ctrl_altering_stmt (tree t)
*** 3057,3062 ****
--- 3048,3054 ----
an abnormal edge if the current function has nonlocal labels. */
if (code == MODIFY_EXPR
&& TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR
+ && !TREE_NOTHROW (TREE_OPERAND (t, 1))
&& (FUNCTION_RECEIVES_NONLOCAL_GOTO (current_function_decl)
|| VARRAY_ACTIVE_SIZE (eh_stack) > 0
|| stmt_ann (t)->reachable_exception_handlers))
// Test that the nothrow optimization works properly.
// { dg-do compile }
// { dg-options "-O -fdump-tree-optimized" }
extern "C" int printf (const char *, ...);
int i, j, k;
int main()
{
try
{
++i;
printf ("foo\n");
++j;
}
catch (...)
{
return 42;
}
}
// The catch block should be optimized away.
// { dg-final { scan-tree-dump-times "42" 0 "optimized" } }