commit 2df0f24332e316b8d18d4571438f76726a0326e7
Author: Kyrylo Tkachov <kyrylo.tkachov@arm.com>
Date:   Wed Jan 27 12:54:54 2016 +0000

    [AArch64] Only update assembler .arch directive when necessary

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 5ca2ae8..0751440 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -11163,6 +11163,17 @@ aarch64_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
    return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type;
 }
 
+struct aarch64_output_asm_info
+{
+  const struct processor *arch;
+  const struct processor *cpu;
+  unsigned long isa_flags;
+};
+
+/* A record of the last architecture state that we output in assembly
+   i.e. the .arch directive.  */
+static struct aarch64_output_asm_info aarch64_previous_asm_output;
+
 /* Implement ASM_DECLARE_FUNCTION_NAME.  Output the ISA features used
    by the function fndecl.  */
 
@@ -11183,25 +11194,60 @@ aarch64_declare_function_name (FILE *stream, const char* name,
     = aarch64_get_arch (targ_options->x_explicit_arch);
 
   unsigned long isa_flags = targ_options->x_aarch64_isa_flags;
-  std::string extension
-    = aarch64_get_extension_string_for_isa_flags (isa_flags);
-  asm_fprintf (asm_out_file, "\t.arch %s%s\n",
-	       this_arch->name, extension.c_str ());
+  /* Only update the assembler .arch state if we are changing to a
+     distinct architecture state.  */
+  if (this_arch != aarch64_previous_asm_output.arch
+      || isa_flags != aarch64_previous_asm_output.isa_flags)
+    {
+      std::string extension
+	= aarch64_get_extension_string_for_isa_flags (isa_flags);
+      asm_fprintf (asm_out_file, "\t.arch %s%s\n",
+		    this_arch->name, extension.c_str ());
 
+      aarch64_previous_asm_output.arch = this_arch;
+      aarch64_previous_asm_output.isa_flags = isa_flags;
+    }
   /* Print the cpu name we're tuning for in the comments, might be
      useful to readers of the generated asm.  */
 
   const struct processor *this_tune
     = aarch64_get_tune_cpu (targ_options->x_explicit_tune_core);
 
-  asm_fprintf (asm_out_file, "\t" ASM_COMMENT_START ".tune %s\n",
-	       this_tune->name);
+  if (flag_debug_asm && this_tune != aarch64_previous_asm_output.cpu)
+    {
+      asm_fprintf (asm_out_file, "\t" ASM_COMMENT_START ".tune %s\n",
+		   this_tune->name);
+      aarch64_previous_asm_output.cpu = this_tune;
+    }
 
   /* Don't forget the type directive for ELF.  */
   ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function");
   ASM_OUTPUT_LABEL (stream, name);
 }
 
+/* Implements TARGET_ASM_FILE_START.  Output the assembly header.  */
+
+static void
+aarch64_start_file (void)
+{
+  struct cl_target_option *default_options
+    = TREE_TARGET_OPTION (target_option_default_node);
+
+  const struct processor *default_arch
+    = aarch64_get_arch (default_options->x_explicit_arch);
+  unsigned long default_isa_flags = default_options->x_aarch64_isa_flags;
+  std::string extension
+    = aarch64_get_extension_string_for_isa_flags (default_isa_flags);
+
+   asm_fprintf (asm_out_file, "\t.arch %s%s\n", default_arch->name,
+		extension.c_str ());
+   aarch64_previous_asm_output.arch = default_arch;
+   aarch64_previous_asm_output.isa_flags = default_isa_flags;
+   aarch64_previous_asm_output.cpu = NULL;
+
+   default_file_start ();
+}
+
 /* Emit load exclusive.  */
 
 static void
@@ -13935,6 +13981,9 @@ aarch64_optab_supported_p (int op, machine_mode, machine_mode,
 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
   hook_bool_const_tree_hwi_hwi_const_tree_true
 
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START aarch64_start_file
+
 #undef TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK aarch64_output_mi_thunk
 
diff --git a/gcc/testsuite/gcc.target/aarch64/assembler_arch_1.c b/gcc/testsuite/gcc.target/aarch64/assembler_arch_1.c
new file mode 100644
index 0000000..901e50a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/assembler_arch_1.c
@@ -0,0 +1,20 @@
+/* { dg-do assemble } */
+/* { dg-options "-march=armv8-a" } */
+
+/* Make sure that the function header in assembly doesn't override
+   user asm arch_extension directives.  */
+
+__asm__ (".arch_extension lse");
+
+void
+foo (int i, int *v)
+{
+  register int w0 asm ("w0") = i;
+  register int *x1 asm ("x1") = v;
+
+  asm volatile (
+  "\tstset   %w[i], %[v]\n"
+  : [i] "+r" (w0), [v] "+Q" (v)
+  : "r" (x1)
+  : "x30");
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/target_attr_1.c b/gcc/testsuite/gcc.target/aarch64/target_attr_1.c
index 852ce1e..0527d0c 100644
--- a/gcc/testsuite/gcc.target/aarch64/target_attr_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/target_attr_1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mcpu=thunderx -save-temps" } */
+/* { dg-options "-O2 -mcpu=thunderx -dA" } */
 
 /* Test that cpu attribute overrides the command-line -mcpu.  */
 
diff --git a/gcc/testsuite/gcc.target/aarch64/target_attr_15.c b/gcc/testsuite/gcc.target/aarch64/target_attr_15.c
index 02091c6..f72bec8 100644
--- a/gcc/testsuite/gcc.target/aarch64/target_attr_15.c
+++ b/gcc/testsuite/gcc.target/aarch64/target_attr_15.c
@@ -10,6 +10,4 @@ foo (int a)
   return a + 1;
 }
 
-/* { dg-final { scan-assembler-not "\\+fp" } } */
-/* { dg-final { scan-assembler-not "\\+crypto" } } */
-/* { dg-final { scan-assembler-not "\\+simd" } } */
+/* { dg-final { scan-assembler-times "\\.arch armv8-a\n" 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/target_attr_7.c b/gcc/testsuite/gcc.target/aarch64/target_attr_7.c
index 32a8403..818d327 100644
--- a/gcc/testsuite/gcc.target/aarch64/target_attr_7.c
+++ b/gcc/testsuite/gcc.target/aarch64/target_attr_7.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mcpu=thunderx -save-temps" } */
+/* { dg-options "-O2 -mcpu=thunderx -dA" } */
 
 /* Make sure that #pragma overrides command line option and
    target attribute overrides the pragma.  */
