PATCH [function-specific, committed] Add #pragma support, make cold functions compile with -Os

Michael Meissner michael.meissner@amd.com
Wed Jun 18 00:19:00 GMT 2008


I committed the following patch to the function-specific branch.  I need to do
more testing, etc. before submitting it to the mainline, add more tests, etc..
I think I have a regression or two I need to check out tomorrow.

This patch adds the #pragma GCC option support to the branch.  Syntax is:
     #pragma GCC option "string"...
     #pragma GCC option push
     #pragma GCC option pop
     #pragma GCC option revert

Where the first option takes one or more strings that are the same strings that
attribute((option(...))) takes, and internally, the #pragmas get converted to
the attributes.

This patch also allows a function to be compiled with different optimization
options than the standard in addition to different target options.  Right now,
the only use is to compile cold functions with -Os.  I am stilling mulling over
how much of the optimization interface to allow users to use via attribute or
#pragma.  I would be interested in hearing from potential users whether you
really need to set say -ftree-vectorize in a function, or just having
-O1/-O2/-O3/-Os is sufficient, and have the -f options inherited from the
command line.

I also reorganized the data structures, so that the structure that holds the
target specific options is at the toplevel, and there are hooks for the MD
parts, instead of the other way around.  I added a new record format type in
the *.opt file so that a backend can specify what fields should be put into the
cl_target_option structure.  I also moved the optimization/target option
structures into full tree nodes.

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

	* doc/options.texi (TargetSave): Document new TargetSave flag to
	create declarations in the cl_target_option structure.
	(Save): Change structure name to cl_target_option from
	cl_option_save.

	* doc/extend.texi (#pragma GCC option): Document #pragma GCC
	option.

	* flags.h (optimize_for_space): Add declaration.

	* tree.c (tree_code_size): Support OPTIMIZATION_NODE and
	TARGET_OPTION_NODE tree structures.
	(tree_node_structure): Ditto.

	* tree.h (DECL_FUNCTION_SPECIFIC_TARGET): Rename from
	DECL_FUNCTION_SPECIFIC.
	(DECL_FUNCTION_SPECIFIC_OPTIMIZATION): New accessor macro.
	(struct tree_function_decl): Change function_specific_data to
	function_specific_target.  Add function_specific_optimization to
	point to the machine independent optimization fields.
	(struct tree_optimization_option): New tree structure to hold the
	machine independent optimization options.
	(TREE_OPTIMIZATION): New accessor macro.
	(struct tree_target_otpion): New tree structure to hold the target
	specific optins that can be changed on a per-function basis.
	(TREE_TARGET_OPTION): New acessor macro.
	(union tree_node): Add tree_optimization_option and
	tree_target_option fields.
	(enum tree_index): Add TI_OPTIMIZATION_DEFAULT,
	TI_OPTIMIZATION_CURRENT, TI_OPTIMIZATION_COLD,
	TI_TARGET_OPTION_DEFAULT, and TI_CURRENT_OPTION_PRAGMA.
	(optimization_default_node): Define as an element in
	global_trees.
	(optimization_current_node): Ditto.
	(optimization_cold_node): Ditto.
	(target_option_default_node): Ditto.
	(current_option_pragma): Ditto.

	* target.h (struct gcc_target): Add new hook functions,
	target_option_save, target_option_restore, target_option_print.

	* opts.c (optimize_for_space): New function, unset optimizations
	that tend to cause code bloat for turning -Os on in cold
	functions.
	(decode_options): Call optimze_for_space if -Os.  On the first
	call, save the current optimization options.

	* optc-gen.awk (flags.h): Include in options.c.
	(target.h): Ditto.
	(cl_optimization_save): Create new functions for saving,
	restoring, and printing optimization options.  Sort by the field
	size.  On the save, add gcc_asserts to make sure the value is not
	truncated.
	(cl_optimization_restore): Ditto.
	(cl_optimization_print): Ditto.
	(cl_target_option_save): Rename from cl_options_save and
	cl_options_restore.  If no 'Save' flag is used, just save and
	restore target_flags.  Sort by the field size.  On the save, add
	gcc_asserts to make sure the value is not truncated.  Call target
	hooks to save/restore other values.

	* opth-gen.awk (struct cl_optimization): New structure that is
	created to remember all optimization options.  Compress fields to
	unsigned char to save space if it is safe.  Sort fields by size.
	(struct cl_target_option): Rename from cl_option_save.  Compress
	fields to unsigned char to save space if is safe.  Sort fields by
	size.  Add support for TargetSafe to store additional fields.

	* opt-functions.awk (var_type_struct): New function to return
	appropriate type for the cl_target_option and cl_optimization
	structures.

	* treestruct.def (TS_OPTIMIZATION): New tree structure for saving
	optimization options.
	(TS_TARGET_OPTION): New tree structure for saving target specific
	options.

	* function.c (invoke_set_current_function_hook): If the function
	has different optimization options, switch to use the options.

	* coretypes.h (struct cl_option_save): Delete.
	(struct function_specific_data): Ditto.
	(struct cl_target_option): Add forward declaration.
	(struct cl_optimization): Ditto.

	* c-pragma.c (option_stack): New vector of trees to implement
	#pragma GCC option [push|pop].
	(handle_pragma_option): Add support for #pragma GCC option.
	(init_pragma): Ditto.

	* tree.def (OPTIMIZATION_NODE): New tree node.
	(TARGET_OPTION_NODE): Ditto.

	* print-tree.c (print_node): Add support for OPTIMIZATION_NODE and
	TARGET_OPTION_NODE.

	* target-def.h (TARGET_OPTION_SAVE): New hook function.
	(TARGET_OPTION_RESTORE): Ditto.
	(TARGET_OPTION_PRINT): Ditto.
	(TARGET_INITIALIZER): Add new hooks.

	* c-common.c (handle_cold_attribute): If cold function, and
	-O2/-O3, turn on -Os for this one function.

	* Makefile (TREE_H): Add options.h.
	(options.o): Add $(TARGET_H) and $(FLAGS_H) dependencies.

	* config/i386/i386.h (TARGET_VALID_OPTION_ATTRIBUTE_P): Move to
	i386.c since it doesn't need to be global.
	(TARGET_SET_CURRENT_FUNCTION): Ditto.
	(struct function_specific_data): Delete, contents moved into
	cl_target_option structure.

	* config/i386/i386.opt (arch): New field to be saved in the
	cl_target_option structure.
	(tune): Ditto.
	(fpmath): Ditto.
	(branch_cost): Ditto.
	(ix86_isa_flags_explicit): Ditto.
	(tune_defaulted): Ditto.
	(arch_specified): Ditto.

	* config/i386/i386.c (ix86_function_specific_save): Make a hook
	function called from cl_target_option_save.
	(ix86_function_specific_restore): Make a hook function called from
	cl_target_option_restore.
	(ix86_function_specific_print): New hook function to be called
	from cl_target_option_print.
	(ix86_insert_attributes): New function to insert #pragma GCC
	option attributes.  If SUBTARGET_INSERT_ATTRIBUTES is defined,
	call it.
	(ix86_initial_options): Delete, use new global tree
	function_specific_default_node.
	(override_options): Save the default target options in
	target_option_default_node.
	(ix86_valid_option_attribute_p): Switch to having target options
	in trees.  Allow fndecl to be NULL when parsing #pragma.
	(ix86_can_inline_p): Switch to having target options in trees.
	(ix86_set_current_function): Ditto.
	(TARGET_INSERT_ATTRIBUTES): Call ix86_insert_attributes.
	(TARGET_VALID_OPTION_ATTRIBUTE_P): Move here from i386.h.
	(TARGET_SET_CURRENT_FUNCTION): Ditto.
	(TARGET_CAN_INLINE_P): Ditto.
	(TARGET_OPTION_SAVE): Call ix86_function_specific_save.
	(TARGET_OPTION_RESTORE): Call ix86_function_specific_restore.
	(TARGET_OPTION_PRINT): Call ix86_function_specific_print.

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

	* gcc.target/i386/cold-1.c: New file to test that the cold
	attribute turns on -Os.

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 136724)
+++ gcc/doc/extend.texi	(working copy)
@@ -11136,6 +11136,7 @@ for further explanation.
 * Diagnostic Pragmas::
 * Visibility Pragmas::
 * Push/Pop Macro Pragmas::
+* Target Option Pragmas::
 @end menu
 
 @node ARM Pragmas
@@ -11486,6 +11487,39 @@ 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
+
+@table @code
+@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.
+@end table
+
+@table @code
+@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
+the previous options.
+@end table
+
+@table @code
+@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.
+@end table
+
 @node Unnamed Fields
 @section Unnamed struct/union fields within structs/unions
 @cindex struct
Index: gcc/doc/options.texi
===================================================================
--- gcc/doc/options.texi	(revision 136724)
+++ gcc/doc/options.texi	(working copy)
@@ -35,6 +35,11 @@ has been declared in this way, it can be
 @xref{Option properties}.
 
 @item
+A target specific save record to save additional information. _These
+records have ttwo fields: the string @samp{TargetSave}, and a
+declaration type to go in the @code{cl_target_option} structure.
+
+@item
 An option definition record.  These records have the following fields:
 
 @enumerate
@@ -223,7 +228,7 @@ controls whether the option is accepted 
 the @option{--help} output.
 
 @item Save
-Build the @code{cl_option_save} structure to hold a copy of the
-option, add the functions @code{cl_options_save} and
-@code{cl_options_restore} to save and restore the option.
+Build the @code{cl_target_option} structure to hold a copy of the
+option, add the functions @code{cl_target_option_save} and
+@code{cl_target_option_restore} to save and restore the options.
 @end table
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	(revision 136591)
+++ gcc/targhooks.c	(working copy)
@@ -704,8 +704,8 @@ bool
 default_can_inline_p (tree caller, tree callee)
 {
   bool ret = false;
-  struct function_specific_data *callee_opts = DECL_FUNCTION_SPECIFIC (callee);
-  struct function_specific_data *caller_opts = DECL_FUNCTION_SPECIFIC (caller);
+  tree callee_opts = DECL_FUNCTION_SPECIFIC_TARGET (callee);
+  tree caller_opts = DECL_FUNCTION_SPECIFIC_TARGET (caller);
 
   /* If callee has no option attributes, then it is ok to inline */
   if (!callee_opts)
Index: gcc/flags.h
===================================================================
--- gcc/flags.h	(revision 136591)
+++ gcc/flags.h	(working copy)
@@ -357,4 +357,10 @@ enum warn_strict_overflow_code
 /* Whether to emit an overflow warning whose code is C.  */
 #define issue_strict_overflow_warning(c) (warn_strict_overflow >= (int) (c))
 
+/* Unset all of the options that are normally off for -Os.  This is to allow
+   targets to have a function specific option that optimizes for space for a
+   particular function.  It is assumed that the current options have been saved
+   by a call to cl_optimization_save and will be restored by a call to
+   cl_optimization_restore at the end of the function.  */
+extern void optimize_for_space (void);
 #endif /* ! GCC_FLAGS_H */
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 136724)
+++ gcc/tree.c	(working copy)
@@ -426,6 +426,8 @@ tree_code_size (enum tree_code code)
 	case BLOCK:		return sizeof (struct tree_block);
 	case VALUE_HANDLE:	return sizeof (struct tree_value_handle);
 	case CONSTRUCTOR:	return sizeof (struct tree_constructor);
+	case OPTIMIZATION_NODE: return sizeof (struct tree_optimization_option);
+	case TARGET_OPTION_NODE: return sizeof (struct tree_target_option);
 
 	default:
 	  return lang_hooks.tree_size (code);
@@ -2333,6 +2335,8 @@ tree_node_structure (const_tree t)
     case TREE_BINFO:		return TS_BINFO;
     case VALUE_HANDLE:		return TS_VALUE_HANDLE;
     case OMP_CLAUSE:		return TS_OMP_CLAUSE;
+    case OPTIMIZATION_NODE:	return TS_OPTIMIZATION;
+    case TARGET_OPTION_NODE:	return TS_TARGET_OPTION;
 
     default:
       gcc_unreachable ();
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 136724)
+++ gcc/tree.h	(working copy)
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.  
 #include "vec.h"
 #include "double-int.h"
 #include "alias.h"
+#include "options.h"
 
 /* Codes of tree nodes */
 
@@ -3407,10 +3408,15 @@ struct tree_decl_non_common GTY(())
 #define DECL_ARGUMENTS(NODE) (FUNCTION_DECL_CHECK (NODE)->decl_non_common.arguments)
 #define DECL_ARGUMENT_FLD(NODE) (DECL_NON_COMMON_CHECK (NODE)->decl_non_common.arguments)
 
-/* In FUNCTION_DECL, the function specific options to use when compiling this
-   function.  */
-#define DECL_FUNCTION_SPECIFIC(NODE) \
-   (FUNCTION_DECL_CHECK (NODE)->function_decl.function_specific)
+/* In FUNCTION_DECL, the function specific target options to use when compiling
+   this function.  */
+#define DECL_FUNCTION_SPECIFIC_TARGET(NODE) \
+   (FUNCTION_DECL_CHECK (NODE)->function_decl.function_specific_target)
+
+/* In FUNCTION_DECL, the function specific optimization options to use when
+   compiling this function.  */
+#define DECL_FUNCTION_SPECIFIC_OPTIMIZATION(NODE) \
+   (FUNCTION_DECL_CHECK (NODE)->function_decl.function_specific_optimization)
 
 /* FUNCTION_DECL inherits from DECL_NON_COMMON because of the use of the
    arguments/result/saved_tree fields by front ends.   It was either inherit
@@ -3424,7 +3430,8 @@ struct tree_function_decl GTY(())
   struct function *f;
 
   /* Function specific options that are used by this function.  */
-  struct function_specific_data * GTY((maybe_undef)) function_specific;
+  tree function_specific_target;	/* target options */
+  tree function_specific_optimization;	/* optimization options */
 
   /* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is
      DECL_FUNCTION_CODE.  Otherwise unused.
@@ -3518,6 +3525,33 @@ struct tree_value_handle GTY(())
      bitmaps of value handles.  */
   unsigned int id;
 };
+
+/* Optimization options used by a function.  */
+
+struct tree_optimization_option GTY(())
+{
+  struct tree_common common;
+
+  /* The optimization options used by the user.  */
+  struct cl_optimization opts;
+};
+
+#define TREE_OPTIMIZATION(NODE) \
+  (&OPTIMIZATION_NODE_CHECK (NODE)->optimization.opts)
+
+/* Target options used by a function.  */
+
+struct tree_target_option GTY(())
+{
+  struct tree_common common;
+
+  /* The optimization options used by the user.  */
+  struct cl_target_option opts;
+};
+
+#define TREE_TARGET_OPTION(NODE) \
+  (&TARGET_OPTION_NODE_CHECK (NODE)->target_option.opts)
+
 

 /* Define the overall contents of a tree node.
    It may be any of the structures declared above
@@ -3563,6 +3597,8 @@ union tree_node GTY ((ptr_alias (union l
   struct tree_memory_tag GTY ((tag ("TS_MEMORY_TAG"))) mtag;
   struct tree_omp_clause GTY ((tag ("TS_OMP_CLAUSE"))) omp_clause;
   struct tree_memory_partition_tag GTY ((tag ("TS_MEMORY_PARTITION_TAG"))) mpt;
+  struct tree_optimization_option GTY ((tag ("TS_OPTIMIZATION"))) optimization;
+  struct tree_target_option GTY ((tag ("TS_TARGET_OPTION"))) target_option;
 };
 

 /* Standard named or nameless data types of the C compiler.  */
@@ -3710,6 +3746,12 @@ enum tree_index
   TI_SAT_UDA_TYPE,
   TI_SAT_UTA_TYPE,
 
+  TI_OPTIMIZATION_DEFAULT,
+  TI_OPTIMIZATION_CURRENT,
+  TI_OPTIMIZATION_COLD,
+  TI_TARGET_OPTION_DEFAULT,
+  TI_CURRENT_OPTION_PRAGMA,
+
   TI_MAX
 };
 
@@ -3877,6 +3919,17 @@ 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.  */
+#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]
+
+/* Default target options.  */
+#define target_option_default_node	global_trees[TI_TARGET_OPTION_DEFAULT]
+
+/* Default option() pragma.  */
+#define current_option_pragma		global_trees[TI_CURRENT_OPTION_PRAGMA]
+
 /* An enumeration of the standard C integer types.  These must be
    ordered so that shorter types appear before longer ones, and so
    that signed types appear before unsigned ones, for the correct
Index: gcc/target.h
===================================================================
--- gcc/target.h	(revision 136724)
+++ gcc/target.h	(working copy)
@@ -955,6 +955,18 @@ 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
+     structure.  */
+  void (*target_option_save) (struct cl_target_option *);
+
+  /* Function to restore any extra target state from the target options
+     structure.  */
+  void (*target_option_restore) (struct cl_target_option *);
+
+  /* Function to print any extra target state from the target options
+     structure.  */
+  void (*target_option_print) (FILE *, int, struct cl_target_option *);
+
   /* Function to determine if one function can inline another function.  */
   bool (*can_inline_p) (tree, tree);
 
Index: gcc/testsuite/gcc.target/i386/cold-1.c
===================================================================
--- gcc/testsuite/gcc.target/i386/cold-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/i386/cold-1.c	(revision 0)
@@ -0,0 +1,13 @@
+/* Test whether using attribute((cold)) really turns on -Os.  Do this test
+   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" } } */
+
+void cold (char *) __attribute__((__cold__));
+
+void cold (char *a)
+{
+  __builtin_strcpy (a, "testing 1.2.3 testing 1.2.3");
+}
Index: gcc/opts.c
===================================================================
--- gcc/opts.c	(revision 136724)
+++ gcc/opts.c	(working copy)
@@ -772,6 +772,66 @@ handle_options (unsigned int argc, const
     }
 }
 
+/* Unset all of the options that are normally off for -Os.  This is to allow
+   targets to have a function specific option that optimizes for space for a
+   particular function.  It is assumed that the current options have been saved
+   by a call to cl_optimization_save and will be restored by a call to
+   cl_optimization_restore at the end of the function.  */
+
+void
+optimize_for_space (void)
+{
+  /* Loop header copying usually increases size of the code.  This used not to
+     be true, since quite often it is possible to verify that the condition is
+     satisfied in the first iteration and therefore to eliminate it.  Jump
+     threading handles these cases now.  */
+  flag_tree_ch = 0;
+
+  /* Conditional DCE generates bigger code.  */
+  flag_tree_builtin_call_dce = 0;
+
+  /* PRE tends to generate bigger code.  */
+  flag_tree_pre = 0;
+
+  /* These options are set with -O3, so reset for -Os */
+  flag_predictive_commoning = 0;
+  flag_inline_functions = 0;
+  flag_unswitch_loops = 0;
+  flag_gcse_after_reload = 0;
+  flag_tree_vectorize = 0;
+
+  /* Don't reorder blocks when optimizing for size because extra jump insns may
+     be created; also barrier may create extra padding.
+
+     More correctly we should have a block reordering mode that tried to
+     minimize the combined size of all the jumps.  This would more or less
+     automatically remove extra jumps, but would also try to use more short
+     jumps instead of long jumps.  */
+  flag_reorder_blocks = 0;
+  flag_reorder_blocks_and_partition = 0;
+
+  /* Inlining of functions reducing size is a good idea regardless of them
+     being declared inline.  */
+  flag_inline_functions = 1;
+
+  /* Don't align code.  */
+  align_loops = 1;
+  align_jumps = 1;
+  align_labels = 1;
+  align_functions = 1;
+
+  /* Unroll/prefetch switches that may be set on the command line, and tend to
+     generate bigger code.  */
+  flag_unroll_loops = 0;
+  flag_unroll_all_loops = 0;
+  flag_prefetch_loop_arrays = 0;
+
+  /* Basic optimization options.  */
+  optimize_size = 1;
+  if (optimize > 2)
+    optimize = 2;
+}
+
 /* Parse command line options and set default flag values.  Do minimal
    options processing.  */
 void
@@ -848,17 +908,9 @@ decode_options (unsigned int argc, const
       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_size)
-	{
-	  /* Loop header copying usually increases size of the code.  This used
-	     not to be true, since quite often it is possible to verify that
-	     the condition is satisfied in the first iteration and therefore
-	     to eliminate it.  Jump threading handles these cases now.  */
-	  flag_tree_ch = 1;
-	}
     }
 
   if (optimize >= 2)
@@ -886,14 +938,8 @@ decode_options (unsigned int argc, const
       flag_reorder_functions = 1;
       flag_tree_store_ccp = 1;
       flag_tree_vrp = 1;
-
-      if (!optimize_size)
-	{
-          /* Conditional DCE generates bigger code.  */
-          flag_tree_builtin_call_dce = 1;
-          /* PRE tends to generate bigger code.  */
-          flag_tree_pre = 1;
-	}
+      flag_tree_builtin_call_dce = 1;
+      flag_tree_pre = 1;
 
       /* Allow more virtual operators to increase alias precision.  */
       set_param_value ("max-aliased-vops", 500);
@@ -912,29 +958,17 @@ decode_options (unsigned int argc, const
       set_param_value ("avg-aliased-vops", 3);
     }
 
-  if (optimize < 2 || optimize_size)
+  if (optimize < 2)
     {
       align_loops = 1;
       align_jumps = 1;
       align_labels = 1;
       align_functions = 1;
-
-      /* Don't reorder blocks when optimizing for size because extra
-	 jump insns may be created; also barrier may create extra padding.
-
-	 More correctly we should have a block reordering mode that tried
-	 to minimize the combined size of all the jumps.  This would more
-	 or less automatically remove extra jumps, but would also try to
-	 use more short jumps instead of long jumps.  */
-      flag_reorder_blocks = 0;
-      flag_reorder_blocks_and_partition = 0;
     }
 
   if (optimize_size)
     {
-      /* Inlining of functions reducing size is a good idea regardless
-	 of them being declared inline.  */
-      flag_inline_functions = 1;
+      optimize_for_space ();
 
       /* We want to crossjump as much as possible.  */
       set_param_value ("min-crossjump-insns", 1);
@@ -1041,6 +1075,14 @@ decode_options (unsigned int argc, const
       flag_reorder_blocks_and_partition = 0;
       flag_reorder_blocks = 1;
     }
+
+  /* Save the current optimization options if this is the first call.  */
+  if (!optimization_default_node)
+    {
+      optimization_default_node = make_node (OPTIMIZATION_NODE);
+      optimization_current_node = optimization_default_node;
+      cl_optimization_save (TREE_OPTIMIZATION (optimization_default_node));
+    }
 }
 
 #define LEFT_COLUMN	27
Index: gcc/optc-gen.awk
===================================================================
--- gcc/optc-gen.awk	(revision 136724)
+++ gcc/optc-gen.awk	(working copy)
@@ -28,6 +28,7 @@
 BEGIN {
 	n_opts = 0
 	n_langs = 0
+	n_target_save = 0
         quote = "\042"
 	comma = ","
 	FS=SUBSEP
@@ -41,6 +42,11 @@ BEGIN {
 			langs[n_langs] = $2
 			n_langs++;
 		}
+		else if ($1 == "TargetSave") {
+			# Make sure the declarations are put in source order
+			target_save_decl[n_target_save] = $2
+			n_target_save++
+		}
 		else {
 			name = opt_args("Mask", $1)
 			if (name == "") {
@@ -64,6 +70,9 @@ print "#include " quote "intl.h" quote
 print ""
 print "#ifdef GCC_DRIVER"
 print "int target_flags;"
+print "#else"
+print "#include " quote "flags.h" quote
+print "#include " quote "target.h" quote
 print "#endif /* GCC_DRIVER */"
 print ""
 
@@ -215,52 +224,299 @@ for (i = 0; i < n_opts; i++) {
 
 print "};"
 
-if (have_save) {
-	print "";
-	print "#ifndef GCC_DRIVER"
-	print "/* Save selected option variables into a structure.  */"
-	print "void";
-	print "cl_options_save (struct cl_option_save *ptr)";
-	print "{";
+print "";
+print "#if !defined(GCC_DRIVER) && !defined(IN_LIBGCC2)"
+print "";
+print "/* Save optimization variables into a structure.  */"
+print "void";
+print "cl_optimization_save (struct cl_optimization *ptr)";
+print "{";
+
+n_opt_char = 2;
+n_opt_short = 0;
+n_opt_int = 0;
+n_opt_other = 0;
+var_opt_char[0] = "optimize";
+var_opt_char[1] = "optimize_size";
+var_opt_range["optimize"] = "0, 255";
+var_opt_range["optimize_size"] = "0, 255";
 
-	for (i = 0; i < n_opts; i++) {
-		if (flag_set_p("Save", flags[i])) {
-			name = var_name(flags[i]);
-			if (name == "")
-				name = "target_flags";
+# Sort by size to mimic how the structure is laid out to be friendlier to the
+# cache.
 
-			if (name in var_seen_save)
-				continue;
+for (i = 0; i < n_opts; i++) {
+	if (flag_set_p("Optimization", flags[i])) {
+		name = var_name(flags[i])
+		if(name == "")
+			continue;
+
+		if(name in var_opt_seen)
+			continue;
 
-			var_seen_save[name] = 1;
-			print "  ptr->" name " = " name ";";
+		var_opt_seen[name]++;
+		otype = var_type_struct(flags[i]);
+		if (otype ~ "^((un)?signed +)?int *$")
+			var_opt_int[n_opt_int++] = name;
+
+		else if (otype ~ "^((un)?signed +)?short *$")
+			var_opt_int[n_opt_int++] = name;
+
+		else if (otype ~ "^((un)?signed +)?char *$") {
+			var_opt_char[n_opt_char++] = name;
+			if (otype ~ "^unsigned +char *$")
+				var_opt_range[name] = "0, 255"
+			else if (otype ~ "^signed +char *$")
+				var_opt_range[name] = "-128, 127"
 		}
+		else
+			var_opt_other[n_opt_other++] = name;
 	}
+}
+
+for (i = 0; i < n_opt_char; i++) {
+	name = var_opt_char[i];
+	if (var_opt_range[name] != "")
+		print "  gcc_assert (IN_RANGE (" name ", " var_opt_range[name] "));";
+}
+
+for (i = 0; i < n_opt_other; i++) {
+	print "  ptr->" var_opt_other[i] " = " var_opt_other[i] ";";
+}
 
-	print "}";
+for (i = 0; i < n_opt_int; i++) {
+	print "  ptr->" var_opt_int[i] " = " var_opt_int[i] ";";
+}
+
+for (i = 0; i < n_opt_short; i++) {
+	print "  ptr->" var_opt_short[i] " = " var_opt_short[i] ";";
+}
+
+for (i = 0; i < n_opt_char; i++) {
+	print "  ptr->" var_opt_char[i] " = " var_opt_char[i] ";";
+}
 
+print "}";
+
+print "";
+print "/* Restore optimization options from a structure.  */";
+print "void";
+print "cl_optimization_restore (struct cl_optimization *ptr)";
+print "{";
+
+for (i = 0; i < n_opt_other; i++) {
+	print "  " var_opt_other[i] " = ptr->" var_opt_other[i] ";";
+}
+
+for (i = 0; i < n_opt_int; i++) {
+	print "  " var_opt_int[i] " = ptr->" var_opt_int[i] ";";
+}
+
+for (i = 0; i < n_opt_short; i++) {
+	print "  " var_opt_short[i] " = ptr->" var_opt_short[i] ";";
+}
+
+for (i = 0; i < n_opt_char; i++) {
+	print "  " var_opt_char[i] " = ptr->" var_opt_char[i] ";";
+}
+
+print "}";
+
+print "";
+print "/* Print optimization options from a structure.  */";
+print "void";
+print "cl_optimization_print (FILE *file,";
+print "                       int indent_to,";
+print "                       struct cl_optimization *ptr)";
+print "{";
+
+for (i = 0; i < n_opt_other; i++) {
+	print "  if (ptr->" var_opt_other[i] ")";
+	print "    fprintf (file, \"%*s%s (0x%lx)\\n\",";
+	print "             indent_to, \"\",";
+	print "             \"" var_opt_other[i] "\",";
+	print "             (unsigned long)ptr->" var_opt_other[i] ");";
+	print "";
+}
+
+for (i = 0; i < n_opt_int; i++) {
+	print "  if (ptr->" var_opt_int[i] ")";
+	print "    fprintf (file, \"%*s%s (0x%x)\\n\",";
+	print "             indent_to, \"\",";
+	print "             \"" var_opt_int[i] "\",";
+	print "             ptr->" var_opt_int[i] ");";
+	print "";
+}
+
+for (i = 0; i < n_opt_short; i++) {
+	print "  if (ptr->" var_opt_short[i] ")";
+	print "    fprintf (file, \"%*s%s (0x%x)\\n\",";
+	print "             indent_to, \"\",";
+	print "             \"" var_opt_short[i] "\",";
+	print "             ptr->" var_opt_short[i] ");";
 	print "";
-	print "/* Restore selected current options from a structure.  */";
-	print "void";
-	print "cl_options_restore (struct cl_option_save *ptr)";
-	print "{";
+}
 
+for (i = 0; i < n_opt_char; i++) {
+	print "  if (ptr->" var_opt_char[i] ")";
+	print "    fprintf (file, \"%*s%s (0x%x)\\n\",";
+	print "             indent_to, \"\",";
+	print "             \"" var_opt_char[i] "\",";
+	print "             ptr->" var_opt_char[i] ");";
+	print "";
+}
+
+print "}";
+
+print "";
+print "/* Save selected option variables into a structure.  */"
+print "void";
+print "cl_target_option_save (struct cl_target_option *ptr)";
+print "{";
+
+n_target_char = 0;
+n_target_short = 0;
+n_target_int = 0;
+n_target_other = 0;
+
+if (have_save) {
 	for (i = 0; i < n_opts; i++) {
 		if (flag_set_p("Save", flags[i])) {
-			name = var_name(flags[i]);
-			if (name == "")
+			name = var_name(flags[i])
+			if(name == "")
 				name = "target_flags";
 
-			if (name in var_seen_restore)
+			if(name in var_save_seen)
 				continue;
 
-			var_seen_restore[name] = 1;
-			print "  " name " = ptr->" name ";";
+			var_save_seen[name]++;
+			otype = var_type_struct(flags[i])
+			if (otype ~ "^((un)?signed +)?int *$")
+				var_target_int[n_target_int++] = name;
+
+			else if (otype ~ "^((un)?signed +)?short *$")
+				var_target_short[n_target_short++] = name;
+
+			else if (otype ~ "^((un)?signed +)?char *$") {
+				var_target_char[n_target_char++] = name;
+				if (otype ~ "^unsigned +char *$")
+					var_target_range[name] = "0, 255"
+				else if (otype ~ "^signed +char *$")
+					var_target_range[name] = "-128, 127"
+			}
+			else
+				var_target_other[n_target_other++] = name;
 		}
 	}
+} else {
+	var_target_int[n_target_int++] = "target_flags";
+}
+
+for (i = 0; i < n_target_char; i++) {
+	name = var_target_char[i];
+	if (var_target_range[name] != "")
+		print "  gcc_assert (IN_RANGE (" name ", " var_target_range[name] "));";
+}
+
+print "";
+print "  if (targetm.target_option_save)";
+print "    targetm.target_option_save (ptr);";
+print "";
+
+for (i = 0; i < n_target_other; i++) {
+	print "  ptr->" var_target_other[i] " = " var_target_other[i] ";";
+}
+
+for (i = 0; i < n_target_int; i++) {
+	print "  ptr->" var_target_int[i] " = " var_target_int[i] ";";
+}
+
+for (i = 0; i < n_target_short; i++) {
+	print "  ptr->" var_target_short[i] " = " var_target_short[i] ";";
+}
+
+for (i = 0; i < n_target_char; i++) {
+	print "  ptr->" var_target_char[i] " = " var_target_char[i] ";";
+}
+
+print "}";
+
+print "";
+print "/* Restore selected current options from a structure.  */";
+print "void";
+print "cl_target_option_restore (struct cl_target_option *ptr)";
+print "{";
 
-	print "}";
-	print "#endif";
+for (i = 0; i < n_target_other; i++) {
+	print "  " var_target_other[i] " = ptr->" var_target_other[i] ";";
 }
 
+for (i = 0; i < n_target_int; i++) {
+	print "  " var_target_int[i] " = ptr->" var_target_int[i] ";";
+}
+
+for (i = 0; i < n_target_short; i++) {
+	print "  " var_target_short[i] " = ptr->" var_target_short[i] ";";
+}
+
+for (i = 0; i < n_target_char; i++) {
+	print "  " var_target_char[i] " = ptr->" var_target_char[i] ";";
+}
+
+print "";
+print "  if (targetm.target_option_restore)";
+print "    targetm.target_option_restore (ptr);";
+
+print "}";
+
+print "";
+print "/* Print optimization options from a structure.  */";
+print "void";
+print "cl_target_option_print (FILE *file,";
+print "                        int indent,";
+print "                        struct cl_target_option *ptr)";
+print "{";
+
+for (i = 0; i < n_target_other; i++) {
+	print "  if (ptr->" var_target_other[i] ")";
+	print "    fprintf (file, \"%*s%s (0x%lx)\\n\",";
+	print "             indent, \"\",";
+	print "             \"" var_target_other[i] "\",";
+	print "             (unsigned long)ptr->" var_target_other[i] ");";
+	print "";
+}
+
+for (i = 0; i < n_target_int; i++) {
+	print "  if (ptr->" var_target_int[i] ")";
+	print "    fprintf (file, \"%*s%s (0x%x)\\n\",";
+	print "             indent, \"\",";
+	print "             \"" var_target_int[i] "\",";
+	print "             ptr->" var_target_int[i] ");";
+	print "";
+}
+
+for (i = 0; i < n_target_short; i++) {
+	print "  if (ptr->" var_target_short[i] ")";
+	print "    fprintf (file, \"%*s%s (0x%x)\\n\",";
+	print "             indent, \"\",";
+	print "             \"" var_target_short[i] "\",";
+	print "             ptr->" var_target_short[i] ");";
+	print "";
+}
+
+for (i = 0; i < n_target_char; i++) {
+	print "  if (ptr->" var_target_char[i] ")";
+	print "    fprintf (file, \"%*s%s (0x%x)\\n\",";
+	print "             indent, \"\",";
+	print "             \"" var_target_char[i] "\",";
+	print "             ptr->" var_target_char[i] ");";
+	print "";
+}
+
+print "";
+print "  if (targetm.target_option_print)";
+print "    targetm.target_option_print (file, indent, ptr);";
+
+print "}";
+print "#endif";
+
 }
Index: gcc/treestruct.def
===================================================================
--- gcc/treestruct.def	(revision 136591)
+++ gcc/treestruct.def	(working copy)
@@ -64,3 +64,6 @@ DEFTREESTRUCT(TS_CONSTRUCTOR, "construct
 DEFTREESTRUCT(TS_MEMORY_TAG, "memory tag")
 DEFTREESTRUCT(TS_OMP_CLAUSE, "omp clause")
 DEFTREESTRUCT(TS_MEMORY_PARTITION_TAG, "memory partition tag")
+DEFTREESTRUCT(TS_OPTIMIZATION, "optimization options")
+DEFTREESTRUCT(TS_TARGET_OPTION, "target options")
+
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c	(revision 136591)
+++ gcc/c-decl.c	(working copy)
@@ -1835,10 +1835,16 @@ merge_decls (tree newdecl, tree olddecl,
 	      = C_DECL_BUILTIN_PROTOTYPE (olddecl);
 	}
 
-      /* Preserve target specific options */
-      if (DECL_FUNCTION_SPECIFIC (olddecl)
-	  && !DECL_FUNCTION_SPECIFIC (newdecl))
-	DECL_FUNCTION_SPECIFIC (newdecl) = DECL_FUNCTION_SPECIFIC (olddecl);
+      /* Preserve function specific target and optimization options */
+      if (DECL_FUNCTION_SPECIFIC_TARGET (olddecl)
+	  && !DECL_FUNCTION_SPECIFIC_TARGET (newdecl))
+	DECL_FUNCTION_SPECIFIC_TARGET (newdecl)
+	  = DECL_FUNCTION_SPECIFIC_TARGET (olddecl);
+
+      if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl)
+	  && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl))
+	DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl)
+	  = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl);
 
       /* Also preserve various other info from the definition.  */
       if (!new_is_definition)
Index: gcc/function.c
===================================================================
--- gcc/function.c	(revision 136724)
+++ gcc/function.c	(working copy)
@@ -3753,13 +3753,30 @@ debug_find_var_in_block_tree (tree var, 
 
 static bool in_dummy_function;
 
-/* Invoke the target hook when setting cfun.  */
+/* Invoke the target hook when setting cfun.  If the function has the cold
+   attribute set, make sure we switch to optimizing for space.  */
 
 static void
 invoke_set_current_function_hook (tree fndecl)
 {
   if (!in_dummy_function)
-    targetm.set_current_function (fndecl);
+    {
+      tree opts = ((fndecl)
+		   ? DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl)
+		   : optimization_default_node);
+
+      if (!opts)
+	opts = optimization_default_node;
+
+      /* Change optimization options if needed.  */
+      if (optimization_current_node != opts)
+	{
+	  optimization_current_node = opts;
+	  cl_optimization_restore (TREE_OPTIMIZATION (opts));
+	}
+
+      targetm.set_current_function (fndecl);
+    }
 }
 
 /* cfun should never be set directly; use this function.  */
Index: gcc/coretypes.h
===================================================================
--- gcc/coretypes.h	(revision 136591)
+++ gcc/coretypes.h	(working copy)
@@ -50,8 +50,8 @@ typedef union tree_node *tree;
 typedef const union tree_node *const_tree;
 union section;
 typedef union section section;
-struct cl_option_save;
-struct function_specific_data;
+struct cl_target_option;
+struct cl_optimization;
 
 /* The major intermediate representations of GCC.  */
 enum ir_type {
Index: gcc/c-pragma.c
===================================================================
--- gcc/c-pragma.c	(revision 136724)
+++ gcc/c-pragma.c	(working copy)
@@ -865,6 +865,97 @@ 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.  */
+static GTY(()) VEC(tree,gc) *option_stack;
+
+static void
+handle_pragma_option(cpp_reader *ARG_UNUSED(dummy))
+{
+  enum cpp_ttype token;
+  const char *name;
+  tree x;
+
+  if (cfun)
+    {
+      error ("#pragma GCC option is not allowed inside functions");
+      return;
+    }
+
+  if (!targetm.valid_option_attribute_p)
+    {
+      error ("#pragma GCC option is not supported for this system");
+      return;
+    }
+
+  token = pragma_lex (&x);
+  if (token == CPP_NAME)
+    {
+      name = IDENTIFIER_POINTER (x);
+      if (strcmp (name, "reset") == 0)
+	current_option_pragma = NULL_TREE;
+
+      else if (strcmp (name, "push") == 0)
+	VEC_safe_push (tree, gc, option_stack,
+		       copy_list (current_option_pragma));
+
+      else if (strcmp (name, "pop") == 0)
+	{
+	  int len = VEC_length (tree, option_stack);
+	  if (len == 0)
+	    {
+	      GCC_BAD ("%<#pragma GCC option pop%> without a %<#pragma GCC option push%>");
+	      return;
+	    }
+	  else
+	    {
+	      VEC_truncate (tree, option_stack, len-1);
+	      current_option_pragma = ((len > 1)
+				       ? VEC_last (tree, option_stack)
+				       : NULL_TREE);
+	    }
+	}
+
+      else
+	{
+	  GCC_BAD ("%<#pragma GCC option%> is not a string or push/pop/reset");
+	  return;
+	}
+
+      token = pragma_lex (&x);
+      if (token != CPP_EOF)
+	{
+	  GCC_BAD ("%<#pragma GCC option [push|pop|reset]%> is badly formed");
+	  return;
+	}
+    }
+
+  else if (token != CPP_STRING)
+    {
+      GCC_BAD ("%<#pragma GCC option%> is not a string or push/pop/reset");
+      return;
+    }
+
+  /* Strings are user options.  */
+  else
+    {
+      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);
+	}
+      while ((token = pragma_lex (&x)) == CPP_STRING);
+
+      if (token != CPP_EOF)
+	{
+	  error ("#pragma GCC option string... is badly formed");
+	  return;
+	}
+    }
+}
+
 /* A vector of registered pragma callbacks.  */
 
 DEF_VEC_O (pragma_handler);
@@ -1027,6 +1118,7 @@ init_pragma (void)
 #endif
 
   c_register_pragma ("GCC", "diagnostic", handle_pragma_diagnostic);
+  c_register_pragma ("GCC", "option", handle_pragma_option);
 
   c_register_pragma_with_expansion (0, "redefine_extname", handle_pragma_redefine_extname);
   c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix);
Index: gcc/tree.def
===================================================================
--- gcc/tree.def	(revision 136724)
+++ gcc/tree.def	(working copy)
@@ -1200,6 +1200,13 @@ DEFTREECODE (VEC_INTERLEAVE_LOW_EXPR, "v
    all conditional branches leading to execution paths executing the
    PREDICT_EXPR will get predicted by the specified predictor.  */
 DEFTREECODE (PREDICT_EXPR, "predict_expr", tcc_unary, 1)
+
+/* OPTIMIZATION_NODE.  Node to store the optimization options.  */
+DEFTREECODE (OPTIMIZATION_NODE, "optimization_node", tcc_exceptional, 0)
+
+/* TARGET_OPTION_NODE.  Node to store the target specific options.  */
+DEFTREECODE (TARGET_OPTION_NODE, "target_option_node", tcc_exceptional, 0)
+
 /*
 Local variables:
 mode:c
Index: gcc/opth-gen.awk
===================================================================
--- gcc/opth-gen.awk	(revision 136724)
+++ gcc/opth-gen.awk	(working copy)
@@ -26,6 +26,7 @@
 BEGIN {
 	n_opts = 0
 	n_langs = 0
+	n_target_save = 0
 	n_extra_masks = 0
 	quote = "\042"
 	comma = ","
@@ -38,6 +39,11 @@ BEGIN {
 			langs[n_langs] = $2
 			n_langs++;
 		}
+		else if ($1 == "TargetSave") {
+			# Make sure the declarations are put in source order
+			target_save_decl[n_target_save] = $2
+			n_target_save++
+		}
 		else {
 			name = opt_args("Mask", $1)
 			if (name == "") {
@@ -82,13 +88,95 @@ for (i = 0; i < n_opts; i++) {
 }
 print ""
 
-if (have_save) {
-	# Define this even if we are in the gcc driver in case the tm.h
-	# file includes this structure in another one.
-	print "/* Structure to save/restore selected options.  */";
-	print "struct cl_option_save GTY(())";
-	print "{";
+# All of the optimization switches gathered together so they can be saved and restored.
+# This will allow attribute((cold)) to turn on space optimization.
+
+# Change the type of normal switches from int to unsigned char to save space.
+# Also, order the structure so that pointer fields occur first, then int
+# fields, and then char fields to provide the best packing.
+
+print "#if !defined(GCC_DRIVER) && !defined(IN_LIBGCC2)"
+print ""
+print "/* Structure to save/restore optimization and target specific options.  */";
+print "struct cl_optimization GTY(())";
+print "{";
+
+n_opt_char = 2;
+n_opt_short = 0;
+n_opt_int = 0;
+n_opt_other = 0;
+var_opt_char[0] = "unsigned char optimize";
+var_opt_char[1] = "unsigned char optimize_size";
+
+for (i = 0; i < n_opts; i++) {
+	if (flag_set_p("Optimization", flags[i])) {
+		name = var_name(flags[i])
+		if(name == "")
+			continue;
+
+		if(name in var_opt_seen)
+			continue;
+
+		var_opt_seen[name]++;
+		otype = var_type_struct(flags[i]);
+		if (otype ~ "^((un)?signed +)?int *$")
+			var_opt_int[n_opt_int++] = otype name;
+
+		else if (otype ~ "^((un)?signed +)?short *$")
+			var_opt_int[n_opt_int++] = otype name;
+
+		else if (otype ~ "^((un)?signed +)?char *$")
+			var_opt_char[n_opt_char++] = otype name;
+
+		else
+			var_opt_other[n_opt_other++] = otype name;
+	}
+}
+
+for (i = 0; i < n_opt_other; i++) {
+	print "  " var_opt_other[i] ";";
+}
+
+for (i = 0; i < n_opt_int; i++) {
+	print "  " var_opt_int[i] ";";
+}
+
+for (i = 0; i < n_opt_short; i++) {
+	print "  " var_opt_short[i] ";";
+}
+
+for (i = 0; i < n_opt_char; i++) {
+	print "  " var_opt_char[i] ";";
+}
+
+print "};";
+print "";
+
+# Target and optimization save/restore/print functions.
+print "/* Structure to save/restore selected target specific options.  */";
+print "struct cl_target_option GTY(())";
+print "{";
+
+n_target_char = 0;
+n_target_short = 0;
+n_target_int = 0;
+n_target_other = 0;
+
+for (i = 0; i < n_target_save; i++) {
+	if (target_save_decl[i] ~ "^((un)?signed +)?int +[_a-zA-Z0-9]+$")
+		var_target_int[n_target_int++] = target_save_decl[i];
+
+	else if (target_save_decl[i] ~ "^((un)?signed +)?short +[_a-zA-Z0-9]+$")
+		var_target_short[n_target_short++] = target_save_decl[i];
+
+	else if (target_save_decl[i] ~ "^((un)?signed +)?char +[_a-zA-Z0-9]+$")
+		var_target_char[n_target_char++] = target_save_decl[i];
 
+	else
+		var_target_other[n_target_other++] = target_save_decl[i];
+}
+
+if (have_save) {
 	for (i = 0; i < n_opts; i++) {
 		if (flag_set_p("Save", flags[i])) {
 			name = var_name(flags[i])
@@ -99,22 +187,63 @@ if (have_save) {
 				continue;
 
 			var_save_seen[name]++;
-			print "  " var_type(flags[i]) name ";";
+			otype = var_type_struct(flags[i])
+			if (otype ~ "^((un)?signed +)?int *$")
+				var_target_int[n_target_int++] = otype name;
+
+			else if (otype ~ "^((un)?signed +)?short *$")
+				var_target_short[n_target_short++] = otype name;
+
+			else if (otype ~ "^((un)?signed +)?char *$")
+				var_target_char[n_target_char++] = otype name;
+
+			else
+				var_target_other[n_target_other++] = otype name;
 		}
 	}
+} else {
+	var_target_int[n_target_int++] = "int target_flags";
+}
 
-	print "};";
-	print "";
-	print "#ifndef GCC_DRIVER"
-	print "/* Save selected option variables into a structure.  */"
-	print "extern void cl_options_save (struct cl_option_save *);";
-	print "";
-	print "/* Restore selected current options from a structure.  */";
-	print "extern void cl_options_restore (struct cl_option_save *);";
-	print "#endif";
-	print "";
+for (i = 0; i < n_target_other; i++) {
+	print "  " var_target_other[i] ";";
 }
 
+for (i = 0; i < n_target_int; i++) {
+	print "  " var_target_int[i] ";";
+}
+
+for (i = 0; i < n_target_short; i++) {
+	print "  " var_target_short[i] ";";
+}
+
+for (i = 0; i < n_target_char; i++) {
+	print "  " var_target_char[i] ";";
+}
+
+print "};";
+print "";
+print "";
+print "/* Save optimization variables into a structure.  */"
+print "extern void cl_optimization_save (struct cl_optimization *);";
+print "";
+print "/* Restore optimization variables from a structure.  */";
+print "extern void cl_optimization_restore (struct cl_optimization *);";
+print "";
+print "/* Print optimization variables from a structure.  */";
+print "extern void cl_optimization_print (FILE *, int, struct cl_optimization *);";
+print "";
+print "/* Save selected option variables into a structure.  */"
+print "extern void cl_target_option_save (struct cl_target_option *);";
+print "";
+print "/* Restore selected option variables from a structure.  */"
+print "extern void cl_target_option_restore (struct cl_target_option *);";
+print "";
+print "/* Print target option variables from a structure.  */";
+print "extern void cl_target_option_print (FILE *, int, struct cl_target_option *);";
+print "#endif";
+print "";
+
 for (i = 0; i < n_opts; i++) {
 	name = opt_args("Mask", flags[i])
 	vname = var_name(flags[i])
Index: gcc/print-tree.c
===================================================================
--- gcc/print-tree.c	(revision 136591)
+++ gcc/print-tree.c	(working copy)
@@ -369,8 +369,12 @@ print_node (FILE *file, const char *pref
       if (TREE_CODE (node) == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (node))
 	fputs (" suppress-debug", file);
 
-      if (TREE_CODE (node) == FUNCTION_DECL && DECL_FUNCTION_SPECIFIC (node))
-	fputs (" function-specific", file);
+      if (TREE_CODE (node) == FUNCTION_DECL
+	  && DECL_FUNCTION_SPECIFIC_TARGET (node))
+	fputs (" function-specific-target", file);
+      if (TREE_CODE (node) == FUNCTION_DECL
+	  && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (node))
+	fputs (" function-specific-opt", file);
       if (TREE_CODE (node) == FUNCTION_DECL && DECL_INLINE (node))
 	fputs (DECL_DECLARED_INLINE_P (node) ? " inline" : " autoinline", file);
       if (TREE_CODE (node) == FUNCTION_DECL && DECL_BUILT_IN (node))
@@ -933,6 +937,14 @@ print_node (FILE *file, const char *pref
 	    }
 	  break;
 
+	case OPTIMIZATION_NODE:
+	  cl_optimization_print (file, indent + 4, TREE_OPTIMIZATION (node));
+	  break;
+
+	case TARGET_OPTION_NODE:
+	  cl_target_option_print (file, indent + 4, TREE_TARGET_OPTION (node));
+	  break;
+
 	default:
 	  if (EXCEPTIONAL_CLASS_P (node))
 	    lang_hooks.print_xnode (file, node, indent);
Index: gcc/target-def.h
===================================================================
--- gcc/target-def.h	(revision 136724)
+++ gcc/target-def.h	(working copy)
@@ -754,6 +754,18 @@
 #define TARGET_VALID_OPTION_ATTRIBUTE_P NULL
 #endif
 
+#ifndef TARGET_OPTION_SAVE
+#define TARGET_OPTION_SAVE NULL
+#endif
+
+#ifndef TARGET_OPTION_RESTORE
+#define TARGET_OPTION_RESTORE NULL
+#endif
+
+#ifndef TARGET_OPTION_PRINT
+#define TARGET_OPTION_PRINT NULL
+#endif
+
 #ifndef TARGET_CAN_INLINE_P
 #define TARGET_CAN_INLINE_P default_can_inline_p
 #endif
@@ -851,6 +863,9 @@
   TARGET_CXX,					\
   TARGET_EMUTLS,				\
   TARGET_VALID_OPTION_ATTRIBUTE_P,		\
+  TARGET_OPTION_SAVE,				\
+  TARGET_OPTION_RESTORE,			\
+  TARGET_OPTION_PRINT,				\
   TARGET_CAN_INLINE_P,				\
   TARGET_EXTRA_LIVE_ON_ENTRY,			\
   TARGET_UNWIND_TABLES_DEFAULT,			\
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c	(revision 136724)
+++ gcc/c-common.c	(working copy)
@@ -4837,8 +4837,34 @@ handle_cold_attribute (tree *node, tree 
 		   name, "hot");
 	  *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 optimizing, but not optimizating for space, turn on
+	     -Os optimizations just for this one function.  */
+	  if (optimize >= 2
+	      && !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;
+
+		  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);
+		  cl_optimization_restore (&current_options);
+		}
+
+	      DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
+		= optimization_cold_node;
+	    }
+	}
     }
   else
     {
Index: gcc/opt-functions.awk
===================================================================
--- gcc/opt-functions.awk	(revision 136591)
+++ gcc/opt-functions.awk	(working copy)
@@ -128,6 +128,23 @@ function var_type(flags)
 		return "const char *"
 }
 
+# Return the type of variable that should be associated with the given flags
+# for use within a structure.  Simple variables are changed to unsigned char
+# type instead of int to save space.
+function var_type_struct(flags)
+{
+	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 *"
+}
+
 # Given that an option has flags FLAGS, return an initializer for the
 # "var_cond" and "var_value" fields of its cl_options[] entry.
 function var_set(flags)
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 136724)
+++ gcc/Makefile.in	(working copy)
@@ -774,7 +774,7 @@ PARAMS_H = params.h params.def
 BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def
 TREE_H = tree.h tree.def $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \
           input.h statistics.h vec.h treestruct.def $(HASHTAB_H) \
-          double-int.h alias.h
+          double-int.h alias.h options.h
 BASIC_BLOCK_H = basic-block.h bitmap.h sbitmap.h varray.h $(PARTITION_H) \
           hard-reg-set.h $(PREDICT_H) vec.h $(FUNCTION_H) \
           cfghooks.h $(OBSTACK_H)
@@ -1927,7 +1927,8 @@ s-options-h: optionlist $(srcdir)/opt-fu
 	$(SHELL) $(srcdir)/../move-if-change tmp-options.h options.h
 	$(STAMP) $@
 
-options.o: options.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) opts.h intl.h
+options.o: options.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) $(FLAGS_H) \
+	$(TM_H) opts.h intl.h
 
 gcc-options.o: options.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) opts.h intl.h
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(OUTPUT_OPTION) -DGCC_DRIVER options.c
Index: gcc/config/i386/i386.h
===================================================================
--- gcc/config/i386/i386.h	(revision 136724)
+++ gcc/config/i386/i386.h	(working copy)
@@ -472,17 +472,6 @@ enum
 
 #define OVERRIDE_OPTIONS override_options (true)
 
-/* Validate the attribute(option(...)) list.  */
-#define TARGET_VALID_OPTION_ATTRIBUTE_P ix86_valid_option_attribute_p
-
-/* Determine whether one function can inline another */
-#define TARGET_CAN_INLINE_P ix86_can_inline_p
-
-/* 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.  */
-#define TARGET_SET_CURRENT_FUNCTION ix86_set_current_function
-
 /* Define this to change the optimizations performed by default.  */
 #define OPTIMIZATION_OPTIONS(LEVEL, SIZE) \
   optimization_options ((LEVEL), (SIZE))
@@ -2536,14 +2525,6 @@ struct machine_option_attr GTY(())
   unsigned char arch_specified;		/* whether -march was specified */
 };
 
-/* Combination of the function specific options generated by the .opt files
-   and by the x86 specific data.  */
-struct function_specific_data GTY(())
-{
-  struct cl_option_save options;		/* option data */
-  struct machine_option_attr machine;		/* machine data */
-};
-
 #define ix86_stack_locals (cfun->machine->stack_locals)
 #define ix86_save_varrargs_registers (cfun->machine->save_varrargs_registers)
 #define ix86_optimize_mode_switching (cfun->machine->optimize_mode_switching)
Index: gcc/config/i386/i386.opt
===================================================================
--- gcc/config/i386/i386.opt	(revision 136724)
+++ gcc/config/i386/i386.opt	(working copy)
@@ -18,6 +18,40 @@
 ; along with GCC; see the file COPYING3.  If not see
 ; <http://www.gnu.org/licenses/>.
 
+;; Definitions to add to the cl_target_option structure
+;; -march= processor
+TargetSave
+unsigned char arch
+
+;; -mtune= processor
+TargetSave
+unsigned char tune
+
+;; -mfpath=
+TargetSave
+unsigned char fpmath
+
+;; branch cost
+TargetSave
+unsigned char branch_cost
+
+;; which flags were passed by the user
+TargetSave
+int ix86_isa_flags_explicit
+
+;; which flags were passed by the user
+TargetSave
+int target_flags_explicit
+
+;; whether -mtune was not specified
+TargetSave
+unsigned char tune_defaulted
+
+;; whether -march was specified
+TargetSave
+unsigned char arch_specified
+
+;; x86 options
 m128bit-long-double
 Target RejectNegative Report Mask(128BIT_LONG_DOUBLE) Save
 sizeof(long double) is 16
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 136724)
+++ gcc/config/i386/i386.c	(working copy)
@@ -1783,15 +1783,16 @@ enum ix86_function_specific_strings
 static char *ix86_target_string (int, int, const char *, const char *,
 				 const char *, bool);
 static void ix86_debug_options (void) ATTRIBUTE_UNUSED;
-static void ix86_function_specific_save (struct function_specific_data *);
-static void ix86_function_specific_restore (struct function_specific_data *);
+static void ix86_function_specific_save (struct cl_target_option *);
+static void ix86_function_specific_restore (struct cl_target_option *);
+static void ix86_function_specific_print (FILE *, int,
+					  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);
 
-static GTY(()) struct function_specific_data *ix86_initial_options;
-
 

 /* The svr4 ABI for the i386 says that records and unions are returned
    in memory.  */
@@ -3181,54 +3182,84 @@ override_options (bool main_args_p)
   /* Save the initial options in case the user does function specific options */
   if (main_args_p)
     {
-      ix86_initial_options
-	= ggc_alloc (sizeof (struct function_specific_data));
-      ix86_function_specific_save (ix86_initial_options);
+      tree t = make_node (TARGET_OPTION_NODE);
+      target_option_default_node = t;
+      cl_target_option_save (TREE_TARGET_OPTION (t));
     }
 }
 

 /* Save the current options */
 
 static void
-ix86_function_specific_save (struct function_specific_data *ptr)
+ix86_function_specific_save (struct cl_target_option *ptr)
 {
-  memset (ptr, '\0', sizeof (struct function_specific_data));
-  cl_options_save (&ptr->options);
-  ptr->machine.arch = ix86_arch;
-  ptr->machine.tune = ix86_tune;
-  ptr->machine.fpmath = ix86_fpmath;
-  ptr->machine.branch_cost = ix86_branch_cost;
-  ptr->machine.tune_defaulted = ix86_tune_defaulted;
-  ptr->machine.arch_specified = ix86_arch_specified;
-  ptr->machine.ix86_isa_flags_explicit = ix86_isa_flags_explicit;
+  gcc_assert (IN_RANGE (ix86_arch, 0, 255));
+  gcc_assert (IN_RANGE (ix86_tune, 0, 255));
+  gcc_assert (IN_RANGE (ix86_fpmath, 0, 255));
+  gcc_assert (IN_RANGE (ix86_branch_cost, 0, 255));
+
+  ptr->arch = ix86_arch;
+  ptr->tune = ix86_tune;
+  ptr->fpmath = ix86_fpmath;
+  ptr->branch_cost = ix86_branch_cost;
+  ptr->tune_defaulted = ix86_tune_defaulted;
+  ptr->arch_specified = ix86_arch_specified;
+  ptr->ix86_isa_flags_explicit = ix86_isa_flags_explicit;
+  ptr->target_flags_explicit = target_flags_explicit;
 }
 
 /* Restore the current options */
 
 static void
-ix86_function_specific_restore (struct function_specific_data *ptr)
+ix86_function_specific_restore (struct cl_target_option *ptr)
 {
   unsigned int ix86_arch_mask, ix86_tune_mask;
   int i;
 
-  cl_options_restore (&ptr->options);
-  ix86_arch = ptr->machine.arch;
-  ix86_tune = ptr->machine.tune;
-  ix86_fpmath = ptr->machine.fpmath;
-  ix86_branch_cost = ptr->machine.branch_cost;
-  ix86_tune_defaulted = ptr->machine.tune_defaulted;
-  ix86_arch_specified = ptr->machine.arch_specified;
-  ix86_isa_flags_explicit = ptr->machine.ix86_isa_flags_explicit;
+  ix86_arch = ptr->arch;
+  ix86_tune = ptr->tune;
+  ix86_fpmath = ptr->fpmath;
+  ix86_branch_cost = ptr->branch_cost;
+  ix86_tune_defaulted = ptr->tune_defaulted;
+  ix86_arch_specified = ptr->arch_specified;
+  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 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);
 }
 
+/* Print the current options */
+
+static void
+ix86_function_specific_print (FILE *file, int indent,
+			      struct cl_target_option *ptr)
+{
+  fprintf (file, "%*sarch = %d (%s)\n",
+	   indent, "",
+	   ptr->arch,
+	   ((ptr->arch < TARGET_CPU_DEFAULT_max)
+	    ? cpu_names[ptr->arch]
+	    : "<unknown>"));
+
+  fprintf (file, "%*stune = %d (%s)\n",
+	   indent, "",
+	   ptr->tune,
+	   ((ptr->tune < TARGET_CPU_DEFAULT_max)
+	    ? cpu_names[ptr->tune]
+	    : "<unknown>"));
+
+  fprintf (file, "%*sfpmath = %d\n", indent, "", ptr->fpmath);
+  fprintf (file, "%*sbranch_cost = %d\n", indent, "", ptr->branch_cost);
+}
+
 

 /* Inner function to process the attribute((option(...))), take an argument and
    set the current options from the argument. If we have a list, recursively go
@@ -3448,9 +3479,11 @@ ix86_valid_option_attribute_p (tree fnde
   int orig_arch_specified = ix86_arch_specified;
   char *option_strings[IX86_FUNCTION_SPECIFIC_MAX] = { NULL, NULL, NULL };
   int i;
+  struct cl_target_option *def
+    = TREE_TARGET_OPTION (target_option_default_node);
 
   /* Make sure we start with clean options.  */
-  ix86_function_specific_restore (ix86_initial_options);
+  cl_target_option_restore (def);
 
   /* Process each of the options on the chain.  */
   ret = ix86_valid_option_attribute_inner_p (args, option_strings);
@@ -3458,14 +3491,12 @@ ix86_valid_option_attribute_p (tree fnde
   /* 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,
      and will be undone when we copy the save structure.  */
-  if (ix86_isa_flags != ix86_initial_options->options.ix86_isa_flags
-      || target_flags != ix86_initial_options->options.target_flags
+  if (ix86_isa_flags != def->ix86_isa_flags
+      || target_flags != def->target_flags
       || option_strings[IX86_FUNCTION_SPECIFIC_ARCH]
       || option_strings[IX86_FUNCTION_SPECIFIC_TUNE]
       || option_strings[IX86_FUNCTION_SPECIFIC_FPMATH])
     {
-      struct function_specific_data *p;
-
       /* If we are using the default tune= or arch=, undo the string assigned,
 	 and use the default.  */
       if (option_strings[IX86_FUNCTION_SPECIFIC_ARCH])
@@ -3487,13 +3518,17 @@ ix86_valid_option_attribute_p (tree fnde
       /* Do any overrides, such as arch=xxx, or tune=xxx support.  */
       override_options (false);
 
-      /* Save the current options.  */
-      p = ggc_alloc (sizeof (struct function_specific_data));
-      DECL_FUNCTION_SPECIFIC (fndecl) = p;
-      ix86_function_specific_save (p);
+      /* 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.  */
-      ix86_function_specific_restore (ix86_initial_options);
+      cl_target_option_restore (def);
 
       ix86_arch_string = orig_arch_string;
       ix86_tune_string = orig_tune_string;
@@ -3515,51 +3550,84 @@ static bool
 ix86_can_inline_p (tree caller, tree callee)
 {
   bool ret = false;
-  struct function_specific_data *caller_opts = DECL_FUNCTION_SPECIFIC (caller);
-  struct function_specific_data *callee_opts = DECL_FUNCTION_SPECIFIC (callee);
+  tree caller_tree = DECL_FUNCTION_SPECIFIC_TARGET (caller);
+  tree callee_tree = DECL_FUNCTION_SPECIFIC_TARGET (callee);
 
   /* If callee has no option attributes, then it is ok to inline.  */
-  if (!callee_opts)
+  if (!callee_tree)
     ret = true;
 
   /* If caller has no option attributes, but callee does then it is not ok to
      inline.  */
-  else if (!caller_opts)
+  else if (!caller_tree)
     ret = false;
 
-  /* Callee's isa options should a subset of the caller's, i.e. a SSE5 function
-     can inline a SSE2 function but a SSE2 function can't inline a SSE5
-     function.  */
-  else if ((caller_opts->options.ix86_isa_flags
-	    & callee_opts->options.ix86_isa_flags)
-	   != callee_opts->options.ix86_isa_flags)
-    ret = false;
+  else
+    {
+      struct cl_target_option *caller_opts = TREE_TARGET_OPTION (caller_tree);
+      struct cl_target_option *callee_opts = TREE_TARGET_OPTION (callee_tree);
 
-  /* See if we have the same non-isa options.  */
-  else if (caller_opts->options.target_flags
-	   != callee_opts->options.target_flags)
-    ret = false;
+      /* Callee's isa options should a subset of the caller's, i.e. a SSE5 function
+	 can inline a SSE2 function but a SSE2 function can't inline a SSE5
+	 function.  */
+      if ((caller_opts->ix86_isa_flags & callee_opts->ix86_isa_flags)
+	  != callee_opts->ix86_isa_flags)
+	ret = false;
 
-  else if (caller_opts->machine.arch != callee_opts->machine.arch)
-    ret = false;
+      /* See if we have the same non-isa options.  */
+      else if (caller_opts->target_flags != callee_opts->target_flags)
+	ret = false;
 
-  else if (caller_opts->machine.tune != callee_opts->machine.tune)
-    ret = false;
+      /* See if arch, tune, etc. are the same.  */
+      else if (caller_opts->arch != callee_opts->arch)
+	ret = false;
 
-  else if (caller_opts->machine.fpmath != callee_opts->machine.fpmath)
-    ret = false;
+      else if (caller_opts->tune != callee_opts->tune)
+	ret = false;
 
-  else if (caller_opts->machine.branch_cost
-	   != callee_opts->machine.branch_cost)
-    ret = false;
+      else if (caller_opts->fpmath != callee_opts->fpmath)
+	ret = false;
 
-  else
-    ret = true;
+      else if (caller_opts->branch_cost != callee_opts->branch_cost)
+	ret = false;
+
+      else
+	ret = true;
+    }
 
   return ret;
 }
 
 

+/* Insert any target specific attributes to a declaration.  */
+
+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.  */
@@ -3573,25 +3641,30 @@ ix86_set_current_function (tree fndecl)
      slow things down too much or call target_reinit when it isn't safe.  */
   if (fndecl && fndecl != previous_fndecl)
     {
-      struct function_specific_data *old_p
-	= (previous_fndecl ? DECL_FUNCTION_SPECIFIC (previous_fndecl) : NULL);
-
-      struct function_specific_data *cur_p
-	= (fndecl ? DECL_FUNCTION_SPECIFIC (fndecl) : NULL);
+      tree old_tree = (previous_fndecl
+		       ? DECL_FUNCTION_SPECIFIC_TARGET (previous_fndecl)
+		       : NULL_TREE);
+
+      tree new_tree = (fndecl
+		       ? DECL_FUNCTION_SPECIFIC_TARGET (fndecl)
+		       : NULL_TREE);
 
       previous_fndecl = fndecl;
-      if (cur_p == old_p)
+      if (old_tree == new_tree)
 	;
 
-      else if (cur_p)
+      else if (new_tree)
 	{
-	  ix86_function_specific_restore (cur_p);
+	  cl_target_option_restore (TREE_TARGET_OPTION (new_tree));
 	  target_reinit ();
 	}
 
-      else if (old_p)
+      else if (old_tree)
 	{
-	  ix86_function_specific_restore (ix86_initial_options);
+	  struct cl_target_option *def
+	    = TREE_TARGET_OPTION (target_option_default_node);
+
+	  cl_target_option_restore (def);
 	  target_reinit ();
 	}
     }
@@ -26864,10 +26937,8 @@ 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 SUBTARGET_INSERT_ATTRIBUTES
-#endif
+#define TARGET_INSERT_ATTRIBUTES ix86_insert_attributes
 
 #undef TARGET_MANGLE_TYPE
 #define TARGET_MANGLE_TYPE ix86_mangle_type
@@ -26884,6 +26955,24 @@ x86_builtin_vectorization_cost (bool run
 #undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST
 #define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST x86_builtin_vectorization_cost
 
+#undef TARGET_VALID_OPTION_ATTRIBUTE_P
+#define TARGET_VALID_OPTION_ATTRIBUTE_P ix86_valid_option_attribute_p
+
+#undef TARGET_SET_CURRENT_FUNCTION
+#define TARGET_SET_CURRENT_FUNCTION ix86_set_current_function
+
+#undef TARGET_OPTION_SAVE
+#define TARGET_OPTION_SAVE ix86_function_specific_save
+
+#undef TARGET_OPTION_RESTORE
+#define TARGET_OPTION_RESTORE ix86_function_specific_restore
+
+#undef TARGET_OPTION_PRINT
+#define TARGET_OPTION_PRINT ix86_function_specific_print
+
+#undef TARGET_CAN_INLINE_P
+#define TARGET_CAN_INLINE_P ix86_can_inline_p
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 

 #include "gt-i386.h"

-- 
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