diff mbox

[i386] Fix PR 57756

Message ID CAAs8Hmz1qS4ZvpN-jU96Y4h2QhpWwOAQ2iEuwyjHUXOoPGMJ5w@mail.gmail.com
State New
Headers show

Commit Message

Sriraman Tallam Sept. 21, 2013, 2:09 a.m. UTC
Forgot to add the test case. Patch updated.

Sri

On Fri, Sep 20, 2013 at 7:06 PM, Sriraman Tallam <tmsriram@google.com> wrote:
> On Wed, Aug 14, 2013 at 3:38 AM, Richard Biener
> <richard.guenther@gmail.com> wrote:
>> On Wed, Aug 14, 2013 at 2:02 AM, Sriraman Tallam <tmsriram@google.com>
>> wrote:
>>>
>>> Hi,
>>>
>>>     I have attached a patch to fix PR57756.  Description:  The
>>> following program,
>>>
>>> __attribute__((always_inline,target("sse4.2")))
>>> __inline int callee ()
>>> {
>>>   return 0;
>>> }
>>>
>>> __attribute__((target("sse")))
>>> __inline int caller ()
>>> {
>>>   return callee();
>>> }
>>>
>>> does not generate an error and callee is inlined into caller. This is
>>> because callee has a higher target ISA.  Interchanging the position of
>>> caller and callee will generate the correct error. Also, removing the
>>> target attribute from caller will generate the error.
>>>
>>> The reason for the bug is that when the caller's target options are
>>> processed, global_options contain the ISA flags of the callee
>>> (previously processed) and doing this in i386-common.c, where opts is
>>> global_options:
>>>
>>> opts->x_ix86_isa_flags |= OPTION_MASK_ISA_SSE_SET;
>>>
>>> is not changing global options.  The fix is to reset global_options to
>>> the default each time a new target option needs to be processed.
>>
>>
>> Shouldn't  ix86_valid_target_attribute_tree be refactored to work on a
>> selected
>> opt structure rather than global_options?
>
> I have attached a patch that does the refactoring of
> ix86_valid_target_attribute_tree. In that process I had to refactor
> ix86_valid_target_attribute_inner_p and ix86_option_override_internal.
> This made it a large patch because global_options structure is touched
> by these functions in multiple places and through vvarious aliases
> like ix86_arch_string for instance. In effect, this frees these
> functions from depending on global_options and the code in
> ix86_alid_target_attribute_p shows how the original bug can be fixed
> by just using a different gcc_options structure.
>
> Please review.
>
> Thanks
> Sri
>
>
>
>> Richard.
>>
>>>
>>> Patch ok?
>>>
>>> Thanks
>>> Sri
>>
>>
* testsuite/gcc.target/i386/pr57756.c: New test. 	
	* tree.c (build_optimization_node): New parameter.
	(build_target_option_node): New parameter.
	* tree.h (build_optimization_node): New parameter.
	(build_target_option_node): New parameter.
	* c-family/c-common.c (handle_optimize_attribute): Fix calls to
	build_optimization_node and build_target_option_node.
	* c-family/c-pragma.c (handle_pragma_optimize): Ditto.
	(handle_pragma_push_options): Ditto.
	* toplev.c (process_options): Ditto.
	* config/i386/i386-c.c (ix86_target_macros_internal): Ditto.
	(ix86_pragma_target_parse): Ditto.
	* config/i386/i386-protos.h (ix86_valid_target_attribute_tree): New
	parameters.
	* config/rs6000/rs6000.c (rs6000_option_override_internal): Fix calls
	to  build_optimization_node and build_target_option_node.
	(rs6000_valid_attribute_p): Ditto.
	(rs6000_pragma_target_parse): Ditto.
	* config/i386/i386.c (ix86_option_override_internal): New parameters
	opts and opts_set.
	Change ix86_tune_string to access opts->x_ix86_tune_string.
	Change ix86_isa_flags to access opts->x_ix86_isa_flags.
	Change ix86_arch_string to access opts->x_ix86_arch_string.
	Change ix86_stringop_alg to access opts->x_ix86_stringop_alg.
	Change ix86_pmode to access opts->x_ix86_pmode.
	Change ix86_abi to access opts->x_ix86_abi.
	Change ix86_cmodel to access opts->x_ix86_cmodel.
	Change ix86_asm_dialect to access opts->x_ix86_asm_dialect.
	Change ix86_isa_flags_explicit to access
	opts->x_ix86_isa_flags_explicit.
	Change ix86_dump_tunes to access opts->x_ix86_dump_tunes.
	Change ix86_regparm to access opts->x_ix86_regparm.
	Change ix86_branch_cost to access opts->x_ix86_branch_cost.
	Change ix86_preferred_stack_boundary_arg to access
	opts->x_ix86_preferred_stack_boundary_arg.
	Change ix86_force_align_arg_pointer to access
	opts->x_ix86_force_align_arg_pointer.
	Change ix86_incoming_stack_boundar_arg to access
	opts->x_ix86_incoming_stack_boundar_arg.
	Change ix86_fpmath to access opts->x_ix86_fpmath.
	Change ix86_veclibabi_type to access opts->x_ix86_veclibabi_type.
	Change ix86_recip_name to access opts->x_ix86_recip_name.
	Change ix86_stack_protector_guard to access
	opts->x_ix86_stack_protector_guard.
	Change ix86_tune_memcpy_strategy to access
	opts->x_ix86_tune_memcpy_strategy.
	Change ix86_tune_memset_strategy to access
	opts->x_ix86_tune_memset_strategy.
	Change global_options to access opts.
	Change global_options_set to access opts_set.
	(ix86_valid_target_attribute_inner_p): New parameters.
	Fix recursive call.
	Fix call to ix86_handle_option and set_option.
	(ix86_valid_target_attribute_tree): New parameters.
	Change global_options to access opts.
	Change global_options_set to access opts_set.
	Fix call to ix86_valid_target_attribute_inner_p.
	Change ix86_tune_string to access opts->x_ix86_tune_string.
	Change ix86_arch_string to access opts->x_ix86_arch_string.
	Change ix86_fpmath to access opts->x_ix86_fpmath
	Fix call to ix86_option_override_internal.
	Fix call to ix86_add_new_builtins.
	Fix calls to build_optimization_node and build_target_option_node.
	(ix86_valid_target_attribute_p): Remove access to global_options.
	Use new gcc_options structure func_options.
	Fix call to ix86_valid_target_attribute_tree.
	Fix call to  build_optimization_node.
	(get_builtin_code_for_version):	Fix call to
	ix86_valid_target_attribute_tree.

Comments

Richard Biener Sept. 23, 2013, 11:09 a.m. UTC | #1
On Sat, Sep 21, 2013 at 4:09 AM, Sriraman Tallam <tmsriram@google.com> wrote:
> Forgot to add the test case. Patch updated.
>
> Sri
>
> On Fri, Sep 20, 2013 at 7:06 PM, Sriraman Tallam <tmsriram@google.com> wrote:
>> On Wed, Aug 14, 2013 at 3:38 AM, Richard Biener
>> <richard.guenther@gmail.com> wrote:
>>> On Wed, Aug 14, 2013 at 2:02 AM, Sriraman Tallam <tmsriram@google.com>
>>> wrote:
>>>>
>>>> Hi,
>>>>
>>>>     I have attached a patch to fix PR57756.  Description:  The
>>>> following program,
>>>>
>>>> __attribute__((always_inline,target("sse4.2")))
>>>> __inline int callee ()
>>>> {
>>>>   return 0;
>>>> }
>>>>
>>>> __attribute__((target("sse")))
>>>> __inline int caller ()
>>>> {
>>>>   return callee();
>>>> }
>>>>
>>>> does not generate an error and callee is inlined into caller. This is
>>>> because callee has a higher target ISA.  Interchanging the position of
>>>> caller and callee will generate the correct error. Also, removing the
>>>> target attribute from caller will generate the error.
>>>>
>>>> The reason for the bug is that when the caller's target options are
>>>> processed, global_options contain the ISA flags of the callee
>>>> (previously processed) and doing this in i386-common.c, where opts is
>>>> global_options:
>>>>
>>>> opts->x_ix86_isa_flags |= OPTION_MASK_ISA_SSE_SET;
>>>>
>>>> is not changing global options.  The fix is to reset global_options to
>>>> the default each time a new target option needs to be processed.
>>>
>>>
>>> Shouldn't  ix86_valid_target_attribute_tree be refactored to work on a
>>> selected
>>> opt structure rather than global_options?
>>
>> I have attached a patch that does the refactoring of
>> ix86_valid_target_attribute_tree. In that process I had to refactor
>> ix86_valid_target_attribute_inner_p and ix86_option_override_internal.
>> This made it a large patch because global_options structure is touched
>> by these functions in multiple places and through vvarious aliases
>> like ix86_arch_string for instance. In effect, this frees these
>> functions from depending on global_options and the code in
>> ix86_alid_target_attribute_p shows how the original bug can be fixed
>> by just using a different gcc_options structure.

This looks nice.  I suppose you grepped for effected targets and rs6000
was the only one besides i386.

This is ok given target maintainers do not object within 24h and the test
successfully bootstrapped and passed regression tests.

Thanks,
Richard.

>> Please review.
>>
>> Thanks
>> Sri
>>
>>
>>
>>> Richard.
>>>
>>>>
>>>> Patch ok?
>>>>
>>>> Thanks
>>>> Sri
>>>
>>>
diff mbox

Patch

Index: c-family/c-common.c
===================================================================
--- c-family/c-common.c	(revision 202662)
+++ c-family/c-common.c	(working copy)
@@ -8993,7 +8993,7 @@  handle_optimize_attribute (tree *node, tree name,
       /* Parse options, and update the vector.  */
       parse_optimize_options (args, true);
       DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
-	= build_optimization_node ();
+	= build_optimization_node (&global_options);
 
       /* Restore current options.  */
       cl_optimization_restore (&global_options, &cur_opts);
Index: c-family/c-pragma.c
===================================================================
--- c-family/c-pragma.c	(revision 202662)
+++ c-family/c-pragma.c	(working copy)
@@ -872,7 +872,7 @@  handle_pragma_optimize (cpp_reader *ARG_UNUSED(dum
 
       parse_optimize_options (args, false);
       current_optimize_pragma = chainon (current_optimize_pragma, args);
-      optimization_current_node = build_optimization_node ();
+      optimization_current_node = build_optimization_node (&global_options);
       c_cpp_builtins_optimize_pragma (parse_in,
 				      optimization_previous_node,
 				      optimization_current_node);
@@ -914,8 +914,8 @@  handle_pragma_push_options (cpp_reader *ARG_UNUSED
   options_stack = p;
 
   /* Save optimization and target flags in binary format.  */
-  p->optimize_binary = build_optimization_node ();
-  p->target_binary = build_target_option_node ();
+  p->optimize_binary = build_optimization_node (&global_options);
+  p->target_binary = build_target_option_node (&global_options);
 
   /* Save optimization and target flags in string list format.  */
   p->optimize_strings = copy_list (current_optimize_pragma);
Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c	(revision 202662)
+++ config/i386/i386.c	(working copy)
@@ -2333,6 +2333,8 @@  static void ix86_function_specific_print (FILE *,
 					  struct cl_target_option *);
 static bool ix86_valid_target_attribute_p (tree, tree, tree, int);
 static bool ix86_valid_target_attribute_inner_p (tree, char *[],
+						 struct gcc_options *,
+						 struct gcc_options *,
 						 struct gcc_options *);
 static bool ix86_can_inline_p (tree, tree);
 static void ix86_set_current_function (tree);
@@ -2997,11 +2999,13 @@  set_ix86_tune_features (enum processor_type ix86_t
    attributes.  */
 
 static void
-ix86_option_override_internal (bool main_args_p)
+ix86_option_override_internal (bool main_args_p,
+			       struct gcc_options *opts,
+			       struct gcc_options *opts_set)
 {
   int i;
   unsigned int ix86_arch_mask, ix86_tune_mask;
-  const bool ix86_tune_specified = (ix86_tune_string != NULL);
+  const bool ix86_tune_specified = (opts->x_ix86_tune_string != NULL);
   const char *prefix;
   const char *suffix;
   const char *sw;
@@ -3236,7 +3240,7 @@  static void
   /* Turn off both OPTION_MASK_ABI_64 and OPTION_MASK_ABI_X32 if
      TARGET_64BIT_DEFAULT is true and TARGET_64BIT is false.  */
   if (TARGET_64BIT_DEFAULT && !TARGET_64BIT)
-    ix86_isa_flags &= ~(OPTION_MASK_ABI_64 | OPTION_MASK_ABI_X32);
+    opts->x_ix86_isa_flags &= ~(OPTION_MASK_ABI_64 | OPTION_MASK_ABI_X32);
 #ifdef TARGET_BI_ARCH
   else
     {
@@ -3246,14 +3250,14 @@  static void
 	 OPTION_MASK_ABI_64 if OPTION_MASK_ABI_X32 is turned on by
 	 -mx32.  */
       if (TARGET_X32)
-	ix86_isa_flags &= ~OPTION_MASK_ABI_64;
+	opts->x_ix86_isa_flags &= ~OPTION_MASK_ABI_64;
 #else
       /* When TARGET_BI_ARCH == 2, by default, OPTION_MASK_ABI_X32 is
 	 on and OPTION_MASK_ABI_64 is off.  We turn off
 	 OPTION_MASK_ABI_X32 if OPTION_MASK_ABI_64 is turned on by
 	 -m64.  */
       if (TARGET_LP64)
-	ix86_isa_flags &= ~OPTION_MASK_ABI_X32;
+	opts->x_ix86_isa_flags &= ~OPTION_MASK_ABI_X32;
 #endif
     }
 #endif
@@ -3262,15 +3266,15 @@  static void
     {
       /* Always turn on OPTION_MASK_ISA_64BIT and turn off
 	 OPTION_MASK_ABI_64 for TARGET_X32.  */
-      ix86_isa_flags |= OPTION_MASK_ISA_64BIT;
-      ix86_isa_flags &= ~OPTION_MASK_ABI_64;
+      opts->x_ix86_isa_flags |= OPTION_MASK_ISA_64BIT;
+      opts->x_ix86_isa_flags &= ~OPTION_MASK_ABI_64;
     }
   else if (TARGET_LP64)
     {
       /* Always turn on OPTION_MASK_ISA_64BIT and turn off
 	 OPTION_MASK_ABI_X32 for TARGET_LP64.  */
-      ix86_isa_flags |= OPTION_MASK_ISA_64BIT;
-      ix86_isa_flags &= ~OPTION_MASK_ABI_X32;
+      opts->x_ix86_isa_flags |= OPTION_MASK_ISA_64BIT;
+      opts->x_ix86_isa_flags &= ~OPTION_MASK_ABI_X32;
     }
 
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
@@ -3286,97 +3290,98 @@  static void
     flag_pic = 2;
 
   /* Need to check -mtune=generic first.  */
-  if (ix86_tune_string)
+  if (opts->x_ix86_tune_string)
     {
-      if (!strcmp (ix86_tune_string, "generic")
-	  || !strcmp (ix86_tune_string, "i686")
+      if (!strcmp (opts->x_ix86_tune_string, "generic")
+	  || !strcmp (opts->x_ix86_tune_string, "i686")
 	  /* As special support for cross compilers we read -mtune=native
 	     as -mtune=generic.  With native compilers we won't see the
 	     -mtune=native, as it was changed by the driver.  */
-	  || !strcmp (ix86_tune_string, "native"))
+	  || !strcmp (opts->x_ix86_tune_string, "native"))
 	{
 	  if (TARGET_64BIT)
-	    ix86_tune_string = "generic64";
+	    opts->x_ix86_tune_string = "generic64";
 	  else
-	    ix86_tune_string = "generic32";
+	    opts->x_ix86_tune_string = "generic32";
 	}
       /* If this call is for setting the option attribute, allow the
 	 generic32/generic64 that was previously set.  */
       else if (!main_args_p
-	       && (!strcmp (ix86_tune_string, "generic32")
-		   || !strcmp (ix86_tune_string, "generic64")))
+	       && (!strcmp (opts->x_ix86_tune_string, "generic32")
+		   || !strcmp (opts->x_ix86_tune_string, "generic64")))
 	;
-      else if (!strncmp (ix86_tune_string, "generic", 7))
+      else if (!strncmp (opts->x_ix86_tune_string, "generic", 7))
         error ("bad value (%s) for %stune=%s %s",
-	       ix86_tune_string, prefix, suffix, sw);
-      else if (!strcmp (ix86_tune_string, "x86-64"))
+	       opts->x_ix86_tune_string, prefix, suffix, sw);
+      else if (!strcmp (opts->x_ix86_tune_string, "x86-64"))
         warning (OPT_Wdeprecated, "%stune=x86-64%s is deprecated; use "
                  "%stune=k8%s or %stune=generic%s instead as appropriate",
                  prefix, suffix, prefix, suffix, prefix, suffix);
     }
   else
     {
-      if (ix86_arch_string)
-	ix86_tune_string = ix86_arch_string;
-      if (!ix86_tune_string)
+      if (opts->x_ix86_arch_string)
+	opts->x_ix86_tune_string = opts->x_ix86_arch_string;
+      if (!opts->x_ix86_tune_string)
 	{
-	  ix86_tune_string = cpu_names[TARGET_CPU_DEFAULT];
+	  opts->x_ix86_tune_string = cpu_names[TARGET_CPU_DEFAULT];
 	  ix86_tune_defaulted = 1;
 	}
 
-      /* ix86_tune_string is set to ix86_arch_string or defaulted.  We
-	 need to use a sensible tune option.  */
-      if (!strcmp (ix86_tune_string, "generic")
-	  || !strcmp (ix86_tune_string, "x86-64")
-	  || !strcmp (ix86_tune_string, "i686"))
+      /* opts->x_ix86_tune_string is set to opts->x_ix86_arch_string
+	 or defaulted.  We need to use a sensible tune option.  */
+      if (!strcmp (opts->x_ix86_tune_string, "generic")
+	  || !strcmp (opts->x_ix86_tune_string, "x86-64")
+	  || !strcmp (opts->x_ix86_tune_string, "i686"))
 	{
 	  if (TARGET_64BIT)
-	    ix86_tune_string = "generic64";
+	    opts->x_ix86_tune_string = "generic64";
 	  else
-	    ix86_tune_string = "generic32";
+	    opts->x_ix86_tune_string = "generic32";
 	}
     }
 
-  if (ix86_stringop_alg == rep_prefix_8_byte && !TARGET_64BIT)
+  if (opts->x_ix86_stringop_alg == rep_prefix_8_byte && !TARGET_64BIT)
     {
       /* rep; movq isn't available in 32-bit code.  */
       error ("-mstringop-strategy=rep_8byte not supported for 32-bit code");
-      ix86_stringop_alg = no_stringop;
+      opts->x_ix86_stringop_alg = no_stringop;
     }
 
-  if (!ix86_arch_string)
-    ix86_arch_string = TARGET_64BIT ? "x86-64" : SUBTARGET32_DEFAULT_CPU;
+  if (!opts->x_ix86_arch_string)
+    opts->x_ix86_arch_string
+      = TARGET_64BIT ? "x86-64" : SUBTARGET32_DEFAULT_CPU;
   else
     ix86_arch_specified = 1;
 
-  if (global_options_set.x_ix86_pmode)
+  if (opts_set->x_ix86_pmode)
     {
-      if ((TARGET_LP64 && ix86_pmode == PMODE_SI)
-	   || (!TARGET_64BIT && ix86_pmode == PMODE_DI))
+      if ((TARGET_LP64 && opts->x_ix86_pmode == PMODE_SI)
+	   || (!TARGET_64BIT && opts->x_ix86_pmode == PMODE_DI))
 	error ("address mode %qs not supported in the %s bit mode",
 	       TARGET_64BIT ? "short" : "long",
 	       TARGET_64BIT ? "64" : "32");
     }
   else
-    ix86_pmode = TARGET_LP64 ? PMODE_DI : PMODE_SI;
+    opts->x_ix86_pmode = TARGET_LP64 ? PMODE_DI : PMODE_SI;
 
-  if (!global_options_set.x_ix86_abi)
-    ix86_abi = DEFAULT_ABI;
+  if (!opts_set->x_ix86_abi)
+    opts->x_ix86_abi = DEFAULT_ABI;
 
   /* For targets using ms ABI enable ms-extensions, if not
      explicit turned off.  For non-ms ABI we turn off this
      option.  */
-  if (!global_options_set.x_flag_ms_extensions)
+  if (!opts_set->x_flag_ms_extensions)
     flag_ms_extensions = (MS_ABI == DEFAULT_ABI);
 
-  if (global_options_set.x_ix86_cmodel)
+  if (opts_set->x_ix86_cmodel)
     {
-      switch (ix86_cmodel)
+      switch (opts->x_ix86_cmodel)
 	{
 	case CM_SMALL:
 	case CM_SMALL_PIC:
 	  if (flag_pic)
-	    ix86_cmodel = CM_SMALL_PIC;
+	    opts->x_ix86_cmodel = CM_SMALL_PIC;
 	  if (!TARGET_64BIT)
 	    error ("code model %qs not supported in the %s bit mode",
 		   "small", "32");
@@ -3385,7 +3390,7 @@  static void
 	case CM_MEDIUM:
 	case CM_MEDIUM_PIC:
 	  if (flag_pic)
-	    ix86_cmodel = CM_MEDIUM_PIC;
+	    opts->x_ix86_cmodel = CM_MEDIUM_PIC;
 	  if (!TARGET_64BIT)
 	    error ("code model %qs not supported in the %s bit mode",
 		   "medium", "32");
@@ -3397,7 +3402,7 @@  static void
 	case CM_LARGE:
 	case CM_LARGE_PIC:
 	  if (flag_pic)
-	    ix86_cmodel = CM_LARGE_PIC;
+	    opts->x_ix86_cmodel = CM_LARGE_PIC;
 	  if (!TARGET_64BIT)
 	    error ("code model %qs not supported in the %s bit mode",
 		   "large", "32");
@@ -3418,7 +3423,7 @@  static void
 	  if (flag_pic)
 	    {
 	      error ("code model %s does not support PIC mode", "kernel");
-	      ix86_cmodel = CM_32;
+	      opts->x_ix86_cmodel = CM_32;
 	    }
 	  if (!TARGET_64BIT)
 	    error ("code model %qs not supported in the %s bit mode",
@@ -3436,23 +3441,24 @@  static void
 	 would otherwise be needed if this object is to be placed in a
 	 DLL, and is essentially just as efficient as direct addressing.  */
       if (TARGET_64BIT && (TARGET_RDOS || TARGET_PECOFF))
-	ix86_cmodel = CM_MEDIUM_PIC, flag_pic = 1;
+	opts->x_ix86_cmodel = CM_MEDIUM_PIC, flag_pic = 1;
       else if (TARGET_64BIT)
-	ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
+	opts->x_ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
       else
-	ix86_cmodel = CM_32;
+	opts->x_ix86_cmodel = CM_32;
     }
-  if (TARGET_MACHO && ix86_asm_dialect == ASM_INTEL)
+  if (TARGET_MACHO && opts->x_ix86_asm_dialect == ASM_INTEL)
     {
       error ("-masm=intel not supported in this configuration");
-      ix86_asm_dialect = ASM_ATT;
+      opts->x_ix86_asm_dialect = ASM_ATT;
     }
-  if ((TARGET_64BIT != 0) != ((ix86_isa_flags & OPTION_MASK_ISA_64BIT) != 0))
+  if ((TARGET_64BIT != 0)
+      != ((opts->x_ix86_isa_flags & OPTION_MASK_ISA_64BIT) != 0))
     sorry ("%i-bit mode not compiled in",
-	   (ix86_isa_flags & OPTION_MASK_ISA_64BIT) ? 64 : 32);
+	   (opts->x_ix86_isa_flags & OPTION_MASK_ISA_64BIT) ? 64 : 32);
 
   for (i = 0; i < pta_size; i++)
-    if (! strcmp (ix86_arch_string, processor_alias_table[i].name))
+    if (! strcmp (opts->x_ix86_arch_string, processor_alias_table[i].name))
       {
 	ix86_schedule = processor_alias_table[i].schedule;
 	ix86_arch = processor_alias_table[i].processor;
@@ -3464,150 +3470,150 @@  static void
 		 "instruction set");
 
 	if (processor_alias_table[i].flags & PTA_MMX
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_MMX))
-	  ix86_isa_flags |= OPTION_MASK_ISA_MMX;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_MMX))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_MMX;
 	if (processor_alias_table[i].flags & PTA_3DNOW
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_3DNOW))
-	  ix86_isa_flags |= OPTION_MASK_ISA_3DNOW;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_3DNOW))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_3DNOW;
 	if (processor_alias_table[i].flags & PTA_3DNOW_A
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_3DNOW_A))
-	  ix86_isa_flags |= OPTION_MASK_ISA_3DNOW_A;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_3DNOW_A))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_3DNOW_A;
 	if (processor_alias_table[i].flags & PTA_SSE
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE))
-	  ix86_isa_flags |= OPTION_MASK_ISA_SSE;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_SSE;
 	if (processor_alias_table[i].flags & PTA_SSE2
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE2))
-	  ix86_isa_flags |= OPTION_MASK_ISA_SSE2;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE2))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_SSE2;
 	if (processor_alias_table[i].flags & PTA_SSE3
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE3))
-	  ix86_isa_flags |= OPTION_MASK_ISA_SSE3;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE3))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_SSE3;
 	if (processor_alias_table[i].flags & PTA_SSSE3
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSSE3))
-	  ix86_isa_flags |= OPTION_MASK_ISA_SSSE3;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_SSSE3))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_SSSE3;
 	if (processor_alias_table[i].flags & PTA_SSE4_1
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE4_1))
-	  ix86_isa_flags |= OPTION_MASK_ISA_SSE4_1;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE4_1))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_SSE4_1;
 	if (processor_alias_table[i].flags & PTA_SSE4_2
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE4_2))
-	  ix86_isa_flags |= OPTION_MASK_ISA_SSE4_2;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE4_2))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_SSE4_2;
 	if (processor_alias_table[i].flags & PTA_AVX
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX))
-	  ix86_isa_flags |= OPTION_MASK_ISA_AVX;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_AVX;
 	if (processor_alias_table[i].flags & PTA_AVX2
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX2))
-	  ix86_isa_flags |= OPTION_MASK_ISA_AVX2;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX2))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_AVX2;
 	if (processor_alias_table[i].flags & PTA_FMA
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_FMA))
-	  ix86_isa_flags |= OPTION_MASK_ISA_FMA;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_FMA))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_FMA;
 	if (processor_alias_table[i].flags & PTA_SSE4A
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE4A))
-	  ix86_isa_flags |= OPTION_MASK_ISA_SSE4A;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE4A))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_SSE4A;
 	if (processor_alias_table[i].flags & PTA_FMA4
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_FMA4))
-	  ix86_isa_flags |= OPTION_MASK_ISA_FMA4;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_FMA4))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_FMA4;
 	if (processor_alias_table[i].flags & PTA_XOP
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_XOP))
-	  ix86_isa_flags |= OPTION_MASK_ISA_XOP;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_XOP))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_XOP;
 	if (processor_alias_table[i].flags & PTA_LWP
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_LWP))
-	  ix86_isa_flags |= OPTION_MASK_ISA_LWP;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_LWP))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_LWP;
 	if (processor_alias_table[i].flags & PTA_ABM
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_ABM))
-	  ix86_isa_flags |= OPTION_MASK_ISA_ABM;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_ABM))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_ABM;
 	if (processor_alias_table[i].flags & PTA_BMI
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_BMI))
-	  ix86_isa_flags |= OPTION_MASK_ISA_BMI;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_BMI))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_BMI;
 	if (processor_alias_table[i].flags & (PTA_LZCNT | PTA_ABM)
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_LZCNT))
-	  ix86_isa_flags |= OPTION_MASK_ISA_LZCNT;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_LZCNT))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_LZCNT;
 	if (processor_alias_table[i].flags & PTA_TBM
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_TBM))
-	  ix86_isa_flags |= OPTION_MASK_ISA_TBM;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_TBM))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_TBM;
 	if (processor_alias_table[i].flags & PTA_BMI2
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_BMI2))
-	  ix86_isa_flags |= OPTION_MASK_ISA_BMI2;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_BMI2))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_BMI2;
 	if (processor_alias_table[i].flags & PTA_CX16
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_CX16))
-	  ix86_isa_flags |= OPTION_MASK_ISA_CX16;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_CX16))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_CX16;
 	if (processor_alias_table[i].flags & (PTA_POPCNT | PTA_ABM)
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_POPCNT))
-	  ix86_isa_flags |= OPTION_MASK_ISA_POPCNT;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_POPCNT))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_POPCNT;
 	if (!(TARGET_64BIT && (processor_alias_table[i].flags & PTA_NO_SAHF))
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SAHF))
-	  ix86_isa_flags |= OPTION_MASK_ISA_SAHF;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_SAHF))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_SAHF;
 	if (processor_alias_table[i].flags & PTA_MOVBE
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_MOVBE))
-	  ix86_isa_flags |= OPTION_MASK_ISA_MOVBE;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_MOVBE))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_MOVBE;
 	if (processor_alias_table[i].flags & PTA_AES
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_AES))
-	  ix86_isa_flags |= OPTION_MASK_ISA_AES;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_AES))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_AES;
 	if (processor_alias_table[i].flags & PTA_PCLMUL
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_PCLMUL))
-	  ix86_isa_flags |= OPTION_MASK_ISA_PCLMUL;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_PCLMUL))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_PCLMUL;
 	if (processor_alias_table[i].flags & PTA_FSGSBASE
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_FSGSBASE))
-	  ix86_isa_flags |= OPTION_MASK_ISA_FSGSBASE;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_FSGSBASE))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_FSGSBASE;
 	if (processor_alias_table[i].flags & PTA_RDRND
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_RDRND))
-	  ix86_isa_flags |= OPTION_MASK_ISA_RDRND;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_RDRND))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_RDRND;
 	if (processor_alias_table[i].flags & PTA_F16C
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_F16C))
-	  ix86_isa_flags |= OPTION_MASK_ISA_F16C;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_F16C))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_F16C;
 	if (processor_alias_table[i].flags & PTA_RTM
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_RTM))
-	  ix86_isa_flags |= OPTION_MASK_ISA_RTM;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_RTM))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_RTM;
 	if (processor_alias_table[i].flags & PTA_HLE
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_HLE))
-	  ix86_isa_flags |= OPTION_MASK_ISA_HLE;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_HLE))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_HLE;
 	if (processor_alias_table[i].flags & PTA_PRFCHW
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_PRFCHW))
-	  ix86_isa_flags |= OPTION_MASK_ISA_PRFCHW;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_PRFCHW))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_PRFCHW;
 	if (processor_alias_table[i].flags & PTA_RDSEED
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_RDSEED))
-	  ix86_isa_flags |= OPTION_MASK_ISA_RDSEED;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_RDSEED))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_RDSEED;
 	if (processor_alias_table[i].flags & PTA_ADX
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_ADX))
-	  ix86_isa_flags |= OPTION_MASK_ISA_ADX;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_ADX))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_ADX;
 	if (processor_alias_table[i].flags & PTA_FXSR
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_FXSR))
-	  ix86_isa_flags |= OPTION_MASK_ISA_FXSR;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_FXSR))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_FXSR;
 	if (processor_alias_table[i].flags & PTA_XSAVE
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_XSAVE))
-	  ix86_isa_flags |= OPTION_MASK_ISA_XSAVE;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_XSAVE))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_XSAVE;
 	if (processor_alias_table[i].flags & PTA_XSAVEOPT
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_XSAVEOPT))
-	  ix86_isa_flags |= OPTION_MASK_ISA_XSAVEOPT;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_XSAVEOPT))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_XSAVEOPT;
 	if (processor_alias_table[i].flags & PTA_AVX512F
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX512F))
-	  ix86_isa_flags |= OPTION_MASK_ISA_AVX512F;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX512F))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_AVX512F;
 	if (processor_alias_table[i].flags & PTA_AVX512ER
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX512ER))
-	  ix86_isa_flags |= OPTION_MASK_ISA_AVX512ER;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX512ER))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_AVX512ER;
 	if (processor_alias_table[i].flags & PTA_AVX512PF
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX512PF))
-	  ix86_isa_flags |= OPTION_MASK_ISA_AVX512PF;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX512PF))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_AVX512PF;
 	if (processor_alias_table[i].flags & PTA_AVX512CD
-	    && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX512CD))
-	  ix86_isa_flags |= OPTION_MASK_ISA_AVX512CD;
+	    && !(opts->x_ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX512CD))
+	  opts->x_ix86_isa_flags |= OPTION_MASK_ISA_AVX512CD;
 	if (processor_alias_table[i].flags & (PTA_PREFETCH_SSE | PTA_SSE))
 	  x86_prefetch_sse = true;
 
 	break;
       }
 
-  if (!strcmp (ix86_arch_string, "generic"))
+  if (!strcmp (opts->x_ix86_arch_string, "generic"))
     error ("generic CPU can be used only for %stune=%s %s",
 	   prefix, suffix, sw);
-  else if (!strncmp (ix86_arch_string, "generic", 7) || i == pta_size)
+  else if (!strncmp (opts->x_ix86_arch_string, "generic", 7) || i == pta_size)
     error ("bad value (%s) for %sarch=%s %s",
-	   ix86_arch_string, prefix, suffix, sw);
+	   opts->x_ix86_arch_string, prefix, suffix, sw);
 
   ix86_arch_mask = 1u << ix86_arch;
   for (i = 0; i < X86_ARCH_LAST; ++i)
     ix86_arch_features[i] = !!(initial_ix86_arch_features[i] & ix86_arch_mask);
 
   for (i = 0; i < pta_size; i++)
-    if (! strcmp (ix86_tune_string, processor_alias_table[i].name))
+    if (! strcmp (opts->x_ix86_tune_string, processor_alias_table[i].name))
       {
 	ix86_schedule = processor_alias_table[i].schedule;
 	ix86_tune = processor_alias_table[i].processor;
@@ -3617,9 +3623,9 @@  static void
 	      {
 		if (ix86_tune_defaulted)
 		  {
-		    ix86_tune_string = "x86-64";
+		    opts->x_ix86_tune_string = "x86-64";
 		    for (i = 0; i < pta_size; i++)
-		      if (! strcmp (ix86_tune_string,
+		      if (! strcmp (opts->x_ix86_tune_string,
 				    processor_alias_table[i].name))
 			break;
 		    ix86_schedule = processor_alias_table[i].schedule;
@@ -3657,9 +3663,9 @@  static void
 
   if (ix86_tune_specified && i == pta_size)
     error ("bad value (%s) for %stune=%s %s",
-	   ix86_tune_string, prefix, suffix, sw);
+	   opts->x_ix86_tune_string, prefix, suffix, sw);
 
-  set_ix86_tune_features (ix86_tune, ix86_dump_tunes);
+  set_ix86_tune_features (ix86_tune, opts->x_ix86_dump_tunes);
 
 #ifndef USE_IX86_FRAME_POINTER
 #define USE_IX86_FRAME_POINTER 0
@@ -3673,7 +3679,7 @@  static void
      in case they weren't overwritten by command line options.  */
   if (TARGET_64BIT)
     {
-      if (optimize >= 1 && !global_options_set.x_flag_omit_frame_pointer)
+      if (optimize >= 1 && !opts_set->x_flag_omit_frame_pointer)
 	flag_omit_frame_pointer = !USE_X86_64_FRAME_POINTER;
       if (flag_asynchronous_unwind_tables == 2)
 	flag_unwind_tables = flag_asynchronous_unwind_tables = 1;
@@ -3682,7 +3688,7 @@  static void
     }
   else
     {
-      if (optimize >= 1 && !global_options_set.x_flag_omit_frame_pointer)
+      if (optimize >= 1 && !opts_set->x_flag_omit_frame_pointer)
 	flag_omit_frame_pointer = !(USE_IX86_FRAME_POINTER || optimize_size);
       if (flag_asynchronous_unwind_tables == 2)
 	flag_asynchronous_unwind_tables = !USE_IX86_FRAME_POINTER;
@@ -3700,19 +3706,19 @@  static void
   init_machine_status = ix86_init_machine_status;
 
   /* Validate -mregparm= value.  */
-  if (global_options_set.x_ix86_regparm)
+  if (opts_set->x_ix86_regparm)
     {
       if (TARGET_64BIT)
 	warning (0, "-mregparm is ignored in 64-bit mode");
-      if (ix86_regparm > REGPARM_MAX)
+      if (opts->x_ix86_regparm > REGPARM_MAX)
 	{
 	  error ("-mregparm=%d is not between 0 and %d",
-		 ix86_regparm, REGPARM_MAX);
-	  ix86_regparm = 0;
+		 opts->x_ix86_regparm, REGPARM_MAX);
+	  opts->x_ix86_regparm = 0;
 	}
     }
   if (TARGET_64BIT)
-    ix86_regparm = REGPARM_MAX;
+    opts->x_ix86_regparm = REGPARM_MAX;
 
   /* Default align_* from the processor table.  */
   if (align_loops == 0)
@@ -3731,8 +3737,8 @@  static void
     }
 
   /* Provide default for -mbranch-cost= value.  */
-  if (!global_options_set.x_ix86_branch_cost)
-    ix86_branch_cost = ix86_cost->branch_cost;
+  if (!opts_set->x_ix86_branch_cost)
+    opts->x_ix86_branch_cost = ix86_cost->branch_cost;
 
   if (TARGET_64BIT)
     {
@@ -3742,9 +3748,10 @@  static void
 	 explicitly disable any of these.  In particular, disabling SSE and
 	 MMX for kernel code is extremely useful.  */
       if (!ix86_arch_specified)
-      ix86_isa_flags
+      opts->x_ix86_isa_flags
 	|= ((OPTION_MASK_ISA_SSE2 | OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_MMX
-	     | TARGET_SUBTARGET64_ISA_DEFAULT) & ~ix86_isa_flags_explicit);
+	     | TARGET_SUBTARGET64_ISA_DEFAULT)
+            & ~opts->x_ix86_isa_flags_explicit);
 
       if (TARGET_RTD)
 	warning (0, "%srtd%s is ignored in 64bit mode", prefix, suffix);
@@ -3754,8 +3761,8 @@  static void
       target_flags |= TARGET_SUBTARGET32_DEFAULT & ~target_flags_explicit;
 
       if (!ix86_arch_specified)
-      ix86_isa_flags
-	|= TARGET_SUBTARGET32_ISA_DEFAULT & ~ix86_isa_flags_explicit;
+      opts->x_ix86_isa_flags
+	|= TARGET_SUBTARGET32_ISA_DEFAULT & ~opts->x_ix86_isa_flags_explicit;
 
       /* i386 ABI does not specify red zone.  It still makes sense to use it
          when programmer takes care to stack from being destroyed.  */
@@ -3786,7 +3793,8 @@  static void
 
   /* Turn on MMX builtins for -msse.  */
   if (TARGET_SSE)
-    ix86_isa_flags |= OPTION_MASK_ISA_MMX & ~ix86_isa_flags_explicit;
+    opts->x_ix86_isa_flags
+      |= OPTION_MASK_ISA_MMX & ~opts->x_ix86_isa_flags_explicit;
 
   /* Enable SSE prefetch.  */
   if (TARGET_SSE || (TARGET_PRFCHW && !TARGET_3DNOW))
@@ -3794,49 +3802,52 @@  static void
 
   /* Enable prefetch{,w} instructions for -m3dnow.  */
   if (TARGET_3DNOW)
-    ix86_isa_flags |= OPTION_MASK_ISA_PRFCHW & ~ix86_isa_flags_explicit;
+    opts->x_ix86_isa_flags
+      |= OPTION_MASK_ISA_PRFCHW & ~opts->x_ix86_isa_flags_explicit;
 
   /* Enable popcnt instruction for -msse4.2 or -mabm.  */
   if (TARGET_SSE4_2 || TARGET_ABM)
-    ix86_isa_flags |= OPTION_MASK_ISA_POPCNT & ~ix86_isa_flags_explicit;
+    opts->x_ix86_isa_flags
+      |= OPTION_MASK_ISA_POPCNT & ~opts->x_ix86_isa_flags_explicit;
 
   /* Enable lzcnt instruction for -mabm.  */
   if (TARGET_ABM)
-    ix86_isa_flags |= OPTION_MASK_ISA_LZCNT & ~ix86_isa_flags_explicit;
+    opts->x_ix86_isa_flags
+      |= OPTION_MASK_ISA_LZCNT & ~opts->x_ix86_isa_flags_explicit;
 
   /* Validate -mpreferred-stack-boundary= value or default it to
      PREFERRED_STACK_BOUNDARY_DEFAULT.  */
   ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
-  if (global_options_set.x_ix86_preferred_stack_boundary_arg)
+  if (opts_set->x_ix86_preferred_stack_boundary_arg)
     {
       int min = (TARGET_64BIT ? (TARGET_SSE ? 4 : 3) : 2);
       int max = (TARGET_SEH ? 4 : 12);
 
-      if (ix86_preferred_stack_boundary_arg < min
-	  || ix86_preferred_stack_boundary_arg > max)
+      if (opts->x_ix86_preferred_stack_boundary_arg < min
+	  || opts->x_ix86_preferred_stack_boundary_arg > max)
 	{
 	  if (min == max)
 	    error ("-mpreferred-stack-boundary is not supported "
 		   "for this target");
 	  else
 	    error ("-mpreferred-stack-boundary=%d is not between %d and %d",
-		   ix86_preferred_stack_boundary_arg, min, max);
+		   opts->x_ix86_preferred_stack_boundary_arg, min, max);
 	}
       else
 	ix86_preferred_stack_boundary
-	  = (1 << ix86_preferred_stack_boundary_arg) * BITS_PER_UNIT;
+	  = (1 << opts->x_ix86_preferred_stack_boundary_arg) * BITS_PER_UNIT;
     }
 
   /* Set the default value for -mstackrealign.  */
-  if (ix86_force_align_arg_pointer == -1)
-    ix86_force_align_arg_pointer = STACK_REALIGN_DEFAULT;
+  if (opts->x_ix86_force_align_arg_pointer == -1)
+    opts->x_ix86_force_align_arg_pointer = STACK_REALIGN_DEFAULT;
 
   ix86_default_incoming_stack_boundary = PREFERRED_STACK_BOUNDARY;
 
   /* Validate -mincoming-stack-boundary= value or default it to
      MIN_STACK_BOUNDARY/PREFERRED_STACK_BOUNDARY.  */
   ix86_incoming_stack_boundary = ix86_default_incoming_stack_boundary;
-  if (global_options_set.x_ix86_incoming_stack_boundary_arg)
+  if (opts_set->x_ix86_incoming_stack_boundary_arg)
     {
       if (ix86_incoming_stack_boundary_arg < (TARGET_64BIT ? 4 : 2)
 	  || ix86_incoming_stack_boundary_arg > 12)
@@ -3856,32 +3867,32 @@  static void
       && ! TARGET_SSE)
     error ("%ssseregparm%s used without SSE enabled", prefix, suffix);
 
-  if (global_options_set.x_ix86_fpmath)
+  if (opts_set->x_ix86_fpmath)
     {
-      if (ix86_fpmath & FPMATH_SSE)
+      if (opts->x_ix86_fpmath & FPMATH_SSE)
 	{
 	  if (!TARGET_SSE)
 	    {
 	      warning (0, "SSE instruction set disabled, using 387 arithmetics");
-	      ix86_fpmath = FPMATH_387;
+	      opts->x_ix86_fpmath = FPMATH_387;
 	    }
-	  else if ((ix86_fpmath & FPMATH_387) && !TARGET_80387)
+	  else if ((opts->x_ix86_fpmath & FPMATH_387) && !TARGET_80387)
 	    {
 	      warning (0, "387 instruction set disabled, using SSE arithmetics");
-	      ix86_fpmath = FPMATH_SSE;
+	      opts->x_ix86_fpmath = FPMATH_SSE;
 	    }
 	}
     }
   else
-    ix86_fpmath = TARGET_FPMATH_DEFAULT;
+    opts->x_ix86_fpmath = TARGET_FPMATH_DEFAULT;
 
   /* If the i387 is disabled, then do not return values in it. */
   if (!TARGET_80387)
     target_flags &= ~MASK_FLOAT_RETURNS;
 
   /* Use external vectorized library in vectorizing intrinsics.  */
-  if (global_options_set.x_ix86_veclibabi_type)
-    switch (ix86_veclibabi_type)
+  if (opts_set->x_ix86_veclibabi_type)
+    switch (opts->x_ix86_veclibabi_type)
       {
       case ix86_veclibabi_type_svml:
 	ix86_veclib_handler = ix86_veclibabi_svml;
@@ -3946,20 +3957,20 @@  static void
 
   maybe_set_param_value (PARAM_SIMULTANEOUS_PREFETCHES,
 			 ix86_tune_cost->simultaneous_prefetches,
-			 global_options.x_param_values,
-			 global_options_set.x_param_values);
+			 opts->x_param_values,
+			 opts_set->x_param_values);
   maybe_set_param_value (PARAM_L1_CACHE_LINE_SIZE,
 			 ix86_tune_cost->prefetch_block,
-			 global_options.x_param_values,
-			 global_options_set.x_param_values);
+			 opts->x_param_values,
+			 opts_set->x_param_values);
   maybe_set_param_value (PARAM_L1_CACHE_SIZE,
 			 ix86_tune_cost->l1_cache_size,
-			 global_options.x_param_values,
-			 global_options_set.x_param_values);
+			 opts->x_param_values,
+			 opts_set->x_param_values);
   maybe_set_param_value (PARAM_L2_CACHE_SIZE,
 			 ix86_tune_cost->l2_cache_size,
-			 global_options.x_param_values,
-			 global_options_set.x_param_values);
+			 opts->x_param_values,
+			 opts_set->x_param_values);
 
   /* Enable sw prefetching at -O3 for CPUS that prefetching is helpful.  */
   if (flag_prefetch_loop_arrays < 0
@@ -4066,9 +4077,9 @@  static void
 	target_flags |= MASK_PREFER_AVX128;
     }
 
-  if (ix86_recip_name)
+  if (opts->x_ix86_recip_name)
     {
-      char *p = ASTRDUP (ix86_recip_name);
+      char *p = ASTRDUP (opts->x_ix86_recip_name);
       char *q;
       unsigned int mask, i;
       bool invert;
@@ -4125,23 +4136,24 @@  static void
      options.  */
   if (main_args_p)
     target_option_default_node = target_option_current_node
-      = build_target_option_node ();
+      = build_target_option_node (opts);
 
   /* Handle stack protector */
-  if (!global_options_set.x_ix86_stack_protector_guard)
-    ix86_stack_protector_guard = TARGET_HAS_BIONIC ? SSP_GLOBAL : SSP_TLS;
+  if (!opts_set->x_ix86_stack_protector_guard)
+    opts->x_ix86_stack_protector_guard
+      = TARGET_HAS_BIONIC ? SSP_GLOBAL : SSP_TLS;
 
   /* Handle -mmemcpy-strategy= and -mmemset-strategy=  */
-  if (ix86_tune_memcpy_strategy)
+  if (opts->x_ix86_tune_memcpy_strategy)
     {
-      char *str = xstrdup (ix86_tune_memcpy_strategy);
+      char *str = xstrdup (opts->x_ix86_tune_memcpy_strategy);
       ix86_parse_stringop_strategy_string (str, false);
       free (str);
     }
 
-  if (ix86_tune_memset_strategy)
+  if (opts->x_ix86_tune_memset_strategy)
     {
-      char *str = xstrdup (ix86_tune_memset_strategy);
+      char *str = xstrdup (opts->x_ix86_tune_memset_strategy);
       ix86_parse_stringop_strategy_string (str, true);
       free (str);
     }
@@ -4158,7 +4170,7 @@  ix86_option_override (void)
 	1, PASS_POS_INSERT_AFTER
       };
 
-  ix86_option_override_internal (true);
+  ix86_option_override_internal (true, &global_options, &global_options_set);
 
 
   /* This needs to be done at start up.  It's convenient to do it here.  */
@@ -4337,6 +4349,8 @@  ix86_function_specific_print (FILE *file, int inde
 
 static bool
 ix86_valid_target_attribute_inner_p (tree args, char *p_strings[],
+				     struct gcc_options *opts,
+				     struct gcc_options *opts_set,
 				     struct gcc_options *enum_opts_set)
 {
   char *next_optstr;
@@ -4453,7 +4467,8 @@  ix86_valid_target_attribute_inner_p (tree args, ch
       for (; args; args = TREE_CHAIN (args))
 	if (TREE_VALUE (args)
 	    && !ix86_valid_target_attribute_inner_p (TREE_VALUE (args),
-						     p_strings, enum_opts_set))
+						     p_strings, opts, opts_set,
+						     enum_opts_set))
 	  ret = false;
 
       return ret;
@@ -4536,7 +4551,7 @@  ix86_valid_target_attribute_inner_p (tree args, ch
 	  struct cl_decoded_option decoded;
 
 	  generate_option (opt, NULL, opt_set_p, CL_TARGET, &decoded);
-	  ix86_handle_option (&global_options, &global_options_set,
+	  ix86_handle_option (opts, opts_set,
 			      &decoded, input_location);
 	}
 
@@ -4569,7 +4584,7 @@  ix86_valid_target_attribute_inner_p (tree args, ch
 
 	  arg_ok = opt_enum_arg_to_value (opt, p + opt_len, &value, CL_TARGET);
 	  if (arg_ok)
-	    set_option (&global_options, enum_opts_set, opt, value,
+	    set_option (opts, enum_opts_set, opt, value,
 			p + opt_len, DK_UNSPECIFIED, input_location,
 			global_dc);
 	  else
@@ -4587,13 +4602,14 @@  ix86_valid_target_attribute_inner_p (tree args, ch
 }
 
 /* Return a TARGET_OPTION_NODE tree of the target options listed or NULL.  */
-
 tree
-ix86_valid_target_attribute_tree (tree args)
+ix86_valid_target_attribute_tree (tree args,
+				  struct gcc_options *opts,
+				  struct gcc_options *opts_set)
 {
   const char *orig_arch_string = ix86_arch_string;
   const char *orig_tune_string = ix86_tune_string;
-  enum fpmath_unit orig_fpmath_set = global_options_set.x_ix86_fpmath;
+  enum fpmath_unit orig_fpmath_set = opts_set->x_ix86_fpmath;
   int orig_tune_defaulted = ix86_tune_defaulted;
   int orig_arch_specified = ix86_arch_specified;
   char *option_strings[IX86_FUNCTION_SPECIFIC_MAX] = { NULL, NULL };
@@ -4606,16 +4622,16 @@  tree
   memset (&enum_opts_set, 0, sizeof (enum_opts_set));
 
   /* Process each of the options on the chain.  */
-  if (! ix86_valid_target_attribute_inner_p (args, option_strings,
-					     &enum_opts_set))
+  if (! ix86_valid_target_attribute_inner_p (args, option_strings, opts,
+					     opts_set, &enum_opts_set))
     return error_mark_node;
 
   /* If the changed options are different from the default, rerun
      ix86_option_override_internal, and then save the options away.
      The string options are are attribute options, and will be undone
      when we copy the save structure.  */
-  if (ix86_isa_flags != def->x_ix86_isa_flags
-      || target_flags != def->x_target_flags
+  if (opts->x_ix86_isa_flags != def->x_ix86_isa_flags
+      || opts->x_target_flags != def->x_target_flags
       || option_strings[IX86_FUNCTION_SPECIFIC_ARCH]
       || option_strings[IX86_FUNCTION_SPECIFIC_TUNE]
       || enum_opts_set.x_ix86_fpmath)
@@ -4623,37 +4639,37 @@  tree
       /* If we are using the default tune= or arch=, undo the string assigned,
 	 and use the default.  */
       if (option_strings[IX86_FUNCTION_SPECIFIC_ARCH])
-	ix86_arch_string = option_strings[IX86_FUNCTION_SPECIFIC_ARCH];
+	opts->x_ix86_arch_string = option_strings[IX86_FUNCTION_SPECIFIC_ARCH];
       else if (!orig_arch_specified)
-	ix86_arch_string = NULL;
+	opts->x_ix86_arch_string = NULL;
 
       if (option_strings[IX86_FUNCTION_SPECIFIC_TUNE])
-	ix86_tune_string = option_strings[IX86_FUNCTION_SPECIFIC_TUNE];
+	opts->x_ix86_tune_string = option_strings[IX86_FUNCTION_SPECIFIC_TUNE];
       else if (orig_tune_defaulted)
-	ix86_tune_string = NULL;
+	opts->x_ix86_tune_string = NULL;
 
       /* If fpmath= is not set, and we now have sse2 on 32-bit, use it.  */
       if (enum_opts_set.x_ix86_fpmath)
-	global_options_set.x_ix86_fpmath = (enum fpmath_unit) 1;
+	opts_set->x_ix86_fpmath = (enum fpmath_unit) 1;
       else if (!TARGET_64BIT && TARGET_SSE)
 	{
-	  ix86_fpmath = (enum fpmath_unit) (FPMATH_SSE | FPMATH_387);
-	  global_options_set.x_ix86_fpmath = (enum fpmath_unit) 1;
+	  opts->x_ix86_fpmath = (enum fpmath_unit) (FPMATH_SSE | FPMATH_387);
+	  opts_set->x_ix86_fpmath = (enum fpmath_unit) 1;
 	}
 
       /* Do any overrides, such as arch=xxx, or tune=xxx support.  */
-      ix86_option_override_internal (false);
+      ix86_option_override_internal (false, opts, opts_set);
 
       /* Add any builtin functions with the new isa if any.  */
-      ix86_add_new_builtins (ix86_isa_flags);
+      ix86_add_new_builtins (opts->x_ix86_isa_flags);
 
       /* Save the current options unless we are validating options for
 	 #pragma.  */
-      t = build_target_option_node ();
+      t = build_target_option_node (opts);
 
-      ix86_arch_string = orig_arch_string;
-      ix86_tune_string = orig_tune_string;
-      global_options_set.x_ix86_fpmath = orig_fpmath_set;
+      opts->x_ix86_arch_string = orig_arch_string;
+      opts->x_ix86_tune_string = orig_tune_string;
+      opts_set->x_ix86_fpmath = orig_fpmath_set;
 
       /* Free up memory allocated to hold the strings */
       for (i = 0; i < IX86_FUNCTION_SPECIFIC_MAX; i++)
@@ -4671,7 +4687,8 @@  ix86_valid_target_attribute_p (tree fndecl,
 			       tree args,
 			       int ARG_UNUSED (flags))
 {
-  struct cl_target_option cur_target;
+  struct gcc_options func_options;
+  tree new_target, new_optimize;
   bool ret = true;
 
   /* attribute((target("default"))) does nothing, beyond
@@ -4682,22 +4699,29 @@  ix86_valid_target_attribute_p (tree fndecl,
       && strcmp (TREE_STRING_POINTER (TREE_VALUE (args)), "default") == 0)
     return true;
 
-  tree old_optimize = build_optimization_node ();
-  tree new_target, new_optimize;
+  tree old_optimize = build_optimization_node (&global_options);
+
+  /* Get the optimization options of the current function.  */  
   tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
+ 
+  if (!func_optimize)
+    func_optimize = old_optimize;
 
-  /* 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,
-			     TREE_OPTIMIZATION (func_optimize));
+  memset (&func_options, 0, sizeof (func_options));
+ 
+  cl_optimization_restore (&func_options,
+			   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);
-  new_target = ix86_valid_target_attribute_tree (args);
-  new_optimize = build_optimization_node ();
+  /* Initialize func_options to the default before its target options can
+     be set.  */
+  cl_target_option_restore (&func_options,
+			    TREE_TARGET_OPTION (target_option_default_node));
 
+  new_target = ix86_valid_target_attribute_tree (args, &func_options,
+						 &global_options_set);
+
+  new_optimize = build_optimization_node (&func_options);
+
   if (new_target == error_mark_node)
     ret = false;
 
@@ -4709,12 +4733,6 @@  ix86_valid_target_attribute_p (tree fndecl,
 	DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
     }
 
-  cl_target_option_restore (&global_options, &cur_target);
-
-  if (old_optimize != new_optimize)
-    cl_optimization_restore (&global_options,
-			     TREE_OPTIMIZATION (old_optimize));
-
   return ret;
 }
 
@@ -29327,7 +29345,8 @@  get_builtin_code_for_version (tree decl, tree *pre
   if (strstr (attrs_str, "arch=") != NULL)
     {
       cl_target_option_save (&cur_target, &global_options);
-      target_node = ix86_valid_target_attribute_tree (attrs);
+      target_node = ix86_valid_target_attribute_tree (attrs, &global_options,
+						      &global_options_set);
     
       gcc_assert (target_node);
       new_target = TREE_TARGET_OPTION (target_node);
Index: config/i386/i386-c.c
===================================================================
--- config/i386/i386-c.c	(revision 202662)
+++ config/i386/i386-c.c	(working copy)
@@ -370,7 +370,7 @@  ix86_target_macros_internal (HOST_WIDE_INT isa_fla
 static bool
 ix86_pragma_target_parse (tree args, tree pop_target)
 {
-  tree prev_tree = build_target_option_node ();
+  tree prev_tree = build_target_option_node (&global_options);
   tree cur_tree;
   struct cl_target_option *prev_opt;
   struct cl_target_option *cur_opt;
@@ -390,7 +390,8 @@  ix86_pragma_target_parse (tree args, tree pop_targ
     }
   else
     {
-      cur_tree = ix86_valid_target_attribute_tree (args);
+      cur_tree = ix86_valid_target_attribute_tree (args, &global_options,
+						   &global_options_set);
       if (!cur_tree || cur_tree == error_mark_node)
        {
          cl_target_option_restore (&global_options,
Index: config/i386/i386-protos.h
===================================================================
--- config/i386/i386-protos.h	(revision 202662)
+++ config/i386/i386-protos.h	(working copy)
@@ -220,7 +220,9 @@  extern int ix86_constant_alignment (tree, int);
 extern tree ix86_handle_shared_attribute (tree *, tree, tree, int, bool *);
 extern tree ix86_handle_selectany_attribute (tree *, tree, tree, int, bool *);
 extern int x86_field_alignment (tree, int);
-extern tree ix86_valid_target_attribute_tree (tree);
+extern tree ix86_valid_target_attribute_tree (tree,
+					      struct gcc_options *,
+					      struct gcc_options *);
 extern unsigned int ix86_get_callcvt (const_tree);
 
 #endif
Index: config/rs6000/rs6000.c
===================================================================
--- config/rs6000/rs6000.c	(revision 202662)
+++ config/rs6000/rs6000.c	(working copy)
@@ -3664,7 +3664,7 @@  rs6000_option_override_internal (bool global_init_
   /* 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 ();
+      = build_target_option_node (&global_options);
 
   /* 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).  */
@@ -29434,7 +29434,7 @@  rs6000_valid_attribute_p (tree fndecl,
 {
   struct cl_target_option cur_target;
   bool ret;
-  tree old_optimize = build_optimization_node ();
+  tree old_optimize = build_optimization_node (&global_options);
   tree new_target, new_optimize;
   tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
 
@@ -29461,7 +29461,7 @@  rs6000_valid_attribute_p (tree fndecl,
       fprintf (stderr, "--------------------\n");
     }
 
-  old_optimize = build_optimization_node ();
+  old_optimize = build_optimization_node (&global_options);
   func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
 
   /* If the function changed the optimization levels as well as setting target
@@ -29480,12 +29480,12 @@  rs6000_valid_attribute_p (tree fndecl,
   if (ret)
     {
       ret = rs6000_option_override_internal (false);
-      new_target = build_target_option_node ();
+      new_target = build_target_option_node (&global_options);
     }
   else
     new_target = NULL;
 
-  new_optimize = build_optimization_node ();
+  new_optimize = build_optimization_node (&global_options);
 
   if (!new_target)
     ret = false;
@@ -29515,7 +29515,7 @@  rs6000_valid_attribute_p (tree fndecl,
 bool
 rs6000_pragma_target_parse (tree args, tree pop_target)
 {
-  tree prev_tree = build_target_option_node ();
+  tree prev_tree = build_target_option_node (&global_options);
   tree cur_tree;
   struct cl_target_option *prev_opt, *cur_opt;
   HOST_WIDE_INT prev_flags, cur_flags, diff_flags;
@@ -29552,7 +29552,8 @@  rs6000_pragma_target_parse (tree args, tree pop_ta
       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 ()) == NULL_TREE)
+	  || (cur_tree = build_target_option_node (&global_options))
+	     == NULL_TREE)
 	{
 	  if (TARGET_DEBUG_BUILTIN || TARGET_DEBUG_TARGET)
 	    fprintf (stderr, "invalid pragma\n");
Index: testsuite/gcc.target/i386/pr57756.c
===================================================================
--- testsuite/gcc.target/i386/pr57756.c	(revision 0)
+++ testsuite/gcc.target/i386/pr57756.c	(revision 0)
@@ -0,0 +1,20 @@ 
+/* callee cannot be inlined into caller because it has a higher
+   target ISA.  */
+/* { dg-do compile } */
+
+__attribute__((always_inline,target("sse4.2")))
+__inline int callee () /* { dg-error "inlining failed in call to always_inline" }  */
+{
+  return 0;
+}
+
+__attribute__((target("sse")))
+__inline int caller ()
+{
+  return callee(); /* { dg-error "called from here" }  */
+}
+
+int main ()
+{
+  return caller();
+}
Index: toplev.c
===================================================================
--- toplev.c	(revision 202662)
+++ toplev.c	(working copy)
@@ -1573,7 +1573,7 @@  process_options (void)
                                     DK_ERROR, UNKNOWN_LOCATION);
 
   /* Save the current optimization options.  */
-  optimization_default_node = build_optimization_node ();
+  optimization_default_node = build_optimization_node (&global_options);
   optimization_current_node = optimization_default_node;
 }
 
Index: tree.c
===================================================================
--- tree.c	(revision 202662)
+++ tree.c	(working copy)
@@ -11486,10 +11486,10 @@  cl_option_hash_eq (const void *x, const void *y)
   return (memcmp (xp, yp, len) == 0);
 }
 
-/* Build an OPTIMIZATION_NODE based on the current options.  */
+/* Build an OPTIMIZATION_NODE based on the options in OPTS.  */
 
 tree
-build_optimization_node (void)
+build_optimization_node (struct gcc_options *opts)
 {
   tree t;
   void **slot;
@@ -11497,7 +11497,7 @@  tree
   /* Use the cache of optimization nodes.  */
 
   cl_optimization_save (TREE_OPTIMIZATION (cl_optimization_node),
-			&global_options);
+			opts);
 
   slot = htab_find_slot (cl_option_hash_table, cl_optimization_node, INSERT);
   t = (tree) *slot;
@@ -11514,10 +11514,10 @@  tree
   return t;
 }
 
-/* Build a TARGET_OPTION_NODE based on the current options.  */
+/* Build a TARGET_OPTION_NODE based on the options in OPTS.  */
 
 tree
-build_target_option_node (void)
+build_target_option_node (struct gcc_options *opts)
 {
   tree t;
   void **slot;
@@ -11525,7 +11525,7 @@  tree
   /* Use the cache of optimization nodes.  */
 
   cl_target_option_save (TREE_TARGET_OPTION (cl_target_option_node),
-			 &global_options);
+			 opts);
 
   slot = htab_find_slot (cl_option_hash_table, cl_target_option_node, INSERT);
   t = (tree) *slot;
Index: tree.h
===================================================================
--- tree.h	(revision 202662)
+++ tree.h	(working copy)
@@ -2584,16 +2584,16 @@  extern vec<tree, va_gc> **decl_debug_args_insert (
 #define TREE_OPTIMIZATION_BASE_OPTABS(NODE) \
   (OPTIMIZATION_NODE_CHECK (NODE)->optimization.base_optabs)
 
-/* Return a tree node that encapsulates the current optimization options.  */
-extern tree build_optimization_node (void);
+/* Return a tree node that encapsulates the optimization options in OPTS.  */
+extern tree build_optimization_node (struct gcc_options *opts);
 
 extern void init_tree_optimization_optabs (tree);
 
 #define TREE_TARGET_OPTION(NODE) \
   (&TARGET_OPTION_NODE_CHECK (NODE)->target_option.opts)
 
-/* Return a tree node that encapsulates the current target options.  */
-extern tree build_target_option_node (void);
+/* Return a tree node that encapsulates the target options in OPTS.  */
+extern tree build_target_option_node (struct gcc_options *opts);
 
 #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)