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)

Reply via email to