Hi All,

This patch adds support for the setting the architecture and extensions
using the target GCC pragma.

#pragma GCC target ("arch=armv8-a+crc")

It also supports a short hand where an extension is just added to the
current architecture without changing it

#pragma GCC target ("+crc")

Popping and pushing options also correctly reconfigure the global state
as expected.

Also supported is using the __attribute__((target("..."))) attributes
on functions to change the architecture or extension.

Regtested on arm-none-eabi and no regressions.

Ok for trunk?

gcc/
2017-11-06  Tamar Christina  <tamar.christ...@arm.com>

        PR target/82641
        * config/arm/arm.c (arm_valid_target_attribute_rec):
        Parse "arch=" and "+<ext>".
        (arm_valid_target_attribute_tree): Re-init global options.
        (arm_option_override): Make non-static.
        (arm_options_perform_arch_sanity_checks): Make errors fatal.
        * gcc/config/arm/arm-c.c (__ARM_FEATURE_CMSE): Support undef.
        (__ARM_FEATURE_CRC32): Support undef.
        * config/arm/arm_acle.h (__ARM_FEATURE_CRC32): Replace with pragma.
        * doc/extend.texi (ARM Function Attributes): Add pragma and target.

gcc/testsuite/
2017-11-06  Tamar Christina  <tamar.christ...@arm.com>

        PR target/82641
        * gcc.target/arm/pragma_arch_attribute.c: New.

-- 
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index ea47d1746fefb8dfb7981e1817edbf942d37be55..2b308fa2e3d5274682cc32dd9b91712c5604267e 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3297,6 +3297,7 @@ arm_configure_build_target (struct arm_build_target *target,
   target->tune_flags = tune_data->tune_flags;
   target->tune = tune_data->tune;
   target->tune_core = tune_data->scheduler;
+  arm_option_reconfigure_globals ();
 }
 
 /* Fix up any incompatible options that the user has specified.  */
@@ -30642,7 +30643,7 @@ arm_valid_target_attribute_rec (tree args, struct gcc_options *opts)
 	  if (! opt_enum_arg_to_value (OPT_mfpu_, q+4,
 				       &fpu_index, CL_TARGET))
 	    {
-	      error ("invalid fpu for attribute(target(\"%s\"))", q);
+	      error ("invalid fpu for target attribute or pragma %qs", q);
 	      return false;
 	    }
 	  if (fpu_index == TARGET_FPU_auto)
@@ -30655,9 +30656,29 @@ arm_valid_target_attribute_rec (tree args, struct gcc_options *opts)
 	    }
 	  opts->x_arm_fpu_index = (enum fpu_type) fpu_index;
 	}
+      else if (!strncmp (q, "arch=", 5))
+	{
+	  char* arch = q+5;
+	  const arch_option *arm_selected_arch
+	     = arm_parse_arch_option_name (all_architectures, "arch", arch);
+
+	  if (!arm_selected_arch)
+	    {
+	      error ("invalid architecture for target attribute or pragma %qs",
+		     q);
+	      return false;
+	    }
+
+	  opts->x_arm_arch_string = xstrndup (arch, strlen (arch));
+	}
+      else if (q[0] == '+')
+	{
+	  opts->x_arm_arch_string
+	    = xasprintf ("%s%s", opts->x_arm_arch_string, q);
+	}
       else
 	{
-	  error ("attribute(target(\"%s\")) is unknown", q);
+	  error ("unknown target attribute or pragma %qs", q);
 	  return false;
 	}
     }
@@ -30679,7 +30700,10 @@ arm_valid_target_attribute_tree (tree args, struct gcc_options *opts,
   cl_target_option_save (&cl_opts, opts);
   arm_configure_build_target (&arm_active_target, &cl_opts, opts_set, false);
   arm_option_check_internal (opts);
-  /* Do any overrides, such as global options arch=xxx.  */
+  /* Do any overrides, such as global options arch=xxx.
+     We do this since arm_active_target was overridden.  */
+  arm_option_reconfigure_globals ();
+  arm_options_perform_arch_sanity_checks ();
   arm_option_override_internal (opts, opts_set);
 
   return build_target_option_node (opts);
diff --git a/gcc/config/arm/arm_acle.h b/gcc/config/arm/arm_acle.h
index 972e28edb86c1f137e16982acc6f346e0eac04fb..ad28a45866df8dadd7d4c830efc7e8494f41716a 100644
--- a/gcc/config/arm/arm_acle.h
+++ b/gcc/config/arm/arm_acle.h
@@ -173,7 +173,10 @@ __arm_mrrc2 (const unsigned int __coproc, const unsigned int __opc1,
 #endif /*  __ARM_ARCH >= 5.  */
 #endif /* (!__thumb__ || __thumb2__) &&  __ARM_ARCH >= 4.  */
 
-#ifdef __ARM_FEATURE_CRC32
+#pragma GCC push_options
+#if __ARM_ARCH >= 8
+#pragma GCC target ("arch=armv8-a+crc")
+
 __extension__ static __inline uint32_t __attribute__ ((__always_inline__))
 __crc32b (uint32_t __a, uint8_t __b)
 {
@@ -232,7 +235,8 @@ __crc32cd (uint32_t __a, uint64_t __b)
 }
 #endif
 
-#endif
+#endif /* __ARM_ARCH >= 8.  */
+#pragma GCC pop_options
 
 #ifdef __cplusplus
 }
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 8aa443f87fb700f7a723d736bdbd53b6c839656d..18d0ffa6820326ce7badf33001b1c6a467c95883 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -3858,6 +3858,42 @@ Specifies the fpu for which to tune the performance of this function.
 The behavior and permissible arguments are the same as for the @option{-mfpu=}
 command-line option.
 
+@item arch=
+@cindex @code{arch=} function attribute, ARM
+Specifies the architecture version and architectural extensions to use
+for this function.  The behavior and permissible arguments are the same as
+for the @option{-march=} command-line option.
+
+The above target attributes can be specified as follows:
+
+@smallexample
+__attribute__((target("@var{attr-string}")))
+int
+f (int a)
+@{
+  return a + 5;
+@}
+@end smallexample
+
+where @code{@var{attr-string}} is one of the attribute strings.
+
+Additionally, the architectural extension string may be specified on its
+own.  This can be used to turn on and off particular architectural extensions
+without having to specify a particular architecture version or core.  Example:
+
+@smallexample
+__attribute__((target("+crc+nocrypto")))
+int
+foo (int a)
+@{
+  return a + 5;
+@}
+@end smallexample
+
+In this example @code{target("+crc+nocrypto")} enables the @code{crc}
+extension and disables the @code{crypto} extension for the function @code{foo}
+without modifying an existing @option{-march=} or @option{-mcpu} option.
+
 @end table
 
 @end table
diff --git a/gcc/testsuite/gcc.target/arm/pragma_arch_attribute.c b/gcc/testsuite/gcc.target/arm/pragma_arch_attribute.c
new file mode 100644
index 0000000000000000000000000000000000000000..a06dbf04037384e98b6b9eaf5ab90b04a09a6d07
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pragma_arch_attribute.c
@@ -0,0 +1,54 @@
+/* Test for #pragma target macros.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8a_ok } */
+/* { dg-add-options arm_arch_v8a } */
+
+#include <arm_acle.h>
+
+#ifdef __ARM_FEATURE_CRC32
+# error "__ARM_FEATURE_CRC32 is already defined."
+#endif
+
+#pragma GCC push_options
+#pragma GCC target ("arch=armv8-a+crc")
+#ifndef __ARM_FEATURE_CRC32
+# error "__ARM_FEATURE_CRC32 is not defined in push 1."
+#endif
+#pragma GCC pop_options
+
+#ifdef __ARM_FEATURE_CRC32
+# error "__ARM_FEATURE_CRC32 is defined after pop 1."
+#endif
+
+#pragma GCC push_options
+#pragma GCC target ("+crc")
+#ifndef __ARM_FEATURE_CRC32
+# error "__ARM_FEATURE_CRC32 is not defined in push 2."
+#endif
+#pragma GCC pop_options
+
+#ifdef __ARM_FEATURE_CRC32
+# error "__ARM_FEATURE_CRC32 is defined after pop 2."
+#endif
+
+__attribute__((target("+crc")))
+void test_crc_unknown_ok_attr_1 ()
+{
+	__crc32b (0, 0);
+}
+
+#ifdef __ARM_FEATURE_CRC32
+# error "__ARM_FEATURE_CRC32 is defined after attribute set 1."
+#endif
+
+__attribute__((target("arch=armv8-a+crc")))
+void test_crc_unknown_ok_attr_2 ()
+{
+	__crc32b (0, 0);
+}
+
+#ifdef __ARM_FEATURE_CRC32
+# error "__ARM_FEATURE_CRC32 is defined after attribute set 2."
+#endif
+
+#pragma GCC reset_options
\ No newline at end of file

Reply via email to