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);

Reply via email to