On Thu, Dec 19, 2024 at 6:53 AM Alexandre Oliva <ol...@adacore.com> wrote:
>
>
> Introduce flags to disable ifcombine as a whole, or its new components.
>
> Disable the potentially quadratic noncontiguous ifcombine at -O1.
> Adjust the tests that expected it with -O to use -O2 instead.
>
> Is this of interest?  I've made it mostly for PR118032, but turned it
> into a proper patch because it seems to make some sense to be able to
> disable these more expensive and less stable features selectively.
> Regstrapping on x86_64-linux-gnu.  Ok to install?
>
>
> for  gcc/ChangeLog
>
>         * common.opt (fcombine-conditionals): New.
>         (fcombine-field-conditionals): New.
>         (fcombine-noncontiguous-conditionals): New.
>         * doc/invoke.texi: Document them.
>         * tree-ssa-ifcombine.cc (ifcombine_ifandif): Don't call
>         fold_truth_andor if -fno-combine-field-conditionals.
>         (tree_ssa_ifcombine_bb): Quit after the first attempt under
>         -fno-combine-noncontiguous-conditionals.
>         (pass_tree_ifcombine::gate): New.
>
> for  gcc/testsuite/ChangeLog
>
>         * gcc.dg/field-merge-1.c: Bump to -O2.
>         * gcc.dg/field-merge-2.c: Likewise.
>         * gcc.dg/field-merge-3.c: Likewise.
>         * gcc.dg/field-merge-4.c: Likewise.
>         * gcc.dg/field-merge-5.c: Likewise.
>         * gcc.dg/field-merge-6.c: Likewise.
>         * gcc.dg/field-merge-7.c: Likewise.
>         * gcc.dg/field-merge-8.c: Likewise.
>         * gcc.dg/field-merge-9.c: Likewise.
>         * gcc.dg/field-merge-10.c: Likewise.
>         * gcc.dg/field-merge-11.c: Likewise.
>         * gcc.dg/field-merge-13.c: Likewise.
>         * gcc.dg/field-merge-14.c: Likewise.
>         * gcc.dg/field-merge-15.c: Likewise.
>         * gcc.dg/field-merge-16.c: Likewise.
> ---
>  gcc/common.opt                        |   12 +++++++++++
>  gcc/doc/invoke.texi                   |   30 +++++++++++++++++++++++++++
>  gcc/testsuite/gcc.dg/field-merge-1.c  |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-10.c |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-11.c |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-13.c |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-14.c |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-15.c |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-16.c |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-2.c  |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-3.c  |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-4.c  |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-5.c  |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-6.c  |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-7.c  |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-8.c  |    2 +-
>  gcc/testsuite/gcc.dg/field-merge-9.c  |    2 +-
>  gcc/tree-ssa-ifcombine.cc             |   37 
> ++++++++++++++++++++++-----------
>  18 files changed, 82 insertions(+), 27 deletions(-)
>
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 1b72826d44b11..aa5ad79741126 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1241,6 +1241,18 @@ fcode-hoisting
>  Common Var(flag_code_hoisting) Optimization
>  Enable code hoisting.
>
> +fcombine-conditionals
> +Common Var(flag_tree_ifcombine) Init(-1) Optimization
> +Combine conditionals, with the ifcombine optimization pass.
> +
> +fcombine-field-conditionals
> +Common Var(flag_tree_ifcombine_fieldmerge) Init(-1) Optimization
> +Combine conditionals involving separate fields
> +
> +fcombine-noncontiguous-conditionals
> +Common Var(flag_tree_ifcombine_noncontig) Init(-1) Optimization
> +Combine conditionals from noncontiguous blocks

Please don't use -1 initializers, instead populate
opts.cc:default_options_table.

IMO options where it's not clear how they interact are bad.  Does
-fcombine-field-conditionals enable -fcombine-conditionals?  Does
-fno-combine-field-conditionals disable it?  A
-fcombine-conditionals=<mode> might be more obvious here,
though with two independent features (fields and non-contiguous)
a set of <feature> might be better, but that has no generic option
machinery support.

I'd go for a pragmatic solution, add -fcombine-conditionals and
document that with -fexpensive-optimizations we're enabling
non-contiguous support and a --param to limit it's search depth.
I think we don't need the field-conditionals flag at this point
(fold always did this), if you want one for debugging I suggest
to add a --param for it.

>  fcombine-stack-adjustments
>  Common Var(flag_combine_stack_adjustments) Optimization
>  Looks for opportunities to reduce stack adjustments and stack references.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 8ed5536365f79..317b1dd233a66 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -570,6 +570,8 @@ Objective-C and Objective-C++ Dialects}.
>  -fassociative-math  -fauto-profile  -fauto-profile[=@var{path}]
>  -fauto-inc-dec  -fbranch-probabilities
>  -fcaller-saves
> +-fcombine-conditionals -fcombine-field-conditionals
> +-fcombine-noncontiguous-conditionals
>  -fcombine-stack-adjustments  -fconserve-stack
>  -ffold-mem-offsets
>  -fcompare-elim  -fcprop-registers  -fcrossjumping
> @@ -12633,6 +12635,8 @@ complexity than at @option{-O}.
>  @c Please keep the following list alphabetized.
>  @gccoptlist{-fauto-inc-dec
>  -fbranch-count-reg
> +-fcombine-conditionals
> +-fcombine-field-conditionals
>  -fcombine-stack-adjustments
>  -fcompare-elim
>  -fcprop-registers
> @@ -12693,6 +12697,7 @@ also turns on the following optimization flags:
>  @gccoptlist{-falign-functions  -falign-jumps
>  -falign-labels  -falign-loops
>  -fcaller-saves
> +-fcombine-noncontiguous-conditionals
>  -fcode-hoisting
>  -fcrossjumping
>  -fcse-follow-jumps  -fcse-skip-blocks
> @@ -13676,6 +13681,31 @@ those which have no call-preserved registers to use 
> instead.
>
>  Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
>
> +@opindex fcombine-conditionals
> +@opindex fno-combine-conditionals
> +@item -fcombine-conditionals
> +Enable combination of conditionals from blocks without side effects.
> +
> +It has no effect when not optimizing.
> +
> +@opindex fcombine-field-conditionals
> +@opindex fno-combine-field-conditionals
> +@item -fcombine-field-conditionals
> +Enable combination of conditionals involving different fields, and
> +similar transformations that widen loads to save compares.
> +
> +It has no effect if @option{-fcombine-conditionals} is not enabled.
> +
> +@opindex fcombine-noncontiguous-conditionals
> +@opindex fno-combine-noncontiguous-conditionals
> +@item -fcombine-noncontiguous-conditionals
> +Enable combination of conditionals that belong to the same chain of
> +tests, even if they aren't adjacent.
> +
> +It has no effect if @option{-fcombine-conditionals} is not enabled.
> +
> +Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
> +
>  @opindex fcombine-stack-adjustments
>  @item -fcombine-stack-adjustments
>  Tracks stack adjustments (pushes and pops) and stack memory references
> diff --git a/gcc/testsuite/gcc.dg/field-merge-1.c 
> b/gcc/testsuite/gcc.dg/field-merge-1.c
> index 1818e104437e1..64905ca04d197 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-1.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-1.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O -save-temps -fdump-tree-optimized" } */
> +/* { dg-options "-O2 -save-temps -fdump-tree-optimized" } */
>
>  /* Check that field loads compared with constants are merged, even if
>     tested out of order, and when fields straddle across alignment
> diff --git a/gcc/testsuite/gcc.dg/field-merge-10.c 
> b/gcc/testsuite/gcc.dg/field-merge-10.c
> index dca6febb75859..5ad33b9068505 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-10.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-10.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O" } */
> +/* { dg-options "-O2" } */
>
>  /* Check that we don't move loads across stores.  */
>
> diff --git a/gcc/testsuite/gcc.dg/field-merge-11.c 
> b/gcc/testsuite/gcc.dg/field-merge-11.c
> index fe627cddd7fdf..66af1f0b21b09 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-11.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-11.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O" } */
> +/* { dg-options "-O2" } */
>
>  /* Check that narrowing casts aren't ignored, and that same-field tests at
>     different widths aren't misoptimized.  */
> diff --git a/gcc/testsuite/gcc.dg/field-merge-13.c 
> b/gcc/testsuite/gcc.dg/field-merge-13.c
> index 7e4f4c499347f..dc5259b1be8b5 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-13.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-13.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O -fdump-tree-ifcombine-details" } */
> +/* { dg-options "-O2 -fdump-tree-ifcombine-details" } */
>
>  /* Check that we optimize swapped compares, and that we don't load from 
> objects
>     before they're fully initialized.  */
> diff --git a/gcc/testsuite/gcc.dg/field-merge-14.c 
> b/gcc/testsuite/gcc.dg/field-merge-14.c
> index 91d84cfebf196..0ef0942c176dc 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-14.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-14.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O -fdump-tree-ifcombine-details" } */
> +/* { dg-options "-O2 -fdump-tree-ifcombine-details" } */
>
>  /* Check that we don't get confused by multiple conversions.  */
>
> diff --git a/gcc/testsuite/gcc.dg/field-merge-15.c 
> b/gcc/testsuite/gcc.dg/field-merge-15.c
> index 34641e893c92f..e365f8f86c2d1 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-15.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-15.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O -fdump-tree-ifcombine-details" } */
> +/* { dg-options "-O2 -fdump-tree-ifcombine-details" } */
>
>  /* Check that bitfield compares-with-zero turned into GT and LE compares with
>     powers-of-two minus 1 are optimized.  */
> diff --git a/gcc/testsuite/gcc.dg/field-merge-16.c 
> b/gcc/testsuite/gcc.dg/field-merge-16.c
> index 2ca23ea663a45..75783547eef66 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-16.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-16.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O -fdump-tree-ifcombine-details" } */
> +/* { dg-options "-O2 -fdump-tree-ifcombine-details" } */
>
>  /* Check that tests for sign-extension bits are handled correctly.  */
>
> diff --git a/gcc/testsuite/gcc.dg/field-merge-2.c 
> b/gcc/testsuite/gcc.dg/field-merge-2.c
> index 80c573b31ddc7..976d41e357ad6 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-2.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-2.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O" } */
> +/* { dg-options "-O2" } */
>
>  struct TL {
>    unsigned short a;
> diff --git a/gcc/testsuite/gcc.dg/field-merge-3.c 
> b/gcc/testsuite/gcc.dg/field-merge-3.c
> index f26e8a96ea04f..6ea01007422f4 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-3.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-3.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O" } */
> +/* { dg-options "-O2" } */
>
>  const int BIG_ENDIAN_P = (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
>
> diff --git a/gcc/testsuite/gcc.dg/field-merge-4.c 
> b/gcc/testsuite/gcc.dg/field-merge-4.c
> index c629069e52b2c..691f95fe94c82 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-4.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-4.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O" } */
> +/* { dg-options "-O2" } */
>
>  struct T1 {
>    unsigned int zn;
> diff --git a/gcc/testsuite/gcc.dg/field-merge-5.c 
> b/gcc/testsuite/gcc.dg/field-merge-5.c
> index 1580b14bcc935..6fbab1760f0cd 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-5.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-5.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O" } */
> +/* { dg-options "-O2" } */
>
>  struct T1 {
>    unsigned int zn;
> diff --git a/gcc/testsuite/gcc.dg/field-merge-6.c 
> b/gcc/testsuite/gcc.dg/field-merge-6.c
> index 7fd48a138d14a..49465682c1fa1 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-6.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-6.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O" } */
> +/* { dg-options "-O2" } */
>  /* { dg-shouldfail } */
>
>  /* Check that the third compare won't be pulled ahead of the second one and
> diff --git a/gcc/testsuite/gcc.dg/field-merge-7.c 
> b/gcc/testsuite/gcc.dg/field-merge-7.c
> index 728a29b6fafa9..a6a2f0a3bb0e0 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-7.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-7.c
> @@ -1,5 +1,5 @@
>  /* { dg-do compile } */
> -/* { dg-options "-O -fdump-tree-ifcombine-details" } */
> +/* { dg-options "-O2 -fdump-tree-ifcombine-details" } */
>
>  /* Check that the third compare won't be combined with the first one.  */
>
> diff --git a/gcc/testsuite/gcc.dg/field-merge-8.c 
> b/gcc/testsuite/gcc.dg/field-merge-8.c
> index ae270e10070e4..8d71f919b8977 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-8.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-8.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O" } */
> +/* { dg-options "-O2" } */
>
>  /* Check that conversions are not thrown away.  */
>
> diff --git a/gcc/testsuite/gcc.dg/field-merge-9.c 
> b/gcc/testsuite/gcc.dg/field-merge-9.c
> index 04df54c2b74ef..64fdfe3d0c6e8 100644
> --- a/gcc/testsuite/gcc.dg/field-merge-9.c
> +++ b/gcc/testsuite/gcc.dg/field-merge-9.c
> @@ -1,5 +1,5 @@
>  /* { dg-do run } */
> -/* { dg-options "-O -fdump-tree-ifcombine-details" } */
> +/* { dg-options "-O2 -fdump-tree-ifcombine-details" } */
>
>  /* Check that conversions and selections of similar bit ranges across 
> different
>     types don't prevent combination.  */
> diff --git a/gcc/tree-ssa-ifcombine.cc b/gcc/tree-ssa-ifcombine.cc
> index c9399a1069452..108fa5b17dacb 100644
> --- a/gcc/tree-ssa-ifcombine.cc
> +++ b/gcc/tree-ssa-ifcombine.cc
> @@ -972,18 +972,19 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool 
> inner_inv,
>                                             gimple_cond_lhs (outer_cond),
>                                             gimple_cond_rhs (outer_cond),
>                                             gimple_bb (outer_cond)))
> -         && !(t = (fold_truth_andor_for_ifcombine
> -                   (TRUTH_ANDIF_EXPR, boolean_type_node,
> -                    gimple_location (outer_cond),
> -                    outer_cond_code,
> -                    gimple_cond_lhs (outer_cond),
> -                    gimple_cond_rhs (outer_cond),
> -                    gimple_location (inner_cond),
> -                    inner_cond_code,
> -                    gimple_cond_lhs (inner_cond),
> -                    gimple_cond_rhs (inner_cond),
> -                    single_pred (inner_cond_bb) != outer_cond_bb
> -                    ? &ts : 0))))
> +         && !(flag_tree_ifcombine_fieldmerge
> +              && (t = (fold_truth_andor_for_ifcombine
> +                       (TRUTH_ANDIF_EXPR, boolean_type_node,
> +                        gimple_location (outer_cond),
> +                        outer_cond_code,
> +                        gimple_cond_lhs (outer_cond),
> +                        gimple_cond_rhs (outer_cond),
> +                        gimple_location (inner_cond),
> +                        inner_cond_code,
> +                        gimple_cond_lhs (inner_cond),
> +                        gimple_cond_rhs (inner_cond),
> +                        single_pred (inner_cond_bb) != outer_cond_bb
> +                        ? &ts : 0)))))
>         {
>           /* Only combine conditions in this fallback case if the blocks are
>              neighbors.  */
> @@ -1255,6 +1256,9 @@ tree_ssa_ifcombine_bb (basic_block inner_cond_bb)
>        /* Record the exit path taken by the outer condition.  */
>        if (!exit_bb)
>         {
> +         if (!flag_tree_ifcombine_noncontig)
> +           break;
> +
>           /* If we have removed the outer condition entirely, we need not
>              commit to an exit block yet, it's as if we'd merged the blocks 
> and
>              were starting afresh.  This is sound as long as we never replace
> @@ -1369,6 +1373,15 @@ public:
>    {}
>
>    /* opt_pass methods: */
> +  bool gate (function *) final override {
> +    if (!flag_tree_ifcombine)
> +      return false;
> +
> +    if (flag_tree_ifcombine_noncontig == -1)
> +      flag_tree_ifcombine_noncontig = (optimize >= 2 || optimize_size);
> +
> +    return flag_tree_ifcombine;
> +  }
>    unsigned int execute (function *) final override;
>
>  }; // class pass_tree_ifcombine
>
> --
> Alexandre Oliva, happy hacker            https://FSFLA.org/blogs/lxo/
>    Free Software Activist                   GNU Toolchain Engineer
> More tolerance and less prejudice are key for inclusion and diversity
> Excluding neuro-others for not behaving ""normal"" is *not* inclusive

Reply via email to