Hi! The following patch, when optimizing, replaces GIMPLE_RETURN in noreturn functions right after warning about them with __builtin_unreachable (). The advantage of that is that we don't emit unnecessary epilogues for them and perhaps optimize away some other useless computations if the only side-effect of those is feeding the return value.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2017-10-19 Jakub Jelinek <ja...@redhat.com> PR target/82158 * tree-cfg.c (pass_warn_function_return::execute): In noreturn functions when optimizing replace GIMPLE_RETURN stmts with calls to __builtin_unreachable (). * gcc.dg/tree-ssa/noreturn-1.c: New test. --- gcc/tree-cfg.c.jj 2017-10-10 22:04:09.000000000 +0200 +++ gcc/tree-cfg.c 2017-10-19 18:41:04.843653944 +0200 @@ -9084,13 +9084,29 @@ pass_warn_function_return::execute (func && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (fun)->preds) > 0) { location = UNKNOWN_LOCATION; - FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (fun)->preds) + for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (fun)->preds); + (e = ei_safe_edge (ei)); ) { last = last_stmt (e->src); if ((gimple_code (last) == GIMPLE_RETURN || gimple_call_builtin_p (last, BUILT_IN_RETURN)) - && (location = gimple_location (last)) != UNKNOWN_LOCATION) + && location == UNKNOWN_LOCATION + && (location = gimple_location (last)) != UNKNOWN_LOCATION + && !optimize) break; + /* When optimizing, replace return stmts in noreturn functions + with __builtin_unreachable () call. */ + if (optimize && gimple_code (last) == GIMPLE_RETURN) + { + tree fndecl = builtin_decl_implicit (BUILT_IN_UNREACHABLE); + gimple *new_stmt = gimple_build_call (fndecl, 0); + gimple_set_location (new_stmt, gimple_location (last)); + gimple_stmt_iterator gsi = gsi_for_stmt (last); + gsi_replace (&gsi, new_stmt, true); + remove_edge (e); + } + else + ei_next (&ei); } if (location == UNKNOWN_LOCATION) location = cfun->function_end_locus; --- gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c.jj 2017-10-19 18:50:53.861660409 +0200 +++ gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c 2017-10-19 18:55:32.270354804 +0200 @@ -0,0 +1,42 @@ +/* { dg-do compile } * +/* { dg-options "-O2 -fdump-tree-ssa -std=gnu11" } */ +/* { dg-final { scan-tree-dump-times "__builtin_unreachable" 4 "ssa" } } */ + +void bar1 (void); +void bar2 (void); +void bar3 (void); +void bar4 (void); + +_Noreturn void +foo1 (int *p, int y) +{ + bar1 (); + *p = y; + return; /* { dg-warning "function declared 'noreturn' has a 'return' statement" } */ +} /* { dg-warning "'noreturn' function does return" "" { target *-*-* } .-1 } */ + +_Noreturn void +foo2 (int *p, int y) +{ + bar2 (); + *p = y; +} /* { dg-warning "'noreturn' function does return" } */ + +_Noreturn void +foo3 (int *p, int y) +{ + if (y > 10) + return; /* { dg-warning "function declared 'noreturn' has a 'return' statement" } */ + bar3 (); + *p = y; + return; /* { dg-warning "function declared 'noreturn' has a 'return' statement" } */ +} /* { dg-warning "'noreturn' function does return" } */ + +_Noreturn void +foo4 (int *p, int y) +{ + if (y > 10) + return; /* { dg-warning "function declared 'noreturn' has a 'return' statement" } */ + bar4 (); + *p = y; +} /* { dg-warning "'noreturn' function does return" } */ Jakub