]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
sra: Fix build_user_friendly_ref_for_offset for bit-fields (PR124151)
authorMartin Jambor <mjambor@suse.cz>
Tue, 12 May 2026 12:59:13 +0000 (14:59 +0200)
committerMartin Jambor <jamborm@gcc.gnu.org>
Tue, 12 May 2026 12:59:33 +0000 (14:59 +0200)
When SRA propagates bit-field propagations across assignments, it
first attempts to use build_user_friendly_ref_for_offset to represent
the expression of the new accesses and a possible scalar replacement
so that if there are any warnings generated for it, they are as nice
as we can make them.

However, this can lead to situations where, despite that the new
access has exactly the same type as the new old one, it accesses a
(record or union): field which is just big enough for its precision,
whereas the one we want to match has size rounded up to bytes.  This
causes discrepancy between the recorded size of the new access and the
size get_ref_base_and_extent reports for its expr, which trips the
verifier.

Unlike the previous approach which avoided propagation in the case of
bit fields, this patch fixes build_user_friendly_ref_for_offset by
making it also track the size it is looking at and the size it is
looking for so that it can declare success only if these two also
match.  Additionally, it reverts the simple bail-out fix for PR 117217
because it is no longer necessary.  (I have verified the bug is still
fixed though by applying the new fix on top of the last problematic
commit.)

gcc/ChangeLog:

2026-04-29  Martin Jambor  <mjambor@suse.cz>

PR tree-optimization/124151
* tree-sra.cc (build_user_friendly_ref_for_offset): Added parameters
CUR_SIZE and EXP_SIZE.  Added code passing the correct CUR_SIZE and
checking it against EXP_SIZE.  Removed unused code for the case when
EXP_TYPE was NULL_TREE.
(create_artificial_child_access): Adjusted the call to
build_user_friendly_ref_for_offset.
(propagate_subaccesses_from_rhs): Likewise.
(propagate_subaccesses_from_rhs): Removed a check that the size of
lchild is a multiple of BITS_PER_UNIT.
(propagate_subaccesses_from_lhs): Likewise.

gcc/testsuite/ChangeLog:

2026-04-29  Martin Jambor  <mjambor@suse.cz>

PR tree-optimization/124151
* gcc.dg/tree-ssa/pr124151.c: New test.

gcc/testsuite/gcc.dg/tree-ssa/pr124151.c [new file with mode: 0644]
gcc/tree-sra.cc

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr124151.c b/gcc/testsuite/gcc.dg/tree-ssa/pr124151.c
new file mode 100644 (file)
index 0000000..37d3edc
--- /dev/null
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O1" } */
+
+typedef struct {
+  _Bool : 1;
+} Http2Identifier;
+typedef struct {
+  _Bool is_end;
+  Http2Identifier identifier;
+} Http2DataFrame;
+typedef struct {
+  Http2Identifier identifier;
+  _Bool end_headers;
+} Http2ContinuationFrame;
+typedef struct {
+  union {
+    Http2DataFrame data;
+    Http2ContinuationFrame continuation;
+  };
+} Http2Frame;
+typedef struct {
+  Http2Identifier stream_identifier;
+} Http2RawHeader;
+Http2RawHeader parse_http2_continuation_frame_http2_raw_header;
+Http2Frame gh2f;
+void http2_send_and_receive_preface() {
+  Http2ContinuationFrame continuation_frame = {
+      parse_http2_continuation_frame_http2_raw_header.stream_identifier, 0};
+  Http2Frame frame = {.continuation = continuation_frame};
+  gh2f = frame;
+}
index 293386b6c2989ee43695435d406b1435d7c9e46c..fde4d558f0eb0d6fb47e15766c5a2ed9493f57a0 100644 (file)
@@ -2091,16 +2091,20 @@ build_debug_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
 }
 
 /* Construct a memory reference consisting of component_refs and array_refs to
-   a part of an aggregate *RES (which is of type TYPE).  The requested part
-   should have type EXP_TYPE at be the given OFFSET.  This function might not
-   succeed, it returns true when it does and only then *RES points to something
-   meaningful.  This function should be used only to build expressions that we
-   might need to present to user (e.g. in warnings).  In all other situations,
+   a part of an aggregate *RES which is of type TYPE.  The requested part
+   should have type EXP_TYPE at the given OFFSET.  CUR_SIZE must be the size of
+   *RES unless it is known that *RES alone cannot be the result.  This function
+   might not succeed, it returns true when it does and only then *RES points to
+   something meaningful.
+
+   This function should be used only to build expressions that we might need to
+   present to user (e.g. in warnings).  In all other situations,
    build_ref_for_model or build_ref_for_offset should be used instead.  */
 
 static bool
 build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset,
-                                   tree exp_type)
+                                   HOST_WIDE_INT cur_size, tree exp_type,
+                                   HOST_WIDE_INT exp_size)
 {
   while (1)
     {
@@ -2108,7 +2112,8 @@ build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset,
       tree tr_size, index, minidx;
       HOST_WIDE_INT el_size;
 
-      if (offset == 0 && exp_type
+      if (offset == 0
+         && cur_size == exp_size
          && types_compatible_p (exp_type, type))
        return true;
 
@@ -2146,7 +2151,8 @@ build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset,
                             NULL_TREE);
              expr_ptr = &expr;
              if (build_user_friendly_ref_for_offset (expr_ptr, TREE_TYPE (fld),
-                                                     offset - pos, exp_type))
+                                                     offset - pos, size,
+                                                     exp_type, exp_size))
                {
                  *res = expr;
                  return true;
@@ -2169,17 +2175,12 @@ build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset,
          *res = build4 (ARRAY_REF, TREE_TYPE (type), *res, index,
                         NULL_TREE, NULL_TREE);
          offset = offset % el_size;
+         cur_size = el_size;
          type = TREE_TYPE (type);
          break;
 
        default:
-         if (offset != 0)
-           return false;
-
-         if (exp_type)
-           return false;
-         else
-           return true;
+         return false;
        }
     }
 }
@@ -3070,7 +3071,8 @@ create_artificial_child_access (struct access *parent, struct access *model,
   struct access *access = access_pool.allocate ();
   memset (access, 0, sizeof (struct access));
   if (!build_user_friendly_ref_for_offset (&expr, TREE_TYPE (expr), new_offset,
-                                          model->type))
+                                          parent->size, model->type,
+                                          model->size))
     {
       access->grp_no_warning = true;
       expr = build_ref_for_model (EXPR_LOCATION (parent->base), parent->base,
@@ -3211,8 +3213,11 @@ propagate_subaccesses_from_rhs (struct access *lacc, struct access *racc)
          tree t = lacc->base;
 
          lacc->type = racc->type;
+         /* We know racc and lacc are of different types so can pass -1 as
+            cur_size.  */
          if (build_user_friendly_ref_for_offset (&t, TREE_TYPE (t),
-                                                 lacc->offset, racc->type))
+                                                 lacc->offset, -1,
+                                                 racc->type, racc->size))
            {
              lacc->expr = t;
              lacc->grp_same_access_path = true;
@@ -3270,7 +3275,6 @@ propagate_subaccesses_from_rhs (struct access *lacc, struct access *racc)
        }
 
       if (rchild->grp_unscalarizable_region
-         || (rchild->size % BITS_PER_UNIT) != 0
          || !budget_for_propagation_access (lacc->base))
        {
          if (!lacc->grp_write && access_or_its_child_written (rchild))
@@ -3330,7 +3334,6 @@ propagate_subaccesses_from_lhs (struct access *lacc, struct access *racc)
       HOST_WIDE_INT norm_offset = lchild->offset + norm_delta;
 
       if (lchild->grp_unscalarizable_region
-         || (lchild->size % BITS_PER_UNIT) != 0
          || child_would_conflict_in_acc (racc, norm_offset, lchild->size,
                                          &matching_acc)
          || !budget_for_propagation_access (racc->base))