/* Language-dependent hooks for LTO.
- Copyright 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2009-2018 Free Software Foundation, Inc.
Contributed by CodeSourcery, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "flags.h"
-#include "tm.h"
-#include "tree.h"
#include "target.h"
+#include "function.h"
+#include "basic-block.h"
+#include "tree.h"
+#include "gimple.h"
+#include "stringpool.h"
+#include "diagnostic-core.h"
+#include "stor-layout.h"
#include "langhooks.h"
#include "langhooks-def.h"
#include "debug.h"
#include "lto-tree.h"
#include "lto.h"
-#include "tree-inline.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "toplev.h"
+#include "stringpool.h"
+#include "attribs.h"
static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
static tree handle_leaf_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 handle_patchable_function_entry_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_fnspec_attribute (tree *, tree, tree, int, bool *);
static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
+/* Helper to define attribute exclusions. */
+#define ATTR_EXCL(name, function, type, variable) \
+ { name, function, type, variable }
+
+/* Define attributes that are mutually exclusive with one another. */
+static const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
+{
+ ATTR_EXCL ("noreturn", true, true, true),
+ ATTR_EXCL ("alloc_align", true, true, true),
+ ATTR_EXCL ("alloc_size", true, true, true),
+ ATTR_EXCL ("const", true, true, true),
+ ATTR_EXCL ("malloc", true, true, true),
+ ATTR_EXCL ("pure", true, true, true),
+ ATTR_EXCL ("returns_twice", true, true, true),
+ ATTR_EXCL ("warn_unused_result", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
+{
+ ATTR_EXCL ("noreturn", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
+{
+ ATTR_EXCL ("const", true, true, true),
+ ATTR_EXCL ("noreturn", true, true, true),
+ ATTR_EXCL ("pure", true, true, true),
+ ATTR_EXCL (NULL, false, false, false)
+};
+
/* 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 } */
- { "noreturn", 0, 0, true, false, false,
- handle_noreturn_attribute },
- { "leaf", 0, 0, true, false, false,
- handle_leaf_attribute },
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+ affects_type_identity, handler, exclude } */
+ { "noreturn", 0, 0, true, false, false, false,
+ handle_noreturn_attribute,
+ attr_noreturn_exclusions },
+ { "leaf", 0, 0, true, false, false, false,
+ handle_leaf_attribute, NULL },
/* The same comments as for noreturn attributes apply to const ones. */
- { "const", 0, 0, true, false, false,
- handle_const_attribute },
- { "malloc", 0, 0, true, false, false,
- handle_malloc_attribute },
- { "pure", 0, 0, true, false, false,
- handle_pure_attribute },
- { "no vops", 0, 0, true, false, false,
- handle_novops_attribute },
- { "nonnull", 0, -1, false, true, true,
- handle_nonnull_attribute },
- { "nothrow", 0, 0, true, false, false,
- handle_nothrow_attribute },
- { "sentinel", 0, 1, false, true, true,
- handle_sentinel_attribute },
- { "type generic", 0, 0, false, true, true,
- handle_type_generic_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+ { "const", 0, 0, true, false, false, false,
+ handle_const_attribute,
+ attr_const_pure_exclusions },
+ { "malloc", 0, 0, true, false, false, false,
+ handle_malloc_attribute, NULL },
+ { "pure", 0, 0, true, false, false, false,
+ handle_pure_attribute,
+ attr_const_pure_exclusions },
+ { "no vops", 0, 0, true, false, false, false,
+ handle_novops_attribute, NULL },
+ { "nonnull", 0, -1, false, true, true, false,
+ handle_nonnull_attribute, NULL },
+ { "nothrow", 0, 0, true, false, false, false,
+ handle_nothrow_attribute, NULL },
+ { "patchable_function_entry", 1, 2, true, false, false, false,
+ handle_patchable_function_entry_attribute,
+ NULL },
+ { "returns_twice", 0, 0, true, false, false, false,
+ handle_returns_twice_attribute,
+ attr_returns_twice_exclusions },
+ { "sentinel", 0, 1, false, true, true, false,
+ handle_sentinel_attribute, NULL },
+ { "type generic", 0, 0, false, true, true, false,
+ handle_type_generic_attribute, NULL },
+ { "fn spec", 1, 1, false, true, true, false,
+ handle_fnspec_attribute, NULL },
+ { "transaction_pure", 0, 0, false, true, true, false,
+ handle_transaction_pure_attribute, NULL },
+ /* 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, false,
+ ignore_attribute, NULL },
+ { NULL, 0, 0, false, false, false, false, NULL, NULL }
};
/* 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 } */
- { "format", 3, 3, false, true, true,
- handle_format_attribute },
- { "format_arg", 1, 1, false, true, true,
- handle_format_arg_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+ affects_type_identity, handler, exclude } */
+ { "format", 3, 3, false, true, true, false,
+ handle_format_attribute, NULL },
+ { "format_arg", 1, 1, false, true, true, false,
+ handle_format_arg_attribute, NULL },
+ { NULL, 0, 0, false, false, false, false, NULL, NULL }
};
enum built_in_attribute
{
#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
+#define DEF_ATTR_STRING(ENUM, VALUE) ENUM,
#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
#include "builtin-attrs.def"
#undef DEF_ATTR_NULL_TREE
#undef DEF_ATTR_INT
+#undef DEF_ATTR_STRING
#undef DEF_ATTR_IDENT
#undef DEF_ATTR_TREE_LIST
ATTR_LAST
#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
-#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
-#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6) NAME,
+#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8) NAME,
+#define DEF_FUNCTION_TYPE_9(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9) NAME,
+#define DEF_FUNCTION_TYPE_10(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9, ARG10) NAME,
+#define DEF_FUNCTION_TYPE_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME,
#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \
- NAME,
+ NAME,
+#define DEF_FUNCTION_TYPE_VAR_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6) NAME,
+#define DEF_FUNCTION_TYPE_VAR_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7) NAME,
#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
#include "builtin-types.def"
#undef DEF_PRIMITIVE_TYPE
#undef DEF_FUNCTION_TYPE_5
#undef DEF_FUNCTION_TYPE_6
#undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
+#undef DEF_FUNCTION_TYPE_9
+#undef DEF_FUNCTION_TYPE_10
+#undef DEF_FUNCTION_TYPE_11
#undef DEF_FUNCTION_TYPE_VAR_0
#undef DEF_FUNCTION_TYPE_VAR_1
#undef DEF_FUNCTION_TYPE_VAR_2
#undef DEF_FUNCTION_TYPE_VAR_3
#undef DEF_FUNCTION_TYPE_VAR_4
#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_FUNCTION_TYPE_VAR_6
+#undef DEF_FUNCTION_TYPE_VAR_7
#undef DEF_POINTER_TYPE
BT_LAST
};
/* Flags needed to process builtins.def. */
int flag_isoc94;
int flag_isoc99;
+int flag_isoc11;
/* Attribute handlers. */
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
bool * ARG_UNUSED (no_add_attrs))
{
+ if (TREE_CODE (*node) != FUNCTION_DECL
+ || !DECL_BUILT_IN (*node))
+ inform (UNKNOWN_LOCATION, "%s:%s: %E: %E", __FILE__, __func__, *node, name);
+
tree type = TREE_TYPE (*node);
/* See FIXME comment on noreturn in c_common_attribute_table. */
get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
{
/* Verify the arg number is a constant. */
- if (TREE_CODE (arg_num_expr) != INTEGER_CST
- || TREE_INT_CST_HIGH (arg_num_expr) != 0)
+ if (!tree_fits_uhwi_p (arg_num_expr))
return false;
*valp = TREE_INT_CST_LOW (arg_num_expr);
/* 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. */
+ will have the correct types when we actually check them later.
+ Avoid diagnosing type-generic built-ins since those have no
+ prototype. */
if (!args)
{
- gcc_assert (TYPE_ARG_TYPES (type));
+ gcc_assert (prototype_p (type)
+ || !TYPE_ATTRIBUTES (type)
+ || lookup_attribute ("type generic", TYPE_ATTRIBUTES (type)));
+
return NULL_TREE;
}
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;
+}
+
+static tree
+handle_patchable_function_entry_attribute (tree *, tree, tree, int, bool *)
+{
+ /* Nothing to be done here. */
+ 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. */
}
+/* Handle a "fn spec" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
+ tree args, int ARG_UNUSED (flags),
+ bool *no_add_attrs ATTRIBUTE_UNUSED)
+{
+ gcc_assert (args
+ && TREE_CODE (TREE_VALUE (args)) == STRING_CST
+ && !TREE_CHAIN (args));
+ return NULL_TREE;
+}
+
/* Cribbed from c-common.c. */
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;
+ bool err = false;
va_start (list, n);
for (i = 0; i < n; ++i)
builtin_type a = (builtin_type) va_arg (list, int);
t = builtin_types[a];
if (t == error_mark_node)
- goto egress;
- args = tree_cons (NULL_TREE, t, args);
+ err = true;
+ args[i] = t;
}
va_end (list);
- args = nreverse (args);
- if (!var)
- args = chainon (args, void_list_node);
-
t = builtin_types[ret];
+ if (err)
+ t = error_mark_node;
if (t == error_mark_node)
- goto egress;
- t = build_function_type (t, args);
+ ;
+ else 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;
}
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);
}
built_in_attributes[(int) ENUM] = NULL_TREE;
#define DEF_ATTR_INT(ENUM, VALUE) \
built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE);
+#define DEF_ATTR_STRING(ENUM, VALUE) \
+ built_in_attributes[(int) ENUM] = build_string (strlen (VALUE), VALUE);
#define DEF_ATTR_IDENT(ENUM, STRING) \
built_in_attributes[(int) ENUM] = get_identifier (STRING);
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
#include "builtin-attrs.def"
#undef DEF_ATTR_NULL_TREE
#undef DEF_ATTR_INT
+#undef DEF_ATTR_STRING
#undef DEF_ATTR_IDENT
#undef DEF_ATTR_TREE_LIST
}
#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
ARG6, ARG7) \
def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8) \
+ def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+ ARG7, ARG8);
+#define DEF_FUNCTION_TYPE_9(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9) \
+ def_fn_type (ENUM, RETURN, 0, 9, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+ ARG7, ARG8, ARG9);
+#define DEF_FUNCTION_TYPE_10(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9, ARG10) \
+ def_fn_type (ENUM, RETURN, 0, 10, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+ ARG7, ARG8, ARG9, ARG10);
+#define DEF_FUNCTION_TYPE_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \
+ def_fn_type (ENUM, RETURN, 0, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+ ARG7, ARG8, ARG9, ARG10, ARG11);
#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
def_fn_type (ENUM, RETURN, 1, 0);
#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_FUNCTION_TYPE_VAR_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6) \
+ def_fn_type (ENUM, RETURN, 1, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+#define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7) \
+ def_fn_type (ENUM, RETURN, 1, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
#define DEF_POINTER_TYPE(ENUM, TYPE) \
builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]);
#include "builtin-types.def"
#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_0
#undef DEF_FUNCTION_TYPE_1
#undef DEF_FUNCTION_TYPE_2
#undef DEF_FUNCTION_TYPE_3
#undef DEF_FUNCTION_TYPE_4
#undef DEF_FUNCTION_TYPE_5
#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
+#undef DEF_FUNCTION_TYPE_9
+#undef DEF_FUNCTION_TYPE_10
+#undef DEF_FUNCTION_TYPE_11
#undef DEF_FUNCTION_TYPE_VAR_0
#undef DEF_FUNCTION_TYPE_VAR_1
#undef DEF_FUNCTION_TYPE_VAR_2
#undef DEF_FUNCTION_TYPE_VAR_3
#undef DEF_FUNCTION_TYPE_VAR_4
#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_FUNCTION_TYPE_VAR_6
+#undef DEF_FUNCTION_TYPE_VAR_7
#undef DEF_POINTER_TYPE
builtin_types[(int) BT_LAST] = NULL_TREE;
builtin_types[(int) LIBTYPE], BOTH_P, FALLBACK_P, \
NONANSI_P, built_in_attributes[(int) ATTRS], IMPLICIT);
#include "builtins.def"
-#undef DEF_BUILTIN
}
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
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;
warn_psabi = value;
break;
+ case OPT_fwpa:
+ flag_wpa = value ? "" : NULL;
+ break;
+
default:
break;
}
if (flag_wpa)
flag_generate_lto = 1;
- /* Excess precision other than "fast" requires front-end
- support. */
- flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
-
- lto_read_all_file_options ();
-
- /* Initialize the compiler back end. */
- return false;
-}
-
-/* Return an integer type with PRECISION bits of precision,
- that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
-
-static tree
-lto_type_for_size (unsigned precision, int unsignedp)
-{
- if (precision == TYPE_PRECISION (integer_type_node))
- return unsignedp ? unsigned_type_node : integer_type_node;
-
- if (precision == TYPE_PRECISION (signed_char_type_node))
- return unsignedp ? unsigned_char_type_node : signed_char_type_node;
-
- if (precision == TYPE_PRECISION (short_integer_type_node))
- return unsignedp ? short_unsigned_type_node : short_integer_type_node;
-
- if (precision == TYPE_PRECISION (long_integer_type_node))
- return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+ /* Initialize the codegen flags according to the output type. */
+ switch (flag_lto_linker_output)
+ {
+ case LTO_LINKER_OUTPUT_REL: /* .o: incremental link producing LTO IL */
+ flag_whole_program = 0;
+ flag_incremental_link = 1;
+ break;
- if (precision == TYPE_PRECISION (long_long_integer_type_node))
- return unsignedp
- ? long_long_unsigned_type_node
- : long_long_integer_type_node;
+ case LTO_LINKER_OUTPUT_DYN: /* .so: PID library */
+ /* On some targets, like i386 it makes sense to build PIC library wihout
+ -fpic for performance reasons. So no need to adjust flags. */
+ break;
- if (precision <= TYPE_PRECISION (intQI_type_node))
- return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+ case LTO_LINKER_OUTPUT_PIE: /* PIE binary */
+ /* If -fPIC or -fPIE was used at compile time, be sure that
+ flag_pie is 2. */
+ flag_pie = MAX (flag_pie, flag_pic);
+ flag_pic = flag_pie;
+ flag_shlib = 0;
+ break;
- if (precision <= TYPE_PRECISION (intHI_type_node))
- return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
+ case LTO_LINKER_OUTPUT_EXEC: /* Normal executable */
+ flag_pic = 0;
+ flag_pie = 0;
+ flag_shlib = 0;
+ break;
- if (precision <= TYPE_PRECISION (intSI_type_node))
- return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
+ case LTO_LINKER_OUTPUT_UNKNOWN:
+ break;
+ }
- if (precision <= TYPE_PRECISION (intDI_type_node))
- return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+ /* Excess precision other than "fast" requires front-end
+ support. */
+ flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
- if (precision <= TYPE_PRECISION (intTI_type_node))
- return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
+ /* When partitioning, we can tear appart STRING_CSTs uses from the same
+ TU into multiple partitions. Without constant merging the constants
+ might not be equal at runtime. See PR50199. */
+ if (!flag_merge_constants)
+ flag_merge_constants = 1;
- return NULL_TREE;
+ /* Initialize the compiler back end. */
+ return false;
}
-
/* Return a data type that has machine mode MODE.
If the mode is an integer,
then UNSIGNEDP selects between signed and unsigned types.
then UNSIGNEDP selects between saturating and nonsaturating types. */
static tree
-lto_type_for_mode (enum machine_mode mode, int unsigned_p)
+lto_type_for_mode (machine_mode mode, int unsigned_p)
{
tree t;
+ int i;
if (mode == TYPE_MODE (integer_type_node))
return unsigned_p ? unsigned_type_node : integer_type_node;
if (mode == TYPE_MODE (long_long_integer_type_node))
return unsigned_p ? long_long_unsigned_type_node : long_long_integer_type_node;
+ for (i = 0; i < NUM_INT_N_ENTS; i ++)
+ if (int_n_enabled_p[i]
+ && mode == int_n_data[i].m)
+ return (unsigned_p ? int_n_trees[i].unsigned_type
+ : int_n_trees[i].signed_type);
+
if (mode == QImode)
return unsigned_p ? unsigned_intQI_type_node : intQI_type_node;
if (mode == TYPE_MODE (void_type_node))
return void_type_node;
- if (mode == TYPE_MODE (build_pointer_type (char_type_node)))
- return (unsigned_p
- ? make_unsigned_type (GET_MODE_PRECISION (mode))
- : make_signed_type (GET_MODE_PRECISION (mode)));
-
- if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
- return (unsigned_p
- ? make_unsigned_type (GET_MODE_PRECISION (mode))
- : make_signed_type (GET_MODE_PRECISION (mode)));
+ if (mode == TYPE_MODE (build_pointer_type (char_type_node))
+ || mode == TYPE_MODE (build_pointer_type (integer_type_node)))
+ {
+ unsigned int precision
+ = GET_MODE_PRECISION (as_a <scalar_int_mode> (mode));
+ return (unsigned_p
+ ? make_unsigned_type (precision)
+ : make_signed_type (precision));
+ }
if (COMPLEX_MODE_P (mode))
{
- enum machine_mode inner_mode;
+ machine_mode inner_mode;
tree inner_type;
if (mode == TYPE_MODE (complex_float_type_node))
if (inner_type != NULL_TREE)
return build_complex_type (inner_type);
}
- else if (VECTOR_MODE_P (mode))
+ else if (VECTOR_MODE_P (mode)
+ && valid_vector_subparts_p (GET_MODE_NUNITS (mode)))
{
- enum machine_mode inner_mode = GET_MODE_INNER (mode);
+ machine_mode inner_mode = GET_MODE_INNER (mode);
tree inner_type = lto_type_for_mode (inner_mode, unsigned_p);
if (inner_type != NULL_TREE)
return build_vector_type_for_mode (inner_type, mode);
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;
-}
-
-static void
-lto_write_globals (void)
-{
- tree *vec = VEC_address (tree, lto_global_var_decls);
- int len = VEC_length (tree, lto_global_var_decls);
- wrapup_global_declarations (vec, len);
- emit_debug_global_declarations (vec, len);
- VEC_free (tree, gc, lto_global_var_decls);
+ /* 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 tree
lto_builtin_function (tree decl)
{
- /* Record it. */
- TREE_CHAIN (decl) = registered_builtin_fndecls;
- registered_builtin_fndecls = decl;
-
return decl;
}
{
tree decl;
- decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL, get_identifier (name), type);
- DECL_ARTIFICIAL (decl) = 1;
if (!TYPE_NAME (type))
- TYPE_NAME (type) = decl;
+ {
+ decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL,
+ get_identifier (name), type);
+ DECL_ARTIFICIAL (decl) = 1;
+ TYPE_NAME (type) = decl;
+ }
registered_builtin_types = tree_cons (0, type, registered_builtin_types);
}
signed_size_type_node = long_long_integer_type_node;
}
else
- gcc_unreachable ();
+ {
+ int i;
+
+ signed_size_type_node = NULL_TREE;
+ for (i = 0; i < NUM_INT_N_ENTS; i++)
+ if (int_n_enabled_p[i])
+ {
+ char name[50];
+ sprintf (name, "__int%d unsigned", int_n_data[i].bitsize);
+
+ if (strcmp (name, SIZE_TYPE) == 0)
+ {
+ intmax_type_node = int_n_trees[i].signed_type;
+ uintmax_type_node = int_n_trees[i].unsigned_type;
+ signed_size_type_node = int_n_trees[i].signed_type;
+ }
+ }
+ if (signed_size_type_node == NULL_TREE)
+ gcc_unreachable ();
+ }
wint_type_node = unsigned_type_node;
pid_type_node = integer_type_node;
}
-
/* Perform LTO-specific initialization. */
static bool
lto_init (void)
{
- /* We need to generate LTO if running in WPA mode. */
- flag_generate_lto = flag_wpa;
+ int i;
- /* 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);
+ /* Initialize LTO-specific data structures. */
+ in_lto_p = true;
+
+ /* We need to generate LTO if running in WPA mode. */
+ flag_generate_lto = (flag_wpa != NULL);
/* Create the basic integer types. */
build_common_tree_nodes (flag_signed_char);
- /* 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. */
- /* ??? This breaks the more common case of consistent but non-standard
- setting of flag_signed_char, so share according to flag_signed_char.
- See PR42528. */
- char_type_node
- = flag_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 if (strcmp (SIZE_TYPE, "long long unsigned int") == 0)
- {
- set_sizetype (long_long_unsigned_type_node);
- size_type_node = long_long_unsigned_type_node;
- }
- else
- gcc_unreachable ();
-
/* The global tree for the main identifier is filled in by
language-specific front-end initialization that is not run in the
LTO back-end. It appears that all languages that perform such
main_identifier_node = get_identifier ("main");
/* In the C++ front-end, fileptr_type_node is defined as a variant
- copy of of ptr_type_node, rather than ptr_node itself. The
+ copy of ptr_type_node, rather than ptr_node itself. 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);
-
- ptrdiff_type_node = integer_type_node;
+ always use the C definition here in lto1.
+ Likewise for const struct tm*. */
+ for (unsigned i = 0;
+ i < sizeof (builtin_structptr_types) / sizeof (builtin_structptr_type);
+ ++i)
+ {
+ gcc_assert (builtin_structptr_types[i].node
+ == builtin_structptr_types[i].base);
+ gcc_assert (TYPE_MAIN_VARIANT (builtin_structptr_types[i].node)
+ == builtin_structptr_types[i].base);
+ }
- /* Create other basic types. */
- build_common_tree_nodes_2 (/*short_double=*/false);
lto_build_c_type_nodes ();
gcc_assert (va_list_type_node);
}
else
{
- lto_define_builtins (va_list_type_node,
- build_reference_type (va_list_type_node));
+ lto_define_builtins (build_reference_type (va_list_type_node),
+ va_list_type_node);
}
targetm.init_builtins ();
build_common_builtin_nodes ();
- /* Initialize LTO-specific data structures. */
- lto_global_var_decls = VEC_alloc (tree, gc, 256);
- in_lto_p = true;
+ /* 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");
+ NAME_TYPE (complex_float_type_node, "complex float");
+ NAME_TYPE (complex_double_type_node, "complex double");
+ NAME_TYPE (complex_long_double_type_node, "complex long double");
+ for (i = 0; i < NUM_INT_N_ENTS; i++)
+ if (int_n_enabled_p[i])
+ {
+ char name[50];
+ sprintf (name, "__int%d", int_n_data[i].bitsize);
+ NAME_TYPE (int_n_trees[i].signed_type, name);
+ }
+#undef NAME_TYPE
return true;
}
#define LANG_HOOKS_GET_ALIAS_SET gimple_get_alias_set
#undef LANG_HOOKS_TYPE_FOR_MODE
#define LANG_HOOKS_TYPE_FOR_MODE lto_type_for_mode
-#undef LANG_HOOKS_TYPE_FOR_SIZE
-#define LANG_HOOKS_TYPE_FOR_SIZE lto_type_for_size
#undef LANG_HOOKS_SET_DECL_ASSEMBLER_NAME
#define LANG_HOOKS_SET_DECL_ASSEMBLER_NAME lto_set_decl_assembler_name
#undef LANG_HOOKS_GLOBAL_BINDINGS_P
#define LANG_HOOKS_PUSHDECL lto_pushdecl
#undef LANG_HOOKS_GETDECLS
#define LANG_HOOKS_GETDECLS lto_getdecls
-#undef LANG_HOOKS_WRITE_GLOBALS
-#define LANG_HOOKS_WRITE_GLOBALS lto_write_globals
#undef LANG_HOOKS_REGISTER_BUILTIN_TYPE
#define LANG_HOOKS_REGISTER_BUILTIN_TYPE lto_register_builtin_type
#undef LANG_HOOKS_BUILTIN_FUNCTION
#define LANG_HOOKS_INIT lto_init
#undef LANG_HOOKS_PARSE_FILE
#define LANG_HOOKS_PARSE_FILE lto_main
-#undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION
-#define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION tree_rest_of_compilation
#undef LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS
#define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS true
#undef LANG_HOOKS_TYPES_COMPATIBLE_P
return TS_LTO_GENERIC;
}
-#include "ggc.h"
#include "gtype-lto.h"
#include "gt-lto-lto-lang.h"