https://gcc.gnu.org/g:9ba2de71815c0ea6cc940ecb50af7cc1a84579f7

commit r15-7287-g9ba2de71815c0ea6cc940ecb50af7cc1a84579f7
Author: Richard Biener <rguent...@suse.de>
Date:   Thu Jan 30 11:22:37 2025 +0100

    middle-end/118695 - missed misalign handling in MEM_REF expansion
    
    When MEM_REF expansion of a non-MEM falls back to a stack temporary
    we fail to handle the case where the offset adjusted reference to
    the temporary is not aligned according to the requirement of the
    mode.  We have to go through bitfield extraction or movmisalign
    in this case.  Fortunately there's a helper for this.
    
    This fixes an ICE observed on arm which has sanity checks in its
    move patterns for this.
    
            PR middle-end/118695
            * expr.cc (expand_expr_real_1): When expanding a MEM_REF
            to a non-MEM by committing it to a stack temporary make
            sure to handle misaligned accesses correctly.
    
            * gcc.dg/pr118695.c: New testcase.

Diff:
---
 gcc/expr.cc                     | 12 ++++++++++++
 gcc/testsuite/gcc.dg/pr118695.c |  9 +++++++++
 2 files changed, 21 insertions(+)

diff --git a/gcc/expr.cc b/gcc/expr.cc
index 10467f82c0d2..f684e26cef78 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -11796,6 +11796,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode 
tmode,
                && known_eq (GET_MODE_BITSIZE (DECL_MODE (base)), type_size))
              return expand_expr (build1 (VIEW_CONVERT_EXPR, type, base),
                                  target, tmode, modifier);
+           unsigned align;
            if (TYPE_MODE (type) == BLKmode || maybe_lt (offset, 0))
              {
                temp = assign_stack_temp (DECL_MODE (base),
@@ -11804,6 +11805,17 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode 
tmode,
                temp = adjust_address (temp, TYPE_MODE (type), offset);
                if (TYPE_MODE (type) == BLKmode)
                  set_mem_size (temp, int_size_in_bytes (type));
+               /* When the original ref was misaligned so will be the
+                  access to the stack temporary.  Not all targets handle
+                  this correctly, some will ICE in sanity checking.
+                  Handle this by doing bitfield extraction when necessary.  */
+               else if ((align = get_object_alignment (exp))
+                        < GET_MODE_ALIGNMENT (TYPE_MODE (type)))
+                 temp
+                   = expand_misaligned_mem_ref (temp, TYPE_MODE (type),
+                                                unsignedp, align,
+                                                modifier == EXPAND_STACK_PARM
+                                                ? NULL_RTX : target, NULL);
                return temp;
              }
            /* When the access is fully outside of the underlying object
diff --git a/gcc/testsuite/gcc.dg/pr118695.c b/gcc/testsuite/gcc.dg/pr118695.c
new file mode 100644
index 000000000000..55e3b767a21c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr118695.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void * g(int obj)
+{
+  char *t = (char*)&obj;
+  t -= 1;
+  return *(int**)t;
+}

Reply via email to