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): New
function.
(main): Call it.
Signed-off-by: Siddhesh Poyarekar <[email protected]>
---
Tests underway for x86_64 and i686. OK if they pass?
gcc/testsuite/gcc.dg/builtin-object-size-1.c | 25 ++++++++++++
gcc/tree-object-size.cc | 41 ++++++++++++++++++++
2 files changed, 66 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..eed1653505c 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c
@@ -712,6 +712,30 @@ 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
+}
+
int
main (void)
{
@@ -729,6 +753,7 @@ main (void)
test10 ();
#ifndef SKIP_STRNDUP
test11 ();
+ test12 (1);
#endif
DONE ();
}
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 4c1fa9b555f..d90cc43fa97 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -1467,6 +1467,44 @@ 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);
+
+ if (gimple_code (stmt) != GIMPLE_PHI)
+ return op;
+
+ tree off = size_unknown (object_size_type);
+
+ for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++)
+ {
+ tree rhs = gimple_phi_arg (stmt, i)->def;
+
+ 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 = size_binop (code, off, rhs);
+ }
+
+ gcc_assert (TREE_CODE (off) == INTEGER_CST);
+ return off;
+}
/* Compute object_sizes for VAR, defined to the result of an assignment
with operator POINTER_PLUS_EXPR. Return true if the object size might
@@ -1499,6 +1537,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