]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
middle-end/118695 - missed misalign handling in MEM_REF expansion
authorRichard Biener <rguenther@suse.de>
Thu, 30 Jan 2025 10:22:37 +0000 (11:22 +0100)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 30 Jan 2025 12:05:37 +0000 (13:05 +0100)
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.

gcc/expr.cc
gcc/testsuite/gcc.dg/pr118695.c [new file with mode: 0644]

index 10467f82c0d24757cf59f28199ee3822bc1c569b..f684e26cef78089ead787976ab8a960f00f29711 100644 (file)
@@ -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 (file)
index 0000000..55e3b76
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void * g(int obj)
+{
+  char *t = (char*)&obj;
+  t -= 1;
+  return *(int**)t;
+}