/* Language-dependent hooks for LTO.
- Copyright 2009 Free Software Foundation, Inc.
+ Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
Contributed by CodeSourcery, Inc.
This file is part of GCC.
#include "flags.h"
#include "tm.h"
#include "tree.h"
-#include "expr.h"
#include "target.h"
#include "langhooks.h"
#include "langhooks-def.h"
#include "lto.h"
#include "tree-inline.h"
#include "gimple.h"
+#include "diagnostic-core.h"
#include "toplev.h"
+#include "lto-streamer.h"
static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
+static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
static tree handle_const_attribute (tree *, tree, tree, int, bool *);
static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
+static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
+static tree ignore_attribute (tree *, tree, tree, int, bool *);
+
static tree handle_format_attribute (tree *, tree, tree, int, bool *);
static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
/* Table of machine-independent attributes supported in GIMPLE. */
const struct attribute_spec lto_attribute_table[] =
{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ do_diagnostic } */
{ "noreturn", 0, 0, true, false, false,
- handle_noreturn_attribute },
+ handle_noreturn_attribute, false },
+ { "leaf", 0, 0, true, false, false,
+ handle_leaf_attribute, false },
/* The same comments as for noreturn attributes apply to const ones. */
{ "const", 0, 0, true, false, false,
- handle_const_attribute },
+ handle_const_attribute, false },
{ "malloc", 0, 0, true, false, false,
- handle_malloc_attribute },
+ handle_malloc_attribute, false },
{ "pure", 0, 0, true, false, false,
- handle_pure_attribute },
+ handle_pure_attribute, false },
{ "no vops", 0, 0, true, false, false,
- handle_novops_attribute },
+ handle_novops_attribute, false },
{ "nonnull", 0, -1, false, true, true,
- handle_nonnull_attribute },
+ handle_nonnull_attribute, false },
{ "nothrow", 0, 0, true, false, false,
- handle_nothrow_attribute },
+ handle_nothrow_attribute, false },
+ { "returns_twice", 0, 0, true, false, false,
+ handle_returns_twice_attribute, false },
{ "sentinel", 0, 1, false, true, true,
- handle_sentinel_attribute },
+ handle_sentinel_attribute, false },
{ "type generic", 0, 0, false, true, true,
- handle_type_generic_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+ handle_type_generic_attribute, false },
+ { "transaction_pure", 0, 0, false, true, true,
+ handle_transaction_pure_attribute, false },
+ /* For internal use only. The leading '*' both prevents its usage in
+ source code and signals that it may be overridden by machine tables. */
+ { "*tm regparm", 0, 0, false, true, true,
+ ignore_attribute, false },
+ { NULL, 0, 0, false, false, false, NULL, false }
};
/* Give the specifications for the format attributes, used by C and all
const struct attribute_spec lto_format_attribute_table[] =
{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity } */
{ "format", 3, 3, false, true, true,
- handle_format_attribute },
+ handle_format_attribute, false },
{ "format_arg", 1, 1, false, true, true,
- handle_format_arg_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+ handle_format_arg_attribute, false },
+ { NULL, 0, 0, false, false, false, NULL, false }
};
enum built_in_attribute
static GTY(()) tree signed_size_type_node;
/* Flags needed to process builtins.def. */
-int flag_no_builtin;
-int flag_no_nonansi_builtin;
int flag_isoc94;
int flag_isoc99;
return NULL_TREE;
}
+/* Handle a "leaf" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_leaf_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ if (!TREE_PUBLIC (*node))
+ {
+ warning (OPT_Wattributes, "%qE attribute has no effect on unit local functions", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
/* Handle a "const" attribute; arguments as in
struct attribute_spec.handler. */
bool * ARG_UNUSED (no_add_attrs))
{
tree type = *node;
- unsigned HOST_WIDE_INT attr_arg_num;
/* If no arguments are specified, all pointer arguments should be
non-null. Verify a full prototype is given so that the arguments
will have the correct types when we actually check them later. */
if (!args)
{
- gcc_assert (TYPE_ARG_TYPES (type));
+ gcc_assert (prototype_p (type));
return NULL_TREE;
}
/* Argument list specified. Verify that each argument number references
a pointer argument. */
- for (attr_arg_num = 1; args; args = TREE_CHAIN (args))
+ for (; args; args = TREE_CHAIN (args))
{
tree argument;
unsigned HOST_WIDE_INT arg_num = 0, ck_num;
int ARG_UNUSED (flags),
bool * ARG_UNUSED (no_add_attrs))
{
- tree params = TYPE_ARG_TYPES (*node);
- gcc_assert (params);
-
- while (TREE_CHAIN (params))
- params = TREE_CHAIN (params);
-
- gcc_assert (!VOID_TYPE_P (TREE_VALUE (params)));
+ gcc_assert (stdarg_p (*node));
if (args)
{
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
bool * ARG_UNUSED (no_add_attrs))
{
- tree params;
-
/* Ensure we have a function type. */
gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
- params = TYPE_ARG_TYPES (*node);
- while (params && ! VOID_TYPE_P (TREE_VALUE (params)))
- params = TREE_CHAIN (params);
-
/* Ensure we have a variadic function. */
- gcc_assert (!params);
+ gcc_assert (!prototype_p (*node) || stdarg_p (*node));
+
+ return NULL_TREE;
+}
+
+/* Handle a "transaction_pure" attribute. */
+
+static tree
+handle_transaction_pure_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ /* Ensure we have a function type. */
+ gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
return NULL_TREE;
}
+/* Handle a "returns_twice" attribute. */
+
+static tree
+handle_returns_twice_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+
+ DECL_IS_RETURNS_TWICE (*node) = 1;
+
+ return NULL_TREE;
+}
+
+/* Ignore the given attribute. Used when this attribute may be usefully
+ overridden by the target, but is not used generically. */
+
+static tree
+ignore_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool *no_add_attrs)
+{
+ *no_add_attrs = true;
+ return NULL_TREE;
+}
+
/* Handle a "format" attribute; arguments as in
struct attribute_spec.handler. */
static void
def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...)
{
- tree args = NULL, t;
+ tree t;
+ tree *args = XALLOCAVEC (tree, n);
va_list list;
int i;
t = builtin_types[a];
if (t == error_mark_node)
goto egress;
- args = tree_cons (NULL_TREE, t, args);
+ args[i] = t;
}
va_end (list);
- args = nreverse (args);
- if (!var)
- args = chainon (args, void_list_node);
-
t = builtin_types[ret];
if (t == error_mark_node)
goto egress;
- t = build_function_type (t, args);
+ if (var)
+ t = build_varargs_function_type_array (t, n, args);
+ else
+ t = build_function_type_array (t, n, args);
egress:
builtin_types[def] = t;
+ va_end (list);
}
/* Used to help initialize the builtin-types.def table. When a type of
add_builtin_function (libname, libtype, fncode, fnclass,
NULL, fnattrs);
- built_in_decls[(int) fncode] = decl;
- if (implicit_p)
- implicit_built_in_decls[(int) fncode] = decl;
+ set_builtin_decl (fncode, decl, implicit_p);
}
static GTY(()) tree registered_builtin_types;
-/* A chain of builtin functions that we need to recognize. We will
- assume that all other function names we see will be defined by the
- user's program. */
-static GTY(()) tree registered_builtin_fndecls;
-
/* Language hooks. */
static unsigned int
-lto_init_options (unsigned int argc ATTRIBUTE_UNUSED,
- const char **argv ATTRIBUTE_UNUSED)
+lto_option_lang_mask (void)
{
- /* Always operate in unit-at-time mode so that we can defer
- decisions about what to output. */
- flag_unit_at_a_time = 1;
-
return CL_LTO;
}
+static bool
+lto_complain_wrong_lang_p (const struct cl_option *option ATTRIBUTE_UNUSED)
+{
+ /* The LTO front end inherits all the options from the first front
+ end that was used. However, not all the original front end
+ options make sense in LTO.
+
+ A real solution would be to filter this in collect2, but collect2
+ does not have access to all the option attributes to know what to
+ filter. So, in lto1 we silently accept inherited flags and do
+ nothing about it. */
+ return false;
+}
+
+static void
+lto_init_options_struct (struct gcc_options *opts)
+{
+ /* By default, C99-like requirements for complex multiply and divide.
+ ??? Until the complex method is encoded in the IL this is the only
+ safe choice. This will pessimize Fortran code with LTO unless
+ people specify a complex method manually or use -ffast-math. */
+ opts->x_flag_complex_method = 2;
+}
+
/* Handle command-line option SCODE. If the option takes an argument, it is
stored in ARG, which is otherwise NULL. VALUE holds either a numerical
argument or a binary value indicating whether the positive or negative form
of the option was supplied. */
const char *resolution_file_name;
-static int
-lto_handle_option (size_t scode, const char *arg, int value ATTRIBUTE_UNUSED)
+static bool
+lto_handle_option (size_t scode, const char *arg,
+ int value ATTRIBUTE_UNUSED, int kind ATTRIBUTE_UNUSED,
+ location_t loc ATTRIBUTE_UNUSED,
+ const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
{
enum opt_code code = (enum opt_code) scode;
- int result = 1;
+ bool result = true;
switch (code)
{
- case OPT_resolution:
+ case OPT_fresolution_:
resolution_file_name = arg;
- result = 1;
break;
case OPT_Wabi:
static bool
lto_post_options (const char **pfilename ATTRIBUTE_UNUSED)
{
- /* FIXME lto: We have stripped enough type and other
- debugging information out of the IR that it may
- appear ill-formed to dwarf2out, etc. We must not
- attempt to generate debug info in lto1. A more
- graceful solution would disable the option flags
- rather than ignoring them, but we'd also have to
- worry about default debugging options. */
- write_symbols = NO_DEBUG;
- debug_info_level = DINFO_LEVEL_NONE;
-
/* -fltrans and -fwpa are mutually exclusive. Check for that here. */
if (flag_wpa && flag_ltrans)
- error ("-fwpa and -fltrans are mutually exclusive.");
+ error ("-fwpa and -fltrans are mutually exclusive");
if (flag_ltrans)
{
support. */
flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
- lto_read_all_file_options ();
-
/* Initialize the compiler back end. */
return false;
}
return NULL_TREE;
}
-static int
-lto_global_bindings_p (void)
+/* Return true if we are in the global binding level. */
+
+static bool
+lto_global_bindings_p (void)
{
return cfun == NULL;
}
static tree
lto_getdecls (void)
{
- return registered_builtin_fndecls;
+ /* We have our own write_globals langhook, hence the getdecls
+ langhook shouldn't be used, except by dbxout.c, so we can't
+ just abort here. */
+ return NULL_TREE;
}
static void
static tree
lto_builtin_function (tree decl)
{
- /* Record it. */
- TREE_CHAIN (decl) = registered_builtin_fndecls;
- registered_builtin_fndecls = decl;
-
return decl;
}
uintmax_type_node = long_unsigned_type_node;
signed_size_type_node = long_integer_type_node;
}
+ else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0)
+ {
+ intmax_type_node = long_long_integer_type_node;
+ uintmax_type_node = long_long_unsigned_type_node;
+ signed_size_type_node = long_long_integer_type_node;
+ }
else
gcc_unreachable ();
pid_type_node = integer_type_node;
}
+/* Re-compute TYPE_CANONICAL for NODE and related types. */
+
+static void
+lto_register_canonical_types (tree node)
+{
+ if (!node
+ || !TYPE_P (node))
+ return;
+
+ TYPE_CANONICAL (node) = NULL_TREE;
+ TYPE_CANONICAL (node) = gimple_register_canonical_type (node);
+
+ if (POINTER_TYPE_P (node)
+ || TREE_CODE (node) == COMPLEX_TYPE
+ || TREE_CODE (node) == ARRAY_TYPE)
+ lto_register_canonical_types (TREE_TYPE (node));
+}
/* Perform LTO-specific initialization. */
static bool
lto_init (void)
{
+ unsigned i;
+
/* We need to generate LTO if running in WPA mode. */
flag_generate_lto = flag_wpa;
/* Initialize libcpp line maps for gcc_assert to work. */
- linemap_add (line_table, LC_RENAME, 0, NULL, 0);
- linemap_add (line_table, LC_RENAME, 0, NULL, 0);
+ linemap_add (line_table, LC_ENTER, 0, NULL, 0);
/* Create the basic integer types. */
- build_common_tree_nodes (flag_signed_char, /*signed_sizetype=*/false);
-
- /* Share char_type_node with whatever would be the default for the target.
- char_type_node will be used for internal types such as
- va_list_type_node but will not be present in the lto stream. */
- char_type_node
- = DEFAULT_SIGNED_CHAR ? signed_char_type_node : unsigned_char_type_node;
-
- /* Tell the middle end what type to use for the size of objects. */
- if (strcmp (SIZE_TYPE, "unsigned int") == 0)
- {
- set_sizetype (unsigned_type_node);
- size_type_node = unsigned_type_node;
- }
- else if (strcmp (SIZE_TYPE, "long unsigned int") == 0)
- {
- set_sizetype (long_unsigned_type_node);
- size_type_node = long_unsigned_type_node;
- }
- else
- gcc_unreachable ();
+ build_common_tree_nodes (flag_signed_char, /*short_double=*/false);
/* The global tree for the main identifier is filled in by
language-specific front-end initialization that is not run in the
distinction should only be relevant to the front-end, so we
always use the C definition here in lto1. */
gcc_assert (fileptr_type_node == ptr_type_node);
+ gcc_assert (TYPE_MAIN_VARIANT (fileptr_type_node) == ptr_type_node);
ptrdiff_type_node = integer_type_node;
- /* Create other basic types. */
- build_common_tree_nodes_2 (/*short_double=*/false);
lto_build_c_type_nodes ();
gcc_assert (va_list_type_node);
targetm.init_builtins ();
build_common_builtin_nodes ();
+ /* Assign names to the builtin types, otherwise they'll end up
+ as __unknown__ in debug info.
+ ??? We simply need to stop pre-seeding the streamer cache.
+ Below is modeled after from c-common.c:c_common_nodes_and_builtins */
+#define NAME_TYPE(t,n) \
+ if (t) \
+ TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, \
+ get_identifier (n), t)
+ NAME_TYPE (integer_type_node, "int");
+ NAME_TYPE (char_type_node, "char");
+ NAME_TYPE (long_integer_type_node, "long int");
+ NAME_TYPE (unsigned_type_node, "unsigned int");
+ NAME_TYPE (long_unsigned_type_node, "long unsigned int");
+ NAME_TYPE (long_long_integer_type_node, "long long int");
+ NAME_TYPE (long_long_unsigned_type_node, "long long unsigned int");
+ NAME_TYPE (short_integer_type_node, "short int");
+ NAME_TYPE (short_unsigned_type_node, "short unsigned int");
+ if (signed_char_type_node != char_type_node)
+ NAME_TYPE (signed_char_type_node, "signed char");
+ if (unsigned_char_type_node != char_type_node)
+ NAME_TYPE (unsigned_char_type_node, "unsigned char");
+ NAME_TYPE (float_type_node, "float");
+ NAME_TYPE (double_type_node, "double");
+ NAME_TYPE (long_double_type_node, "long double");
+ NAME_TYPE (void_type_node, "void");
+ NAME_TYPE (boolean_type_node, "bool");
+#undef NAME_TYPE
+
+ /* Register the common node types with the canonical type machinery so
+ we properly share alias-sets across languages and TUs. Do not
+ expose the common nodes as type merge target - those that should be
+ are already exposed so by pre-loading the LTO streamer caches. */
+ for (i = 0; i < itk_none; ++i)
+ lto_register_canonical_types (integer_types[i]);
+ /* The sizetypes are not used to access data so we do not need to
+ do anything about them. */
+ for (i = 0; i < TI_MAX; ++i)
+ lto_register_canonical_types (global_trees[i]);
+
/* Initialize LTO-specific data structures. */
lto_global_var_decls = VEC_alloc (tree, gc, 256);
in_lto_p = true;
#undef LANG_HOOKS_NAME
#define LANG_HOOKS_NAME "GNU GIMPLE"
-#undef LANG_HOOKS_INIT_OPTIONS
-#define LANG_HOOKS_INIT_OPTIONS lto_init_options
+#undef LANG_HOOKS_OPTION_LANG_MASK
+#define LANG_HOOKS_OPTION_LANG_MASK lto_option_lang_mask
+#undef LANG_HOOKS_COMPLAIN_WRONG_LANG_P
+#define LANG_HOOKS_COMPLAIN_WRONG_LANG_P lto_complain_wrong_lang_p
+#undef LANG_HOOKS_INIT_OPTIONS_STRUCT
+#define LANG_HOOKS_INIT_OPTIONS_STRUCT lto_init_options_struct
#undef LANG_HOOKS_HANDLE_OPTION
#define LANG_HOOKS_HANDLE_OPTION lto_handle_option
#undef LANG_HOOKS_POST_OPTIONS
#define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS true
#undef LANG_HOOKS_TYPES_COMPATIBLE_P
#define LANG_HOOKS_TYPES_COMPATIBLE_P NULL
+#undef LANG_HOOKS_EH_PERSONALITY
+#define LANG_HOOKS_EH_PERSONALITY lto_eh_personality
/* Attribute hooks. */
#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE lto_format_attribute_table
#undef LANG_HOOKS_BEGIN_SECTION
-#define LANG_HOOKS_BEGIN_SECTION lto_elf_begin_section
+#define LANG_HOOKS_BEGIN_SECTION lto_obj_begin_section
#undef LANG_HOOKS_APPEND_DATA
-#define LANG_HOOKS_APPEND_DATA lto_elf_append_data
+#define LANG_HOOKS_APPEND_DATA lto_obj_append_data
#undef LANG_HOOKS_END_SECTION
-#define LANG_HOOKS_END_SECTION lto_elf_end_section
+#define LANG_HOOKS_END_SECTION lto_obj_end_section
#undef LANG_HOOKS_INIT_TS
#define LANG_HOOKS_INIT_TS lto_init_ts