https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94482

--- Comment #21 from Martin Jambor <jamborm at gcc dot gnu.org> ---
As Richi already found out, the path in sra_modify_expr handling type
incompatible replacement does not work when the replaced expr comes
from within a BIT_FIELD_REF - it does only half of what is necessary.

A conservative (not yet much tested) fix would be to emit a full RMW:

*** /tmp/UTN9NX_tree-sra.c      Mon Apr  6 15:28:23 2020
--- gcc/tree-sra.c      Mon Apr  6 15:22:40 2020
*************** sra_modify_expr (tree *expr, gimple_stmt
*** 3742,3768 ****

          ref = build_ref_for_model (loc, orig_expr, 0, access, gsi, false);

!         if (write)
            {
              gassign *stmt;

              if (access->grp_partial_lhs)
!               ref = force_gimple_operand_gsi (gsi, ref, true, NULL_TREE,
!                                                false, GSI_NEW_STMT);
!             stmt = gimple_build_assign (repl, ref);
              gimple_set_location (stmt, loc);
!             gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
            }
!         else
            {
              gassign *stmt;

              if (access->grp_partial_lhs)
!               repl = force_gimple_operand_gsi (gsi, repl, true, NULL_TREE,
!                                                true, GSI_SAME_STMT);
!             stmt = gimple_build_assign (ref, repl);
              gimple_set_location (stmt, loc);
!             gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
            }
        }
        else
--- 3742,3771 ----

          ref = build_ref_for_model (loc, orig_expr, 0, access, gsi, false);

!         if (!write || bfr)
            {
              gassign *stmt;
+             tree src = repl;

              if (access->grp_partial_lhs)
!               src = force_gimple_operand_gsi (gsi, repl, true, NULL_TREE,
!                                                true, GSI_SAME_STMT);
!             stmt = gimple_build_assign (ref, src);
              gimple_set_location (stmt, loc);
!             gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
            }
!         if (bfr)
!           ref = unshare_expr (ref);
!         if (write || bfr)
            {
              gassign *stmt;

              if (access->grp_partial_lhs)
!               ref = force_gimple_operand_gsi (gsi, ref, true, NULL_TREE,
!                                                false, GSI_NEW_STMT);
!             stmt = gimple_build_assign (repl, ref);
              gimple_set_location (stmt, loc);
!             gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
            }
        }
        else

But I wonder whether we care about type incompatibility within a B_F_R
at all - isn't B_F_R also an implicit V_C_E, always looking at the
binary image?  So perhaps something as simple as the following might
work?

diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index b2056b58750..d22b03814d2 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -3736,7 +3736,7 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi,
bool write)
          be accessed as a different type too, potentially creating a need for
          type conversion (see PR42196) and when scalarized unions are involved
          in assembler statements (see PR42398).  */
-      if (!useless_type_conversion_p (type, access->type))
+      if (!bfr && !useless_type_conversion_p (type, access->type))
        {
          tree ref;

I'll test both options ...and it seems we need the RMW one to handle
REALPART_EXPR and IMAGPART_EXPR.

Reply via email to