On Thu, Dec 3, 2015 at 6:54 PM, Jeff Law <l...@redhat.com> wrote:
> This is something I noticed while working on fixing 67816.
>
> Essentially I was seeing trivially true or trivially false conditionals left
> in the IL for DOM to clean up.
>
> While DOM can and will clean that crud up, but a trivially true or trivially
> false conditional ought to be detected and cleaned up by cleanup_cfg.
>
> It turns out the reassociation pass does not schedule a CFG cleanup even in
> cases where it optimizes a conditional to TRUE or FALSE.
>
> Bubbling up an indicator that we optimized away a conditional and using that
> to trigger a CFG cleanup is trivial.
>
> While I have a slight preference to see this fix in GCC 6, if folks object
> and want this to wait for GCC 7 stage1, I'd understand.
>
> Bootstrapped and regression tested on x86_64-linux-gnu.
>
> OK for the trunk?

Ok.  [I always hoped we can at some point assert we don't have trivially
optimizable control flow in the IL]

Richard.

> Thanks,
> Jeff
>
> diff --git a/gcc/ChangeLog b/gcc/ChangeLog
> index 04dbcb0..61a5e54 100644
> --- a/gcc/ChangeLog
> +++ b/gcc/ChangeLog
> @@ -1,3 +1,12 @@
> +2015-12-03  Jeff Law  <l...@redhat.com>
> +
> +       * tree-ssa-reassoc.c (maybe_optimize_range_tests): Return boolean
> +       indicating if a gimple conditional was optimized to true/false.
> +       (reassociate_bb): Bubble up return value from
> +       maybe_optimize_range_tests.
> +       (do_reassoc): Similarly, but for reassociate_bb.
> +       (execute_reassoc): Return TODO_cleanup_cfg as needed.
> +
>  2015-11-27  Jiri Engelthaler  <eng...@gmail.com>
>
>         PR driver/68029
> diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
> index 4e62a06..893aab1 100644
> --- a/gcc/testsuite/ChangeLog
> +++ b/gcc/testsuite/ChangeLog
> @@ -1,3 +1,7 @@
> +2015-12-02  Jeff Law  <l...@redhat.com>
> +
> +       * gcc.dg/tree-ssa/reassoc-43.c: New test.
> +
>  2015-12-02  Andreas Krebbel  <kreb...@linux.vnet.ibm.com>
>
>         * gcc.dg/optimize-bswapdi-1.c: Force using -mzarch on s390 and
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-43.c
> b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-43.c
> new file mode 100644
> index 0000000..ea44f30
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-43.c
> @@ -0,0 +1,53 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-reassoc -w" } */
> +
> +typedef union tree_node *tree;
> +enum cpp_ttype { CPP_COLON, CPP_SEMICOLON, CPP_CLOSE_BRACE, CPP_COMMA };
> +enum rid { RID_STATIC = 0, RID_ATTRIBUTE, };
> +typedef struct c_token
> +{
> +  enum cpp_ttype type:8;
> +}
> +c_token;
> +typedef struct c_parser
> +{
> +  c_token tokens[2];
> +  short tokens_avail;
> +}
> +c_parser;
> +__inline__ c_token *
> +c_parser_peek_token (c_parser * parser)
> +{
> +  if (parser->tokens_avail == 0)
> +    {
> +      parser->tokens_avail = 1;
> +    }
> +  return &parser->tokens[0];
> +}
> +
> +__inline__ unsigned char
> +c_parser_next_token_is (c_parser * parser, enum cpp_ttype type)
> +{
> +  return c_parser_peek_token (parser)->type == type;
> +}
> +
> +void
> +c_parser_translation_unit (c_parser * parser)
> +{
> +  tree prefix_attrs;
> +  tree all_prefix_attrs;
> +  while (1)
> +    {
> +      if (c_parser_next_token_is (parser, CPP_COLON)
> +         || c_parser_next_token_is (parser, CPP_COMMA)
> +         || c_parser_next_token_is (parser, CPP_SEMICOLON)
> +         || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)
> +         || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
> +       {
> +         if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
> +           all_prefix_attrs =
> +             chainon (c_parser_attributes (parser), prefix_attrs);
> +       }
> +    }
> +}
> +/* { dg-final { scan-tree-dump-not "0 != 0" "reassoc2"} } */
> diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
> index dfd0da1..315b0bf 100644
> --- a/gcc/tree-ssa-reassoc.c
> +++ b/gcc/tree-ssa-reassoc.c
> @@ -2976,9 +2976,15 @@ struct inter_bb_range_test_entry
>    unsigned int first_idx, last_idx;
>  };
>
> -/* Inter-bb range test optimization.  */
> +/* Inter-bb range test optimization.
>
> -static void
> +   Returns TRUE if a gimple conditional is optimized to a true/false,
> +   otherwise return FALSE.
> +
> +   This indicates to the caller that it should run a CFG cleanup pass
> +   once reassociation is completed.  */
> +
> +static bool
>  maybe_optimize_range_tests (gimple *stmt)
>  {
>    basic_block first_bb = gimple_bb (stmt);
> @@ -2990,6 +2996,7 @@ maybe_optimize_range_tests (gimple *stmt)
>    auto_vec<operand_entry *> ops;
>    auto_vec<inter_bb_range_test_entry> bbinfo;
>    bool any_changes = false;
> +  bool cfg_cleanup_needed = false;
>
>    /* Consider only basic blocks that end with GIMPLE_COND or
>       a cast statement satisfying final_range_test_p.  All
> @@ -2998,15 +3005,15 @@ maybe_optimize_range_tests (gimple *stmt)
>    if (gimple_code (stmt) == GIMPLE_COND)
>      {
>        if (EDGE_COUNT (first_bb->succs) != 2)
> -       return;
> +       return cfg_cleanup_needed;
>      }
>    else if (final_range_test_p (stmt))
>      other_bb = single_succ (first_bb);
>    else
> -    return;
> +    return cfg_cleanup_needed;
>
>    if (stmt_could_throw_p (stmt))
> -    return;
> +    return cfg_cleanup_needed;
>
>    /* As relative ordering of post-dominator sons isn't fixed,
>       maybe_optimize_range_tests can be called first on any
> @@ -3030,14 +3037,14 @@ maybe_optimize_range_tests (gimple *stmt)
>        /* As non-GIMPLE_COND last stmt always terminates the range,
>          if forward search didn't discover anything, just give up.  */
>        if (gimple_code (stmt) != GIMPLE_COND)
> -       return;
> +       return cfg_cleanup_needed;
>        /* Look at both successors.  Either it ends with a GIMPLE_COND
>          and satisfies suitable_cond_bb, or ends with a cast and
>          other_bb is that cast's successor.  */
>        FOR_EACH_EDGE (e, ei, first_bb->succs)
>         if (!(e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))
>             || e->dest == first_bb)
> -         return;
> +         return cfg_cleanup_needed;
>         else if (single_pred_p (e->dest))
>           {
>             stmt = last_stmt (e->dest);
> @@ -3060,7 +3067,7 @@ maybe_optimize_range_tests (gimple *stmt)
>               }
>           }
>        if (other_bb == NULL)
> -       return;
> +       return cfg_cleanup_needed;
>      }
>    /* Now do the forward search, moving last_bb to successor bbs
>       that aren't other_bb.  */
> @@ -3080,7 +3087,7 @@ maybe_optimize_range_tests (gimple *stmt)
>        last_bb = e->dest;
>      }
>    if (first_bb == last_bb)
> -    return;
> +    return cfg_cleanup_needed;
>    /* Here basic blocks first_bb through last_bb's predecessor
>       end with GIMPLE_COND, all of them have one of the edges to
>       other_bb and another to another block in the range,
> @@ -3289,10 +3296,18 @@ maybe_optimize_range_tests (gimple *stmt)
>               && ops[bbinfo[idx].first_idx]->op != NULL_TREE)
>             {
>               gcond *cond_stmt = as_a <gcond *> (last_stmt (bb));
> +             /* If we collapse the conditional to a true/false
> +                condition, then bubble that knowledge up to our caller.  */
>               if (integer_zerop (ops[bbinfo[idx].first_idx]->op))
> -               gimple_cond_make_false (cond_stmt);
> +               {
> +                 gimple_cond_make_false (cond_stmt);
> +                 cfg_cleanup_needed = true;
> +               }
>               else if (integer_onep (ops[bbinfo[idx].first_idx]->op))
> -               gimple_cond_make_true (cond_stmt);
> +               {
> +                 gimple_cond_make_true (cond_stmt);
> +                 cfg_cleanup_needed = true;
> +               }
>               else
>                 {
>                   gimple_cond_set_code (cond_stmt, NE_EXPR);
> @@ -3306,6 +3321,7 @@ maybe_optimize_range_tests (gimple *stmt)
>             break;
>         }
>      }
> +  return cfg_cleanup_needed;
>  }
>
>  /* Return true if OPERAND is defined by a PHI node which uses the LHS
> @@ -4753,17 +4769,20 @@ transform_stmt_to_multiply (gimple_stmt_iterator
> *gsi, gimple *stmt,
>  }
>
>  /* Reassociate expressions in basic block BB and its post-dominator as
> -   children.  */
> +   children.
>
> -static void
> +   Bubble up return status from maybe_optimize_range_tests.  */
> +
> +static bool
>  reassociate_bb (basic_block bb)
>  {
>    gimple_stmt_iterator gsi;
>    basic_block son;
>    gimple *stmt = last_stmt (bb);
> +  bool cfg_cleanup_needed = false;
>
>    if (stmt && !gimple_visited_p (stmt))
> -    maybe_optimize_range_tests (stmt);
> +    cfg_cleanup_needed |= maybe_optimize_range_tests (stmt);
>
>    for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
>      {
> @@ -4922,7 +4941,9 @@ reassociate_bb (basic_block bb)
>    for (son = first_dom_son (CDI_POST_DOMINATORS, bb);
>         son;
>         son = next_dom_son (CDI_POST_DOMINATORS, son))
> -    reassociate_bb (son);
> +    cfg_cleanup_needed |= reassociate_bb (son);
> +
> +  return cfg_cleanup_needed;
>  }
>
>  /* Add jumps around shifts for range tests turned into bit tests.
> @@ -5028,11 +5049,13 @@ debug_ops_vector (vec<operand_entry *> ops)
>    dump_ops_vector (stderr, ops);
>  }
>
> -static void
> +/* Bubble up return status from reassociate_bb.  */
> +
> +static bool
>  do_reassoc (void)
>  {
>    break_up_subtract_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun));
> -  reassociate_bb (EXIT_BLOCK_PTR_FOR_FN (cfun));
> +  return reassociate_bb (EXIT_BLOCK_PTR_FOR_FN (cfun));
>  }
>
>  /* Initialize the reassociation pass.  */
> @@ -5106,7 +5129,10 @@ fini_reassoc (void)
>  }
>
>  /* Gate and execute functions for Reassociation.  If INSERT_POWI_P, enable
> -   insertion of __builtin_powi calls.  */
> +   insertion of __builtin_powi calls.
> +
> +   Returns TODO_cfg_cleanup if a CFG cleanup pass is desired due to
> +   optimization of a gimple conditional.  Otherwise returns zero.  */
>
>  static unsigned int
>  execute_reassoc (bool insert_powi_p)
> @@ -5115,12 +5141,13 @@ execute_reassoc (bool insert_powi_p)
>
>    init_reassoc ();
>
> -  do_reassoc ();
> +  bool cfg_cleanup_needed;
> +  cfg_cleanup_needed = do_reassoc ();
>    repropagate_negates ();
>    branch_fixup ();
>
>    fini_reassoc ();
> -  return 0;
> +  return cfg_cleanup_needed ? TODO_cleanup_cfg : 0;
>  }
>
>  namespace {
>

Reply via email to