The PR highlights several places where IVOPTs gets lost in tracking
an appropriate base to use for a TARGET_MEM_REF.  The following
addresses the initial place, enough to fix the bug, but already
showing difficulties in avoiding fallout.  The first place is
alloc_iv where we convert the nice pointer IV to an unsigned integer
before applying affine canonicalization.  Removing that causes
gcc.target/i386/pr115462.c to regress because aff_combination_to_tree
invokes fold which eventually, with unlucky association, triggers
fold_plusminus_mult_expr and factoring resulting in missed IV
commoning.  There's also some important part of fold_plusminus_mult_expr
which, when removed, regresses things again (it's all about costs).
Specifically this is factoring a * 4 - b * 4 to (a - b) * 4.  After
the alloc_iv hunk this becomes a * 4 + b * -4U which isn't currently
handled, so I've hacked that in.

The alloc_iv issue was triggered by a somewhat recent change from Tamar
for GCC 15 where IIRC I suggested IVOPTs probably doesn't want to go back to
GENERIC but keep the representation as affine during analysis at least,
but that's a big change.

I'm a bit of at a loss what to do about gcc-16, we can possibly live
with some IVOPTs quality regressions by just picking the alloc_iv
change?  As for fold_plusminus_mult_expr in itself I'm not sure,
suggestions welcome ...

Bootstrap and regtest ongoing on x86_64-unknown-linux-gnu.

As said, I've run over various problematic places in affine and
IVOPTs with regard to "base object"s, but before I fix those
with mostly ignoring regressions thinking about this bug and
16 sounds like a good idea.

Thanks,
Richard.

        PR tree-optimization/125730
        * tree-ssa-loop-ivopts.cc (alloc_iv): Do not convert IVs to
        unsigned before canonicalizing.
        * fold-const.h (want_fold_plusminus_mult_expr): Declare.
        * fold-const.cc (want_fold_plusminus_mult_expr): Define.
        (fold_plusminus_mult_expr): Restrict parts of it.  Extend
        A * CST1 +- B * CST2 handling to allow for unsigned 64bit
        values with sign bit set.
        * tree-affine.cc (add_elt_to_tree): Unset
        want_fold_plusminus_mult_expr around folding of PLUS/MINUS_EXPR.

        * gcc.dg/torture/pr125730.c: New testcase.
---
 gcc/fold-const.cc                       | 14 +++++----
 gcc/fold-const.h                        |  2 ++
 gcc/testsuite/gcc.dg/torture/pr125730.c | 40 +++++++++++++++++++++++++
 gcc/tree-affine.cc                      | 18 +++++++++--
 gcc/tree-ssa-loop-ivopts.cc             |  8 ++---
 5 files changed, 69 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr125730.c

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 7f49126c95a..3f94180e0d2 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -7198,6 +7198,8 @@ fold_to_nonsharp_ineq_using_bound (location_t loc, tree 
ineq, tree bound)
   return fold_build2_loc (loc, GE_EXPR, type, a, y);
 }
 
+bool want_fold_plusminus_mult_expr = true;
+
 /* Fold a sum or difference of at least one multiplication.
    Returns the folded tree or NULL if no simplification could be made.  */
 
@@ -7237,7 +7239,8 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code 
code, tree type,
       arg10 = TREE_OPERAND (arg1, 0);
       arg11 = TREE_OPERAND (arg1, 1);
     }
-  else if (TREE_CODE (arg1) == INTEGER_CST)
+  else if (TREE_CODE (arg1) == INTEGER_CST
+          && want_fold_plusminus_mult_expr)
     {
       arg10 = build_one_cst (type);
       /* As we canonicalize A - 2 to A + -2 get rid of that sign for
@@ -7255,7 +7258,7 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code 
code, tree type,
   else
     {
       /* We cannot generate constant 1 for fract.  */
-      if (ALL_FRACT_MODE_P (TYPE_MODE (type)))
+      if (ALL_FRACT_MODE_P (TYPE_MODE (type)) || 
!want_fold_plusminus_mult_expr)
        return NULL_TREE;
       arg10 = arg1;
       arg11 = build_one_cst (type);
@@ -7275,10 +7278,11 @@ fold_plusminus_mult_expr (location_t loc, enum 
tree_code code, tree type,
   /* No identical multiplicands; see if we can find a common
      power-of-two factor in non-power-of-two multiplies.  This
      can help in multi-dimensional array access.  */
-  else if (tree_fits_shwi_p (arg01) && tree_fits_shwi_p (arg11))
+  else if ((tree_fits_shwi_p (arg01) || tree_fits_uhwi_p (arg01))
+          && (tree_fits_shwi_p (arg11) || tree_fits_uhwi_p (arg11)))
     {
-      HOST_WIDE_INT int01 = tree_to_shwi (arg01);
-      HOST_WIDE_INT int11 = tree_to_shwi (arg11);
+      HOST_WIDE_INT int01 = TREE_INT_CST_LOW (arg01);
+      HOST_WIDE_INT int11 = TREE_INT_CST_LOW (arg11);
       HOST_WIDE_INT tmp;
       bool swap = false;
       tree maybe_same;
diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index 57d32b1b6ca..ddf7718d1d7 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -31,6 +31,8 @@ extern int folding_initializer;
    during folding in that context.  */
 extern bool folding_cxx_constexpr;
 
+extern bool want_fold_plusminus_mult_expr;
+
 /* Convert between trees and native memory representation.  */
 extern int native_encode_expr (const_tree, unsigned char *, int, int off = -1);
 extern int native_encode_initializer (tree, unsigned char *, int,
diff --git a/gcc/testsuite/gcc.dg/torture/pr125730.c 
b/gcc/testsuite/gcc.dg/torture/pr125730.c
new file mode 100644
index 00000000000..ef698e4f513
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr125730.c
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+
+char *key;
+char *value;
+char **name_regex = &key;
+
+__attribute__ ((noipa)) void
+dict_get_item_ref (char ***result)
+{
+  *result = &value;
+}
+
+__attribute__ ((noinline)) static void
+parse_keyword_dict (char ***argnames, char ***values,
+                   int num_posargs, int num_kwargs)
+{
+  char ***first_kw_arg = argnames + num_posargs;
+  char ***name = first_kw_arg;
+
+  while (*name && num_kwargs > 0)
+    {
+      char **fetched_value;
+      dict_get_item_ref (&fetched_value);
+      values[name - argnames] = fetched_value;
+      name++;
+    }
+}
+
+int
+main ()
+{
+  char **fetched_values[] = { 0 };
+  char **argnames[] = { name_regex, 0 };
+  parse_keyword_dict (argnames, fetched_values, 0, 1);
+
+  if (fetched_values[0] != &value)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/tree-affine.cc b/gcc/tree-affine.cc
index b5b7249c675..531625a0520 100644
--- a/gcc/tree-affine.cc
+++ b/gcc/tree-affine.cc
@@ -494,7 +494,11 @@ add_elt_to_tree (tree expr, tree type, tree elt, const 
widest_int &scale_in)
       if (!expr)
        return elt;
 
-      return fold_build2 (PLUS_EXPR, type, expr, elt);
+      bool saved_want_fold_plusminus_mult_expr = want_fold_plusminus_mult_expr;
+      want_fold_plusminus_mult_expr = false;
+      elt = fold_build2 (PLUS_EXPR, type, expr, elt);
+      want_fold_plusminus_mult_expr = saved_want_fold_plusminus_mult_expr;
+      return elt;
     }
 
   if (scale == -1)
@@ -502,7 +506,11 @@ add_elt_to_tree (tree expr, tree type, tree elt, const 
widest_int &scale_in)
       if (!expr)
        return fold_build1 (NEGATE_EXPR, type, elt);
 
-      return fold_build2 (MINUS_EXPR, type, expr, elt);
+      bool saved_want_fold_plusminus_mult_expr = want_fold_plusminus_mult_expr;
+      want_fold_plusminus_mult_expr = false;
+      elt = fold_build2 (MINUS_EXPR, type, expr, elt);
+      want_fold_plusminus_mult_expr = saved_want_fold_plusminus_mult_expr;
+      return elt;
     }
 
   if (!expr)
@@ -517,7 +525,11 @@ add_elt_to_tree (tree expr, tree type, tree elt, const 
widest_int &scale_in)
     code = PLUS_EXPR;
 
   elt = fold_build2 (MULT_EXPR, type, elt, wide_int_to_tree (type, scale));
-  return fold_build2 (code, type, expr, elt);
+  bool saved_want_fold_plusminus_mult_expr = want_fold_plusminus_mult_expr;
+  want_fold_plusminus_mult_expr = false;
+  elt = fold_build2 (code, type, expr, elt);
+  want_fold_plusminus_mult_expr = saved_want_fold_plusminus_mult_expr;
+  return elt;
 }
 
 /* Makes tree from the affine combination COMB.  */
diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc
index 5c209ab77dc..15221b55e6f 100644
--- a/gcc/tree-ssa-loop-ivopts.cc
+++ b/gcc/tree-ssa-loop-ivopts.cc
@@ -1162,8 +1162,8 @@ alloc_iv (struct ivopts_data *data, tree base, tree step,
                                              sizeof (struct iv));
   gcc_assert (step != NULL_TREE);
 
-  /* Canonicalize the address expression in base if it were an unsigned
-      computation. That leads to more equalities being detected and results in:
+  /* Canonicalize the address expression in base.
+     That leads to more equalities being detected and results in:
 
        1) More accurate cost can be computed for address expressions;
        2) Duplicate candidates won't be created for bases in different
@@ -1171,10 +1171,8 @@ alloc_iv (struct ivopts_data *data, tree base, tree step,
        3) Duplicate candidates won't be created for IV expressions that differ
          only in their sign.  */
   aff_tree comb;
-  STRIP_NOPS (expr);
-  expr = fold_convert (unsigned_type_for (TREE_TYPE (expr)), expr);
   tree_to_aff_combination (expr, TREE_TYPE (expr), &comb);
-  base = fold_convert (TREE_TYPE (base), aff_combination_to_tree (&comb));
+  base = aff_combination_to_tree (&comb);
 
   iv->base = base;
   iv->base_object = determine_base_object (data, base);
-- 
2.51.0

Reply via email to