diff options
author | Lewis Hyatt <lhyatt@gmail.com> | 2023-10-27 04:32:50 -0400 |
---|---|---|
committer | Lewis Hyatt <lhyatt@gmail.com> | 2023-10-27 04:34:15 -0400 |
commit | 8697d3a1dcf32750a3b9dc007586eb5f9ba5f17a (patch) | |
tree | 32f91b14f6c52acaf7c018011614bbd951d7e5e6 /gcc | |
parent | b038e202210eb3e982c2ec802438edd523b47a02 (diff) | |
download | gcc-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.cc | 49 | ||||
-rw-r--r-- | gcc/c-family/c-pragma.h | 2 | ||||
-rw-r--r-- | gcc/cp/parser.cc | 6 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/pragma-target-1.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/pragma-target-2.c | 27 | ||||
-rw-r--r-- | gcc/testsuite/g++.target/i386/pr87299-1.C | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.target/i386/pr87299-2.C | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1b.c | 3 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/arm/pragma_arch_attribute_1b.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr87299-1.c | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr87299-2.c | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/nios2/custom-fp-2b.c | 26 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/float128-3b.c | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/s390/target-attribute/tattr-2b.c | 51 | ||||
-rw-r--r-- | gcc/toplev.cc | 21 |
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; |