On Thu, 7 Aug 2025, Jakub Jelinek wrote: > Hi! > > My earlier r16-1886 PR120608 change incorrectly assumed that the > finally_tmp.N vars introduced by eh pass will be only initialized > to values 0 and 1 and there will be only EQ_EXPR/NE_EXPR comparisons > of those. > > The following testcases show that is a bad assumption, the eh pass > sets finally_tmp.N vars to 0 up to some highest index depending on > hoiw many different exits there are from the finally region. > And it emits then switch (finally_tmp.N) statement for all the > different cases. So, if it uses more than 0/1 indexes, the lowering > of the switch can turn it into a series of GIMPLE_CONDs, > if (finally_tmp.N_M > 15) > goto ... > else > goto ... > > if (finally_tmp.N_M > 7) > goto ... > else > goto ... > etc. (and that also means no longer single uses). And if unlucky, > we can see a non-lowered GIMPLE_SWITCH as well. > > So, the following patch removes the assumption that it has to be 0/1 > and EQ_EXPR/NE_EXPR, allows all the normal integral comparisons > and handles GIMPLE_SWITCH too. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/15.3?
OK. Richard. > 2025-08-07 Jakub Jelinek <ja...@redhat.com> > > PR middle-end/121389 > * tree-tailcall.cc (find_tail_calls): For finally_tmp.N > handle not just GIMPLE_CONDs with EQ_EXPR/NE_EXPR and only > values 0 and 1, but arbitrary non-negative values, arbitrary > comparisons in conditions and also GIMPLE_SWITCH next to > GIMPLE_CONDs. > > * c-c++-common/asan/pr121389-1.c: New test. > * c-c++-common/asan/pr121389-2.c: New test. > * c-c++-common/asan/pr121389-3.c: New test. > * c-c++-common/asan/pr121389-4.c: New test. > > --- gcc/tree-tailcall.cc.jj 2025-08-07 08:40:59.951833459 +0200 > +++ gcc/tree-tailcall.cc 2025-08-07 13:33:22.870820827 +0200 > @@ -605,6 +605,12 @@ find_tail_calls (basic_block bb, edge es > && (stmt = last_nondebug_stmt (bb)) > && gimple_code (stmt) == GIMPLE_COND) > ; > + else if (esucc > + && cfun->has_musttail > + && diag_musttail > + && (stmt = last_nondebug_stmt (bb)) > + && gimple_code (stmt) == GIMPLE_SWITCH) > + ; > /* If there is an abnormal edge assume it's the only extra one. > Tolerate that case so that we can give better error messages > for musttail later. */ > @@ -668,7 +674,7 @@ find_tail_calls (basic_block bb, edge es > else > goto <bb 6>; [INV] > When walking backwards, ESUCC is the edge we are coming from, > - depending on its EDGE_TRUE_FLAG, == vs. != for the comparison > + depending on its EDGE_TRUE_FLAG, comparison code > and value compared against try to find out through which edge > we need to go and which edge should be ignored. The code handles > both INTEGER_CST PHI arguments and SSA_NAMEs set to constants > @@ -677,19 +683,16 @@ find_tail_calls (basic_block bb, edge es > && diag_musttail > && esucc > && gimple_code (stmt) == GIMPLE_COND > - && (gimple_cond_code (stmt) == EQ_EXPR > - || gimple_cond_code (stmt) == NE_EXPR) > && TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME > && TREE_CODE (gimple_cond_rhs (stmt)) == INTEGER_CST > && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))) > - && (integer_zerop (gimple_cond_rhs (stmt)) > - || integer_onep (gimple_cond_rhs (stmt)))) > + && tree_int_cst_sgn (gimple_cond_rhs (stmt)) >= 0) > { > tree lhs = gimple_cond_lhs (stmt); > - bool rhsv = integer_onep (gimple_cond_rhs (stmt)); > - if (((esucc->flags & EDGE_TRUE_VALUE) != 0) > - ^ (gimple_cond_code (stmt) == EQ_EXPR)) > - rhsv = !rhsv; > + tree_code ccode = gimple_cond_code (stmt); > + tree rhsv = gimple_cond_rhs (stmt); > + if ((esucc->flags & EDGE_FALSE_VALUE) != 0) > + ccode = invert_tree_comparison (ccode, false); > if (!ignored_edges) > { > ignored_edges = new hash_set<edge>; > @@ -700,8 +703,10 @@ find_tail_calls (basic_block bb, edge es > && (gimple_assign_rhs_code (SSA_NAME_DEF_STMT (lhs)) > == INTEGER_CST)) > { > - tree rhs = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (lhs)); > - if (rhsv ? integer_onep (rhs) : integer_zerop (rhs)) > + tree lhsv = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (lhs)); > + > + if (const_binop (ccode, boolean_type_node, lhsv, rhsv) > + == boolean_true_node) > continue; > } > else if (gimple_code (SSA_NAME_DEF_STMT (lhs)) == GIMPLE_PHI) > @@ -712,15 +717,62 @@ find_tail_calls (basic_block bb, edge es > edge_iterator ei; > FOR_EACH_EDGE (e, ei, pbb->preds) > { > - tree rhs = gimple_phi_arg_def_from_edge (phi, e); > - if (TREE_CODE (rhs) == SSA_NAME > - && is_gimple_assign (SSA_NAME_DEF_STMT (rhs)) > - && (gimple_assign_rhs_code (SSA_NAME_DEF_STMT (rhs)) > + tree lhsv = gimple_phi_arg_def_from_edge (phi, e); > + if (TREE_CODE (lhsv) == SSA_NAME > + && is_gimple_assign (SSA_NAME_DEF_STMT (lhsv)) > + && (gimple_assign_rhs_code (SSA_NAME_DEF_STMT (lhsv)) > + == INTEGER_CST)) > + lhsv = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (lhsv)); > + if (TREE_CODE (lhsv) != INTEGER_CST > + || const_binop (ccode, boolean_type_node, > + lhsv, rhsv) != boolean_true_node) > + ignored_edges->add (e); > + } > + continue; > + } > + } > + if (cfun->has_musttail > + && diag_musttail > + && esucc > + && gimple_code (stmt) == GIMPLE_SWITCH > + && (TREE_CODE (gimple_switch_index (as_a <gswitch *> (stmt))) > + == SSA_NAME)) > + { > + gswitch *swtch = as_a <gswitch *> (stmt); > + tree idx = gimple_switch_index (swtch); > + if (!ignored_edges) > + { > + ignored_edges = new hash_set<edge>; > + must_see_bbs = new hash_set<basic_block>; > + delete_ignored_edges = true; > + } > + if (is_gimple_assign (SSA_NAME_DEF_STMT (idx)) > + && (gimple_assign_rhs_code (SSA_NAME_DEF_STMT (idx)) > + == INTEGER_CST)) > + { > + tree val = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (idx)); > + if (find_taken_edge_switch_expr (swtch, val) == esucc) > + continue; > + } > + else if (gimple_code (SSA_NAME_DEF_STMT (idx)) == GIMPLE_PHI) > + { > + gimple *phi = SSA_NAME_DEF_STMT (idx); > + basic_block pbb = gimple_bb (phi); > + must_see_bbs->add (pbb); > + edge_iterator ei; > + FOR_EACH_EDGE (e, ei, pbb->preds) > + { > + tree val = gimple_phi_arg_def_from_edge (phi, e); > + if (TREE_CODE (val) == SSA_NAME > + && is_gimple_assign (SSA_NAME_DEF_STMT (val)) > + && (gimple_assign_rhs_code (SSA_NAME_DEF_STMT (val)) > == INTEGER_CST)) > - rhs = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (rhs)); > - if (!(rhsv ? integer_onep (rhs) : integer_zerop (rhs))) > + val = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (val)); > + if (TREE_CODE (val) != INTEGER_CST > + || find_taken_edge_switch_expr (swtch, val) != esucc) > ignored_edges->add (e); > } > + continue; > } > } > > @@ -1138,47 +1190,67 @@ find_tail_calls (basic_block bb, edge es > if (ignored_edges) > { > if (is_gimple_assign (stmt) > - && gimple_assign_rhs_code (stmt) == INTEGER_CST) > + && gimple_assign_rhs_code (stmt) == INTEGER_CST > + && tree_int_cst_sgn (gimple_assign_rhs1 (stmt)) >= 0) > { > use_operand_p use_p; > - gimple *use_stmt; > - if ((integer_zerop (gimple_assign_rhs1 (stmt)) > - || integer_onep (gimple_assign_rhs1 (stmt))) > - && single_imm_use (gimple_assign_lhs (stmt), &use_p, > - &use_stmt)) > + imm_use_iterator imm_iter; > + bool bad_p = false; > + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, > + gimple_assign_lhs (stmt)) > { > - if (gimple_code (use_stmt) == GIMPLE_COND) > - continue; > - if (gimple_code (use_stmt) == GIMPLE_PHI > - && single_imm_use (gimple_phi_result (use_stmt), > - &use_p, &use_stmt) > - && gimple_code (use_stmt) == GIMPLE_COND) > + gimple *use_stmt = USE_STMT (use_p); > + if (is_gimple_debug (use_stmt) > + || gimple_code (use_stmt) == GIMPLE_COND > + || gimple_code (use_stmt) == GIMPLE_SWITCH) > continue; > + if (gimple_code (use_stmt) == GIMPLE_PHI) > + { > + use_operand_p use_p2; > + imm_use_iterator imm_iter2; > + FOR_EACH_IMM_USE_FAST (use_p2, imm_iter2, > + gimple_phi_result (use_stmt)) > + { > + gimple *use_stmt2 = USE_STMT (use_p2); > + if (is_gimple_debug (use_stmt2) > + || gimple_code (use_stmt2) == GIMPLE_COND > + || gimple_code (use_stmt2) == GIMPLE_SWITCH) > + continue; > + bad_p = true; > + break; > + } > + if (bad_p) > + break; > + } > + else > + { > + bad_p = true; > + break; > + } > } > + if (!bad_p) > + continue; > } > if (gimple_code (stmt) == GIMPLE_COND > - && (gimple_cond_code (stmt) == EQ_EXPR > - || gimple_cond_code (stmt) == NE_EXPR) > && TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME > && TREE_CODE (gimple_cond_rhs (stmt)) == INTEGER_CST > && INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))) > - && (integer_zerop (gimple_cond_rhs (stmt)) > - || integer_onep (gimple_cond_rhs (stmt)))) > + && tree_int_cst_sgn (gimple_cond_rhs (stmt)) >= 0) > { > edge e = NULL, et, ef; > + enum tree_code ccode = gimple_cond_code (stmt); > tree lhs = gimple_cond_lhs (stmt); > - bool rhsv = integer_onep (gimple_cond_rhs (stmt)); > - if (gimple_cond_code (stmt) == NE_EXPR) > - rhsv = !rhsv; > + tree rhsv = gimple_cond_rhs (stmt); > extract_true_false_edges_from_block (gimple_bb (stmt), &et, &ef); > if (is_gimple_assign (SSA_NAME_DEF_STMT (lhs)) > && (gimple_assign_rhs_code (SSA_NAME_DEF_STMT (lhs)) > == INTEGER_CST)) > { > - tree rhs = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (lhs)); > - if (rhsv ? integer_onep (rhs) : integer_zerop (rhs)) > + tree lhsv = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (lhs)); > + tree r = const_binop (ccode, boolean_type_node, lhsv, rhsv); > + if (r == boolean_true_node) > e = et; > - else if (rhsv ? integer_zerop (rhs) : integer_onep (rhs)) > + else if (r == boolean_false_node) > e = ef; > } > else if (gimple_code (SSA_NAME_DEF_STMT (lhs)) == GIMPLE_PHI) > @@ -1188,20 +1260,63 @@ find_tail_calls (basic_block bb, edge es > for (edge e2 : edges) > if (e2->dest == pbb) > { > - tree rhs = gimple_phi_arg_def_from_edge (phi, e2); > - if (TREE_CODE (rhs) == SSA_NAME) > - if (gimple *g = SSA_NAME_DEF_STMT (rhs)) > + tree lhsv = gimple_phi_arg_def_from_edge (phi, e2); > + if (TREE_CODE (lhsv) == SSA_NAME) > + if (gimple *g = SSA_NAME_DEF_STMT (lhsv)) > if (is_gimple_assign (g) > && gimple_assign_rhs_code (g) == INTEGER_CST) > - rhs = gimple_assign_rhs1 (g); > - if (rhsv ? integer_onep (rhs) : integer_zerop (rhs)) > + lhsv = gimple_assign_rhs1 (g); > + tree r = const_binop (ccode, boolean_type_node, > + lhsv, rhsv); > + if (r == boolean_true_node) > e = et; > - else if (rhsv ? integer_zerop (rhs) > - : integer_onep (rhs)) > + else if (r == boolean_false_node) > e = ef; > break; > } > } > + if (e) > + { > + ass_var = propagate_through_phis (ass_var, e); > + if (!ass_var || ignored_edges) > + edges.safe_push (e); > + abb = e->dest; > + agsi = gsi_start_bb (abb); > + goto new_bb; > + } > + } > + if (gimple_code (stmt) == GIMPLE_SWITCH > + && (TREE_CODE (gimple_switch_index (as_a <gswitch *> (stmt))) > + == SSA_NAME)) > + { > + edge e = NULL; > + gswitch *swtch = as_a <gswitch *> (stmt); > + tree idx = gimple_switch_index (swtch); > + if (is_gimple_assign (SSA_NAME_DEF_STMT (idx)) > + && (gimple_assign_rhs_code (SSA_NAME_DEF_STMT (idx)) > + == INTEGER_CST)) > + { > + tree val = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (idx)); > + e = find_taken_edge_switch_expr (swtch, val); > + } > + else if (gimple_code (SSA_NAME_DEF_STMT (idx)) == GIMPLE_PHI) > + { > + gimple *phi = SSA_NAME_DEF_STMT (idx); > + basic_block pbb = gimple_bb (phi); > + for (edge e2 : edges) > + if (e2->dest == pbb) > + { > + tree val = gimple_phi_arg_def_from_edge (phi, e2); > + if (TREE_CODE (val) == SSA_NAME) > + if (gimple *g = SSA_NAME_DEF_STMT (val)) > + if (is_gimple_assign (g) > + && gimple_assign_rhs_code (g) == INTEGER_CST) > + val = gimple_assign_rhs1 (g); > + if (TREE_CODE (val) == INTEGER_CST) > + e = find_taken_edge_switch_expr (swtch, val); > + break; > + } > + } > if (e) > { > ass_var = propagate_through_phis (ass_var, e); > --- gcc/testsuite/c-c++-common/asan/pr121389-1.c.jj 2025-08-07 > 11:12:27.725703815 +0200 > +++ gcc/testsuite/c-c++-common/asan/pr121389-1.c 2025-08-07 > 13:34:42.763753626 +0200 > @@ -0,0 +1,23 @@ > +// PR middle-end/121389 > +// { dg-do compile { target musttail } } > +// { dg-options "-fsanitize=address" } > + > +int foo (void); > +int bar (void); > +int baz (unsigned *); > + > +int > +bar (void) > +{ > + do > + { > + unsigned t; > + int u = baz (&t); > + if (u == 42) > + [[gnu::musttail]] return foo (); > + if (u == -42) > + break; > + } > + while (1); > + return 42; > +} > --- gcc/testsuite/c-c++-common/asan/pr121389-2.c.jj 2025-08-07 > 11:12:27.725703815 +0200 > +++ gcc/testsuite/c-c++-common/asan/pr121389-2.c 2025-08-07 > 13:34:46.900698363 +0200 > @@ -0,0 +1,37 @@ > +// PR middle-end/121389 > +// { dg-do compile { target musttail } } > +// { dg-options "-fsanitize=address" } > + > +int foo (void); > +int bar (void); > +int baz (unsigned *); > + > +int > +bar (void) > +{ > + for (int a = 0; a < 420; ++a) > + { > + for (int b = 0; b < 420; ++b) > + { > + for (int c = 0; c < 420; ++c) > + { > + unsigned t; > + int u = baz (&t); > + if (u == 42) > + [[gnu::musttail]] return foo (); > + if (u == -42) > + break; > + if (u == 16) > + goto l1; > + if (u == 18) > + goto l2; > + if (u == 20) > + goto l3; > + } > + l3:; > + } > + l2:; > + } > + l1:; > + return 42; > +} > --- gcc/testsuite/c-c++-common/asan/pr121389-3.c.jj 2025-08-07 > 11:12:27.725703815 +0200 > +++ gcc/testsuite/c-c++-common/asan/pr121389-3.c 2025-08-07 > 13:34:50.702647575 +0200 > @@ -0,0 +1,130 @@ > +// PR middle-end/121389 > +// { dg-do compile { target musttail } } > +// { dg-options "-fsanitize=address" } > + > +int foo (void); > +int bar (void); > +int baz (unsigned *); > + > +int > +bar (void) > +{ > + for (int a = 0; a < 420; ++a) > + { > + for (int b = 0; b < 420; ++b) > + { > + for (int c = 0; c < 420; ++c) > + { > + unsigned t; > + int u = baz (&t); > + if (u == 42) > + [[gnu::musttail]] return foo (); > + if (u == -42) > + break; > + if (u == 16) > + goto l1; > + if (u == 18) > + goto l2; > + if (u == 20) > + goto l3; > + switch (u) > + { > + case 100: goto l100; > + case 101: goto l101; > + case 102: goto l102; > + case 103: goto l103; > + case 104: goto l104; > + case 105: goto l105; > + case 106: goto l106; > + case 107: goto l107; > + case 108: goto l108; > + case 109: goto l109; > + case 110: goto l110; > + case 111: goto l111; > + case 112: goto l112; > + case 113: goto l113; > + case 114: goto l114; > + case 115: goto l115; > + case 116: goto l116; > + case 117: goto l117; > + case 118: goto l118; > + case 119: goto l119; > + case 120: goto l120; > + case 121: goto l121; > + case 122: goto l122; > + case 123: goto l123; > + case 124: goto l124; > + case 125: goto l125; > + case 126: goto l126; > + case 127: goto l127; > + case 128: goto l128; > + case 129: goto l129; > + } > + } > + l3:; > + foo (); > + l100: > + foo (); > + l101: > + foo (); > + l102: > + foo (); > + l103: > + foo (); > + l104: > + foo (); > + l105: > + foo (); > + l106: > + foo (); > + l107: > + foo (); > + l108: > + foo (); > + l109:; > + } > + l2:; > + foo (); > + l110: > + foo (); > + l111: > + foo (); > + l112: > + foo (); > + l113: > + foo (); > + l114: > + foo (); > + l115: > + foo (); > + l116: > + foo (); > + l117: > + foo (); > + l118: > + foo (); > + l119:; > + } > + l1:; > + foo (); > + l120: > + foo (); > + l121: > + foo (); > + l122: > + foo (); > + l123: > + foo (); > + l124: > + foo (); > + l125: > + foo (); > + l126: > + foo (); > + l127: > + foo (); > + l128: > + foo (); > + l129:; > + return 42; > +} > --- gcc/testsuite/c-c++-common/asan/pr121389-4.c.jj 2025-08-07 > 11:12:27.725703815 +0200 > +++ gcc/testsuite/c-c++-common/asan/pr121389-4.c 2025-08-07 > 13:36:21.066440504 +0200 > @@ -0,0 +1,6 @@ > +// PR middle-end/121389 > +// { dg-do compile { target musttail } } > +// { dg-options "-fsanitize=address -fdisable-tree-switchlower_O0" } > +// { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } > + > +#include "pr121389-3.c" > > Jakub > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)