From 468e1ef4be47810052687c8193d106e591c74bc4 Mon Sep 17 00:00:00 2001
From: Alexandre Oliva <aoliva@gcc.gnu.org>
Date: Thu, 20 Sep 2018 19:34:44 +0000
Subject: [PATCH] [PR87054] fix unaligned access

Building an ADDR_EXPR uses the canonical type to build the pointer
type, but then, as we dereference it, we lose track of lax alignment
known to apply to the dereferenced object.  This might not be a
problem in general, but it is when the compiler implicitly introduces
address taking and dereferencing, as it does for asm statements, and
as it may do in some loop optimizations.

From: Richard Biener <rguenther@suse.de>
for  gcc/ChangeLog

	PR middle-end/87054
	* gimplify.c (gimplify_expr): Retain alignment of
	addressable lvalue in dereference.

From: Alexandre Oliva <oliva@adacore.com>
for  gcc/testsuite/ChangeLog

	PR middle-end/87054
	* gcc.dg/pr87054.c: New.

From-SVN: r264450
---
 gcc/ChangeLog                  |  6 ++++++
 gcc/gimplify.c                 |  8 +++++++-
 gcc/testsuite/ChangeLog        |  5 +++++
 gcc/testsuite/gcc.dg/pr87054.c | 29 +++++++++++++++++++++++++++++
 4 files changed, 47 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr87054.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 641e3591040f..361dfc468a17 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2018-09-20  Richard Biener <rguenther@suse.de>
+
+	PR middle-end/87054
+	* gimplify.c (gimplify_expr): Retain alignment of
+	addressable lvalue in dereference.
+
 2018-09-20  Alexandre Oliva <aoliva@redhat.com>
 
 	PR bootstrap/87013
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index f0eb04a751cc..509fc2f3f5be 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -12538,9 +12538,15 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
       /* An lvalue will do.  Take the address of the expression, store it
 	 in a temporary, and replace the expression with an INDIRECT_REF of
 	 that temporary.  */
+      tree ref_alias_type = reference_alias_ptr_type (*expr_p);
+      unsigned int ref_align = get_object_alignment (*expr_p);
+      tree ref_type = TREE_TYPE (*expr_p);
       tmp = build_fold_addr_expr_loc (input_location, *expr_p);
       gimplify_expr (&tmp, pre_p, post_p, is_gimple_reg, fb_rvalue);
-      *expr_p = build_simple_mem_ref (tmp);
+      if (TYPE_ALIGN (ref_type) != ref_align)
+	ref_type = build_aligned_type (ref_type, ref_align);
+      *expr_p = build2 (MEM_REF, ref_type,
+			tmp, build_zero_cst (ref_alias_type));
     }
   else if ((fallback & fb_rvalue) && is_gimple_reg_rhs_or_call (*expr_p))
     {
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c7c8e90b27c5..a0a08a4d4998 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2018-09-20  Alexandre Oliva <oliva@adacore.com>
+
+	PR middle-end/87054
+	* gcc.dg/pr87054.c: New.
+
 2018-09-20  Richard Sandiford  <richard.sandiford@arm.com>
 
 	PR tree-optimization/87288
diff --git a/gcc/testsuite/gcc.dg/pr87054.c b/gcc/testsuite/gcc.dg/pr87054.c
new file mode 100644
index 000000000000..4ca2b62d2c7c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr87054.c
@@ -0,0 +1,29 @@
+// { dg-do run }
+// { dg-options "-O2" }
+
+#ifndef T
+# ifdef __SSE__
+#  define T __int128
+# else
+#  define T long
+# endif
+#endif
+#ifndef R
+# ifdef __SSE__
+#  define R "x"
+# else
+#  define R "r"
+# endif
+#endif
+
+
+typedef T A; // #define T to long or __int128
+struct B { char d; A c; } __attribute__((packed));
+struct B b[50]; // many elements to avoid loop unrolling
+
+int main () {
+  int i;
+  for (i = 0; i < sizeof(b) / sizeof(*b); i++) {
+    asm ("" : "+" R (b[i].c)); // #define R to "r" on ppc or "x" on x86_64
+  }
+}
-- 
GitLab