ping: [PATCH] preprocessor: c++: Support `#pragma GCC target' macros [PR87299]

Message ID 20231013212840.GA21815@ldh-imac.local
State Accepted
Headers
Series ping: [PATCH] preprocessor: c++: Support `#pragma GCC target' macros [PR87299] |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Lewis Hyatt Oct. 13, 2023, 9:28 p.m. UTC
  On Tue, Sep 12, 2023 at 04:09:21PM -0400, Lewis Hyatt wrote:
> On Tue, Aug 8, 2023 at 5:53 PM Jason Merrill <jason@redhat.com> wrote:
> >
> > On 7/31/23 22:22, Lewis Hyatt via Gcc-patches wrote:
> > > `#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 to some of them, to test that it now works 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-2.c: Add -save-temps to the
> > >       options, to test preprocess-only mode as well.
> > >       * gcc.target/aarch64/pragma_cpp_predefs_1.c: Likewise.
> > >       * gcc.target/arm/pragma_arch_attribute.c: Likewise.
> > >       * gcc.target/nios2/custom-fp-2.c: Likewise.
> > >       * gcc.target/powerpc/float128-3.c: Likewise.
> > > ---
> > >
> > > Notes:
> > >      Hello-
> > >
> > >      This patch fixes the PR by enabling early pragma handling for `#pragma GCC
> > >      target' and related pragmas such as `#pragma GCC push_options'. I did not
> > >      need to touch any target-specific code, however I did need to make a change
> > >      to toplev.cc, affecting all targets, to make it safe to call target_reinit()
> > >      in preprocess-only mode. (Otherwise, it would be necessary to modify the
> > >      implementation of target pragmas in every target, to avoid this code path.)
> > >      That was the only complication I ran into.
> > >
> > >      Regarding testing, I did: (thanks to GCC compile farm for the non-x86
> > >      targets)
> > >
> > >      bootstrap + regtest all languages - x86_64-pc-linux-gnu
> > >      bootstrap + regtest c/c++ - powerpc64le-unknown-linux-gnu,
> > >                                  aarch64-unknown-linux-gnu
> > >
> > >      The following backends also implement this pragma so ought to be tested:
> > >          arm
> > >          nios2
> > >          s390
> > >
> > >      I am not able to test those directly. I did add coverage to their testsuites
> > >      (basically, adding -save-temps to any existing test, causes it to test the
> > >      pragma in preprocess-only mode.) Then, I verified on x86_64 with a cross
> > >      compiler, that the modified testcases fail before the patch and pass
> > >      afterwards. nios2 is an exception, it does not set any libcpp macros when
> > >      handling the pragma, so there is nothing to test, but I did verify that
> > >      processing the pragma in preprocess-only mode does not cause any problems.
> > >      The cross compilers tested were targets arm-unknown-linux-gnueabi,
> > >      nios2-unknown-linux, and s390-ibm-linux.
> > >
> > >      Please let me know if it looks OK? Thanks!
> >
> > The c-family and C++ changes look good.  David, any comments on the
> > toplev changes?
> >
> > Jason
> >
> 
> Thanks for the review! To be clear, I should continue to wait for
> additional feedback on the toplev.cc change, correct?
> I have also implemented Joseph's suggestion, to add new testcases
> rather than modifying existing ones. That's a pretty minor change just
> to the testsuite part so I did not resend the whole patch because of
> it, but I can if needed.
> 
> -Lewis

May I please ping this one again? My understanding is that it's approved
other than the changes to toplev.cc, and Jason suggested that David look
at that. I have attached a rebased patch here as well. Thanks!

-Lewis
From: Lewis Hyatt <lhyatt@gmail.com>
Date: Fri, 13 Oct 2023 14:38:06 -0400
Subject: [PATCH] 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-2.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.
  

Comments

Jason Merrill Oct. 26, 2023, 9:10 p.m. UTC | #1
On 10/13/23 17:28, Lewis Hyatt wrote:
> On Tue, Sep 12, 2023 at 04:09:21PM -0400, Lewis Hyatt wrote:
>> On Tue, Aug 8, 2023 at 5:53 PM Jason Merrill <jason@redhat.com> wrote:
>>>
>>> On 7/31/23 22:22, Lewis Hyatt via Gcc-patches wrote:
>>>> `#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 to some of them, to test that it now works 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-2.c: Add -save-temps to the
>>>>        options, to test preprocess-only mode as well.
>>>>        * gcc.target/aarch64/pragma_cpp_predefs_1.c: Likewise.
>>>>        * gcc.target/arm/pragma_arch_attribute.c: Likewise.
>>>>        * gcc.target/nios2/custom-fp-2.c: Likewise.
>>>>        * gcc.target/powerpc/float128-3.c: Likewise.
>>>> ---
>>>>
>>>> Notes:
>>>>       Hello-
>>>>
>>>>       This patch fixes the PR by enabling early pragma handling for `#pragma GCC
>>>>       target' and related pragmas such as `#pragma GCC push_options'. I did not
>>>>       need to touch any target-specific code, however I did need to make a change
>>>>       to toplev.cc, affecting all targets, to make it safe to call target_reinit()
>>>>       in preprocess-only mode. (Otherwise, it would be necessary to modify the
>>>>       implementation of target pragmas in every target, to avoid this code path.)
>>>>       That was the only complication I ran into.
>>>>
>>>>       Regarding testing, I did: (thanks to GCC compile farm for the non-x86
>>>>       targets)
>>>>
>>>>       bootstrap + regtest all languages - x86_64-pc-linux-gnu
>>>>       bootstrap + regtest c/c++ - powerpc64le-unknown-linux-gnu,
>>>>                                   aarch64-unknown-linux-gnu
>>>>
>>>>       The following backends also implement this pragma so ought to be tested:
>>>>           arm
>>>>           nios2
>>>>           s390
>>>>
>>>>       I am not able to test those directly. I did add coverage to their testsuites
>>>>       (basically, adding -save-temps to any existing test, causes it to test the
>>>>       pragma in preprocess-only mode.) Then, I verified on x86_64 with a cross
>>>>       compiler, that the modified testcases fail before the patch and pass
>>>>       afterwards. nios2 is an exception, it does not set any libcpp macros when
>>>>       handling the pragma, so there is nothing to test, but I did verify that
>>>>       processing the pragma in preprocess-only mode does not cause any problems.
>>>>       The cross compilers tested were targets arm-unknown-linux-gnueabi,
>>>>       nios2-unknown-linux, and s390-ibm-linux.
>>>>
>>>>       Please let me know if it looks OK? Thanks!
>>>
>>> The c-family and C++ changes look good.  David, any comments on the
>>> toplev changes?
>>>
>>> Jason
>>>
>>
>> Thanks for the review! To be clear, I should continue to wait for
>> additional feedback on the toplev.cc change, correct?
>> I have also implemented Joseph's suggestion, to add new testcases
>> rather than modifying existing ones. That's a pretty minor change just
>> to the testsuite part so I did not resend the whole patch because of
>> it, but I can if needed.
>>
>> -Lewis
> 
> May I please ping this one again? My understanding is that it's approved
> other than the changes to toplev.cc, and Jason suggested that David look
> at that. I have attached a rebased patch here as well. Thanks!

Since David hasn't asked for any changes, the patch is OK.

Jason
  

Patch

diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc
index 293311dd4ce..9fb841cd793 100644
--- a/gcc/c-family/c-pragma.cc
+++ b/gcc/c-family/c-pragma.cc
@@ -1288,24 +1288,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);
@@ -1325,6 +1317,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
@@ -1843,11 +1848,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 603c5151978..682157a4517 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 f3abae716fe..d0331a92348 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 00000000000..2584c228318
--- /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 00000000000..e7bf305a0eb
--- /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 00000000000..38d4c3bbc26
--- /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 00000000000..263dfb710a0
--- /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 00000000000..65bfab8740c
--- /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 00000000000..652d084e2e0
--- /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 00000000000..38d4c3bbc26
--- /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 00000000000..263dfb710a0
--- /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 00000000000..ce35c63baa8
--- /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 00000000000..6b409c13d1c
--- /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 00000000000..7ae78fcb9c2
--- /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 8af9bf5090e..9a734890a18 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;