https://gcc.gnu.org/g:458997f785630c5390f7833e88e53fddf3a3f8b8
commit 458997f785630c5390f7833e88e53fddf3a3f8b8 Author: Alexandre Oliva <ol...@gnu.org> Date: Fri Jan 17 16:47:25 2025 -0300 [ifcombine] out-of-bounds bitfield refs can trap [PR118514] Diff: --- gcc/gimple-fold.cc | 27 +++++++++++++++++++++++---- gcc/testsuite/gcc.dg/field-merge-23.c | 19 +++++++++++++++++++ gcc/tree-eh.cc | 30 +++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index 3c971a29ef04..8e3bb5c74f79 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -7815,6 +7815,20 @@ compute_split_boundary_from_align (HOST_WIDE_INT align, return boundary; } +/* Return true iff REF and the LOADed expression both trap, or neither do. */ + +static inline bool +still_trap_p (gimple *load, const_tree ref) +{ + const_tree before = gimple_assign_rhs1 (load); + const_tree now = ref; + + STRIP_NOPS (before); + STRIP_NOPS (now); + + return (tree_could_trap_p (before) == tree_could_trap_p (now)); +} + /* Make a bit_field_ref. If POINT is NULL, return the BIT_FIELD_REF. Otherwise, build and insert a load stmt before POINT, and return the SSA_NAME. ??? Rewrite LOAD in terms of the bitfield? */ @@ -7836,11 +7850,16 @@ make_bit_field_load (location_t loc, tree inner, tree orig_inner, tree type, /* If we're remaking the same load, reuse the SSA NAME it is already loaded into. */ - if (gimple_assign_load_p (point) - && operand_equal_p (ref, gimple_assign_rhs1 (point))) + if (gimple_assign_load_p (point)) { - gcc_checking_assert (TREE_CODE (gimple_assign_lhs (point)) == SSA_NAME); - return gimple_assign_lhs (point); + if (operand_equal_p (ref, gimple_assign_rhs1 (point))) + { + gcc_checking_assert (TREE_CODE (gimple_assign_lhs (point)) + == SSA_NAME); + return gimple_assign_lhs (point); + } + else + gcc_checking_assert (still_trap_p (point, ref)); } gimple_seq stmts = NULL; diff --git a/gcc/testsuite/gcc.dg/field-merge-23.c b/gcc/testsuite/gcc.dg/field-merge-23.c new file mode 100644 index 000000000000..d60f76206ebe --- /dev/null +++ b/gcc/testsuite/gcc.dg/field-merge-23.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-options "-O" } */ + +/* PR tree-optimization/118514 */ + +/* Check that we don't pull optimized references that could trap out of + loops. */ + +int a, c = 1; +unsigned char b[1], d; +int main() { + while (a || !c) { + signed char e = b[1000000000]; + d = e < 0 || b[1000000000] > 1; + if (d) + __builtin_abort (); + } + return 0; +} diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc index 1033b124e4df..a92eccb4bb6d 100644 --- a/gcc/tree-eh.cc +++ b/gcc/tree-eh.cc @@ -2646,6 +2646,30 @@ range_in_array_bounds_p (tree ref) return true; } +/* Return true iff EXPR, a BIT_FIELD_REF, accesses a bit range that is known to + be in bounds for the referred operand type. */ + +static bool +bit_field_ref_in_bounds_p (tree expr) +{ + tree size_tree; + poly_uint64 size_max, min, wid, max; + + size_tree = TYPE_SIZE (TREE_TYPE (TREE_OPERAND (expr, 0))); + if (!size_tree + || !poly_int_tree_p (size_tree, &size_max) + || !poly_int_tree_p (TREE_OPERAND (expr, 2), &min) + || !poly_int_tree_p (TREE_OPERAND (expr, 1), &wid)) + return false; + + max = min + wid; + if (maybe_lt (max, min) + || maybe_lt (size_max, max)) + return false; + + return true; +} + /* Return true if EXPR can trap, as in dereferencing an invalid pointer location or floating point arithmetic. C.f. the rtl version, may_trap_p. This routine expects only GIMPLE lhs or rhs input. */ @@ -2688,10 +2712,14 @@ tree_could_trap_p (tree expr) restart: switch (code) { + case BIT_FIELD_REF: + if (!bit_field_ref_in_bounds_p (expr)) + return true; + /* Fall through. */ + case COMPONENT_REF: case REALPART_EXPR: case IMAGPART_EXPR: - case BIT_FIELD_REF: case VIEW_CONVERT_EXPR: case WITH_SIZE_EXPR: expr = TREE_OPERAND (expr, 0);