The following fixes PR85627 and more generally complex lowering not preserving EH information with -fnon-call-exceptions when replacing complex multiplication or division with a libcall.
This requires changing BUILT_IN_COMPLEX_{MUL,DIV} to be no longer declared nothrow - complex lowering (which looks like the only consumer) properly will set the nothrow flag on the individual call based on the context. Test coverage of -fnon-call-exceptions is notoriously bad and I'm not sure whether Ada uses GCCs complex types. Eric? Otherwise does this look sane? I'm waiting for Kyrylos patch to come in and then will refresh and re-test. Bootstrap / regtest running on x86_64-unknown-linux-gnu. Richard. 2018-05-03 Richard Biener <rguent...@suse.de> PR middle-end/85627 * tree-complex.c (update_complex_assignment): We are always in SSA form. (expand_complex_div_wide): Likewise. (expand_complex_operations_1): Likewise. (expand_complex_libcall): Preserve EH info of the original stmt. (tree_lower_complex): Handle removed blocks. * tree.c (build_common_builtin_nodes): Do not set ECF_NOTRHOW on complex multiplication and division libcall builtins. * g++.dg/torture/pr85627.C: New testcase. Index: gcc/tree-complex.c =================================================================== --- gcc/tree-complex.c (revision 259879) +++ gcc/tree-complex.c (working copy) @@ -703,8 +703,7 @@ update_complex_assignment (gimple_stmt_i if (maybe_clean_eh_stmt (stmt)) gimple_purge_dead_eh_edges (gimple_bb (stmt)); - if (gimple_in_ssa_p (cfun)) - update_complex_components (gsi, gsi_stmt (*gsi), r, i); + update_complex_components (gsi, gsi_stmt (*gsi), r, i); } @@ -1009,20 +1008,29 @@ expand_complex_libcall (gimple_stmt_iter stmt = gimple_build_call (fn, 4, ar, ai, br, bi); gimple_call_set_lhs (stmt, lhs); + gimple_call_set_nothrow (stmt, !stmt_could_throw_p (old_stmt)); update_stmt (stmt); - gsi_replace (gsi, stmt, false); + gsi_replace (gsi, stmt, true); - if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt)) - gimple_purge_dead_eh_edges (gsi_bb (*gsi)); - - if (gimple_in_ssa_p (cfun)) + type = TREE_TYPE (type); + if (stmt_can_throw_internal (stmt)) { - type = TREE_TYPE (type); - update_complex_components (gsi, stmt, + edge_iterator ei; + edge e; + FOR_EACH_EDGE (e, ei, gimple_bb (stmt)->succs) + if (!(e->flags & EDGE_EH)) + break; + basic_block bb = split_edge (e); + gimple_stmt_iterator gsi2 = gsi_start_bb (bb); + update_complex_components (&gsi2, stmt, build1 (REALPART_EXPR, type, lhs), build1 (IMAGPART_EXPR, type, lhs)); - SSA_NAME_DEF_STMT (lhs) = stmt; } + else + update_complex_components (gsi, stmt, + build1 (REALPART_EXPR, type, lhs), + build1 (IMAGPART_EXPR, type, lhs)); + SSA_NAME_DEF_STMT (lhs) = stmt; } /* Expand complex multiplication to scalars: @@ -1170,14 +1178,8 @@ expand_complex_div_wide (gimple_stmt_ite gimple *stmt; tree cond, tmp; - tmp = create_tmp_var (boolean_type_node); + tmp = make_ssa_name (boolean_type_node); stmt = gimple_build_assign (tmp, compare); - if (gimple_in_ssa_p (cfun)) - { - tmp = make_ssa_name (tmp, stmt); - gimple_assign_set_lhs (stmt, tmp); - } - gsi_insert_before (gsi, stmt, GSI_SAME_STMT); cond = fold_build2_loc (gimple_location (stmt), @@ -1602,25 +1604,20 @@ expand_complex_operations_1 (gimple_stmt else br = bi = NULL_TREE; - if (gimple_in_ssa_p (cfun)) + al = find_lattice_value (ac); + if (al == UNINITIALIZED) + al = VARYING; + + if (TREE_CODE_CLASS (code) == tcc_unary) + bl = UNINITIALIZED; + else if (ac == bc) + bl = al; + else { - al = find_lattice_value (ac); - if (al == UNINITIALIZED) - al = VARYING; - - if (TREE_CODE_CLASS (code) == tcc_unary) - bl = UNINITIALIZED; - else if (ac == bc) - bl = al; - else - { - bl = find_lattice_value (bc); - if (bl == UNINITIALIZED) - bl = VARYING; - } + bl = find_lattice_value (bc); + if (bl == UNINITIALIZED) + bl = VARYING; } - else - al = bl = VARYING; switch (code) { @@ -1692,6 +1689,8 @@ tree_lower_complex (void) for (i = 0; i < n_bbs; i++) { bb = BASIC_BLOCK_FOR_FN (cfun, rpo[i]); + if (!bb) + continue; update_phi_components (bb); for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) expand_complex_operations_1 (&gsi); Index: gcc/tree.c =================================================================== --- gcc/tree.c (revision 259879) +++ gcc/tree.c (working copy) @@ -10386,17 +10386,19 @@ build_common_builtin_nodes (void) *q = TOLOWER (*p); *q = '\0'; + /* For -ftrapping-math these should throw from a former + -fnon-call-exception stmt. */ built_in_names[mcode] = concat (prefix, "mul", mode_name_buf, "3", NULL); local_define_builtin (built_in_names[mcode], ftype, mcode, built_in_names[mcode], - ECF_CONST | ECF_NOTHROW | ECF_LEAF); + ECF_CONST | ECF_LEAF); built_in_names[dcode] = concat (prefix, "div", mode_name_buf, "3", NULL); local_define_builtin (built_in_names[dcode], ftype, dcode, built_in_names[dcode], - ECF_CONST | ECF_NOTHROW | ECF_LEAF); + ECF_CONST | ECF_LEAF); } } Index: gcc/testsuite/g++.dg/torture/pr85627.C =================================================================== --- gcc/testsuite/g++.dg/torture/pr85627.C (nonexistent) +++ gcc/testsuite/g++.dg/torture/pr85627.C (working copy) @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */ +/* { dg-additional-options "-fnon-call-exceptions -fdump-tree-optimized" } */ + +__complex double +foo (__complex double a, __complex double b) +{ + __complex res = a; + try { + res = a * b; + } + catch (...) { + res = b; + } + return res; +} + +__complex double +bar (__complex double a, __complex double b) +{ + __complex res = a; + try { + res = a / b; + } + catch (...) { + res = b; + } + return res; +} + +/* Verify EH is preserved by complex lowering. */ + +/* { dg-final { scan-tree-dump-times "__cxa_begin_catch" 2 "optimized" } } */