diff mbox series

[PR87054] fix unaligned access

Message ID orbm8vzctl.fsf@lxoliva.fsfla.org
State New
Headers show
Series [PR87054] fix unaligned access | expand

Commit Message

Alexandre Oliva Sept. 18, 2018, 3:47 a.m. UTC
Richard, this is the patch you proposed in the PR a while ago, along
with the testcase I'd posted.  Please let me know if the commit-message
paragraph below sounds good to you, and then I'll proceed to install it,
or amend as requested.  (do we really want the MEM_REF to carry stricter
alignment than the base type?  I'd have retained the object's alignment
only for looser-than-type alignment)

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.

Regstrapped on x86_64-linux-gnu.

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.
---
 gcc/gimplify.c                 |    8 +++++++-
 gcc/testsuite/gcc.dg/pr87054.c |   29 +++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr87054.c

Comments

Richard Biener Sept. 18, 2018, 5:41 a.m. UTC | #1
On September 18, 2018 5:47:34 AM GMT+02:00, Alexandre Oliva <oliva@adacore.com> wrote:
>Richard, this is the patch you proposed in the PR a while ago, along
>with the testcase I'd posted.  Please let me know if the commit-message
>paragraph below sounds good to you, and then I'll proceed to install
>it,
>or amend as requested.  (do we really want the MEM_REF to carry
>stricter
>alignment than the base type?  I'd have retained the object's alignment
>only for looser-than-type alignment)

I think so. We want to retain the alignment we'd extracted from the original ref. As you said the indirection is spuirously introduced by the compiler. 

>
>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.
>
>Regstrapped on x86_64-linux-gnu.

OK. 

Richard. 

>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.
>---
> gcc/gimplify.c                 |    8 +++++++-
> gcc/testsuite/gcc.dg/pr87054.c |   29 +++++++++++++++++++++++++++++
> 2 files changed, 36 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/gcc.dg/pr87054.c
>
>diff --git a/gcc/gimplify.c b/gcc/gimplify.c
>index f0eb04a751ccc..509fc2f3f5be2 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/gcc.dg/pr87054.c
>b/gcc/testsuite/gcc.dg/pr87054.c
>new file mode 100644
>index 0000000000000..4ca2b62d2c7c9
>--- /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
>+  }
>+}
Alexandre Oliva Sept. 24, 2018, 9:26 a.m. UTC | #2
On Sep 18, 2018, Richard Biener <rguenther@suse.de> wrote:

>> +# ifdef __SSE__
>> +#  define T __int128

Rainer reported this didn't work on 32-bit x86 with SSE enabled.
Here's a patch that fixes it.  Ok to install?  Tested on x86_64,
including such combinations as -m32, -m32/-msse, and -m32/-mno-sse.


[PR87054] adjust testcase for 32-bit x86

From: Alexandre Oliva <oliva@adacore.com>

The test assumed __int128 to be available whenever __SSE__ was
defined, but this assumption doesn't hold on 32-bit x86.  Fixed.

for  gcc/testsuite/ChangeLog

	PR middle-end/87054
	* gcc.dg/pr87054.c: Adjust for no __int128 on x86.
---
 gcc/testsuite/gcc.dg/pr87054.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/testsuite/gcc.dg/pr87054.c b/gcc/testsuite/gcc.dg/pr87054.c
index 4ca2b62d2c7c9..3cb3b7dac6586 100644
--- a/gcc/testsuite/gcc.dg/pr87054.c
+++ b/gcc/testsuite/gcc.dg/pr87054.c
@@ -2,7 +2,7 @@
 // { dg-options "-O2" }
 
 #ifndef T
-# ifdef __SSE__
+# if __SIZEOF_INT128__ && defined __SSE__
 #  define T __int128
 # else
 #  define T long
Richard Biener Sept. 24, 2018, 9:58 a.m. UTC | #3
On Mon, 24 Sep 2018, Alexandre Oliva wrote:

> On Sep 18, 2018, Richard Biener <rguenther@suse.de> wrote:
> 
> >> +# ifdef __SSE__
> >> +#  define T __int128
> 
> Rainer reported this didn't work on 32-bit x86 with SSE enabled.
> Here's a patch that fixes it.  Ok to install?  Tested on x86_64,
> including such combinations as -m32, -m32/-msse, and -m32/-mno-sse.

Works for me.

> 
> [PR87054] adjust testcase for 32-bit x86
> 
> From: Alexandre Oliva <oliva@adacore.com>
> 
> The test assumed __int128 to be available whenever __SSE__ was
> defined, but this assumption doesn't hold on 32-bit x86.  Fixed.
> 
> for  gcc/testsuite/ChangeLog
> 
> 	PR middle-end/87054
> 	* gcc.dg/pr87054.c: Adjust for no __int128 on x86.
> ---
>  gcc/testsuite/gcc.dg/pr87054.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/gcc/testsuite/gcc.dg/pr87054.c b/gcc/testsuite/gcc.dg/pr87054.c
> index 4ca2b62d2c7c9..3cb3b7dac6586 100644
> --- a/gcc/testsuite/gcc.dg/pr87054.c
> +++ b/gcc/testsuite/gcc.dg/pr87054.c
> @@ -2,7 +2,7 @@
>  // { dg-options "-O2" }
>  
>  #ifndef T
> -# ifdef __SSE__
> +# if __SIZEOF_INT128__ && defined __SSE__
>  #  define T __int128
>  # else
>  #  define T long
>
diff mbox series

Patch

diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index f0eb04a751ccc..509fc2f3f5be2 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/gcc.dg/pr87054.c b/gcc/testsuite/gcc.dg/pr87054.c
new file mode 100644
index 0000000000000..4ca2b62d2c7c9
--- /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
+  }
+}