This implements #pragma GCC target () for riscv.
All the functionality was already there so we only need to wrap existing
functions.
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.
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,
{
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);
}
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);
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. */
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
/* 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. */
#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
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{})
--- /dev/null
+/* 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
+}
--- /dev/null
+/* 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 */
+}