diff options
Diffstat (limited to 'gcc/lto-opts.c')
-rw-r--r-- | gcc/lto-opts.c | 409 |
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); +} |