[Bug tree-optimization/114151] [14 Regression] weird and inefficient codegen and addressing modes since g:a0b1798042d033fd2cc2c806afbb77875dd2909b

2024-03-01 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114151

--- Comment #6 from Richard Biener  ---
(In reply to Andrew Macleod from comment #5)
> (In reply to rguent...@suse.de from comment #4)
> 
> > 
> > What was definitely missing is consideration of POLY_INT_CSTs (and
> > variable polys, as I think there's no range info for those).
> > 
> Ranger doesn't do anything with POLY_INTs, mostly because I didn't
> understand them.  
> 
> > We do eventually want to improve how ranger behaves here.  I'm not sure
> > why when we do not provide a context 'stmt' it can't see to compute
> > a range valid at the SSA names point of definition?  (so basically
> > compute the global range)
> 
> The call looks like it doesn't provide the stmt.  Without the stmt, all
> ranger will ever provide is global ranges.
> 
> I think you are asking why, If there is no global range, it doesn't try to
> compute one from the ssa_name_def_stmt?  Ranger does when it is active.  

I tried with an active ranger but that doesn't make a difference.  Basically
I added enable_ranger () / disable_ranger () around the pass and thought
that would "activate" it.  But looking at range_for_expr I don't see how
that would make a difference without a provided stmt.

But maybe I'm doing it wrong?

[Bug tree-optimization/114151] [14 Regression] weird and inefficient codegen and addressing modes since g:a0b1798042d033fd2cc2c806afbb77875dd2909b

2024-02-29 Thread amacleod at redhat dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114151

--- Comment #5 from Andrew Macleod  ---
(In reply to rguent...@suse.de from comment #4)

> 
> What was definitely missing is consideration of POLY_INT_CSTs (and
> variable polys, as I think there's no range info for those).
> 
Ranger doesn't do anything with POLY_INTs, mostly because I didn't understand
them.  

> We do eventually want to improve how ranger behaves here.  I'm not sure
> why when we do not provide a context 'stmt' it can't see to compute
> a range valid at the SSA names point of definition?  (so basically
> compute the global range)

The call looks like it doesn't provide the stmt.  Without the stmt, all ranger
will ever provide is global ranges.

I think you are asking why, If there is no global range, it doesn't try to
compute one from the ssa_name_def_stmt?  Ranger does when it is active.  
Otherwise it simply picks up the global information from SSA_NAME_RANGE_INFO() 
  Of course, if its a poly int, we don't actually support those... so all you
will ever see is VARYING.  Again, because I don't understand them.


> Maybe there's another API to do that.  But I thought it was convenient
> to use range_of_expr as that also handles GENERIC expression trees
> to some extent and those are common within SCEV.

A range can always be calculated by simply calling fold_range from
gimple-range-fold.h:

// Fold stmt S into range R using range query Q.
bool fold_range (vrange , gimple *s, range_query *q = NULL);

if range_query is not provided, it'll simply use the current one.   If you want
to ensure its only global ranges, you call it with

fold_range (r, SSA_NAME_DEF_STMT (name), get_global_range_query ());

[Bug tree-optimization/114151] [14 Regression] weird and inefficient codegen and addressing modes since g:a0b1798042d033fd2cc2c806afbb77875dd2909b

2024-02-28 Thread rguenther at suse dot de via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114151

--- Comment #4 from rguenther at suse dot de  ---
On Wed, 28 Feb 2024, tnfchris at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114151
> 
> --- Comment #3 from Tamar Christina  ---
> > 
> > This was a correctness fix btw, so I'm not sure we can easily recover - we
> > could try using niter information for CHREC_VARIABLE but then there's
> > variable niter here so I don't see a chance.
> > 
> 
> It looks like it's mostly SVE suffering here. Adv. SIMD an scalar codegen 
> seems
> to have vastly improved with it. we see ~10% improvements due to better
> addressing for scalar.
> 
> It also only happens at -O3 but -O2 is fine, which is weird as I was expected
> IVopts to be enabled at -O2 too.

Note the underlying issue, analyzing { a, +, b } * c differently and
thus eventually dependent CHRECs failing to analyze should be independent
on the architecture.

What was definitely missing is consideration of POLY_INT_CSTs (and
variable polys, as I think there's no range info for those).

We do eventually want to improve how ranger behaves here.  I'm not sure
why when we do not provide a context 'stmt' it can't see to compute
a range valid at the SSA names point of definition?  (so basically
compute the global range)

Maybe there's another API to do that.  But I thought it was convenient
to use range_of_expr as that also handles GENERIC expression trees
to some extent and those are common within SCEV.

[Bug tree-optimization/114151] [14 Regression] weird and inefficient codegen and addressing modes since g:a0b1798042d033fd2cc2c806afbb77875dd2909b

2024-02-28 Thread tnfchris at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114151

--- Comment #3 from Tamar Christina  ---
> 
> This was a correctness fix btw, so I'm not sure we can easily recover - we
> could try using niter information for CHREC_VARIABLE but then there's
> variable niter here so I don't see a chance.
> 

It looks like it's mostly SVE suffering here. Adv. SIMD an scalar codegen seems
to have vastly improved with it. we see ~10% improvements due to better
addressing for scalar.

It also only happens at -O3 but -O2 is fine, which is weird as I was expected
IVopts to be enabled at -O2 too.

> 
> OTOH the +1 could make it overflow for large size.
> 
> Can you test the above?  It should be an incremental improvement.
> 

Applying the changes does not seem to make a difference for the final codegen
:(

[Bug tree-optimization/114151] [14 Regression] weird and inefficient codegen and addressing modes since g:a0b1798042d033fd2cc2c806afbb77875dd2909b

2024-02-28 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114151

--- Comment #2 from Richard Biener  ---
Yep, it seems to only pick up global ranges that way.

diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc
index 7cae5bdefea..626fc5bf5d7 100644
--- a/gcc/tree-ssa-loop-ivopts.cc
+++ b/gcc/tree-ssa-loop-ivopts.cc
@@ -132,6 +132,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vectorizer.h"
 #include "dbgcnt.h"
 #include "cfganal.h"
+#include "gimple-range.h"

 /* For lang_hooks.types.type_for_mode.  */
 #include "langhooks.h"
@@ -8280,6 +8281,8 @@ tree_ssa_iv_optimize (void)
   tree_ssa_iv_optimize_init ();
   mark_ssa_maybe_undefs ();

+  enable_ranger (cfun);
+
   /* Optimize the loops starting with the innermost ones.  */
   for (auto loop : loops_list (cfun, LI_FROM_INNERMOST))
 {
@@ -8292,6 +8295,8 @@ tree_ssa_iv_optimize (void)
   tree_ssa_iv_optimize_loop (, loop, toremove);
 }

+  disable_ranger (cfun);
+
   /* Remove eliminated IV defs.  */
   release_defs_bitset (toremove);

[Bug tree-optimization/114151] [14 Regression] weird and inefficient codegen and addressing modes since g:a0b1798042d033fd2cc2c806afbb77875dd2909b

2024-02-28 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114151

Richard Biener  changed:

   What|Removed |Added

 Status|UNCONFIRMED |NEW
   Last reconfirmed||2024-02-28
 Ever confirmed|0   |1
 CC||amacleod at redhat dot com,
   ||rsandifo at gcc dot gnu.org
   Target Milestone|--- |14.0

--- Comment #1 from Richard Biener  ---
Do we have POLY_INT_CSTs in CHRECs?  Huh, yeah - we do.  So in IVOPTs the
differences are like

 (get_scalar_evolution 
   (scalar = col_i_61)
-  (scalar_evolution = {iftmp.0_11 * _105, +, iftmp.0_11}_2))
+  (scalar_evolution = (int) {(unsigned int) col_stride_10 * (unsigned int)
_105, +, (unsigned int) col_stride_10}_2))

but also

 (set_scalar_evolution 
   instantiated_below = 22 
   (scalar = _58)
-  (scalar_evolution = {(__fp16 *) p_mat_16(D) + ((long unsigned int) _105 +
(long unsigned int) (iftmp.0_11 * _105)) * 2, +, ((long unsigned int)
iftmp.0_11 + 1) * 2}_2))
+  (scalar_evolution = _58))

(that's completely missed)

Likewise, with POLY_INT_CST:

-  (scalar_evolution = {(__fp16 *) p_mat_16(D) + (((long unsigned int)
(iftmp.0_11 * _105) + (long unsigned int) _105) * 2 + POLY_INT_CST [16, 16]),
+, ((long unsigned int) iftmp.0_11 + 1) * 2}_2))
+  (scalar_evolution = _13))

The special-casing of CHREC * x we allow to be expressed works by looking
at value-ranges and signs of INTEGER_CSTs:

+ if (!ANY_INTEGRAL_TYPE_P (type)
+ || TYPE_OVERFLOW_WRAPS (type)
+ || integer_zerop (CHREC_LEFT (op0))
+ || (TREE_CODE (CHREC_LEFT (op0)) == INTEGER_CST
+ && TREE_CODE (CHREC_RIGHT (op0)) == INTEGER_CST
+ && (tree_int_cst_sgn (CHREC_LEFT (op0))
+ == tree_int_cst_sgn (CHREC_RIGHT (op0
+ || (get_range_query (cfun)->range_of_expr (rl, CHREC_LEFT (op0
...

possibly there might be a way to adapt the "same sign" check to also work
for POLY_INT_CSTs which I think have known signs?  Possibly rewriting
that by using poly_int_tree_p () isntead of checking for INTEGER_CST
and then using known_lt (wi::to_poly_wide (), 0) && known_lt (..., 0)
|| known_gt (..., 0) && known_gt (..., 0) helps?

Nope, the following doesn't make a difference here.

diff --git a/gcc/tree-chrec.cc b/gcc/tree-chrec.cc
index 2e6c7356d3b..366ab914c8f 100644
--- a/gcc/tree-chrec.cc
+++ b/gcc/tree-chrec.cc
@@ -442,10 +442,12 @@ chrec_fold_multiply (tree type,
  if (!ANY_INTEGRAL_TYPE_P (type)
  || TYPE_OVERFLOW_WRAPS (type)
  || integer_zerop (CHREC_LEFT (op0))
- || (TREE_CODE (CHREC_LEFT (op0)) == INTEGER_CST
- && TREE_CODE (CHREC_RIGHT (op0)) == INTEGER_CST
- && (tree_int_cst_sgn (CHREC_LEFT (op0))
- == tree_int_cst_sgn (CHREC_RIGHT (op0
+ || (poly_int_tree_p (CHREC_LEFT (op0))
+ && poly_int_tree_p (CHREC_RIGHT (op0))
+ && ((known_lt (wi::to_poly_widest (CHREC_LEFT (op0)), 0)
+  && known_lt (wi::to_poly_widest (CHREC_RIGHT (op0)), 0))
+ || (known_ge (wi::to_poly_widest (CHREC_LEFT (op0)), 0)
+ && known_ge (wi::to_poly_widest (CHREC_RIGHT (op0)),
0
  || (get_range_query (cfun)->range_of_expr (rl, CHREC_LEFT (op0))
  && !rl.undefined_p ()
  && (rl.nonpositive_p () || rl.nonnegative_p ())


This was a correctness fix btw, so I'm not sure we can easily recover - we
could try using niter information for CHREC_VARIABLE but then there's
variable niter here so I don't see a chance.

This is mainly IVs like

  col_i_61 = col_stride_10 * j_73;
  _60 = (long unsigned int) col_i_61;
  _59 = _60 * 2;
  _58 = a_j_69 + _59;
  _54 = MEM <__SVFloat16_t> [(__fp16 *)_58];

where we compose for example the scalar evolution of col_i_61 by
multiplyinig that of j_73 which is {_105, +, 1}_2 with col_stride_10.

Possibly adding a ranger instance to IVOPTs could help, for this instance
since

   [local count: 118111600]:
  # col_stride_10 = PHI 
  if (size_15(D) > 0)
goto ; [89.00%]
  else
goto ; [11.00%]

   [local count: 118111600]:
  return;

so col_stride_10 should be positive, and _105 as well:

  _12 = MAX_EXPR <_103, 0>;
  _3 = (unsigned int) _12;
  _4 = _3 + 1;
  _105 = (int) _4;

OTOH the +1 could make it overflow for large size.

Can you test the above?  It should be an incremental improvement.

Adding enable_ranger (cfun); / disable_ranger (cfun);  around the IVOPTs
pass doesn't seem to help (but see above - there might not be enough
info, also the code added doesn't pass in a context stmt so ranger
might not do much/anything here).

Confirmed.