[PATCH, function-specific, committed] Add #pragma GCC option/optimize, attribute((optimize))

Michael Meissner michael.meissner@amd.com
Mon Jun 23 14:57:00 GMT 2008


This patch should complete the basic patches for stage2 of the function
specific work.  It adds #pragma GCC optimize and attribute((optimize)) to allow
users to set the optimization level on a per function basis (and yes, you
can set individual optimization options, as several of the people asked for
after my last patch).  Sample code:

#pragma GCC optimize (3,"unroll-all-loops")
void func1 (void) { ... }
void func2 (void) { ... }

#pragma GCC optimize (reset)
void func3 (void) __attribute__((__optimize__("Os")));

Using #pragma GCC option also changes the target specific #defines.  For
example:

#pragma GCC option ("sse5")
#ifdef __SSE5__
       /* this will be defined after the pragma.  */
#endif

#pragma GCC option (reset)
#ifdef __SSE5__
       /* this will not be defined after the pragma unless you used -msse5 on
	  the compilation line.  */
#endif

[gcc]
2008-06-22  Michael Meissner  <michael.meissner@amd.com>

	* attribs.c (toplevel): Add c-common.h include file.
	(decl_attributes): Convert #pragma GCC optimize into
	attribute((optimize(...))), and #pragma GCC option into
	attribute((option(...))).

	* doc/extend.texi: Update option attribute documentation.
	Document optimize attribute.  Document that the hot attribute
	turns on -O3 optimization for the function.  Document that the
	cold attribute turns on -Os optimization for the function.
	Document #pragma GCC option.  Document #pragma GCC optimize.

	* doc/options.texi (UInteger): Document UInteger must be used on
	options that that a flag word with a joined option like
	-falign-loops.

	* doc/tm.texi (TARGET_VALID_OPTION_ATTRIBUTE_P): Update
	documentation.
	(TARGET_OPTION_SAVE): Document new hook.
	(TARGET_OPTION_RESTORE): Ditto.
	(TARGET_OPTION_PRINT): Ditto.
	(TARGET_OPTION_PRAGMA_PARSE): Ditto.

	* tree.c (cl_optimization_node): New static node to build
	OPTIMIZATION_NODE's.
	(cl_target_option_node): New static node to build
	TARGET_OPTION_NODE's.
	(cl_option_hash_table): New static hash table to hold
	OPTIMIZATION_NODE and TARGET_OPTION_NODE's.
	(cl_option_hash_eq): New function for hashing OPTIMIZATION_NODE
	and TARGET_OPTION_NODE's.
	(cl_option_hash_hash): Ditto.
	(init_tree): Make the cl_optimization_node and
	cl_target_option_node.
	(build_optimization_node): New function to return a tree that
	includes all of the optimization options.
	(build_target_option_ndoe): New function to return a tree that
	includes the target options that can be specified for target
	specific optimization.

	* tree.h (build_optimization_node): Add declaration.
	(build_target_option_node): Ditto.
	(enum tree_index): Add TI_OPTIMIZATION_HOT,
	TI_TARGET_OPTION_CURRENT, TI_CURRENT_OPTIMIZE_PRAGMA.
	(optimization_hot_node): New global_trees variable.
	(target_option_current_node): Ditto.
	(current_optimize_pragma): Ditto.

	* target.h (struct gcc_target): Add target_option_pragma_parse to
	implement #pragma GCC option.

	* toplev.h (parse_optimize_options): Add declaration.
	(fast_math_flags_struct_set_p): Ditto.

	* c-cppbuiltin.c (c_cpp_builtins_optimize_pragma): New function
	to adjust #defines after a #pragma GCC optimize.

	* opts.c (decode_options): Allow function to be called more than
	once to support attribute((optimize(...))).  Build initial
	optimization nodes.
	(fast_math_flags_struct_set_p): New function, analog of
	fast_math_flags_set_p, except take cl_optimization structure
	pointer instead of looking at global variables.

	* optc-gen.awk: Fix thinko in handling short fields.  Add some
	extra blank lines.

	* function.c (invoke_set_current_function_block): Update a
	comment.

	* c-pragma.c (handle_pragma_option): Allow optional ().  Change to
	use the target_option_pragma_parse hook.  Break some long lines.
	(optimize_stack): New VEC to track #pragma GCC optimize.
	(handle_pragma_optimize): Add #pragma GCC optimize support.
	(init_pragma): Register handle_pragma_optimize.

	* opth-gen.awk: Fix thinko in handling short fields.

	* common.opt (-O): Add Optimization specifier.
	(-Os): Ditto.
	(-falign-functions): Add UInteger option so field is stored as a
	full size int in the cl_optimization structure.  Add
	Optimization.
	(-falign-jumps): Ditto.
	(-falign-labels): Ditto.
	(-falign-loops): Ditto.
	(-fsched-stalled-insns): Ditto.
	(-fsched-stalled-insns-dep): Ditto.
	(-fmath-errno): Add Optimization option so that we can adjust
	__FINITE_MATH__ define in #pragma GCC optimize.

	* target-def.h (TARGET_OPTION_PRAGMA_PARSE): Add new hook.
	(TARGET_INITIALIZER): Add TARGET_OPTION_PRAGMA_PARSE.

	* tree-inline.c (tree_can_inline_p): Don't allow a function to
	inline a function with a higher optimization level than itself, or
	a different space/time tradeoff.

	* opt-functions.awk (var_type_struct): Move UInteger handling
	above Joined so the right type is returned.

	* c-common.c (handle_optimize_attribute): New attribute to
	handling setting optimization options.
	(c_common_attribute): Add "optimize" attribute.
	(handle_hot_attribute): Set optimization level to -O3.
	(handle_cold_attribute): Update setting optimization level to
	-Os.
	(optimize_args): New static vector for the command line arguments
	to attribute((optimize(...))).
	(parse_optimize_options): New function that is common code between
	attribute((optimize(...))) and #pragma GCC optimize to parse and
	set the optimization options.

	* c-common.h (c_cpp_builtins_optimize_pragma): Add declaration.
	(builtin_define_std): Ditto.

	* config.gcc (x86_64-*-darwin*): Make sure tmake_file includes
	previoius tmake_file's.  Make sure c_target_objs includes previous
	c_target_objs.
	(i[34567]86-*-elf*): Ditto.
	(x86_64-*-elf*): Ditto.
	(i[34567]86-*-netbsd*): Ditto.
	(i[34567]86-*-openbsd2.*): Ditto.
	(i[34567]86-*openbsd3.[0123]): Ditto.
	(i[34567]86-pc-msdosdjgpp*): Ditto.
	(i[34567]86-*-lynxos*): Ditto.
	(i[3456x]86-*-netware*): Ditto.
	(i[34567]86-*-nto-qnx*): Ditto.
	(i[34567]86-*-rtems*): Ditto.
	(i[34567]86-*-solaris2*): Ditto.
	(i[34567]86-*-pe): Ditto.
	(i[34567]86-*-cygwin*): Ditto.
	(i[34567]86-*-mingw*): Ditto.
	(x86_64-*-mingw*): Ditto.
	(i[34567]86-*-interix3*): Ditto.
	(i[34567]86-*-linux*): Add i386/t-i386 as a new Makefile fragment.
	(x86_64-*-linux*): Ditto.
	(i[34567]86-*-*): Ditto.
	(x86_64-*-*): Ditto.

	* config/i386/i386.h (TARGET_CPU_CPP_BUILTINS): Move to
	ix86_target_macros.

	* config/i386/i386-c.c: New file for macro/preprocessor support.
	(ix86_target_macros_internal): New function to #define or #undef
	target specific macros.
	(ix86_target_macros): New function, set up all of the target
	macros like __SSE__.
	(ix86_function_specific_target_macros): New function to update the
	target macros based on the #pragma GCC option's used.

	* config/i386/t-i386: New file, add more dependencies for i386.o.
	Add new file i386-c.o.

	* config/i386/i386-protos.h (ix86_target_macros): Add declaration.
	(ix86_valid_option_attribute_tree): Ditto.

	* config/i386/i386.c (ix86_valid_option_attribute_tree): New
	function, split from ix86_valid_option_attribute_p, to be common
	code between attribute and pragma parsing.
	(ix86_valid_option_attribute_p): Move most of the code to
	ix86_valid_option_attribute_tree.
	(ix86_pragma_option_parse): New hook for #pragma GCC option
	support.
	(override_options): Use build_target_option_node to build the
	initial target option node.
	(ix86_function_specific_restore): Save some time if the arch or
	tune variables were not changed.
	(ix86_function_specific_print): Decode the target options.
	(ix86_insert_attributes): Delete, move #pragma GCC option handling
	into decl_attributes.
	(ix86_current_target): New static to remember the current target
	options.
	(ix86_previous_fndecl): New static to track last declaration
	passed to ix86_set_current_function.
	(ix86_set_current_function): Rewrite how the target options are
	set up and when to call target_reinit.  Use the current target
	options intead of the default options, so that #pragma GCC option
	works correctly.
	(ix86_init_builtins): Merge ix86_init_mmx_sse_builtins with this
	code, remove test for -mmmx.
	(ix86_init_mmx_sse_builtins): Merge into ix86_init_builtins.
	(TARGET_INSERT_ATTRIBUTES): Go back to the original code for
	machine dependent inserting attributes.

[gcc/testsuite]
2008-06-22  Michael Meissner  <michael.meissner@amd.com>

	* gcc.target/i386/opt-1.c: New file.

	* gcc.target/i386/cold-1.c: Allow jmp and call strcpy.

	* gcc.target/i386/funcspec-1.c: Add a test to make sure 387 code
	is generated if attribute((option("sse2"))) is not in effect.

	* gcc.target/i386/hot-1.c: New file.

	* gcc.target/i386/funcspec-9.c: New file.

	* gcc.target/i386/sse-22.c: New file.

	* gcc.target/i386/sse-23.c: New file.

Index: gcc/attribs.c
===================================================================
--- gcc/attribs.c	(revision 136933)
+++ gcc/attribs.c	(working copy)
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  
 #include "target.h"
 #include "langhooks.h"
 #include "hashtab.h"
+#include "c-common.h"
 
 static void init_attributes (void);
 
@@ -231,6 +232,44 @@ decl_attributes (tree *node, tree attrib
   if (!attributes_initialized)
     init_attributes ();
 
+  /* If this is a function, do we have a pragma optimization to set the
+     optimization flags add it to the optimization attribute.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL && current_optimize_pragma)
+    {
+      tree cur_attr = lookup_attribute ("optimize", attributes);
+      tree opts = copy_list (current_optimize_pragma);
+
+      if (! cur_attr)
+	attributes
+	  = tree_cons (get_identifier ("optimize"), opts, attributes);
+      else
+	TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr));
+    }
+
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && optimization_current_node != optimization_default_node
+      && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node))
+    DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) = optimization_current_node;
+
+  /* If this is a function, do we have a pragma option to set the target
+     flags?  If so, add it and re-validate it, which will create the
+     appropriate target option node in the node.  */
+
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && current_option_pragma
+      && targetm.valid_option_attribute_p
+      && targetm.valid_option_attribute_p (*node, NULL_TREE,
+					   current_option_pragma, 0))
+    {
+      tree cur_attr = lookup_attribute ("option", attributes);
+      tree opts = copy_list (current_option_pragma);
+
+      if (! cur_attr)
+	attributes = tree_cons (get_identifier ("option"), opts, attributes);
+      else
+	TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr));
+    }
+
   targetm.insert_attributes (*node, &attributes);
 
   for (a = attributes; a; a = TREE_CHAIN (a))
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 136933)
+++ gcc/doc/extend.texi	(working copy)
@@ -1793,6 +1793,7 @@ the enclosing block.
 @cindex functions that pop the argument stack on the 386
 @cindex functions that do not pop the argument stack on the 386
 @cindex functions that have different compilation options on the 386
+@cindex functions that have different optimization options
 
 In GNU C, you declare certain things about functions called in your program
 which help the compiler optimize function calls and check your code more
@@ -2667,20 +2668,30 @@ implemented in GCC versions earlier than
 @item option
 @cindex @code{option} function attribute
 The @code{option} attribute is used to specify that a function is to
-be compiled with different options than specified on the command line.
-This can be used for instance to have functions compiled with a
-different ISA (instruction set architecture) than the default.  For
-instance on a 386, you could compile one function with
+be compiled with different target options than specified on the
+command line.  This can be used for instance to have functions
+compiled with a different ISA (instruction set architecture) than the
+default.  You can also use the @samp{#pragma GCC option} pragma to set
+more than one function to be compiled with specific target options.
+@xref{Function Specific Option Pragmas}, for details about the
+@samp{#pragma GCC option} pragma.
+
+For instance on a 386, you could compile one function with
 @code{option("sse4.1,arch=core2")} and another with
 @code{option("sse4a,arch=amdfam10")} that would be equivalent to
-compiling the first function with @code{-msse4.1} and
-@code{-march=core2} options, and the second function with
-@code{-msse4a} and @code{-march=amdfam10} options.  It is up to the
+compiling the first function with @option{-msse4.1} and
+@option{-march=core2} options, and the second function with
+@option{-msse4a} and @option{-march=amdfam10} options.  It is up to the
 user to make sure that a function is only invoked on a machine that
 supports the particular ISA it was compiled for (for example by using
 @code{cpuid} on 386 to determine what feature bits and architecture
 family are used).
 
+@smallexample
+int core2_func (void) __attribute__ ((__option__ ("arch=core2")));
+int sse3_func (void) __attribute__ ((__option__ ("sse3")));
+@end smallexample
+
 On the 386, the following options are allowed:
 
 @table @samp
@@ -2827,6 +2838,34 @@ target options of the caller.  For examp
 The @code{option} attribute is not implemented in GCC versions earlier
 than 4.4, and at present only the 386 uses it.
 
+@item optimize
+@cindex @code{optimize} function attribute
+The @code{optimize} attribute is used to specify that a function is to
+be compiled with different optimization options than specified on the
+command line.  Arguments can either be numbers or strings.  Numbers
+are assumed to be an optimization level.  Strings that begin with
+@code{O} are assumed to be an optimization option, while other options
+are assumed to be used with a @code{-f} prefix.  You can also use the
+@samp{#pragma GCC optimize} pragma to set the optimization options
+that affect more than one function.
+@xref{Function Specific Option Pragmas}, for details about the
+@samp{#pragma GCC option} pragma.
+
+This can be used for instance to have frequently executed functions
+compiled with more aggressive optimization options that produce faster
+and larger code, while other functions can be called with less
+agressive options.  The @code{hot} attribute implies
+@code{optimize("O3")}, and @code{cold} attribute implies
+@code{optimize("Os")}.
+
+@smallexample
+int fast_func (void) __attribute__ ((__optimize__ ("O3,unroll-loops")));
+int slow_func (void) __attribute__ ((__optimize__ ("Os")));
+@end smallexample
+
+The inliner will not inline functions with a higher optimization level
+than the caller or different space/time trade offs.
+
 @item pure
 @cindex @code{pure} function attribute
 Many functions have no effects except the return value and their
@@ -2862,7 +2901,11 @@ all hot functions appears close together
 When profile feedback is available, via @option{-fprofile-use}, hot functions
 are automatically detected and this attribute is ignored.
 
-The @code{hot} attribute is not implemented in GCC versions earlier than 4.3.
+The @code{hot} attribute is not implemented in GCC versions earlier
+than 4.3.
+
+Starting with GCC 4.4, the @code{hot} attribute sets
+@code{optimize("O3")} to turn on more aggressive optimization.
 
 @item cold
 @cindex @code{cold} function attribute
@@ -2879,7 +2922,10 @@ occasions.
 When profile feedback is available, via @option{-fprofile-use}, hot functions
 are automatically detected and this attribute is ignored.
 
-The @code{hot} attribute is not implemented in GCC versions earlier than 4.3.
+The @code{cold} attribute is not implemented in GCC versions earlier than 4.3.
+
+Starting with GCC 4.4, the @code{cold} attribute sets
+@code{optimize("Os")} to save space.
 
 @item regparm (@var{number})
 @cindex @code{regparm} attribute
@@ -11263,7 +11309,7 @@ for further explanation.
 * Diagnostic Pragmas::
 * Visibility Pragmas::
 * Push/Pop Macro Pragmas::
-* Target Option Pragmas::
+* Function Specific Option Pragmas::
 @end menu
 
 @node ARM Pragmas
@@ -11614,37 +11660,78 @@ int x [X]; 
 In this example, the definition of X as 1 is saved by @code{#pragma
 push_macro} and restored by @code{#pragma pop_macro}.
 
-@node Target Option Pragmas
-@subsection Target Option Pragmas
+@node Function Specific Option Pragmas
+@subsection Function Specific Option Pragmas
 
 @table @code
-@item #pragma GCC option @var{"string"}...
+@item #pragma GCC option (@var{"string"}...)
 @cindex pragma GCC option
 
 This pragma allows you to set target specific options for functions
 defined later in the source file.  One or more strings can be
 specified.  Each function that is defined after this point will be as
-if @code{attribute((option("STRING")))} was specified for that function.
+if @code{attribute((option("STRING")))} was specified for that
+function.  The parenthesis around the options is optional.
+@xref{Function Attributes}, for more information about the
+@code{option} attribute and the attribute syntax.
+
+The @samp{#pragma GCC option} pragma is not implemented in GCC
+versions earlier than 4.4, and is currently only implemented for the
+386 and x86_64 backend.
 @end table
 
 @table @code
-@item #pragma GCC option push
-@itemx #pragma GCC option pop
+@item #pragma GCC option (push)
+@itemx #pragma GCC option (pop)
 @cindex pragma GCC option
 
 These pragmas maintain a stack of the current options.  It is
-intendent for include files where you temporarily want to switch to
-using a different @code{#pragma GCC option} and then to pop back to
+intended for include files where you temporarily want to switch to
+using a different @samp{#pragma GCC option} and then to pop back to
 the previous options.
 @end table
 
 @table @code
-@item #pragma GCC option reset
+@item #pragma GCC option (reset)
 @cindex pragma, target option
 @cindex pragma GCC option
 
 This pragma clears the current @code{#pragma GCC options} to use the
-default swtiches as specified on the command line.
+default switches as specified on the command line.
+@end table
+@table @code
+@item #pragma GCC optimize (@var{"string"}...)
+@cindex pragma GCC optimize
+
+This pragma allows you to set global optimization options for functions
+defined later in the source file.  One or more strings can be
+specified.  Each function that is defined after this point will be as
+if @code{attribute((optimize("STRING")))} was specified for that
+function.  The parenthesis around the options is optional.
+@xref{Function Attributes}, for more information about the
+@code{optimize} attribute and the attribute syntax.
+
+The @samp{#pragma GCC optimize} pragma is not implemented in GCC
+versions earlier than 4.4.
+@end table
+
+@table @code
+@item #pragma GCC optimize (push)
+@itemx #pragma GCC optimize (pop)
+@cindex pragma GCC optimize
+
+These pragmas maintain a stack of the current optimization options.
+It is intended for include files where you temporarily want to switch
+to using a different @code{#pragma GCC optimize} and then to pop back
+to the previous optimizations.
+@end table
+
+@table @code
+@item #pragma GCC optimize reset
+@cindex pragma GCC optimize
+
+This pragma clears the current @code{#pragma GCC optimize} to use the
+default switches as specified on the command line.
 @end table
 
 @node Unnamed Fields
Index: gcc/doc/options.texi
===================================================================
--- gcc/doc/options.texi	(revision 136933)
+++ gcc/doc/options.texi	(working copy)
@@ -36,7 +36,7 @@ has been declared in this way, it can be
 
 @item
 A target specific save record to save additional information. These
-records have ttwo fields: the string @samp{TargetSave}, and a
+records have two fields: the string @samp{TargetSave}, and a
 declaration type to go in the @code{cl_target_option} structure.
 
 @item
@@ -127,7 +127,10 @@ This property cannot be used alongside @
 @item UInteger
 The option's argument is a non-negative integer.  The option parser
 will check and convert the argument before passing it to the relevant
-option handler.
+option handler.  @code{UInteger} should also be used on options like
+@code{-falign-loops} where both @code{-falign-loops} and
+@code{-falign-loops}=@var{n} are supported to make sure the saved
+options are given a full integer.
 
 @item Var(@var{var})
 The state of this option should be stored in variable @var{var}.
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 136933)
+++ gcc/doc/tm.texi	(working copy)
@@ -9232,13 +9232,40 @@ target specific attribute attached to it
 
 @deftypefn {Target Hook} bool TARGET_VALID_OPTION_ATTRIBUTE_P (tree @var{fndecl}, tree @var{name}, tree @var{args}, int @var{flags})
 This hook is called to parse the @code{attribute(option("..."))}, and
-it allows the function to set compile time options for the current
-function that might be different than the options specified on the
-command line.  The hook should return @code{true} if the options are valid.
-
-The hook should set the @var{DECL_FUNCTION_SPECIFIC} field in the
-function declaration to hold a pointer to a target specific
-@var{struct function_specific_data} structure.
+it allows the function to set different target machine compile time
+options for the current function that might be different than the
+options specified on the command line.  The hook should return
+@code{true} if the options are valid.
+
+The hook should set the @var{DECL_FUNCTION_SPECIFIC_TARGET} field in
+the function declaration to hold a pointer to a target specific
+@var{struct cl_target_option} structure.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_OPTION_SAVE (struct cl_target_option *@var{ptr})
+This hook is called to save any additional target specific information
+in the @var{struct cl_target_option} structure for function specific
+options.
+@xref{Option file format}.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_OPTION_RESTORE (struct cl_target_option *@var{ptr})
+This hook is called to restore any additional target specific
+information in the @var{struct cl_target_option} structure for
+function specific options.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_OPTION_PRINT (struct cl_target_option *@var{ptr})
+This hook is called to print any additional target specific
+information in the @var{struct cl_target_option} structure for
+function specific options.
+@end deftypefn
+
+@deftypefn {Target Hook} bool TARGET_OPTION_PRAGMA_PARSE (target @var{args})
+This target hook parses the options for @code{#pragma GCC option} to
+set the machine specific options for functions that occur later in the
+input stream.  The options should be the same as handled by the
+@code{TARGET_VALID_OPTION_ATTRIBUTE_P} hook.
 @end deftypefn
 
 @deftypefn {Target Hook} bool TARGET_CAN_INLINE_P (tree @var{caller}, tree @var{callee})
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 136933)
+++ gcc/tree.c	(working copy)
@@ -137,6 +137,13 @@ static GTY (()) tree int_cst_node;
 static GTY ((if_marked ("ggc_marked_p"), param_is (union tree_node)))
      htab_t int_cst_hash_table;
 
+/* Hash table and temporary node for optimization flags and target option
+   flags.  Use the same hash table for both sets of options.  */
+static GTY (()) tree cl_optimization_node;
+static GTY (()) tree cl_target_option_node;
+static GTY ((if_marked ("ggc_marked_p"), param_is (union tree_node)))
+     htab_t cl_option_hash_table;
+
 /* General tree->tree mapping  structure for use in hash tables.  */
 
 
@@ -158,6 +165,8 @@ static int type_hash_eq (const void *, c
 static hashval_t type_hash_hash (const void *);
 static hashval_t int_cst_hash_hash (const void *);
 static int int_cst_hash_eq (const void *, const void *);
+static hashval_t cl_option_hash_hash (const void *);
+static int cl_option_hash_eq (const void *, const void *);
 static void print_type_hash_statistics (void);
 static void print_debug_expr_statistics (void);
 static void print_value_expr_statistics (void);
@@ -235,6 +244,12 @@ init_ttree (void)
   
   int_cst_node = make_node (INTEGER_CST);
 
+  cl_option_hash_table = htab_create_ggc (64, cl_option_hash_hash,
+					  cl_option_hash_eq, NULL);
+
+  cl_optimization_node = make_node (OPTIMIZATION_NODE);
+  cl_target_option_node = make_node (TARGET_OPTION_NODE);
+
   tree_contains_struct[FUNCTION_DECL][TS_DECL_NON_COMMON] = 1;
   tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_NON_COMMON] = 1;
   tree_contains_struct[TYPE_DECL][TS_DECL_NON_COMMON] = 1;
@@ -8786,4 +8801,132 @@ block_nonartificial_location (tree block
   return ret;
 }
 
+/* These are the hash table functions for the hash table of OPTIMIZATION_NODEq
+   nodes.  */
+
+/* Return the hash code code X, an OPTIMIZATION_NODE or TARGET_OPTION code.  */
+
+static hashval_t
+cl_option_hash_hash (const void *x)
+{
+  const_tree const t = (const_tree) x;
+  const char *p;
+  size_t i;
+  size_t len = 0;
+  hashval_t hash = 0;
+
+  if (TREE_CODE (t) == OPTIMIZATION_NODE)
+    {
+      p = (const char *)TREE_OPTIMIZATION (t);
+      len = sizeof (struct cl_optimization);
+    }
+
+  else if (TREE_CODE (t) == TARGET_OPTION_NODE)
+    {
+      p = (const char *)TREE_TARGET_OPTION (t);
+      len = sizeof (struct cl_target_option);
+    }
+
+  else
+    gcc_unreachable ();
+
+  /* assume most opt flags are just 0/1, some are 2-3, and a few might be
+     something else.  */
+  for (i = 0; i < len; i++)
+    if (p[i])
+      hash = (hash << 4) ^ ((i << 2) | p[i]);
+
+  return hash;
+}
+
+/* Return nonzero if the value represented by *X (an OPTIMIZATION or
+   TARGET_OPTION tree node) is the same as that given by *Y, which is the
+   same.  */
+
+static int
+cl_option_hash_eq (const void *x, const void *y)
+{
+  const_tree const xt = (const_tree) x;
+  const_tree const yt = (const_tree) y;
+  const char *xp;
+  const char *yp;
+  size_t len;
+
+  if (TREE_CODE (xt) != TREE_CODE (yt))
+    return 0;
+
+  if (TREE_CODE (xt) == OPTIMIZATION_NODE)
+    {
+      xp = (const char *)TREE_OPTIMIZATION (xt);
+      yp = (const char *)TREE_OPTIMIZATION (yt);
+      len = sizeof (struct cl_optimization);
+    }
+
+  else if (TREE_CODE (xt) == TARGET_OPTION_NODE)
+    {
+      xp = (const char *)TREE_TARGET_OPTION (xt);
+      yp = (const char *)TREE_TARGET_OPTION (yt);
+      len = sizeof (struct cl_target_option);
+    }
+
+  else
+    gcc_unreachable ();
+
+  return (memcmp (xp, yp, len) == 0);
+}
+
+/* Build an OPTIMIZATION_NODE based on the current options.  */
+
+tree
+build_optimization_node (void)
+{
+  tree t;
+  void **slot;
+
+  /* Use the cache of optimization nodes.  */
+
+  cl_optimization_save (TREE_OPTIMIZATION (cl_optimization_node));
+
+  slot = htab_find_slot (cl_option_hash_table, cl_optimization_node, INSERT);
+  t = *slot;
+  if (!t)
+    {
+      /* Insert this one into the hash table.  */
+      t = cl_optimization_node;
+      *slot = t;
+
+      /* Make a new node for next time round.  */
+      cl_optimization_node = make_node (OPTIMIZATION_NODE);
+    }
+
+  return t;
+}
+
+/* Build a TARGET_OPTION_NODE based on the current options.  */
+
+tree
+build_target_option_node (void)
+{
+  tree t;
+  void **slot;
+
+  /* Use the cache of optimization nodes.  */
+
+  cl_target_option_save (TREE_TARGET_OPTION (cl_target_option_node));
+
+  slot = htab_find_slot (cl_option_hash_table, cl_target_option_node, INSERT);
+  t = *slot;
+  if (!t)
+    {
+      /* Insert this one into the hash table.  */
+      t = cl_target_option_node;
+      *slot = t;
+
+      /* Make a new node for next time round.  */
+      cl_target_option_node = make_node (TARGET_OPTION_NODE);
+    }
+
+  return t;
+}
+
 #include "gt-tree.h"
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 136933)
+++ gcc/tree.h	(working copy)
@@ -3539,6 +3539,9 @@ struct tree_optimization_option GTY(())
 #define TREE_OPTIMIZATION(NODE) \
   (&OPTIMIZATION_NODE_CHECK (NODE)->optimization.opts)
 
+/* Return a tree node that encapsulates the current optimization options.  */
+extern tree build_optimization_node (void);
+
 /* Target options used by a function.  */
 
 struct tree_target_option GTY(())
@@ -3552,6 +3555,9 @@ struct tree_target_option GTY(())
 #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);
+
 
 /* Define the overall contents of a tree node.
    It may be any of the structures declared above
@@ -3749,8 +3755,11 @@ enum tree_index
   TI_OPTIMIZATION_DEFAULT,
   TI_OPTIMIZATION_CURRENT,
   TI_OPTIMIZATION_COLD,
+  TI_OPTIMIZATION_HOT,
   TI_TARGET_OPTION_DEFAULT,
+  TI_TARGET_OPTION_CURRENT,
   TI_CURRENT_OPTION_PRAGMA,
+  TI_CURRENT_OPTIMIZE_PRAGMA,
 
   TI_MAX
 };
@@ -3919,16 +3928,21 @@ extern GTY(()) tree global_trees[TI_MAX]
 #define main_identifier_node		global_trees[TI_MAIN_IDENTIFIER]
 #define MAIN_NAME_P(NODE) (IDENTIFIER_NODE_CHECK (NODE) == main_identifier_node)
 
-/* Optimization options to use for default, cold, and hot functions.  */
+/* Optimization options (OPTIMIZATION_NODE) to use for default, current, cold,
+   and hot functions.  */
 #define optimization_default_node	global_trees[TI_OPTIMIZATION_DEFAULT]
 #define optimization_current_node	global_trees[TI_OPTIMIZATION_CURRENT]
 #define optimization_cold_node		global_trees[TI_OPTIMIZATION_COLD]
+#define optimization_hot_node		global_trees[TI_OPTIMIZATION_HOT]
 
-/* Default target options.  */
+/* Default/current target options (TARGET_OPTION_NODE).  */
 #define target_option_default_node	global_trees[TI_TARGET_OPTION_DEFAULT]
+#define target_option_current_node	global_trees[TI_TARGET_OPTION_CURRENT]
 
-/* Default option() pragma.  */
+/* Default tree list option(), optimize() pragmas to be linked into the
+   attribute list.  */
 #define current_option_pragma		global_trees[TI_CURRENT_OPTION_PRAGMA]
+#define current_optimize_pragma		global_trees[TI_CURRENT_OPTIMIZE_PRAGMA]
 
 /* An enumeration of the standard C integer types.  These must be
    ordered so that shorter types appear before longer ones, and so
Index: gcc/target.h
===================================================================
--- gcc/target.h	(revision 136933)
+++ gcc/target.h	(working copy)
@@ -955,7 +955,7 @@ struct gcc_target
      filled in in the function decl node.  */
   bool (*valid_option_attribute_p) (tree, tree, tree, int);
 
-  /* Function to save any extra target state in the the target options
+  /* Function to save any extra target state in the target options
      structure.  */
   void (*target_option_save) (struct cl_target_option *);
 
@@ -967,6 +967,12 @@ struct gcc_target
      structure.  */
   void (*target_option_print) (FILE *, int, struct cl_target_option *);
 
+  /* Function to parse arguments to be validated for #pragma option, and to
+     change the state if the options are valid.  If the arguments are NULL, use
+     the default target options.  Return true if the options are valid, and set
+     the current state.  */
+  bool (*target_option_pragma_parse) (tree);
+
   /* Function to determine if one function can inline another function.  */
   bool (*can_inline_p) (tree, tree);
 
Index: gcc/toplev.h
===================================================================
--- gcc/toplev.h	(revision 136933)
+++ gcc/toplev.h	(working copy)
@@ -79,6 +79,7 @@ extern void announce_function (tree);
 extern void error_for_asm (const_rtx, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
 extern void warning_for_asm (const_rtx, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
 extern void warn_deprecated_use (tree);
+extern bool parse_optimize_options (tree, bool);
 
 #ifdef BUFSIZ
 extern void output_quoted_string	(FILE *, const char *);
@@ -155,6 +156,7 @@ extern void decode_d_option		(const char
 
 /* Return true iff flags are set as if -ffast-math.  */
 extern bool fast_math_flags_set_p	(void);
+extern bool fast_math_flags_struct_set_p (struct cl_optimization *);
 
 /* Return log2, or -1 if not exact.  */
 extern int exact_log2                  (unsigned HOST_WIDE_INT);
Index: gcc/c-cppbuiltin.c
===================================================================
--- gcc/c-cppbuiltin.c	(revision 136933)
+++ gcc/c-cppbuiltin.c	(working copy)
@@ -405,6 +405,58 @@ builtin_define_stdint_macros (void)
   builtin_define_type_max ("__INTMAX_MAX__", intmax_type_node, intmax_long);
 }
 
+/* Adjust the optimization macros when a #pragma GCC optimization is done to
+   reflect the current level.  */
+void
+c_cpp_builtins_optimize_pragma (cpp_reader *pfile, tree prev_tree,
+				tree cur_tree)
+{
+  struct cl_optimization *prev = TREE_OPTIMIZATION (prev_tree);
+  struct cl_optimization *cur  = TREE_OPTIMIZATION (cur_tree);
+  bool prev_fast_math;
+  bool cur_fast_math;
+
+  /* -undef turns off target-specific built-ins.  */
+  if (flag_undef)
+    return;
+
+  /* Other target-independent built-ins determined by command-line
+     options.  */
+  if (!prev->optimize_size && cur->optimize_size)
+    cpp_define (pfile, "__OPTIMIZE_SIZE__");
+  else if (prev->optimize_size && !cur->optimize_size)
+    cpp_undef (pfile, "__OPTIMIZE_SIZE__");
+
+  if (!prev->optimize && cur->optimize)
+    cpp_define (pfile, "__OPTIMIZE__");
+  else if (prev->optimize && !cur->optimize)
+    cpp_undef (pfile, "__OPTIMIZE__");
+
+  prev_fast_math = fast_math_flags_struct_set_p (prev);
+  cur_fast_math  = fast_math_flags_struct_set_p (cur);
+  if (!prev_fast_math && cur_fast_math)
+    cpp_define (pfile, "__FAST_MATH__");
+  else if (prev_fast_math && !cur_fast_math)
+    cpp_undef (pfile, "__FAST_MATH__");
+
+  if (!prev->flag_signaling_nans && cur->flag_signaling_nans)
+    cpp_define (pfile, "__SUPPORT_SNAN__");
+  else if (prev->flag_signaling_nans && !cur->flag_signaling_nans)
+    cpp_undef (pfile, "__SUPPORT_SNAN__");
+
+  if (!prev->flag_finite_math_only && cur->flag_finite_math_only)
+    {
+      cpp_undef (pfile, "__FINITE_MATH_ONLY__");
+      cpp_define (pfile, "__FINITE_MATH_ONLY__=1");
+    }
+  else if (!prev->flag_finite_math_only && cur->flag_finite_math_only)
+    {
+      cpp_undef (pfile, "__FINITE_MATH_ONLY__");
+      cpp_define (pfile, "__FINITE_MATH_ONLY__=0");
+    }
+}
+
+
 /* Hook that registers front end and target-specific built-ins.  */
 void
 c_cpp_builtins (cpp_reader *pfile)
Index: gcc/testsuite/gcc.target/i386/sse-23.c
===================================================================
--- gcc/testsuite/gcc.target/i386/sse-23.c	(revision 0)
+++ gcc/testsuite/gcc.target/i386/sse-23.c	(revision 0)
@@ -0,0 +1,108 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Werror-implicit-function-declaration -march=k8" } */
+
+#include <mm_malloc.h>
+
+/* Test that the intrinsics compile with optimization.  All of them are
+   defined as inline functions in {,x,e,p,t,s,w,a,b}mmintrin.h and mm3dnow.h
+   that reference the proper builtin functions.  Defining away "extern" and
+   "__inline" results in all of them being compiled as proper functions.  */
+
+#define extern
+#define __inline
+
+/* Following intrinsics require immediate arguments. */
+
+/* ammintrin.h */
+#define __builtin_ia32_extrqi(X, I, L)  __builtin_ia32_extrqi(X, 1, 1)
+#define __builtin_ia32_insertqi(X, Y, I, L) __builtin_ia32_insertqi(X, Y, 1, 1)
+
+/* wmmintrin.h */
+#define __builtin_ia32_aeskeygenassist128(X, C) __builtin_ia32_aeskeygenassist128(X, 1)
+#define __builtin_ia32_pclmulqdq128(X, Y, I) __builtin_ia32_pclmulqdq128(X, Y, 1)
+
+/* mmintrin-common.h */
+#define __builtin_ia32_roundpd(V, M) __builtin_ia32_roundpd(V, 1)
+#define __builtin_ia32_roundsd(D, V, M) __builtin_ia32_roundsd(D, V, 1)
+#define __builtin_ia32_roundps(V, M) __builtin_ia32_roundps(V, 1)
+#define __builtin_ia32_roundss(D, V, M) __builtin_ia32_roundss(D, V, 1)
+
+/* smmintrin.h */
+#define __builtin_ia32_pblendw128(X, Y, M) __builtin_ia32_pblendw128 (X, Y, 1)
+#define __builtin_ia32_blendps(X, Y, M) __builtin_ia32_blendps(X, Y, 1)
+#define __builtin_ia32_blendpd(X, Y, M) __builtin_ia32_blendpd(X, Y, 1)
+#define __builtin_ia32_dpps(X, Y, M) __builtin_ia32_dpps(X, Y, 1)
+#define __builtin_ia32_dppd(X, Y, M) __builtin_ia32_dppd(X, Y, 1)
+#define __builtin_ia32_insertps128(D, S, N) __builtin_ia32_insertps128(D, S, 1)
+#define __builtin_ia32_vec_ext_v4sf(X, N) __builtin_ia32_vec_ext_v4sf(X, 1)
+#define __builtin_ia32_vec_set_v16qi(D, S, N) __builtin_ia32_vec_set_v16qi(D, S, 1)
+#define __builtin_ia32_vec_set_v4si(D, S, N) __builtin_ia32_vec_set_v4si(D, S, 1)
+#define __builtin_ia32_vec_set_v2di(D, S, N) __builtin_ia32_vec_set_v2di(D, S, 1)
+#define __builtin_ia32_vec_ext_v16qi(X, N) __builtin_ia32_vec_ext_v16qi(X, 1)
+#define __builtin_ia32_vec_ext_v4si(X, N) __builtin_ia32_vec_ext_v4si(X, 1)
+#define __builtin_ia32_vec_ext_v2di(X, N) __builtin_ia32_vec_ext_v2di(X, 1)
+#define __builtin_ia32_mpsadbw128(X, Y, M) __builtin_ia32_mpsadbw128(X, Y, 1)
+#define __builtin_ia32_pcmpistrm128(X, Y, M) \
+  __builtin_ia32_pcmpistrm128(X, Y, 1)
+#define __builtin_ia32_pcmpistri128(X, Y, M) \
+  __builtin_ia32_pcmpistri128(X, Y, 1)
+#define __builtin_ia32_pcmpestrm128(X, LX, Y, LY, M) \
+  __builtin_ia32_pcmpestrm128(X, LX, Y, LY, 1)
+#define __builtin_ia32_pcmpestri128(X, LX, Y, LY, M) \
+  __builtin_ia32_pcmpestri128(X, LX, Y, LY, 1)
+#define __builtin_ia32_pcmpistria128(X, Y, M) \
+  __builtin_ia32_pcmpistria128(X, Y, 1)
+#define __builtin_ia32_pcmpistric128(X, Y, M) \
+  __builtin_ia32_pcmpistric128(X, Y, 1)
+#define __builtin_ia32_pcmpistrio128(X, Y, M) \
+  __builtin_ia32_pcmpistrio128(X, Y, 1)
+#define __builtin_ia32_pcmpistris128(X, Y, M) \
+  __builtin_ia32_pcmpistris128(X, Y, 1)
+#define __builtin_ia32_pcmpistriz128(X, Y, M) \
+  __builtin_ia32_pcmpistriz128(X, Y, 1)
+#define __builtin_ia32_pcmpestria128(X, LX, Y, LY, M) \
+  __builtin_ia32_pcmpestria128(X, LX, Y, LY, 1)
+#define __builtin_ia32_pcmpestric128(X, LX, Y, LY, M) \
+  __builtin_ia32_pcmpestric128(X, LX, Y, LY, 1)
+#define __builtin_ia32_pcmpestrio128(X, LX, Y, LY, M) \
+  __builtin_ia32_pcmpestrio128(X, LX, Y, LY, 1)
+#define __builtin_ia32_pcmpestris128(X, LX, Y, LY, M) \
+  __builtin_ia32_pcmpestris128(X, LX, Y, LY, 1)
+#define __builtin_ia32_pcmpestriz128(X, LX, Y, LY, M) \
+  __builtin_ia32_pcmpestriz128(X, LX, Y, LY, 1)
+
+/* tmmintrin.h */
+#define __builtin_ia32_palignr128(X, Y, N) __builtin_ia32_palignr128(X, Y, 8)
+#define __builtin_ia32_palignr(X, Y, N) __builtin_ia32_palignr(X, Y, 8)
+
+/* emmintrin.h */
+#define __builtin_ia32_psrldqi128(A, B) __builtin_ia32_psrldqi128(A, 8)
+#define __builtin_ia32_pslldqi128(A, B) __builtin_ia32_pslldqi128(A, 8)
+#define __builtin_ia32_pshufhw(A, N) __builtin_ia32_pshufhw(A, 0)
+#define __builtin_ia32_pshuflw(A, N) __builtin_ia32_pshuflw(A, 0)
+#define __builtin_ia32_pshufd(A, N) __builtin_ia32_pshufd(A, 0)
+#define __builtin_ia32_vec_set_v8hi(A, D, N) \
+  __builtin_ia32_vec_set_v8hi(A, D, 0)
+#define __builtin_ia32_vec_ext_v8hi(A, N) __builtin_ia32_vec_ext_v8hi(A, 0)
+#define __builtin_ia32_shufpd(A, B, N) __builtin_ia32_shufpd(A, B, 0)
+
+/* xmmintrin.h */
+#define __builtin_prefetch(P, A, I) __builtin_prefetch(P, A, _MM_HINT_NTA)
+#define __builtin_ia32_pshufw(A, N) __builtin_ia32_pshufw(A, 0)
+#define __builtin_ia32_vec_set_v4hi(A, D, N) \
+  __builtin_ia32_vec_set_v4hi(A, D, 0)
+#define __builtin_ia32_vec_ext_v4hi(A, N) __builtin_ia32_vec_ext_v4hi(A, 0)
+#define __builtin_ia32_shufps(A, B, N) __builtin_ia32_shufps(A, B, 0)
+
+/* bmmintrin.h */
+#define __builtin_ia32_protbi(A, B) __builtin_ia32_protbi(A,1)
+#define __builtin_ia32_protwi(A, B) __builtin_ia32_protwi(A,1)
+#define __builtin_ia32_protdi(A, B) __builtin_ia32_protdi(A,1)
+#define __builtin_ia32_protqi(A, B) __builtin_ia32_protqi(A,1)
+
+
+#pragma GCC option ("3dnow,sse4,sse5,aes,pclmul")
+#include <wmmintrin.h>
+#include <bmmintrin.h>
+#include <smmintrin.h>
+#include <mm3dnow.h>
Index: gcc/testsuite/gcc.target/i386/opt-1.c
===================================================================
--- gcc/testsuite/gcc.target/i386/opt-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/i386/opt-1.c	(revision 0)
@@ -0,0 +1,35 @@
+/* Test the attribute((optimize)) really works.  Do this test by checking
+   whether we vectorize a simple loop.  */
+/* { dg-do compile } */
+/* { dg-options "-O1 -msse2 -mfpmath=sse -march=k8" } */
+/* { dg-final { scan-assembler "prefetcht0" } } */
+/* { dg-final { scan-assembler "addps" } } */
+/* { dg-final { scan-assembler "subss" } } */
+
+#define SIZE 10240
+float a[SIZE] __attribute__((__aligned__(32)));
+float b[SIZE] __attribute__((__aligned__(32)));
+float c[SIZE] __attribute__((__aligned__(32)));
+
+/* This should vectorize.  */
+void opt3 (void) __attribute__((__optimize__(3,"unroll-all-loops,-fprefetch-loop-arrays")));
+
+void
+opt3 (void)
+{
+  int i;
+
+  for (i = 0; i < SIZE; i++)
+    a[i] = b[i] + c[i];
+}
+
+/* This should not vectorize.  */
+void
+not_opt3 (void)
+{
+  int i;
+
+  for (i = 0; i < SIZE; i++)
+    a[i] = b[i] - c[i];
+}
+
Index: gcc/testsuite/gcc.target/i386/cold-1.c
===================================================================
--- gcc/testsuite/gcc.target/i386/cold-1.c	(revision 136933)
+++ gcc/testsuite/gcc.target/i386/cold-1.c	(working copy)
@@ -2,8 +2,8 @@
    by checking whether strcpy calls the library function rather than doing
    the move inline.  */
 /* { dg-do compile } */
-/* { dg-options "-O3 -march=k8 -fno-optimize-sibling-calls" } */
-/* { dg-final { scan-assembler "call\t(.*)strcpy" } } */
+/* { dg-options "-O3 -march=k8" } */
+/* { dg-final { scan-assembler "(jmp|call)\t(.*)strcpy" } } */
 
 void cold (char *) __attribute__((__cold__));
 
Index: gcc/testsuite/gcc.target/i386/funcspec-1.c
===================================================================
--- gcc/testsuite/gcc.target/i386/funcspec-1.c	(revision 136933)
+++ gcc/testsuite/gcc.target/i386/funcspec-1.c	(working copy)
@@ -1,9 +1,11 @@
 /* Test whether using target specific options, we can generate SSE2 code on
-   32-bit, which does not generate SSE2 by default.  */
+   32-bit, which does not generate SSE2 by default, but still generate 387 code
+   for a function that doesn't use attribute((option)).  */
 /* { dg-do compile } */
 /* { dg-require-effective-target ilp32 } */
 /* { dg-options "-O3 -ftree-vectorize -march=i386" } */
 /* { dg-final { scan-assembler "addps\[ \t\]" } } */
+/* { dg-final { scan-assembler "fsubs\[ \t\]" } } */
 
 #ifndef SIZE
 #define SIZE 1024
@@ -13,12 +15,20 @@ static float a[SIZE] __attribute__((__al
 static float b[SIZE] __attribute__((__aligned__(16)));
 static float c[SIZE] __attribute__((__aligned__(16)));
 
-void addnums (void) __attribute__ ((__option__ ("sse2")));
+void sse_addnums (void) __attribute__ ((__option__ ("sse2")));
 
 void
-addnums (void)
+sse_addnums (void)
 {
   int i = 0;
   for (; i < SIZE; ++i)
     a[i] = b[i] + c[i];
 }
+
+void
+i387_subnums (void)
+{
+  int i = 0;
+  for (; i < SIZE; ++i)
+    a[i] = b[i] - c[i];
+}
Index: gcc/testsuite/gcc.target/i386/hot-1.c
===================================================================
--- gcc/testsuite/gcc.target/i386/hot-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/i386/hot-1.c	(revision 0)
@@ -0,0 +1,33 @@
+/* Test whether using attribute((hot)) really turns on -O3.  Do this test
+   by checking whether we vectorize a simple loop.  */
+/* { dg-do compile } */
+/* { dg-options "-O1 -msse2 -mfpmath=sse -march=k8" } */
+/* { dg-final { scan-assembler "addps" } } */
+/* { dg-final { scan-assembler "subss" } } */
+
+#define SIZE 1024
+float a[SIZE] __attribute__((__aligned__(32)));
+float b[SIZE] __attribute__((__aligned__(32)));
+float c[SIZE] __attribute__((__aligned__(32)));
+
+/* This should vectorize.  */
+void hot (void) __attribute__((__hot__));
+
+void
+hot (void)
+{
+  int i;
+
+  for (i = 0; i < SIZE; i++)
+    a[i] = b[i] + c[i];
+}
+
+/* This should not vectorize.  */
+void
+not_hot (void)
+{
+  int i;
+
+  for (i = 0; i < SIZE; i++)
+    a[i] = b[i] - c[i];
+}
Index: gcc/testsuite/gcc.target/i386/funcspec-9.c
===================================================================
--- gcc/testsuite/gcc.target/i386/funcspec-9.c	(revision 0)
+++ gcc/testsuite/gcc.target/i386/funcspec-9.c	(revision 0)
@@ -0,0 +1,36 @@
+/* Test whether using target specific options, we can generate SSE5 code.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=k8 -mfpmath=sse -msse2" } */
+
+extern void exit (int);
+
+#ifdef __SSE5__
+#warning "__SSE5__ should not be defined before #pragma GCC option."
+#endif
+
+#pragma GCC option (push)
+#pragma GCC option ("sse5,fused-madd")
+
+#ifndef __SSE5__
+#warning "__SSE5__ should have be defined after #pragma GCC option."
+#endif
+
+float
+flt_mul_add (float a, float b, float c)
+{
+  return (a * b) + c;
+}
+
+#pragma GCC option (pop)
+#ifdef __SSE5__
+#warning "__SSE5__ should not be defined after #pragma GCC pop option."
+#endif
+
+double
+dbl_mul_add (double a, double b, double c)
+{
+  return (a * b) + c;
+}
+
+/* { dg-final { scan-assembler "fmaddss" } } */
+/* { dg-final { scan-assembler "addsd" } } */
Index: gcc/testsuite/gcc.target/i386/sse-22.c
===================================================================
--- gcc/testsuite/gcc.target/i386/sse-22.c	(revision 0)
+++ gcc/testsuite/gcc.target/i386/sse-22.c	(revision 0)
@@ -0,0 +1,147 @@
+/* Same as sse-14, except converted to use #pragma GCC option.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -Werror-implicit-function-declaration -msse" } */
+
+#include <mm_malloc.h>
+
+/* Test that the intrinsics compile without optimization.  All of them are
+   defined as inline functions in {,x,e,p,t,s,w,a,b}mmintrin.h  and mm3dnow.h
+   that reference the proper builtin functions.  Defining away "extern" and
+   "__inline" results in all of them being compiled as proper functions.  */
+
+#define extern
+#define __inline
+
+#define _CONCAT(x,y) x ## y
+
+#define test_1(func, type, op1_type, imm)				\
+  type _CONCAT(_,func) (op1_type A, int const I)			\
+  { return func (A, imm); }
+
+#define test_1x(func, type, op1_type, imm1, imm2)			\
+  type _CONCAT(_,func) (op1_type A, int const I, int const L)		\
+  { return func (A, imm1, imm2); }
+
+#define test_2(func, type, op1_type, op2_type, imm)			\
+  type _CONCAT(_,func) (op1_type A, op2_type B, int const I)		\
+  { return func (A, B, imm); }
+
+#define test_2x(func, type, op1_type, op2_type, imm1, imm2)		\
+  type _CONCAT(_,func) (op1_type A, op2_type B, int const I, int const L) \
+  { return func (A, B, imm1, imm2); }
+
+#define test_4(func, type, op1_type, op2_type, op3_type, op4_type, imm)	\
+  type _CONCAT(_,func) (op1_type A, op2_type B,				\
+			op3_type C, op4_type D, int const I)		\
+  { return func (A, B, C, D, imm); }
+
+
+/* Following intrinsics require immediate arguments.  They
+   are defined as macros for non-optimized compilations. */
+
+/* mmintrin.h (MMX).  */
+#pragma GCC option ("mmx")
+#include <mmintrin.h>
+
+/* mm3dnow.h (3DNOW).  */
+#pragma GCC option ("3dnow")
+#include <mm3dnow.h>
+
+/* xmmintrin.h (SSE).  */
+#pragma GCC option ("sse")
+#include <xmmintrin.h>
+test_2 (_mm_shuffle_ps, __m128, __m128, __m128, 1)
+test_1 (_mm_extract_pi16, int, __m64, 1)
+test_1 (_m_pextrw, int, __m64, 1)
+test_2 (_mm_insert_pi16, __m64, __m64, int, 1)
+test_2 (_m_pinsrw, __m64, __m64, int, 1)
+test_1 (_mm_shuffle_pi16, __m64, __m64, 1)
+test_1 (_m_pshufw, __m64, __m64, 1)
+test_1 (_mm_prefetch, void, void *, _MM_HINT_NTA)
+
+/* emmintrin.h (SSE2).  */
+#pragma GCC option ("sse2")
+#include <emmintrin.h>
+test_2 (_mm_shuffle_pd, __m128d, __m128d, __m128d, 1)
+test_1 (_mm_srli_si128, __m128i, __m128i, 1)
+test_1 (_mm_slli_si128, __m128i, __m128i, 1)
+test_1 (_mm_extract_epi16, int, __m128i, 1)
+test_2 (_mm_insert_epi16, __m128i, __m128i, int, 1)
+test_1 (_mm_shufflehi_epi16, __m128i, __m128i, 1)
+test_1 (_mm_shufflelo_epi16, __m128i, __m128i, 1)
+test_1 (_mm_shuffle_epi32, __m128i, __m128i, 1)
+
+/* pmmintrin.h (SSE3).  */
+#pragma GCC option ("sse3")
+#include <pmmintrin.h>
+
+/* tmmintrin.h (SSSE3).  */
+#pragma GCC option ("ssse3")
+#include <tmmintrin.h>
+test_2 (_mm_alignr_epi8, __m128i, __m128i, __m128i, 1)
+test_2 (_mm_alignr_pi8, __m64, __m64, __m64, 1)
+
+/* ammintrin.h (SSE4A).  */
+#pragma GCC option ("sse4a")
+#include <ammintrin.h>
+test_1x (_mm_extracti_si64, __m128i, __m128i, 1, 1)
+test_2x (_mm_inserti_si64, __m128i, __m128i, __m128i, 1, 1)
+
+/* smmintrin.h (SSE4.1).  */
+/* nmmintrin.h (SSE4.2).  */
+/* Note, nmmintrin.h includes smmintrin.h, and smmintrin.h checks for the
+   #ifdef.  So just set the option to SSE4.2.  */
+#pragma GCC option ("sse4.2")
+#include <nmmintrin.h>
+test_2 (_mm_blend_epi16, __m128i, __m128i, __m128i, 1)
+test_2 (_mm_blend_ps, __m128, __m128, __m128, 1)
+test_2 (_mm_blend_pd, __m128d, __m128d, __m128d, 1)
+test_2 (_mm_dp_ps, __m128, __m128, __m128, 1)
+test_2 (_mm_dp_pd, __m128d, __m128d, __m128d, 1)
+test_2 (_mm_insert_ps, __m128, __m128, __m128, 1)
+test_1 (_mm_extract_ps, int, __m128, 1)
+test_2 (_mm_insert_epi8, __m128i, __m128i, int, 1)
+test_2 (_mm_insert_epi32, __m128i, __m128i, int, 1)
+#ifdef __x86_64__
+test_2 (_mm_insert_epi64, __m128i, __m128i, long long, 1)
+#endif
+test_1 (_mm_extract_epi8, int, __m128i, 1)
+test_1 (_mm_extract_epi32, int, __m128i, 1)
+#ifdef __x86_64__
+test_1 (_mm_extract_epi64, long long, __m128i, 1)
+#endif
+test_2 (_mm_mpsadbw_epu8, __m128i, __m128i, __m128i, 1)
+test_2 (_mm_cmpistrm, __m128i, __m128i, __m128i, 1)
+test_2 (_mm_cmpistri, int, __m128i, __m128i, 1)
+test_4 (_mm_cmpestrm, __m128i, __m128i, int, __m128i, int, 1)
+test_4 (_mm_cmpestri, int, __m128i, int, __m128i, int, 1)
+test_2 (_mm_cmpistra, int, __m128i, __m128i, 1)
+test_2 (_mm_cmpistrc, int, __m128i, __m128i, 1)
+test_2 (_mm_cmpistro, int, __m128i, __m128i, 1)
+test_2 (_mm_cmpistrs, int, __m128i, __m128i, 1)
+test_2 (_mm_cmpistrz, int, __m128i, __m128i, 1)
+test_4 (_mm_cmpestra, int, __m128i, int, __m128i, int, 1)
+test_4 (_mm_cmpestrc, int, __m128i, int, __m128i, int, 1)
+test_4 (_mm_cmpestro, int, __m128i, int, __m128i, int, 1)
+test_4 (_mm_cmpestrs, int, __m128i, int, __m128i, int, 1)
+test_4 (_mm_cmpestrz, int, __m128i, int, __m128i, int, 1)
+
+/* bmmintrin.h (SSE5).  */
+#pragma GCC option ("sse5")
+#include <bmmintrin.h>
+test_1 (_mm_roti_epi8, __m128i, __m128i, 1)
+test_1 (_mm_roti_epi16, __m128i, __m128i, 1)
+test_1 (_mm_roti_epi32, __m128i, __m128i, 1)
+test_1 (_mm_roti_epi64, __m128i, __m128i, 1)
+
+/* wmmintrin.h (AES/PCLMUL).  */
+#pragma GCC option ("aes,pclmul")
+#include <wmmintrin.h>
+test_1 (_mm_aeskeygenassist_si128, __m128i, __m128i, 1)
+test_2 (_mm_clmulepi64_si128, __m128i, __m128i, __m128i, 1)
+
+/* mmintrin-common.h */
+test_1 (_mm_round_pd, __m128d, __m128d, 1)
+test_1 (_mm_round_ps, __m128, __m128, 1)
+test_2 (_mm_round_sd, __m128d, __m128d, __m128d, 1)
+test_2 (_mm_round_ss, __m128, __m128, __m128, 1)
Index: gcc/opts.c
===================================================================
--- gcc/opts.c	(revision 136933)
+++ gcc/opts.c	(working copy)
@@ -837,12 +837,34 @@ optimize_for_space (void)
 void
 decode_options (unsigned int argc, const char **argv)
 {
-  unsigned int i, lang_mask;
-
-  /* Perform language-specific options initialization.  */
-  lang_mask = lang_hooks.init_options (argc, argv);
+  static bool first_time_p = true;
+  static int initial_max_aliased_vops;
+  static int initial_avg_aliased_vops;
+  static int initial_min_crossjump_insns;
+  static unsigned int initial_lang_mask;
 
-  lang_hooks.initialize_diagnostics (global_dc);
+  unsigned int i, lang_mask;
+  int opt0;
+  int opt1;
+  int opt2;
+  int opt3;
+  int opt1_max;
+
+  if (first_time_p)
+    {
+      /* Perform language-specific options initialization.  */
+      initial_lang_mask = lang_mask = lang_hooks.init_options (argc, argv);
+
+      lang_hooks.initialize_diagnostics (global_dc);
+
+      /* Save initial values of parameters we reset.  */
+      initial_max_aliased_vops = MAX_ALIASED_VOPS;
+      initial_avg_aliased_vops = AVG_ALIASED_VOPS;
+      initial_min_crossjump_insns
+	= compiler_params[PARAM_MIN_CROSSJUMP_INSNS].value;
+    }
+  else
+    lang_mask = initial_lang_mask;
 
   /* Scan to see what optimization level has been specified.  That will
      determine the default value of many flags.  */
@@ -877,94 +899,97 @@ decode_options (unsigned int argc, const
 	}
     }
 
-  if (!optimize)
-    {
-      flag_merge_constants = 0;
-    }
-
-  if (optimize >= 1)
-    {
-      flag_defer_pop = 1;
+  /* Originally we just set the variables if a particular optimization level,
+     but with the advent of being able to change the optimization level for a
+     function, we need to reset optimizations.  */
+
+  /* -O0 optimizations.  */
+  opt0 = (optimize == 0);
+  flag_merge_constants = !opt0;
+
+  /* -O1 optimizations.  */
+  opt1 = (optimize >= 1);
+  flag_defer_pop = opt1;
 #ifdef DELAY_SLOTS
-      flag_delayed_branch = 1;
+  flag_delayed_branch = opt1;
 #endif
 #ifdef CAN_DEBUG_WITHOUT_FP
-      flag_omit_frame_pointer = 1;
+  flag_omit_frame_pointer = opt1;
 #endif
-      flag_guess_branch_prob = 1;
-      flag_cprop_registers = 1;
-      flag_if_conversion = 1;
-      flag_if_conversion2 = 1;
-      flag_ipa_pure_const = 1;
-      flag_ipa_reference = 1;
-      flag_split_wide_types = 1;
-      flag_tree_ccp = 1;
-      flag_tree_dce = 1;
-      flag_tree_dom = 1;
-      flag_tree_dse = 1;
-      flag_tree_ter = 1;
-      flag_tree_sra = 1;
-      flag_tree_copyrename = 1;
-      flag_tree_fre = 1;
-      flag_tree_copy_prop = 1;
-      flag_tree_sink = 1;
-      flag_tree_ch = 1;
-      if (!no_unit_at_a_time_default)
-        flag_unit_at_a_time = 1;
-    }
-
-  if (optimize >= 2)
-    {
-      flag_inline_small_functions = 1;
-      flag_thread_jumps = 1;
-      flag_crossjumping = 1;
-      flag_optimize_sibling_calls = 1;
-      flag_forward_propagate = 1;
-      flag_cse_follow_jumps = 1;
-      flag_gcse = 1;
-      flag_expensive_optimizations = 1;
-      flag_rerun_cse_after_loop = 1;
-      flag_caller_saves = 1;
-      flag_peephole2 = 1;
+  flag_guess_branch_prob = opt1;
+  flag_cprop_registers = opt1;
+  flag_if_conversion = opt1;
+  flag_if_conversion2 = opt1;
+  flag_ipa_pure_const = opt1;
+  flag_ipa_reference = opt1;
+  flag_split_wide_types = opt1;
+  flag_tree_ccp = opt1;
+  flag_tree_dce = opt1;
+  flag_tree_dom = opt1;
+  flag_tree_dse = opt1;
+  flag_tree_ter = opt1;
+  flag_tree_sra = opt1;
+  flag_tree_copyrename = opt1;
+  flag_tree_fre = opt1;
+  flag_tree_copy_prop = opt1;
+  flag_tree_sink = opt1;
+  flag_tree_ch = opt1;
+  if (!no_unit_at_a_time_default)
+    flag_unit_at_a_time = opt1;
+
+  /* -O2 optimizations.  */
+  opt2 = (optimize >= 2);
+  flag_inline_small_functions = opt2;
+  flag_thread_jumps = opt2;
+  flag_crossjumping = opt2;
+  flag_optimize_sibling_calls = opt2;
+  flag_forward_propagate = opt2;
+  flag_cse_follow_jumps = opt2;
+  flag_gcse = opt2;
+  flag_expensive_optimizations = opt2;
+  flag_rerun_cse_after_loop = opt2;
+  flag_caller_saves = opt2;
+  flag_peephole2 = opt2;
 #ifdef INSN_SCHEDULING
-      flag_schedule_insns = 1;
-      flag_schedule_insns_after_reload = 1;
+  flag_schedule_insns = opt2;
+  flag_schedule_insns_after_reload = opt2;
 #endif
-      flag_regmove = 1;
-      flag_strict_aliasing = 1;
-      flag_strict_overflow = 1;
-      flag_delete_null_pointer_checks = 1;
-      flag_reorder_blocks = 1;
-      flag_reorder_functions = 1;
-      flag_tree_store_ccp = 1;
-      flag_tree_vrp = 1;
-      flag_tree_builtin_call_dce = 1;
-      flag_tree_pre = 1;
+  flag_regmove = opt2;
+  flag_strict_aliasing = opt2;
+  flag_strict_overflow = opt2;
+  flag_delete_null_pointer_checks = opt2;
+  flag_reorder_blocks = opt2;
+  flag_reorder_functions = opt2;
+  flag_tree_store_ccp = opt2;
+  flag_tree_vrp = opt2;
+  flag_tree_builtin_call_dce = opt2;
+  flag_tree_pre = opt2;
 
       /* Allow more virtual operators to increase alias precision.  */
-      set_param_value ("max-aliased-vops", 500);
-    }
+  set_param_value ("max-aliased-vops",
+		   (opt2) ? 500 : initial_max_aliased_vops);
 
-  if (optimize >= 3)
-    {
-      flag_predictive_commoning = 1;
-      flag_inline_functions = 1;
-      flag_unswitch_loops = 1;
-      flag_gcse_after_reload = 1;
-      flag_tree_vectorize = 1;
-
-      /* Allow even more virtual operators.  */
-      set_param_value ("max-aliased-vops", 1000);
-      set_param_value ("avg-aliased-vops", 3);
-    }
-
-  if (optimize < 2)
-    {
-      align_loops = 1;
-      align_jumps = 1;
-      align_labels = 1;
-      align_functions = 1;
-    }
+  /* -O3 optimizations.  */
+  opt3 = (optimize >= 3);
+  flag_predictive_commoning = opt3;
+  flag_inline_functions = opt3;
+  flag_unswitch_loops = opt3;
+  flag_gcse_after_reload = opt3;
+  flag_tree_vectorize = opt3;
+
+  /* Allow even more virtual operators.  Max-aliased-vops was set above for
+     -O2, so don't reset it unless we are at -O3.  */
+  if (opt3)
+    set_param_value ("max-aliased-vops", 1000);
+
+  set_param_value ("avg-aliased-vops", (opt3) ? 3 : initial_avg_aliased_vops);
+
+  /* Just -O1/-O0 optimizations.  */
+  opt1_max = (optimize <= 1);
+  align_loops = opt1_max;
+  align_jumps = opt1_max;
+  align_labels = opt1_max;
+  align_functions = opt1_max;
 
   if (optimize_size)
     {
@@ -973,19 +998,24 @@ decode_options (unsigned int argc, const
       /* We want to crossjump as much as possible.  */
       set_param_value ("min-crossjump-insns", 1);
     }
+  else
+    set_param_value ("min-crossjump-insns", initial_min_crossjump_insns);
 
-  /* Initialize whether `char' is signed.  */
-  flag_signed_char = DEFAULT_SIGNED_CHAR;
-  /* Set this to a special "uninitialized" value.  The actual default is set
-     after target options have been processed.  */
-  flag_short_enums = 2;
-
-  /* Initialize target_flags before OPTIMIZATION_OPTIONS so the latter can
-     modify it.  */
-  target_flags = targetm.default_target_flags;
+  if (first_time_p)
+    {
+      /* Initialize whether `char' is signed.  */
+      flag_signed_char = DEFAULT_SIGNED_CHAR;
+      /* Set this to a special "uninitialized" value.  The actual default is
+	 set after target options have been processed.  */
+      flag_short_enums = 2;
+
+      /* Initialize target_flags before OPTIMIZATION_OPTIONS so the latter can
+	 modify it.  */
+      target_flags = targetm.default_target_flags;
 
-  /* Some targets have ABI-specified unwind tables.  */
-  flag_unwind_tables = targetm.unwind_tables_default;
+      /* Some targets have ABI-specified unwind tables.  */
+      flag_unwind_tables = targetm.unwind_tables_default;
+    }
 
 #ifdef OPTIMIZATION_OPTIONS
   /* Allow default optimizations to be specified on a per-machine basis.  */
@@ -994,15 +1024,18 @@ decode_options (unsigned int argc, const
 
   handle_options (argc, argv, lang_mask);
 
-  if (flag_pie)
-    flag_pic = flag_pie;
-  if (flag_pic && !flag_pie)
-    flag_shlib = 1;
+  if (first_time_p)
+    {
+      if (flag_pie)
+	flag_pic = flag_pie;
+      if (flag_pic && !flag_pie)
+	flag_shlib = 1;
 
-  if (flag_no_inline == 2)
-    flag_no_inline = 0;
-  else
-    flag_really_no_inline = flag_no_inline;
+      if (flag_no_inline == 2)
+	flag_no_inline = 0;
+      else
+	flag_really_no_inline = flag_no_inline;
+    }
 
   /* Set flag_no_inline before the post_options () hook.  The C front
      ends use it to determine tree inlining defaults.  FIXME: such
@@ -1077,11 +1110,11 @@ decode_options (unsigned int argc, const
     }
 
   /* Save the current optimization options if this is the first call.  */
-  if (!optimization_default_node)
+  if (first_time_p)
     {
-      optimization_default_node = make_node (OPTIMIZATION_NODE);
+      optimization_default_node = build_optimization_node ();
       optimization_current_node = optimization_default_node;
-      cl_optimization_save (TREE_OPTIMIZATION (optimization_default_node));
+      first_time_p = false;
     }
 }
 
@@ -2069,6 +2102,18 @@ fast_math_flags_set_p (void)
 	  && !flag_errno_math);
 }
 
+/* Return true iff flags are set as if -ffast-math but using the flags stored
+   in the struct cl_optimization structure.  */
+bool
+fast_math_flags_struct_set_p (struct cl_optimization *opt)
+{
+  return (!opt->flag_trapping_math
+	  && opt->flag_unsafe_math_optimizations
+	  && opt->flag_finite_math_only
+	  && !opt->flag_signed_zeros
+	  && !opt->flag_errno_math);
+}
+
 /* Handle a debug output -g switch.  EXTENDED is true or false to support
    extended output (2 is special and means "-ggdb" was given).  */
 static void
Index: gcc/optc-gen.awk
===================================================================
--- gcc/optc-gen.awk	(revision 136933)
+++ gcc/optc-gen.awk	(working copy)
@@ -259,7 +259,7 @@ for (i = 0; i < n_opts; i++) {
 			var_opt_int[n_opt_int++] = name;
 
 		else if (otype ~ "^((un)?signed +)?short *$")
-			var_opt_int[n_opt_int++] = name;
+			var_opt_short[n_opt_short++] = name;
 
 		else if (otype ~ "^((un)?signed +)?char *$") {
 			var_opt_char[n_opt_char++] = name;
@@ -279,6 +279,7 @@ for (i = 0; i < n_opt_char; i++) {
 		print "  gcc_assert (IN_RANGE (" name ", " var_opt_range[name] "));";
 }
 
+print "";
 for (i = 0; i < n_opt_other; i++) {
 	print "  ptr->" var_opt_other[i] " = " var_opt_other[i] ";";
 }
@@ -329,6 +330,7 @@ print "                       int indent
 print "                       struct cl_optimization *ptr)";
 print "{";
 
+print "  fputs (\"\\n\", file);";
 for (i = 0; i < n_opt_other; i++) {
 	print "  if (ptr->" var_opt_other[i] ")";
 	print "    fprintf (file, \"%*s%s (0x%lx)\\n\",";
@@ -411,13 +413,18 @@ if (have_save) {
 	var_target_int[n_target_int++] = "target_flags";
 }
 
+have_assert = 0;
 for (i = 0; i < n_target_char; i++) {
 	name = var_target_char[i];
-	if (var_target_range[name] != "")
+	if (var_target_range[name] != "") {
+		have_assert = 1;
 		print "  gcc_assert (IN_RANGE (" name ", " var_target_range[name] "));";
+	}
 }
 
-print "";
+if (have_assert)
+	print "";
+
 print "  if (targetm.target_option_save)";
 print "    targetm.target_option_save (ptr);";
 print "";
@@ -462,6 +469,8 @@ for (i = 0; i < n_target_char; i++) {
 	print "  " var_target_char[i] " = ptr->" var_target_char[i] ";";
 }
 
+# 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 (ptr);";
@@ -476,6 +485,7 @@ print "                        int inden
 print "                        struct cl_target_option *ptr)";
 print "{";
 
+print "  fputs (\"\\n\", file);";
 for (i = 0; i < n_target_other; i++) {
 	print "  if (ptr->" var_target_other[i] ")";
 	print "    fprintf (file, \"%*s%s (0x%lx)\\n\",";
Index: gcc/function.c
===================================================================
--- gcc/function.c	(revision 136933)
+++ gcc/function.c	(working copy)
@@ -3753,8 +3753,8 @@ debug_find_var_in_block_tree (tree var, 
 
 static bool in_dummy_function;
 
-/* Invoke the target hook when setting cfun.  If the function has the cold
-   attribute set, make sure we switch to optimizing for space.  */
+/* Invoke the target hook when setting cfun.  Update the optimization options
+   if the function uses different options than the default.  */
 
 static void
 invoke_set_current_function_hook (tree fndecl)
Index: gcc/c-pragma.c
===================================================================
--- gcc/c-pragma.c	(revision 136933)
+++ gcc/c-pragma.c	(working copy)
@@ -865,15 +865,17 @@ handle_pragma_diagnostic(cpp_reader *ARG
   GCC_BAD ("unknown option after %<#pragma GCC diagnostic%> kind");
 }
 
-/* Stack of the #pragma GCC option created with #pragma GCC option push.  */
+/* Stack of the #pragma GCC options created with #pragma GCC option push.  */
 static GTY(()) VEC(tree,gc) *option_stack;
 
+/*  Parse #pragma GCC option (xxx) to set target specific options.  */
 static void
 handle_pragma_option(cpp_reader *ARG_UNUSED(dummy))
 {
   enum cpp_ttype token;
   const char *name;
   tree x;
+  bool close_paren_needed_p = false;
 
   if (cfun)
     {
@@ -881,18 +883,30 @@ handle_pragma_option(cpp_reader *ARG_UNU
       return;
     }
 
-  if (!targetm.valid_option_attribute_p)
+  if (!targetm.target_option_pragma_parse)
     {
       error ("#pragma GCC option is not supported for this system");
       return;
     }
 
   token = pragma_lex (&x);
+  if (token == CPP_OPEN_PAREN)
+    {
+      close_paren_needed_p = true;
+      token = pragma_lex (&x);
+    }
+
   if (token == CPP_NAME)
     {
+      bool call_pragma_parse_p = false;
+      bool ok_p;
+
       name = IDENTIFIER_POINTER (x);
       if (strcmp (name, "reset") == 0)
-	current_option_pragma = NULL_TREE;
+	{
+	  current_option_pragma = NULL_TREE;
+	  call_pragma_parse_p = true;
+	}
 
       else if (strcmp (name, "push") == 0)
 	VEC_safe_push (tree, gc, option_stack,
@@ -903,7 +917,8 @@ handle_pragma_option(cpp_reader *ARG_UNU
 	  int len = VEC_length (tree, option_stack);
 	  if (len == 0)
 	    {
-	      GCC_BAD ("%<#pragma GCC option pop%> without a %<#pragma GCC option push%>");
+	      GCC_BAD ("%<#pragma GCC option pop%> without a %<#pragma GCC "
+		       "option push%>");
 	      return;
 	    }
 	  else
@@ -912,21 +927,40 @@ handle_pragma_option(cpp_reader *ARG_UNU
 	      current_option_pragma = ((len > 1)
 				       ? VEC_last (tree, option_stack)
 				       : NULL_TREE);
+
+	      call_pragma_parse_p = true;
 	    }
 	}
 
       else
 	{
-	  GCC_BAD ("%<#pragma GCC option%> is not a string or push/pop/reset");
+	  GCC_BAD ("%<#pragma GCC option%> is not a string or "
+		   "push/pop/reset");
 	  return;
 	}
 
       token = pragma_lex (&x);
+      if (close_paren_needed_p)
+	{
+	  if (token == CPP_CLOSE_PAREN)
+	    token = pragma_lex (&x);
+	  else
+	    GCC_BAD ("%<#pragma GCC option ([push|pop|reset])%> does not "
+		     "have a final %<)%>.");
+	}
+
       if (token != CPP_EOF)
 	{
-	  GCC_BAD ("%<#pragma GCC option [push|pop|reset]%> is badly formed");
+	  GCC_BAD ("%<#pragma GCC option [push|pop|reset]%> is badly "
+		   "formed");
 	  return;
 	}
+
+      /* See if we need to call the pragma_parse hook.  This must occur at the
+	 end after processing all of the tokens, or we may get spurious errors
+	 when we define or undef macros.  */
+      ok_p = targetm.target_option_pragma_parse (current_option_pragma);
+      gcc_assert (ok_p);
     }
 
   else if (token != CPP_STRING)
@@ -938,21 +972,203 @@ handle_pragma_option(cpp_reader *ARG_UNU
   /* Strings are user options.  */
   else
     {
+      tree args = NULL_TREE;
+
       do
 	{
-	  /* Parse the target option now.  Only build up the list if the string
-	     is valid.  */
-	  if (targetm.valid_option_attribute_p (NULL_TREE, NULL_TREE, x, 0))
-	    current_option_pragma = tree_cons (NULL_TREE, x,
-					       current_option_pragma);
+	  /* Build up the strings now as a tree linked list.  Skip empty
+	     strings.  */
+	  if (TREE_STRING_LENGTH (x) > 0)
+	    args = tree_cons (NULL_TREE, x, args);
+
+	  token = pragma_lex (&x);
+	  while (token == CPP_COMMA)
+	    token = pragma_lex (&x);
+	}
+      while (token == CPP_STRING);
+
+      if (close_paren_needed_p)
+	{
+	  if (token == CPP_CLOSE_PAREN)
+	    token = pragma_lex (&x);
+	  else
+	    GCC_BAD ("%<#pragma GCC option (string [,string]...)%> does "
+		     "not have a final %<)%>.");
 	}
-      while ((token = pragma_lex (&x)) == CPP_STRING);
 
       if (token != CPP_EOF)
 	{
 	  error ("#pragma GCC option string... is badly formed");
 	  return;
 	}
+
+      /* put arguments in the order the user typed them.  */
+      args = nreverse (args);
+
+      if (targetm.target_option_pragma_parse (args))
+	current_option_pragma = args;
+    }
+}
+
+/* Stack of the #pragma GCC optimize options created with #pragma GCC optimize
+   push.  */
+static GTY(()) VEC(tree,gc) *optimize_stack;
+
+/* Handle #pragma GCC optimize to set optimization options.  */
+static void
+handle_pragma_optimize(cpp_reader *ARG_UNUSED(dummy))
+{
+  enum cpp_ttype token;
+  const char *name;
+  tree x;
+  bool close_paren_needed_p = false;
+  tree optimization_previous_node = optimization_current_node;
+
+  if (cfun)
+    {
+      error ("#pragma GCC optimize is not allowed inside functions");
+      return;
+    }
+
+  token = pragma_lex (&x);
+  if (token == CPP_OPEN_PAREN)
+    {
+      close_paren_needed_p = true;
+      token = pragma_lex (&x);
+    }
+
+  if (token == CPP_NAME)
+    {
+      bool call_opt_p = false;
+
+      name = IDENTIFIER_POINTER (x);
+      if (strcmp (name, "reset") == 0)
+	{
+	  struct cl_optimization *def
+	    = TREE_OPTIMIZATION (optimization_default_node);
+	  current_optimize_pragma = NULL_TREE;
+	  optimization_current_node = optimization_default_node;
+	  cl_optimization_restore (def);
+	  call_opt_p = true;
+	}
+
+      else if (strcmp (name, "push") == 0)
+	VEC_safe_push (tree, gc, optimize_stack, current_optimize_pragma);
+
+      else if (strcmp (name, "pop") == 0)
+	{
+	  int len = VEC_length (tree, optimize_stack);
+	  if (len == 0)
+	    {
+	      GCC_BAD ("%<#pragma GCC optimize pop%> without a %<#pragma "
+		       "GCC optimize push%>");
+	      return;
+	    }
+	  else
+	    {
+	      VEC_truncate (tree, optimize_stack, len-1);
+	      current_optimize_pragma
+		= ((len > 1)
+		   ? VEC_last (tree, optimize_stack)
+		   : NULL_TREE);
+
+	      call_opt_p = true;
+	      if (current_optimize_pragma)
+		{
+		  bool ok_p
+		    = parse_optimize_options (current_optimize_pragma, false);
+		  gcc_assert (ok_p);	/* should be parsed previously.  */
+		  optimization_current_node = build_optimization_node ();
+		}
+	      else
+		{
+		  struct cl_optimization *opt
+		    = TREE_OPTIMIZATION (optimization_default_node);
+		  optimization_current_node = optimization_default_node;
+		  cl_optimization_restore (opt);
+		}
+	    }
+	}
+
+      else
+	{
+	  GCC_BAD ("%<#pragma GCC optimize%> is not a string or "
+		   "push/pop/reset");
+	  return;
+	}
+
+      token = pragma_lex (&x);
+      if (close_paren_needed_p)
+	{
+	  if (token == CPP_CLOSE_PAREN)
+	    token = pragma_lex (&x);
+	  else
+	    GCC_BAD ("%<#pragma GCC optimize ([push|pop|reset])%> does not "
+		     "have a final %<)%>.");
+	}
+
+      if (token != CPP_EOF)
+	{
+	  GCC_BAD ("%<#pragma GCC optimize [push|pop|reset]%> is badly "
+		   "formed");
+	  return;
+	}
+
+      if (call_opt_p &&
+	  (optimization_previous_node != optimization_current_node))
+	c_cpp_builtins_optimize_pragma (parse_in,
+					optimization_previous_node,
+					optimization_current_node);
+
+    }
+
+  else if (token != CPP_STRING && token != CPP_NUMBER)
+    {
+      GCC_BAD ("%<#pragma GCC optimize%> is not a string, number, or "
+	       "push/pop/reset");
+      return;
+    }
+
+  /* Strings/numbers are user options.  */
+  else
+    {
+      tree args = NULL_TREE;
+
+      do
+	{
+	  /* Build up the numbers/strings now as a list.  */
+	  if (token != CPP_STRING || TREE_STRING_LENGTH (x) > 0)
+	    args = tree_cons (NULL_TREE, x, args);
+
+	  token = pragma_lex (&x);
+	  while (token == CPP_COMMA)
+	    token = pragma_lex (&x);
+	}
+      while (token == CPP_STRING || token == CPP_NUMBER);
+
+      if (close_paren_needed_p)
+	{
+	  if (token == CPP_CLOSE_PAREN)
+	    token = pragma_lex (&x);
+	  else
+	    GCC_BAD ("%<#pragma GCC optimize (string [,string]...)%> does "
+		     "not have a final %<)%>.");
+	}
+
+      if (token != CPP_EOF)
+	{
+	  error ("#pragma GCC optimize string... is badly formed");
+	  return;
+	}
+
+      /* put arguments in the order the user typed them.  */
+      args = nreverse (args);
+
+      parse_optimize_options (args, false);
+      optimization_current_node = build_optimization_node ();
+      c_cpp_builtins_optimize_pragma (parse_in,
+				      optimization_previous_node,
+				      optimization_current_node);
     }
 }
 
@@ -1119,6 +1335,7 @@ init_pragma (void)
 
   c_register_pragma ("GCC", "diagnostic", handle_pragma_diagnostic);
   c_register_pragma ("GCC", "option", handle_pragma_option);
+  c_register_pragma ("GCC", "optimize", handle_pragma_optimize);
 
   c_register_pragma_with_expansion (0, "redefine_extname", handle_pragma_redefine_extname);
   c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix);
Index: gcc/opth-gen.awk
===================================================================
--- gcc/opth-gen.awk	(revision 136933)
+++ gcc/opth-gen.awk	(working copy)
@@ -123,7 +123,7 @@ for (i = 0; i < n_opts; i++) {
 			var_opt_int[n_opt_int++] = otype name;
 
 		else if (otype ~ "^((un)?signed +)?short *$")
-			var_opt_int[n_opt_int++] = otype name;
+			var_opt_short[n_opt_short++] = otype name;
 
 		else if (otype ~ "^((un)?signed +)?char *$")
 			var_opt_char[n_opt_char++] = otype name;
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 136933)
+++ gcc/common.opt	(working copy)
@@ -59,11 +59,11 @@ Common Joined Separate UInteger
 -G<number>	Put global and static data smaller than <number> bytes into a special section (on some targets)
 
 O
-Common JoinedOrMissing
+Common JoinedOrMissing Optimization
 -O<number>	Set optimization level to <number>
 
 Os
-Common
+Common Optimization
 Optimize for space rather than speed
 
 W
@@ -271,28 +271,28 @@ fabi-version=
 Common Joined UInteger Var(flag_abi_version) Init(2)
 
 falign-functions
-Common Report Var(align_functions,0)
+Common Report Var(align_functions,0) Optimization UInteger
 Align the start of functions
 
 falign-functions=
 Common RejectNegative Joined UInteger
 
 falign-jumps
-Common Report Var(align_jumps,0) Optimization
+Common Report Var(align_jumps,0) Optimization UInteger
 Align labels which are only reached by jumping
 
 falign-jumps=
 Common RejectNegative Joined UInteger
 
 falign-labels
-Common Report Var(align_labels,0) Optimization
+Common Report Var(align_labels,0) Optimization UInteger
 Align all labels
 
 falign-labels=
 Common RejectNegative Joined UInteger
 
 falign-loops
-Common Report Var(align_loops) Optimization
+Common Report Var(align_loops) Optimization UInteger
 Align the start of loops
 
 falign-loops=
@@ -662,7 +662,7 @@ Common
 Does nothing.  Preserved for backward compatibility.
 
 fmath-errno
-Common Report Var(flag_errno_math) Init(1)
+Common Report Var(flag_errno_math) Init(1) Optimization
 Set errno after built-in math functions
 
 fmem-report
@@ -921,7 +921,7 @@ Reschedule instructions after register a
 ; sched_stalled_insns means that insns can be moved prematurely from the queue
 ; of stalled insns into the ready list.
 fsched-stalled-insns
-Common Report Var(flag_sched_stalled_insns) Optimization
+Common Report Var(flag_sched_stalled_insns) Optimization UInteger
 Allow premature scheduling of queued insns
 
 fsched-stalled-insns=
@@ -933,7 +933,7 @@ Common RejectNegative Joined UInteger
 ; premature removal from the queue of stalled insns into the ready list (has
 ; an effect only if the flag 'sched_stalled_insns' is set).
 fsched-stalled-insns-dep
-Common Report Var(flag_sched_stalled_insns_dep,1) Init(1) Optimization
+Common Report Var(flag_sched_stalled_insns_dep,1) Init(1) Optimization UInteger
 Set dependence distance checking in premature scheduling of queued insns
 
 fsched-stalled-insns-dep=
Index: gcc/target-def.h
===================================================================
--- gcc/target-def.h	(revision 136933)
+++ gcc/target-def.h	(working copy)
@@ -766,6 +766,10 @@
 #define TARGET_OPTION_PRINT NULL
 #endif
 
+#ifndef TARGET_OPTION_PRAGMA_PARSE
+#define TARGET_OPTION_PRAGMA_PARSE NULL
+#endif
+
 #ifndef TARGET_CAN_INLINE_P
 #define TARGET_CAN_INLINE_P default_can_inline_p
 #endif
@@ -866,6 +870,7 @@
   TARGET_OPTION_SAVE,				\
   TARGET_OPTION_RESTORE,			\
   TARGET_OPTION_PRINT,				\
+  TARGET_OPTION_PRAGMA_PARSE,			\
   TARGET_CAN_INLINE_P,				\
   TARGET_EXTRA_LIVE_ON_ENTRY,			\
   TARGET_UNWIND_TABLES_DEFAULT,			\
Index: gcc/tree-inline.c
===================================================================
--- gcc/tree-inline.c	(revision 136933)
+++ gcc/tree-inline.c	(working copy)
@@ -3682,9 +3682,32 @@ build_duplicate_type (tree type)
 }
 
 /* Return whether it is safe to inline a function because it used different
-   target specific options.  */
+   target specific options or different optimization options.  */
 bool
 tree_can_inline_p (tree caller, tree callee)
 {
+  /* Don't inline a function with a higher optimization level than the
+     caller, or with different space constraints (hot/cold functions).  */
+  tree caller_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (caller);
+  tree callee_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (callee);
+
+  if (caller_tree != callee_tree)
+    {
+      struct cl_optimization *caller_opt
+	= TREE_OPTIMIZATION ((caller_tree)
+			     ? caller_tree
+			     : optimization_default_node);
+
+      struct cl_optimization *callee_opt
+	= TREE_OPTIMIZATION ((callee_tree)
+			     ? callee_tree
+			     : optimization_default_node);
+
+      if ((caller_opt->optimize > callee_opt->optimize)
+	  || (caller_opt->optimize_size != callee_opt->optimize_size))
+	return false;
+    }
+
+  /* Allow the backend to decide if inlining is ok.  */
   return targetm.can_inline_p (caller, callee);
 }
Index: gcc/opt-functions.awk
===================================================================
--- gcc/opt-functions.awk	(revision 136933)
+++ gcc/opt-functions.awk	(working copy)
@@ -133,14 +133,14 @@ function var_type(flags)
 # type instead of int to save space.
 function var_type_struct(flags)
 {
-	if (!flag_set_p("Joined.*", flags)) {
+	if (flag_set_p("UInteger", flags))
+		return "int "
+	else if (!flag_set_p("Joined.*", flags)) {
 		if (flag_set_p(".*Mask.*", flags))
 			return "int "
 		else
 			return "unsigned char "
 	}
-	else if (flag_set_p("UInteger", flags))
-		return "int "
 	else
 		return "const char *"
 }
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c	(revision 136933)
+++ gcc/c-common.c	(working copy)
@@ -575,6 +575,7 @@ static tree handle_sentinel_attribute (t
 static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
 static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
 static tree handle_option_attribute (tree *, tree, tree, int, bool *);
+static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
 
 static void check_function_nonnull (tree, int, tree *);
 static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
@@ -687,6 +688,8 @@ const struct attribute_spec c_common_att
 			      handle_error_attribute },
   { "option",                 1, -1, true, false, false,
 			      handle_option_attribute },
+  { "optimize",               1, -1, true, false, false,
+			      handle_optimize_attribute },
   { NULL,                     0, 0, false, false, false, NULL }
 };
 
@@ -4801,7 +4804,7 @@ handle_noreturn_attribute (tree *node, t
 
 static tree
 handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args),
-			  int ARG_UNUSED (flags), bool *no_add_attrs)
+		      int ARG_UNUSED (flags), bool *no_add_attrs)
 {
   if (TREE_CODE (*node) == FUNCTION_DECL)
     {
@@ -4811,8 +4814,34 @@ handle_hot_attribute (tree *node, tree n
 		   name, "cold");
 	  *no_add_attrs = true;
 	}
-      /* Do nothing else, just set the attribute.  We'll get at
-	 it later with lookup_attribute.  */
+
+      else
+	{
+	  tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
+
+	  /* If we are not at -O3, but are optimizing, turn on -O3
+	     optimizations just for this one function.  */
+	  if (((optimize > 0 && optimize < 3) || optimize_size)
+	      && (!old_opts || old_opts == optimization_default_node))
+	    {
+	      /* Create the hot optimization node if needed.  */
+	      if (!optimization_hot_node)
+		{
+		  struct cl_optimization current_options;
+		  static const char *os_argv[] = { NULL, "-O3", NULL };
+
+		  cl_optimization_save (&current_options);
+		  decode_options (2, os_argv);
+		  optimization_hot_node = build_optimization_node ();
+		  cl_optimization_restore (&current_options);
+		}
+
+	      DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
+		= optimization_hot_node;
+	    }
+	}
+      /* Most of the rest of the hot processing is done later with
+	 lookup_attribute.  */
     }
   else
     {
@@ -4841,23 +4870,20 @@ handle_cold_attribute (tree *node, tree 
 	{
 	  tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
 
-	  /* If we are optimizing, but not optimizating for space, turn on
-	     -Os optimizations just for this one function.  */
-	  if (optimize >= 2
-	      && !optimize_size
+	  /* If we are optimizing, but not optimizing for space, turn on -Os
+	     optimizations just for this one function.  */
+	  if (optimize && !optimize_size
 	      && (!old_opts || old_opts == optimization_default_node))
 	    {
 	      /* Create the cold optimization node if needed.  */
 	      if (!optimization_cold_node)
 		{
-		  struct cl_optimization *cold;
 		  struct cl_optimization current_options;
+		  static const char *os_argv[] = { NULL, "-Os", NULL };
 
 		  cl_optimization_save (&current_options);
-		  optimize_for_space ();
-		  optimization_cold_node = make_node (OPTIMIZATION_NODE);
-		  cold = TREE_OPTIMIZATION (optimization_cold_node);
-		  cl_optimization_save (cold);
+		  decode_options (2, os_argv);
+		  optimization_cold_node = build_optimization_node ();
 		  cl_optimization_restore (&current_options);
 		}
 
@@ -6586,6 +6612,160 @@ handle_option_attribute (tree *node, tre
 
   return NULL_TREE;
 }
+
+/* Arguments being collected for optimization.  */
+typedef const char *const_char_p;		/* For DEF_VEC_P.  */
+DEF_VEC_P(const_char_p);
+DEF_VEC_ALLOC_P(const_char_p, gc);
+static GTY(()) VEC(const_char_p, gc) *optimize_args;
+
+
+/* Inner function to convert a TREE_LIST to argv string to parse the optimize
+   options in ARGS.  ATTR_P is true if this is for attribute(optimize), and
+   false for #pragma GCC optimize.  */
+
+bool
+parse_optimize_options (tree args, bool attr_p)
+{
+  bool ret = true;
+  unsigned opt_argc;
+  unsigned i;
+  const char **opt_argv;
+  tree ap;
+
+  /* Build up argv vector.  Just in case the string is stored away, use garbage
+     collected strings.  */
+  VEC_truncate (const_char_p, optimize_args, 0);
+  VEC_safe_push (const_char_p, gc, optimize_args, NULL);
+
+  for (ap = args; ap != NULL_TREE; ap = TREE_CHAIN (ap))
+    {
+      tree value = TREE_VALUE (ap);
+
+      if (TREE_CODE (value) == INTEGER_CST)
+	{
+	  char buffer[20];
+	  sprintf (buffer, "-O%ld", (long) TREE_INT_CST_LOW (value));
+	  VEC_safe_push (const_char_p, gc, optimize_args, ggc_strdup (buffer));
+	}
+
+      else if (TREE_CODE (value) == STRING_CST)
+	{
+	  size_t len = TREE_STRING_LENGTH (value);
+	  char *p = alloca (len + 1);
+	  char *end = p + len;
+	  char *comma;
+	  char *next_p = p;
+
+	  /* Split string into multiple substrings.  */
+	  memcpy (p, TREE_STRING_POINTER (value), len+1);
+
+	  while (next_p != NULL)
+	    {
+	      size_t len2;
+	      char *q, *r;
+
+	      p = next_p;
+	      comma = strchr (p, ',');
+	      if (comma)
+		{
+		  len2 = comma - p;
+		  *comma = '\0';
+		  next_p = comma+1;
+		}
+	      else
+		{
+		  len2 = end - p;
+		  next_p = NULL;
+		}
+
+	      r = q = alloca (len2 + 3);
+
+	      /* If the user supplied -Oxxx or -fxxx, only allow -Oxxx or -fxxx
+		 options.  */
+	      if (*p == '-' && p[1] != 'O' && p[1] != 'f')
+		{
+		  ret = false;
+		  if (attr_p)
+		    warning (OPT_Wattributes,
+			     "Bad option %s to optimize attribute.", p);
+		  else
+		    warning (OPT_Wpragmas,
+			     "Bad option %s to pragma attribute", p);
+		  continue;
+		}
+
+	      if (*p != '-')
+		{
+		  *r++ = '-';
+
+		  /* Assume that Ox is -Ox, a numeric value is -Ox, a s by
+		     itself is -Os, and any other swtich begins with a -f.  */
+		  if ((*p >= '0' && *p <= '9')
+		      || (p[0] == 's' && p[1] == '\0'))
+		    *r++ = 'O';
+		  else if (*p != 'O')
+		    *r++ = 'f';
+		}
+
+	      memcpy (r, p, len2);
+	      r[len2] = '\0';
+	      VEC_safe_push (const_char_p, gc, optimize_args, ggc_strdup (q));
+	    }
+
+	}
+    }
+
+  opt_argc = VEC_length (const_char_p, optimize_args);
+  opt_argv = alloca (sizeof (char *) * (opt_argc + 1));
+
+  for (i = 1; i < opt_argc; i++)
+    opt_argv[i] = VEC_index (const_char_p, optimize_args, i);
+
+  /* Now parse the options.  */
+  decode_options (opt_argc, opt_argv);
+
+  VEC_truncate (const_char_p, optimize_args, 0);
+  return ret;
+}
+
+/* For handling "optimize" attribute. arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_optimize_attribute (tree *node, tree name, tree args,
+			   int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  /* Ensure we have a function type.  */
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+  else
+    {
+      struct cl_optimization cur_opts;
+      tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
+
+      /* Save current options.  */
+      cl_optimization_save (&cur_opts);
+
+      /* If we previously had some optimization options, use them as the
+	 default.  */
+      if (old_opts)
+	cl_optimization_restore (TREE_OPTIMIZATION (old_opts));
+
+      /* Parse options, and update the vector.  */
+      parse_optimize_options (args, true);
+      DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
+	= build_optimization_node ();
+
+      /* Restore current options.  */
+      cl_optimization_restore (&cur_opts);
+    }
+
+  return NULL_TREE;
+}
 
 /* Check for valid arguments being passed to a function.
    ATTRS is a list of attributes.  There are NARGS arguments in the array
Index: gcc/c-common.h
===================================================================
--- gcc/c-common.h	(revision 136933)
+++ gcc/c-common.h	(working copy)
@@ -840,6 +840,7 @@ extern tree c_staticp (tree);
 extern void init_c_lex (void);
 
 extern void c_cpp_builtins (cpp_reader *);
+extern void c_cpp_builtins_optimize_pragma (cpp_reader *, tree, tree);
 
 /* Positive if an implicit `extern "C"' scope has just been entered;
    negative if such a scope has just been exited.  */
@@ -895,7 +896,6 @@ extern void warn_about_parentheses (enum
 extern void warn_for_unused_label (tree label);
 extern void warn_for_div_by_zero (tree divisor);
 
-
 /* In c-gimplify.c  */
 extern void c_genericize (tree);
 extern int c_gimplify_expr (tree *, tree *, tree *);
@@ -914,6 +914,8 @@ extern void c_common_print_pch_checksum 
 /* In *-checksum.c */
 extern const unsigned char executable_checksum[16];
 
+/* In c-cppbuiltin.c  */
+extern void builtin_define_std (const char *macro);
 extern void builtin_define_with_value (const char *, const char *, int);
 extern void c_stddef_cpp_builtins (void);
 extern void fe_file_change (const struct line_map *);
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 136933)
+++ gcc/config.gcc	(working copy)
@@ -278,6 +278,8 @@ fido-*-*)
         ;;
 i[34567]86-*-*)
 	cpu_type=i386
+	c_target_objs="i386-c.o"
+	cxx_target_objs="i386-c.o"
 	extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h
 		       pmmintrin.h tmmintrin.h ammintrin.h smmintrin.h
 		       nmmintrin.h bmmintrin.h mmintrin-common.h
@@ -285,6 +287,8 @@ i[34567]86-*-*)
 	;;
 x86_64-*-*)
 	cpu_type=i386
+	c_target_objs="i386-c.o"
+	cxx_target_objs="i386-c.o"
 	extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h
 		       pmmintrin.h tmmintrin.h ammintrin.h smmintrin.h
 		       nmmintrin.h bmmintrin.h mmintrin-common.h
@@ -394,8 +398,8 @@ case ${target} in
   tmake_file="t-darwin ${cpu_type}/t-darwin t-slibgcc-darwin"
   target_gtfiles="\$(srcdir)/config/darwin.c"
   extra_options="${extra_options} darwin.opt"
-  c_target_objs="darwin-c.o"
-  cxx_target_objs="darwin-c.o"
+  c_target_objs="${c_target_objs} darwin-c.o"
+  cxx_target_objs="${cxx_target_objs} darwin-c.o"
   fortran_target_objs="darwin-f.o"
   extra_objs="darwin.o"
   extra_gcc_objs="darwin-driver.o"
@@ -1011,16 +1015,16 @@ i[34567]86-*-darwin*)
 	;;
 x86_64-*-darwin*)
 	with_cpu=${with_cpu:-generic}
-	tmake_file="t-darwin ${cpu_type}/t-darwin64 t-slibgcc-darwin i386/t-fprules-softfp64 soft-fp/t-softfp i386/t-crtpc i386/t-crtfm"
+	tmake_file="${tmake_file} t-darwin ${cpu_type}/t-darwin64 t-slibgcc-darwin i386/t-fprules-softfp64 soft-fp/t-softfp i386/t-crtpc i386/t-crtfm"
 	tm_file="${tm_file} ${cpu_type}/darwin64.h"
 	;;
 i[34567]86-*-elf*)
 	tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/i386elf.h"
-	tmake_file="i386/t-i386elf t-svr4"
+	tmake_file="${tmake_file} i386/t-i386elf t-svr4"
 	;;
 x86_64-*-elf*)
 	tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/i386elf.h i386/x86-64.h"
-	tmake_file="i386/t-i386elf t-svr4"
+	tmake_file="${tmake_file} i386/t-i386elf t-svr4"
 	;;
 i[34567]86-*-aout*)
 	tm_file="${tm_file} i386/unix.h i386/bsd.h i386/gas.h i386/gstabs.h i386/i386-aout.h"
@@ -1037,7 +1041,7 @@ i[34567]86-*-netbsdelf*)
 	;;
 i[34567]86-*-netbsd*)
 	tm_file="${tm_file} i386/unix.h i386/bsd.h i386/gas.h i386/gstabs.h netbsd.h netbsd-aout.h i386/netbsd.h"
-	tmake_file=t-netbsd
+	tmake_file="${tmake_file} t-netbsd"
 	extra_parts=""
 	use_collect2=yes
 	;;
@@ -1048,7 +1052,7 @@ x86_64-*-netbsd*)
 i[34567]86-*-openbsd2.*|i[34567]86-*openbsd3.[0123])
 	tm_file="i386/i386.h i386/unix.h i386/bsd.h i386/gas.h i386/gstabs.h openbsd-oldgas.h openbsd.h i386/openbsd.h"
 	# needed to unconfuse gdb
-	tmake_file="t-libc-ok t-openbsd i386/t-openbsd"
+	tmake_file="${tmake_file} t-libc-ok t-openbsd i386/t-openbsd"
 	# we need collect2 until our bug is fixed...
 	use_collect2=yes
 	;;
@@ -1109,7 +1113,7 @@ i[34567]86-*-gnu*)
 i[34567]86-pc-msdosdjgpp*)
 	xm_file=i386/xm-djgpp.h
 	tm_file="dbxcoff.h ${tm_file} i386/unix.h i386/bsd.h i386/gas.h i386/djgpp.h"
-	tmake_file=i386/t-djgpp
+	tmake_file="${tmake_file} i386/t-djgpp"
 	extra_options="${extra_options} i386/djgpp.opt"
 	gnu_ld=yes
 	gas=yes
@@ -1117,7 +1121,7 @@ i[34567]86-pc-msdosdjgpp*)
 i[34567]86-*-lynxos*)
 	xm_defines=POSIX
 	tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/lynx.h lynx.h"
-	tmake_file="i386/t-crtstuff t-lynx"
+	tmake_file="${tmake_file} i386/t-crtstuff t-lynx"
 	extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
 	extra_options="${extra_options} lynx.opt"
 	thread_file=lynx
@@ -1126,7 +1130,7 @@ i[34567]86-*-lynxos*)
 	;;
 i[3456x]86-*-netware*)
 	tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h svr4.h tm-dwarf2.h i386/netware.h"
- 	tmake_file=i386/t-netware
+ 	tmake_file="${tmake_file} i386/t-netware"
 	extra_objs=netware.o
 	case /${with_ld} in
 	*/nwld)
@@ -1145,14 +1149,14 @@ i[3456x]86-*-netware*)
 	;;
 i[34567]86-*-nto-qnx*)
 	tm_file="${tm_file} i386/att.h dbxelf.h tm-dwarf2.h elfos.h svr4.h i386/unix.h i386/nto.h"
-	tmake_file=i386/t-nto
+	tmake_file="${tmake_file} i386/t-nto"
 	gnu_ld=yes
 	gas=yes
 	;;
 i[34567]86-*-rtems*)
 	tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/i386elf.h i386/rtemself.h rtems.h"
 	extra_parts="crtbegin.o crtend.o crti.o crtn.o"
-	tmake_file="i386/t-rtems-i386 i386/t-crtstuff t-rtems"
+	tmake_file="${tmake_file} i386/t-rtems-i386 i386/t-crtstuff t-rtems"
 	;;
 i[34567]86-*-solaris2*)
 	tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h svr4.h i386/sysv4.h sol2.h"
@@ -1162,9 +1166,9 @@ i[34567]86-*-solaris2*)
 		;;
 	esac
 	tm_file="${tm_file} i386/sol2.h"
-	tmake_file="t-sol2 i386/t-sol2 t-svr4"
-	c_target_objs="sol2-c.o"
-	cxx_target_objs="sol2-c.o"
+	tmake_file="${tmake_file} t-sol2 i386/t-sol2 t-svr4"
+	c_target_objs="${c_target_objs} sol2-c.o"
+	cxx_target_objs="${cxx_target_objs} sol2-c.o"
 	extra_objs="sol2.o"
 	tm_p_file="${tm_p_file} sol2-protos.h"
 	if test x$gnu_ld = xyes; then
@@ -1230,12 +1234,12 @@ i[4567]86-wrs-vxworks|i[4567]86-wrs-vxwo
 i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	tm_file="${tm_file} i386/unix.h i386/bsd.h i386/gas.h dbxcoff.h i386/cygming.h i386/cygwin.h"
 	xm_file=i386/xm-cygwin.h
-	tmake_file="i386/t-cygwin i386/t-cygming"
+	tmake_file="${tmake_file} i386/t-cygwin i386/t-cygming"
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs="cygwin2.o msformat-c.o"
-	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
+	c_target_objs="${c_target_objs} cygwin2.o msformat-c.o"
+	cxx_target_objs="${cxx_target_objs} cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1244,12 +1248,12 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 i[34567]86-*-mingw* | x86_64-*-mingw*)
 	tm_file="${tm_file} i386/unix.h i386/bsd.h i386/gas.h dbxcoff.h i386/cygming.h i386/mingw32.h"
 	xm_file=i386/xm-mingw32.h
-	tmake_file="i386/t-cygming i386/t-mingw32"
+	tmake_file="${tmake_file} i386/t-cygming i386/t-mingw32"
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs="msformat-c.o"
-	cxx_target_objs="winnt-cxx.o msformat-c.o"
+	c_target_objs="${c_target_objs} msformat-c.o"
+	cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
@@ -1274,7 +1278,7 @@ i[34567]86-*-mingw* | x86_64-*-mingw*)
 	;;
 i[34567]86-*-interix3*)
 	tm_file="${tm_file} i386/unix.h i386/bsd.h i386/gas.h i386/i386-interix.h i386/i386-interix3.h interix.h interix3.h"
-	tmake_file="i386/t-interix"
+	tmake_file="${tmake_file} i386/t-interix"
 	extra_objs=winnt.o
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	if test x$enable_threads = xyes ; then
@@ -2350,10 +2354,10 @@ esac
 
 case ${target} in
 i[34567]86-*-linux* | x86_64-*-linux*)
-	tmake_file="${tmake_file} i386/t-pmm_malloc"
+	tmake_file="${tmake_file} i386/t-pmm_malloc i386/t-i386"
 	;;
 i[34567]86-*-* | x86_64-*-*)
-	tmake_file="${tmake_file} i386/t-gmm_malloc"
+	tmake_file="${tmake_file} i386/t-gmm_malloc i386/t-i386"
 	;;
 esac
 
Index: gcc/config/i386/i386.h
===================================================================
--- gcc/config/i386/i386.h	(revision 136933)
+++ gcc/config/i386/i386.h	(working copy)
@@ -532,196 +532,7 @@ extern const char *host_detect_local_cpu
 #endif
 
 /* Target CPU builtins.  */
-#define TARGET_CPU_CPP_BUILTINS()				\
-  do								\
-    {								\
-      size_t arch_len = strlen (ix86_arch_string);		\
-      size_t tune_len = strlen (ix86_tune_string);		\
-      int last_arch_char = ix86_arch_string[arch_len - 1];	\
-      int last_tune_char = ix86_tune_string[tune_len - 1];	\
-								\
-      if (TARGET_64BIT)						\
-	{							\
-	  builtin_assert ("cpu=x86_64");			\
-	  builtin_assert ("machine=x86_64");			\
-	  builtin_define ("__amd64");				\
-	  builtin_define ("__amd64__");				\
-	  builtin_define ("__x86_64");				\
-	  builtin_define ("__x86_64__");			\
-	}							\
-      else							\
-	{							\
-	  builtin_assert ("cpu=i386");				\
-	  builtin_assert ("machine=i386");			\
-	  builtin_define_std ("i386");				\
-	}							\
-								\
-      /* Built-ins based on -march=.  */			\
-      switch (ix86_arch)					\
-	{							\
-	case PROCESSOR_I386:					\
-	  break;						\
-	case PROCESSOR_I486:					\
-	  builtin_define ("__i486");				\
-	  builtin_define ("__i486__");				\
-	  break;						\
-	case PROCESSOR_PENTIUM:					\
-	  builtin_define ("__i586");				\
-	  builtin_define ("__i586__");				\
-	  builtin_define ("__pentium");				\
-	  builtin_define ("__pentium__");			\
-	  if (last_arch_char == 'x')				\
-	    builtin_define ("__pentium_mmx__");			\
-	  break;						\
-	case PROCESSOR_PENTIUMPRO:				\
-	  builtin_define ("__i686");				\
-	  builtin_define ("__i686__");				\
-	  builtin_define ("__pentiumpro");			\
-	  builtin_define ("__pentiumpro__");			\
-	  break;						\
-	case PROCESSOR_GEODE:					\
-	  builtin_define ("__geode");				\
-	  builtin_define ("__geode__");				\
-	  break;						\
-	case PROCESSOR_K6:					\
-	  builtin_define ("__k6");				\
-	  builtin_define ("__k6__");				\
-	  if (last_arch_char == '2')				\
-	    builtin_define ("__k6_2__");			\
-	  else if (last_arch_char == '3')			\
-	    builtin_define ("__k6_3__");			\
-	  break;						\
-	case PROCESSOR_ATHLON:					\
-	  builtin_define ("__athlon");				\
-	  builtin_define ("__athlon__");			\
-	  /* Only plain "athlon" lacks SSE.  */			\
-	  if (last_arch_char != 'n')				\
-	    builtin_define ("__athlon_sse__");			\
-	  break;						\
-	case PROCESSOR_K8:					\
-	  builtin_define ("__k8");				\
-	  builtin_define ("__k8__");				\
-	  break;						\
-	case PROCESSOR_AMDFAM10:				\
-	  builtin_define ("__amdfam10");			\
-	  builtin_define ("__amdfam10__");			\
-	  break;						\
-	case PROCESSOR_PENTIUM4:				\
-	  builtin_define ("__pentium4");			\
-	  builtin_define ("__pentium4__");			\
-	  break;						\
-	case PROCESSOR_NOCONA:					\
-	  builtin_define ("__nocona");				\
-	  builtin_define ("__nocona__");			\
-	  break;						\
-	case PROCESSOR_CORE2:					\
-	  builtin_define ("__core2");				\
-	  builtin_define ("__core2__");				\
-	  break;						\
-	case PROCESSOR_GENERIC32:				\
-	case PROCESSOR_GENERIC64:				\
-	case PROCESSOR_max:					\
-	  gcc_unreachable ();					\
-	}							\
-								\
-      /* Built-ins based on -mtune=.  */			\
-      switch (ix86_tune)					\
-	{							\
-	case PROCESSOR_I386:					\
-	  builtin_define ("__tune_i386__");			\
-	  break;						\
-	case PROCESSOR_I486:					\
-	  builtin_define ("__tune_i486__");			\
-	  break;						\
-	case PROCESSOR_PENTIUM:					\
-	  builtin_define ("__tune_i586__");			\
-	  builtin_define ("__tune_pentium__");			\
-	  if (last_tune_char == 'x')				\
-	    builtin_define ("__tune_pentium_mmx__");		\
-	  break;						\
-	case PROCESSOR_PENTIUMPRO:				\
-	  builtin_define ("__tune_i686__");			\
-	  builtin_define ("__tune_pentiumpro__");		\
-	  switch (last_tune_char)				\
-	    {							\
-	    case '3':						\
-	      builtin_define ("__tune_pentium3__");		\
-	      /* FALLTHRU */					\
-	    case '2':						\
-	      builtin_define ("__tune_pentium2__");		\
-	      break;						\
-	    }							\
-	  break;						\
-	case PROCESSOR_GEODE:					\
-	  builtin_define ("__tune_geode__");			\
-	  break;						\
-	case PROCESSOR_K6:					\
-	  builtin_define ("__tune_k6__");			\
-	  if (last_tune_char == '2')				\
-	    builtin_define ("__tune_k6_2__");			\
-	  else if (last_tune_char == '3')			\
-	    builtin_define ("__tune_k6_3__");			\
-	  break;						\
-	case PROCESSOR_ATHLON:					\
-	  builtin_define ("__tune_athlon__");			\
-	  /* Only plain "athlon" lacks SSE.  */			\
-	  if (last_tune_char != 'n')				\
-	    builtin_define ("__tune_athlon_sse__");		\
-	  break;						\
-	case PROCESSOR_K8:					\
-	  builtin_define ("__tune_k8__");			\
-	  break;						\
-	case PROCESSOR_AMDFAM10:				\
-	  builtin_define ("__tune_amdfam10__");			\
-	  break;						\
-	case PROCESSOR_PENTIUM4:				\
-	  builtin_define ("__tune_pentium4__");			\
-	  break;						\
-        case PROCESSOR_NOCONA:					\
-	  builtin_define ("__tune_nocona__");			\
-	  break;						\
-	case PROCESSOR_CORE2:					\
-	  builtin_define ("__tune_core2__");			\
-	  break;						\
-	case PROCESSOR_GENERIC32:				\
-	case PROCESSOR_GENERIC64:				\
-	  break;						\
-	case PROCESSOR_max:					\
-	  gcc_unreachable ();					\
-	}							\
-								\
-      if (TARGET_MMX)						\
-	builtin_define ("__MMX__");				\
-      if (TARGET_3DNOW)						\
-	builtin_define ("__3dNOW__");				\
-      if (TARGET_3DNOW_A)					\
-	builtin_define ("__3dNOW_A__");				\
-      if (TARGET_SSE)						\
-	builtin_define ("__SSE__");				\
-      if (TARGET_SSE2)						\
-	builtin_define ("__SSE2__");				\
-      if (TARGET_SSE3)						\
-	builtin_define ("__SSE3__");				\
-      if (TARGET_SSSE3)						\
-	builtin_define ("__SSSE3__");				\
-      if (TARGET_SSE4_1)					\
-	builtin_define ("__SSE4_1__");				\
-      if (TARGET_SSE4_2)					\
-	builtin_define ("__SSE4_2__");				\
-      if (TARGET_AES)						\
-	builtin_define ("__AES__");				\
-      if (TARGET_PCLMUL)					\
-	builtin_define ("__PCLMUL__");				\
-      if (TARGET_SSE4A)						\
- 	builtin_define ("__SSE4A__");		                \
-      if (TARGET_SSE5)						\
-	builtin_define ("__SSE5__");				\
-      if (TARGET_SSE_MATH && TARGET_SSE)			\
-	builtin_define ("__SSE_MATH__");			\
-      if (TARGET_SSE_MATH && TARGET_SSE2)			\
-	builtin_define ("__SSE2_MATH__");			\
-    }								\
-  while (0)
+#define TARGET_CPU_CPP_BUILTINS() ix86_target_macros ()
 
 enum target_cpu_default
 {
Index: gcc/config/i386/i386-c.c
===================================================================
--- gcc/config/i386/i386-c.c	(revision 0)
+++ gcc/config/i386/i386-c.c	(revision 0)
@@ -0,0 +1,330 @@
+/* Subroutines used for macro/preprocessor support on the ia-32.
+   Copyright (C) 2008
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tree.h"
+#include "tm_p.h"
+#include "flags.h"
+#include "c-common.h"
+#include "ggc.h"
+#include "target.h"
+#include "target-def.h"
+#include "cpplib.h"
+#include "c-pragma.h"
+
+static bool ix86_pragma_option_parse (tree);
+static void ix86_target_macros_internal
+  (int, enum processor_type, enum processor_type, enum fpmath_unit,
+   void (*def_or_undef) (cpp_reader *, const char *));
+
+
+/* Internal function to either define or undef the appropriate system
+   macros.  */
+static void
+ix86_target_macros_internal (int isa_flag,
+			     enum processor_type arch,
+			     enum processor_type tune,
+			     enum fpmath_unit fpmath,
+			     void (*def_or_undef) (cpp_reader *,
+						   const char *))
+{
+  /* For some of the k6/pentium varients there weren't seperate ISA bits to
+     identify which tune/arch flag was passed, so figure it out here.  */
+  size_t arch_len = strlen (ix86_arch_string);
+  size_t tune_len = strlen (ix86_tune_string);
+  int last_arch_char = ix86_arch_string[arch_len - 1];
+  int last_tune_char = ix86_tune_string[tune_len - 1];
+
+  /* Built-ins based on -march=.  */
+  switch (arch)
+    {
+    case PROCESSOR_I386:
+      break;
+    case PROCESSOR_I486:
+      def_or_undef (parse_in, "__i486");
+      def_or_undef (parse_in, "__i486__");
+      break;
+    case PROCESSOR_PENTIUM:
+      def_or_undef (parse_in, "__i586");
+      def_or_undef (parse_in, "__i586__");
+      def_or_undef (parse_in, "__pentium");
+      def_or_undef (parse_in, "__pentium__");
+      if (isa_flag & OPTION_MASK_ISA_MMX)
+	def_or_undef (parse_in, "__pentium_mmx__");
+      break;
+    case PROCESSOR_PENTIUMPRO:
+      def_or_undef (parse_in, "__i686");
+      def_or_undef (parse_in, "__i686__");
+      def_or_undef (parse_in, "__pentiumpro");
+      def_or_undef (parse_in, "__pentiumpro__");
+      break;
+    case PROCESSOR_GEODE:
+      def_or_undef (parse_in, "__geode");
+      def_or_undef (parse_in, "__geode__");
+      break;
+    case PROCESSOR_K6:
+      def_or_undef (parse_in, "__k6");
+      def_or_undef (parse_in, "__k6__");
+      if (last_arch_char == '2')
+	def_or_undef (parse_in, "__k6_2__");
+      else if (last_arch_char == '3')
+	def_or_undef (parse_in, "__k6_3__");
+      else if (isa_flag & OPTION_MASK_ISA_3DNOW)
+	def_or_undef (parse_in, "__k6_3__");
+      break;
+    case PROCESSOR_ATHLON:
+      def_or_undef (parse_in, "__athlon");
+      def_or_undef (parse_in, "__athlon__");
+      if (isa_flag & OPTION_MASK_ISA_SSE)
+	def_or_undef (parse_in, "__athlon_sse__");
+      break;
+    case PROCESSOR_K8:
+      def_or_undef (parse_in, "__k8");
+      def_or_undef (parse_in, "__k8__");
+      break;
+    case PROCESSOR_AMDFAM10:
+      def_or_undef (parse_in, "__amdfam10");
+      def_or_undef (parse_in, "__amdfam10__");
+      break;
+    case PROCESSOR_PENTIUM4:
+      def_or_undef (parse_in, "__pentium4");
+      def_or_undef (parse_in, "__pentium4__");
+      break;
+    case PROCESSOR_NOCONA:
+      def_or_undef (parse_in, "__nocona");
+      def_or_undef (parse_in, "__nocona__");
+      break;
+    case PROCESSOR_CORE2:
+      def_or_undef (parse_in, "__core2");
+      def_or_undef (parse_in, "__core2__");
+      break;
+    /* use PROCESSOR_max to not set/unset the arch macro.  */
+    case PROCESSOR_max:
+      break;
+    case PROCESSOR_GENERIC32:
+    case PROCESSOR_GENERIC64:
+      gcc_unreachable ();
+    }
+
+  /* Built-ins based on -mtune=.  */
+  switch (tune)
+    {
+    case PROCESSOR_I386:
+      def_or_undef (parse_in, "__tune_i386__");
+      break;
+    case PROCESSOR_I486:
+      def_or_undef (parse_in, "__tune_i486__");
+      break;
+    case PROCESSOR_PENTIUM:
+      def_or_undef (parse_in, "__tune_i586__");
+      def_or_undef (parse_in, "__tune_pentium__");
+      if (last_tune_char == 'x')
+	def_or_undef (parse_in, "__tune_pentium_mmx__");
+      break;
+    case PROCESSOR_PENTIUMPRO:
+      def_or_undef (parse_in, "__tune_i686__");
+      def_or_undef (parse_in, "__tune_pentiumpro__");
+      switch (last_tune_char)
+	{
+	case '3':
+	  def_or_undef (parse_in, "__tune_pentium3__");
+	  /* FALLTHRU */
+	case '2':
+	  def_or_undef (parse_in, "__tune_pentium2__");
+	  break;
+	}
+      break;
+    case PROCESSOR_GEODE:
+      def_or_undef (parse_in, "__tune_geode__");
+      break;
+    case PROCESSOR_K6:
+      def_or_undef (parse_in, "__tune_k6__");
+      if (last_tune_char == '2')
+	def_or_undef (parse_in, "__tune_k6_2__");
+      else if (last_tune_char == '3')
+	def_or_undef (parse_in, "__tune_k6_3__");
+      else if (isa_flag & OPTION_MASK_ISA_3DNOW)
+	def_or_undef (parse_in, "__tune_k6_3__");
+      break;
+    case PROCESSOR_ATHLON:
+      def_or_undef (parse_in, "__tune_athlon__");
+      if (isa_flag & OPTION_MASK_ISA_SSE)
+	def_or_undef (parse_in, "__tune_athlon_sse__");
+      break;
+    case PROCESSOR_K8:
+      def_or_undef (parse_in, "__tune_k8__");
+      break;
+    case PROCESSOR_AMDFAM10:
+      def_or_undef (parse_in, "__tune_amdfam10__");
+      break;
+    case PROCESSOR_PENTIUM4:
+      def_or_undef (parse_in, "__tune_pentium4__");
+      break;
+    case PROCESSOR_NOCONA:
+      def_or_undef (parse_in, "__tune_nocona__");
+      break;
+    case PROCESSOR_CORE2:
+      def_or_undef (parse_in, "__tune_core2__");
+      break;
+    case PROCESSOR_GENERIC32:
+    case PROCESSOR_GENERIC64:
+      break;
+    /* use PROCESSOR_max to not set/unset the tune macro.  */
+    case PROCESSOR_max:
+      break;
+    }
+
+  if (isa_flag & OPTION_MASK_ISA_MMX)
+    def_or_undef (parse_in, "__MMX__");
+  if (isa_flag & OPTION_MASK_ISA_3DNOW)
+    def_or_undef (parse_in, "__3dNOW__");
+  if (isa_flag & OPTION_MASK_ISA_3DNOW_A)
+    def_or_undef (parse_in, "__3dNOW_A__");
+  if (isa_flag & OPTION_MASK_ISA_SSE)
+    def_or_undef (parse_in, "__SSE__");
+  if (isa_flag & OPTION_MASK_ISA_SSE2)
+    def_or_undef (parse_in, "__SSE2__");
+  if (isa_flag & OPTION_MASK_ISA_SSE3)
+    def_or_undef (parse_in, "__SSE3__");
+  if (isa_flag & OPTION_MASK_ISA_SSSE3)
+    def_or_undef (parse_in, "__SSSE3__");
+  if (isa_flag & OPTION_MASK_ISA_SSE4_1)
+    def_or_undef (parse_in, "__SSE4_1__");
+  if (isa_flag & OPTION_MASK_ISA_SSE4_2)
+    def_or_undef (parse_in, "__SSE4_2__");
+  if (isa_flag & OPTION_MASK_ISA_AES)
+    def_or_undef (parse_in, "__AES__");
+  if (isa_flag & OPTION_MASK_ISA_PCLMUL)
+    def_or_undef (parse_in, "__PCLMUL__");
+  if (isa_flag & OPTION_MASK_ISA_SSE4A)
+    def_or_undef (parse_in, "__SSE4A__");
+  if (isa_flag & OPTION_MASK_ISA_SSE5)
+    def_or_undef (parse_in, "__SSE5__");
+  if ((fpmath & FPMATH_SSE) && (isa_flag & OPTION_MASK_ISA_SSE))
+    def_or_undef (parse_in, "__SSE_MATH__");
+  if ((fpmath & FPMATH_SSE) && (isa_flag & OPTION_MASK_ISA_SSE2))
+    def_or_undef (parse_in, "__SSE2_MATH__");
+}
+
+
+/* Hook to validate the current #pragma option and set the state, and update
+   the macros based on what was changed.  */
+
+static bool
+ix86_pragma_option_parse (tree args)
+{
+  tree prev_tree = build_target_option_node ();
+  tree cur_tree;
+  struct cl_target_option *prev_opt;
+  struct cl_target_option *cur_opt;
+  int prev_isa;
+  int cur_isa;
+  int diff_isa;
+  enum processor_type prev_arch;
+  enum processor_type prev_tune;
+  enum processor_type cur_arch;
+  enum processor_type cur_tune;
+
+  if (! args)
+    {
+      cur_tree = target_option_default_node;
+      cl_target_option_restore (TREE_TARGET_OPTION (cur_tree));
+    }
+  else
+    {
+      cur_tree = ix86_valid_option_attribute_tree (args);
+      if (!cur_tree)
+	return false;
+    }
+
+  target_option_current_node = cur_tree;
+
+  /* Figure out the previous/current isa, arch, tune and the differences.  */
+  prev_opt  = TREE_TARGET_OPTION (prev_tree);
+  cur_opt   = TREE_TARGET_OPTION (cur_tree);
+  prev_isa  = prev_opt->ix86_isa_flags;
+  cur_isa   = cur_opt->ix86_isa_flags;
+  diff_isa  = (prev_isa ^ cur_isa);
+  prev_arch = prev_opt->arch;
+  prev_tune = prev_opt->tune;
+  cur_arch  = cur_opt->arch;
+  cur_tune  = cur_opt->tune;
+
+  /* If the same processor is used for both previous and current options, don't
+     change the macros.  */
+  if (cur_arch == prev_arch)
+    cur_arch = prev_arch = PROCESSOR_max;
+
+  if (cur_tune == prev_tune)
+    cur_tune = prev_tune = PROCESSOR_max;
+
+  /* Undef all of the macros for that are no longer current.  */
+  ix86_target_macros_internal (prev_isa & diff_isa,
+			       prev_arch,
+			       prev_tune,
+			       prev_opt->fpmath,
+			       cpp_undef);
+
+  /* Define all of the macros for new options that were just turned on.  */
+  ix86_target_macros_internal (cur_isa & diff_isa,
+			       cur_arch,
+			       cur_tune,
+			       cur_opt->fpmath,
+			       cpp_define);
+
+  return true;
+}
+
+/* Function to tell the preprocessor about the defines for the current target.  */
+
+void
+ix86_target_macros (void)
+{
+  /* Update pragma hook to allow parsing #pragma GCC option.  */
+  targetm.target_option_pragma_parse = ix86_pragma_option_parse;
+
+  /* 32/64-bit won't change with target specific options, so do the assert and
+     builtin_define_std calls here.  */
+  if (TARGET_64BIT)
+    {
+      cpp_assert (parse_in, "cpu=x86_64");
+      cpp_assert (parse_in, "machine=x86_64");
+      cpp_define (parse_in, "__amd64");
+      cpp_define (parse_in, "__amd64__");
+      cpp_define (parse_in, "__x86_64");
+      cpp_define (parse_in, "__x86_64__");
+    }
+  else
+    {
+      cpp_assert (parse_in, "cpu=i386");
+      cpp_assert (parse_in, "machine=i386");
+      builtin_define_std ("i386");
+    }
+
+  ix86_target_macros_internal (ix86_isa_flags,
+			       ix86_arch,
+			       ix86_tune,
+			       ix86_fpmath,
+			       cpp_define);
+}
Index: gcc/config/i386/t-i386
===================================================================
--- gcc/config/i386/t-i386	(revision 0)
+++ gcc/config/i386/t-i386	(revision 0)
@@ -0,0 +1,13 @@
+i386.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+  $(RTL_H) $(TREE_H) $(TM_P_H) $(REGS_H) hard-reg-set.h \
+  $(REAL_H) insn-config.h conditions.h output.h insn-codes.h \
+  $(INSN_ATTR_H) $(FLAGS_H) $(C_COMMON_H) except.h $(FUNCTION_H) \
+  $(RECOG_H) $(EXPR_H) $(OPTABS_H) toplev.h $(BASIC_BLOCK_H) \
+  $(GGC_H) $(TARGET_H) $(TARGET_DEF_H) langhooks.h $(CGRAPH_H) \
+  $(TREE_GIMPLE_H) dwarf2.h $(DF_H) tm-constrs.h $(PARAMS_H)
+
+i386-c.o: $(srcdir)/config/i386/i386-c.c \
+  $(srcdir)/config/i386/i386-protos.h $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(FLAGS_H) $(C_COMMON_H) $(GGC_H) \
+  $(TARGET_H) $(TARGET_DEF_H) $(CPPLIB_H) $(C_PRAGMA_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/i386/i386-c.c
Index: gcc/config/i386/i386-protos.h
===================================================================
--- gcc/config/i386/i386-protos.h	(revision 136933)
+++ gcc/config/i386/i386-protos.h	(working copy)
@@ -199,6 +199,7 @@ extern int ix86_constant_alignment (tree
 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_option_attribute_tree (tree);
 #endif
 
 extern rtx ix86_tls_get_addr (void);
@@ -212,6 +213,9 @@ extern void ix86_expand_reduc_v4sf (rtx 
 extern bool ix86_sse5_valid_op_p (rtx [], rtx, int, bool, int);
 extern void ix86_expand_sse5_multiple_memory (rtx [], int, enum machine_mode);
 
+/* In i386-c.c  */
+extern void ix86_target_macros (void);
+
 /* In winnt.c  */
 extern void i386_pe_unique_section (tree, int);
 extern void i386_pe_declare_function_type (FILE *, const char *, int);
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 136933)
+++ gcc/config/i386/i386.c	(working copy)
@@ -1789,7 +1789,6 @@ static void ix86_function_specific_print
 					  struct cl_target_option *);
 static bool ix86_valid_option_attribute_p (tree, tree, tree, int);
 static bool ix86_valid_option_attribute_inner_p (tree, char *[]);
-static void ix86_insert_attributes (tree, tree *);
 static bool ix86_can_inline_p (tree, tree);
 static void ix86_set_current_function (tree);
 
@@ -1946,7 +1945,7 @@ static const char *const cpu_names[TARGE
   "k8",
   "amdfam10"
 };
-
+
 /* Implement TARGET_HANDLE_OPTION.  */
 
 static bool
@@ -2179,7 +2178,7 @@ ix86_handle_option (size_t code, const c
       return true;
     }
 }
-
+
 /* Return a string the documents the current -m options.  The caller is
    responsible for freeing the string.  */
 
@@ -2384,7 +2383,7 @@ ix86_debug_options (void)
 
   return;
 }
-
+
 /* Sometimes certain combinations of command options do not make
    sense on a particular target machine.  You can define a macro
    `OVERRIDE_OPTIONS' to take account of this.  This macro, if
@@ -3181,11 +3180,8 @@ override_options (bool main_args_p)
 
   /* Save the initial options in case the user does function specific options */
   if (main_args_p)
-    {
-      tree t = make_node (TARGET_OPTION_NODE);
-      target_option_default_node = t;
-      cl_target_option_save (TREE_TARGET_OPTION (t));
-    }
+    target_option_default_node = target_option_current_node
+      = build_target_option_node ();
 }
 
 /* Save the current options */
@@ -3213,6 +3209,8 @@ ix86_function_specific_save (struct cl_t
 static void
 ix86_function_specific_restore (struct cl_target_option *ptr)
 {
+  enum processor_type old_tune = ix86_tune;
+  enum processor_type old_arch = ix86_arch;
   unsigned int ix86_arch_mask, ix86_tune_mask;
   int i;
 
@@ -3225,15 +3223,23 @@ ix86_function_specific_restore (struct c
   ix86_isa_flags_explicit = ptr->ix86_isa_flags_explicit;
   target_flags_explicit = ptr->target_flags_explicit;
 
-  /* Recreate the arch feature tests */
-  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);
+  /* Recreate the arch feature tests if the arch changed */
+  if (old_arch != ix86_arch)
+    {
+      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);
+    }
 
   /* Recreate the tune optimization tests */
-  ix86_tune_mask = 1u << ix86_tune;
-  for (i = 0; i < X86_TUNE_LAST; ++i)
-    ix86_tune_features[i] = !!(initial_ix86_tune_features[i] & ix86_tune_mask);
+  if (old_tune != ix86_tune)
+    {
+      ix86_tune_mask = 1u << ix86_tune;
+      for (i = 0; i < X86_TUNE_LAST; ++i)
+	ix86_tune_features[i]
+	  = !!(initial_ix86_tune_features[i] & ix86_tune_mask);
+    }
 }
 
 /* Print the current options */
@@ -3242,6 +3248,10 @@ static void
 ix86_function_specific_print (FILE *file, int indent,
 			      struct cl_target_option *ptr)
 {
+  char *target_string
+    = ix86_target_string (ptr->ix86_isa_flags, ptr->target_flags,
+			  NULL, NULL, NULL, false);
+
   fprintf (file, "%*sarch = %d (%s)\n",
 	   indent, "",
 	   ptr->arch,
@@ -3256,8 +3266,16 @@ ix86_function_specific_print (FILE *file
 	    ? cpu_names[ptr->tune]
 	    : "<unknown>"));
 
-  fprintf (file, "%*sfpmath = %d\n", indent, "", ptr->fpmath);
+  fprintf (file, "%*sfpmath = %d%s%s\n", indent, "", ptr->fpmath,
+	   (ptr->fpmath & FPMATH_387) ? ", 387" : "",
+	   (ptr->fpmath & FPMATH_SSE) ? ", sse" : "");
   fprintf (file, "%*sbranch_cost = %d\n", indent, "", ptr->branch_cost);
+
+  if (target_string)
+    {
+      fprintf (file, "%*s%s\n", indent, "", target_string);
+      free (target_string);
+    }
 }
 
 
@@ -3294,6 +3312,7 @@ ix86_valid_option_attribute_inner_p (tre
     int mask;
   } attrs[] = {
     /* isa options */
+    IX86_ATTR_ISA ("3dnow",	OPT_m3dnow),
     IX86_ATTR_ISA ("abm",	OPT_mabm),
     IX86_ATTR_ISA ("aes",	OPT_maes),
     IX86_ATTR_ISA ("mmx",	OPT_mmmx),
@@ -3463,30 +3482,25 @@ ix86_valid_option_attribute_inner_p (tre
   return ret;
 }
 
-/* Hook to validate attribute((option("string"))).  */
+/* Return a TARGET_OPTION_NODE tree of the target options listed or NULL.  */
 
-static bool
-ix86_valid_option_attribute_p (tree fndecl,
-			       tree ARG_UNUSED (name),
-			       tree args,
-			       int ARG_UNUSED (flags))
+tree
+ix86_valid_option_attribute_tree (tree args)
 {
-  bool ret;
   const char *orig_arch_string = ix86_arch_string;
   const char *orig_tune_string = ix86_tune_string;
   const char *orig_fpmath_string = ix86_fpmath_string;
   int orig_tune_defaulted = ix86_tune_defaulted;
   int orig_arch_specified = ix86_arch_specified;
   char *option_strings[IX86_FUNCTION_SPECIFIC_MAX] = { NULL, NULL, NULL };
+  tree t = NULL_TREE;
   int i;
   struct cl_target_option *def
     = TREE_TARGET_OPTION (target_option_default_node);
 
-  /* Make sure we start with clean options.  */
-  cl_target_option_restore (def);
-
   /* Process each of the options on the chain.  */
-  ret = ix86_valid_option_attribute_inner_p (args, option_strings);
+  if (! ix86_valid_option_attribute_inner_p (args, option_strings))
+    return NULL_TREE;
 
   /* If the changed options are different from the default, rerun override_options,
      and then save the options away.  The string options are are attribute options,
@@ -3520,15 +3534,7 @@ ix86_valid_option_attribute_p (tree fnde
 
       /* Save the current options unless we are validating options for
 	 #pragma.  */
-      if (fndecl)
-	{
-	  tree t = make_node (TARGET_OPTION_NODE);
-	  DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = t;
-	  cl_target_option_save (TREE_TARGET_OPTION (t));
-	}
-
-      /* Restore options.  */
-      cl_target_option_restore (def);
+      t = build_target_option_node ();
 
       ix86_arch_string = orig_arch_string;
       ix86_tune_string = orig_tune_string;
@@ -3540,6 +3546,30 @@ ix86_valid_option_attribute_p (tree fnde
 	  free (option_strings[i]);
     }
 
+  return t;
+}
+
+/* Hook to validate attribute((option("string"))).  */
+
+static bool
+ix86_valid_option_attribute_p (tree fndecl,
+			       tree ARG_UNUSED (name),
+			       tree args,
+			       int ARG_UNUSED (flags))
+{
+  struct cl_target_option cur_opts;
+  bool ret = true;
+  tree new_opts;
+
+  cl_target_option_save (&cur_opts);
+  new_opts = ix86_valid_option_attribute_tree (args);
+  if (!new_opts)
+    ret = false;
+
+  else if (fndecl)
+    DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_opts;
+
+  cl_target_option_restore (&cur_opts);
   return ret;
 }
 
@@ -3599,57 +3629,29 @@ ix86_can_inline_p (tree caller, tree cal
 }
 
 
-/* Insert any target specific attributes to a declaration.  */
+/* Remember the last target of ix86_set_current_function.  */
+static GTY(()) tree ix86_previous_fndecl;
 
-static void
-ix86_insert_attributes (tree node, tree *attr_ptr ATTRIBUTE_UNUSED)
-{
-  /* If this is a function, do we have an option pragma?  If so, add it and
-     re-validate it, which will create the appropriate target option node in
-     the node.  */
-
-  if (TREE_CODE (node) == FUNCTION_DECL
-      && current_option_pragma
-      && ix86_valid_option_attribute_p (node, NULL_TREE,
-					current_option_pragma, 0))
-    {
-      tree cur_attr = lookup_attribute ("option", *attr_ptr);
-      tree opts = copy_list (current_option_pragma);
-
-      if (! cur_attr)
-	*attr_ptr = tree_cons (get_identifier ("option"), opts, *attr_ptr);
-      else
-	TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr));
-    }
-
-#ifdef SUBTARGET_INSERT_ATTRIBUTES
-  SUBTARGET_INSERT_ATTRIBUTES (tree, attr_ptr);
-#endif
-}
-
-
 /* Establish appropriate back-end context for processing the function
    FNDECL.  The argument might be NULL to indicate processing at top
    level, outside of any function scope.  */
 static void
 ix86_set_current_function (tree fndecl)
 {
-  static tree previous_fndecl = NULL_TREE;
-
   /* Only change the context if the function changes.  This hook is called
      several times in the course of compiling a function, and we don't want to
      slow things down too much or call target_reinit when it isn't safe.  */
-  if (fndecl && fndecl != previous_fndecl)
+  if (fndecl && fndecl != ix86_previous_fndecl)
     {
-      tree old_tree = (previous_fndecl
-		       ? DECL_FUNCTION_SPECIFIC_TARGET (previous_fndecl)
+      tree old_tree = (ix86_previous_fndecl
+		       ? DECL_FUNCTION_SPECIFIC_TARGET (ix86_previous_fndecl)
 		       : NULL_TREE);
 
       tree new_tree = (fndecl
 		       ? DECL_FUNCTION_SPECIFIC_TARGET (fndecl)
 		       : NULL_TREE);
 
-      previous_fndecl = fndecl;
+      ix86_previous_fndecl = fndecl;
       if (old_tree == new_tree)
 	;
 
@@ -3662,7 +3664,7 @@ ix86_set_current_function (tree fndecl)
       else if (old_tree)
 	{
 	  struct cl_target_option *def
-	    = TREE_TARGET_OPTION (target_option_default_node);
+	    = TREE_TARGET_OPTION (target_option_current_node);
 
 	  cl_target_option_restore (def);
 	  target_reinit ();
@@ -19960,7 +19962,7 @@ static const struct builtin_description 
    is zero.  Otherwise, if TARGET_SSE is not set, only expand the MMX
    builtins.  */
 static void
-ix86_init_mmx_sse_builtins (void)
+ix86_init_builtins (void)
 {
   const struct builtin_description * d;
   size_t i;
@@ -21097,13 +21099,6 @@ ix86_init_mmx_sse_builtins (void)
     }
 }
 
-static void
-ix86_init_builtins (void)
-{
-  if (TARGET_MMX)
-    ix86_init_mmx_sse_builtins ();
-}
-
 /* Errors in the source file can cause expand_expr to return const0_rtx
    where we expect a vector.  To avoid crashing, use one of the vector
    clear instructions.  */
@@ -26937,8 +26932,10 @@ x86_builtin_vectorization_cost (bool run
 #define TARGET_ASM_OUTPUT_DWARF_DTPREL i386_output_dwarf_dtprel
 #endif
 
+#ifdef SUBTARGET_INSERT_ATTRIBUTES
 #undef TARGET_INSERT_ATTRIBUTES
-#define TARGET_INSERT_ATTRIBUTES ix86_insert_attributes
+#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
+#endif
 
 #undef TARGET_MANGLE_TYPE
 #define TARGET_MANGLE_TYPE ix86_mangle_type

-- 
Michael Meissner, AMD
90 Central Street, MS 83-29, Boxborough, MA, 01719, USA
michael.meissner@amd.com



More information about the Gcc-patches mailing list