From d6fcbe8370a04b897273e31585bb932ee398289e Mon Sep 17 00:00:00 2001
From: Sunil K Pandey <skpgkp1@gmail.com>
Date: Thu, 18 Jun 2020 08:40:45 -0700
Subject: [PATCH] Add TARGET_LOWER_LOCAL_DECL_ALIGNMENT [PR95237]

Default for this hook is NOP. For x86, in 32 bit mode, this hook
sets alignment of long long on stack to 32 bits if preferred stack
boundary is 32 bits.

 - This patch fixes
 	gcc.target/i386/pr69454-2.c
	gcc.target/i386/stackalign/longlong-1.c
 - Regression test on x86-64, no new fail introduced.

Tested on x86-64.

gcc/ChangeLog:

	PR target/95237
	* config/i386/i386.c (ix86_lower_local_decl_alignment): New
	function.
	(TARGET_LOWER_LOCAL_DECL_ALIGNMENT): Define.
	* doc/tm.texi: Regenerate.
	* doc/tm.texi.in (TARGET_LOWER_LOCAL_DECL_ALIGNMENT): New
	hook.
	* stor-layout.c (do_type_align): Call target hook to lower
	local decl alignment.
	* target.def (lower_local_decl_alignment): New hook.

gcc/testsuite/ChangeLog:

	PR target/95237
	* gcc.target/i386/pr95237-1.c: New test.
	* gcc.target/i386/pr95237-2.c: New test.
	* gcc.target/i386/pr95237-3.c: New test.
	* gcc.target/i386/pr95237-4.c: New test.
	* gcc.target/i386/pr95237-5.c: New test.
	* gcc.target/i386/pr95237-6.c: New test.
	* gcc.target/i386/pr95237-7.c: New test.
---
 gcc/config/i386/i386.c                    | 13 ++++++++++++
 gcc/doc/tm.texi                           |  6 ++++++
 gcc/doc/tm.texi.in                        |  2 ++
 gcc/stor-layout.c                         |  6 ++++++
 gcc/target.def                            |  7 +++++++
 gcc/testsuite/gcc.target/i386/pr95237-1.c | 16 +++++++++++++++
 gcc/testsuite/gcc.target/i386/pr95237-2.c | 10 ++++++++++
 gcc/testsuite/gcc.target/i386/pr95237-3.c | 10 ++++++++++
 gcc/testsuite/gcc.target/i386/pr95237-4.c | 10 ++++++++++
 gcc/testsuite/gcc.target/i386/pr95237-5.c | 16 +++++++++++++++
 gcc/testsuite/gcc.target/i386/pr95237-6.c | 24 +++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr95237-7.c | 19 ++++++++++++++++++
 12 files changed, 139 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr95237-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr95237-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr95237-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr95237-4.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr95237-5.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr95237-6.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr95237-7.c

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 37aaa49996d..0eb2930ac74 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -16917,6 +16917,16 @@ ix86_minimum_alignment (tree exp, machine_mode mode,
 
   return align;
 }
+
+/* Implement TARGET_LOWER_LOCAL_DECL_ALIGNMENT.  */
+
+static void
+ix86_lower_local_decl_alignment (tree decl)
+{
+  unsigned new_align = LOCAL_DECL_ALIGNMENT (decl);
+  if (new_align < DECL_ALIGN (decl))
+    SET_DECL_ALIGN (decl, new_align);
+}
 
 /* Find a location for the static chain incoming to a nested function.
    This is a register, unless all free registers are used by arguments.  */
@@ -23519,6 +23529,9 @@ ix86_run_selftests (void)
 #undef TARGET_CAN_CHANGE_MODE_CLASS
 #define TARGET_CAN_CHANGE_MODE_CLASS ix86_can_change_mode_class
 
+#undef TARGET_LOWER_LOCAL_DECL_ALIGNMENT
+#define TARGET_LOWER_LOCAL_DECL_ALIGNMENT ix86_lower_local_decl_alignment
+
 #undef TARGET_STATIC_RTX_ALIGNMENT
 #define TARGET_STATIC_RTX_ALIGNMENT ix86_static_rtx_alignment
 #undef TARGET_CONSTANT_ALIGNMENT
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 6e7d9dc54a9..60421c3cb5a 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -1086,6 +1086,12 @@ On 32-bit ELF the largest supported section alignment in bits is
 @samp{(0x80000000 * 8)}, but this is not representable on 32-bit hosts.
 @end defmac
 
+@deftypefn {Target Hook} void TARGET_LOWER_LOCAL_DECL_ALIGNMENT
+(tree @var{decl})
+Define this hook to lower alignment of local decl
+@samp{(@var{decl}}.
+@end deftypefn
+
 @deftypefn {Target Hook} HOST_WIDE_INT TARGET_STATIC_RTX_ALIGNMENT (machine_mode @var{mode})
 This hook returns the preferred alignment in bits for a
 statically-allocated rtx, such as a constant pool entry.  @var{mode}
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 3be984bbd5c..d76c85d5800 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -1036,6 +1036,8 @@ On 32-bit ELF the largest supported section alignment in bits is
 @samp{(0x80000000 * 8)}, but this is not representable on 32-bit hosts.
 @end defmac
 
+@hook TARGET_LOWER_LOCAL_DECL_ALIGNMENT
+
 @hook TARGET_STATIC_RTX_ALIGNMENT
 
 @defmac DATA_ALIGNMENT (@var{type}, @var{basic-align})
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index bde6fa22b58..24c66e68083 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -607,6 +607,12 @@ do_type_align (tree type, tree decl)
       SET_DECL_ALIGN (decl, TYPE_ALIGN (type));
       if (TREE_CODE (decl) == FIELD_DECL)
 	DECL_USER_ALIGN (decl) = TYPE_USER_ALIGN (type);
+      /* Lower local decl alignment.  */
+      else if (cfun != NULL
+	       && VAR_P (decl)
+	       && !is_global_var (decl)
+	       && !DECL_HARD_REGISTER (decl))
+	targetm.lower_local_decl_alignment (decl);
     }
   if (TYPE_WARN_IF_NOT_ALIGN (type) > DECL_WARN_IF_NOT_ALIGN (decl))
     SET_DECL_WARN_IF_NOT_ALIGN (decl, TYPE_WARN_IF_NOT_ALIGN (type));
diff --git a/gcc/target.def b/gcc/target.def
index 07059a87caf..6efaee62c19 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -3348,6 +3348,13 @@ HOOK_VECTOR_END (addr_space)
 #undef HOOK_PREFIX
 #define HOOK_PREFIX "TARGET_"
 
+DEFHOOK
+(lower_local_decl_alignment,
+ "Define this hook to lower alignment of local decl\n\
+@samp{(@var{decl}}.",
+ void, (tree decl),
+ hook_void_tree)
+
 DEFHOOK
 (static_rtx_alignment,
  "This hook returns the preferred alignment in bits for a\n\
diff --git a/gcc/testsuite/gcc.target/i386/pr95237-1.c b/gcc/testsuite/gcc.target/i386/pr95237-1.c
new file mode 100644
index 00000000000..bc8a84ee0db
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr95237-1.c
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-require-effective-target ia32 } */
+/* { dg-options "-mpreferred-stack-boundary=2" } */
+typedef __UINTPTR_TYPE__ uintptr_t;
+void __attribute__((noipa)) foo (long long *p, uintptr_t a)
+{
+  if ((uintptr_t)p & (a-1))
+      __builtin_abort ();
+}
+int main()
+{
+	long long x;
+	uintptr_t a = __alignof__(x);
+	foo(&x, a);
+	return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr95237-2.c b/gcc/testsuite/gcc.target/i386/pr95237-2.c
new file mode 100644
index 00000000000..82ff777669a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr95237-2.c
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+/* { dg-require-effective-target ia32 } */
+/* { dg-options "-mpreferred-stack-boundary=2" } */
+long long x;
+int main()
+{
+	if (__alignof__(x) != 8)
+	  __builtin_abort();
+	return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr95237-3.c b/gcc/testsuite/gcc.target/i386/pr95237-3.c
new file mode 100644
index 00000000000..2fb1f630362
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr95237-3.c
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+/* { dg-require-effective-target ia32 } */
+/* { dg-options "-mpreferred-stack-boundary=2" } */
+int main()
+{
+	long long x;
+	if (__alignof__(x) != 4)
+	  __builtin_abort();
+	return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr95237-4.c b/gcc/testsuite/gcc.target/i386/pr95237-4.c
new file mode 100644
index 00000000000..d52a770d703
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr95237-4.c
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+/* { dg-require-effective-target ia32 } */
+/* { dg-options "-mpreferred-stack-boundary=4" } */
+int main()
+{
+	long long x;
+	if (__alignof__(x) != 8)
+	  __builtin_abort();
+	return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr95237-5.c b/gcc/testsuite/gcc.target/i386/pr95237-5.c
new file mode 100644
index 00000000000..4d9be06a045
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr95237-5.c
@@ -0,0 +1,16 @@
+/* { dg-do compile { target ia32 } } */
+/* { dg-options "-mpreferred-stack-boundary=2 -Os -w" } */
+
+int a;
+
+long long
+b (void)
+{
+}
+
+void
+c (void)
+{
+  if (b())
+    a = 1;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr95237-6.c b/gcc/testsuite/gcc.target/i386/pr95237-6.c
new file mode 100644
index 00000000000..a1357de2c48
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr95237-6.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+#include <stddef.h>
+#ifdef  __x86_64__
+# define EXP_ALIGN 8
+#else
+# define EXP_ALIGN 4
+#endif
+
+struct test
+{
+  char a;
+  long long b;
+};
+struct test global_var;
+int main()
+{
+  	struct test local_var;
+	if (__alignof__(global_var) != EXP_ALIGN
+	    || __alignof__(local_var) != EXP_ALIGN
+	    || offsetof(struct test, b) != EXP_ALIGN)
+	  __builtin_abort();
+	return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr95237-7.c b/gcc/testsuite/gcc.target/i386/pr95237-7.c
new file mode 100644
index 00000000000..d612eb4a1f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr95237-7.c
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-require-effective-target ia32 } */
+/* { dg-options "-mpreferred-stack-boundary=2" } */
+#include <stddef.h>
+struct test
+{
+  char a;
+  long long b;
+};
+struct test global_var;
+int main()
+{
+  	struct test local_var;
+	if (__alignof__(global_var) != 4
+	    || __alignof__(local_var) != 4
+	    || offsetof(struct test, b) != 4)
+	  __builtin_abort();
+	return 0;
+}
-- 
2.26.2

