Index: java/lang.c =================================================================== --- java/lang.c (revision 150526) +++ java/lang.c (working copy) @@ -161,7 +161,7 @@ struct GTY(()) language_function { #define LANG_HOOKS_ATTRIBUTE_TABLE java_attribute_table /* Each front end provides its own. */ -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* * process java-specific compiler command-line options Index: tree.c =================================================================== --- tree.c (revision 150526) +++ tree.c (working copy) @@ -52,6 +52,13 @@ along with GCC; see the file COPYING3. #include "params.h" #include "pointer-set.h" #include "fixed-value.h" +#include "tree-pass.h" +#include "langhooks-def.h" +#include "diagnostic.h" +#include "cgraph.h" +#include "timevar.h" +#include "except.h" +#include "debug.h" /* Tree code classes. */ @@ -4112,6 +4119,734 @@ build_type_attribute_variant (tree ttype TYPE_QUALS (ttype)); } +/* Reset all language specific information still present in TYPE. */ + +static void +free_lang_data_in_type (tree type) +{ + gcc_assert (TYPE_P (type)); + + /* Give the FE a chance to remove its own data first. */ + lang_hooks.free_lang_data (type); + + TREE_LANG_FLAG_0 (type) = 0; + TREE_LANG_FLAG_1 (type) = 0; + TREE_LANG_FLAG_2 (type) = 0; + TREE_LANG_FLAG_3 (type) = 0; + TREE_LANG_FLAG_4 (type) = 0; + TREE_LANG_FLAG_5 (type) = 0; + TREE_LANG_FLAG_6 (type) = 0; + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + /* Remove the const and volatile qualifiers from arguments. The + C++ front end removes them, but the C front end does not, + leading to false ODR violation errors when merging two + instances of the same function signature compiled by + different front ends. */ + tree p; + + for (p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p)) + { + tree arg_type = TREE_VALUE (p); + + if (TYPE_READONLY (arg_type) || TYPE_VOLATILE (arg_type)) + { + int quals = TYPE_QUALS (arg_type) + & ~TYPE_QUAL_CONST + & ~TYPE_QUAL_VOLATILE; + TREE_VALUE (p) = build_qualified_type (arg_type, quals); + free_lang_data_in_type (TREE_VALUE (p)); + } + } + } + + /* Remove members that are not actually FIELD_DECLs from the field + list of an aggregate. These occur in C++. */ + if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + { + tree prev, member; + + /* Note that TYPE_FIELDS can be shared across distinct + TREE_TYPEs. Therefore, if the first field of TYPE_FIELDS is + to be removed, we cannot set its TREE_CHAIN to NULL. + Otherwise, we would not be able to find all the other fields + in the other instances of this TREE_TYPE. + + This was causing an ICE in testsuite/g++.dg/lto/20080915.C. + + FIXME lto, long term we should probably convert TYPE_FIELDS + and TYPE_METHODS to a proper container like TREE_LIST or a + VEC (though this would increase memory utilization). */ + prev = NULL_TREE; + member = TYPE_FIELDS (type); + while (member) + { + if (TREE_CODE (member) == FIELD_DECL) + { + if (prev) + TREE_CHAIN (prev) = member; + else + TYPE_FIELDS (type) = member; + prev = member; + } + + member = TREE_CHAIN (member); + } + + if (prev) + TREE_CHAIN (prev) = NULL_TREE; + else + TYPE_FIELDS (type) = NULL_TREE; + + TYPE_METHODS (type) = NULL_TREE; + TYPE_BINFO (type) = NULL_TREE; + } + + /* Overloads TYPE_BINFO for non-record, non-union types. */ + if (TREE_CODE (type) != RECORD_TYPE && TREE_CODE (type) != UNION_TYPE) + TYPE_LANG_SLOT_1 (type) = NULL_TREE; + + /* Clear TYPE_CONTEXT, which reflects source-language + scoping and should not be part of the IR. + FIXME lto: This will break debug info generation. */ + TYPE_CONTEXT (type) = NULL_TREE; + + /* FIXME lto: This will break debug info generation. */ + TYPE_STUB_DECL (type) = NULL_TREE; + + /* Remove type variants other than the main variant. This is both + wasteful and it may introduce infinite loops when the types are + read from disk and merged (since the variant will be the same + type as the main variant, traversing type variants will get into + an infinite loop). */ + if (TYPE_MAIN_VARIANT (type)) + TYPE_NEXT_VARIANT (TYPE_MAIN_VARIANT (type)) = NULL_TREE; + + TYPE_NEXT_VARIANT (type) = NULL_TREE; +} + + +/* Return true if DECL may need an assembler name to be set. */ + +static inline bool +need_assembler_name_p (tree decl) +{ + /* Only FUNCTION_DECLs and VAR_DECLs are considered. */ + if (TREE_CODE (decl) != FUNCTION_DECL + && TREE_CODE (decl) != VAR_DECL) + return false; + + /* If DECL already has its assembler name set, it does not need a new one. */ + if (!HAS_DECL_ASSEMBLER_NAME_P (decl) + || DECL_ASSEMBLER_NAME_SET_P (decl)) + return false; + + /* For VAR_DECLs, we are only interested in static, public and external + declarations. */ + if (TREE_CODE (decl) == VAR_DECL + && !TREE_STATIC (decl) + && !TREE_PUBLIC (decl) + && !DECL_EXTERNAL (decl)) + return false; + + /* For FUNCTION_DECLs, we only are interested in builtins, + addressable and used functions. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && !TREE_USED (decl) + && !TREE_ADDRESSABLE (decl) + && !DECL_BUILT_IN (decl)) + return false; + + return true; +} + + +/* Remove all the non-variable decls from BLOCK. LOCALS is the set of + variables in DECL_STRUCT_FUNCTION (FN)->local_decls. Every decl + in BLOCK that is not in LOCALS is removed. */ + +static void +free_lang_data_in_block (tree fn, tree block, struct pointer_set_t *locals) +{ + tree *tp, t; + + tp = &BLOCK_VARS (block); + while (*tp) + { + if (!pointer_set_contains (locals, *tp)) + *tp = TREE_CHAIN (*tp); + else + tp = &TREE_CHAIN (*tp); + } + + for (t = BLOCK_SUBBLOCKS (block); t; t = BLOCK_CHAIN (t)) + free_lang_data_in_block (fn, t, locals); +} + + +/* Reset all language specific information still present in symbol + DECL. */ + +static void +free_lang_data_in_decl (tree decl) +{ + gcc_assert (DECL_P (decl)); + + /* Give the FE a chance to remove its own data first. */ + lang_hooks.free_lang_data (decl); + + TREE_LANG_FLAG_0 (decl) = 0; + TREE_LANG_FLAG_1 (decl) = 0; + TREE_LANG_FLAG_2 (decl) = 0; + TREE_LANG_FLAG_3 (decl) = 0; + TREE_LANG_FLAG_4 (decl) = 0; + TREE_LANG_FLAG_5 (decl) = 0; + TREE_LANG_FLAG_6 (decl) = 0; + + /* Identifiers need not have a type. */ + if (DECL_NAME (decl)) + TREE_TYPE (DECL_NAME (decl)) = NULL_TREE; + + if (TREE_CODE (decl) == CONST_DECL) + DECL_CONTEXT (decl) = NULL_TREE; + + /* Ignore any intervening types, because we are going to clear their + TYPE_CONTEXT fields. */ + if (TREE_CODE (decl) != FIELD_DECL) + DECL_CONTEXT (decl) = decl_function_context (decl); + + if (DECL_CONTEXT (decl) + && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL) + DECL_CONTEXT (decl) = NULL_TREE; + + if (TREE_CODE (decl) == VAR_DECL) + { + tree context = DECL_CONTEXT (decl); + + if (context) + { + enum tree_code code = TREE_CODE (context); + if (code == FUNCTION_DECL && DECL_ABSTRACT (context)) + { + /* Do not clear the decl context here, that will promote + all vars to global ones. */ + DECL_INITIAL (decl) = NULL_TREE; + } + + if (TREE_STATIC (decl)) + DECL_CONTEXT (decl) = NULL_TREE; + } + } + + if (TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == FIELD_DECL + || TREE_CODE (decl) == RESULT_DECL) + { + tree unit_size = DECL_SIZE_UNIT (decl); + tree size = DECL_SIZE (decl); + if ((unit_size && TREE_CODE (unit_size) != INTEGER_CST) + || (size && TREE_CODE (size) != INTEGER_CST)) + { + DECL_SIZE_UNIT (decl) = NULL_TREE; + DECL_SIZE (decl) = NULL_TREE; + } + + if (TREE_CODE (decl) == FIELD_DECL + && DECL_FIELD_OFFSET (decl) + && TREE_CODE (DECL_FIELD_OFFSET (decl)) != INTEGER_CST) + DECL_FIELD_OFFSET (decl) = NULL_TREE; + } + else if (TREE_CODE (decl) == FUNCTION_DECL) + { + /* A weakref to an external function is DECL_EXTERNAL but not + TREE_PUBLIC. */ + if (DECL_EXTERNAL (decl) + && !lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))) + TREE_PUBLIC (decl) = true; + + if (gimple_has_body_p (decl)) + { + tree t; + struct pointer_set_t *locals; + + /* If DECL has a gimple body, then the context for its + arguments must be DECL. Otherwise, it doesn't really + matter, as we will not be emitting any code for DECL. In + general, there may be other instances of DECL created by + the front end and since PARM_DECLs are generally shared, + their DECL_CONTEXT changes as the replicas of DECL are + created. The only time where DECL_CONTEXT is important + is for the FUNCTION_DECLs that have a gimple body (since + the PARM_DECL will be used in the function's body). */ + for (t = DECL_ARGUMENTS (decl); t; t = TREE_CHAIN (t)) + DECL_CONTEXT (t) = decl; + + /* Collect all the symbols declared in DECL. */ + locals = pointer_set_create (); + t = DECL_STRUCT_FUNCTION (decl)->local_decls; + for (; t; t = TREE_CHAIN (t)) + { + pointer_set_insert (locals, TREE_VALUE (t)); + + /* All the local symbols should have DECL as their + context. */ + DECL_CONTEXT (TREE_VALUE (t)) = decl; + } + + /* Get rid of any decl not in local_decls. */ + free_lang_data_in_block (decl, DECL_INITIAL (decl), locals); + + pointer_set_destroy (locals); + } + + /* DECL_SAVED_TREE holds the GENERIC representation for DECL. + At this point, it is not needed anymore. */ + DECL_SAVED_TREE (decl) = NULL_TREE; + } + else if (TREE_CODE (decl) == VAR_DECL) + { + tree expr = DECL_DEBUG_EXPR (decl); + if (expr + && TREE_CODE (expr) == VAR_DECL + && !TREE_STATIC (expr) && !DECL_EXTERNAL (expr)) + SET_DECL_DEBUG_EXPR (decl, NULL_TREE); + + if (DECL_EXTERNAL (decl)) + DECL_INITIAL (decl) = NULL_TREE; + } + else if (TREE_CODE (decl) == TYPE_DECL) + { + /* FIXME lto: + DECL_INITIAL should not be defined here, but it is + overloaded by the C++ front-end as DECL_FRIENDLIST. + We should probably call out to FE-specific cleanup + routines to handle this sort of thing. */ + DECL_INITIAL (decl) = NULL_TREE; + + /* DECL_CONTEXT is overloaded as DECL_FIELD_CONTEXT for + FIELD_DECLs, which should be preserved. Otherwise, + we shouldn't be concerned with source-level lexical + nesting beyond this point. */ + /* FIXME lto: Unfortunately, calls to decl_function_context + may occur in the back-end and depend on the DECL_CONTEXT + being set for FUNCTION_DECL and possibly others. + See also the use of DECL_CONTEXT of FUNCTION_DECL + in cgraph_node. */ + DECL_CONTEXT (decl) = NULL_TREE; + } +} + + +/* Data used when collecting DECLs and TYPEs for language data removal. */ + +struct free_lang_data_d +{ + /* Set of traversed objects. Used to avoid duplicate visits. */ + struct pointer_set_t *pset; + + /* Array of symbols to process with free_lang_data_in_decl. */ + VEC(tree,heap) *decls; + + /* Array of types to process with free_lang_data_in_type. */ + VEC(tree,heap) *types; +}; + + +/* Operand callback helper for free_lang_data_in_node. *TP is the + subtree operand being considered. */ + +static tree +find_decls_types_r (tree *tp, int *ws ATTRIBUTE_UNUSED, void *data) +{ + tree t = *tp; + struct free_lang_data_d *fld = (struct free_lang_data_d *) data; + + if (DECL_P (t)) + { + /* Note that walk_tree does not traverse every possible field in + decls, so we have to do our own traversals here. */ + VEC_safe_push (tree, heap, fld->decls, t); + + walk_tree (&DECL_NAME (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_CONTEXT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_SIZE (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_SIZE_UNIT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_INITIAL (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_ATTRIBUTES (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_ABSTRACT_ORIGIN (t), find_decls_types_r, fld, fld->pset); + + if (TREE_CODE (t) == FUNCTION_DECL) + { + walk_tree (&DECL_ARGUMENTS (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_RESULT (t), find_decls_types_r, fld, fld->pset); + } + else if (TREE_CODE (t) == TYPE_DECL) + { + walk_tree (&DECL_ARGUMENT_FLD (t), find_decls_types_r, fld, + fld->pset); + walk_tree (&DECL_VINDEX (t), find_decls_types_r, fld, fld->pset); + } + else if (TREE_CODE (t) == FIELD_DECL) + { + walk_tree (&DECL_FIELD_OFFSET (t), find_decls_types_r, fld, + fld->pset); + walk_tree (&DECL_BIT_FIELD_TYPE (t), find_decls_types_r, fld, + fld->pset); + walk_tree (&DECL_QUALIFIER (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_FIELD_BIT_OFFSET (t), find_decls_types_r, fld, + fld->pset); + walk_tree (&DECL_FCONTEXT (t), find_decls_types_r, fld, fld->pset); + } + else if (TREE_CODE (t) == VAR_DECL) + { + walk_tree (&DECL_SECTION_NAME (t), find_decls_types_r, fld, + fld->pset); + walk_tree (&DECL_COMDAT_GROUP (t), find_decls_types_r, fld, + fld->pset); + } + } + else if (TYPE_P (t)) + { + /* Note that walk_tree does not traverse every possible field in + types, so we have to do our own traversals here. */ + VEC_safe_push (tree, heap, fld->types, t); + + walk_tree (&TYPE_CACHED_VALUES (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_SIZE (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_SIZE_UNIT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_ATTRIBUTES (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_POINTER_TO (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_REFERENCE_TO (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_NAME (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_MINVAL (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_MAXVAL (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_NEXT_VARIANT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_MAIN_VARIANT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_CONTEXT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_CANONICAL (t), find_decls_types_r, fld, fld->pset); + } + + if (TREE_TYPE (t)) + walk_tree (&TREE_TYPE (t), find_decls_types_r, fld, fld->pset); + + /* Do not recurse into TREE_CHAIN to avoid blowing up the stack. */ + for (tp = &TREE_CHAIN (t); *tp; tp = &TREE_CHAIN (*tp)) + { + tree saved_chain = TREE_CHAIN (*tp); + TREE_CHAIN (*tp) = NULL_TREE; + walk_tree (tp, find_decls_types_r, fld, fld->pset); + TREE_CHAIN (*tp) = saved_chain; + } + + return NULL_TREE; +} + + +/* Translate all the types in LIST with the corresponding runtime + types. */ + +static tree +get_eh_types_for_runtime (tree list) +{ + tree head, prev; + + if (list == NULL_TREE) + return NULL_TREE; + + head = build_tree_list (0, lookup_type_for_runtime (TREE_VALUE (list))); + prev = head; + list = TREE_CHAIN (list); + while (list) + { + tree n = build_tree_list (0, lookup_type_for_runtime (TREE_VALUE (list))); + TREE_CHAIN (prev) = n; + prev = TREE_CHAIN (prev); + list = TREE_CHAIN (list); + } + + return head; +} + + +/* Find decls and types referenced in EH region R and store them in + FLD->DECLS and FLD->TYPES. */ + +static void +find_decls_types_in_eh_region (eh_region r, struct free_lang_data_d *fld) +{ + if (r == NULL) + return; + + /* The types referenced in R must first be changed to the EH types + used at runtime. This removes references to FE types in the + region. */ + if (r->type == ERT_CATCH) + { + tree list = r->u.eh_catch.type_list; + r->u.eh_catch.type_list = get_eh_types_for_runtime (list); + walk_tree (&r->u.eh_catch.type_list, find_decls_types_r, fld, fld->pset); + } + else if (r->type == ERT_ALLOWED_EXCEPTIONS) + { + tree list = r->u.allowed.type_list; + r->u.allowed.type_list = get_eh_types_for_runtime (list); + walk_tree (&r->u.allowed.type_list, find_decls_types_r, fld, fld->pset); + } +} + + +/* Find decls and types referenced in cgraph node N and store them in + FLD->DECLS and FLD->TYPES. Unlike pass_referenced_vars, this will + look for *every* kind of DECL and TYPE node reachable from N, + including those embedded inside types and decls (i.e,, TYPE_DECLs, + NAMESPACE_DECLs, etc). */ + +static void +find_decls_types_in_node (struct cgraph_node *n, struct free_lang_data_d *fld) +{ + basic_block bb; + struct function *fn; + tree t; + + /* Although free_lang_data_in_cgraph will set the assembler name on + most DECLs, it refuses to do it on unused ones. For cgraph + nodes, we need to set it even if it's seemingly unused. */ + if (!DECL_ASSEMBLER_NAME_SET_P (n->decl)) + lang_hooks.set_decl_assembler_name (n->decl); + + walk_tree (&n->decl, find_decls_types_r, fld, fld->pset); + + if (!gimple_has_body_p (n->decl)) + return; + + gcc_assert (current_function_decl == NULL_TREE && cfun == NULL); + + fn = DECL_STRUCT_FUNCTION (n->decl); + + /* Traverse locals. */ + for (t = fn->local_decls; t; t = TREE_CHAIN (t)) + { + tree *tp = &TREE_VALUE (t); + tree saved_chain = TREE_CHAIN (*tp); + TREE_CHAIN (*tp) = NULL_TREE; + walk_tree (tp, find_decls_types_r, fld, fld->pset); + TREE_CHAIN (*tp) = saved_chain; + } + + /* Traverse EH regions in FN. */ + if (fn->eh->region_array) + { + unsigned i; + eh_region r; + + for (i = 0; VEC_iterate (eh_region, fn->eh->region_array, i, r); i++) + find_decls_types_in_eh_region (r, fld); + } + + /* Traverse every statement in FN. */ + FOR_EACH_BB_FN (bb, fn) + { + gimple_stmt_iterator si; + unsigned i; + + for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) + { + gimple phi = gsi_stmt (si); + + for (i = 0; i < gimple_phi_num_args (phi); i++) + { + tree *arg_p = gimple_phi_arg_def_ptr (phi, i); + walk_tree (arg_p, find_decls_types_r, fld, fld->pset); + } + } + + for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si)) + { + gimple stmt = gsi_stmt (si); + + for (i = 0; i < gimple_num_ops (stmt); i++) + { + tree *arg_p = gimple_op_ptr (stmt, i); + walk_tree (arg_p, find_decls_types_r, fld, fld->pset); + } + } + } +} + + +/* Find decls and types referenced in varpool node N and store them in + FLD->DECLS and FLD->TYPES. Unlike pass_referenced_vars, this will + look for *every* kind of DECL and TYPE node reachable from N, + including those embedded inside types and decls (i.e,, TYPE_DECLs, + NAMESPACE_DECLs, etc). */ + +static void +find_decls_types_in_var (struct varpool_node *v, struct free_lang_data_d *fld) +{ + walk_tree (&v->decl, find_decls_types_r, fld, fld->pset); +} + + +/* Free language specific information for every operand and expression + in every node of the call graph. This process operates in three stages: + + 1- Every callgraph node and varpool node is traversed looking for + decls and types embedded in them. This is a more exhaustive + search than that done by find_referenced_vars, because it will + also collect individual fields, decls embedded in types, etc. + + 2- All the decls found are sent to free_lang_data_in_decl. + + 3- All the types found are sent to free_lang_data_in_type. + + The ordering between decls and types is important because + free_lang_data_in_decl sets assembler names, which includes + mangling. So types cannot be freed up until assembler names have + been set up. */ + +static void +free_lang_data_in_cgraph (void) +{ + struct cgraph_node *n; + struct varpool_node *v; + struct free_lang_data_d fld; + tree t; + unsigned i; + alias_pair *p; + + /* Initialize sets and arrays to store referenced decls and types. */ + fld.pset = pointer_set_create (); + fld.decls = VEC_alloc (tree, heap, 100); + fld.types = VEC_alloc (tree, heap, 100); + + /* Find decls and types in the body of every function in the callgraph. */ + for (n = cgraph_nodes; n; n = n->next) + find_decls_types_in_node (n, &fld); + + for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++) + walk_tree (&p->decl, find_decls_types_r, &fld, fld.pset); + + /* Find decls and types in every varpool symbol. */ + for (v = varpool_nodes_queue; v; v = v->next_needed) + find_decls_types_in_var (v, &fld); + + /* Set the assembler name on every decl found. We need to do this + now because free_lang_data_in_decl will invalidate data needed + for mangling. This breaks mangling on interdependent decls. */ + for (i = 0; VEC_iterate (tree, fld.decls, i, t); i++) + if (need_assembler_name_p (t)) + lang_hooks.set_decl_assembler_name (t); + + /* Traverse every decl found freeing its language data. */ + for (i = 0; VEC_iterate (tree, fld.decls, i, t); i++) + free_lang_data_in_decl (t); + + /* Traverse every type found freeing its language data. */ + for (i = 0; VEC_iterate (tree, fld.types, i, t); i++) + free_lang_data_in_type (t); + + pointer_set_destroy (fld.pset); + VEC_free (tree, heap, fld.decls); + VEC_free (tree, heap, fld.types); +} + + +/* Free resources that are used by FE but are not needed once they are done. */ + +static unsigned +free_lang_data (void) +{ + /* Traverse the IL resetting language specific information for + operands, expressions, etc. */ + free_lang_data_in_cgraph (); + + /* FIXME lto. This is a hack. ptrdiff_type_node is only created + by the C/C++ FE. This should be converted to some similar + type shared by all FEs (i.e., converted to a "GIMPLE type"). */ + ptrdiff_type_node = integer_type_node; + + /* FIXME lto. This is a hack. fileptr_type_node may be set to + a variant copy of ptr_type_node for front-end purposes. */ + fileptr_type_node = ptr_type_node; + + /* FIXME lto. This is a hack. boolean_type_node is set to + a frontend-specific mode by Fortran and Java at least. */ + if (TREE_CODE (boolean_type_node) != BOOLEAN_TYPE + || (TYPE_MODE (boolean_type_node) + != mode_for_size (BOOL_TYPE_SIZE, MODE_INT, 0)) + || TYPE_PRECISION (boolean_type_node) != 1 + || !TYPE_UNSIGNED (boolean_type_node)) + { + boolean_type_node = make_unsigned_type (BOOL_TYPE_SIZE); + TREE_SET_CODE (boolean_type_node, BOOLEAN_TYPE); + TYPE_MAX_VALUE (boolean_type_node) = build_int_cst (boolean_type_node, 1); + TYPE_PRECISION (boolean_type_node) = 1; + boolean_false_node = TYPE_MIN_VALUE (boolean_type_node); + boolean_true_node = TYPE_MAX_VALUE (boolean_type_node); + } + + /* Reset some langhooks. */ + lang_hooks.callgraph.analyze_expr = NULL; + lang_hooks.types_compatible_p = gimple_types_compatible_p; + lang_hooks.expr_size = lhd_expr_size; + + /* FIXME lto: We have to compute these names early. */ + lang_hooks.dwarf_name = lhd_dwarf_name; + lang_hooks.decl_printable_name = lhd_decl_printable_name; + + /* FIXME lto: Ideally we would like to abort at any attempt to compute + an assemble name, but there are too many places in gcc that create + new decls. */ + lang_hooks.set_decl_assembler_name = lhd_set_decl_assembler_name; + + /* FIXME lto: We should implement a diagnostic machinery for GIMPLE + that can unmangle symbols and types. For now, the default hooks + work but will not be able to print C++ symbols. */ + diagnostic_initialize (global_dc); + diagnostic_format_decoder (global_dc) = default_tree_printer; + + /* FIXME lto: We remove sufficient language data that the debug + info writer gets completely confused. Disable debug information + for now. */ + debug_info_level = DINFO_LEVEL_NONE; + write_symbols = NO_DEBUG; + debug_hooks = &do_nothing_debug_hooks; + + return 0; +} + + +/* Gate function for free_lang_data. */ + +static bool +gate_free_lang_data (void) +{ + return true; +} + + +struct simple_ipa_opt_pass pass_ipa_free_lang_data = +{ + { + SIMPLE_IPA_PASS, + NULL, /* name */ + gate_free_lang_data, /* gate */ + free_lang_data, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_IPA_FREE_LANG_DATA, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ + } +}; + /* Return nonzero if IDENT is a valid name for attribute ATTR, or zero if not. Index: tree.h =================================================================== --- tree.h (revision 150526) +++ tree.h (working copy) @@ -183,6 +183,22 @@ DEF_VEC_P(tree); DEF_VEC_ALLOC_P(tree,gc); DEF_VEC_ALLOC_P(tree,heap); +/* We have to be able to tell cgraph about the needed-ness of the target + of an alias. This requires that the decl have been defined. Aliases + that precede their definition have to be queued for later processing. */ + +typedef struct GTY(()) alias_pair +{ + tree decl; + tree target; +} alias_pair; + +/* Define gc'd vector type. */ +DEF_VEC_O(alias_pair); +DEF_VEC_ALLOC_O(alias_pair,gc); + +extern GTY(()) VEC(alias_pair,gc) * alias_pairs; + /* Classify which part of the compiler has defined a given builtin function. Note that we assume below that this is no more than two bits. */ @@ -1259,7 +1275,7 @@ extern void omp_clause_range_check_faile This is interesting in an inline function, since it might not need to be compiled separately. Nonzero in a RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE or ENUMERAL_TYPE - if the sdb debugging info for the type has been written. + if the debugging info for the type has been written. In a BLOCK node, nonzero if reorder_blocks has already seen this block. In an SSA_NAME node, nonzero if the SSA_NAME occurs in an abnormal PHI node. */ @@ -2032,6 +2048,8 @@ struct GTY(()) tree_block { #define TYPE_NEXT_VARIANT(NODE) (TYPE_CHECK (NODE)->type.next_variant) #define TYPE_MAIN_VARIANT(NODE) (TYPE_CHECK (NODE)->type.main_variant) #define TYPE_CONTEXT(NODE) (TYPE_CHECK (NODE)->type.context) +#define TYPE_MAXVAL(NODE) (TYPE_CHECK (NODE)->type.maxval) +#define TYPE_MINVAL(NODE) (TYPE_CHECK (NODE)->type.minval) /* Vector types need to check target flags to determine type. */ extern enum machine_mode vector_type_mode (const_tree); @@ -2436,9 +2454,9 @@ struct function; /* For FIELD_DECLs, this is the RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE node that the field is a member of. For VAR_DECL, - PARM_DECL, FUNCTION_DECL, LABEL_DECL, and CONST_DECL nodes, this - points to either the FUNCTION_DECL for the containing function, - the RECORD_TYPE or UNION_TYPE for the containing type, or + PARM_DECL, FUNCTION_DECL, LABEL_DECL, RESULT_DECL, and CONST_DECL + nodes, this points to either the FUNCTION_DECL for the containing + function, the RECORD_TYPE or UNION_TYPE for the containing type, or NULL_TREE or a TRANSLATION_UNIT_DECL if the given decl has "file scope". */ #define DECL_CONTEXT(NODE) (DECL_MINIMAL_CHECK (NODE)->decl_minimal.context) @@ -4881,6 +4899,7 @@ extern hashval_t iterative_hash_exprs_co const_tree, hashval_t); extern hashval_t iterative_hash_host_wide_int (HOST_WIDE_INT, hashval_t); extern hashval_t iterative_hash_hashval_t (hashval_t, hashval_t); +extern hashval_t iterative_hash_host_wide_int (HOST_WIDE_INT, hashval_t); extern int compare_tree_int (const_tree, unsigned HOST_WIDE_INT); extern int type_list_equal (const_tree, const_tree); extern int chain_member (const_tree, const_tree); @@ -5039,6 +5058,7 @@ extern void process_pending_assemble_ext extern void finish_aliases_1 (void); extern void finish_aliases_2 (void); extern tree emutls_decl (tree); +extern void remove_unreachable_alias_pairs (void); /* In stmt.c */ extern void expand_computed_goto (tree); Index: tree-pass.h =================================================================== --- tree-pass.h (revision 150526) +++ tree-pass.h (working copy) @@ -409,6 +409,7 @@ extern struct gimple_opt_pass pass_warn_ /* IPA Passes */ extern struct ipa_opt_pass_d pass_ipa_inline; +extern struct simple_ipa_opt_pass pass_ipa_free_lang_data; extern struct ipa_opt_pass_d pass_ipa_cp; extern struct ipa_opt_pass_d pass_ipa_reference; extern struct ipa_opt_pass_d pass_ipa_pure_const; Index: diagnostic.h =================================================================== --- diagnostic.h (revision 150526) +++ diagnostic.h (working copy) @@ -239,4 +239,8 @@ extern void print_gimple_stmt (FILE *, g extern void print_gimple_expr (FILE *, gimple, int, int); extern void dump_gimple_stmt (pretty_printer *, gimple, int, int); +/* In toplev.c */ +extern bool default_tree_printer (pretty_printer *, text_info *, const char *, + int, bool, bool, bool); + #endif /* ! GCC_DIAGNOSTIC_H */ Index: objc/objc-lang.c =================================================================== --- objc/objc-lang.c (revision 150526) +++ objc/objc-lang.c (working copy) @@ -52,7 +52,7 @@ static void objc_init_ts (void); #define LANG_HOOKS_INIT_TS objc_init_ts /* Each front end provides its own lang hook initializer. */ -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* Lang hook routines common to C and ObjC appear in c-objc-common.c; there should be very few (if any) routines below. */ Index: toplev.c =================================================================== --- toplev.c (revision 150526) +++ toplev.c (working copy) @@ -1564,8 +1564,8 @@ default_pch_valid_p (const void *data_p, } /* Default tree printer. Handles declarations only. */ -static bool -default_tree_printer (pretty_printer * pp, text_info *text, const char *spec, +bool +default_tree_printer (pretty_printer *pp, text_info *text, const char *spec, int precision, bool wide, bool set_locus, bool hash) { tree t; Index: objcp/objcp-lang.c =================================================================== --- objcp/objcp-lang.c (revision 150526) +++ objcp/objcp-lang.c (working copy) @@ -52,7 +52,7 @@ static void objcxx_init_ts (void); #define LANG_HOOKS_INIT_TS objcxx_init_ts /* Each front end provides its own lang hook initializer. */ -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* Lang hook routines common to C++ and ObjC++ appear in cp/cp-objcp-common.c; there should be very few (if any) routines below. */ Index: cp/tree.c =================================================================== --- cp/tree.c (revision 150526) +++ cp/tree.c (working copy) @@ -3025,6 +3025,61 @@ cast_valid_in_integral_constant_expressi || type == error_mark_node); } +/* Return true if we need to fix linkage information of DECL. */ + +static bool +cp_fix_function_decl_p (tree decl) +{ + /* Skip if DECL is not externally visible. */ + if (!TREE_PUBLIC (decl)) + return false; + + /* We need to fix DECL if it a appears to be exported but with no + function body. Thunks do not have CFGs and we may need to + handle them specially later. */ + if (!gimple_has_body_p (decl) + && !DECL_THUNK_P (decl) + && !DECL_EXTERNAL (decl)) + return true; + + return false; +} + +/* Clean the C++ specific parts of the tree T. */ + +void +cp_free_lang_data (tree t) +{ + if (TREE_CODE (t) == METHOD_TYPE + || TREE_CODE (t) == FUNCTION_TYPE) + { + /* Default args are not interesting anymore. */ + tree argtypes = TYPE_ARG_TYPES (t); + while (argtypes) + { + TREE_PURPOSE (argtypes) = 0; + argtypes = TREE_CHAIN (argtypes); + } + } + else if (TREE_CODE (t) == TYPE_DECL) + { + tree template_info; + + /* Remove context information held in templated decls. */ + if (mangle_decl_is_template_id (t, &template_info)) + DECL_CONTEXT (TREE_PURPOSE (template_info)) = NULL_TREE; + } + else if (TREE_CODE (t) == FUNCTION_DECL + && cp_fix_function_decl_p (t)) + { + /* If T is used in this translation unit at all, the definition + must exist somewhere else since we have decided to not emit it + in this TU. So make it an external reference. */ + DECL_EXTERNAL (t) = 1; + TREE_STATIC (t) = 0; + } +} + #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007) /* Complain that some language-specific thing hanging off a tree Index: cp/cp-lang.c =================================================================== --- cp/cp-lang.c (revision 150526) +++ cp/cp-lang.c (working copy) @@ -53,13 +53,17 @@ static enum classify_record cp_classify_ #define LANG_HOOKS_DECL_PRINTABLE_NAME cxx_printable_name #undef LANG_HOOKS_DWARF_NAME #define LANG_HOOKS_DWARF_NAME cxx_dwarf_name -#undef LANG_HOOKS_FOLD_OBJ_TYPE_REF -#define LANG_HOOKS_FOLD_OBJ_TYPE_REF cp_fold_obj_type_ref + +/* FIXME lto: disabled so we can clear TYPE_BINFO. + See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38178. */ +/* #undef LANG_HOOKS_FOLD_OBJ_TYPE_REF */ +/* #define LANG_HOOKS_FOLD_OBJ_TYPE_REF cp_fold_obj_type_ref */ + #undef LANG_HOOKS_INIT_TS #define LANG_HOOKS_INIT_TS cp_init_ts /* Each front end provides its own lang hook initializer. */ -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* Lang hook routines common to C++ and ObjC++ appear in cp/cp-objcp-common.c; there should be very few routines below. */ Index: cp/semantics.c =================================================================== --- cp/semantics.c (revision 150526) +++ cp/semantics.c (working copy) @@ -3239,6 +3239,7 @@ expand_or_defer_fn (tree fn) /* We don't want to process FN again, so pretend we've written it out, even though we haven't. */ TREE_ASM_WRITTEN (fn) = 1; + DECL_SAVED_TREE (fn) = NULL_TREE; return; } Index: cp/cp-objcp-common.h =================================================================== --- cp/cp-objcp-common.h (revision 150526) +++ cp/cp-objcp-common.h (working copy) @@ -32,6 +32,8 @@ extern bool cp_function_decl_explicit_p specific to C++ or ObjC++ go in cp/cp-lang.c and objcp/objcp-lang.c, respectively. */ +#undef LANG_HOOKS_FREE_LANG_DATA +#define LANG_HOOKS_FREE_LANG_DATA cp_free_lang_data #undef LANG_HOOKS_TREE_SIZE #define LANG_HOOKS_TREE_SIZE cp_tree_size #undef LANG_HOOKS_FINISH Index: cp/mangle.c =================================================================== --- cp/mangle.c (revision 150526) +++ cp/mangle.c (working copy) @@ -282,6 +282,8 @@ decl_is_template_id (const tree decl, tr /* Check if this is a primary template. */ if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_USE_TEMPLATE (decl) + && TREE_CODE (DECL_TI_TEMPLATE (decl)) != OVERLOAD + && TREE_CODE (DECL_TI_TEMPLATE (decl)) != IDENTIFIER_NODE && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)) && TREE_CODE (decl) != TEMPLATE_DECL) { @@ -3130,6 +3132,15 @@ mangle_ref_init_variable (const tree var write_name (variable, /*ignore_local_scope=*/0); return finish_mangling_get_identifier (/*warn=*/false); } + +/* Return true if decl is templated, along with the associated template info + node. TEMPLATE_INFO may be null. */ + +int +mangle_decl_is_template_id (const tree decl, tree* const template_info) +{ + return decl_is_template_id (decl, template_info); +} /* Foreign language type mangling section. */ Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 150526) +++ cp/cp-tree.h (working copy) @@ -4881,6 +4881,7 @@ extern tree finish_decltype_type extern tree finish_trait_expr (enum cp_trait_kind, tree, tree); /* in tree.c */ +void cp_free_lang_data (tree t); extern tree force_target_expr (tree, tree); extern tree build_target_expr_with_type (tree, tree); extern void lang_check_failed (const char *, int, @@ -5111,6 +5112,7 @@ extern tree mangle_thunk (tree, int, t extern tree mangle_conv_op_name_for_type (tree); extern tree mangle_guard_variable (tree); extern tree mangle_ref_init_variable (tree); +extern int mangle_decl_is_template_id (const tree, tree* const); /* in dump.c */ extern bool cp_dump_tree (void *, tree); Index: timevar.def =================================================================== --- timevar.def (revision 150526) +++ timevar.def (working copy) @@ -46,6 +46,7 @@ DEFTIMEVAR (TV_IPA_REFERENCE , " DEFTIMEVAR (TV_IPA_PURE_CONST , "ipa pure const") DEFTIMEVAR (TV_IPA_TYPE_ESCAPE , "ipa type escape") DEFTIMEVAR (TV_IPA_PTA , "ipa points-to") +DEFTIMEVAR (TV_IPA_FREE_LANG_DATA , "ipa free lang data") /* Time spent by constructing CFG. */ DEFTIMEVAR (TV_CFG , "cfg construction") /* Time spent by cleaning up CFG. */ Index: fortran/f95-lang.c =================================================================== --- fortran/f95-lang.c (revision 150526) +++ fortran/f95-lang.c (working copy) @@ -156,7 +156,7 @@ static void gfc_init_ts (void); #define LANG_HOOKS_BUILTIN_FUNCTION gfc_builtin_function #define LANG_HOOKS_GET_ARRAY_DESCR_INFO gfc_get_array_descr_info -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; #define NULL_BINDING_LEVEL (struct binding_level *) NULL Index: langhooks.h =================================================================== --- langhooks.h (revision 150526) +++ langhooks.h (working copy) @@ -228,6 +228,9 @@ struct lang_hooks identifier nodes long enough for the language-specific slots. */ size_t identifier_size; + /* Remove any parts of the tree that are used only by the FE. */ + void (*free_lang_data) (tree); + /* Determines the size of any language-specific tcc_constant or tcc_exceptional nodes. Since it is called from make_node, the only information available is the tree code. Expected to die @@ -412,7 +415,7 @@ struct lang_hooks }; /* Each front end provides its own. */ -extern const struct lang_hooks lang_hooks; +extern struct lang_hooks lang_hooks; extern tree add_builtin_function (const char *name, tree type, int function_code, enum built_in_class cl, const char *library_name, Index: ipa.c =================================================================== --- ipa.c (revision 150526) +++ ipa.c (working copy) @@ -240,6 +240,11 @@ cgraph_remove_unreachable_nodes (bool be #ifdef ENABLE_CHECKING verify_cgraph (); #endif + + /* Reclaim alias pairs for functions that have disappeared from the + call graph. */ + remove_unreachable_alias_pairs (); + return changed; } Index: except.c =================================================================== --- except.c (revision 150526) +++ except.c (working copy) @@ -1688,6 +1688,10 @@ add_type_for_runtime (tree type) { tree *slot; + /* If TYPE is NOP_EXPR, it means that it already is a runtime type. */ + if (TREE_CODE (type) == NOP_EXPR) + return; + slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type, TREE_HASH (type), INSERT); if (*slot == NULL) @@ -1702,6 +1706,10 @@ lookup_type_for_runtime (tree type) { tree *slot; + /* If TYPE is NOP_EXPR, it means that it already is a runtime type. */ + if (TREE_CODE (type) == NOP_EXPR) + return type; + slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type, TREE_HASH (type), NO_INSERT); @@ -2880,8 +2888,33 @@ check_handled (tree handled, tree type) if (! lang_eh_type_covers) { for (t = handled; t ; t = TREE_CHAIN (t)) - if (TREE_VALUE (t) == type) - return 1; + { + tree t1 = TREE_VALUE (t); + tree t2 = type; + + /* If the types have been converted to runtime types (i.e., + when the IL is being read from disk in an LTO + compilation), then T1 and T2 will be pointers to the + runtime type of the form '(void *) &' (See + cp/except.c:build_eh_type_type). Strip the conversion + and the address. */ + if (CONVERT_EXPR_P (t1)) + { + STRIP_NOPS (t1); + gcc_assert (TREE_CODE (t1) == ADDR_EXPR); + t1 = TREE_OPERAND (t1, 0); + } + + if (CONVERT_EXPR_P (t2)) + { + STRIP_NOPS (t2); + gcc_assert (TREE_CODE (t2) == ADDR_EXPR); + t2 = TREE_OPERAND (t2, 0); + } + + if (t1 == t2) + return 1; + } } else { @@ -4159,7 +4192,14 @@ output_ttype (tree type, int tt_format, { struct varpool_node *node; - type = lookup_type_for_runtime (type); + /* FIXME lto. During LTO compiles, pass_ipa_free_lang_data + changes all types to runtime types so TYPE should already be + a runtime type reference. When pass_ipa_free_lang data is + made a default pass, we can then remove the call to + lookup_type_for_runtime below. */ + if (TYPE_P (type)) + type = lookup_type_for_runtime (type); + value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER); /* Let cgraph know that the rtti decl is used. Not all of the Index: varasm.c =================================================================== --- varasm.c (revision 150526) +++ varasm.c (working copy) @@ -5369,20 +5369,7 @@ globalize_decl (tree decl) targetm.asm_out.globalize_decl_name (asm_out_file, decl); } -/* We have to be able to tell cgraph about the needed-ness of the target - of an alias. This requires that the decl have been defined. Aliases - that precede their definition have to be queued for later processing. */ - -typedef struct GTY(()) alias_pair { - tree decl; - tree target; -} alias_pair; - -/* Define gc'd vector type. */ -DEF_VEC_O(alias_pair); -DEF_VEC_ALLOC_O(alias_pair,gc); - -static GTY(()) VEC(alias_pair,gc) *alias_pairs; +VEC(alias_pair,gc) *alias_pairs; /* Given an assembly name, find the decl it is associated with. At the same time, mark it needed for cgraph. */ @@ -5526,6 +5513,39 @@ do_assemble_alias (tree decl, tree targe #endif } + +/* Remove the alias pairing for functions that are no longer in the call + graph. */ + +void +remove_unreachable_alias_pairs (void) +{ + unsigned i; + alias_pair *p; + + if (alias_pairs == NULL) + return; + + for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ) + { + if (!DECL_EXTERNAL (p->decl)) + { + struct cgraph_node *fnode = NULL; + struct varpool_node *vnode = NULL; + fnode = cgraph_node_for_asm (p->target); + vnode = (fnode == NULL) ? varpool_node_for_asm (p->target) : NULL; + if (fnode == NULL && vnode == NULL) + { + VEC_unordered_remove (alias_pair, alias_pairs, i); + continue; + } + } + + i++; + } +} + + /* First pass of completing pending aliases. Make sure that cgraph knows which symbols will be required. */ Index: gimple.c =================================================================== --- gimple.c (revision 150526) +++ gimple.c (working copy) @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. #include "system.h" #include "coretypes.h" #include "tm.h" +#include "target.h" #include "tree.h" #include "ggc.h" #include "hard-reg-set.h" @@ -33,6 +34,14 @@ along with GCC; see the file COPYING3. #include "tree-flow.h" #include "value-prof.h" #include "flags.h" +#include "alias.h" + +/* Global type table. FIXME lto, it should be possible to re-use some + of the type hashing routines in tree.c (type_hash_canon, type_hash_lookup, + etc), but those assume that types were built with the various + build_*_type routines which is not the case with the streamer. */ +static htab_t gimple_types; +static struct pointer_map_t *type_hash_cache; #define DEFGSCODE(SYM, NAME, STRUCT) NAME, const char *const gimple_code_name[] = { @@ -135,7 +144,7 @@ gss_for_code (enum gimple_code code) /* Return the number of bytes needed to hold a GIMPLE statement with code CODE. */ -static size_t +size_t gimple_size (enum gimple_code code) { enum gimple_statement_structure_enum gss = gss_for_code (code); @@ -191,6 +200,8 @@ gimple_size (enum gimple_code code) return sizeof (struct gimple_statement_wce); case GIMPLE_PREDICT: return sizeof (struct gimple_statement_base); + case GIMPLE_PHI: + return sizeof (struct gimple_statement_phi); default: break; } @@ -202,8 +213,7 @@ gimple_size (enum gimple_code code) /* Allocate memory for a GIMPLE statement with code CODE and NUM_OPS operands. */ -#define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO) -static gimple +gimple gimple_alloc_stat (enum gimple_code code, unsigned num_ops MEM_STAT_DECL) { size_t size; @@ -3070,6 +3080,1021 @@ gimple_call_copy_skip_args (gimple stmt, } +/* Structure used to maintain a cache of some type pairs compared by + gimple_compare_types when comparing aggregate types. There are + four possible values for SAME_P: + + -2: The pair (T1, T2) has just been inserted in the table. + -1: The pair (T1, T2) is currently being compared. + 0: T1 and T2 are different types. + 1: T1 and T2 are the same type. + + This table is only used when comparing aggregate types to avoid + infinite recursion due to self-referential types. */ +struct type_pair_d +{ + tree t1; + tree t2; + int same_p; +}; +typedef struct type_pair_d *type_pair_t; + +/* Return a hash value for the type pair pointed-to by P. */ + +static hashval_t +type_pair_hash (const void *p) +{ + const struct type_pair_d *pair = (const struct type_pair_d *) p; + hashval_t val = iterative_hash_hashval_t (htab_hash_pointer (pair->t1), 0); + return iterative_hash_hashval_t (htab_hash_pointer (pair->t2), val); +} + +/* Compare two type pairs pointed-to by P1 and P2. */ + +static int +type_pair_eq (const void *p1, const void *p2) +{ + const struct type_pair_d *pair1 = (const struct type_pair_d *) p1; + const struct type_pair_d *pair2 = (const struct type_pair_d *) p2; + return (pair1->t1 == pair2->t1 && pair1->t2 == pair2->t2); +} + + +/* Lookup the pair of types T1 and T2 in *VISITED_P. Insert a new + entry if none existed. */ + +static type_pair_t +lookup_type_pair (tree t1, tree t2, htab_t *visited_p) +{ + struct type_pair_d pair; + type_pair_t p; + void **slot; + + if (*visited_p == NULL) + *visited_p = htab_create (13, type_pair_hash, type_pair_eq, free); + + pair.t1 = t1; + pair.t2 = t2; + pair.same_p = -2; + slot = htab_find_slot (*visited_p, &pair, INSERT); + + if (*slot) + p = *((type_pair_t *) slot); + else + { + p = XCNEW (struct type_pair_d); + p->t1 = t1; + p->t2 = t2; + p->same_p = -2; + *slot = (void *) p; + } + + return p; +} + + +/* Return true if both types have the same name. */ + +static bool +compare_type_names_p (tree t1, tree t2) +{ + tree variant1 = TYPE_MAIN_VARIANT (t1); + tree variant2 = TYPE_MAIN_VARIANT (t2); + tree name1 = TYPE_NAME (t1); + tree name2 = TYPE_NAME (t2); + + /* Consider anonymous types all unique. */ + if (!name1 || !name2) + return false; + + if (TREE_CODE (name1) == TYPE_DECL) + { + name1 = DECL_NAME (name1); + if (!name1) + return false; + } + gcc_assert (TREE_CODE (name1) == IDENTIFIER_NODE); + + if (TREE_CODE (name2) == TYPE_DECL) + { + name2 = DECL_NAME (name2); + if (!name2) + return false; + } + gcc_assert (TREE_CODE (name2) == IDENTIFIER_NODE); + + /* Identifiers can be compared with pointer equality rather + than a string comparison. */ + if (name1 == name2) + return true; + + /* If either type has a variant type, compare that. This finds + the case where a struct is typedef'ed in one module but referred + to as 'struct foo' in the other; here, the main type for one is + 'foo', and for the other 'foo_t', but the variants have the same + name 'foo'. */ + if (variant1 != t1 || variant2 != t2) + return compare_type_names_p (variant1, variant2); + + return false; +} + +/* Recursive helper for gimple_types_compatible_p. Return 1 iff T1 + and T2 are structurally identical. Otherwise, return 0. + VISITED_P points to a hash table of type pairs that have been + visited while comparing aggregate types. This prevents infinite + recursion when comparing aggregates with self-referential fields. */ + +static int +gimple_compare_types (tree t1, tree t2, htab_t *visited_p) +{ + type_pair_t p = NULL; + + /* Check first for the obvious case of pointer identity. */ + if (t1 == t2) + goto same_types; + + /* Check that we have two types to compare. */ + if (t1 == NULL_TREE || t2 == NULL_TREE) + goto different_types; + + /* Can't be the same type if the types don't have the same code. */ + if (TREE_CODE (t1) != TREE_CODE (t2)) + goto different_types; + + /* Void types are always the same. */ + if (TREE_CODE (t1) == VOID_TYPE) + goto same_types; + + /* Can't be the same type if they have different CV qualifiers. */ + if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) + goto different_types; + + /* If we've visited this type pair before (in the case of aggregates + with self-referntial types), and we made a decision, return it. */ + p = lookup_type_pair (t1, t2, visited_p); + if (p->same_p == 0 || p->same_p == 1) + { + /* We have already decided whether T1 and T2 are the + same, return the cached result. */ + return p->same_p == 1; + } + else if (p->same_p == -1) + { + /* We are currently comparing this pair of types, assume + that they are the same and let the caller decide. */ + return 1; + } + + gcc_assert (p->same_p == -2); + + /* If their attributes are not the same they can't be the same type. */ + if (!attribute_list_equal (TYPE_ATTRIBUTES (t1), TYPE_ATTRIBUTES (t2))) + goto different_types; + + if (!targetm.comp_type_attributes (t1, t2)) + goto different_types; + + /* For numerical types, the bounds must coincide. */ + if (INTEGRAL_TYPE_P (t1) + || SCALAR_FLOAT_TYPE_P (t1) + || FIXED_POINT_TYPE_P (t1)) + { + /* Can't be the same type if they have different size, alignment, + sign, precision or mode. Note that from now on, comparisons + between *_CST nodes must be done using tree_int_cst_equal because + we cannot assume that constants from T1 and T2 will be shared + since T1 and T2 are distinct pointers. */ + if (!tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)) + || !tree_int_cst_equal (TYPE_SIZE_UNIT (t1), TYPE_SIZE_UNIT (t2)) + || TYPE_ALIGN (t1) != TYPE_ALIGN (t2) + || TYPE_PRECISION (t1) != TYPE_PRECISION (t2) + || TYPE_MODE (t1) != TYPE_MODE (t2) + || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)) + goto different_types; + + /* For non-enumeral types, check type bounds. FIXME lto, we + cannot check bounds on enumeral types because different front + ends will produce different values. In C, enumeral types are + integers, while in C++ each element will have its own + symbolic value. We should decide how enums are to be + represented in GIMPLE and have each front end lower to that. */ + if (TREE_CODE (t1) != ENUMERAL_TYPE) + { + tree min1 = TYPE_MIN_VALUE (t1); + tree max1 = TYPE_MAX_VALUE (t1); + tree min2 = TYPE_MIN_VALUE (t2); + tree max2 = TYPE_MAX_VALUE (t2); + bool min_equal_p = false; + bool max_equal_p = false; + + /* If either type has a minimum value, the other type must + have the same. */ + if (min1 == NULL_TREE && min2 == NULL_TREE) + min_equal_p = true; + else if (min1 && min2 && operand_equal_p (min1, min2, 0)) + min_equal_p = true; + + /* Likewise, if either type has a maximum value, the other + type must have the same. */ + if (max1 == NULL_TREE && max2 == NULL_TREE) + max_equal_p = true; + else if (max1 && max2 && operand_equal_p (max1, max2, 0)) + max_equal_p = true; + + if (!min_equal_p || !max_equal_p) + goto different_types; + } + + if (TREE_CODE (t1) == INTEGER_TYPE) + { + if (TYPE_IS_SIZETYPE (t1) == TYPE_IS_SIZETYPE (t2) + && TYPE_STRING_FLAG (t1) == TYPE_STRING_FLAG (t2)) + goto same_types; + else + goto different_types; + } + else if (TREE_CODE (t1) == BOOLEAN_TYPE) + goto same_types; + else if (TREE_CODE (t1) == REAL_TYPE) + goto same_types; + } + + /* Do type-specific comparisons. */ + switch (TREE_CODE (t1)) + { + case ARRAY_TYPE: + /* Array types are the same if the element types are the same and + the number of elements are the same. */ + if (!gimple_compare_types (TREE_TYPE (t1), TREE_TYPE (t2), visited_p) + || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2)) + goto different_types; + else + { + tree i1 = TYPE_DOMAIN (t1); + tree i2 = TYPE_DOMAIN (t2); + + /* For an incomplete external array, the type domain can be + NULL_TREE. Check this condition also. */ + if (i1 == NULL_TREE && i2 == NULL_TREE) + goto same_types; + else if (i1 == NULL_TREE || i2 == NULL_TREE) + goto different_types; + else + { + tree min1 = TYPE_MIN_VALUE (i1); + tree min2 = TYPE_MIN_VALUE (i2); + tree max1 = TYPE_MAX_VALUE (i1); + tree max2 = TYPE_MAX_VALUE (i2); + bool min_equal_p = false; + bool max_equal_p = false; + + /* For variable-sized arrays, use the same notion as in the C + front end. If either domain is variable, consider the types + compatible. */ + if (min1 == NULL_TREE && min2 == NULL_TREE) + min_equal_p = true; + else if (min1 && TREE_CODE (min1) != INTEGER_CST) + min_equal_p = true; + else if (min2 && TREE_CODE (min2) != INTEGER_CST) + min_equal_p = true; + else if (min1 && min2 && operand_equal_p (min1, min2, 0)) + min_equal_p = true; + + if (max1 == NULL_TREE && max2 == NULL_TREE) + max_equal_p = true; + else if (max1 && TREE_CODE (max1) != INTEGER_CST) + max_equal_p = true; + else if (max2 && TREE_CODE (max2) != INTEGER_CST) + max_equal_p = true; + else if (max1 && max2 && operand_equal_p (max1, max2, 0)) + max_equal_p = true; + + if (min_equal_p && max_equal_p) + goto same_types; + else + goto different_types; + } + } + + case METHOD_TYPE: + /* Method types should belong to the same class. */ + if (!gimple_compare_types (TYPE_METHOD_BASETYPE (t1), + TYPE_METHOD_BASETYPE (t2), + visited_p)) + goto different_types; + + /* Fallthru */ + + case FUNCTION_TYPE: + /* Function types are the same if the return type and arguments types + are the same. */ + if (!gimple_compare_types (TREE_TYPE (t1), TREE_TYPE (t2), visited_p)) + goto different_types; + else + { + if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2)) + goto same_types; + else + { + tree parms1, parms2; + + for (parms1 = TYPE_ARG_TYPES (t1), parms2 = TYPE_ARG_TYPES (t2); + parms1 && parms2; + parms1 = TREE_CHAIN (parms1), parms2 = TREE_CHAIN (parms2)) + { + if (!gimple_compare_types (TREE_VALUE (parms1), + TREE_VALUE (parms2), + visited_p)) + goto different_types; + } + + if (parms1 || parms2) + goto different_types; + + goto same_types; + } + } + + case POINTER_TYPE: + case REFERENCE_TYPE: + { + /* If the two pointers have different ref-all attributes, + they can't be the same type. */ + if (TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)) + goto different_types; + + /* Otherwise, pointer and reference types are the same if the + pointed-to types are the same. */ + if (gimple_compare_types (TREE_TYPE (t1), TREE_TYPE (t2), visited_p)) + goto same_types; + + goto different_types; + } + + case ENUMERAL_TYPE: + { + /* For enumeral types, all the values must be the same. */ + tree v1, v2; + + if (TYPE_VALUES (t1) == TYPE_VALUES (t2)) + goto same_types; + + for (v1 = TYPE_VALUES (t1), v2 = TYPE_VALUES (t2); + v1 && v2; + v1 = TREE_CHAIN (v1), v2 = TREE_CHAIN (v2)) + { + tree c1 = TREE_VALUE (v1); + tree c2 = TREE_VALUE (v2); + + if (TREE_CODE (c1) == CONST_DECL) + c1 = DECL_INITIAL (c1); + + if (TREE_CODE (c2) == CONST_DECL) + c2 = DECL_INITIAL (c2); + + if (tree_int_cst_equal (c1, c2) != 1) + goto different_types; + } + + /* If one enumeration has more values than the other, they + are not the same. */ + if (v1 || v2) + goto different_types; + + goto same_types; + } + + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + { + /* For aggregate types, all the fields must be the same. */ + tree f1, f2; + + /* Mark the (T1, T2) comparison in progress. */ + p->same_p = -1; + + /* If either structure is empty, they should at least have + the same name. */ + if ((!TYPE_SIZE (t1) || !TYPE_SIZE (t2)) + && compare_type_names_p (t1, t2)) + goto same_types; + + /* Otherwise, compare every field. */ + for (f1 = TYPE_FIELDS (t1), f2 = TYPE_FIELDS (t2); + f1 && f2; + f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2)) + { + /* The fields must have the same name, offset and type. */ + if (DECL_NAME (f1) != DECL_NAME (f2) + || !tree_int_cst_equal (DECL_FIELD_OFFSET (f1), + DECL_FIELD_OFFSET (f2)) + || !gimple_compare_types (TREE_TYPE (f1), + TREE_TYPE (f2), + visited_p)) + goto different_types; + } + + /* If one aggregate has more fields than the other, they + are not the same. */ + if (f1 || f2) + goto different_types; + + goto same_types; + } + + default: + goto different_types; + } + + /* Common exit path for types that are not compatible. */ +different_types: + if (p) + p->same_p = 0; + return 0; + + /* Common exit path for types that are compatible. */ +same_types: + if (p) + p->same_p = 1; + return 1; +} + + +/* Return 1 iff T1 and T2 are structurally identical. Otherwise, + return 0. */ + +int +gimple_types_compatible_p (tree t1, tree t2) +{ + int same_p; + htab_t visited = NULL; + + same_p = gimple_compare_types (t1, t2, &visited); + + if (visited) + htab_delete (visited); + + return same_p; +} + + +/* Per pointer state for the SCC finding. The on_sccstack flag + is not strictly required, it is true when there is no hash value + recorded for the type and false otherwise. But querying that + is slower. */ + +struct sccs +{ + unsigned int dfsnum; + unsigned int low; + bool on_sccstack; + hashval_t hash; +}; + +static unsigned int next_dfs_num; + +static hashval_t +iterative_hash_gimple_type (tree, hashval_t, VEC(tree, heap) **, + struct pointer_map_t *, struct obstack *); + +/* DFS visit the edge from the callers type with state *STATE to T. + Update the callers type hash V with the hash for T if it is not part + of the SCC containing the callers type and return it. + SCCSTACK, SCCSTATE and SCCSTATE_OBSTACK are state for the DFS walk done. */ + +static hashval_t +visit (tree t, struct sccs *state, hashval_t v, + VEC (tree, heap) **sccstack, + struct pointer_map_t *sccstate, + struct obstack *sccstate_obstack) +{ + struct sccs *cstate = NULL; + void **slot; + + /* If there is a hash value recorded for this type then it can't + possibly be part of our parent SCC. Simply mix in its hash. */ + if ((slot = pointer_map_contains (type_hash_cache, t))) + { +#ifdef ENABLE_CHECKING + void **slot2; + /* If we have visited the type during the DFS walk then it + should not be on the SCC stack anymore. */ + if ((slot2 = pointer_map_contains (sccstate, t)) != NULL) + gcc_assert (!((struct sccs *)*slot2)->on_sccstack); +#endif + return iterative_hash_hashval_t ((hashval_t) (size_t) *slot, v); + } + + if ((slot = pointer_map_contains (sccstate, t)) != NULL) + cstate = (struct sccs *)*slot; + if (!cstate) + { + hashval_t tem; + /* Not yet visited. DFS recurse. */ + tem = iterative_hash_gimple_type (t, v, + sccstack, sccstate, sccstate_obstack); + if (!cstate) + cstate = (struct sccs *)* pointer_map_contains (sccstate, t); + state->low = MIN (state->low, cstate->low); + /* If the type is no longer on the SCC stack and thus is not part + of the parents SCC mix in its hash value. Otherwise we will + ignore the type for hashing purposes and return the unaltered + hash value. */ + if (!cstate->on_sccstack) + { +#ifdef ENABLE_CHECKING + /* If we are not on the stack we should have a hash value + recorded. */ + gcc_assert (pointer_map_contains (type_hash_cache, t)); +#endif + return tem; + } + } + if (cstate->dfsnum < state->dfsnum + && cstate->on_sccstack) + state->low = MIN (cstate->dfsnum, state->low); + +#ifdef ENABLE_CHECKING + /* As we are part of an SCC that is still in processing we should + not have a hash value recorded. */ + gcc_assert (!pointer_map_contains (type_hash_cache, t)); +#endif + + /* We are part of our parents SCC, skip this type during hashing + and return the unaltered hash value. */ + return v; +} + +/* Returning a hash value for gimple type TYPE combined with VAL. + SCCSTACK, SCCSTATE and SCCSTATE_OBSTACK are state for the DFS walk done. + + To hash a type we end up hashing in types that are reachable. + Through pointers we can end up with cycles which messes up the + required property that we need to compute the same hash value + for structurally equivalent types. To avoid this we have to + hash all types in a cycle (the SCC) in a commutative way. The + easiest way is to not mix in the hashes of the SCC members at + all. To make this work we have to delay setting the hash + values of the SCC until it is complete. */ + +static hashval_t +iterative_hash_gimple_type (tree type, hashval_t val, + VEC(tree, heap) **sccstack, + struct pointer_map_t *sccstate, + struct obstack *sccstate_obstack) +{ + hashval_t v; + void **slot; + struct sccs *state; + +#ifdef ENABLE_CHECKING + /* Not visited during this DFS walk nor during previous walks. */ + gcc_assert (!pointer_map_contains (type_hash_cache, type) + && !pointer_map_contains (sccstate, type)); +#endif + state = XOBNEW (sccstate_obstack, struct sccs); + *pointer_map_insert (sccstate, type) = state; + + VEC_safe_push (tree, heap, *sccstack, type); + state->dfsnum = next_dfs_num++; + state->low = state->dfsnum; + state->on_sccstack = true; + + /* Combine a few common features of types so that types are grouped into + smaller sets; when searching for existing matching types to merge, + only existing types having the same features as the new type will be + checked. */ + v = iterative_hash_hashval_t (TREE_CODE (type), 0); + v = iterative_hash_hashval_t (TYPE_QUALS (type), v); + v = iterative_hash_expr (TYPE_SIZE (type), v); + v = iterative_hash_expr (TYPE_SIZE_UNIT (type), v); + v = iterative_hash_hashval_t (TREE_ADDRESSABLE (type), v); + + /* Incorporate common features of numerical types. */ + if (INTEGRAL_TYPE_P (type) + || SCALAR_FLOAT_TYPE_P (type) + || FIXED_POINT_TYPE_P (type)) + { + v = iterative_hash_hashval_t (TYPE_PRECISION (type), v); + v = iterative_hash_hashval_t (TYPE_MODE (type), v); + v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v); + } + + /* Incorporate function return and argument types. */ + if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) + { + unsigned na; + tree p; + + /* For method types also incorporate their parent class. */ + if (TREE_CODE (type) == METHOD_TYPE) + v = visit (TYPE_METHOD_BASETYPE (type), state, v, + sccstack, sccstate, sccstate_obstack); + + v = visit (TREE_TYPE (type), state, v, + sccstack, sccstate, sccstate_obstack); + + for (p = TYPE_ARG_TYPES (type), na = 0; p; p = TREE_CHAIN (p)) + { + v = visit (TREE_VALUE (p), state, v, + sccstack, sccstate, sccstate_obstack); + na++; + } + + v = iterative_hash_hashval_t (na, v); + } + + /* For pointer and reference types, fold in information about the type + pointed to. */ + if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) + v = visit (TREE_TYPE (type), state, v, + sccstack, sccstate, sccstate_obstack); + + if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + { + unsigned nf; + tree f; + + for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f)) + { + v = visit (TREE_TYPE (f), state, v, + sccstack, sccstate, sccstate_obstack); + nf++; + } + + v = iterative_hash_hashval_t (nf, v); + } + + /* Record hash for us. */ + state->hash = v; + + /* See if we found an SCC. */ + if (state->low == state->dfsnum) + { + tree x; + + /* Pop off the SCC and set its hash values. */ + do + { + struct sccs *cstate; + x = VEC_pop (tree, *sccstack); + gcc_assert (!pointer_map_contains (type_hash_cache, x)); + cstate = (struct sccs *)*pointer_map_contains (sccstate, x); + cstate->on_sccstack = false; + slot = pointer_map_insert (type_hash_cache, x); + *slot = (void *) (size_t) cstate->hash; + } + while (x != type); + } + + return iterative_hash_hashval_t (v, val); +} + + +/* Returns a hash value for P (assumed to be a type). The hash value + is computed using some distinguishing features of the type. Note + that we cannot use pointer hashing here as we may be dealing with + two distinct instances of the same type. + + This function should produce the same hash value for two compatible + types according to gimple_types_compatible_p. */ + +static hashval_t +gimple_type_hash (const void *p) +{ + VEC(tree, heap) *sccstack = NULL; + struct pointer_map_t *sccstate; + struct obstack sccstate_obstack; + hashval_t val; + void **slot; + + if (type_hash_cache == NULL) + type_hash_cache = pointer_map_create (); + + if ((slot = pointer_map_contains (type_hash_cache, p)) != NULL) + return iterative_hash_hashval_t ((hashval_t) (size_t) *slot, 0); + + /* Perform a DFS walk and pre-hash all reachable types. */ + next_dfs_num = 1; + sccstate = pointer_map_create (); + gcc_obstack_init (&sccstate_obstack); + val = iterative_hash_gimple_type (CONST_CAST2 (tree, const void *, p), 0, + &sccstack, sccstate, &sccstate_obstack); + VEC_free (tree, heap, sccstack); + pointer_map_destroy (sccstate); + obstack_free (&sccstate_obstack, NULL); + + return val; +} + + +/* Returns nonzero if P1 and P2 are equal. */ + +static int +gimple_type_eq (const void *p1, const void *p2) +{ + const_tree t1 = (const_tree) p1; + const_tree t2 = (const_tree) p2; + return gimple_types_compatible_p (CONST_CAST_TREE (t1), CONST_CAST_TREE (t2)); +} + + +/* Register type T in the global type table gimple_types. + If another type T', compatible with T, already existed in + gimple_types then return T', otherwise return T. This is used by + LTO to merge identical types read from different TUs. */ + +tree +gimple_register_type (tree t) +{ + void **slot; + + gcc_assert (TYPE_P (t)); + + if (gimple_types == NULL) + gimple_types = htab_create (100000, gimple_type_hash, gimple_type_eq, 0); + + if (getenv ("MERGE_TYPE_DEBUG")) + { + fprintf (stderr, "\nRegistering type: %p - ", (void *) t); + print_generic_stmt (stderr, t, 0); + } + + slot = htab_find_slot (gimple_types, t, INSERT); + if (*slot) + { + tree new_type = (tree) *((tree *) slot); + + /* Do not merge types with different addressability. */ + gcc_assert (TREE_ADDRESSABLE (t) == TREE_ADDRESSABLE (new_type)); + + if (getenv ("MERGE_TYPE_DEBUG")) + { + if (t != new_type) + { + fprintf (stderr, "Merged with existing compatible type: %p - ", + *slot); + print_generic_stmt (stderr, new_type, 0); + } + } + + t = new_type; + } + else + *slot = (void *) t; + + return t; +} + + +/* Show statistics on references to the global type table gimple_types. */ + +void +print_gimple_types_stats (void) +{ + if (gimple_types) + fprintf (stderr, "GIMPLE type table: size %ld, %ld elements, " + "%ld searches, %ld collisions (ratio: %f)\n", + (long) htab_size (gimple_types), + (long) htab_elements (gimple_types), + (long) gimple_types->searches, + (long) gimple_types->collisions, + htab_collisions (gimple_types)); + else + fprintf (stderr, "GIMPLE type table is empty\n"); +} + + +/* Return a type the same as TYPE except unsigned or + signed according to UNSIGNEDP. */ + +static tree +gimple_signed_or_unsigned_type (bool unsignedp, tree type) +{ + tree type1; + + type1 = TYPE_MAIN_VARIANT (type); + if (type1 == signed_char_type_node + || type1 == char_type_node + || type1 == unsigned_char_type_node) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + if (type1 == integer_type_node || type1 == unsigned_type_node) + return unsignedp ? unsigned_type_node : integer_type_node; + if (type1 == short_integer_type_node || type1 == short_unsigned_type_node) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + if (type1 == long_integer_type_node || type1 == long_unsigned_type_node) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + if (type1 == long_long_integer_type_node + || type1 == long_long_unsigned_type_node) + return unsignedp + ? long_long_unsigned_type_node + : long_long_integer_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 + if (type1 == intTI_type_node || type1 == unsigned_intTI_type_node) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; +#endif + if (type1 == intDI_type_node || type1 == unsigned_intDI_type_node) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + if (type1 == intSI_type_node || type1 == unsigned_intSI_type_node) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + if (type1 == intHI_type_node || type1 == unsigned_intHI_type_node) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + if (type1 == intQI_type_node || type1 == unsigned_intQI_type_node) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + +#define GIMPLE_FIXED_TYPES(NAME) \ + if (type1 == short_ ## NAME ## _type_node \ + || type1 == unsigned_short_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_short_ ## NAME ## _type_node \ + : short_ ## NAME ## _type_node; \ + if (type1 == NAME ## _type_node \ + || type1 == unsigned_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_ ## NAME ## _type_node \ + : NAME ## _type_node; \ + if (type1 == long_ ## NAME ## _type_node \ + || type1 == unsigned_long_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_long_ ## NAME ## _type_node \ + : long_ ## NAME ## _type_node; \ + if (type1 == long_long_ ## NAME ## _type_node \ + || type1 == unsigned_long_long_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_long_long_ ## NAME ## _type_node \ + : long_long_ ## NAME ## _type_node; + +#define GIMPLE_FIXED_MODE_TYPES(NAME) \ + if (type1 == NAME ## _type_node \ + || type1 == u ## NAME ## _type_node) \ + return unsignedp ? u ## NAME ## _type_node \ + : NAME ## _type_node; + +#define GIMPLE_FIXED_TYPES_SAT(NAME) \ + if (type1 == sat_ ## short_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_short_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_short_ ## NAME ## _type_node \ + : sat_ ## short_ ## NAME ## _type_node; \ + if (type1 == sat_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_ ## NAME ## _type_node \ + : sat_ ## NAME ## _type_node; \ + if (type1 == sat_ ## long_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_long_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_long_ ## NAME ## _type_node \ + : sat_ ## long_ ## NAME ## _type_node; \ + if (type1 == sat_ ## long_long_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_long_long_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_long_long_ ## NAME ## _type_node \ + : sat_ ## long_long_ ## NAME ## _type_node; + +#define GIMPLE_FIXED_MODE_TYPES_SAT(NAME) \ + if (type1 == sat_ ## NAME ## _type_node \ + || type1 == sat_ ## u ## NAME ## _type_node) \ + return unsignedp ? sat_ ## u ## NAME ## _type_node \ + : sat_ ## NAME ## _type_node; + + GIMPLE_FIXED_TYPES (fract); + GIMPLE_FIXED_TYPES_SAT (fract); + GIMPLE_FIXED_TYPES (accum); + GIMPLE_FIXED_TYPES_SAT (accum); + + GIMPLE_FIXED_MODE_TYPES (qq); + GIMPLE_FIXED_MODE_TYPES (hq); + GIMPLE_FIXED_MODE_TYPES (sq); + GIMPLE_FIXED_MODE_TYPES (dq); + GIMPLE_FIXED_MODE_TYPES (tq); + GIMPLE_FIXED_MODE_TYPES_SAT (qq); + GIMPLE_FIXED_MODE_TYPES_SAT (hq); + GIMPLE_FIXED_MODE_TYPES_SAT (sq); + GIMPLE_FIXED_MODE_TYPES_SAT (dq); + GIMPLE_FIXED_MODE_TYPES_SAT (tq); + GIMPLE_FIXED_MODE_TYPES (ha); + GIMPLE_FIXED_MODE_TYPES (sa); + GIMPLE_FIXED_MODE_TYPES (da); + GIMPLE_FIXED_MODE_TYPES (ta); + GIMPLE_FIXED_MODE_TYPES_SAT (ha); + GIMPLE_FIXED_MODE_TYPES_SAT (sa); + GIMPLE_FIXED_MODE_TYPES_SAT (da); + GIMPLE_FIXED_MODE_TYPES_SAT (ta); + + /* For ENUMERAL_TYPEs in C++, must check the mode of the types, not + the precision; they have precision set to match their range, but + may use a wider mode to match an ABI. If we change modes, we may + wind up with bad conversions. For INTEGER_TYPEs in C, must check + the precision as well, so as to yield correct results for + bit-field types. C++ does not have these separate bit-field + types, and producing a signed or unsigned variant of an + ENUMERAL_TYPE may cause other problems as well. */ + if (!INTEGRAL_TYPE_P (type) + || TYPE_UNSIGNED (type) == unsignedp) + return type; + +#define TYPE_OK(node) \ + (TYPE_MODE (type) == TYPE_MODE (node) \ + && TYPE_PRECISION (type) == TYPE_PRECISION (node)) + if (TYPE_OK (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + if (TYPE_OK (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + if (TYPE_OK (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + if (TYPE_OK (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + if (TYPE_OK (long_long_integer_type_node)) + return (unsignedp + ? long_long_unsigned_type_node + : long_long_integer_type_node); + +#if HOST_BITS_PER_WIDE_INT >= 64 + if (TYPE_OK (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; +#endif + if (TYPE_OK (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + if (TYPE_OK (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + if (TYPE_OK (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + if (TYPE_OK (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + +#undef GIMPLE_FIXED_TYPES +#undef GIMPLE_FIXED_MODE_TYPES +#undef GIMPLE_FIXED_TYPES_SAT +#undef GIMPLE_FIXED_MODE_TYPES_SAT +#undef TYPE_OK + + return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp); +} + + +/* Return an unsigned type the same as TYPE in other respects. */ + +tree +gimple_unsigned_type (tree type) +{ + return gimple_signed_or_unsigned_type (true, type); +} + + +/* Return a signed type the same as TYPE in other respects. */ + +tree +gimple_signed_type (tree type) +{ + return gimple_signed_or_unsigned_type (false, type); +} + + +/* Return the typed-based alias set for T, which may be an expression + or a type. Return -1 if we don't do anything special. */ + +alias_set_type +gimple_get_alias_set (tree t) +{ + tree u; + + /* Permit type-punning when accessing a union, provided the access + is directly through the union. For example, this code does not + permit taking the address of a union member and then storing + through it. Even the type-punning allowed here is a GCC + extension, albeit a common and useful one; the C standard says + that such accesses have implementation-defined behavior. */ + for (u = t; + TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF; + u = TREE_OPERAND (u, 0)) + if (TREE_CODE (u) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE) + return 0; + + /* That's all the expressions we handle specially. */ + if (!TYPE_P (t)) + return -1; + + /* For convenience, follow the C standard when dealing with + character types. Any object may be accessed via an lvalue that + has character type. */ + if (t == char_type_node + || t == signed_char_type_node + || t == unsigned_char_type_node) + return 0; + + /* Allow aliasing between signed and unsigned variants of the same + type. We treat the signed variant as canonical. */ + if (TREE_CODE (t) == INTEGER_TYPE && TYPE_UNSIGNED (t)) + { + tree t1 = gimple_signed_type (t); + + /* t1 == t can happen for boolean nodes which are always unsigned. */ + if (t1 != t) + return get_alias_set (t1); + } + + return -1; +} + + /* Data structure used to count the number of dereferences to PTR inside an expression. */ struct count_ptr_d Index: gimple.h =================================================================== --- gimple.h (revision 150526) +++ gimple.h (working copy) @@ -824,6 +824,9 @@ bool gimple_assign_rhs_could_trap_p (gim void gimple_regimplify_operands (gimple, gimple_stmt_iterator *); bool empty_body_p (gimple_seq); unsigned get_gimple_rhs_num_ops (enum tree_code); +size_t gimple_size (enum gimple_code); +#define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO) +gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL); /* Returns true iff T is a valid GIMPLE statement. */ extern bool is_gimple_stmt (tree); @@ -880,6 +883,12 @@ extern bool is_gimple_call_addr (tree); extern tree get_call_expr_in (tree t); extern void recalculate_side_effects (tree); +extern int gimple_types_compatible_p (tree, tree); +extern tree gimple_register_type (tree); +extern void print_gimple_types_stats (void); +extern tree gimple_unsigned_type (tree); +extern tree gimple_signed_type (tree); +extern alias_set_type gimple_get_alias_set (tree); extern void count_uses_and_derefs (tree, gimple, unsigned *, unsigned *, unsigned *); extern bool walk_stmt_load_store_addr_ops (gimple, void *, @@ -900,6 +909,7 @@ extern tree get_formal_tmp_var (tree, gi extern void declare_vars (tree, gimple, bool); extern void tree_annotate_all_with_location (tree *, location_t); extern void annotate_all_with_location (gimple_seq, location_t); +extern void mark_addressable (tree); /* Validation of GIMPLE expressions. Note that these predicates only check the basic form of the expression, they don't recurse to make sure that Index: passes.c =================================================================== --- passes.c (revision 150526) +++ passes.c (working copy) @@ -535,6 +535,7 @@ init_optimization_passes (void) NEXT_PASS (pass_inline_parameters); NEXT_PASS (pass_rebuild_cgraph_edges); } + NEXT_PASS (pass_ipa_free_lang_data); NEXT_PASS (pass_early_local_passes); { struct opt_pass **p = &pass_early_local_passes.pass.sub; Index: c-lang.c =================================================================== --- c-lang.c (revision 150526) +++ c-lang.c (working copy) @@ -46,7 +46,7 @@ enum c_language_kind c_language = clk_c; #define LANG_HOOKS_INIT c_objc_common_init /* Each front end provides its own lang hook initializer. */ -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* Final processing of file-scope data. The Objective-C version of this function still does something. */ Index: langhooks-def.h =================================================================== --- langhooks-def.h (revision 150526) +++ langhooks-def.h (working copy) @@ -101,6 +101,7 @@ extern void lhd_omp_firstprivatize_type_ #define LANG_HOOKS_DECL_PRINTABLE_NAME lhd_decl_printable_name #define LANG_HOOKS_DWARF_NAME lhd_dwarf_name #define LANG_HOOKS_EXPR_SIZE lhd_expr_size +#define LANG_HOOKS_FREE_LANG_DATA lhd_do_nothing_t #define LANG_HOOKS_TREE_SIZE lhd_tree_size #define LANG_HOOKS_TYPES_COMPATIBLE_P lhd_types_compatible_p #define LANG_HOOKS_BUILTIN_FUNCTION lhd_builtin_function @@ -225,6 +226,7 @@ extern tree lhd_make_node (enum tree_cod #define LANG_HOOKS_INITIALIZER { \ LANG_HOOKS_NAME, \ LANG_HOOKS_IDENTIFIER_SIZE, \ + LANG_HOOKS_FREE_LANG_DATA, \ LANG_HOOKS_TREE_SIZE, \ LANG_HOOKS_INIT_OPTIONS, \ LANG_HOOKS_INITIALIZE_DIAGNOSTICS, \