@@ -214,4 +214,7 @@ extern bool loongarch_explicit_relocs_p (enum loongarch_symbol_type);
extern bool loongarch_symbol_extreme_p (enum loongarch_symbol_type);
extern bool loongarch_option_valid_attribute_p (tree, tree, tree, int);
extern void loongarch_option_override_internal (struct loongarch_target *, struct gcc_options *, struct gcc_options *);
+extern void loongarch_reset_previous_fndecl (void);
+extern void loongarch_save_restore_target_globals (tree new_tree);
+extern void loongarch_register_pragmas (void);
#endif /* ! GCC_LOONGARCH_PROTOS_H */
@@ -349,6 +349,16 @@ loongarch_option_valid_attribute_p (tree fndecl, tree, tree args, int)
tree new_target, new_optimize;
tree existing_target = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
+ /* If what we're processing is the current pragma string then the
+ target option node is already stored in target_option_current_node
+ by loongarch_pragma_target_parse in loongarch-target-attr.cc.
+ Use that to avoid having to re-parse the string. */
+ if (!existing_target && args == current_target_pragma)
+ {
+ DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = target_option_current_node;
+ return true;
+ }
+
tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
old_optimize
@@ -411,3 +421,52 @@ loongarch_option_valid_attribute_p (tree fndecl, tree, tree args, int)
TREE_OPTIMIZATION (old_optimize));
return ret;
}
+
+/* Hook to validate the current #pragma GCC target and set the state, and
+ update the macros based on what was changed. If ARGS is NULL, then
+ POP_TARGET is used to reset the options. */
+
+static bool
+loongarch_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 (!loongarch_process_target_attr (args, NULL))
+ return false;
+
+ loongarch_option_override_internal (&la_target,
+ &global_options,
+ &global_options_set);
+ }
+
+ /* 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);
+
+ loongarch_reset_previous_fndecl ();
+
+ /* If we're popping or reseting make sure to update the globals so that
+ the optab availability predicates get recomputed. */
+ if (pop_target)
+ loongarch_save_restore_target_globals (pop_target);
+
+ return true;
+}
+
+/* Implement REGISTER_TARGET_PRAGMAS. */
+
+void
+loongarch_register_pragmas (void)
+{
+ /* Update pragma hook to allow parsing #pragma GCC target. */
+ targetm.target_option.pragma_parse = loongarch_pragma_target_parse;
+}
@@ -7677,11 +7677,17 @@ loongarch_option_override_internal (struct loongarch_target *target,
static GTY(()) tree loongarch_previous_fndecl;
+void
+loongarch_reset_previous_fndecl (void)
+{
+ loongarch_previous_fndecl = NULL;
+}
+
/* Restore or save the TREE_TARGET_GLOBALS from or to new_tree.
Used by loongarch_set_current_function to
make sure optab availability predicates are recomputed when necessary. */
-static void
+void
loongarch_save_restore_target_globals (tree new_tree)
{
if (TREE_TARGET_GLOBALS (new_tree))
@@ -7734,13 +7740,12 @@ loongarch_set_current_function (tree fndecl)
loongarch_previous_fndecl = fndecl;
- if (new_tree == old_tree)
- return;
+ if (new_tree != old_tree)
+ /* According to the settings of the functions attribute and pragma,
+ the options is corrected. */
+ cl_target_option_restore (&global_options, &global_options_set,
+ TREE_TARGET_OPTION (new_tree));
- /* According to the settings of the functions attribute and pragma,
- the options is corrected. */
- cl_target_option_restore (&global_options, &global_options_set,
- TREE_TARGET_OPTION (new_tree));
/* After correcting the value of options, we need to update the
rules for using the hardware registers to ensure that the
@@ -26,6 +26,8 @@ along with GCC; see the file COPYING3. If not see
#define SWITCHABLE_TARGET 1
+#define REGISTER_TARGET_PRAGMAS() loongarch_register_pragmas ()
+
#define TARGET_SUPPORTS_WIDE_INT 1
/* Macros to silence warnings about numbers being signed in traditional
@@ -28413,6 +28413,7 @@ option is specified. @xref{OpenMP}, and @ref{OpenACC}.
@menu
* AArch64 Pragmas::
* ARM Pragmas::
+* LoongArch Pragmas::
* M32C Pragmas::
* PRU Pragmas::
* RS/6000 and PowerPC Pragmas::
@@ -28465,6 +28466,18 @@ Do not affect the @code{long_call} or @code{short_call} attributes of
subsequent functions.
@end table
+@node LoongArch Pragmas
+@subsection LoongArch Pragmas
+
+The list of attributes supported by Pragma is the same as that of target
+function attributres. @xref{LoongArch Function Attributes}.
+
+Example:
+
+@smallexample
+#pragma GCC target("strict-align")
+@end smallexample
+
@node M32C Pragmas
@subsection M32C Pragmas
@@ -1,10 +1,14 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -march=loongarch64 -mno-lsx" } */
+/* { dg-options "-O2 -march=loongarch64 -mno-lsx -std=gnu11" } */
extern char a[64];
extern char b[64];
+#ifndef TEST_TARGET_PRAGMA
__attribute__ ((target ("arch=la64v1.1")))
+#else
+#pragma GCC target ("arch=la64v1.1")
+#endif
void
test (void)
{
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=loongarch64 -mno-lsx -std=gnu11" } */
+
+#define TEST_TARGET_PRAGMA 1
+#include "./arch-func-attr-1.c"
+
+/* { dg-final { scan-assembler "vld" } } */
@@ -4,7 +4,11 @@
extern char a[8];
extern char b[8];
+#ifndef TEST_TARGET_PRAGMA
__attribute__ ((target ("cmodel=extreme")))
+#else
+#pragma GCC target ("cmodel=extreme")
+#endif
void
test (void)
{
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcmodel=normal -mexplicit-relocs=none" } */
+
+#define TEST_TARGET_PRAGMA 1
+#include "./cmodel-func-attr-1.c"
+
+/* { dg-final { scan-assembler "la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,a" } } */
@@ -4,7 +4,11 @@
typedef int v8i32 __attribute__ ((vector_size(32), aligned(32)));
extern v8i32 a, b, c;
+#ifndef TEST_TARGET_PRAGMA
__attribute__ ((target ("lasx")))
+#else
+#pragma GCC target ("lasx")
+#endif
void
test (void)
{
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mno-lsx" } */
+
+#define TEST_TARGET_PRAGMA 1
+#include "./lasx-func-attr-1.c"
+
+/* { dg-final { scan-assembler "xvadd.w" } } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlasx" } */
+
+typedef int v8i32 __attribute__ ((vector_size(32), aligned(32)));
+extern v8i32 a, b, c;
+
+#pragma GCC target ("no-lasx")
+void
+test (void)
+{
+ a = __builtin_lasx_xvadd_w (b, c); /* { dg-error "built-in function '__builtin_lasx_xvadd_w' is not enabled" } */
+}
@@ -4,7 +4,11 @@
typedef int v4i32 __attribute__ ((vector_size(16), aligned(16)));
extern v4i32 a, b, c;
+#ifndef TEST_TARGET_PRAGMA
__attribute__ ((target ("lsx")))
+#else
+#pragma GCC target ("lsx")
+#endif
void
test (void)
{
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mno-lsx" } */
+
+#define TEST_TARGET_PRAGMA 1
+#include "./lsx-func-attr-1.c"
+
+/* { dg-final { scan-assembler "vadd.w" } } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlsx" } */
+
+typedef int v4i32 __attribute__ ((vector_size(16), aligned(16)));
+extern v4i32 a, b, c;
+
+#pragma GCC target ("no-lsx")
+void
+test (void)
+{
+ a = __builtin_lsx_vadd_w (b, c); /* { dg-error "built-in function '__builtin_lsx_vadd_w' is not enabled" } */
+}
new file mode 100644
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlasx" } */
+/* { dg-final { scan-assembler-not "xvadd\\\.w" } } */
+/* { dg-final { scan-assembler "xvsll\\\.w" } } */
+
+#include <lasxintrin.h>
+
+extern v8i32 a, b, c;
+#pragma GCC push_options
+#pragma GCC target ("no-lasx")
+void
+test (void)
+{
+ a = b + c;
+}
+#pragma GCC pop_options
+
+void
+test1 (void)
+{
+ c = __builtin_lasx_xvsll_w (a, b);
+}
@@ -3,7 +3,11 @@
extern char a[8];
extern char b[8];
+#ifndef TEST_TARGET_PRAGMA
__attribute__ ((target ("no-strict-align")))
+#else
+#pragma GCC target ("no-strict-align")
+#endif
void
test (void)
{
@@ -3,7 +3,11 @@
extern char a[8];
extern char b[8];
+#ifndef TEST_TARGET_PRAGMA
__attribute__ ((target ("strict-align")))
+#else
+#pragma GCC target ("strict-align")
+#endif
void
test (void)
{
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mstrict-align" } */
+
+#define TEST_TARGET_PRAGMA 1
+#include "./strict_align-func-attr-1.c"
+
+/* { dg-final { scan-assembler-not "ld.bu" } } */
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mno-strict-align" } */
+
+#define TEST_TARGET_PRAGMA 1
+#include "./strict_align-func-attr-2.c"
+
+/* { dg-final { scan-assembler-not "ld.w" } } */
@@ -4,7 +4,11 @@
typedef int v4i32 __attribute__ ((vector_size(16), aligned(16)));
extern v4i32 a, b, c;
+#ifndef TEST_TARGET_PRAGMA
__attribute__ ((target ("no-lasx")))
+#else
+#pragma GCC target ("no-lasx")
+#endif
void
test (void)
{
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlsx" } */
+
+#define TEST_TARGET_PRAGMA 1
+#include "./vector-func-attr-1.c"
+
+/* { dg-final { scan-assembler "vadd.w" } } */