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 <siddh...@gotplt.org> --- 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