https://gcc.gnu.org/g:9423845243798c80a6a8ec5365b2f8cba9923e2f

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

    [ifcombine] avoid creating out-of-bounds BIT_FIELD_REFs [PR118514]
    
    If decode_field_reference finds a load that accesses past the inner
    object's size, bail out.
    
    If loads we're attempting to combine don't have the same trapping
    status, bail out, to avoid replacing the wrong load and enabling loads
    to be moved that shouldn't.
    
    
    for  gcc/ChangeLog
    
            PR tree-optimization/118514
            * gimple-fold.cc (decode_field_reference): Refuse to consider
            merging out-of-bounds BIT_FIELD_REFs.
            (fold_truth_andor_for_ifcombine): Check that combinable loads
            have the same trapping status.
            * tree-eh.cc (bit_field_ref_in_bounds_p): Rename to...
            (access_in_bounds_of_type_p): ... this.  Change interface,
            export.
            (tree_could_trap_p): Adjust.
            * tree-eh.h (access_in_bounds_of_type_p): Declare.

Diff:
---
 gcc/gimple-fold.cc | 16 ++++++++++------
 gcc/tree-eh.cc     | 25 +++++++++++++------------
 gcc/tree-eh.h      |  1 +
 3 files changed, 24 insertions(+), 18 deletions(-)

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 45485782cdf9..1844129719ec 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -7686,10 +7686,8 @@ 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, PR118514).  */
+      || !access_in_bounds_for_type_p (TREE_TYPE (inner), bs, bp)
       || (INTEGRAL_TYPE_P (TREE_TYPE (inner))
          && !type_has_mode_precision_p (TREE_TYPE (inner))))
     return NULL_TREE;
@@ -8228,8 +8226,12 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
tree truth_type,
       std::swap (rl_loc, rr_loc);
     }
 
+  /* Check that the loads that we're trying to combine have the same vuse and
+     same trapping status.  */
   if ((ll_load && rl_load)
-      ? gimple_vuse (ll_load) != gimple_vuse (rl_load)
+      ? (gimple_vuse (ll_load) != gimple_vuse (rl_load)
+        || (tree_could_trap_p (gimple_assign_rhs1 (ll_load))
+            != tree_could_trap_p (gimple_assign_rhs1 (rl_load))))
       : (!ll_load != !rl_load))
     return 0;
 
@@ -8282,7 +8284,9 @@ fold_truth_andor_for_ifcombine (enum tree_code code, tree 
truth_type,
   else if (lr_reversep != rr_reversep
           || ! operand_equal_p (lr_inner, rr_inner, 0)
           || ((lr_load && rr_load)
-              ? gimple_vuse (lr_load) != gimple_vuse (rr_load)
+              ? (gimple_vuse (lr_load) != gimple_vuse (rr_load)
+                 || (tree_could_trap_p (gimple_assign_rhs1 (lr_load))
+                     != tree_could_trap_p (gimple_assign_rhs1 (rr_load))))
               : (!lr_load != !rr_load)))
     return 0;
 
diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc
index 27a4b2b5b166..68008cea588a 100644
--- a/gcc/tree-eh.cc
+++ b/gcc/tree-eh.cc
@@ -2646,24 +2646,22 @@ 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.  */
+/* Return true iff a BIT_FIELD_REF <(TYPE)???, SIZE, OFFSET> would access a bit
+   range that is known to be in bounds for TYPE.  */
 
-static bool
-bit_field_ref_in_bounds_p (tree expr)
+bool
+access_in_bounds_of_type_p (tree type, poly_uint64 size, poly_uint64 offset)
 {
-  tree size_tree;
-  poly_uint64 size_max, min, wid, max;
+  tree type_size_tree;
+  poly_uint64 type_size_max, min = offset, wid = size, max;
 
-  size_tree = TYPE_SIZE (TREE_TYPE (TREE_OPERAND (expr, 0)));
-  if (!size_tree || !poly_int_tree_p (size_tree, &size_max))
+  type_size_tree = TYPE_SIZE (type);
+  if (!type_size_tree || !poly_int_tree_p (type_size_tree, &type_size_max))
     return false;
 
-  min = bit_field_offset (expr);
-  wid = bit_field_size (expr);
   max = min + wid;
   if (maybe_lt (max, min)
-      || maybe_lt (size_max, max))
+      || maybe_lt (type_size_max, max))
     return false;
 
   return true;
@@ -2712,7 +2710,10 @@ tree_could_trap_p (tree expr)
   switch (code)
     {
     case BIT_FIELD_REF:
-      if (DECL_P (TREE_OPERAND (expr, 0)) && !bit_field_ref_in_bounds_p (expr))
+      if (DECL_P (TREE_OPERAND (expr, 0))
+         && !access_in_bounds_of_type_p (TREE_TYPE (TREE_OPERAND (expr, 0)),
+                                         bit_field_size (expr),
+                                         bit_field_offset (expr)))
        return true;
       /* Fall through.  */
 
diff --git a/gcc/tree-eh.h b/gcc/tree-eh.h
index 69fe193f1b82..1fe6de80c42e 100644
--- a/gcc/tree-eh.h
+++ b/gcc/tree-eh.h
@@ -36,6 +36,7 @@ extern void redirect_eh_dispatch_edge (geh_dispatch *, edge, 
basic_block);
 extern bool operation_could_trap_helper_p (enum tree_code, bool, bool, bool,
                                           bool, tree, bool *);
 extern bool operation_could_trap_p (enum tree_code, bool, bool, tree);
+extern bool access_in_bounds_of_type_p (tree, poly_uint64, poly_uint64);
 extern bool tree_could_trap_p (tree);
 extern tree rewrite_to_non_trapping_overflow (tree);
 extern bool stmt_could_throw_p (function *, gimple *);

Reply via email to