public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r11-3183] options: Save and restore opts_set for Optimization and Target options
@ 2020-09-14  7:06 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2020-09-14  7:06 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:ba948b37768c99cd8eb9f5b6fbd45fcf4bd15b78

commit r11-3183-gba948b37768c99cd8eb9f5b6fbd45fcf4bd15b78
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Mon Sep 14 09:04:45 2020 +0200

    options: Save and restore opts_set for Optimization and Target options
    
    > Seems a latent issue.
    > Neither cl_optimization_{save,restore} nor cl_target_option_{save,restore}
    > (nor any of the target hooks they call) saves or restores any opts_set
    > values, so I think opts_set can be trusted only during option processing (if
    > at all), but not later.
    > So, short term a fix would be IMHO just stop using opts_set altogether in
    > arm_configure_build_target, it doesn't make much sense to me, it should test
    > if those strings are non-NULL instead, or at least do that when it is
    > invoked from arm_option_restore (e.g. could be done by calling it with
    > opts instead of &global_options_set ).
    > Longer term, the question is if cl_optimization_{save,restore} and
    > cl_target_option_{save,restore} shouldn't be changed not to only
    > save/restore the options, but also save the opts_set flags.
    > It could be done e.g. by adding a bool array or set of bool members
    > to struct cl_optimization and struct cl_target_option , or even more compact
    > by using bitmasks, pack each 64 adjacent option flags into a UHWI element
    > of an array.
    
    So, I've tried under debugger how it behaves and seems global_options_set
    is really an or of whether an option has been ever seen as explicit, either
    on the command line or in any of the option pragmas or optimize/target
    attributes seen so far, so it isn't something that can be relied on.
    
    The following patch implements the saving/restoring of the opts_set bits
    (though only for the options/variables saved by the generic options-save.c
    code, for the target specific stuff that isn't handled by the generic code
    the opts_set argument is now passed to the hook and the backends can choose
    e.g. to use a TargetSave variable to save the flags either individually or
    together in some bitmask (or ignore it if they never need opts_set for the
    options).
    
    This patch itself doesn't fix the testcase failing on arm, but a follow up
    patch will.
    
    2020-09-14  Jakub Jelinek  <jakub@redhat.com>
    
    gcc/
            * opt-read.awk: Also initialize extra_target_var_types array.
            * opth-gen.awk: Emit explicit_mask arrays to struct cl_optimization
            and cl_target_option.  Adjust cl_optimization_save,
            cl_optimization_restore, cl_target_option_save and
            cl_target_option_restore declarations.
            * optc-save-gen.awk: Add opts_set argument to cl_optimization_save,
            cl_optimization_restore, cl_target_option_save and
            cl_target_option_restore functions and save or restore opts_set
            next to the opts values into or from explicit_mask arrays.
            In cl_target_option_eq and cl_optimization_option_eq compare
            explicit_mask arrays, in cl_target_option_hash and cl_optimization_hash
            hash them and in cl_target_option_stream_out,
            cl_target_option_stream_in, cl_optimization_stream_out and
            cl_optimization_stream_in stream them.
            * tree.h (build_optimization_node, build_target_option_node): Add
            opts_set argument.
            * tree.c (build_optimization_node): Add opts_set argument, pass it
            to cl_optimization_save.
            (build_target_option_node): Add opts_set argument, pass it to
            cl_target_option_save.
            * function.c (invoke_set_current_function_hook): Adjust
            cl_optimization_restore caller.
            * ipa-inline-transform.c (inline_call): Adjust cl_optimization_restore
            and build_optimization_node callers.
            * target.def (TARGET_OPTION_SAVE, TARGET_OPTION_RESTORE): Add opts_set
            argument.
            * target-globals.c (save_target_globals_default_opts): Adjust
            cl_optimization_restore callers.
            * toplev.c (process_options): Adjust build_optimization_node and
            cl_optimization_restore callers.
            (target_reinit): Adjust cl_optimization_restore caller.
            * tree-streamer-in.c (lto_input_ts_function_decl_tree_pointers):
            Adjust build_optimization_node and cl_optimization_restore callers.
            * doc/tm.texi: Updated.
            * config/aarch64/aarch64.c (aarch64_override_options): Adjust
            build_target_option_node caller.
            (aarch64_option_save, aarch64_option_restore): Add opts_set argument.
            (aarch64_set_current_function): Adjust cl_target_option_restore
            caller.
            (aarch64_option_valid_attribute_p): Adjust cl_target_option_save,
            cl_target_option_restore, cl_optimization_restore,
            build_optimization_node and build_target_option_node callers.
            * config/aarch64/aarch64-c.c (aarch64_pragma_target_parse): Adjust
            cl_target_option_restore and build_target_option_node callers.
            * config/arm/arm.c (arm_option_save, arm_option_restore): Add
            opts_set argument.
            (arm_option_override): Adjust cl_target_option_save,
            build_optimization_node and build_target_option_node callers.
            (arm_set_current_function): Adjust cl_target_option_restore caller.
            (arm_valid_target_attribute_tree): Adjust build_target_option_node
            caller.
            (add_attribute): Formatting fix.
            (arm_valid_target_attribute_p): Adjust cl_optimization_restore,
            cl_target_option_restore, arm_valid_target_attribute_tree and
            build_optimization_node callers.
            * config/arm/arm-c.c (arm_pragma_target_parse): Adjust
            cl_target_option_restore callers.
            * config/csky/csky.c (csky_option_override): Adjust
            build_target_option_node and cl_target_option_save callers.
            * config/gcn/gcn.c (gcn_fixup_accel_lto_options): Adjust
            build_optimization_node and cl_optimization_restore callers.
            * config/i386/i386-builtins.c (get_builtin_code_for_version):
            Adjust cl_target_option_save and cl_target_option_restore
            callers.
            * config/i386/i386-c.c (ix86_pragma_target_parse): Adjust
            build_target_option_node and cl_target_option_restore callers.
            * config/i386/i386-options.c (ix86_function_specific_save,
            ix86_function_specific_restore): Add opts_set arguments.
            (ix86_valid_target_attribute_tree): Adjust build_target_option_node
            caller.
            (ix86_valid_target_attribute_p): Adjust build_optimization_node,
            cl_optimization_restore, cl_target_option_restore,
            ix86_valid_target_attribute_tree and build_optimization_node callers.
            (ix86_option_override_internal): Adjust build_target_option_node
            caller.
            (ix86_reset_previous_fndecl, ix86_set_current_function): Adjust
            cl_target_option_restore callers.
            * config/i386/i386-options.h (ix86_function_specific_save,
            ix86_function_specific_restore): Add opts_set argument.
            * config/nios2/nios2.c (nios2_option_override): Adjust
            build_target_option_node caller.
            (nios2_option_save, nios2_option_restore): Add opts_set argument.
            (nios2_valid_target_attribute_tree): Adjust build_target_option_node
            caller.
            (nios2_valid_target_attribute_p): Adjust build_optimization_node,
            cl_optimization_restore, cl_target_option_save and
            cl_target_option_restore callers.
            (nios2_set_current_function, nios2_pragma_target_parse): Adjust
            cl_target_option_restore callers.
            * config/pru/pru.c (pru_option_override): Adjust
            build_target_option_node caller.
            (pru_set_current_function): Adjust cl_target_option_restore
            callers.
            * config/rs6000/rs6000.c (rs6000_debug_reg_global): Adjust
            cl_target_option_save caller.
            (rs6000_option_override_internal): Adjust build_target_option_node
            caller.
            (rs6000_valid_attribute_p): Adjust build_optimization_node,
            cl_optimization_restore, cl_target_option_save,
            cl_target_option_restore and build_target_option_node callers.
            (rs6000_pragma_target_parse): Adjust cl_target_option_restore and
            build_target_option_node callers.
            (rs6000_activate_target_options): Adjust cl_target_option_restore
            callers.
            (rs6000_function_specific_save, rs6000_function_specific_restore):
            Add opts_set argument.
            * config/s390/s390.c (s390_function_specific_restore): Likewise.
            (s390_option_override_internal): Adjust s390_function_specific_restore
            caller.
            (s390_option_override, s390_valid_target_attribute_tree): Adjust
            build_target_option_node caller.
            (s390_valid_target_attribute_p): Adjust build_optimization_node,
            cl_optimization_restore and cl_target_option_restore callers.
            (s390_activate_target_options): Adjust cl_target_option_restore
            caller.
            * config/s390/s390-c.c (s390_cpu_cpp_builtins): Adjust
            cl_target_option_save caller.
            (s390_pragma_target_parse): Adjust build_target_option_node and
            cl_target_option_restore callers.
    gcc/c-family/
            * c-attribs.c (handle_optimize_attribute): Adjust
            cl_optimization_save, cl_optimization_restore and
            build_optimization_node callers.
            * c-pragma.c (handle_pragma_optimize): Adjust
            build_optimization_node caller.
            (handle_pragma_push_options): Adjust
            build_optimization_node and build_target_option_node callers.
            (handle_pragma_pop_options, handle_pragma_reset_options):
            Adjust cl_optimization_restore callers.
    gcc/go/
            * go-gcc.cc (Gcc_backend::function): Adjust
            cl_optimization_save, cl_optimization_restore and
            build_optimization_node callers.
    gcc/ada/
            * gcc-interface/trans.c (gigi): Adjust build_optimization_node
            caller.

Diff:
---
 gcc/ada/gcc-interface/trans.c   |   3 +-
 gcc/c-family/c-attribs.c        |   9 +-
 gcc/c-family/c-pragma.c         |  13 +-
 gcc/config/aarch64/aarch64-c.c  |   4 +-
 gcc/config/aarch64/aarch64.c    |  36 ++--
 gcc/config/arm/arm-c.c          |   4 +-
 gcc/config/arm/arm.c            |  41 +++--
 gcc/config/csky/csky.c          |   4 +-
 gcc/config/gcn/gcn.c            |  10 +-
 gcc/config/i386/i386-builtins.c |   6 +-
 gcc/config/i386/i386-c.c        |   7 +-
 gcc/config/i386/i386-options.c  |  30 ++--
 gcc/config/i386/i386-options.h  |   4 +-
 gcc/config/nios2/nios2.c        |  27 +--
 gcc/config/pru/pru.c            |   6 +-
 gcc/config/rs6000/rs6000.c      |  36 ++--
 gcc/config/s390/s390-c.c        |   7 +-
 gcc/config/s390/s390.c          |  26 +--
 gcc/doc/tm.texi                 |   4 +-
 gcc/function.c                  |   3 +-
 gcc/go/go-gcc.cc                |   8 +-
 gcc/ipa-inline-transform.c      |  10 +-
 gcc/opt-read.awk                |   1 +
 gcc/optc-save-gen.awk           | 370 ++++++++++++++++++++++++++++++++++++++--
 gcc/opth-gen.awk                |  19 ++-
 gcc/target-globals.c            |   4 +-
 gcc/target.def                  |   6 +-
 gcc/toplev.c                    |   7 +-
 gcc/tree-streamer-in.c          |   9 +-
 gcc/tree.c                      |  14 +-
 gcc/tree.h                      |  12 +-
 31 files changed, 583 insertions(+), 157 deletions(-)

diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 9be12952c5b..3491451cc3d 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -691,7 +691,8 @@ gigi (Node_Id gnat_root,
 
   /* Save the current optimization options again after the above possible
      global_options changes.  */
-  optimization_default_node = build_optimization_node (&global_options);
+  optimization_default_node
+    = build_optimization_node (&global_options, &global_options_set);
   optimization_current_node = optimization_default_node;
 
   /* Now translate the compilation unit proper.  */
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 37214831538..4920725ca2d 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -4448,7 +4448,7 @@ handle_optimize_attribute (tree *node, tree name, tree args,
       tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
 
       /* Save current options.  */
-      cl_optimization_save (&cur_opts, &global_options);
+      cl_optimization_save (&cur_opts, &global_options, &global_options_set);
 
       /* If we previously had some optimization options, use them as the
 	 default.  */
@@ -4460,16 +4460,17 @@ handle_optimize_attribute (tree *node, tree name, tree args,
 	}
 
       if (old_opts)
-	cl_optimization_restore (&global_options,
+	cl_optimization_restore (&global_options, &global_options_set,
 				 TREE_OPTIMIZATION (old_opts));
 
       /* Parse options, and update the vector.  */
       parse_optimize_options (args, true);
       DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
-	= build_optimization_node (&global_options);
+	= build_optimization_node (&global_options, &global_options_set);
 
       /* Restore current options.  */
-      cl_optimization_restore (&global_options, &cur_opts);
+      cl_optimization_restore (&global_options, &global_options_set,
+			       &cur_opts);
       if (saved_global_options != NULL)
 	{
 	  cl_optimization_compare (saved_global_options, &global_options);
diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index e3169e68fb6..dc52ee8b003 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -987,7 +987,8 @@ handle_pragma_optimize (cpp_reader *ARG_UNUSED(dummy))
 
       parse_optimize_options (args, false);
       current_optimize_pragma = chainon (current_optimize_pragma, args);
-      optimization_current_node = build_optimization_node (&global_options);
+      optimization_current_node
+	= build_optimization_node (&global_options, &global_options_set);
       c_cpp_builtins_optimize_pragma (parse_in,
 				      optimization_previous_node,
 				      optimization_current_node);
@@ -1034,8 +1035,10 @@ handle_pragma_push_options (cpp_reader *ARG_UNUSED(dummy))
       p->saved_global_options = XNEW (gcc_options);
       *p->saved_global_options = global_options;
     }
-  p->optimize_binary = build_optimization_node (&global_options);
-  p->target_binary = build_target_option_node (&global_options);
+  p->optimize_binary = build_optimization_node (&global_options,
+						&global_options_set);
+  p->target_binary = build_target_option_node (&global_options,
+					       &global_options_set);
 
   /* Save optimization and target flags in string list format.  */
   p->optimize_strings = copy_list (current_optimize_pragma);
@@ -1079,7 +1082,7 @@ handle_pragma_pop_options (cpp_reader *ARG_UNUSED(dummy))
   if (p->optimize_binary != optimization_current_node)
     {
       tree old_optimize = optimization_current_node;
-      cl_optimization_restore (&global_options,
+      cl_optimization_restore (&global_options, &global_options_set,
 			       TREE_OPTIMIZATION (p->optimize_binary));
       c_cpp_builtins_optimize_pragma (parse_in, old_optimize,
 				      p->optimize_binary);
@@ -1122,7 +1125,7 @@ handle_pragma_reset_options (cpp_reader *ARG_UNUSED(dummy))
   if (new_optimize != optimization_current_node)
     {
       tree old_optimize = optimization_current_node;
-      cl_optimization_restore (&global_options,
+      cl_optimization_restore (&global_options, &global_options_set,
 			       TREE_OPTIMIZATION (new_optimize));
       c_cpp_builtins_optimize_pragma (parse_in, old_optimize, new_optimize);
       optimization_current_node = new_optimize;
diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c
index 69691b3ad72..5e23328608b 100644
--- a/gcc/config/aarch64/aarch64-c.c
+++ b/gcc/config/aarch64/aarch64-c.c
@@ -242,12 +242,12 @@ aarch64_pragma_target_parse (tree args, tree pop_target)
   else
     {
       pop_target = pop_target ? pop_target : target_option_default_node;
-      cl_target_option_restore (&global_options,
+      cl_target_option_restore (&global_options, &global_options_set,
 				TREE_TARGET_OPTION (pop_target));
     }
 
   target_option_current_node
-    = build_target_option_node (&global_options);
+    = build_target_option_node (&global_options, &global_options_set);
 
   aarch64_reset_previous_fndecl ();
   /* For the definitions, ensure all newly defined macros are considered
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index b6d74496cd0..b251f3947e2 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -15034,7 +15034,7 @@ aarch64_override_options (void)
   /* Save these options as the default ones in case we push and pop them later
      while processing functions with potential target attributes.  */
   target_option_default_node = target_option_current_node
-      = build_target_option_node (&global_options);
+    = build_target_option_node (&global_options, &global_options_set);
 }
 
 /* Implement targetm.override_options_after_change.  */
@@ -15109,7 +15109,8 @@ initialize_aarch64_code_model (struct gcc_options *opts)
 /* Implement TARGET_OPTION_SAVE.  */
 
 static void
-aarch64_option_save (struct cl_target_option *ptr, struct gcc_options *opts)
+aarch64_option_save (struct cl_target_option *ptr, struct gcc_options *opts,
+		     struct gcc_options */* opts_set */)
 {
   ptr->x_aarch64_override_tune_string = opts->x_aarch64_override_tune_string;
   ptr->x_aarch64_branch_protection_string
@@ -15120,7 +15121,9 @@ aarch64_option_save (struct cl_target_option *ptr, struct gcc_options *opts)
    using the information saved in PTR.  */
 
 static void
-aarch64_option_restore (struct gcc_options *opts, struct cl_target_option *ptr)
+aarch64_option_restore (struct gcc_options *opts,
+			struct gcc_options */* opts_set */,
+			struct cl_target_option *ptr)
 {
   opts->x_explicit_tune_core = ptr->x_explicit_tune_core;
   selected_tune = aarch64_get_tune_cpu (ptr->x_explicit_tune_core);
@@ -15210,7 +15213,8 @@ aarch64_set_current_function (tree fndecl)
   aarch64_previous_fndecl = fndecl;
 
   /* First set the target options.  */
-  cl_target_option_restore (&global_options, TREE_TARGET_OPTION (new_tree));
+  cl_target_option_restore (&global_options, &global_options_set,
+			    TREE_TARGET_OPTION (new_tree));
 
   aarch64_save_restore_target_globals (new_tree);
 }
@@ -15709,17 +15713,18 @@ aarch64_option_valid_attribute_p (tree fndecl, tree, tree args, int)
     }
   tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
 
-  old_optimize = build_optimization_node (&global_options);
+  old_optimize
+    = build_optimization_node (&global_options, &global_options_set);
   func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
 
   /* If the function changed the optimization levels as well as setting
      target options, start with the optimizations specified.  */
   if (func_optimize && func_optimize != old_optimize)
-    cl_optimization_restore (&global_options,
+    cl_optimization_restore (&global_options, &global_options_set,
 			     TREE_OPTIMIZATION (func_optimize));
 
   /* Save the current target options to restore at the end.  */
-  cl_target_option_save (&cur_target, &global_options);
+  cl_target_option_save (&cur_target, &global_options, &global_options_set);
 
   /* If fndecl already has some target attributes applied to it, unpack
      them so that we add this attribute on top of them, rather than
@@ -15730,11 +15735,12 @@ aarch64_option_valid_attribute_p (tree fndecl, tree, tree args, int)
 	= TREE_TARGET_OPTION (existing_target);
 
       if (existing_options)
-	cl_target_option_restore (&global_options, existing_options);
+	cl_target_option_restore (&global_options, &global_options_set,
+				  existing_options);
     }
   else
-    cl_target_option_restore (&global_options,
-			TREE_TARGET_OPTION (target_option_current_node));
+    cl_target_option_restore (&global_options, &global_options_set,
+			      TREE_TARGET_OPTION (target_option_current_node));
 
   ret = aarch64_process_target_attr (args);
 
@@ -15754,12 +15760,14 @@ aarch64_option_valid_attribute_p (tree fndecl, tree, tree args, int)
 	  aarch64_init_simd_builtins ();
 	  current_target_pragma = saved_current_target_pragma;
 	}
-      new_target = build_target_option_node (&global_options);
+      new_target = build_target_option_node (&global_options,
+					     &global_options_set);
     }
   else
     new_target = NULL;
 
-  new_optimize = build_optimization_node (&global_options);
+  new_optimize = build_optimization_node (&global_options,
+					  &global_options_set);
 
   if (fndecl && ret)
     {
@@ -15769,10 +15777,10 @@ aarch64_option_valid_attribute_p (tree fndecl, tree, tree args, int)
 	DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
     }
 
-  cl_target_option_restore (&global_options, &cur_target);
+  cl_target_option_restore (&global_options, &global_options_set, &cur_target);
 
   if (old_optimize != new_optimize)
-    cl_optimization_restore (&global_options,
+    cl_optimization_restore (&global_options, &global_options_set,
 			     TREE_OPTIMIZATION (old_optimize));
   return ret;
 }
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index 7468a20bd98..899b890d7a3 100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -390,7 +390,7 @@ arm_pragma_target_parse (tree args, tree pop_target)
   if (! args)
     {
       cur_tree = ((pop_target) ? pop_target : target_option_default_node);
-      cl_target_option_restore (&global_options,
+      cl_target_option_restore (&global_options, &global_options_set,
 				TREE_TARGET_OPTION (cur_tree));
     }
   else
@@ -399,7 +399,7 @@ arm_pragma_target_parse (tree args, tree pop_target)
 						  &global_options_set);
       if (cur_tree == NULL_TREE)
 	{
-	  cl_target_option_restore (&global_options,
+	  cl_target_option_restore (&global_options, &global_options_set,
 				    TREE_TARGET_OPTION (prev_tree));
 	  return false;
 	}
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index bae8791dd9a..f4f32b66a3b 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -247,8 +247,9 @@ static tree arm_build_builtin_va_list (void);
 static void arm_expand_builtin_va_start (tree, rtx);
 static tree arm_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
 static void arm_option_override (void);
-static void arm_option_save (struct cl_target_option *, struct gcc_options *);
-static void arm_option_restore (struct gcc_options *,
+static void arm_option_save (struct cl_target_option *, struct gcc_options *,
+			     struct gcc_options *);
+static void arm_option_restore (struct gcc_options *, struct gcc_options *,
 				struct cl_target_option *);
 static void arm_override_options_after_change (void);
 static void arm_option_print (FILE *, int, struct cl_target_option *);
@@ -3043,7 +3044,8 @@ arm_override_options_after_change (void)
 
 /* Implement TARGET_OPTION_SAVE.  */
 static void
-arm_option_save (struct cl_target_option *ptr, struct gcc_options *opts)
+arm_option_save (struct cl_target_option *ptr, struct gcc_options *opts,
+		 struct gcc_options */* opts_set */)
 {
   ptr->x_arm_arch_string = opts->x_arm_arch_string;
   ptr->x_arm_cpu_string = opts->x_arm_cpu_string;
@@ -3052,13 +3054,13 @@ arm_option_save (struct cl_target_option *ptr, struct gcc_options *opts)
 
 /* Implement TARGET_OPTION_RESTORE.  */
 static void
-arm_option_restore (struct gcc_options *opts, struct cl_target_option *ptr)
+arm_option_restore (struct gcc_options *opts, struct gcc_options *opts_set,
+		    struct cl_target_option *ptr)
 {
   opts->x_arm_arch_string = ptr->x_arm_arch_string;
   opts->x_arm_cpu_string = ptr->x_arm_cpu_string;
   opts->x_arm_tune_string = ptr->x_arm_tune_string;
-  arm_configure_build_target (&arm_active_target, ptr, &global_options_set,
-			      false);
+  arm_configure_build_target (&arm_active_target, ptr, opts_set, false);
 }
 
 /* Reset options between modes that the user has specified.  */
@@ -3457,7 +3459,7 @@ arm_option_override (void)
       arm_fpu_index = (enum fpu_type) fpu_index;
     }
 
-  cl_target_option_save (&opts, &global_options);
+  cl_target_option_save (&opts, &global_options, &global_options_set);
   arm_configure_build_target (&arm_active_target, &opts, &global_options_set,
 			      true);
 
@@ -3682,7 +3684,8 @@ arm_option_override (void)
     flag_schedule_fusion = 0;
 
   /* Need to remember initial options before they are overriden.  */
-  init_optimize = build_optimization_node (&global_options);
+  init_optimize = build_optimization_node (&global_options,
+					   &global_options_set);
 
   arm_options_perform_arch_sanity_checks ();
   arm_option_override_internal (&global_options, &global_options_set);
@@ -3691,7 +3694,7 @@ arm_option_override (void)
 
   /* Create the default target_options structure.  */
   target_option_default_node = target_option_current_node
-    = build_target_option_node (&global_options);
+    = build_target_option_node (&global_options, &global_options_set);
 
   /* Register global variables with the garbage collector.  */
   arm_add_gc_roots ();
@@ -32332,7 +32335,8 @@ arm_set_current_function (tree fndecl)
   arm_previous_fndecl = fndecl;
 
   /* First set the target options.  */
-  cl_target_option_restore (&global_options, TREE_TARGET_OPTION (new_tree));
+  cl_target_option_restore (&global_options, &global_options_set,
+			    TREE_TARGET_OPTION (new_tree));
 
   save_restore_target_globals (new_tree);
 
@@ -32534,7 +32538,7 @@ arm_valid_target_attribute_tree (tree args, struct gcc_options *opts,
   if (!arm_valid_target_attribute_rec (args, opts))
     return NULL_TREE;
 
-  cl_target_option_save (&cl_opts, opts);
+  cl_target_option_save (&cl_opts, opts, opts_set);
   arm_configure_build_target (&arm_active_target, &cl_opts, opts_set, false);
   arm_option_check_internal (opts);
   /* Do any overrides, such as global options arch=xxx.
@@ -32543,11 +32547,11 @@ arm_valid_target_attribute_tree (tree args, struct gcc_options *opts,
   arm_options_perform_arch_sanity_checks ();
   arm_option_override_internal (opts, opts_set);
 
-  return build_target_option_node (opts);
+  return build_target_option_node (opts, opts_set);
 }
 
 static void 
-add_attribute  (const char * mode, tree *attributes)
+add_attribute (const char * mode, tree *attributes)
 {
   size_t len = strlen (mode);
   tree value = build_string (len, mode);
@@ -32599,7 +32603,7 @@ arm_valid_target_attribute_p (tree fndecl, tree ARG_UNUSED (name),
 			      tree args, int ARG_UNUSED (flags))
 {
   bool ret = true;
-  struct gcc_options func_options;
+  struct gcc_options func_options, func_options_set;
   tree cur_tree, new_optimize;
   gcc_assert ((fndecl != NULL_TREE) && (args != NULL_TREE));
 
@@ -32615,22 +32619,23 @@ arm_valid_target_attribute_p (tree fndecl, tree ARG_UNUSED (name),
   memset (&func_options, 0, sizeof (func_options));
   init_options_struct (&func_options, NULL);
   lang_hooks.init_options_struct (&func_options);
+  memset (&func_options_set, 0, sizeof (func_options_set));
 
   /* Initialize func_options to the defaults.  */
-  cl_optimization_restore (&func_options,
+  cl_optimization_restore (&func_options, &func_options_set,
 			   TREE_OPTIMIZATION (func_optimize));
 
-  cl_target_option_restore (&func_options,
+  cl_target_option_restore (&func_options, &func_options_set,
 			    TREE_TARGET_OPTION (target_option_default_node));
 
   /* Set func_options flags with new target mode.  */
   cur_tree = arm_valid_target_attribute_tree (args, &func_options,
-					      &global_options_set);
+					      &func_options_set);
 
   if (cur_tree == NULL_TREE)
     ret = false;
 
-  new_optimize = build_optimization_node (&func_options);
+  new_optimize = build_optimization_node (&func_options, &func_options_set);
 
   DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = cur_tree;
 
diff --git a/gcc/config/csky/csky.c b/gcc/config/csky/csky.c
index 7ba3ed3e74e..aa05365162a 100644
--- a/gcc/config/csky/csky.c
+++ b/gcc/config/csky/csky.c
@@ -2435,7 +2435,7 @@ csky_option_override (void)
   /* Create the default target_options structure.  We need this early
      to configure the overall build target.  */
   target_option_default_node = target_option_current_node
-			     = build_target_option_node (&global_options);
+    = build_target_option_node (&global_options, &global_options_set);
 
   csky_configure_build_target (&csky_active_target,
 			      TREE_TARGET_OPTION (target_option_default_node),
@@ -2600,7 +2600,7 @@ csky_option_override (void)
 
   /* Resynchronize the saved target options.  */
   cl_target_option_save (TREE_TARGET_OPTION (target_option_default_node),
-			 &global_options);
+			 &global_options, &global_options_set);
 
 #ifdef ENABLE_TPF_DEBUG
   /* Don't emit DWARF4 unless specifically selected.  The TPF
diff --git a/gcc/config/gcn/gcn.c b/gcc/config/gcn/gcn.c
index 84d1fd9a354..e868a8d9ae4 100644
--- a/gcc/config/gcn/gcn.c
+++ b/gcc/config/gcn/gcn.c
@@ -4975,26 +4975,28 @@ gcn_fixup_accel_lto_options (tree fndecl)
   if (!func_optimize)
     return;
 
-  tree old_optimize = build_optimization_node (&global_options);
+  tree old_optimize
+    = build_optimization_node (&global_options, &global_options_set);
   tree new_optimize;
 
   /* If the function changed the optimization levels as well as
      setting target options, start with the optimizations
      specified.  */
   if (func_optimize != old_optimize)
-    cl_optimization_restore (&global_options,
+    cl_optimization_restore (&global_options, &global_options_set,
 			     TREE_OPTIMIZATION (func_optimize));
 
   gcn_option_override ();
 
   /* The target attributes may also change some optimization flags,
      so update the optimization options if necessary.  */
-  new_optimize = build_optimization_node (&global_options);
+  new_optimize = build_optimization_node (&global_options,
+					  &global_options_set);
 
   if (old_optimize != new_optimize)
     {
       DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
-      cl_optimization_restore (&global_options,
+      cl_optimization_restore (&global_options, &global_options_set,
 			       TREE_OPTIMIZATION (old_optimize));
     }
 }
diff --git a/gcc/config/i386/i386-builtins.c b/gcc/config/i386/i386-builtins.c
index 834438a6666..ca7a870896b 100644
--- a/gcc/config/i386/i386-builtins.c
+++ b/gcc/config/i386/i386-builtins.c
@@ -1866,7 +1866,8 @@ get_builtin_code_for_version (tree decl, tree *predicate_list)
      before the ssse3 version. */
   if (strstr (attrs_str, "arch=") != NULL)
     {
-      cl_target_option_save (&cur_target, &global_options);
+      cl_target_option_save (&cur_target, &global_options,
+			     &global_options_set);
       target_node
 	= ix86_valid_target_attribute_tree (decl, attrs, &global_options,
 					    &global_options_set, 0);
@@ -1935,7 +1936,8 @@ get_builtin_code_for_version (tree decl, tree *predicate_list)
 	      break;
 	    }
 
-      cl_target_option_restore (&global_options, &cur_target);
+      cl_target_option_restore (&global_options, &global_options_set,
+				&cur_target);
 	
       if (predicate_list && arg_str == NULL)
 	{
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 2d61a0ce70a..3553a372427 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -603,7 +603,8 @@ ix86_target_macros_internal (HOST_WIDE_INT isa_flag,
 static bool
 ix86_pragma_target_parse (tree args, tree pop_target)
 {
-  tree prev_tree = build_target_option_node (&global_options);
+  tree prev_tree
+    = build_target_option_node (&global_options, &global_options_set);
   tree cur_tree;
   struct cl_target_option *prev_opt;
   struct cl_target_option *cur_opt;
@@ -621,7 +622,7 @@ ix86_pragma_target_parse (tree args, tree pop_target)
   if (! args)
     {
       cur_tree = (pop_target ? pop_target : target_option_default_node);
-      cl_target_option_restore (&global_options,
+      cl_target_option_restore (&global_options, &global_options_set,
 				TREE_TARGET_OPTION (cur_tree));
     }
   else
@@ -631,7 +632,7 @@ ix86_pragma_target_parse (tree args, tree pop_target)
 						   &global_options_set, 0);
       if (!cur_tree || cur_tree == error_mark_node)
        {
-         cl_target_option_restore (&global_options,
+         cl_target_option_restore (&global_options, &global_options_set,
                                    TREE_TARGET_OPTION (prev_tree));
          return false;
        }
diff --git a/gcc/config/i386/i386-options.c b/gcc/config/i386/i386-options.c
index b93c338346f..2fabd200298 100644
--- a/gcc/config/i386/i386-options.c
+++ b/gcc/config/i386/i386-options.c
@@ -627,7 +627,8 @@ ix86_debug_options (void)
 
 void
 ix86_function_specific_save (struct cl_target_option *ptr,
-			     struct gcc_options *opts)
+			     struct gcc_options *opts,
+			     struct gcc_options */* opts_set */)
 {
   ptr->arch = ix86_arch;
   ptr->schedule = ix86_schedule;
@@ -754,6 +755,7 @@ set_ix86_tune_features (struct gcc_options *opts,
 
 void
 ix86_function_specific_restore (struct gcc_options *opts,
+				struct gcc_options */* opts_set */,
 				struct cl_target_option *ptr)
 {
   enum processor_type old_tune = ix86_tune;
@@ -1356,7 +1358,7 @@ ix86_valid_target_attribute_tree (tree fndecl, tree args,
 
       /* Save the current options unless we are validating options for
 	 #pragma.  */
-      t = build_target_option_node (opts);
+      t = build_target_option_node (opts, opts_set);
 
       opts->x_ix86_arch_string = orig_arch_string;
       opts->x_ix86_tune_string = orig_tune_string;
@@ -1377,7 +1379,7 @@ ix86_valid_target_attribute_p (tree fndecl,
 			       tree args,
 			       int flags)
 {
-  struct gcc_options func_options;
+  struct gcc_options func_options, func_options_set;
   tree new_target, new_optimize;
   bool ret = true;
 
@@ -1389,7 +1391,8 @@ ix86_valid_target_attribute_p (tree fndecl,
       && strcmp (TREE_STRING_POINTER (TREE_VALUE (args)), "default") == 0)
     return true;
 
-  tree old_optimize = build_optimization_node (&global_options);
+  tree old_optimize = build_optimization_node (&global_options,
+					       &global_options_set);
 
   /* Get the optimization options of the current function.  */  
   tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
@@ -1401,21 +1404,22 @@ ix86_valid_target_attribute_p (tree fndecl,
   memset (&func_options, 0, sizeof (func_options));
   init_options_struct (&func_options, NULL);
   lang_hooks.init_options_struct (&func_options);
- 
-  cl_optimization_restore (&func_options,
+  memset (&func_options_set, 0, sizeof (func_options_set));
+
+  cl_optimization_restore (&func_options, &func_options_set,
 			   TREE_OPTIMIZATION (func_optimize));
 
   /* Initialize func_options to the default before its target options can
      be set.  */
-  cl_target_option_restore (&func_options,
+  cl_target_option_restore (&func_options, &func_options_set,
 			    TREE_TARGET_OPTION (target_option_default_node));
 
   /* FLAGS == 1 is used for target_clones attribute.  */
   new_target
     = ix86_valid_target_attribute_tree (fndecl, args, &func_options,
-					&global_options_set, flags == 1);
+					&func_options_set, flags == 1);
 
-  new_optimize = build_optimization_node (&func_options);
+  new_optimize = build_optimization_node (&func_options, &func_options_set);
 
   if (new_target == error_mark_node)
     ret = false;
@@ -2954,7 +2958,7 @@ ix86_option_override_internal (bool main_args_p,
      options.  */
   if (main_args_p)
     target_option_default_node = target_option_current_node
-      = build_target_option_node (opts);
+      = build_target_option_node (opts, opts_set);
 
   if (opts->x_flag_cf_protection != CF_NONE)
     opts->x_flag_cf_protection
@@ -2991,7 +2995,8 @@ void
 ix86_reset_previous_fndecl (void)
 {
   tree new_tree = target_option_current_node;
-  cl_target_option_restore (&global_options, TREE_TARGET_OPTION (new_tree));
+  cl_target_option_restore (&global_options, &global_options_set,
+			    TREE_TARGET_OPTION (new_tree));
   if (TREE_TARGET_GLOBALS (new_tree))
     restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
   else if (new_tree == target_option_default_node)
@@ -3250,7 +3255,8 @@ ix86_set_current_function (tree fndecl)
 
   if (old_tree != new_tree)
     {
-      cl_target_option_restore (&global_options, TREE_TARGET_OPTION (new_tree));
+      cl_target_option_restore (&global_options, &global_options_set,
+				TREE_TARGET_OPTION (new_tree));
       if (TREE_TARGET_GLOBALS (new_tree))
 	restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
       else if (new_tree == target_option_default_node)
diff --git a/gcc/config/i386/i386-options.h b/gcc/config/i386/i386-options.h
index 646d3d55515..9172936bbea 100644
--- a/gcc/config/i386/i386-options.h
+++ b/gcc/config/i386/i386-options.h
@@ -70,8 +70,10 @@ extern const char *stringop_alg_names[];
 
 void ix86_add_new_builtins (HOST_WIDE_INT isa, HOST_WIDE_INT isa2);
 void ix86_function_specific_save (struct cl_target_option *,
-				  struct gcc_options *opts);
+				  struct gcc_options *opts,
+				  struct gcc_options *opts_set);
 void ix86_function_specific_restore (struct gcc_options *opts,
+				     struct gcc_options *opts_set,
 				     struct cl_target_option *);
 void ix86_function_specific_post_stream_in (struct cl_target_option *);
 void ix86_function_specific_print (FILE *, int,
diff --git a/gcc/config/nios2/nios2.c b/gcc/config/nios2/nios2.c
index ba0a0a9ba43..55664358ba4 100644
--- a/gcc/config/nios2/nios2.c
+++ b/gcc/config/nios2/nios2.c
@@ -1448,7 +1448,7 @@ nios2_option_override (void)
   /* Save the initial options in case the user does function specific
      options.  */
   target_option_default_node = target_option_current_node
-    = build_target_option_node (&global_options);
+    = build_target_option_node (&global_options, &global_options_set);
 }
 
 \f
@@ -4137,7 +4137,8 @@ nios2_deregister_custom_code (unsigned int N)
 
 static void
 nios2_option_save (struct cl_target_option *ptr,
-		   struct gcc_options *opts ATTRIBUTE_UNUSED)
+		   struct gcc_options *opts ATTRIBUTE_UNUSED,
+		   struct gcc_options *opts_set ATTRIBUTE_UNUSED)
 {
   unsigned int i;
   for (i = 0; i < ARRAY_SIZE (nios2_fpu_insn); i++)
@@ -4150,6 +4151,7 @@ nios2_option_save (struct cl_target_option *ptr,
 
 static void
 nios2_option_restore (struct gcc_options *opts ATTRIBUTE_UNUSED,
+		      struct gcc_options *opts_set ATTRIBUTE_UNUSED,
 		      struct cl_target_option *ptr)
 {
   unsigned int i;
@@ -4310,7 +4312,7 @@ nios2_valid_target_attribute_tree (tree args)
   if (!nios2_valid_target_attribute_rec (args))
     return NULL_TREE;
   nios2_custom_check_insns ();
-  return build_target_option_node (&global_options);
+  return build_target_option_node (&global_options, &global_options_set);
 }
 
 /* Hook to validate attribute((target("string"))).  */
@@ -4321,21 +4323,22 @@ nios2_valid_target_attribute_p (tree fndecl, tree ARG_UNUSED (name),
 {
   struct cl_target_option cur_target;
   bool ret = true;
-  tree old_optimize = build_optimization_node (&global_options);
+  tree old_optimize
+    = build_optimization_node (&global_options, &global_options_set);
   tree new_target, new_optimize;
   tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
 
   /* If the function changed the optimization levels as well as setting target
      options, start with the optimizations specified.  */
   if (func_optimize && func_optimize != old_optimize)
-    cl_optimization_restore (&global_options,
+    cl_optimization_restore (&global_options, &global_options_set,
 			     TREE_OPTIMIZATION (func_optimize));
 
   /* The target attributes may also change some optimization flags, so update
      the optimization options if necessary.  */
-  cl_target_option_save (&cur_target, &global_options);
+  cl_target_option_save (&cur_target, &global_options, &global_options_set);
   new_target = nios2_valid_target_attribute_tree (args);
-  new_optimize = build_optimization_node (&global_options);
+  new_optimize = build_optimization_node (&global_options, &global_options_set);
 
   if (!new_target)
     ret = false;
@@ -4348,10 +4351,10 @@ nios2_valid_target_attribute_p (tree fndecl, tree ARG_UNUSED (name),
 	DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
     }
 
-  cl_target_option_restore (&global_options, &cur_target);
+  cl_target_option_restore (&global_options, &global_options_set, &cur_target);
 
   if (old_optimize != new_optimize)
-    cl_optimization_restore (&global_options,
+    cl_optimization_restore (&global_options, &global_options_set,
 			     TREE_OPTIMIZATION (old_optimize));
   return ret;
 }
@@ -4381,7 +4384,7 @@ nios2_set_current_function (tree fndecl)
 
       else if (new_tree)
 	{
-	  cl_target_option_restore (&global_options,
+	  cl_target_option_restore (&global_options, &global_options_set,
 				    TREE_TARGET_OPTION (new_tree));
 	  target_reinit ();
 	}
@@ -4391,7 +4394,7 @@ nios2_set_current_function (tree fndecl)
 	  struct cl_target_option *def
 	    = TREE_TARGET_OPTION (target_option_current_node);
 
-	  cl_target_option_restore (&global_options, def);
+	  cl_target_option_restore (&global_options, &global_options_set, def);
 	  target_reinit ();
 	}
     }
@@ -4409,7 +4412,7 @@ nios2_pragma_target_parse (tree args, tree pop_target)
       cur_tree = ((pop_target)
 		  ? pop_target
 		  : target_option_default_node);
-      cl_target_option_restore (&global_options,
+      cl_target_option_restore (&global_options, &global_options_set,
 				TREE_TARGET_OPTION (cur_tree));
     }
   else
diff --git a/gcc/config/pru/pru.c b/gcc/config/pru/pru.c
index a715f6b07ce..39104e5f9cd 100644
--- a/gcc/config/pru/pru.c
+++ b/gcc/config/pru/pru.c
@@ -621,7 +621,7 @@ pru_option_override (void)
   /* Save the initial options in case the user does function specific
      options.  */
   target_option_default_node = target_option_current_node
-    = build_target_option_node (&global_options);
+    = build_target_option_node (&global_options, &global_options_set);
 
   /* Due to difficulties in implementing the TI ABI with GCC,
      at least check and error-out if GCC cannot compile a
@@ -2848,7 +2848,7 @@ pru_set_current_function (tree fndecl)
 
       else if (new_tree)
 	{
-	  cl_target_option_restore (&global_options,
+	  cl_target_option_restore (&global_options, &global_options_set,
 				    TREE_TARGET_OPTION (new_tree));
 	  target_reinit ();
 	}
@@ -2858,7 +2858,7 @@ pru_set_current_function (tree fndecl)
 	  struct cl_target_option *def
 	    = TREE_TARGET_OPTION (target_option_current_node);
 
-	  cl_target_option_restore (&global_options, def);
+	  cl_target_option_restore (&global_options, &global_options_set, def);
 	  target_reinit ();
 	}
     }
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 20a4ba382bc..abbcc50e104 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -2393,7 +2393,7 @@ rs6000_debug_reg_global (void)
   else
     fprintf (stderr, DEBUG_FMT_S, "tune", "<none>");
 
-  cl_target_option_save (&cl_opts, &global_options);
+  cl_target_option_save (&cl_opts, &global_options, &global_options_set);
   rs6000_print_isa_options (stderr, 0, "rs6000_isa_flags",
 			    rs6000_isa_flags);
 
@@ -4769,7 +4769,7 @@ rs6000_option_override_internal (bool global_init_p)
   /* Save the initial options in case the user does function specific options */
   if (global_init_p)
     target_option_default_node = target_option_current_node
-      = build_target_option_node (&global_options);
+      = build_target_option_node (&global_options, &global_options_set);
 
   /* If not explicitly specified via option, decide whether to generate the
      extra blr's required to preserve the link stack on some cpus (eg, 476).  */
@@ -23662,18 +23662,19 @@ rs6000_valid_attribute_p (tree fndecl,
       && strcmp (TREE_STRING_POINTER (TREE_VALUE (args)), "default") == 0)
     return true;
 
-  old_optimize = build_optimization_node (&global_options);
+  old_optimize = build_optimization_node (&global_options,
+					  &global_options_set);
   func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
 
   /* If the function changed the optimization levels as well as setting target
      options, start with the optimizations specified.  */
   if (func_optimize && func_optimize != old_optimize)
-    cl_optimization_restore (&global_options,
+    cl_optimization_restore (&global_options, &global_options_set,
 			     TREE_OPTIMIZATION (func_optimize));
 
   /* The target attributes may also change some optimization flags, so update
      the optimization options if necessary.  */
-  cl_target_option_save (&cur_target, &global_options);
+  cl_target_option_save (&cur_target, &global_options, &global_options_set);
   rs6000_cpu_index = rs6000_tune_index = -1;
   ret = rs6000_inner_target_options (args, true);
 
@@ -23681,12 +23682,14 @@ rs6000_valid_attribute_p (tree fndecl,
   if (ret)
     {
       ret = rs6000_option_override_internal (false);
-      new_target = build_target_option_node (&global_options);
+      new_target = build_target_option_node (&global_options,
+					     &global_options_set);
     }
   else
     new_target = NULL;
 
-  new_optimize = build_optimization_node (&global_options);
+  new_optimize = build_optimization_node (&global_options,
+					  &global_options_set);
 
   if (!new_target)
     ret = false;
@@ -23699,10 +23702,10 @@ rs6000_valid_attribute_p (tree fndecl,
 	DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
     }
 
-  cl_target_option_restore (&global_options, &cur_target);
+  cl_target_option_restore (&global_options, &global_options_set, &cur_target);
 
   if (old_optimize != new_optimize)
-    cl_optimization_restore (&global_options,
+    cl_optimization_restore (&global_options, &global_options_set,
 			     TREE_OPTIMIZATION (old_optimize));
 
   return ret;
@@ -23716,7 +23719,8 @@ rs6000_valid_attribute_p (tree fndecl,
 bool
 rs6000_pragma_target_parse (tree args, tree pop_target)
 {
-  tree prev_tree = build_target_option_node (&global_options);
+  tree prev_tree = build_target_option_node (&global_options,
+					     &global_options_set);
   tree cur_tree;
   struct cl_target_option *prev_opt, *cur_opt;
   HOST_WIDE_INT prev_flags, cur_flags, diff_flags;
@@ -23745,7 +23749,7 @@ rs6000_pragma_target_parse (tree args, tree pop_target)
       cur_tree = ((pop_target)
 		  ? pop_target
 		  : target_option_default_node);
-      cl_target_option_restore (&global_options,
+      cl_target_option_restore (&global_options, &global_options_set,
 				TREE_TARGET_OPTION (cur_tree));
     }
   else
@@ -23753,7 +23757,8 @@ rs6000_pragma_target_parse (tree args, tree pop_target)
       rs6000_cpu_index = rs6000_tune_index = -1;
       if (!rs6000_inner_target_options (args, false)
 	  || !rs6000_option_override_internal (false)
-	  || (cur_tree = build_target_option_node (&global_options))
+	  || (cur_tree = build_target_option_node (&global_options,
+						   &global_options_set))
 	     == NULL_TREE)
 	{
 	  if (TARGET_DEBUG_BUILTIN || TARGET_DEBUG_TARGET)
@@ -23808,7 +23813,8 @@ static GTY(()) tree rs6000_previous_fndecl;
 void
 rs6000_activate_target_options (tree new_tree)
 {
-  cl_target_option_restore (&global_options, TREE_TARGET_OPTION (new_tree));
+  cl_target_option_restore (&global_options, &global_options_set,
+			    TREE_TARGET_OPTION (new_tree));
   if (TREE_TARGET_GLOBALS (new_tree))
     restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
   else if (new_tree == target_option_default_node)
@@ -23899,7 +23905,8 @@ rs6000_set_current_function (tree fndecl)
 
 static void
 rs6000_function_specific_save (struct cl_target_option *ptr,
-			       struct gcc_options *opts)
+			       struct gcc_options *opts,
+			       struct gcc_options */* opts_set */)
 {
   ptr->x_rs6000_isa_flags = opts->x_rs6000_isa_flags;
   ptr->x_rs6000_isa_flags_explicit = opts->x_rs6000_isa_flags_explicit;
@@ -23909,6 +23916,7 @@ rs6000_function_specific_save (struct cl_target_option *ptr,
 
 static void
 rs6000_function_specific_restore (struct gcc_options *opts,
+				  struct gcc_options */* opts_set */,
 				  struct cl_target_option *ptr)
 				  
 {
diff --git a/gcc/config/s390/s390-c.c b/gcc/config/s390/s390-c.c
index f236c55e006..8e5f2c9a394 100644
--- a/gcc/config/s390/s390-c.c
+++ b/gcc/config/s390/s390-c.c
@@ -388,7 +388,7 @@ s390_cpu_cpp_builtins (cpp_reader *pfile)
     cpp_define (pfile, "__s390x__");
   if (TARGET_LONG_DOUBLE_128)
     cpp_define (pfile, "__LONG_DOUBLE_128__");
-  cl_target_option_save (&opts, &global_options);
+  cl_target_option_save (&opts, &global_options, &global_options_set);
   s390_cpu_cpp_builtins_internal (pfile, &opts, NULL);
 }
 
@@ -400,7 +400,8 @@ s390_cpu_cpp_builtins (cpp_reader *pfile)
 static bool
 s390_pragma_target_parse (tree args, tree pop_target)
 {
-  tree prev_tree = build_target_option_node (&global_options);
+  tree prev_tree = build_target_option_node (&global_options,
+					     &global_options_set);
   tree cur_tree;
 
   if (! args)
@@ -411,7 +412,7 @@ s390_pragma_target_parse (tree args, tree pop_target)
 						   &global_options_set, true);
       if (!cur_tree || cur_tree == error_mark_node)
 	{
-	  cl_target_option_restore (&global_options,
+	  cl_target_option_restore (&global_options, &global_options_set,
 				    TREE_TARGET_OPTION (prev_tree));
 	  return false;
 	}
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 5488a5dc5e8..c762840c7e0 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -15207,6 +15207,7 @@ s390_loop_unroll_adjust (unsigned nunroll, struct loop *loop)
 
 static void
 s390_function_specific_restore (struct gcc_options *opts,
+				struct gcc_options */* opts_set */,
 				struct cl_target_option *ptr ATTRIBUTE_UNUSED)
 {
   opts->x_s390_cost_pointer = (long)processor_table[opts->x_s390_tune].cost;
@@ -15230,7 +15231,7 @@ s390_override_options_after_change (void)
 
 static void
 s390_option_override_internal (struct gcc_options *opts,
-			       const struct gcc_options *opts_set)
+			       struct gcc_options *opts_set)
 {
   /* Architecture mode defaults according to ABI.  */
   if (!(opts_set->x_target_flags & MASK_ZARCH))
@@ -15444,7 +15445,7 @@ s390_option_override_internal (struct gcc_options *opts,
 
   /* Call target specific restore function to do post-init work.  At the moment,
      this just sets opts->x_s390_cost_pointer.  */
-  s390_function_specific_restore (opts, NULL);
+  s390_function_specific_restore (opts, opts_set, NULL);
 
   /* Check whether -mfentry is supported. It cannot be used in 31-bit mode,
      because 31-bit PLT stubs assume that %r12 contains GOT address, which is
@@ -15513,7 +15514,8 @@ s390_option_override (void)
 
   /* Save the initial options in case the user does function specific
      options.  */
-  target_option_default_node = build_target_option_node (&global_options);
+  target_option_default_node
+    = build_target_option_node (&global_options, &global_options_set);
   target_option_current_node = target_option_default_node;
 
   /* This cannot reside in s390_option_optimization_table since HAVE_prefetch
@@ -15803,7 +15805,7 @@ s390_valid_target_attribute_tree (tree args,
       s390_option_override_internal (opts, &new_opts_set);
       /* Save the current options unless we are validating options for
 	 #pragma.  */
-      t = build_target_option_node (opts);
+      t = build_target_option_node (opts, &new_opts_set);
     }
   return t;
 }
@@ -15816,7 +15818,7 @@ s390_valid_target_attribute_p (tree fndecl,
 			       tree args,
 			       int ARG_UNUSED (flags))
 {
-  struct gcc_options func_options;
+  struct gcc_options func_options, func_options_set;
   tree new_target, new_optimize;
   bool ret = true;
 
@@ -15828,7 +15830,8 @@ s390_valid_target_attribute_p (tree fndecl,
       && strcmp (TREE_STRING_POINTER (TREE_VALUE (args)), "default") == 0)
     return true;
 
-  tree old_optimize = build_optimization_node (&global_options);
+  tree old_optimize
+    = build_optimization_node (&global_options, &global_options_set);
 
   /* Get the optimization options of the current function.  */
   tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
@@ -15840,19 +15843,21 @@ s390_valid_target_attribute_p (tree fndecl,
   memset (&func_options, 0, sizeof (func_options));
   init_options_struct (&func_options, NULL);
   lang_hooks.init_options_struct (&func_options);
+  memset (&func_options_set, 0, sizeof (func_options_set));
 
-  cl_optimization_restore (&func_options, TREE_OPTIMIZATION (func_optimize));
+  cl_optimization_restore (&func_options, &func_options_set,
+			   TREE_OPTIMIZATION (func_optimize));
 
   /* Initialize func_options to the default before its target options can
      be set.  */
-  cl_target_option_restore (&func_options,
+  cl_target_option_restore (&func_options, &func_options_set,
 			    TREE_TARGET_OPTION (target_option_default_node));
 
   new_target = s390_valid_target_attribute_tree (args, &func_options,
 						 &global_options_set,
 						 (args ==
 						  current_target_pragma));
-  new_optimize = build_optimization_node (&func_options);
+  new_optimize = build_optimization_node (&func_options, &func_options_set);
   if (new_target == error_mark_node)
     ret = false;
   else if (fndecl && new_target)
@@ -15990,7 +15995,8 @@ s390_indirect_branch_settings (tree fndecl)
 void
 s390_activate_target_options (tree new_tree)
 {
-  cl_target_option_restore (&global_options, TREE_TARGET_OPTION (new_tree));
+  cl_target_option_restore (&global_options, &global_options_set,
+			    TREE_TARGET_OPTION (new_tree));
   if (TREE_TARGET_GLOBALS (new_tree))
     restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
   else if (new_tree == target_option_default_node)
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index fb902b36d99..8e9e7701531 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -10493,14 +10493,14 @@ the function declaration to hold a pointer to a target-specific
 @code{struct cl_target_option} structure.
 @end deftypefn
 
-@deftypefn {Target Hook} void TARGET_OPTION_SAVE (struct cl_target_option *@var{ptr}, struct gcc_options *@var{opts})
+@deftypefn {Target Hook} void TARGET_OPTION_SAVE (struct cl_target_option *@var{ptr}, struct gcc_options *@var{opts}, struct gcc_options *@var{opts_set})
 This hook is called to save any additional target-specific information
 in the @code{struct cl_target_option} structure for function-specific
 options from the @code{struct gcc_options} structure.
 @xref{Option file format}.
 @end deftypefn
 
-@deftypefn {Target Hook} void TARGET_OPTION_RESTORE (struct gcc_options *@var{opts}, struct cl_target_option *@var{ptr})
+@deftypefn {Target Hook} void TARGET_OPTION_RESTORE (struct gcc_options *@var{opts}, struct gcc_options *@var{opts_set}, struct cl_target_option *@var{ptr})
 This hook is called to restore any additional target-specific
 information in the @code{struct cl_target_option} structure for
 function-specific options to the @code{struct gcc_options} structure.
diff --git a/gcc/function.c b/gcc/function.c
index 2c8fa217f1f..de5947937eb 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4664,7 +4664,8 @@ invoke_set_current_function_hook (tree fndecl)
       if (optimization_current_node != opts)
 	{
 	  optimization_current_node = opts;
-	  cl_optimization_restore (&global_options, TREE_OPTIMIZATION (opts));
+	  cl_optimization_restore (&global_options, &global_options_set,
+				   TREE_OPTIMIZATION (opts));
 	}
 
       targetm.set_current_function (fndecl);
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index fd96481b12d..505fb1528fa 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -3281,13 +3281,15 @@ Gcc_backend::function(Btype* fntype, const std::string& name,
       if (pos == name.length())
 	{
 	  struct cl_optimization cur_opts;
-	  cl_optimization_save(&cur_opts, &global_options);
+	  cl_optimization_save(&cur_opts, &global_options,
+			       &global_options_set);
 	  global_options.x_optimize_size = 1;
 	  global_options.x_optimize_fast = 0;
 	  global_options.x_optimize_debug = 0;
 	  DECL_FUNCTION_SPECIFIC_OPTIMIZATION(decl) =
-	    build_optimization_node(&global_options);
-	  cl_optimization_restore(&global_options, &cur_opts);
+	    build_optimization_node(&global_options, &global_options_set);
+	  cl_optimization_restore(&global_options, &global_options_set,
+				  &cur_opts);
 	}
     }
 
diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c
index e9e21cc0296..5e37e612bfd 100644
--- a/gcc/ipa-inline-transform.c
+++ b/gcc/ipa-inline-transform.c
@@ -380,14 +380,15 @@ inline_call (struct cgraph_edge *e, bool update_original,
       && opt_for_fn (to->decl, flag_strict_aliasing))
     {
       struct gcc_options opts = global_options;
+      struct gcc_options opts_set = global_options_set;
 
-      cl_optimization_restore (&opts, opts_for_fn (to->decl));
+      cl_optimization_restore (&opts, &opts_set, opts_for_fn (to->decl));
       opts.x_flag_strict_aliasing = false;
       if (dump_file)
 	fprintf (dump_file, "Dropping flag_strict_aliasing on %s\n",
 		 to->dump_name ());
       DECL_FUNCTION_SPECIFIC_OPTIMIZATION (to->decl)
-	 = build_optimization_node (&opts);
+	 = build_optimization_node (&opts, &opts_set);
       reload_optimization_node = true;
     }
 
@@ -420,8 +421,9 @@ inline_call (struct cgraph_edge *e, bool update_original,
 	     != opt_for_fn (to->decl, flag_errno_math))
 	{
 	  struct gcc_options opts = global_options;
+	  struct gcc_options opts_set = global_options_set;
 
-	  cl_optimization_restore (&opts, opts_for_fn (to->decl));
+	  cl_optimization_restore (&opts, &opts_set, opts_for_fn (to->decl));
 	  opts.x_flag_rounding_math
 	    = opt_for_fn (callee->decl, flag_rounding_math);
 	  opts.x_flag_trapping_math
@@ -448,7 +450,7 @@ inline_call (struct cgraph_edge *e, bool update_original,
 	    fprintf (dump_file, "Copying FP flags from %s to %s\n",
 		     callee->dump_name (), to->dump_name ());
 	  DECL_FUNCTION_SPECIFIC_OPTIMIZATION (to->decl)
-	     = build_optimization_node (&opts);
+	     = build_optimization_node (&opts, &opts_set);
 	  reload_optimization_node = true;
 	}
     }
diff --git a/gcc/opt-read.awk b/gcc/opt-read.awk
index 9bb9dfcf6ca..b113291f9a4 100644
--- a/gcc/opt-read.awk
+++ b/gcc/opt-read.awk
@@ -71,6 +71,7 @@ BEGIN {
 			n_target_save++
 
 			extra_target_vars[n_extra_target_vars] = name
+			extra_target_var_types[n_extra_target_vars] = type
 			n_extra_target_vars++
 		}
 		else if ($1 == "HeaderInclude") {
diff --git a/gcc/optc-save-gen.awk b/gcc/optc-save-gen.awk
index ff173fee404..2e4787ec57e 100644
--- a/gcc/optc-save-gen.awk
+++ b/gcc/optc-save-gen.awk
@@ -78,7 +78,8 @@ for (i = 0; i < n_opts; i++) {
 
 print "/* Save optimization variables into a structure.  */"
 print "void";
-print "cl_optimization_save (struct cl_optimization *ptr, struct gcc_options *opts)";
+print "cl_optimization_save (struct cl_optimization *ptr, struct gcc_options *opts,";
+print "		      struct gcc_options *opts_set)";
 print "{";
 
 n_opt_char = 4;
@@ -116,9 +117,10 @@ for (i = 0; i < n_opts; i++) {
 		else if (otype ~ "^((un)?signed +)?short *$")
 			var_opt_short[n_opt_short++] = name;
 
-		else if (otype ~ ("^enum +[_" alnum "]+ *"))
+		else if (otype ~ ("^enum +[_" alnum "]+ *")) {
+			var_opt_enum_type[n_opt_enum] = otype;
 			var_opt_enum[n_opt_enum++] = name;
-
+		}
 		else if (otype ~ "^((un)?signed +)?char *$") {
 			var_opt_char[n_opt_char++] = name;
 			if (otype ~ "^unsigned +char *$")
@@ -166,12 +168,88 @@ for (i = 0; i < n_opt_string; i++) {
 	print "  ptr->x_" var_opt_string[i] " = opts->x_" var_opt_string[i] ";";
 }
 
+print "";
+print "  unsigned HOST_WIDE_INT mask = 0;";
+
+j = 0;
+k = 0;
+for (i = 0; i < n_opt_other; i++) {
+	print "  if (opts_set->x_" var_opt_other[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+for (i = 0; i < n_opt_int; i++) {
+	print "  if (opts_set->x_" var_opt_int[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+for (i = 0; i < n_opt_enum; i++) {
+	print "  if (opts_set->x_" var_opt_enum[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+for (i = 0; i < n_opt_short; i++) {
+	print "  if (opts_set->x_" var_opt_short[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+for (i = 0; i < n_opt_char; i++) {
+	print "  if (opts_set->x_" var_opt_char[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+for (i = 0; i < n_opt_string; i++) {
+	print "  if (opts_set->x_" var_opt_string[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+if (j != 0) {
+	print "  ptr->explicit_mask[" k "] = mask;";
+}
+
 print "}";
 
 print "";
 print "/* Restore optimization options from a structure.  */";
 print "void";
-print "cl_optimization_restore (struct gcc_options *opts, struct cl_optimization *ptr)";
+print "cl_optimization_restore (struct gcc_options *opts, struct gcc_options *opts_set,";
+print "			 struct cl_optimization *ptr)";
 print "{";
 
 for (i = 0; i < n_opt_other; i++) {
@@ -198,6 +276,77 @@ for (i = 0; i < n_opt_string; i++) {
 	print "  opts->x_" var_opt_string[i] " = ptr->x_" var_opt_string[i] ";";
 }
 
+print "";
+print "  unsigned HOST_WIDE_INT mask;";
+
+j = 64;
+k = 0;
+for (i = 0; i < n_opt_other; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_opt_other[i] " = (mask & 1) != 0;";
+	print "  mask >>= 1;"
+	j++;
+}
+
+for (i = 0; i < n_opt_int; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_opt_int[i] " = (mask & 1) != 0;";
+	print "  mask >>= 1;"
+	j++;
+}
+
+for (i = 0; i < n_opt_enum; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_opt_enum[i] " = static_cast<" var_opt_enum_type[i] ">((mask & 1) != 0);";
+	print "  mask >>= 1;"
+	j++;
+}
+
+for (i = 0; i < n_opt_short; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_opt_short[i] " = (mask & 1) != 0;";
+	print "  mask >>= 1;"
+	j++;
+}
+
+for (i = 0; i < n_opt_char; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_opt_char[i] " = (mask & 1) != 0;";
+	print "  mask >>= 1;"
+	j++;
+}
+
+for (i = 0; i < n_opt_string; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_opt_string[i] " = (mask & 1) ? \"\" : nullptr;";
+	print "  mask >>= 1;"
+	j++;
+}
+
 print "  targetm.override_options_after_change ();";
 print "}";
 
@@ -344,7 +493,8 @@ print "}";
 print "";
 print "/* Save selected option variables into a structure.  */"
 print "void";
-print "cl_target_option_save (struct cl_target_option *ptr, struct gcc_options *opts)";
+print "cl_target_option_save (struct cl_target_option *ptr, struct gcc_options *opts,";
+print "		       struct gcc_options *opts_set)";
 print "{";
 
 n_target_char = 0;
@@ -372,9 +522,10 @@ if (have_save) {
 			else if (otype ~ "^((un)?signed +)?short *$")
 				var_target_short[n_target_short++] = name;
 
-			else if (otype ~ ("^enum +[_" alnum "]+ *$"))
+			else if (otype ~ ("^enum +[_" alnum "]+ *$")) {
+				var_target_enum_type[n_target_enum] = otype;
 				var_target_enum[n_target_enum++] = name;
-
+			}
 			else if (otype ~ "^((un)?signed +)?char *$") {
 				var_target_char[n_target_char++] = name;
 				if (otype ~ "^unsigned +char *$")
@@ -409,7 +560,7 @@ if (have_assert)
 	print "";
 
 print "  if (targetm.target_option.save)";
-print "    targetm.target_option.save (ptr, opts);";
+print "    targetm.target_option.save (ptr, opts, opts_set);";
 print "";
 
 for (i = 0; i < n_extra_target_vars; i++) {
@@ -440,12 +591,99 @@ for (i = 0; i < n_target_string; i++) {
 	print "  ptr->x_" var_target_string[i] " = opts->x_" var_target_string[i] ";";
 }
 
+print "";
+print "  unsigned HOST_WIDE_INT mask = 0;";
+
+j = 0;
+k = 0;
+for (i = 0; i < n_extra_target_vars; i++) {
+	print "  if (opts_set->x_" extra_target_vars[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+for (i = 0; i < n_target_other; i++) {
+	print "  if (opts_set->x_" var_target_other[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+for (i = 0; i < n_target_enum; i++) {
+	print "  if (opts_set->x_" var_target_enum[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+for (i = 0; i < n_target_int; i++) {
+	print "  if (opts_set->x_" var_target_int[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+for (i = 0; i < n_target_short; i++) {
+	print "  if (opts_set->x_" var_target_short[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+for (i = 0; i < n_target_char; i++) {
+	print "  if (opts_set->x_" var_target_char[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+for (i = 0; i < n_target_string; i++) {
+	print "  if (opts_set->x_" var_target_string[i] ") mask |= HOST_WIDE_INT_1U << " j ";";
+	j++;
+	if (j == 64) {
+		print "  ptr->explicit_mask[" k "] = mask;";
+		print "  mask = 0;";
+		j = 0;
+		k++;
+	}
+}
+
+if (j != 0) {
+	print "  ptr->explicit_mask[" k "] = mask;";
+}
+
 print "}";
 
 print "";
 print "/* Restore selected current options from a structure.  */";
 print "void";
-print "cl_target_option_restore (struct gcc_options *opts, struct cl_target_option *ptr)";
+print "cl_target_option_restore (struct gcc_options *opts, struct gcc_options *opts_set,";
+print "			  struct cl_target_option *ptr)";
 print "{";
 
 for (i = 0; i < n_extra_target_vars; i++) {
@@ -476,11 +714,101 @@ for (i = 0; i < n_target_string; i++) {
 	print "  opts->x_" var_target_string[i] " = ptr->x_" var_target_string[i] ";";
 }
 
+print "";
+print "  unsigned HOST_WIDE_INT mask;";
+
+j = 64;
+k = 0;
+for (i = 0; i < n_extra_target_vars; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	if (extra_target_var_types[i] ~ ("^enum +[_" alnum "]+ *$")) {
+		print "  opts_set->x_" extra_target_vars[i] " = static_cast<" extra_target_var_types[i] ">((mask & 1) != 0);";
+	}
+	else if (extra_target_var_types[i] ~ "^const char \\**$") {
+		print "  opts_set->x_" extra_target_vars[i] " = (mask & 1) ? \"\" : nullptr;";
+	}
+	else {
+		print "  opts_set->x_" extra_target_vars[i] " = (mask & 1) != 0;";
+	}
+	print "  mask >>= 1;"
+	j++;
+}
+
+for (i = 0; i < n_target_other; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_target_other[i] " = (mask & 1) != 0;";
+	print "  mask >>= 1;"
+	j++;
+}
+
+for (i = 0; i < n_target_enum; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_target_enum[i] " = static_cast<" var_target_enum_type[i] ">((mask & 1) != 0);";
+	print "  mask >>= 1;"
+	j++;
+}
+
+for (i = 0; i < n_target_int; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_target_int[i] " = (mask & 1) != 0;";
+	print "  mask >>= 1;"
+	j++;
+}
+
+for (i = 0; i < n_target_short; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_target_short[i] " = (mask & 1) != 0;";
+	print "  mask >>= 1;"
+	j++;
+}
+
+for (i = 0; i < n_target_char; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_target_char[i] " = (mask & 1) != 0;";
+	print "  mask >>= 1;"
+	j++;
+}
+
+for (i = 0; i < n_target_string; i++) {
+	if (j == 64) {
+		print "  mask = ptr->explicit_mask[" k "];";
+		k++;
+		j = 0;
+	}
+	print "  opts_set->x_" var_target_string[i] " = (mask & 1) ? \"\" : nullptr;";
+	print "  mask >>= 1;"
+	j++;
+}
+
 # This must occur after the normal variables in case the code depends on those
 # variables.
 print "";
 print "  if (targetm.target_option.restore)";
-print "    targetm.target_option.restore (opts, ptr);";
+print "    targetm.target_option.restore (opts, opts_set, ptr);";
 
 print "}";
 
@@ -726,6 +1054,10 @@ for (i = 0; i < n_target_val; i++) {
 	print "    return false;";
 }
 
+print "  for (size_t i = 0; i < sizeof (ptr1->explicit_mask) / sizeof (ptr1->explicit_mask[0]); i++)";
+print "    if (ptr1->explicit_mask[i] != ptr2->explicit_mask[i])";
+print "      return false;"
+
 print "  return true;";
 
 print "}";
@@ -754,6 +1086,8 @@ for (i = 0; i < n_target_val; i++) {
 	name = var_target_val[i]
 	print "  hstate.add_hwi (ptr->" name");";
 }
+print "  for (size_t i = 0; i < sizeof (ptr->explicit_mask) / sizeof (ptr->explicit_mask[0]); i++)";
+print "    hstate.add_hwi (ptr->explicit_mask[i]);";
 print "  return hstate.end ();";
 print "}";
 
@@ -778,6 +1112,10 @@ for (i = 0; i < n_target_val; i++) {
 	name = var_target_val[i]
 	print "  bp_pack_value (bp, ptr->" name", 64);";
 }
+
+print "  for (size_t i = 0; i < sizeof (ptr->explicit_mask) / sizeof (ptr->explicit_mask[0]); i++)";
+print "    bp_pack_value (bp, ptr->explicit_mask[i], 64);";
+
 print "}";
 
 print "";
@@ -804,6 +1142,9 @@ for (i = 0; i < n_target_val; i++) {
 	print "  ptr->" name" = (" var_target_val_type[i] ") bp_unpack_value (bp, 64);";
 }
 
+print "  for (size_t i = 0; i < sizeof (ptr->explicit_mask) / sizeof (ptr->explicit_mask[0]); i++)";
+print "    ptr->explicit_mask[i] = bp_unpack_value (bp, 64);";
+
 print "}";
 
 print "/* free heap memory used by target options  */";
@@ -869,6 +1210,8 @@ for (i = 0; i < n_opt_val; i++) {
 	else
 		print "  hstate.add_hwi (ptr->" name");";
 }
+print "  for (size_t i = 0; i < sizeof (ptr->explicit_mask) / sizeof (ptr->explicit_mask[0]); i++)";
+print "    hstate.add_hwi (ptr->explicit_mask[i]);";
 print "  return hstate.end ();";
 print "}";
 
@@ -896,6 +1239,9 @@ for (i = 0; i < n_opt_val; i++) {
 		print "    return false;";
 	}
 }
+print "  for (size_t i = 0; i < sizeof (ptr1->explicit_mask) / sizeof (ptr1->explicit_mask[0]); i++)";
+print "    if (ptr1->explicit_mask[i] != ptr2->explicit_mask[i])";
+print "      return false;"
 print "  return true;";
 print "}";
 
@@ -914,6 +1260,8 @@ for (i = 0; i < n_opt_val; i++) {
 	else
 		print "  bp_pack_value (bp, ptr->" name", 64);";
 }
+print "  for (size_t i = 0; i < sizeof (ptr->explicit_mask) / sizeof (ptr->explicit_mask[0]); i++)";
+print "    bp_pack_value (bp, ptr->explicit_mask[i], 64);";
 print "}";
 
 print "";
@@ -935,6 +1283,8 @@ for (i = 0; i < n_opt_val; i++) {
 	else
 	      print "  ptr->" name" = (" var_opt_val_type[i] ") bp_unpack_value (bp, 64);";
 }
+print "  for (size_t i = 0; i < sizeof (ptr->explicit_mask) / sizeof (ptr->explicit_mask[0]); i++)";
+print "    ptr->explicit_mask[i] = bp_unpack_value (bp, 64);";
 print "}";
 print "/* Free heap memory used by optimization options  */";
 print "void";
diff --git a/gcc/opth-gen.awk b/gcc/opth-gen.awk
index 472fd591413..8fec607041e 100644
--- a/gcc/opth-gen.awk
+++ b/gcc/opth-gen.awk
@@ -137,6 +137,7 @@ n_opt_short = 0;
 n_opt_int = 0;
 n_opt_enum = 0;
 n_opt_other = 0;
+n_opt_explicit = 4;
 var_opt_char[0] = "unsigned char x_optimize";
 var_opt_char[1] = "unsigned char x_optimize_size";
 var_opt_char[2] = "unsigned char x_optimize_debug";
@@ -152,6 +153,7 @@ for (i = 0; i < n_opts; i++) {
 			continue;
 
 		var_opt_seen[name]++;
+		n_opt_explicit++;
 		otype = var_type_struct(flags[i]);
 		if (otype ~ "^((un)?signed +)?int *$")
 			var_opt_int[n_opt_int++] = otype "x_" name;
@@ -190,6 +192,9 @@ for (i = 0; i < n_opt_char; i++) {
 	print "  " var_opt_char[i] ";";
 }
 
+print "  /* " n_opt_explicit " members */";
+print "  unsigned HOST_WIDE_INT explicit_mask[" int ((n_opt_explicit + 63) / 64) "];";
+
 print "};";
 print "";
 
@@ -203,6 +208,7 @@ n_target_short = 0;
 n_target_int = 0;
 n_target_enum = 0;
 n_target_other = 0;
+n_target_explicit = n_extra_target_vars;
 
 for (i = 0; i < n_target_save; i++) {
 	if (target_save_decl[i] ~ "^((un)?signed +)?int +[_" alnum "]+$")
@@ -232,6 +238,7 @@ if (have_save) {
 				continue;
 
 			var_save_seen[name]++;
+			n_target_explicit++;
 			otype = var_type_struct(flags[i])
 			if (otype ~ "^((un)?signed +)?int *$")
 				var_target_int[n_target_int++] = otype "x_" name;
@@ -251,6 +258,7 @@ if (have_save) {
 	}
 } else {
 	var_target_int[n_target_int++] = "int x_target_flags";
+	n_target_explicit++;
 }
 
 for (i = 0; i < n_target_other; i++) {
@@ -273,14 +281,17 @@ for (i = 0; i < n_target_char; i++) {
 	print "  " var_target_char[i] ";";
 }
 
+print "  /* " n_target_explicit " members */";
+print "  unsigned HOST_WIDE_INT explicit_mask[" int ((n_target_explicit + 63) / 64) "];";
+
 print "};";
 print "";
 print "";
 print "/* Save optimization variables into a structure.  */"
-print "extern void cl_optimization_save (struct cl_optimization *, struct gcc_options *);";
+print "extern void cl_optimization_save (struct cl_optimization *, struct gcc_options *, struct gcc_options *);";
 print "";
 print "/* Restore optimization variables from a structure.  */";
-print "extern void cl_optimization_restore (struct gcc_options *, struct cl_optimization *);";
+print "extern void cl_optimization_restore (struct gcc_options *, struct gcc_options *, struct cl_optimization *);";
 print "";
 print "/* Print optimization variables from a structure.  */";
 print "extern void cl_optimization_print (FILE *, int, struct cl_optimization *);";
@@ -289,10 +300,10 @@ print "/* Print different optimization variables from structures provided as arg
 print "extern void cl_optimization_print_diff (FILE *, int, cl_optimization *ptr1, cl_optimization *ptr2);";
 print "";
 print "/* Save selected option variables into a structure.  */"
-print "extern void cl_target_option_save (struct cl_target_option *, struct gcc_options *);";
+print "extern void cl_target_option_save (struct cl_target_option *, struct gcc_options *, struct gcc_options *);";
 print "";
 print "/* Restore selected option variables from a structure.  */"
-print "extern void cl_target_option_restore (struct gcc_options *, struct cl_target_option *);";
+print "extern void cl_target_option_restore (struct gcc_options *, struct gcc_options *, struct cl_target_option *);";
 print "";
 print "/* Print target option variables from a structure.  */";
 print "extern void cl_target_option_print (FILE *, int, struct cl_target_option *);";
diff --git a/gcc/target-globals.c b/gcc/target-globals.c
index 3d8e8a4ae9a..c7fcd70f776 100644
--- a/gcc/target-globals.c
+++ b/gcc/target-globals.c
@@ -108,11 +108,11 @@ save_target_globals_default_opts ()
 	 attribute.  */
       optimization_current_node = optimization_default_node;
       cl_optimization_restore
-	(&global_options,
+	(&global_options, &global_options_set,
 	 TREE_OPTIMIZATION (optimization_default_node));
       globals = save_target_globals ();
       optimization_current_node = opts;
-      cl_optimization_restore (&global_options,
+      cl_optimization_restore (&global_options, &global_options_set,
 			       TREE_OPTIMIZATION (opts));
       return globals;
     }
diff --git a/gcc/target.def b/gcc/target.def
index c11cab8891f..fc4563d144c 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6376,7 +6376,8 @@ DEFHOOK
 in the @code{struct cl_target_option} structure for function-specific\n\
 options from the @code{struct gcc_options} structure.\n\
 @xref{Option file format}.",
- void, (struct cl_target_option *ptr, struct gcc_options *opts), NULL)
+ void, (struct cl_target_option *ptr, struct gcc_options *opts,
+	struct gcc_options *opts_set), NULL)
 
 /* Function to restore any extra target state from the target options
    structure.  */
@@ -6385,7 +6386,8 @@ DEFHOOK
  "This hook is called to restore any additional target-specific\n\
 information in the @code{struct cl_target_option} structure for\n\
 function-specific options to the @code{struct gcc_options} structure.",
- void, (struct gcc_options *opts, struct cl_target_option *ptr), NULL)
+ void, (struct gcc_options *opts, struct gcc_options *opts_set,
+	struct cl_target_option *ptr), NULL)
 
 /* Function to update target-specific option information after being
    streamed in.  */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 07457d08c3a..cdd4b5b4f92 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1867,7 +1867,8 @@ process_options (void)
                                     DK_ERROR, UNKNOWN_LOCATION);
 
   /* Save the current optimization options.  */
-  optimization_default_node = build_optimization_node (&global_options);
+  optimization_default_node
+    = build_optimization_node (&global_options, &global_options_set);
   optimization_current_node = optimization_default_node;
 
   if (flag_checking >= 2)
@@ -2075,7 +2076,7 @@ target_reinit (void)
     {
       optimization_current_node = optimization_default_node;
       cl_optimization_restore
-	(&global_options,
+	(&global_options, &global_options_set,
 	 TREE_OPTIMIZATION (optimization_default_node));
     }
   this_fn_optabs = this_target_optabs;
@@ -2107,7 +2108,7 @@ target_reinit (void)
   if (saved_optimization_current_node != optimization_default_node)
     {
       optimization_current_node = saved_optimization_current_node;
-      cl_optimization_restore (&global_options,
+      cl_optimization_restore (&global_options, &global_options_set,
 			       TREE_OPTIMIZATION (optimization_current_node));
     }
   this_fn_optabs = saved_this_fn_optabs;
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index a456709ffd8..2a8817bd282 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -800,11 +800,12 @@ lto_input_ts_function_decl_tree_pointers (class lto_input_block *ib,
     tree opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr);
     if (opts)
       {
-	struct gcc_options tmp;
+	struct gcc_options tmp, tmp_set;
 	init_options_struct (&tmp, NULL);
-	cl_optimization_restore (&tmp, TREE_OPTIMIZATION (opts));
-	finish_options (&tmp, &global_options_set, UNKNOWN_LOCATION);
-	opts = build_optimization_node (&tmp);
+	memset (&tmp_set, 0, sizeof (tmp_set));
+	cl_optimization_restore (&tmp, &tmp_set, TREE_OPTIMIZATION (opts));
+	finish_options (&tmp, &tmp_set, UNKNOWN_LOCATION);
+	opts = build_optimization_node (&tmp, &tmp_set);
 	DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr) = opts;
       }
   }
diff --git a/gcc/tree.c b/gcc/tree.c
index 45aacadbe2d..4046debb72f 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -12574,17 +12574,18 @@ cl_option_hasher::equal (tree x, tree y)
     gcc_unreachable ();
 }
 
-/* Build an OPTIMIZATION_NODE based on the options in OPTS.  */
+/* Build an OPTIMIZATION_NODE based on the options in OPTS and OPTS_SET.  */
 
 tree
-build_optimization_node (struct gcc_options *opts)
+build_optimization_node (struct gcc_options *opts,
+			 struct gcc_options *opts_set)
 {
   tree t;
 
   /* Use the cache of optimization nodes.  */
 
   cl_optimization_save (TREE_OPTIMIZATION (cl_optimization_node),
-			opts);
+			opts, opts_set);
 
   tree *slot = cl_option_hash_table->find_slot (cl_optimization_node, INSERT);
   t = *slot;
@@ -12601,17 +12602,18 @@ build_optimization_node (struct gcc_options *opts)
   return t;
 }
 
-/* Build a TARGET_OPTION_NODE based on the options in OPTS.  */
+/* Build a TARGET_OPTION_NODE based on the options in OPTS and OPTS_SET.  */
 
 tree
-build_target_option_node (struct gcc_options *opts)
+build_target_option_node (struct gcc_options *opts,
+			  struct gcc_options *opts_set)
 {
   tree t;
 
   /* Use the cache of optimization nodes.  */
 
   cl_target_option_save (TREE_TARGET_OPTION (cl_target_option_node),
-			 opts);
+			 opts, opts_set);
 
   tree *slot = cl_option_hash_table->find_slot (cl_target_option_node, INSERT);
   t = *slot;
diff --git a/gcc/tree.h b/gcc/tree.h
index 9ec24a3008b..8c65f7ca0a9 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3272,8 +3272,10 @@ extern vec<tree, va_gc> **decl_debug_args_insert (tree);
 #define TREE_OPTIMIZATION_BASE_OPTABS(NODE) \
   (OPTIMIZATION_NODE_CHECK (NODE)->optimization.base_optabs)
 
-/* Return a tree node that encapsulates the optimization options in OPTS.  */
-extern tree build_optimization_node (struct gcc_options *opts);
+/* Return a tree node that encapsulates the optimization options in OPTS
+   and OPTS_SET.  */
+extern tree build_optimization_node (struct gcc_options *opts,
+				     struct gcc_options *opts_set);
 
 #define TREE_TARGET_OPTION(NODE) \
   (TARGET_OPTION_NODE_CHECK (NODE)->target_option.opts)
@@ -3281,8 +3283,10 @@ extern tree build_optimization_node (struct gcc_options *opts);
 #define TREE_TARGET_GLOBALS(NODE) \
   (TARGET_OPTION_NODE_CHECK (NODE)->target_option.globals)
 
-/* Return a tree node that encapsulates the target options in OPTS.  */
-extern tree build_target_option_node (struct gcc_options *opts);
+/* Return a tree node that encapsulates the target options in OPTS and
+   OPTS_SET.  */
+extern tree build_target_option_node (struct gcc_options *opts,
+				      struct gcc_options *opts_set);
 
 extern void prepare_target_option_nodes_for_pch (void);


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-09-14  7:06 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-14  7:06 [gcc r11-3183] options: Save and restore opts_set for Optimization and Target options Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).