https://gcc.gnu.org/g:49b5606e0e8d0b133227071c9d39582e8734aead

commit 49b5606e0e8d0b133227071c9d39582e8734aead
Author: Alexandre Oliva <ol...@adacore.com>
Date:   Sat Jan 18 00:40:51 2025 -0300

    [ifcombine] avoid dropping tree_could_trap_p [PR118514]
    
    Unlike other access patterns, BIT_FIELD_REFs aren't regarded as
    possibly-trapping out of referencing out-of-bounds bits.
    
    So, if decode_field_reference finds a load that could trap, but whose
    inner object doesn't, bail out if the accesses past the inner object's
    size.
    
    This may drop some optimizations in VLAs, that could be safe if we
    managed to reuse the same pre-existing load for both compares, but
    those get optimized later (as in the new testcase).  The cases of most
    interest are those that merge separate fields, and they necessarily
    involve new BIT_FIELD_REFs loads.
    
    
    for  gcc/ChangeLog
    
            PR tree-optimization/118514
            * gimple-fold.cc (decode_field_reference): Refuse to consider
            BIT_FIELD_REF of non-trapping object if the original load
            could trap for being out-of-bounds.
            (make_bit_field_ref): Check that replacement loads could trap
            as much as the original loads.
    
    for  gcc/testsuite/ChangeLog
    
            PR tree-optimization/118514
            * gcc.dg/field-merge-23.c: New.

Diff:
---
 gcc/gimple-fold.cc                    | 19 +++++++++++++++----
 gcc/testsuite/gcc.dg/field-merge-23.c | 19 +++++++++++++++++++
 2 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 3c971a29ef04..41b21ecd58a3 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -7686,10 +7686,16 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT 
*pbitsize,
       || bs <= shiftrt
       || offset != 0
       || TREE_CODE (inner) == PLACEHOLDER_EXPR
-      /* Reject out-of-bound accesses (PR79731).  */
-      || (! AGGREGATE_TYPE_P (TREE_TYPE (inner))
-         && compare_tree_int (TYPE_SIZE (TREE_TYPE (inner)),
-                              bp + bs) < 0)
+      /* Reject out-of-bound accesses (PR79731).  BIT_FIELD_REFs aren't flagged
+        as tree_could_trap_p just because of out-of-range bits, so don't even
+        try to optimize loads that could trap if they access out-of-range bits
+        of an object that could not trap (PR118514).  */
+      || ((! AGGREGATE_TYPE_P (TREE_TYPE (inner))
+          || (load && tree_could_trap_p (gimple_assign_rhs1 (load))
+              & !tree_could_trap_p (inner)))
+         && (!tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (inner)))
+             || compare_tree_int (TYPE_SIZE (TREE_TYPE (inner)),
+                                  bp + bs) < 0))
       || (INTEGRAL_TYPE_P (TREE_TYPE (inner))
          && !type_has_mode_precision_p (TREE_TYPE (inner))))
     return NULL_TREE;
@@ -7859,6 +7865,11 @@ make_bit_field_load (location_t loc, tree inner, tree 
orig_inner, tree type,
       gimple *new_stmt = gsi_stmt (i);
       if (gimple_has_mem_ops (new_stmt))
        gimple_set_vuse (new_stmt, reaching_vuse);
+      gcc_checking_assert (! (gimple_assign_load_p (point)
+                             && gimple_assign_load_p (new_stmt))
+                          || (tree_could_trap_p (gimple_assign_rhs1 (point))
+                              == tree_could_trap_p (gimple_assign_rhs1
+                                                    (new_stmt))));
     }
 
   gimple_stmt_iterator gsi = gsi_for_stmt (point);
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..96604d43c9de
--- /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 create BIT_FIELD_REFs that could trap, because they are
+   assumed not to trap and could be pulled 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;
+}

Reply via email to