summaryrefslogtreecommitdiff
path: root/gcc/lto-opts.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/lto-opts.c')
-rw-r--r--gcc/lto-opts.c409
1 files changed, 409 insertions, 0 deletions
diff --git a/gcc/lto-opts.c b/gcc/lto-opts.c
new file mode 100644
index 00000000000..2a379f40fdc
--- /dev/null
+++ b/gcc/lto-opts.c
@@ -0,0 +1,409 @@
+/* LTO IL options.
+
+ Copyright 2009 Free Software Foundation, Inc.
+ Contributed by Simon Baldwin <simonb@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "hashtab.h"
+#include "ggc.h"
+#include "vec.h"
+#include "bitmap.h"
+#include "flags.h"
+#include "opts.h"
+#include "options.h"
+#include "target.h"
+#include "toplev.h"
+#include "lto-streamer.h"
+
+/* When a file is initially compiled, the options used when generating
+ the IL are not necessarily the same as those used when linking the
+ objects into the final executable. In general, most build systems
+ will proceed with something along the lines of:
+
+ $ gcc <cc-flags> -flto -c f1.c -o f1.o
+ $ gcc <cc-flags> -flto -c f2.c -o f2.o
+ ...
+ $ gcc <cc-flags> -flto -c fN.c -o fN.o
+
+ And the final link may or may not include the same <cc-flags> used
+ to generate the initial object files:
+
+ $ gcc <ld-flags> -flto -o prog f1.o ... fN.o
+
+ Since we will be generating final code during the link step, some
+ of the flags used during the compile step need to be re-applied
+ during the link step. For instance, flags in the -m family.
+
+ The idea is to save a selected set of <cc-flags> in a special
+ section of the initial object files. This section is then read
+ during linking and the options re-applied.
+
+ FIXME lto. Currently the scheme is limited in that only the
+ options saved on the first object file (f1.o) are read back during
+ the link step. This means that the options used to compile f1.o
+ will be applied to ALL the object files in the final link step.
+ More work needs to be done to implement a merging and validation
+ mechanism, as this will not be enough for all cases. */
+
+/* Saved options hold the type of the option (currently CL_TARGET or
+ CL_COMMON), and the code, argument, and value. */
+
+typedef struct GTY(()) opt_d
+{
+ unsigned int type;
+ size_t code;
+ char *arg;
+ int value;
+} opt_t;
+
+DEF_VEC_O (opt_t);
+DEF_VEC_ALLOC_O (opt_t, heap);
+
+
+/* Options are held in two vectors, one for those registered by
+ command line handling code, and the other for those read in from
+ any LTO IL input. */
+static VEC(opt_t, heap) *user_options = NULL;
+static VEC(opt_t, heap) *file_options = NULL;
+
+/* Iterate FROM in reverse, writing option codes not yet in CODES into *TO.
+ Mark each new option code encountered in CODES. */
+
+static void
+reverse_iterate_options (VEC(opt_t, heap) *from, VEC(opt_t, heap) **to,
+ bitmap codes)
+{
+ int i;
+
+ for (i = VEC_length (opt_t, from); i > 0; i--)
+ {
+ const opt_t *const o = VEC_index (opt_t, from, i - 1);
+
+ if (bitmap_set_bit (codes, o->code))
+ VEC_safe_push (opt_t, heap, *to, o);
+ }
+}
+
+/* Concatenate options vectors FIRST and SECOND, rationalize so that only the
+ final of any given option remains, and return the result. */
+
+static VEC(opt_t, heap) *
+concatenate_options (VEC(opt_t, heap) *first, VEC(opt_t, heap) *second)
+{
+ VEC(opt_t, heap) *results = NULL;
+ bitmap codes = lto_bitmap_alloc ();
+
+ reverse_iterate_options (second, &results, codes);
+ reverse_iterate_options (first, &results, codes);
+
+ lto_bitmap_free (codes);
+ return results;
+}
+
+/* Clear the options vector in *OPTS_P and set it to NULL. */
+
+static void
+clear_options (VEC(opt_t, heap) **opts_p)
+{
+ int i;
+ opt_t *o;
+
+ for (i = 0; VEC_iterate (opt_t, *opts_p, i, o); i++)
+ free (o->arg);
+
+ VEC_free (opt_t, heap, *opts_p);
+}
+
+/* Write LENGTH bytes from ADDR to STREAM. */
+
+static void
+output_data_stream (struct lto_output_stream *stream,
+ const void *addr, size_t length)
+{
+ lto_output_data_stream (stream, addr, length);
+}
+
+/* Write string STRING to STREAM. */
+
+static void
+output_string_stream (struct lto_output_stream *stream, const char *string)
+{
+ bool flag = false;
+
+ if (string != NULL)
+ {
+ const size_t length = strlen (string);
+
+ flag = true;
+ output_data_stream (stream, &flag, sizeof (flag));
+ output_data_stream (stream, &length, sizeof (length));
+ output_data_stream (stream, string, length);
+ }
+ else
+ output_data_stream (stream, &flag, sizeof (flag));
+}
+
+/* Read LENGTH bytes from STREAM to ADDR. */
+
+static void
+input_data_block (struct lto_input_block *ib, void *addr, size_t length)
+{
+ size_t i;
+ unsigned char *const buffer = (unsigned char *const) addr;
+
+ for (i = 0; i < length; i++)
+ buffer[i] = lto_input_1_unsigned (ib);
+}
+
+/* Return a string from IB. The string is allocated, and the caller is
+ responsible for freeing it. */
+
+static char *
+input_string_block (struct lto_input_block *ib)
+{
+ bool flag;
+
+ input_data_block (ib, &flag, sizeof (flag));
+ if (flag)
+ {
+ size_t length;
+ char *string;
+
+ input_data_block (ib, &length, sizeof (length));
+ string = (char *) xcalloc (1, length + 1);
+ input_data_block (ib, string, length);
+
+ return string;
+ }
+ else
+ return NULL;
+}
+
+/* Return true if this option is one we need to save in LTO output files.
+ At present, we pass along all target options, and common options that
+ involve position independent code.
+
+ TODO This list of options requires expansion and rationalization.
+ Among others, optimization options may well be appropriate here. */
+
+static bool
+register_user_option_p (size_t code, int type)
+{
+ return type == CL_TARGET
+ || (type == CL_COMMON
+ && (code == OPT_fPIC
+ || code == OPT_fcommon));
+}
+
+/* Note command line option with the given TYPE and CODE, ARG, and VALUE.
+ If relevant to LTO, save it in the user options vector. */
+
+void
+lto_register_user_option (size_t code, const char *arg, int value, int type)
+{
+ if (register_user_option_p (code, type))
+ {
+ opt_t o;
+
+ o.type = type;
+ o.code = code;
+ if (arg != NULL)
+ {
+ o.arg = (char *) xmalloc (strlen (arg) + 1);
+ strcpy (o.arg, arg);
+ }
+ else
+ o.arg = NULL;
+ o.value = value;
+ VEC_safe_push (opt_t, heap, user_options, &o);
+ }
+}
+
+/* Empty the saved user options vector. */
+
+void
+lto_clear_user_options (void)
+{
+ clear_options (&user_options);
+}
+
+/* Empty the saved file options vector. */
+
+void
+lto_clear_file_options (void)
+{
+ clear_options (&file_options);
+}
+
+/* Concatenate the user options and any file options read from an LTO IL
+ file, and serialize them to STREAM. File options precede user options
+ so that the latter override the former when reissued. */
+
+static void
+output_options (struct lto_output_stream *stream)
+{
+ VEC(opt_t, heap) *opts = concatenate_options (file_options, user_options);
+ const size_t length = VEC_length (opt_t, opts);
+ int i;
+ opt_t *o;
+
+ output_data_stream (stream, &length, sizeof (length));
+
+ for (i = 0; VEC_iterate (opt_t, opts, i, o); i++)
+ {
+ output_data_stream (stream, &o->type, sizeof (o->type));
+ output_data_stream (stream, &o->code, sizeof (o->code));
+ output_string_stream (stream, o->arg);
+ output_data_stream (stream, &o->value, sizeof (o->value));
+ }
+
+ VEC_free (opt_t, heap, opts);
+}
+
+/* Write currently held options to an LTO IL section. */
+
+void
+lto_write_options (void)
+{
+ char *const section_name = lto_get_section_name (LTO_section_opts, NULL);
+ struct lto_output_stream stream;
+ struct lto_simple_header header;
+ struct lto_output_stream *header_stream;
+
+ lto_begin_section (section_name, !flag_wpa);
+ free (section_name);
+
+ memset (&stream, 0, sizeof (stream));
+ output_options (&stream);
+
+ memset (&header, 0, sizeof (header));
+ header.lto_header.major_version = LTO_major_version;
+ header.lto_header.minor_version = LTO_minor_version;
+ header.lto_header.section_type = LTO_section_opts;
+
+ header.compressed_size = 0;
+ header.main_size = stream.total_size;
+
+ header_stream = ((struct lto_output_stream *)
+ xcalloc (1, sizeof (*header_stream)));
+ lto_output_data_stream (header_stream, &header, sizeof (header));
+ lto_write_stream (header_stream);
+ free (header_stream);
+
+ lto_write_stream (&stream);
+ lto_end_section ();
+}
+
+/* Unserialize an options vector from IB, and append to file_options. */
+
+static void
+input_options (struct lto_input_block *ib)
+{
+ size_t length, i;
+
+ input_data_block (ib, &length, sizeof (length));
+
+ for (i = 0; i < length; i++)
+ {
+ opt_t o;
+
+ input_data_block (ib, &o.type, sizeof (o.type));
+ input_data_block (ib, &o.code, sizeof (o.code));
+ o.arg = input_string_block (ib);
+ input_data_block (ib, &o.value, sizeof (o.value));
+ VEC_safe_push (opt_t, heap, file_options, &o);
+ }
+}
+
+/* Read options from an LTO IL section. */
+
+void
+lto_read_file_options (struct lto_file_decl_data *file_data)
+{
+ size_t len;
+ const char *data;
+ const struct lto_simple_header *header;
+ int32_t opts_offset;
+ struct lto_input_block ib;
+
+ data = lto_get_section_data (file_data, LTO_section_opts, NULL, &len);
+ header = (const struct lto_simple_header *) data;
+ opts_offset = sizeof (*header);
+
+ lto_check_version (header->lto_header.major_version,
+ header->lto_header.minor_version);
+
+ LTO_INIT_INPUT_BLOCK (ib, data + opts_offset, 0, header->main_size);
+ input_options (&ib);
+
+ lto_free_section_data (file_data, LTO_section_opts, 0, data, len);
+}
+
+/* Re-handle option with type TYPE and CODE, ARG, and VALUE. Logic extracted
+ from common_handle_option() in opts.c.
+
+ FIXME lto. This section is not complete. If extended to handle
+ optimization options, note that changing these after opts.c prescan may
+ involve also adjusting other options that were defaulted from initial
+ optimization option values. */
+
+static void
+handle_common_option (size_t code, const char *arg ATTRIBUTE_UNUSED, int value)
+{
+ switch (code)
+ {
+ case OPT_fPIC:
+ flag_pic = !!value;
+ break;
+
+ case OPT_fcommon:
+ flag_no_common = !value;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Concatenate the user options and any file options read from an LTO IL
+ file, and reissue them as if all had just been read in from the command
+ line. As with serialization, file options precede user options. */
+
+void
+lto_reissue_options (void)
+{
+ VEC(opt_t, heap) *opts = concatenate_options (file_options, user_options);
+ int i;
+ opt_t *o;
+
+ for (i = 0; VEC_iterate (opt_t, opts, i, o); i++)
+ {
+ if (o->type == CL_TARGET)
+ targetm.handle_option (o->code, o->arg, o->value);
+ else if (o->type == CL_COMMON)
+ handle_common_option (o->code, o->arg, o->value);
+ else
+ gcc_unreachable ();
+ }
+
+ VEC_free (opt_t, heap, opts);
+}