Hi,

As agreed in the patchwork sync call two weeks ago, this implements
#pragma GCC target () for riscv.

All the functionality was already there so we only need to wrap existing
functions.

Regtested on rv64gcv_zvl512b.

Regards
 Robin

        PR target/115325

gcc/ChangeLog:

        * config/riscv/riscv-c.cc (riscv_pragma_target_parse): New
        function.
        (riscv_register_pragmas): Register riscv_pragma_target_parse.
        * config/riscv/riscv-protos.h (riscv_process_target_attr_for_pragma):
        Declare.
        (riscv_reset_previous_fndecl): Ditto.
        * config/riscv/riscv-target-attr.cc 
(riscv_process_target_attr_for_pragma):
        New function.
        * config/riscv/riscv.cc (riscv_reset_previous_fndecl): Reset.
        (riscv_option_save): New function.
        (riscv_option_print): Ditto.
        (riscv_get_interrupt_type): Adjust docs.
        (TARGET_OPTION_SAVE): Implement.
        (TARGET_OPTION_PRINT): Ditto.
        * doc/extend.texi: Document that riscv can do target pragams.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/pragma-target-1.c: New test.
        * gcc.target/riscv/pragma-target-2.c: New test.
---
 gcc/config/riscv/riscv-c.cc                   | 44 ++++++++++++++
 gcc/config/riscv/riscv-protos.h               |  3 +
 gcc/config/riscv/riscv-target-attr.cc         | 11 ++++
 gcc/config/riscv/riscv.cc                     | 41 ++++++++++++-
 gcc/doc/extend.texi                           |  2 +-
 .../gcc.target/riscv/pragma-target-1.c        | 59 +++++++++++++++++++
 .../gcc.target/riscv/pragma-target-2.c        | 26 ++++++++
 7 files changed, 184 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/pragma-target-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/pragma-target-2.c

diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 4fc05281782..24537d547cf 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -213,6 +213,49 @@ riscv_pragma_intrinsic (cpp_reader *)
     error ("unknown %<#pragma riscv intrinsic%> option %qs", name);
 }
 
+/* Implement TARGETM.TARGET_OPTION.PRAGMA_PARSE.  */
+
+static bool
+riscv_pragma_target_parse (tree args, tree pop_target)
+{
+  /* If args is not NULL then process it and setup the target-specific
+     information that it specifies.  */
+  if (args)
+    {
+      if (!riscv_process_target_attr_for_pragma (args))
+       return false;
+
+      riscv_override_options_internal (&global_options);
+    }
+  /* args is NULL, restore to the state described in pop_target.  */
+  else
+    {
+      pop_target = pop_target ? pop_target : target_option_default_node;
+      cl_target_option_restore (&global_options, &global_options_set,
+                               TREE_TARGET_OPTION (pop_target));
+    }
+
+  target_option_current_node
+    = build_target_option_node (&global_options, &global_options_set);
+
+  riscv_reset_previous_fndecl ();
+
+  /* For the definitions, ensure all newly defined macros are considered
+     as used for -Wunused-macros.  There is no point warning about the
+     compiler predefined macros.  */
+  cpp_options *cpp_opts = cpp_get_options (parse_in);
+  unsigned char saved_warn_unused_macros = cpp_opts->warn_unused_macros;
+  cpp_opts->warn_unused_macros = 0;
+
+  cpp_force_token_locations (parse_in, BUILTINS_LOCATION);
+  riscv_cpu_cpp_builtins (parse_in);
+  cpp_stop_forcing_token_locations (parse_in);
+
+  cpp_opts->warn_unused_macros = saved_warn_unused_macros;
+
+  return true;
+}
+
 /* Implement TARGET_CHECK_BUILTIN_CALL.  */
 static bool
 riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
@@ -272,5 +315,6 @@ riscv_register_pragmas (void)
 {
   targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin;
   targetm.check_builtin_call = riscv_check_builtin_call;
+  targetm.target_option.pragma_parse = riscv_pragma_target_parse;
   c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic);
 }
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index d97773256c9..4f05ebd6a8d 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -848,12 +848,15 @@ riscv_option_valid_attribute_p (tree, tree, tree, int);
 extern bool
 riscv_option_valid_version_attribute_p (tree, tree, tree, int);
 extern bool
+riscv_process_target_attr_for_pragma (tree);
+extern bool
 riscv_process_target_version_attr (tree, location_t *);
 extern bool
 riscv_process_target_version_str (string_slice, location_t *);
 extern void
 riscv_override_options_internal (struct gcc_options *);
 extern void riscv_option_override (void);
+extern void riscv_reset_previous_fndecl (void);
 extern rtx riscv_prefetch_cookie (rtx, rtx);
 extern bool riscv_prefetch_offset_address_p (rtx, machine_mode);
 
diff --git a/gcc/config/riscv/riscv-target-attr.cc 
b/gcc/config/riscv/riscv-target-attr.cc
index 94f0a296e30..e6ea073acc1 100644
--- a/gcc/config/riscv/riscv-target-attr.cc
+++ b/gcc/config/riscv/riscv-target-attr.cc
@@ -489,6 +489,17 @@ riscv_option_valid_attribute_p (tree fndecl, tree, tree 
args, int)
   return ret;
 }
 
+/* Public wrapper for pragma processing.
+   Parse ARGS (a TREE_LIST of target attributes) and update global_options.
+   This is used by #pragma GCC target.  */
+
+bool
+riscv_process_target_attr_for_pragma (tree args)
+{
+  location_t loc = UNKNOWN_LOCATION;
+  return riscv_process_target_attr (args, &loc, riscv_target_attrs);
+}
+
 /* Parse the tree in ARGS that contains the target_version attribute
    information and update the global target options space.  If LOC is nonnull,
    report diagnostics against *LOC, otherwise remain silent.  */
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 1804d5a689b..c86cbc03857 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -12451,6 +12451,39 @@ riscv_option_restore (struct gcc_options *opts,
 
 static GTY (()) tree riscv_previous_fndecl;
 
+/* Reset the previous function declaration.  */
+
+void
+riscv_reset_previous_fndecl (void)
+{
+  riscv_previous_fndecl = NULL;
+}
+
+/* Implement TARGET_OPTION_SAVE.  */
+
+static void
+riscv_option_save (struct cl_target_option *ptr,
+                  struct gcc_options *opts,
+                  struct gcc_options * /* opts_set */)
+{
+  ptr->x_riscv_arch_string = opts->x_riscv_arch_string;
+  ptr->x_riscv_tune_string = opts->x_riscv_tune_string;
+  ptr->x_riscv_cpu_string = opts->x_riscv_cpu_string;
+}
+
+/* Implement TARGET_OPTION_PRINT.  */
+
+static void
+riscv_option_print (FILE *file, int indent, struct cl_target_option *ptr)
+{
+  fprintf (file, "%*sarch = %s\n", indent, "",
+          ptr->x_riscv_arch_string ? ptr->x_riscv_arch_string : "default");
+  fprintf (file, "%*stune = %s\n", indent, "",
+          ptr->x_riscv_tune_string ? ptr->x_riscv_tune_string : "default");
+  if (ptr->x_riscv_cpu_string)
+    fprintf (file, "%*scpu = %s\n", indent, "", ptr->x_riscv_cpu_string);
+}
+
 /* Implement TARGET_CONDITIONAL_REGISTER_USAGE.  */
 
 static void
@@ -12787,7 +12820,7 @@ riscv_get_interrupt_type (tree decl)
 /* Implement `TARGET_SET_CURRENT_FUNCTION'.  Unpack the codegen decisions
    like tuning and ISA features from the DECL_FUNCTION_SPECIFIC_TARGET
    of the function, if such exists.  This function may be called multiple
-   times on a single function so use aarch64_previous_fndecl to avoid
+   times on a single function so use riscv_previous_fndecl to avoid
    setting up identical state.  */
 
 /* Sanity checking for above function attributes.  */
@@ -16298,9 +16331,15 @@ riscv_prefetch_offset_address_p (rtx x, machine_mode 
mode)
 #undef TARGET_OPTION_OVERRIDE
 #define TARGET_OPTION_OVERRIDE riscv_option_override
 
+#undef TARGET_OPTION_SAVE
+#define TARGET_OPTION_SAVE riscv_option_save
+
 #undef TARGET_OPTION_RESTORE
 #define TARGET_OPTION_RESTORE riscv_option_restore
 
+#undef TARGET_OPTION_PRINT
+#define TARGET_OPTION_PRINT riscv_option_print
+
 #undef TARGET_OPTION_VALID_ATTRIBUTE_P
 #define TARGET_OPTION_VALID_ATTRIBUTE_P riscv_option_valid_attribute_p
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 11f6b02db36..916452a932d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10722,7 +10722,7 @@ for more information about the @code{target} attribute 
and the attribute
 syntax.
 
 The @code{#pragma GCC target} pragma is presently implemented for
-x86, ARM, AArch64, PowerPC, and S/390 targets only.
+x86, ARM, AArch64, PowerPC, RISC-V, and S/390 targets only.
 
 @cindex pragma GCC optimize
 @item #pragma GCC optimize (@var{string}, @dots{})
diff --git a/gcc/testsuite/gcc.target/riscv/pragma-target-1.c 
b/gcc/testsuite/gcc.target/riscv/pragma-target-1.c
new file mode 100644
index 00000000000..d1a06001557
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pragma-target-1.c
@@ -0,0 +1,59 @@
+/* Test for #pragma GCC target and push/pop options support in RISC-V */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O2" } */
+
+/* Default compilation options - no vector */
+void default_func(void) {
+#ifdef __riscv_vector
+  __builtin_abort();  /* Should not have vector by default */
+#endif
+}
+
+/* Change target to enable vector */
+#pragma GCC push_options
+#pragma GCC target("arch=rv64gcv")
+void vector_func(void) {
+#ifndef __riscv_vector
+  __builtin_abort();  /* Should have vector here */
+#endif
+}
+#pragma GCC pop_options
+
+/* Back to default - no vector */
+void after_pop_func(void) {
+#ifdef __riscv_vector
+  __builtin_abort();  /* Should not have vector after pop */
+#endif
+}
+
+/* Test multiple push/pop levels */
+#pragma GCC push_options
+#pragma GCC target("arch=rv64gc")
+void base_func(void) {
+#ifdef __riscv_vector
+  __builtin_abort();  /* Should not have vector */
+#endif
+}
+
+#pragma GCC push_options
+#pragma GCC target("arch=rv64gcv")
+void nested_vector_func(void) {
+#ifndef __riscv_vector
+  __builtin_abort();  /* Should have vector here */
+#endif
+}
+#pragma GCC pop_options
+
+void after_nested_pop_func(void) {
+#ifdef __riscv_vector
+  __builtin_abort();  /* Should not have vector after nested pop */
+#endif
+}
+#pragma GCC pop_options
+
+/* Final function should be back to original default */
+void final_func(void) {
+#ifdef __riscv_vector
+  __builtin_abort();  /* Should not have vector */
+#endif
+}
diff --git a/gcc/testsuite/gcc.target/riscv/pragma-target-2.c 
b/gcc/testsuite/gcc.target/riscv/pragma-target-2.c
new file mode 100644
index 00000000000..077bcdd280c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pragma-target-2.c
@@ -0,0 +1,26 @@
+/* Test for #pragma GCC target with tune parameter */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -mtune=rocket -O2" } */
+
+void default_tune(void) {
+  /* Default tune is rocket */
+}
+
+#pragma GCC push_options
+#pragma GCC target("tune=sifive-7-series")
+void sifive_tune(void) {
+  /* Tune should be sifive-7-series */
+}
+#pragma GCC pop_options
+
+void back_to_rocket(void) {
+  /* Tune should be back to rocket */
+}
+
+#pragma GCC target("arch=rv64gcv;tune=generic")
+void combined_options(void) {
+#ifndef __riscv_vector
+  __builtin_abort();  /* Should have vector */
+#endif
+  /* Tune should be generic */
+}
-- 
2.51.1


Reply via email to