aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorLewis Hyatt <lhyatt@gmail.com>2023-10-27 04:32:50 -0400
committerLewis Hyatt <lhyatt@gmail.com>2023-10-27 04:34:15 -0400
commit8697d3a1dcf32750a3b9dc007586eb5f9ba5f17a (patch)
tree32f91b14f6c52acaf7c018011614bbd951d7e5e6 /gcc
parentb038e202210eb3e982c2ec802438edd523b47a02 (diff)
downloadgcc-8697d3a1dcf32750a3b9dc007586eb5f9ba5f17a.zip
gcc-8697d3a1dcf32750a3b9dc007586eb5f9ba5f17a.tar.gz
gcc-8697d3a1dcf32750a3b9dc007586eb5f9ba5f17a.tar.bz2
preprocessor: c++: Support `#pragma GCC target' macros [PR87299]
`#pragma GCC target' is not currently handled in preprocess-only mode (e.g., when running gcc -E or gcc -save-temps). As noted in the PR, this means that if the target pragma defines any macros, those macros are not effective in preprocess-only mode. Similarly, such macros are not effective when compiling with C++ (even when compiling without -save-temps), because C++ does not process the pragma until after all tokens have been obtained from libcpp, at which point it is too late for macro expansion to take place. Since r13-1544 and r14-2893, there is a general mechanism to handle pragmas under these conditions as well, so resolve the PR by using the new "early pragma" support. toplev.cc required some changes because the target-specific handlers for `#pragma GCC target' may call target_reinit(), and toplev.cc was not expecting that function to be called in preprocess-only mode. I added some additional testcases from the PR for x86. The other targets that support `#pragma GCC target' (aarch64, arm, nios2, powerpc, s390) already had tests verifying that the pragma sets macros as expected; here I have added -save-temps versions of some of them, to test that they now work in preprocess-only mode as well. gcc/c-family/ChangeLog: PR preprocessor/87299 * c-pragma.cc (init_pragma): Register `#pragma GCC target' and related pragmas in preprocess-only mode, and enable early handling. (c_reset_target_pragmas): New function refactoring code from... (handle_pragma_reset_options): ...here. * c-pragma.h (c_reset_target_pragmas): Declare. gcc/cp/ChangeLog: PR preprocessor/87299 * parser.cc (cp_lexer_new_main): Call c_reset_target_pragmas () after preprocessing is complete, before starting compilation. gcc/ChangeLog: PR preprocessor/87299 * toplev.cc (no_backend): New static global. (finalize): Remove argument no_backend, which is now a static global. (process_options): Likewise. (do_compile): Likewise. (target_reinit): Don't do anything in preprocess-only mode. (toplev::main): Adapt to no_backend change. (toplev::finalize): Likewise. gcc/testsuite/ChangeLog: PR preprocessor/87299 * c-c++-common/pragma-target-1.c: New test. * c-c++-common/pragma-target-2.c: New test. * g++.target/i386/pr87299-1.C: New test. * g++.target/i386/pr87299-2.C: New test. * gcc.target/i386/pr87299-1.c: New test. * gcc.target/i386/pr87299-2.c: New test. * gcc.target/s390/target-attribute/tattr-2b.c: New test. * gcc.target/aarch64/pragma_cpp_predefs_1b.c: New test. * gcc.target/arm/pragma_arch_attribute_1b.c: New test. * gcc.target/nios2/custom-fp-2b.c: New test. * gcc.target/powerpc/float128-3b.c: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/c-family/c-pragma.cc49
-rw-r--r--gcc/c-family/c-pragma.h2
-rw-r--r--gcc/cp/parser.cc6
-rw-r--r--gcc/testsuite/c-c++-common/pragma-target-1.c19
-rw-r--r--gcc/testsuite/c-c++-common/pragma-target-2.c27
-rw-r--r--gcc/testsuite/g++.target/i386/pr87299-1.C8
-rw-r--r--gcc/testsuite/g++.target/i386/pr87299-2.C8
-rw-r--r--gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1b.c3
-rw-r--r--gcc/testsuite/gcc.target/arm/pragma_arch_attribute_1b.c6
-rw-r--r--gcc/testsuite/gcc.target/i386/pr87299-1.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr87299-2.c8
-rw-r--r--gcc/testsuite/gcc.target/nios2/custom-fp-2b.c26
-rw-r--r--gcc/testsuite/gcc.target/powerpc/float128-3b.c4
-rw-r--r--gcc/testsuite/gcc.target/s390/target-attribute/tattr-2b.c51
-rw-r--r--gcc/toplev.cc21
15 files changed, 219 insertions, 27 deletions
diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc
index 98dfb0f..df3e3e6 100644
--- a/gcc/c-family/c-pragma.cc
+++ b/gcc/c-family/c-pragma.cc
@@ -1289,24 +1289,16 @@ handle_pragma_pop_options (cpp_reader *)
current_optimize_pragma = p->optimize_strings;
}
-/* Handle #pragma GCC reset_options to restore the current target and
- optimization options to the original options used on the command line. */
+/* This is mostly a helper for handle_pragma_reset_options () to do the actual
+ work, but the C++ frontend, for example, needs an external interface to
+ perform this operation, since it processes target pragmas twice. (Once for
+ preprocessing purposes, and then again during compilation.) */
-static void
-handle_pragma_reset_options (cpp_reader *)
+void
+c_reset_target_pragmas ()
{
- enum cpp_ttype token;
- tree x = 0;
tree new_optimize = optimization_default_node;
tree new_target = target_option_default_node;
-
- token = pragma_lex (&x);
- if (token != CPP_EOF)
- {
- warning (OPT_Wpragmas, "junk at end of %<#pragma reset_options%>");
- return;
- }
-
if (new_target != target_option_current_node)
{
(void) targetm.target_option.pragma_parse (NULL_TREE, new_target);
@@ -1326,6 +1318,19 @@ handle_pragma_reset_options (cpp_reader *)
current_optimize_pragma = NULL_TREE;
}
+/* Handle #pragma GCC reset_options to restore the current target and
+ optimization options to the original options used on the command line. */
+
+static void
+handle_pragma_reset_options (cpp_reader *)
+{
+ tree x;
+ if (pragma_lex (&x) != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of %<#pragma reset_options%>");
+ else
+ c_reset_target_pragmas ();
+}
+
/* Print a plain user-specified message. */
static void
@@ -1844,11 +1849,19 @@ init_pragma (void)
c_register_pragma_with_early_handler ("GCC", "diagnostic",
handle_pragma_diagnostic,
handle_pragma_diagnostic_early);
- c_register_pragma ("GCC", "target", handle_pragma_target);
+ c_register_pragma_with_early_handler ("GCC", "target",
+ handle_pragma_target,
+ handle_pragma_target);
c_register_pragma ("GCC", "optimize", handle_pragma_optimize);
- c_register_pragma ("GCC", "push_options", handle_pragma_push_options);
- c_register_pragma ("GCC", "pop_options", handle_pragma_pop_options);
- c_register_pragma ("GCC", "reset_options", handle_pragma_reset_options);
+ c_register_pragma_with_early_handler ("GCC", "push_options",
+ handle_pragma_push_options,
+ handle_pragma_push_options);
+ c_register_pragma_with_early_handler ("GCC", "pop_options",
+ handle_pragma_pop_options,
+ handle_pragma_pop_options);
+ c_register_pragma_with_early_handler ("GCC", "reset_options",
+ handle_pragma_reset_options,
+ handle_pragma_reset_options);
c_register_pragma (0, "region", handle_pragma_ignore);
c_register_pragma (0, "endregion", handle_pragma_ignore);
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index 603c515..682157a 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -256,7 +256,7 @@ c_register_pragma_with_early_handler (const char *space, const char *name,
pragma_handler_1arg early_handler);
extern void c_invoke_early_pragma_handler (unsigned int);
extern void c_pp_invoke_early_pragma_handler (unsigned int);
-
+extern void c_reset_target_pragmas ();
extern void maybe_apply_pragma_weak (tree);
extern void maybe_apply_pending_pragma_weaks (void);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 5a6c416..5f13904 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -766,6 +766,12 @@ cp_lexer_new_main (void)
maybe_check_all_macros (parse_in);
+ /* If we processed any #pragma GCC target directives, we handled them early so
+ any macros they defined would be effective during preprocessing. Now, we
+ need to reset to the default state to begin compilation, and we will
+ process them again at the correct time as needed. */
+ c_reset_target_pragmas ();
+
gcc_assert (!lexer->next_token->purged_p);
return lexer;
}
diff --git a/gcc/testsuite/c-c++-common/pragma-target-1.c b/gcc/testsuite/c-c++-common/pragma-target-1.c
new file mode 100644
index 0000000..2584c22
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pragma-target-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-mno-avx -O3" } */
+
+void f (double *x)
+{
+ for (int i = 0; i != 8; ++i)
+ x[i] *= 2;
+}
+
+#pragma GCC target("avx")
+
+void g (double *x)
+{
+ for (int i = 0; i != 8; ++i)
+ x[i] *= 2;
+}
+
+/* Make sure the target pragma affected only g() and not also f(). */
+/* { dg-final { scan-assembler-times vzeroupper 1 } } */
diff --git a/gcc/testsuite/c-c++-common/pragma-target-2.c b/gcc/testsuite/c-c++-common/pragma-target-2.c
new file mode 100644
index 0000000..e7bf305
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pragma-target-2.c
@@ -0,0 +1,27 @@
+/* { dg-do preprocess { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-mno-avx" } */
+
+#ifdef __AVX__
+#error "__AVX__ should not be defined #1"
+#endif
+
+#pragma GCC target("avx")
+#ifndef __AVX__
+#error "__AVX__ should be defined #1"
+#endif
+
+#pragma GCC reset_options
+#ifdef __AVX__
+#error "__AVX__ should not be defined #2"
+#endif
+
+#pragma GCC push_options
+#pragma GCC target("avx")
+#ifndef __AVX__
+#error "__AVX__ should be defined #2"
+#endif
+
+#pragma GCC pop_options
+#ifdef __AVX__
+#error "__AVX__ should not be defined #3"
+#endif
diff --git a/gcc/testsuite/g++.target/i386/pr87299-1.C b/gcc/testsuite/g++.target/i386/pr87299-1.C
new file mode 100644
index 0000000..38d4c3b
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr87299-1.C
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-mno-avx" } */
+
+#pragma GCC target("avx")
+const int x1 = __AVX__;
+
+_Pragma("GCC target(\"avx512f\")")
+const int x2 = __AVX512F__;
diff --git a/gcc/testsuite/g++.target/i386/pr87299-2.C b/gcc/testsuite/g++.target/i386/pr87299-2.C
new file mode 100644
index 0000000..263dfb7
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr87299-2.C
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-save-temps -mno-avx" } */
+
+#pragma GCC target("avx")
+const int x1 = __AVX__;
+
+_Pragma("GCC target(\"avx512f\")")
+const int x2 = __AVX512F__;
diff --git a/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1b.c b/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1b.c
new file mode 100644
index 0000000..65bfab8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1b.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv8-a+crypto -save-temps" } */
+#include "pragma_cpp_predefs_1.c"
diff --git a/gcc/testsuite/gcc.target/arm/pragma_arch_attribute_1b.c b/gcc/testsuite/gcc.target/arm/pragma_arch_attribute_1b.c
new file mode 100644
index 0000000..652d084
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pragma_arch_attribute_1b.c
@@ -0,0 +1,6 @@
+/* Test for #pragma target macros. */
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8a_ok } */
+/* { dg-additional-options "-save-temps" } */
+/* { dg-add-options arm_arch_v8a } */
+#include "pragma_arch_attribute.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr87299-1.c b/gcc/testsuite/gcc.target/i386/pr87299-1.c
new file mode 100644
index 0000000..38d4c3b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr87299-1.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-mno-avx" } */
+
+#pragma GCC target("avx")
+const int x1 = __AVX__;
+
+_Pragma("GCC target(\"avx512f\")")
+const int x2 = __AVX512F__;
diff --git a/gcc/testsuite/gcc.target/i386/pr87299-2.c b/gcc/testsuite/gcc.target/i386/pr87299-2.c
new file mode 100644
index 0000000..263dfb7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr87299-2.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-save-temps -mno-avx" } */
+
+#pragma GCC target("avx")
+const int x1 = __AVX__;
+
+_Pragma("GCC target(\"avx512f\")")
+const int x2 = __AVX512F__;
diff --git a/gcc/testsuite/gcc.target/nios2/custom-fp-2b.c b/gcc/testsuite/gcc.target/nios2/custom-fp-2b.c
new file mode 100644
index 0000000..ce35c63
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nios2/custom-fp-2b.c
@@ -0,0 +1,26 @@
+/* Test specification of custom instructions via pragmas. */
+
+/* { dg-do compile } */
+/* { dg-options "-O1 -ffinite-math-only -save-temps" } */
+
+/* -O1 in the options is significant. Without it FP operations may not be
+ optimized to custom instructions. */
+
+#include <stdio.h>
+#include <math.h>
+
+#pragma GCC target ("custom-fmaxs=246")
+#pragma GCC target ("custom-fmins=247")
+#pragma GCC target ("custom-fsqrts=251")
+
+void
+custom_fp (float operand_a, float operand_b, float *result)
+{
+ result[0] = fmaxf (operand_a, operand_b);
+ result[1] = fminf (operand_a, operand_b);
+ result[2] = sqrtf (operand_a);
+}
+
+/* { dg-final { scan-assembler "custom\\t246, .* # fmaxs .*" } } */
+/* { dg-final { scan-assembler "custom\\t247, .* # fmins .*" } } */
+/* { dg-final { scan-assembler "custom\\t251, .* # fsqrts .*" } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-3b.c b/gcc/testsuite/gcc.target/powerpc/float128-3b.c
new file mode 100644
index 0000000..6b409c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-3b.c
@@ -0,0 +1,4 @@
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-O2 -mvsx -mno-float128 -save-temps" } */
+#include "float128-3.c"
diff --git a/gcc/testsuite/gcc.target/s390/target-attribute/tattr-2b.c b/gcc/testsuite/gcc.target/s390/target-attribute/tattr-2b.c
new file mode 100644
index 0000000..7ae78fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/target-attribute/tattr-2b.c
@@ -0,0 +1,51 @@
+/* Functional tests for the "target" attribute and pragma. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target target_attribute } */
+/* { dg-options "-O3 -march=zEC12 -mno-htm -fno-ipa-icf -save-temps" } */
+
+#pragma GCC target("htm")
+void p1(void)
+{
+#ifndef __HTM__
+#error __HTM__ is not defined
+#endif
+ __builtin_tend ();
+}
+#pragma GCC reset_options
+
+#pragma GCC target("no-htm")
+void p0(void)
+{
+#ifdef __HTM__
+#error __HTM__ is defined
+#endif
+ __builtin_tend (); /* { dg-error "is not supported without '-mhtm'" } */
+}
+#pragma GCC reset_options
+
+__attribute__ ((target("htm")))
+void a1(void)
+{
+#ifdef __HTM__
+#error __HTM__ is defined
+#endif
+ __builtin_tend ();
+}
+
+__attribute__ ((target("no-htm")))
+void a0(void)
+{
+#ifdef __HTM__
+#error __HTM__ is defined
+#endif
+ __builtin_tend (); /* { dg-error "is not supported without '-mhtm'" } */
+}
+
+void htmd(void)
+{
+#ifdef __HTM__
+#error __HTM__ is defined
+#endif
+ __builtin_tend (); /* { dg-error "is not supported without '-mhtm'" } */
+}
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 8af9bf5..9a73489 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -99,7 +99,7 @@ static void general_init (const char *, bool);
static void backend_init (void);
static int lang_dependent_init (const char *);
static void init_asm_output (const char *);
-static void finalize (bool);
+static void finalize ();
static void crash_signal (int) ATTRIBUTE_NORETURN;
static void compile_file (void);
@@ -163,6 +163,7 @@ FILE *aux_info_file;
FILE *callgraph_info_file = NULL;
static bitmap callgraph_info_external_printed;
FILE *stack_usage_file = NULL;
+static bool no_backend = false;
/* The current working directory of a translation. It's generally the
directory from which compilation was initiated, but a preprocessed
@@ -1221,7 +1222,7 @@ parse_alignment_opts (void)
/* Process the options that have been parsed. */
static void
-process_options (bool no_backend)
+process_options ()
{
const char *language_string = lang_hooks.name;
@@ -1871,6 +1872,9 @@ lang_dependent_init (const char *name)
void
target_reinit (void)
{
+ if (no_backend)
+ return;
+
struct rtl_data saved_x_rtl;
rtx *saved_regno_reg_rtx;
tree saved_optimization_current_node;
@@ -1963,7 +1967,7 @@ dump_memory_report (const char *header)
/* Clean up: close opened files, etc. */
static void
-finalize (bool no_backend)
+finalize ()
{
/* Close the dump files. */
if (flag_gen_aux_info)
@@ -2045,7 +2049,7 @@ standard_type_bitsize (int bitsize)
/* Initialize the compiler, and compile the input file. */
static void
-do_compile (bool no_backend)
+do_compile ()
{
/* Don't do any more if an error has already occurred. */
if (!seen_error ())
@@ -2132,7 +2136,7 @@ do_compile (bool no_backend)
timevar_start (TV_PHASE_FINALIZE);
- finalize (no_backend);
+ finalize ();
timevar_stop (TV_PHASE_FINALIZE);
}
@@ -2273,13 +2277,13 @@ toplev::main (int argc, char **argv)
initialization based on the command line options. This hook also
sets the original filename if appropriate (e.g. foo.i -> foo.c)
so we can correctly initialize debug output. */
- bool no_backend = lang_hooks.post_options (&main_input_filename);
+ no_backend = lang_hooks.post_options (&main_input_filename);
- process_options (no_backend);
+ process_options ();
if (m_use_TV_TOTAL)
start_timevars ();
- do_compile (no_backend);
+ do_compile ();
if (flag_self_test && !seen_error ())
{
@@ -2324,6 +2328,7 @@ toplev::main (int argc, char **argv)
void
toplev::finalize (void)
{
+ no_backend = false;
rtl_initialized = false;
this_target_rtl->target_specific_initialized = false;