IVOPTs has strip_offset which suffers from the same issues regarding
integer overflow that split_constant_offset did but the latter was
fixed quite some time ago.  The following implements strip_offset
in terms of split_constant_offset, removing the redundant and
incorrect implementation.

The implementations are not exactly the same, strip_offset relies
on ptrdiff_tree_p to fend off too large offsets while split_constant_offset
simply assumes those do not happen and truncates them.  By
the same means strip_offset also handles POLY_INT_CSTs but
split_constant_offset does not.  Massaging the latter to
behave like strip_offset in those cases might be the way to go?

Bootstrapped and tested on x86_64-unknown-linux-gnu.

Comments?

Thanks,
Richard.

        PR tree-optimization/110243
        * tree-ssa-loop-ivopts.cc (strip_offset_1): Remove.
        (strip_offset): Make it a wrapper around split_constant_offset.

        * gcc.dg/torture/pr110243.c: New testcase.
---
 gcc/testsuite/gcc.dg/torture/pr110243.c |  22 +++
 gcc/tree-ssa-loop-ivopts.cc             | 182 ++----------------------
 2 files changed, 32 insertions(+), 172 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr110243.c

diff --git a/gcc/testsuite/gcc.dg/torture/pr110243.c 
b/gcc/testsuite/gcc.dg/torture/pr110243.c
new file mode 100644
index 00000000000..07dffd95d4d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr110243.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-require-effective-target lp64 } */
+
+#define X 1100000000
+unsigned char a;
+long b = X;
+int c[9][1];
+unsigned d;
+static long *e = &b, *f = &b;
+int g() {
+  if (a && a <= '9')
+    return '0';
+  if (a)
+    return 10;
+  return -1;
+}
+int main() {
+  d = 0;
+  for (; (int)*f -(X-1) + d < 9; d++)
+    c[g() + (int)*f + ((int)*e - X) -(X-1) + d]
+     [0] = 0;
+}
diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc
index 6fbd2d59318..a03764072a4 100644
--- a/gcc/tree-ssa-loop-ivopts.cc
+++ b/gcc/tree-ssa-loop-ivopts.cc
@@ -2772,183 +2772,21 @@ find_interesting_uses (struct ivopts_data *data, 
basic_block *body)
     }
 }
 
-/* Strips constant offsets from EXPR and stores them to OFFSET.  If INSIDE_ADDR
-   is true, assume we are inside an address.  If TOP_COMPREF is true, assume
-   we are at the top-level of the processed address.  */
-
-static tree
-strip_offset_1 (tree expr, bool inside_addr, bool top_compref,
-               poly_int64 *offset)
-{
-  tree op0 = NULL_TREE, op1 = NULL_TREE, tmp, step;
-  enum tree_code code;
-  tree type, orig_type = TREE_TYPE (expr);
-  poly_int64 off0, off1;
-  HOST_WIDE_INT st;
-  tree orig_expr = expr;
-
-  STRIP_NOPS (expr);
-
-  type = TREE_TYPE (expr);
-  code = TREE_CODE (expr);
-  *offset = 0;
-
-  switch (code)
-    {
-    case POINTER_PLUS_EXPR:
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-      op0 = TREE_OPERAND (expr, 0);
-      op1 = TREE_OPERAND (expr, 1);
-
-      op0 = strip_offset_1 (op0, false, false, &off0);
-      op1 = strip_offset_1 (op1, false, false, &off1);
-
-      *offset = (code == MINUS_EXPR ? off0 - off1 : off0 + off1);
-      if (op0 == TREE_OPERAND (expr, 0)
-         && op1 == TREE_OPERAND (expr, 1))
-       return orig_expr;
-
-      if (integer_zerop (op1))
-       expr = op0;
-      else if (integer_zerop (op0))
-       {
-         if (code == MINUS_EXPR)
-           expr = fold_build1 (NEGATE_EXPR, type, op1);
-         else
-           expr = op1;
-       }
-      else
-       expr = fold_build2 (code, type, op0, op1);
-
-      return fold_convert (orig_type, expr);
-
-    case MULT_EXPR:
-      op1 = TREE_OPERAND (expr, 1);
-      if (!cst_and_fits_in_hwi (op1))
-       return orig_expr;
-
-      op0 = TREE_OPERAND (expr, 0);
-      op0 = strip_offset_1 (op0, false, false, &off0);
-      if (op0 == TREE_OPERAND (expr, 0))
-       return orig_expr;
-
-      *offset = off0 * int_cst_value (op1);
-      if (integer_zerop (op0))
-       expr = op0;
-      else
-       expr = fold_build2 (MULT_EXPR, type, op0, op1);
-
-      return fold_convert (orig_type, expr);
-
-    case ARRAY_REF:
-    case ARRAY_RANGE_REF:
-      if (!inside_addr)
-       return orig_expr;
-
-      step = array_ref_element_size (expr);
-      if (!cst_and_fits_in_hwi (step))
-       break;
-
-      st = int_cst_value (step);
-      op1 = TREE_OPERAND (expr, 1);
-      op1 = strip_offset_1 (op1, false, false, &off1);
-      *offset = off1 * st;
-
-      if (top_compref
-         && integer_zerop (op1))
-       {
-         /* Strip the component reference completely.  */
-         op0 = TREE_OPERAND (expr, 0);
-         op0 = strip_offset_1 (op0, inside_addr, top_compref, &off0);
-         *offset += off0;
-         return op0;
-       }
-      break;
-
-    case COMPONENT_REF:
-      {
-       tree field;
-
-       if (!inside_addr)
-         return orig_expr;
-
-       tmp = component_ref_field_offset (expr);
-       field = TREE_OPERAND (expr, 1);
-       if (top_compref
-           && cst_and_fits_in_hwi (tmp)
-           && cst_and_fits_in_hwi (DECL_FIELD_BIT_OFFSET (field)))
-         {
-           HOST_WIDE_INT boffset, abs_off;
-
-           /* Strip the component reference completely.  */
-           op0 = TREE_OPERAND (expr, 0);
-           op0 = strip_offset_1 (op0, inside_addr, top_compref, &off0);
-           boffset = int_cst_value (DECL_FIELD_BIT_OFFSET (field));
-           abs_off = abs_hwi (boffset) / BITS_PER_UNIT;
-           if (boffset < 0)
-             abs_off = -abs_off;
-
-           *offset = off0 + int_cst_value (tmp) + abs_off;
-           return op0;
-         }
-      }
-      break;
-
-    case ADDR_EXPR:
-      op0 = TREE_OPERAND (expr, 0);
-      op0 = strip_offset_1 (op0, true, true, &off0);
-      *offset += off0;
-
-      if (op0 == TREE_OPERAND (expr, 0))
-       return orig_expr;
-
-      expr = build_fold_addr_expr (op0);
-      return fold_convert (orig_type, expr);
-
-    case MEM_REF:
-      /* ???  Offset operand?  */
-      inside_addr = false;
-      break;
-
-    default:
-      if (ptrdiff_tree_p (expr, offset) && maybe_ne (*offset, 0))
-       return build_int_cst (orig_type, 0);
-      return orig_expr;
-    }
-
-  /* Default handling of expressions for that we want to recurse into
-     the first operand.  */
-  op0 = TREE_OPERAND (expr, 0);
-  op0 = strip_offset_1 (op0, inside_addr, false, &off0);
-  *offset += off0;
-
-  if (op0 == TREE_OPERAND (expr, 0)
-      && (!op1 || op1 == TREE_OPERAND (expr, 1)))
-    return orig_expr;
-
-  expr = copy_node (expr);
-  TREE_OPERAND (expr, 0) = op0;
-  if (op1)
-    TREE_OPERAND (expr, 1) = op1;
-
-  /* Inside address, we might strip the top level component references,
-     thus changing type of the expression.  Handling of ADDR_EXPR
-     will fix that.  */
-  expr = fold_convert (orig_type, expr);
-
-  return expr;
-}
-
 /* Strips constant offsets from EXPR and stores them to OFFSET.  */
 
 tree
 strip_offset (tree expr, poly_uint64_pod *offset)
 {
-  poly_int64 off;
-  tree core = strip_offset_1 (expr, false, false, &off);
-  *offset = off;
-  return core;
+  tree core, toff;
+  split_constant_offset (expr, &core, &toff);
+  gcc_assert (!TYPE_UNSIGNED (TREE_TYPE (toff)));
+  if (tree_fits_poly_int64_p (toff))
+    {
+      *offset = tree_to_poly_int64 (toff);
+      return core;
+    }
+  *offset = 0;
+  return expr;
 }
 
 /* Returns variant of TYPE that can be used as base for different uses.
-- 
2.35.3

Reply via email to