Propogate constant additions and subtractions to an offset when computing an estimate for a PHI of constants.
gcc/ChangeLog: PR tree-optimization/PR116556 * tree-object-size.cc (try_collapsing_offset): New parameters CST and CODE. Use them to propagate PLUS_EXPR and MINUS_EXPR through recursively calling TRY_COLLAPSE_OFFSET. (plus_stmt_object_size): Adjust call to TRY_COLLAPSE_OFFSET. * testsuite/gcc.dg/builtin-object-size-1.c (test13): Test constant addition and subtraction. * testsuite/gcc.dg/builtin-object-size-3.c (test13): Likewise. Signed-off-by: Siddhesh Poyarekar <siddh...@gotplt.org> --- gcc/testsuite/gcc.dg/builtin-object-size-1.c | 20 +++++++ gcc/testsuite/gcc.dg/builtin-object-size-3.c | 20 +++++++ gcc/tree-object-size.cc | 58 ++++++++++++++++---- 3 files changed, 86 insertions(+), 12 deletions(-) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index 1f5cd5d99a1..6ffe12be683 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c @@ -769,6 +769,26 @@ test13 (unsigned cond) if (__builtin_object_size (&p[t], 0) != 9) FAIL (); #endif + + t += 4; + +#ifdef __builtin_object_size + if (__builtin_object_size (&p[t], 0) != (cond ? 1 : 5)) + FAIL (); +#else + if (__builtin_object_size (&p[t], 0) != 5) + FAIL (); +#endif + + t -= 5; + +#ifdef __builtin_object_size + if (__builtin_object_size (&p[t], 0) != (cond ? 6 : 10)) + FAIL (); +#else + if (__builtin_object_size (&p[t], 0) != 10) + FAIL (); +#endif } int diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index 7fad106fc27..c51cb69c01b 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c @@ -777,6 +777,26 @@ test13 (unsigned cond) if (__builtin_object_size (&p[t], 2) != 5) FAIL (); #endif + + t += 4; + +#ifdef __builtin_object_size + if (__builtin_object_size (&p[t], 2) != (cond ? 1 : 5)) + FAIL (); +#else + if (__builtin_object_size (&p[t], 2) != 1) + FAIL (); +#endif + + t -= 5; + +#ifdef __builtin_object_size + if (__builtin_object_size (&p[t], 2) != (cond ? 6 : 10)) + FAIL (); +#else + if (__builtin_object_size (&p[t], 2) != 6) + FAIL (); +#endif } int diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc index 2dfc28407ab..1b569c3d12b 100644 --- a/gcc/tree-object-size.cc +++ b/gcc/tree-object-size.cc @@ -1473,7 +1473,7 @@ merge_object_sizes (struct object_size_info *osi, tree dest, tree orig) with all of its targets are constants. */ static tree -try_collapsing_offset (tree op, int object_size_type) +try_collapsing_offset (tree op, tree cst, tree_code code, int object_size_type) { gcc_assert (!(object_size_type & OST_DYNAMIC)); @@ -1485,13 +1485,41 @@ try_collapsing_offset (tree op, int object_size_type) switch (gimple_code (stmt)) { case GIMPLE_ASSIGN: - /* Peek through casts. */ - if (gimple_assign_rhs_code (stmt) == NOP_EXPR) + switch (gimple_assign_rhs_code (stmt)) { - tree ret = try_collapsing_offset (gimple_assign_rhs1 (stmt), - object_size_type); - if (TREE_CODE (ret) == INTEGER_CST) - return ret; + /* Peek through casts. */ + case NOP_EXPR: + { + tree ret = try_collapsing_offset (gimple_assign_rhs1 (stmt), + NULL_TREE, NOP_EXPR, + object_size_type); + if (TREE_CODE (ret) == INTEGER_CST) + return ret; + break; + } + /* Propagate constant offsets to PHI expressions. */ + case PLUS_EXPR: + case MINUS_EXPR: + { + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs2 = gimple_assign_rhs2 (stmt); + tree ret = NULL_TREE; + + if (TREE_CODE (rhs1) == INTEGER_CST) + ret = try_collapsing_offset (rhs2, rhs1, + gimple_assign_rhs_code (stmt), + object_size_type); + else if (TREE_CODE (rhs2) == INTEGER_CST) + ret = try_collapsing_offset (rhs1, rhs2, + gimple_assign_rhs_code (stmt), + object_size_type); + + if (ret && TREE_CODE (ret) == INTEGER_CST) + return ret; + break; + } + default: + break; } break; case GIMPLE_PHI: @@ -1507,14 +1535,20 @@ try_collapsing_offset (tree op, int object_size_type) if (TREE_CODE (rhs) != INTEGER_CST) return op; + if (cst) + rhs = fold_build2 (code, sizetype, + fold_convert (ptrdiff_type_node, rhs), + fold_convert (ptrdiff_type_node, cst)); + else + rhs = fold_convert (ptrdiff_type_node, rhs); + /* 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); + enum tree_code selection_code = (object_size_type & OST_MINIMUM + ? MAX_EXPR : MIN_EXPR); - off = fold_build2 (code, ptrdiff_type_node, off, - fold_convert (ptrdiff_type_node, rhs)); + off = fold_build2 (selection_code, ptrdiff_type_node, off, rhs); } return fold_convert (sizetype, off); } @@ -1558,7 +1592,7 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) return false; if (!(object_size_type & OST_DYNAMIC) && TREE_CODE (op1) != INTEGER_CST) - op1 = try_collapsing_offset (op1, object_size_type); + op1 = try_collapsing_offset (op1, NULL_TREE, NOP_EXPR, object_size_type); /* Handle PTR + OFFSET here. */ if (size_valid_p (op1, object_size_type) -- 2.45.1