diff mbox

LTO streaming of TARGET_OPTIMIZE_NODE

Message ID 20141114003713.GD31795@kam.mff.cuni.cz
State New
Headers show

Commit Message

Jan Hubicka Nov. 14, 2014, 12:37 a.m. UTC
Hi,
here is upated version with bitfields and also tested on PPC64-linux/aix.
I hacked configury to use system awk instead of gawk, so the changes are hopefully safe.

OK?
Honza

	* optc-save-gen.awk: Output cl_target_option_eq,
	cl_target_option_hash, cl_target_option_stream_out,
	cl_target_option_stream_in functions.
	* opth-gen.awk: Output prototypes for
	cl_target_option_eq and cl_target_option_hash.
	* lto-streamer.h (cl_target_option_stream_out,
	cl_target_option_stream_in): Declare.
	* tree.c (cl_option_hash_hash): Use cl_target_option_hash.
	(cl_option_hash_eq): Use cl_target_option_eq.
	* tree-streamer-in.c (unpack_value_fields): Stream in
	TREE_TARGET_OPTION.
	* lto-streamer-out.c (DFS::DFS_write_tree_body): Follow
	DECL_FUNCTION_SPECIFIC_TARGET.
	(hash_tree): Hash TREE_TARGET_OPTION; visit
	DECL_FUNCTION_SPECIFIC_TARGET.
	* tree-streamer-out.c (streamer_pack_tree_bitfields): Skip
	TS_TARGET_OPTION.
	(streamer_write_tree_body): Output TS_TARGET_OPTION.

	* lto.c (compare_tree_sccs_1): Compare cl_target_option_eq.

Comments

Richard Biener Nov. 14, 2014, 8:39 a.m. UTC | #1
On Fri, 14 Nov 2014, Jan Hubicka wrote:

> Hi,
> here is upated version with bitfields and also tested on PPC64-linux/aix.
> I hacked configury to use system awk instead of gawk, so the changes are hopefully safe.
> 
> OK?

Ok.

Thanks,
Richard.

> Honza
> 
> 	* optc-save-gen.awk: Output cl_target_option_eq,
> 	cl_target_option_hash, cl_target_option_stream_out,
> 	cl_target_option_stream_in functions.
> 	* opth-gen.awk: Output prototypes for
> 	cl_target_option_eq and cl_target_option_hash.
> 	* lto-streamer.h (cl_target_option_stream_out,
> 	cl_target_option_stream_in): Declare.
> 	* tree.c (cl_option_hash_hash): Use cl_target_option_hash.
> 	(cl_option_hash_eq): Use cl_target_option_eq.
> 	* tree-streamer-in.c (unpack_value_fields): Stream in
> 	TREE_TARGET_OPTION.
> 	* lto-streamer-out.c (DFS::DFS_write_tree_body): Follow
> 	DECL_FUNCTION_SPECIFIC_TARGET.
> 	(hash_tree): Hash TREE_TARGET_OPTION; visit
> 	DECL_FUNCTION_SPECIFIC_TARGET.
> 	* tree-streamer-out.c (streamer_pack_tree_bitfields): Skip
> 	TS_TARGET_OPTION.
> 	(streamer_write_tree_body): Output TS_TARGET_OPTION.
> 
> 	* lto.c (compare_tree_sccs_1): Compare cl_target_option_eq.
> Index: lto/lto.c
> ===================================================================
> --- lto/lto.c	(revision 217513)
> +++ lto/lto.c	(working copy)
> @@ -1377,7 +1377,8 @@
>        return false;
>  
>    if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
> -    gcc_unreachable ();
> +    if (!cl_target_option_eq (TREE_TARGET_OPTION (t1), TREE_TARGET_OPTION (t2)))
> +      return false;
>  
>    if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
>      if (memcmp (TREE_OPTIMIZATION (t1), TREE_OPTIMIZATION (t2),
> Index: lto-streamer-out.c
> ===================================================================
> --- lto-streamer-out.c	(revision 217513)
> +++ lto-streamer-out.c	(working copy)
> @@ -594,7 +594,7 @@
>      {
>        DFS_follow_tree_edge (DECL_VINDEX (expr));
>        DFS_follow_tree_edge (DECL_FUNCTION_PERSONALITY (expr));
> -      /* Do not DECL_FUNCTION_SPECIFIC_TARGET.  They will be regenerated.  */
> +      DFS_follow_tree_edge (DECL_FUNCTION_SPECIFIC_TARGET (expr));
>        DFS_follow_tree_edge (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr));
>      }
>  
> @@ -945,7 +945,7 @@
>  			strlen (TRANSLATION_UNIT_LANGUAGE (t)));
>  
>    if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
> -    gcc_unreachable ();
> +    hstate.add_wide_int (cl_target_option_hash (TREE_TARGET_OPTION (t)));
>  
>    if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
>      hstate.add (t, sizeof (struct cl_optimization));
> @@ -1028,7 +1028,7 @@
>      {
>        visit (DECL_VINDEX (t));
>        visit (DECL_FUNCTION_PERSONALITY (t));
> -      /* Do not follow DECL_FUNCTION_SPECIFIC_TARGET.  */
> +      visit (DECL_FUNCTION_SPECIFIC_TARGET (t));
>        visit (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (t));
>      }
>  
> Index: lto-streamer.h
> ===================================================================
> --- lto-streamer.h	(revision 217513)
> +++ lto-streamer.h	(working copy)
> @@ -836,7 +836,15 @@
>  lto_symtab_encoder_t compute_ltrans_boundary (lto_symtab_encoder_t encoder);
>  void select_what_to_stream (bool);
>  
> +/* In options-save.c.  */
> +void cl_target_option_stream_out (struct output_block *, struct bitpack_d *,
> +				  struct cl_target_option *);
>  
> +void cl_target_option_stream_in (struct data_in *,
> +				 struct bitpack_d *,
> +				 struct cl_target_option *);
> +
> +
>  /* In lto-symtab.c.  */
>  extern void lto_symtab_merge_decls (void);
>  extern void lto_symtab_merge_symbols (void);
> Index: optc-save-gen.awk
> ===================================================================
> --- optc-save-gen.awk	(revision 217513)
> +++ optc-save-gen.awk	(working copy)
> @@ -39,6 +39,18 @@
>  print ""
>  print "#include " quote "flags.h" quote
>  print "#include " quote "target.h" quote
> +print "#include " quote "inchash.h" quote
> +print "#include " quote "tree.h" quote
> +print "#include " quote "tree-ssa-alias.h" quote
> +print "#include " quote "is-a.h" quote
> +print "#include " quote "predict.h" quote
> +print "#include " quote "function.h" quote
> +print "#include " quote "basic-block.h" quote
> +print "#include " quote "gimple-expr.h" quote
> +print "#include " quote "gimple.h" quote
> +print "#include " quote "data-streamer.h" quote
> +print "#include " quote "ipa-ref.h" quote
> +print "#include " quote "cgraph.h" quote
>  print ""
>  
>  if (n_extra_c_includes > 0) {
> @@ -417,4 +429,126 @@
>  
>  print "}";
>  
> +print "";
> +print "/* Compare two target options  */";
> +print "bool";
> +print "cl_target_option_eq (struct cl_target_option const *ptr1 ATTRIBUTE_UNUSED,";
> +print "                     struct cl_target_option const *ptr2 ATTRIBUTE_UNUSED)";
> +print "{";
> +n_target_val = 0;
> +n_target_str = 0;
> +
> +for (i = 0; i < n_target_save; i++) {
> +	var = target_save_decl[i];
> +	sub (" *=.*", "", var);
> +	name = var;
> +	type = var;
> +	sub("^.*[ *]", "", name)
> +	sub(" *" name "$", "", type)
> +	if (target_save_decl[i] ~ "^const char \\*+[_" alnum "]+$")
> +		var_target_str[n_target_str++] = name;
> +	else {
> +		var_target_val_type[n_target_val] = type;
> +		var_target_val[n_target_val++] = name;
> +	}
>  }
> +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 = "target_flags";
> +
> +			if(name in var_list_seen)
> +				continue;
> +
> +			var_list_seen[name]++;
> +			otype = var_type_struct(flags[i])
> +			if (otype ~ "^const char \\**$")
> +				var_target_str[n_target_str++] = "x_" name;
> +			else {
> +				var_target_val_type[n_target_val] = otype;
> +				var_target_val[n_target_val++] = "x_" name;
> +			}
> +		}
> +	}
> +} else {
> +	var_target_val_type[n_target_val] = "int";
> +	var_target_val[n_target_val++] = "x_target_flags";
> +}
> +
> +for (i = 0; i < n_target_str; i++) {
> +	name = var_target_str[i]
> +	print "  if (ptr1->" name" != ptr2->" name;
> +	print "      && (!ptr1->" name" || !ptr2->" name
> +	print "          || strcmp (ptr1->" name", ptr2->" name ")))";
> +	print "    return false;";
> +}
> +for (i = 0; i < n_target_val; i++) {
> +	name = var_target_val[i]
> +	print "  if (ptr1->" name" != ptr2->" name ")";
> +	print "    return false;";
> +}
> +
> +print "  return true;";
> +
> +print "}";
> +
> +print "";
> +print "/* Hash target options  */";
> +print "hashval_t";
> +print "cl_target_option_hash (struct cl_target_option const *ptr ATTRIBUTE_UNUSED)";
> +print "{";
> +print "  inchash::hash hstate;";
> +for (i = 0; i < n_target_str; i++) {
> +	name = var_target_str[i]
> +	print "  if (ptr->" name")";
> +	print "    hstate.add (ptr->" name", strlen (ptr->" name"));";
> +	print "  else";
> +	print "    hstate.add_int (0);";
> +}
> +for (i = 0; i < n_target_val; i++) {
> +	name = var_target_val[i]
> +	print "  hstate.add_wide_int (ptr->" name");";
> +}
> +print "  return hstate.end ();";
> +print "}";
> +
> +print "";
> +print "/* Stream out target options  */";
> +print "void";
> +print "cl_target_option_stream_out (struct output_block *ob ATTRIBUTE_UNUSED,";
> +print "                             struct bitpack_d *bp ATTRIBUTE_UNUSED,";
> +print "                             struct cl_target_option *ptr ATTRIBUTE_UNUSED)";
> +print "{";
> +for (i = 0; i < n_target_str; i++) {
> +	name = var_target_str[i]
> +	print "  bp_pack_string (ob, bp, ptr->" name", true);";
> +}
> +for (i = 0; i < n_target_val; i++) {
> +	name = var_target_val[i]
> +	print "  bp_pack_value (bp, ptr->" name", 64);";
> +}
> +print "}";
> +
> +print "";
> +print "/* Stream in target options  */";
> +print "void";
> +print "cl_target_option_stream_in (struct data_in *data_in ATTRIBUTE_UNUSED,";
> +print "                            struct bitpack_d *bp ATTRIBUTE_UNUSED,";
> +print "                            struct cl_target_option *ptr ATTRIBUTE_UNUSED)";
> +print "{";
> +for (i = 0; i < n_target_str; i++) {
> +	name = var_target_str[i]
> +	print "  ptr->" name" = bp_unpack_string (data_in, bp);";
> +	print "  if (ptr->" name")";
> +	print "    ptr->" name" = xstrdup (ptr->" name");";
> +}
> +for (i = 0; i < n_target_val; i++) {
> +	name = var_target_val[i]
> +	print "  ptr->" name" = (" var_target_val_type[i] ") bp_unpack_value (bp, 64);";
> +}
> +
> +print "}";
> +
> +}
> Index: opth-gen.awk
> ===================================================================
> --- opth-gen.awk	(revision 217513)
> +++ opth-gen.awk	(working copy)
> @@ -293,6 +293,12 @@
>  print "/* Print target option variables from a structure.  */";
>  print "extern void cl_target_option_print (FILE *, int, struct cl_target_option *);";
>  print "";
> +print "/* Compare two target option variables from a structure.  */";
> +print "extern bool cl_target_option_eq (const struct cl_target_option *, const struct cl_target_option *);";
> +print "";
> +print "/* Hash option variables from a structure.  */";
> +print "extern hashval_t cl_target_option_hash (const struct cl_target_option *);";
> +print "";
>  print "/* Anything that includes tm.h, does not necessarily need this.  */"
>  print "#if !defined(GCC_TM_H)"
>  print "#include \"input.h\" /* for location_t */"
> Index: tree-streamer-in.c
> ===================================================================
> --- tree-streamer-in.c	(revision 217513)
> +++ tree-streamer-in.c	(working copy)
> @@ -506,9 +506,6 @@
>    if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
>      unpack_ts_translation_unit_decl_value_fields (data_in, bp, expr);
>  
> -  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
> -    gcc_unreachable ();
> -
>    if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
>      unpack_ts_optimization (bp, expr);
>  
> @@ -526,6 +523,9 @@
>  	vec_safe_grow (CONSTRUCTOR_ELTS (expr), length);
>      }
>  
> +  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
> +    cl_target_option_stream_in (data_in, bp, TREE_TARGET_OPTION (expr));
> +
>    if (code == OMP_CLAUSE)
>      unpack_ts_omp_clause_value_fields (data_in, bp, expr);
>  }
> Index: tree-streamer-out.c
> ===================================================================
> --- tree-streamer-out.c	(revision 217513)
> +++ tree-streamer-out.c	(working copy)
> @@ -472,9 +472,6 @@
>    if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
>      pack_ts_translation_unit_decl_value_fields (ob, bp, expr);
>  
> -  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
> -    gcc_unreachable ();
> -
>    if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
>      pack_ts_optimization (bp, expr);
>  
> @@ -484,6 +481,9 @@
>    if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
>      bp_pack_var_len_unsigned (bp, CONSTRUCTOR_NELTS (expr));
>  
> +  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
> +    cl_target_option_stream_out (ob, bp, TREE_TARGET_OPTION (expr));
> +
>    if (code == OMP_CLAUSE)
>      pack_ts_omp_clause_value_fields (ob, bp, expr);
>  }
> Index: tree.c
> ===================================================================
> --- tree.c	(revision 217513)
> +++ tree.c	(working copy)
> @@ -11486,10 +11486,7 @@
>      }
>  
>    else if (TREE_CODE (t) == TARGET_OPTION_NODE)
> -    {
> -      p = (const char *)TREE_TARGET_OPTION (t);
> -      len = sizeof (struct cl_target_option);
> -    }
> +    return cl_target_option_hash (TREE_TARGET_OPTION (t));
>  
>    else
>      gcc_unreachable ();
> @@ -11528,9 +11525,8 @@
>  
>    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);
> +      return cl_target_option_eq (TREE_TARGET_OPTION (xt),
> +				  TREE_TARGET_OPTION (yt));
>      }
>  
>    else
> 
>
Jan-Benedict Glaw Nov. 14, 2014, 6:09 p.m. UTC | #2
On Fri, 2014-11-14 01:37:14 +0100, Jan Hubicka <hubicka@ucw.cz> wrote:
> Hi,
> here is upated version with bitfields and also tested on PPC64-linux/aix.
> I hacked configury to use system awk instead of gawk, so the changes are hopefully safe.
> 
> OK?
> Honza
> 
> 	* optc-save-gen.awk: Output cl_target_option_eq,
> 	cl_target_option_hash, cl_target_option_stream_out,
> 	cl_target_option_stream_in functions.
> 	* opth-gen.awk: Output prototypes for
> 	cl_target_option_eq and cl_target_option_hash.
> 	* lto-streamer.h (cl_target_option_stream_out,
> 	cl_target_option_stream_in): Declare.
> 	* tree.c (cl_option_hash_hash): Use cl_target_option_hash.
> 	(cl_option_hash_eq): Use cl_target_option_eq.
> 	* tree-streamer-in.c (unpack_value_fields): Stream in
> 	TREE_TARGET_OPTION.
> 	* lto-streamer-out.c (DFS::DFS_write_tree_body): Follow
> 	DECL_FUNCTION_SPECIFIC_TARGET.
> 	(hash_tree): Hash TREE_TARGET_OPTION; visit
> 	DECL_FUNCTION_SPECIFIC_TARGET.
> 	* tree-streamer-out.c (streamer_pack_tree_bitfields): Skip
> 	TS_TARGET_OPTION.
> 	(streamer_write_tree_body): Output TS_TARGET_OPTION.

Breaks build:

g++ -c   -g -O2 -DIN_GCC  -DCROSS_DIRECTORY_STRUCTURE  -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -fno-common  -DHAVE_CONFIG_H -I. -I. -I/home/jbglaw/repos/gcc/gcc -I/home/jbglaw/repos/gcc/gcc/. -I/home/jbglaw/repos/gcc/gcc/../include -I/home/jbglaw/repos/gcc/gcc/../libcpp/include  -I/home/jbglaw/repos/gcc/gcc/../libdecnumber -I/home/jbglaw/repos/gcc/gcc/../libdecnumber/dpd -I../libdecnumber -I/home/jbglaw/repos/gcc/gcc/../libbacktrace    -o tree-streamer-in.o -MT tree-streamer-in.o -MMD -MP -MF ./.deps/tree-streamer-in.TPo /home/jbglaw/repos/gcc/gcc/tree-streamer-in.c
/home/jbglaw/repos/gcc/gcc/tree-streamer-in.c: In function ‘void unpack_value_fields(data_in*, bitpack_d*, tree)’:
/home/jbglaw/repos/gcc/gcc/tree-streamer-in.c:527:180: error: ‘cl_target_option_stream_in’ was not declared in this scope
make[1]: *** [tree-streamer-in.o] Error 1


See eg. these builds:

http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=376049
http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=376050
http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=376051

MfG, JBG
Jan Hubicka Nov. 14, 2014, 6:53 p.m. UTC | #3
> 
> Breaks build:
> 
> g++ -c   -g -O2 -DIN_GCC  -DCROSS_DIRECTORY_STRUCTURE  -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -fno-common  -DHAVE_CONFIG_H -I. -I. -I/home/jbglaw/repos/gcc/gcc -I/home/jbglaw/repos/gcc/gcc/. -I/home/jbglaw/repos/gcc/gcc/../include -I/home/jbglaw/repos/gcc/gcc/../libcpp/include  -I/home/jbglaw/repos/gcc/gcc/../libdecnumber -I/home/jbglaw/repos/gcc/gcc/../libdecnumber/dpd -I../libdecnumber -I/home/jbglaw/repos/gcc/gcc/../libbacktrace    -o tree-streamer-in.o -MT tree-streamer-in.o -MMD -MP -MF ./.deps/tree-streamer-in.TPo /home/jbglaw/repos/gcc/gcc/tree-streamer-in.c
> /home/jbglaw/repos/gcc/gcc/tree-streamer-in.c: In function ‘void unpack_value_fields(data_in*, bitpack_d*, tree)’:
> /home/jbglaw/repos/gcc/gcc/tree-streamer-in.c:527:180: error: ‘cl_target_option_stream_in’ was not declared in this scope
> make[1]: *** [tree-streamer-in.o] Error 1
> 
> 
> See eg. these builds:
> 
> http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=376049
> http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=376050
> http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=376051

I managed to do a partial commit (mistyping lto-streamer.h). It should be fixed by the followup commit
a minute later.  Does it works for you now?

Honza
> 
> MfG, JBG
> 
> -- 
>       Jan-Benedict Glaw      jbglaw@lug-owl.de              +49-172-7608481
> Signature of:              What we do for ourselves dies with us. What we do for
> the second  :         others and the world remains and is immortal. (Albert Pine)
Jan-Benedict Glaw Nov. 15, 2014, 4:23 p.m. UTC | #4
On Fri, 2014-11-14 19:53:33 +0100, Jan Hubicka <hubicka@ucw.cz> wrote:
> > Breaks build:
> > 
> > g++ -c   -g -O2 -DIN_GCC  -DCROSS_DIRECTORY_STRUCTURE  -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -fno-common  -DHAVE_CONFIG_H -I. -I. -I/home/jbglaw/repos/gcc/gcc -I/home/jbglaw/repos/gcc/gcc/. -I/home/jbglaw/repos/gcc/gcc/../include -I/home/jbglaw/repos/gcc/gcc/../libcpp/include  -I/home/jbglaw/repos/gcc/gcc/../libdecnumber -I/home/jbglaw/repos/gcc/gcc/../libdecnumber/dpd -I../libdecnumber -I/home/jbglaw/repos/gcc/gcc/../libbacktrace    -o tree-streamer-in.o -MT tree-streamer-in.o -MMD -MP -MF ./.deps/tree-streamer-in.TPo /home/jbglaw/repos/gcc/gcc/tree-streamer-in.c
> > /home/jbglaw/repos/gcc/gcc/tree-streamer-in.c: In function ‘void unpack_value_fields(data_in*, bitpack_d*, tree)’:
> > /home/jbglaw/repos/gcc/gcc/tree-streamer-in.c:527:180: error: ‘cl_target_option_stream_in’ was not declared in this scope
> > make[1]: *** [tree-streamer-in.o] Error 1
> > 
> > 
> > See eg. these builds:
> > 
> > http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=376049
> > http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=376050
> > http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=376051
> 
> I managed to do a partial commit (mistyping lto-streamer.h). It should be fixed by the followup commit
> a minute later.  Does it works for you now?

Looks good. Thanks!

MfG, JBG
diff mbox

Patch

Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 217513)
+++ lto/lto.c	(working copy)
@@ -1377,7 +1377,8 @@ 
       return false;
 
   if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
-    gcc_unreachable ();
+    if (!cl_target_option_eq (TREE_TARGET_OPTION (t1), TREE_TARGET_OPTION (t2)))
+      return false;
 
   if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
     if (memcmp (TREE_OPTIMIZATION (t1), TREE_OPTIMIZATION (t2),
Index: lto-streamer-out.c
===================================================================
--- lto-streamer-out.c	(revision 217513)
+++ lto-streamer-out.c	(working copy)
@@ -594,7 +594,7 @@ 
     {
       DFS_follow_tree_edge (DECL_VINDEX (expr));
       DFS_follow_tree_edge (DECL_FUNCTION_PERSONALITY (expr));
-      /* Do not DECL_FUNCTION_SPECIFIC_TARGET.  They will be regenerated.  */
+      DFS_follow_tree_edge (DECL_FUNCTION_SPECIFIC_TARGET (expr));
       DFS_follow_tree_edge (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr));
     }
 
@@ -945,7 +945,7 @@ 
 			strlen (TRANSLATION_UNIT_LANGUAGE (t)));
 
   if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
-    gcc_unreachable ();
+    hstate.add_wide_int (cl_target_option_hash (TREE_TARGET_OPTION (t)));
 
   if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
     hstate.add (t, sizeof (struct cl_optimization));
@@ -1028,7 +1028,7 @@ 
     {
       visit (DECL_VINDEX (t));
       visit (DECL_FUNCTION_PERSONALITY (t));
-      /* Do not follow DECL_FUNCTION_SPECIFIC_TARGET.  */
+      visit (DECL_FUNCTION_SPECIFIC_TARGET (t));
       visit (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (t));
     }
 
Index: lto-streamer.h
===================================================================
--- lto-streamer.h	(revision 217513)
+++ lto-streamer.h	(working copy)
@@ -836,7 +836,15 @@ 
 lto_symtab_encoder_t compute_ltrans_boundary (lto_symtab_encoder_t encoder);
 void select_what_to_stream (bool);
 
+/* In options-save.c.  */
+void cl_target_option_stream_out (struct output_block *, struct bitpack_d *,
+				  struct cl_target_option *);
 
+void cl_target_option_stream_in (struct data_in *,
+				 struct bitpack_d *,
+				 struct cl_target_option *);
+
+
 /* In lto-symtab.c.  */
 extern void lto_symtab_merge_decls (void);
 extern void lto_symtab_merge_symbols (void);
Index: optc-save-gen.awk
===================================================================
--- optc-save-gen.awk	(revision 217513)
+++ optc-save-gen.awk	(working copy)
@@ -39,6 +39,18 @@ 
 print ""
 print "#include " quote "flags.h" quote
 print "#include " quote "target.h" quote
+print "#include " quote "inchash.h" quote
+print "#include " quote "tree.h" quote
+print "#include " quote "tree-ssa-alias.h" quote
+print "#include " quote "is-a.h" quote
+print "#include " quote "predict.h" quote
+print "#include " quote "function.h" quote
+print "#include " quote "basic-block.h" quote
+print "#include " quote "gimple-expr.h" quote
+print "#include " quote "gimple.h" quote
+print "#include " quote "data-streamer.h" quote
+print "#include " quote "ipa-ref.h" quote
+print "#include " quote "cgraph.h" quote
 print ""
 
 if (n_extra_c_includes > 0) {
@@ -417,4 +429,126 @@ 
 
 print "}";
 
+print "";
+print "/* Compare two target options  */";
+print "bool";
+print "cl_target_option_eq (struct cl_target_option const *ptr1 ATTRIBUTE_UNUSED,";
+print "                     struct cl_target_option const *ptr2 ATTRIBUTE_UNUSED)";
+print "{";
+n_target_val = 0;
+n_target_str = 0;
+
+for (i = 0; i < n_target_save; i++) {
+	var = target_save_decl[i];
+	sub (" *=.*", "", var);
+	name = var;
+	type = var;
+	sub("^.*[ *]", "", name)
+	sub(" *" name "$", "", type)
+	if (target_save_decl[i] ~ "^const char \\*+[_" alnum "]+$")
+		var_target_str[n_target_str++] = name;
+	else {
+		var_target_val_type[n_target_val] = type;
+		var_target_val[n_target_val++] = name;
+	}
 }
+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 = "target_flags";
+
+			if(name in var_list_seen)
+				continue;
+
+			var_list_seen[name]++;
+			otype = var_type_struct(flags[i])
+			if (otype ~ "^const char \\**$")
+				var_target_str[n_target_str++] = "x_" name;
+			else {
+				var_target_val_type[n_target_val] = otype;
+				var_target_val[n_target_val++] = "x_" name;
+			}
+		}
+	}
+} else {
+	var_target_val_type[n_target_val] = "int";
+	var_target_val[n_target_val++] = "x_target_flags";
+}
+
+for (i = 0; i < n_target_str; i++) {
+	name = var_target_str[i]
+	print "  if (ptr1->" name" != ptr2->" name;
+	print "      && (!ptr1->" name" || !ptr2->" name
+	print "          || strcmp (ptr1->" name", ptr2->" name ")))";
+	print "    return false;";
+}
+for (i = 0; i < n_target_val; i++) {
+	name = var_target_val[i]
+	print "  if (ptr1->" name" != ptr2->" name ")";
+	print "    return false;";
+}
+
+print "  return true;";
+
+print "}";
+
+print "";
+print "/* Hash target options  */";
+print "hashval_t";
+print "cl_target_option_hash (struct cl_target_option const *ptr ATTRIBUTE_UNUSED)";
+print "{";
+print "  inchash::hash hstate;";
+for (i = 0; i < n_target_str; i++) {
+	name = var_target_str[i]
+	print "  if (ptr->" name")";
+	print "    hstate.add (ptr->" name", strlen (ptr->" name"));";
+	print "  else";
+	print "    hstate.add_int (0);";
+}
+for (i = 0; i < n_target_val; i++) {
+	name = var_target_val[i]
+	print "  hstate.add_wide_int (ptr->" name");";
+}
+print "  return hstate.end ();";
+print "}";
+
+print "";
+print "/* Stream out target options  */";
+print "void";
+print "cl_target_option_stream_out (struct output_block *ob ATTRIBUTE_UNUSED,";
+print "                             struct bitpack_d *bp ATTRIBUTE_UNUSED,";
+print "                             struct cl_target_option *ptr ATTRIBUTE_UNUSED)";
+print "{";
+for (i = 0; i < n_target_str; i++) {
+	name = var_target_str[i]
+	print "  bp_pack_string (ob, bp, ptr->" name", true);";
+}
+for (i = 0; i < n_target_val; i++) {
+	name = var_target_val[i]
+	print "  bp_pack_value (bp, ptr->" name", 64);";
+}
+print "}";
+
+print "";
+print "/* Stream in target options  */";
+print "void";
+print "cl_target_option_stream_in (struct data_in *data_in ATTRIBUTE_UNUSED,";
+print "                            struct bitpack_d *bp ATTRIBUTE_UNUSED,";
+print "                            struct cl_target_option *ptr ATTRIBUTE_UNUSED)";
+print "{";
+for (i = 0; i < n_target_str; i++) {
+	name = var_target_str[i]
+	print "  ptr->" name" = bp_unpack_string (data_in, bp);";
+	print "  if (ptr->" name")";
+	print "    ptr->" name" = xstrdup (ptr->" name");";
+}
+for (i = 0; i < n_target_val; i++) {
+	name = var_target_val[i]
+	print "  ptr->" name" = (" var_target_val_type[i] ") bp_unpack_value (bp, 64);";
+}
+
+print "}";
+
+}
Index: opth-gen.awk
===================================================================
--- opth-gen.awk	(revision 217513)
+++ opth-gen.awk	(working copy)
@@ -293,6 +293,12 @@ 
 print "/* Print target option variables from a structure.  */";
 print "extern void cl_target_option_print (FILE *, int, struct cl_target_option *);";
 print "";
+print "/* Compare two target option variables from a structure.  */";
+print "extern bool cl_target_option_eq (const struct cl_target_option *, const struct cl_target_option *);";
+print "";
+print "/* Hash option variables from a structure.  */";
+print "extern hashval_t cl_target_option_hash (const struct cl_target_option *);";
+print "";
 print "/* Anything that includes tm.h, does not necessarily need this.  */"
 print "#if !defined(GCC_TM_H)"
 print "#include \"input.h\" /* for location_t */"
Index: tree-streamer-in.c
===================================================================
--- tree-streamer-in.c	(revision 217513)
+++ tree-streamer-in.c	(working copy)
@@ -506,9 +506,6 @@ 
   if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
     unpack_ts_translation_unit_decl_value_fields (data_in, bp, expr);
 
-  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
-    gcc_unreachable ();
-
   if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
     unpack_ts_optimization (bp, expr);
 
@@ -526,6 +523,9 @@ 
 	vec_safe_grow (CONSTRUCTOR_ELTS (expr), length);
     }
 
+  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
+    cl_target_option_stream_in (data_in, bp, TREE_TARGET_OPTION (expr));
+
   if (code == OMP_CLAUSE)
     unpack_ts_omp_clause_value_fields (data_in, bp, expr);
 }
Index: tree-streamer-out.c
===================================================================
--- tree-streamer-out.c	(revision 217513)
+++ tree-streamer-out.c	(working copy)
@@ -472,9 +472,6 @@ 
   if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
     pack_ts_translation_unit_decl_value_fields (ob, bp, expr);
 
-  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
-    gcc_unreachable ();
-
   if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
     pack_ts_optimization (bp, expr);
 
@@ -484,6 +481,9 @@ 
   if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
     bp_pack_var_len_unsigned (bp, CONSTRUCTOR_NELTS (expr));
 
+  if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
+    cl_target_option_stream_out (ob, bp, TREE_TARGET_OPTION (expr));
+
   if (code == OMP_CLAUSE)
     pack_ts_omp_clause_value_fields (ob, bp, expr);
 }
Index: tree.c
===================================================================
--- tree.c	(revision 217513)
+++ tree.c	(working copy)
@@ -11486,10 +11486,7 @@ 
     }
 
   else if (TREE_CODE (t) == TARGET_OPTION_NODE)
-    {
-      p = (const char *)TREE_TARGET_OPTION (t);
-      len = sizeof (struct cl_target_option);
-    }
+    return cl_target_option_hash (TREE_TARGET_OPTION (t));
 
   else
     gcc_unreachable ();
@@ -11528,9 +11525,8 @@ 
 
   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);
+      return cl_target_option_eq (TREE_TARGET_OPTION (xt),
+				  TREE_TARGET_OPTION (yt));
     }
 
   else