In PTR + OFFSET cases, try harder to see if the target offset could
result in a constant.  Specifically, if the offset is a PHI node with
all constant branches, return the minimum (or maximum for OST_MINIMUM)
of the possible values.

gcc/ChangeLog:

        PR tree-optimization/116556
        * tree-object-size.cc (try_collapsing_offset): New function.
        (plus_stmt_object_size): Use it.
        * gcc/testsuite/gcc.dg/builtin-object-size-1.c (test12, test13):
        New functions.
        (main): Call them.
        * gcc/testsuite/gcc.dg/builtin-object-size-3.c (test12, test13):
        New functions.
        (main): Call them.

Signed-off-by: Siddhesh Poyarekar <siddh...@gotplt.org>
---
 gcc/testsuite/gcc.dg/builtin-object-size-1.c | 63 ++++++++++++++++++++
 gcc/testsuite/gcc.dg/builtin-object-size-3.c | 63 ++++++++++++++++++++
 gcc/tree-object-size.cc                      | 60 +++++++++++++++++++
 3 files changed, 186 insertions(+)

diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-object-size-1.c
index d6d13c5ef7a..1f5cd5d99a1 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c
@@ -712,6 +712,65 @@ test11 (void)
 }
 #endif
 
+void
+__attribute__ ((noinline))
+test12 (unsigned cond)
+{
+  char *buf2 = malloc (10);
+  char *p;
+  size_t t;
+
+  if (cond)
+    t = 8;
+  else
+    t = 4;
+
+  p = &buf2[t];
+
+#ifdef __builtin_object_size
+  if (__builtin_object_size (p, 0) != (cond ? 2 : 6))
+    FAIL ();
+#else
+  if (__builtin_object_size (p, 0) != 6)
+    FAIL ();
+#endif
+}
+
+void
+__attribute__ ((noinline))
+test13 (unsigned cond)
+{
+  char *buf2 = malloc (10);
+  char *p = &buf2[4];
+  int t;
+
+  if (cond)
+    t = -1;
+  else
+    t = -2;
+
+#ifdef __builtin_object_size
+  if (__builtin_object_size (&p[t], 0) != (cond ? 7 : 8))
+    FAIL ();
+#else
+  if (__builtin_object_size (&p[t], 0) != 8)
+    FAIL ();
+#endif
+
+  if (cond)
+    t = 1;
+  else
+    t = -3;
+
+#ifdef __builtin_object_size
+  if (__builtin_object_size (&p[t], 0) != (cond ? 5 : 9))
+    FAIL ();
+#else
+  if (__builtin_object_size (&p[t], 0) != 9)
+    FAIL ();
+#endif
+}
+
 int
 main (void)
 {
@@ -729,6 +788,10 @@ main (void)
   test10 ();
 #ifndef SKIP_STRNDUP
   test11 ();
+  test12 (1);
+  test12 (0);
+  test13 (1);
+  test13 (0);
 #endif
   DONE ();
 }
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c 
b/gcc/testsuite/gcc.dg/builtin-object-size-3.c
index ec2c62c9640..7fad106fc27 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c
@@ -720,6 +720,65 @@ test11 (void)
 }
 #endif
 
+void
+__attribute__ ((noinline))
+test12 (unsigned cond)
+{
+  char *buf2 = malloc (10);
+  char *p;
+  size_t t;
+
+  if (cond)
+    t = 8;
+  else
+    t = 4;
+
+  p = &buf2[t];
+
+#ifdef __builtin_object_size
+  if (__builtin_object_size (p, 2) != (cond ? 2 : 6))
+    FAIL ();
+#else
+  if (__builtin_object_size (p, 2) != 2)
+    FAIL ();
+#endif
+}
+
+void
+__attribute__ ((noinline))
+test13 (unsigned cond)
+{
+  char *buf2 = malloc (10);
+  char *p = &buf2[4];
+  size_t t;
+
+  if (cond)
+    t = -1;
+  else
+    t = -2;
+
+#ifdef __builtin_object_size
+  if (__builtin_object_size (&p[t], 2) != (cond ? 7 : 8))
+    FAIL ();
+#else
+  if (__builtin_object_size (&p[t], 2) != 7)
+    FAIL ();
+#endif
+
+  if (cond)
+    t = 1;
+  else
+    t = -3;
+
+#ifdef __builtin_object_size
+  if (__builtin_object_size (&p[t], 2) != (cond ? 5 : 9))
+    FAIL ();
+#else
+  if (__builtin_object_size (&p[t], 2) != 5)
+    FAIL ();
+#endif
+}
+
 int
 main (void)
 {
@@ -738,5 +797,9 @@ main (void)
 #ifndef SKIP_STRNDUP
   test11 ();
 #endif
+  test12 (1);
+  test12 (0);
+  test13 (1);
+  test13 (0);
   DONE ();
 }
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index f8fae0cbc82..2dfc28407ab 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -1468,6 +1468,63 @@ merge_object_sizes (struct object_size_info *osi, tree 
dest, tree orig)
   return bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (orig));
 }
 
+/* For constant sizes, try collapsing a non-constant offset to a constant if
+   possible.  The case handled at the moment is when the offset is a PHI node
+   with all of its targets are constants.  */
+
+static tree
+try_collapsing_offset (tree op, int object_size_type)
+{
+  gcc_assert (!(object_size_type & OST_DYNAMIC));
+
+  if (TREE_CODE (op) != SSA_NAME)
+    return op;
+
+  gimple *stmt = SSA_NAME_DEF_STMT (op);
+
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_ASSIGN:
+      /* Peek through casts.  */
+      if (gimple_assign_rhs_code (stmt) == NOP_EXPR)
+       {
+         tree ret = try_collapsing_offset (gimple_assign_rhs1 (stmt),
+                                           object_size_type);
+         if (TREE_CODE (ret) == INTEGER_CST)
+           return ret;
+       }
+      break;
+    case GIMPLE_PHI:
+       {
+         tree off = ((object_size_type & OST_MINIMUM)
+                     ? TYPE_MIN_VALUE (ptrdiff_type_node)
+                     : TYPE_MAX_VALUE (ptrdiff_type_node));
+
+         for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++)
+           {
+             tree rhs = gimple_phi_arg_def (stmt, i);
+
+             if (TREE_CODE (rhs) != INTEGER_CST)
+               return op;
+
+             /* Note that this is the *opposite* of what we usually do with
+                sizes, because the maximum offset estimate here will give us a
+                minimum size estimate and vice versa.  */
+             enum tree_code code = (object_size_type & OST_MINIMUM
+                                    ? MAX_EXPR : MIN_EXPR);
+
+             off = fold_build2 (code, ptrdiff_type_node, off,
+                                fold_convert (ptrdiff_type_node, rhs));
+           }
+         return fold_convert (sizetype, off);
+       }
+    default:
+      break;
+    }
+
+  /* Nothing worked, so return OP untouched.  */
+  return op;
+}
 
 /* Compute object_sizes for VAR, defined to the result of an assignment
    with operator POINTER_PLUS_EXPR.  Return true if the object size might
@@ -1500,6 +1557,9 @@ plus_stmt_object_size (struct object_size_info *osi, tree 
var, gimple *stmt)
   if (object_sizes_unknown_p (object_size_type, varno))
     return false;
 
+  if (!(object_size_type & OST_DYNAMIC) && TREE_CODE (op1) != INTEGER_CST)
+    op1 = try_collapsing_offset (op1, object_size_type);
+
   /* Handle PTR + OFFSET here.  */
   if (size_valid_p (op1, object_size_type)
       && (TREE_CODE (op0) == SSA_NAME || TREE_CODE (op0) == ADDR_EXPR))
-- 
2.45.1

Reply via email to