https://gcc.gnu.org/g:e58a7d75e81b3f4b3286a49455452c3a2cc02721

commit e58a7d75e81b3f4b3286a49455452c3a2cc02721
Author: Alexandre Oliva <ol...@adacore.com>
Date:   Tue Dec 10 06:49:32 2024 -0300

    ifcombine field-merge: saturate align at inner object size
    
    A bootstrap on aarch64-linux-gnu revealed that sometimes (for example,
    when building shorten_branches in final.cc) we will find such things
    as MEM <unsigned int>, where unsigned int happen to be a variant of
    the original unsigned int type, given 64-bit alignment.  This unusual
    alignment circumstance caused get_best_mode to choose DImode instead
    of SImode, and that failed gimple verification because there aren't
    that many bits in the unsigned int object.
    
    Arrange for alignment to saturate at the inner object size to avoid
    tripping this error.
    
    
    for  gcc/ChangeLog
    
            * gimple-fold.cc (fold_truth_andor_for_ifcombine): Saturate
            align at inner object size.

Diff:
---
 gcc/gimple-fold.cc | 39 +++++++++++++++++++++++++++------------
 1 file changed, 27 insertions(+), 12 deletions(-)

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index a31fc283d51b..967356a95019 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -8204,24 +8204,31 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
tree truth_type,
      to be relative to a field of that size.  */
   first_bit = MIN (ll_bitpos, rl_bitpos);
   end_bit = MAX (ll_bitpos + ll_bitsize, rl_bitpos + rl_bitsize);
+  HOST_WIDE_INT ll_align = TYPE_ALIGN (TREE_TYPE (ll_inner));
+  /* Guard from types with wider-than-size alignment.  We must not widen the
+     load beyond its total size.  This is rare.  */
+  while (ll_align > BITS_PER_UNIT
+        && TYPE_SIZE (TREE_TYPE (ll_inner))
+        && uniform_integer_cst_p (TYPE_SIZE (TREE_TYPE (ll_inner)))
+        && known_gt ((unsigned HOST_WIDE_INT)ll_align,
+                     tree_to_poly_uint64 (TYPE_SIZE (TREE_TYPE (ll_inner)))))
+    ll_align /= 2;
   if (get_best_mode (end_bit - first_bit, first_bit, 0, 0,
-                    TYPE_ALIGN (TREE_TYPE (ll_inner)), BITS_PER_WORD,
-                    volatilep, &lnmode))
+                    ll_align, BITS_PER_WORD, volatilep, &lnmode))
     l_split_load = false;
   else
     {
       /* Consider the possibility of recombining loads if any of the
         fields straddles across an alignment boundary, so that either
         part can be loaded along with the other field.  */
-      HOST_WIDE_INT align = TYPE_ALIGN (TREE_TYPE (ll_inner));
       HOST_WIDE_INT boundary = compute_split_boundary_from_align
-       (align, ll_bitpos, ll_bitsize, rl_bitpos, rl_bitsize);
+       (ll_align, ll_bitpos, ll_bitsize, rl_bitpos, rl_bitsize);
 
       if (boundary < 0
          || !get_best_mode (boundary - first_bit, first_bit, 0, 0,
-                            align, BITS_PER_WORD, volatilep, &lnmode)
+                            ll_align, BITS_PER_WORD, volatilep, &lnmode)
          || !get_best_mode (end_bit - boundary, boundary, 0, 0,
-                            align, BITS_PER_WORD, volatilep, &lnmode2))
+                            ll_align, BITS_PER_WORD, volatilep, &lnmode2))
        return 0;
 
       /* If we can't have a single load, but can with two, figure out whether
@@ -8368,16 +8375,24 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
tree truth_type,
         and then we use two separate compares.  */
       first_bit = MIN (lr_bitpos, rr_bitpos);
       end_bit = MAX (lr_bitpos + lr_bitsize, rr_bitpos + rr_bitsize);
+      HOST_WIDE_INT lr_align = TYPE_ALIGN (TREE_TYPE (lr_inner));
+      /* Guard from types with wider-than-size alignment.  We must not widen 
the
+        load beyond its total size.  This is rare.  */
+      while (lr_align > BITS_PER_UNIT
+            && TYPE_SIZE (TREE_TYPE (lr_inner))
+            && uniform_integer_cst_p (TYPE_SIZE (TREE_TYPE (lr_inner)))
+            && known_gt ((unsigned HOST_WIDE_INT)lr_align,
+                         tree_to_poly_uint64 (TYPE_SIZE
+                                              (TREE_TYPE (lr_inner)))))
+       lr_align /= 2;
       if (!get_best_mode (end_bit - first_bit, first_bit, 0, 0,
-                         TYPE_ALIGN (TREE_TYPE (lr_inner)), BITS_PER_WORD,
-                         volatilep, &rnmode))
+                         lr_align, BITS_PER_WORD, volatilep, &rnmode))
        {
          /* Consider the possibility of recombining loads if any of the
             fields straddles across an alignment boundary, so that either
             part can be loaded along with the other field.  */
-         HOST_WIDE_INT align = TYPE_ALIGN (TREE_TYPE (lr_inner));
          HOST_WIDE_INT boundary = compute_split_boundary_from_align
-           (align, lr_bitpos, lr_bitsize, rr_bitpos, rr_bitsize);
+           (lr_align, lr_bitpos, lr_bitsize, rr_bitpos, rr_bitsize);
 
          if (boundary < 0
              /* If we're to split both, make sure the split point is
@@ -8386,9 +8401,9 @@ fold_truth_andor_for_ifcombine (enum tree_code code, tree 
truth_type,
                  && (boundary - lr_bitpos
                      != (lnbitpos + GET_MODE_BITSIZE (lnmode)) - ll_bitpos))
              || !get_best_mode (boundary - first_bit, first_bit, 0, 0,
-                                align, BITS_PER_WORD, volatilep, &rnmode)
+                                lr_align, BITS_PER_WORD, volatilep, &rnmode)
              || !get_best_mode (end_bit - boundary, boundary, 0, 0,
-                                align, BITS_PER_WORD, volatilep, &rnmode2))
+                                lr_align, BITS_PER_WORD, volatilep, &rnmode2))
            return 0;
 
          r_split_load = true;

Reply via email to