Mercurial > hg > CbC > CbC_gcc
diff gcc/varasm.c @ 55:77e2b8dfacca gcc-4.4.5
update it from 4.4.3 to 4.5.0
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 12 Feb 2010 23:39:51 +0900 |
parents | 3bfb6c00c1e0 |
children | b7f97abdc517 |
line wrap: on
line diff
--- a/gcc/varasm.c Sun Feb 07 18:28:00 2010 +0900 +++ b/gcc/varasm.c Fri Feb 12 23:39:51 2010 +0900 @@ -1,7 +1,7 @@ /* Output variables, constants and external declarations, for GNU compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - 2010 Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Free Software Foundation, Inc. This file is part of GCC. @@ -42,7 +42,6 @@ #include "output.h" #include "toplev.h" #include "hashtab.h" -#include "c-pragma.h" #include "ggc.h" #include "langhooks.h" #include "tm_p.h" @@ -115,7 +114,6 @@ static void output_addressed_constants (tree); static unsigned HOST_WIDE_INT array_size_for_constructor (tree); static unsigned min_align (unsigned, unsigned); -static void output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int); static void globalize_decl (tree); #ifdef BSS_SECTION_ASM_OP #ifdef ASM_OUTPUT_BSS @@ -217,7 +215,7 @@ unsigned plen = strlen (prefix); unsigned nlen = strlen (IDENTIFIER_POINTER (name)); char *toname = (char *) alloca (plen + nlen + 1); - + memcpy (toname, prefix, plen); memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1); @@ -240,25 +238,29 @@ default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED) { tree word_type_node, field, next_field; - - field = build_decl (FIELD_DECL, get_identifier ("__templ"), ptr_type_node); + + field = build_decl (UNKNOWN_LOCATION, + FIELD_DECL, get_identifier ("__templ"), ptr_type_node); DECL_CONTEXT (field) = type; next_field = field; - - field = build_decl (FIELD_DECL, get_identifier ("__offset"), + + field = build_decl (UNKNOWN_LOCATION, + FIELD_DECL, get_identifier ("__offset"), ptr_type_node); DECL_CONTEXT (field) = type; TREE_CHAIN (field) = next_field; next_field = field; - + word_type_node = lang_hooks.types.type_for_mode (word_mode, 1); - field = build_decl (FIELD_DECL, get_identifier ("__align"), + field = build_decl (UNKNOWN_LOCATION, + FIELD_DECL, get_identifier ("__align"), word_type_node); DECL_CONTEXT (field) = type; TREE_CHAIN (field) = next_field; next_field = field; - - field = build_decl (FIELD_DECL, get_identifier ("__size"), word_type_node); + + field = build_decl (UNKNOWN_LOCATION, + FIELD_DECL, get_identifier ("__size"), word_type_node); DECL_CONTEXT (field) = type; TREE_CHAIN (field) = next_field; @@ -282,7 +284,8 @@ field = targetm.emutls.var_fields (type, &type_name); if (!type_name) type_name = get_identifier ("__emutls_object"); - type_name = build_decl (TYPE_DECL, type_name, type); + type_name = build_decl (UNKNOWN_LOCATION, + TYPE_DECL, type_name, type); TYPE_NAME (type) = type_name; TYPE_FIELDS (type) = field; layout_type (type); @@ -297,7 +300,7 @@ get_emutls_init_templ_addr (tree decl) { tree name, to; - + if (targetm.emutls.register_common && !DECL_INITIAL (decl) && !DECL_SECTION_NAME (decl)) return null_pointer_node; @@ -311,7 +314,8 @@ name = prefix_name (prefix, name); } - to = build_decl (VAR_DECL, name, TREE_TYPE (decl)); + to = build_decl (DECL_SOURCE_LOCATION (decl), + VAR_DECL, name, TREE_TYPE (decl)); SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to)); DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED; DECL_ARTIFICIAL (to) = 1; @@ -320,11 +324,11 @@ DECL_IGNORED_P (to) = 1; DECL_CONTEXT (to) = DECL_CONTEXT (decl); DECL_SECTION_NAME (to) = DECL_SECTION_NAME (decl); - + DECL_WEAK (to) = DECL_WEAK (decl); if (DECL_ONE_ONLY (decl)) { - make_decl_one_only (to); + make_decl_one_only (to, DECL_ASSEMBLER_NAME (to)); TREE_STATIC (to) = TREE_STATIC (decl); TREE_PUBLIC (to) = TREE_PUBLIC (decl); DECL_VISIBILITY (to) = DECL_VISIBILITY (decl); @@ -371,7 +375,8 @@ to = h->to; else { - to = build_decl (VAR_DECL, get_emutls_object_name (name), + to = build_decl (DECL_SOURCE_LOCATION (decl), + VAR_DECL, get_emutls_object_name (name), get_emutls_object_type ()); h = GGC_NEW (struct tree_map); @@ -386,7 +391,7 @@ TREE_READONLY (to) = 0; SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to)); if (DECL_ONE_ONLY (decl)) - make_decl_one_only (to); + make_decl_one_only (to, DECL_ASSEMBLER_NAME (to)); DECL_CONTEXT (to) = DECL_CONTEXT (decl); if (targetm.emutls.var_align_fixed) /* If we're not allowed to change the proxy object's @@ -440,7 +445,7 @@ args = tree_cons (NULL, x, args); x = built_in_decls[BUILT_IN_EMUTLS_REGISTER_COMMON]; - x = build_function_call_expr (x, args); + x = build_function_call_expr (UNKNOWN_LOCATION, x, args); append_to_statement_list (x, pstmts); return 1; @@ -459,7 +464,7 @@ htab_traverse_noresize (emutls_htab, emutls_common_1, &body); if (body == NULL_TREE) return; - + cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY); } } @@ -869,11 +874,18 @@ if (DECL_ONE_ONLY (decl) && HAVE_COMDAT_GROUP) { - size_t len = strlen (name) + 3; - char* rname = (char *) alloca (len); + const char *dot; + size_t len; + char* rname; + + dot = strchr (name + 1, '.'); + if (!dot) + dot = name; + len = strlen (dot) + 8; + rname = (char *) alloca (len); strcpy (rname, ".rodata"); - strcat (rname, name + 5); + strcat (rname, dot); return get_section (rname, SECTION_LINKONCE, decl); } /* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo. */ @@ -1156,11 +1168,17 @@ static section * get_variable_section (tree decl, bool prefer_noswitch_p) { + addr_space_t as = ADDR_SPACE_GENERIC; int reloc; - /* If the decl has been given an explicit section name, then it - isn't common, and shouldn't be handled as such. */ - if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL) + if (TREE_TYPE (decl) != error_mark_node) + as = TYPE_ADDR_SPACE (TREE_TYPE (decl)); + + /* If the decl has been given an explicit section name, or it resides + in a non-generic address space, then it isn't common, and shouldn't + be handled as such. */ + if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL + && ADDR_SPACE_GENERIC_P (as)) { if (DECL_THREAD_LOCAL_P (decl)) return tls_comm_section; @@ -1184,7 +1202,8 @@ if (IN_NAMED_SECTION (decl)) return get_named_section (decl, NULL, reloc); - if (!DECL_THREAD_LOCAL_P (decl) + if (ADDR_SPACE_GENERIC_P (as) + && !DECL_THREAD_LOCAL_P (decl) && !(prefer_noswitch_p && targetm.have_switchable_bss_sections) && bss_initializer_p (decl)) { @@ -1428,7 +1447,15 @@ if (use_object_blocks_p () && use_blocks_for_decl_p (decl)) x = create_block_symbol (name, get_block_for_decl (decl), -1); else - x = gen_rtx_SYMBOL_REF (Pmode, name); + { + enum machine_mode address_mode = Pmode; + if (TREE_TYPE (decl) != error_mark_node) + { + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl)); + address_mode = targetm.addr_space.address_mode (as); + } + x = gen_rtx_SYMBOL_REF (address_mode, name); + } SYMBOL_REF_WEAK (x) = DECL_WEAK (decl); SET_SYMBOL_REF_DECL (x, decl); @@ -1482,7 +1509,7 @@ } /* Write the address of the entity given by SYMBOL to SEC. */ -void +void assemble_addr_to_section (rtx symbol, section *sec) { switch_to_section (sec); @@ -1513,7 +1540,7 @@ section *sec; if (priority != DEFAULT_INIT_PRIORITY) - sec = get_cdtor_priority_section (priority, + sec = get_cdtor_priority_section (priority, /*constructor_p=*/false); else sec = get_section (".dtors", SECTION_WRITE, NULL); @@ -1553,7 +1580,7 @@ section *sec; if (priority != DEFAULT_INIT_PRIORITY) - sec = get_cdtor_priority_section (priority, + sec = get_cdtor_priority_section (priority, /*constructor_p=*/true); else sec = get_section (".ctors", SECTION_WRITE, NULL); @@ -1737,7 +1764,8 @@ ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname); #endif - (*debug_hooks->begin_function) (decl); + if (!DECL_IGNORED_P (decl)) + (*debug_hooks->begin_function) (decl); /* Make function name accessible from other files, if appropriate. */ @@ -2004,27 +2032,27 @@ constructor_elt *elt; tree type = TREE_TYPE (to); tree field = TYPE_FIELDS (type); - + elt = VEC_quick_push (constructor_elt, v, NULL); elt->index = field; elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl)); - + elt = VEC_quick_push (constructor_elt, v, NULL); field = TREE_CHAIN (field); elt->index = field; elt->value = build_int_cst (TREE_TYPE (field), DECL_ALIGN_UNIT (decl)); - + elt = VEC_quick_push (constructor_elt, v, NULL); field = TREE_CHAIN (field); elt->index = field; elt->value = null_pointer_node; - + elt = VEC_quick_push (constructor_elt, v, NULL); field = TREE_CHAIN (field); elt->index = field; elt->value = proxy; - + return build_constructor (type, v); } @@ -2069,7 +2097,7 @@ Without this, if the variable is placed in a section-anchored block, the template will only be marked when it's too late. */ - record_references_in_initializer (to); + record_references_in_initializer (to, false); } decl = to; @@ -2249,7 +2277,7 @@ return true; name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0) + if (is_builtin_name (name)) return true; } return false; @@ -2309,20 +2337,20 @@ /* We want to output annotation for weak and external symbols at very last to check if they are references or not. */ - if (SUPPORTS_WEAK - && DECL_WEAK (decl) + if (SUPPORTS_WEAK && DECL_WEAK (decl) /* TREE_STATIC is a weird and abused creature which is not generally the right test for whether an entity has been locally emitted, inlined or otherwise not-really-extern, but for declarations that can be weak, it happens to be match. */ && !TREE_STATIC (decl) - && lookup_attribute ("weak", DECL_ATTRIBUTES (decl))) + && value_member (decl, weak_decls) == NULL_TREE) weak_decls = tree_cons (NULL, decl, weak_decls); #ifdef ASM_OUTPUT_EXTERNAL - pending_assemble_externals = tree_cons (0, decl, - pending_assemble_externals); + if (value_member (decl, pending_assemble_externals) == NULL_TREE) + pending_assemble_externals = tree_cons (NULL, decl, + pending_assemble_externals); #endif } @@ -2494,7 +2522,6 @@ static GTY(()) rtx initial_trampoline; -#ifdef TRAMPOLINE_TEMPLATE rtx assemble_trampoline_template (void) { @@ -2503,6 +2530,8 @@ int align; rtx symbol; + gcc_assert (targetm.asm_out.trampoline_template != NULL); + if (initial_trampoline) return initial_trampoline; @@ -2517,12 +2546,10 @@ /* Write the assembler code to define one. */ align = floor_log2 (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT); if (align > 0) - { - ASM_OUTPUT_ALIGN (asm_out_file, align); - } + ASM_OUTPUT_ALIGN (asm_out_file, align); targetm.asm_out.internal_label (asm_out_file, "LTRAMP", 0); - TRAMPOLINE_TEMPLATE (asm_out_file); + targetm.asm_out.trampoline_template (asm_out_file); /* Record the rtl to refer to it. */ ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0); @@ -2530,12 +2557,12 @@ symbol = gen_rtx_SYMBOL_REF (Pmode, name); SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL; - initial_trampoline = gen_rtx_MEM (BLKmode, symbol); + initial_trampoline = gen_const_mem (BLKmode, symbol); set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT); + set_mem_size (initial_trampoline, GEN_INT (TRAMPOLINE_SIZE)); return initial_trampoline; } -#endif /* A and B are either alignments or offsets. Return the minimum alignment that may be assumed after adding the two together. */ @@ -2630,7 +2657,7 @@ enum machine_mode omode, imode; unsigned int subalign; unsigned int subsize, i; - unsigned char mclass; + enum mode_class mclass; subsize = size > UNITS_PER_WORD? UNITS_PER_WORD : 1; subalign = MIN (align, subsize * BITS_PER_UNIT); @@ -2706,8 +2733,7 @@ Store them both in the structure *VALUE. EXP must be reducible. */ -struct addr_const GTY(()) -{ +struct GTY(()) addr_const { rtx base; HOST_WIDE_INT offset; }; @@ -2771,23 +2797,6 @@ value->offset = offset; } -/* Uniquize all constants that appear in memory. - Each constant in memory thus far output is recorded - in `const_desc_table'. */ - -struct constant_descriptor_tree GTY(()) -{ - /* A MEM for the constant. */ - rtx rtl; - - /* The value of the constant. */ - tree value; - - /* Hash of value. Computing the hash from value each time - hashfn is called can't work properly, as that means recursive - use of the hash table during hash table expansion. */ - hashval_t hash; -}; static GTY((param_is (struct constant_descriptor_tree))) htab_t const_desc_htab; @@ -2795,6 +2804,14 @@ static struct constant_descriptor_tree * build_constant_desc (tree); static void maybe_output_constant_def_contents (struct constant_descriptor_tree *, int); +/* Constant pool accessor function. */ + +htab_t +constant_pool_htab (void) +{ + return const_desc_htab; +} + /* Compute a hash code for a constant expression. */ static hashval_t @@ -3198,6 +3215,10 @@ set_mem_alias_set (rtl, 0); set_mem_alias_set (rtl, const_alias_set); + /* We cannot share RTX'es in pool entries. + Mark this piece of RTL as required for unsharing. */ + RTX_FLAG (rtl, used) = 1; + /* Set flags or add text to the name to record information, such as that it is a local symbol. If the name is changed, the macro ASM_OUTPUT_LABELREF will have to know how to strip this @@ -3361,8 +3382,7 @@ can use one per-file pool. Should add a targetm bit to tell the difference. */ -struct rtx_constant_pool GTY(()) -{ +struct GTY(()) rtx_constant_pool { /* Pointers to first and last constant in pool, as ordered by offset. */ struct constant_descriptor_rtx *first; struct constant_descriptor_rtx *last; @@ -3378,8 +3398,7 @@ HOST_WIDE_INT offset; }; -struct constant_descriptor_rtx GTY((chain_next ("%h.next"))) -{ +struct GTY((chain_next ("%h.next"))) constant_descriptor_rtx { struct constant_descriptor_rtx *next; rtx mem; rtx sym; @@ -3437,7 +3456,7 @@ hwi = INTVAL (x); fold_hwi: { - const int shift = sizeof (hashval_t) * CHAR_BIT; + int shift = sizeof (hashval_t) * CHAR_BIT; const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t); int i; @@ -4072,9 +4091,6 @@ && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor))); } -static tree initializer_constant_valid_p_1 (tree value, tree endtype, - tree *cache); - /* A subroutine of initializer_constant_valid_p. VALUE is a MINUS_EXPR, PLUS_EXPR or POINTER_PLUS_EXPR. This looks for cases of VALUE which are valid when ENDTYPE is an integer of any size; in @@ -4084,7 +4100,7 @@ returns NULL. */ static tree -narrowing_initializer_constant_valid_p (tree value, tree endtype, tree *cache) +narrowing_initializer_constant_valid_p (tree value, tree endtype) { tree op0, op1; @@ -4123,14 +4139,11 @@ op1 = inner; } - op0 = initializer_constant_valid_p_1 (op0, endtype, cache); - if (!op0) - return NULL_TREE; - - op1 = initializer_constant_valid_p_1 (op1, endtype, - cache ? cache + 2 : NULL); + op0 = initializer_constant_valid_p (op0, endtype); + op1 = initializer_constant_valid_p (op1, endtype); + /* Both initializers must be known. */ - if (op1) + if (op0 && op1) { if (op0 == op1 && (op0 == null_pointer_node @@ -4151,8 +4164,7 @@ return NULL_TREE; } -/* Helper function of initializer_constant_valid_p. - Return nonzero if VALUE is a valid constant-valued expression +/* Return nonzero if VALUE is a valid constant-valued expression for use in initializing a static variable; one that can be an element of a "constant" initializer. @@ -4160,12 +4172,10 @@ if it is relocatable, return the variable that determines the relocation. We assume that VALUE has been folded as much as possible; therefore, we do not need to check for such things as - arithmetic-combinations of integers. - - Use CACHE (pointer to 2 tree values) for caching if non-NULL. */ - -static tree -initializer_constant_valid_p_1 (tree value, tree endtype, tree *cache) + arithmetic-combinations of integers. */ + +tree +initializer_constant_valid_p (tree value, tree endtype) { tree ret; @@ -4178,33 +4188,18 @@ tree elt; bool absolute = true; - if (cache && cache[0] == value) - return cache[1]; FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt) { tree reloc; - reloc = initializer_constant_valid_p_1 (elt, TREE_TYPE (elt), - NULL); + reloc = initializer_constant_valid_p (elt, TREE_TYPE (elt)); if (!reloc) - { - if (cache) - { - cache[0] = value; - cache[1] = NULL_TREE; - } - return NULL_TREE; - } + return NULL_TREE; if (reloc != null_pointer_node) absolute = false; } /* For a non-absolute relocation, there is no single variable that can be "the variable that determines the relocation." */ - if (cache) - { - cache[0] = value; - cache[1] = absolute ? null_pointer_node : error_mark_node; - } return absolute ? null_pointer_node : error_mark_node; } @@ -4232,8 +4227,7 @@ /* Taking the address of a nested function involves a trampoline, unless we don't need or want one. */ if (TREE_CODE (op0) == FUNCTION_DECL - && decl_function_context (op0) - && !DECL_NO_STATIC_CHAIN (op0) + && DECL_STATIC_CHAIN (op0) && !TREE_NO_TRAMPOLINE (value)) return NULL_TREE; /* "&{...}" requires a temporary to hold the constructed @@ -4245,8 +4239,7 @@ } case NON_LVALUE_EXPR: - return initializer_constant_valid_p_1 (TREE_OPERAND (value, 0), - endtype, cache); + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); case VIEW_CONVERT_EXPR: { @@ -4261,13 +4254,13 @@ if (AGGREGATE_TYPE_P (src_type) && !AGGREGATE_TYPE_P (dest_type)) { if (TYPE_MODE (endtype) == TYPE_MODE (dest_type)) - return initializer_constant_valid_p_1 (src, endtype, cache); + return initializer_constant_valid_p (src, endtype); else return NULL_TREE; } /* Allow all other kinds of view-conversion. */ - return initializer_constant_valid_p_1 (src, endtype, cache); + return initializer_constant_valid_p (src, endtype); } CASE_CONVERT: @@ -4282,18 +4275,18 @@ || (FLOAT_TYPE_P (dest_type) && FLOAT_TYPE_P (src_type)) || (TREE_CODE (dest_type) == OFFSET_TYPE && TREE_CODE (src_type) == OFFSET_TYPE)) - return initializer_constant_valid_p_1 (src, endtype, cache); + return initializer_constant_valid_p (src, endtype); /* Allow length-preserving conversions between integer types. */ if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type) && (TYPE_PRECISION (dest_type) == TYPE_PRECISION (src_type))) - return initializer_constant_valid_p_1 (src, endtype, cache); + return initializer_constant_valid_p (src, endtype); /* Allow conversions between other integer types only if explicit value. */ if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type)) { - tree inner = initializer_constant_valid_p_1 (src, endtype, cache); + tree inner = initializer_constant_valid_p (src, endtype); if (inner == null_pointer_node) return null_pointer_node; break; @@ -4302,7 +4295,7 @@ /* Allow (int) &foo provided int is as wide as a pointer. */ if (INTEGRAL_TYPE_P (dest_type) && POINTER_TYPE_P (src_type) && (TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type))) - return initializer_constant_valid_p_1 (src, endtype, cache); + return initializer_constant_valid_p (src, endtype); /* Likewise conversions from int to pointers, but also allow conversions from 0. */ @@ -4316,14 +4309,14 @@ if (integer_zerop (src)) return null_pointer_node; else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type)) - return initializer_constant_valid_p_1 (src, endtype, cache); + return initializer_constant_valid_p (src, endtype); } /* Allow conversions to struct or union types if the value inside is okay. */ if (TREE_CODE (dest_type) == RECORD_TYPE || TREE_CODE (dest_type) == UNION_TYPE) - return initializer_constant_valid_p_1 (src, endtype, cache); + return initializer_constant_valid_p (src, endtype); } break; @@ -4333,104 +4326,117 @@ with -frounding-math we hit this with addition of two constants. */ if (TREE_CODE (endtype) == REAL_TYPE) return NULL_TREE; - if (cache && cache[0] == value) - return cache[1]; if (! INTEGRAL_TYPE_P (endtype) - || TYPE_PRECISION (endtype) >= POINTER_SIZE) + || TYPE_PRECISION (endtype) >= TYPE_PRECISION (TREE_TYPE (value))) { - tree ncache[4] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE }; - tree valid0 - = initializer_constant_valid_p_1 (TREE_OPERAND (value, 0), - endtype, ncache); - tree valid1 - = initializer_constant_valid_p_1 (TREE_OPERAND (value, 1), - endtype, ncache + 2); + tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1), + endtype); /* If either term is absolute, use the other term's relocation. */ if (valid0 == null_pointer_node) - ret = valid1; - else if (valid1 == null_pointer_node) - ret = valid0; - /* Support narrowing pointer differences. */ - else - ret = narrowing_initializer_constant_valid_p (value, endtype, - ncache); + return valid1; + if (valid1 == null_pointer_node) + return valid0; } - else + /* Support narrowing pointer differences. */ - ret = narrowing_initializer_constant_valid_p (value, endtype, NULL); - if (cache) - { - cache[0] = value; - cache[1] = ret; - } - return ret; + ret = narrowing_initializer_constant_valid_p (value, endtype); + if (ret != NULL_TREE) + return ret; + + break; case MINUS_EXPR: if (TREE_CODE (endtype) == REAL_TYPE) return NULL_TREE; - if (cache && cache[0] == value) - return cache[1]; if (! INTEGRAL_TYPE_P (endtype) - || TYPE_PRECISION (endtype) >= POINTER_SIZE) + || TYPE_PRECISION (endtype) >= TYPE_PRECISION (TREE_TYPE (value))) { - tree ncache[4] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE }; - tree valid0 - = initializer_constant_valid_p_1 (TREE_OPERAND (value, 0), - endtype, ncache); - tree valid1 - = initializer_constant_valid_p_1 (TREE_OPERAND (value, 1), - endtype, ncache + 2); + tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1), + endtype); /* Win if second argument is absolute. */ if (valid1 == null_pointer_node) - ret = valid0; + return valid0; /* Win if both arguments have the same relocation. Then the value is absolute. */ - else if (valid0 == valid1 && valid0 != 0) - ret = null_pointer_node; + if (valid0 == valid1 && valid0 != 0) + return null_pointer_node; + /* Since GCC guarantees that string constants are unique in the generated code, a subtraction between two copies of the same constant string is absolute. */ - else if (valid0 && TREE_CODE (valid0) == STRING_CST - && valid1 && TREE_CODE (valid1) == STRING_CST - && operand_equal_p (valid0, valid1, 1)) - ret = null_pointer_node; - /* Support narrowing differences. */ - else - ret = narrowing_initializer_constant_valid_p (value, endtype, - ncache); + if (valid0 && TREE_CODE (valid0) == STRING_CST + && valid1 && TREE_CODE (valid1) == STRING_CST + && operand_equal_p (valid0, valid1, 1)) + return null_pointer_node; } - else - /* Support narrowing differences. */ - ret = narrowing_initializer_constant_valid_p (value, endtype, NULL); - if (cache) - { - cache[0] = value; - cache[1] = ret; - } - return ret; + + /* Support narrowing differences. */ + ret = narrowing_initializer_constant_valid_p (value, endtype); + if (ret != NULL_TREE) + return ret; + + break; default: break; } - return NULL_TREE; -} - -/* Return nonzero if VALUE is a valid constant-valued expression - for use in initializing a static variable; one that can be an - element of a "constant" initializer. - - Return null_pointer_node if the value is absolute; - if it is relocatable, return the variable that determines the relocation. - We assume that VALUE has been folded as much as possible; - therefore, we do not need to check for such things as - arithmetic-combinations of integers. */ -tree -initializer_constant_valid_p (tree value, tree endtype) -{ - return initializer_constant_valid_p_1 (value, endtype, NULL); + return 0; } +/* Return true if VALUE is a valid constant-valued expression + for use in initializing a static bit-field; one that can be + an element of a "constant" initializer. */ + +bool +initializer_constant_valid_for_bitfield_p (tree value) +{ + /* For bitfields we support integer constants or possibly nested aggregates + of such. */ + switch (TREE_CODE (value)) + { + case CONSTRUCTOR: + { + unsigned HOST_WIDE_INT idx; + tree elt; + + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt) + if (!initializer_constant_valid_for_bitfield_p (elt)) + return false; + return true; + } + + case INTEGER_CST: + return true; + + case VIEW_CONVERT_EXPR: + case NON_LVALUE_EXPR: + return + initializer_constant_valid_for_bitfield_p (TREE_OPERAND (value, 0)); + + default: + break; + } + + return false; +} + +/* output_constructor outer state of relevance in recursive calls, typically + for nested aggregate bitfields. */ + +typedef struct { + unsigned int bit_offset; /* current position in ... */ + int byte; /* ... the outer byte buffer. */ +} oc_outer_state; + +static unsigned HOST_WIDE_INT + output_constructor (tree, unsigned HOST_WIDE_INT, unsigned int, + oc_outer_state *); + /* Output assembler code for constant EXP to FILE, with no label. This includes the pseudo-op such as ".int" or ".byte", and a newline. Assumes output_addressed_constants has been done on EXP already. @@ -4466,7 +4472,9 @@ resolving it. */ if (TREE_CODE (exp) == NOP_EXPR && POINTER_TYPE_P (TREE_TYPE (exp)) - && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp)))) + && targetm.addr_space.valid_pointer_mode + (TYPE_MODE (TREE_TYPE (exp)), + TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))))) { tree saved_type = TREE_TYPE (exp); @@ -4474,7 +4482,9 @@ pointer modes. */ while (TREE_CODE (exp) == NOP_EXPR && POINTER_TYPE_P (TREE_TYPE (exp)) - && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp)))) + && targetm.addr_space.valid_pointer_mode + (TYPE_MODE (TREE_TYPE (exp)), + TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))))) exp = TREE_OPERAND (exp, 0); /* If what we're left with is the address of something, we can @@ -4486,7 +4496,7 @@ else if (TREE_CODE (exp) == INTEGER_CST) exp = build_int_cst_wide (saved_type, TREE_INT_CST_LOW (exp), TREE_INT_CST_HIGH (exp)); - + } /* Eliminate any conversions since we'll be outputting the underlying @@ -4569,7 +4579,7 @@ switch (TREE_CODE (exp)) { case CONSTRUCTOR: - output_constructor (exp, size, align); + output_constructor (exp, size, align, NULL); return; case STRING_CST: thissize = MIN ((unsigned HOST_WIDE_INT)TREE_STRING_LENGTH (exp), @@ -4607,7 +4617,7 @@ case RECORD_TYPE: case UNION_TYPE: gcc_assert (TREE_CODE (exp) == CONSTRUCTOR); - output_constructor (exp, size, align); + output_constructor (exp, size, align, NULL); return; case ERROR_MARK: @@ -4663,316 +4673,462 @@ return tree_low_cst (i, 1); } -/* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants). - Generate at least SIZE bytes, padding if necessary. */ +/* Other datastructures + helpers for output_constructor. */ + +/* output_constructor local state to support interaction with helpers. */ + +typedef struct { + + /* Received arguments. */ + tree exp; /* Constructor expression. */ + unsigned HOST_WIDE_INT size; /* # bytes to output - pad if necessary. */ + unsigned int align; /* Known initial alignment. */ + + /* Constructor expression data. */ + tree type; /* Expression type. */ + tree field; /* Current field decl in a record. */ + tree min_index; /* Lower bound if specified for an array. */ + + /* Output processing state. */ + HOST_WIDE_INT total_bytes; /* # bytes output so far / current position. */ + bool byte_buffer_in_use; /* Whether byte ... */ + int byte; /* ... contains part of a bitfield byte yet to + be output. */ + + int last_relative_index; /* Implicit or explicit index of the last + array element output within a bitfield. */ + /* Current element. */ + tree val; /* Current element value. */ + tree index; /* Current element index. */ + +} oc_local_state; + +/* Helper for output_constructor. From the current LOCAL state, output a + RANGE_EXPR element. */ + +static void +output_constructor_array_range (oc_local_state *local) +{ + unsigned HOST_WIDE_INT fieldsize + = int_size_in_bytes (TREE_TYPE (local->type)); + + HOST_WIDE_INT lo_index + = tree_low_cst (TREE_OPERAND (local->index, 0), 0); + HOST_WIDE_INT hi_index + = tree_low_cst (TREE_OPERAND (local->index, 1), 0); + HOST_WIDE_INT index; + + unsigned int align2 + = min_align (local->align, fieldsize * BITS_PER_UNIT); + + for (index = lo_index; index <= hi_index; index++) + { + /* Output the element's initial value. */ + if (local->val == NULL_TREE) + assemble_zeros (fieldsize); + else + output_constant (local->val, fieldsize, align2); + + /* Count its size. */ + local->total_bytes += fieldsize; + } +} + +/* Helper for output_constructor. From the current LOCAL state, output a + field element that is not true bitfield or part of an outer one. */ + +static void +output_constructor_regular_field (oc_local_state *local) +{ + /* Field size and position. Since this structure is static, we know the + positions are constant. */ + unsigned HOST_WIDE_INT fieldsize; + HOST_WIDE_INT fieldpos; + + unsigned int align2; + + if (local->index != NULL_TREE) + fieldpos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (local->val)), 1) + * ((tree_low_cst (local->index, 0) + - tree_low_cst (local->min_index, 0)))); + else if (local->field != NULL_TREE) + fieldpos = int_byte_position (local->field); + else + fieldpos = 0; + + /* Output any buffered-up bit-fields preceding this element. */ + if (local->byte_buffer_in_use) + { + assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1); + local->total_bytes++; + local->byte_buffer_in_use = false; + } + + /* Advance to offset of this element. + Note no alignment needed in an array, since that is guaranteed + if each element has the proper size. */ + if ((local->field != NULL_TREE || local->index != NULL_TREE) + && fieldpos != local->total_bytes) + { + gcc_assert (fieldpos >= local->total_bytes); + assemble_zeros (fieldpos - local->total_bytes); + local->total_bytes = fieldpos; + } + + /* Find the alignment of this element. */ + align2 = min_align (local->align, BITS_PER_UNIT * fieldpos); + + /* Determine size this element should occupy. */ + if (local->field) + { + fieldsize = 0; + + /* If this is an array with an unspecified upper bound, + the initializer determines the size. */ + /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL, + but we cannot do this until the deprecated support for + initializing zero-length array members is removed. */ + if (TREE_CODE (TREE_TYPE (local->field)) == ARRAY_TYPE + && TYPE_DOMAIN (TREE_TYPE (local->field)) + && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (local->field)))) + { + fieldsize = array_size_for_constructor (local->val); + /* Given a non-empty initialization, this field had + better be last. */ + gcc_assert (!fieldsize || !TREE_CHAIN (local->field)); + } + else if (DECL_SIZE_UNIT (local->field)) + { + /* ??? This can't be right. If the decl size overflows + a host integer we will silently emit no data. */ + if (host_integerp (DECL_SIZE_UNIT (local->field), 1)) + fieldsize = tree_low_cst (DECL_SIZE_UNIT (local->field), 1); + } + } + else + fieldsize = int_size_in_bytes (TREE_TYPE (local->type)); + + /* Output the element's initial value. */ + if (local->val == NULL_TREE) + assemble_zeros (fieldsize); + else + output_constant (local->val, fieldsize, align2); + + /* Count its size. */ + local->total_bytes += fieldsize; +} + +/* Helper for output_constructor. From the current LOCAL and OUTER states, + output an element that is a true bitfield or part of an outer one. */ static void +output_constructor_bitfield (oc_local_state *local, oc_outer_state *outer) +{ + /* Bit size of this element. */ + HOST_WIDE_INT ebitsize + = (local->field + ? tree_low_cst (DECL_SIZE (local->field), 1) + : tree_low_cst (TYPE_SIZE (TREE_TYPE (local->type)), 1)); + + /* Relative index of this element if this is an array component. */ + HOST_WIDE_INT relative_index + = (!local->field + ? (local->index + ? (tree_low_cst (local->index, 0) + - tree_low_cst (local->min_index, 0)) + : local->last_relative_index + 1) + : 0); + + /* Bit position of this element from the start of the containing + constructor. */ + HOST_WIDE_INT constructor_relative_ebitpos + = (local->field + ? int_bit_position (local->field) + : ebitsize * relative_index); + + /* Bit position of this element from the start of a possibly ongoing + outer byte buffer. */ + HOST_WIDE_INT byte_relative_ebitpos + = ((outer ? outer->bit_offset : 0) + constructor_relative_ebitpos); + + /* From the start of a possibly ongoing outer byte buffer, offsets to + the first bit of this element and to the first bit past the end of + this element. */ + HOST_WIDE_INT next_offset = byte_relative_ebitpos; + HOST_WIDE_INT end_offset = byte_relative_ebitpos + ebitsize; + + local->last_relative_index = relative_index; + + if (local->val == NULL_TREE) + local->val = integer_zero_node; + + while (TREE_CODE (local->val) == VIEW_CONVERT_EXPR + || TREE_CODE (local->val) == NON_LVALUE_EXPR) + local->val = TREE_OPERAND (local->val, 0); + + if (TREE_CODE (local->val) != INTEGER_CST + && TREE_CODE (local->val) != CONSTRUCTOR) + { + error ("invalid initial value for member %qE", DECL_NAME (local->field)); + return; + } + + /* If this field does not start in this (or, next) byte, + skip some bytes. */ + if (next_offset / BITS_PER_UNIT != local->total_bytes) + { + /* Output remnant of any bit field in previous bytes. */ + if (local->byte_buffer_in_use) + { + assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1); + local->total_bytes++; + local->byte_buffer_in_use = false; + } + + /* If still not at proper byte, advance to there. */ + if (next_offset / BITS_PER_UNIT != local->total_bytes) + { + gcc_assert (next_offset / BITS_PER_UNIT >= local->total_bytes); + assemble_zeros (next_offset / BITS_PER_UNIT - local->total_bytes); + local->total_bytes = next_offset / BITS_PER_UNIT; + } + } + + /* Set up the buffer if necessary. */ + if (!local->byte_buffer_in_use) + { + local->byte = 0; + if (ebitsize > 0) + local->byte_buffer_in_use = true; + } + + /* If this is nested constructor, recurse passing the bit offset and the + pending data, then retrieve the new pending data afterwards. */ + if (TREE_CODE (local->val) == CONSTRUCTOR) + { + oc_outer_state output_state; + + output_state.bit_offset = next_offset % BITS_PER_UNIT; + output_state.byte = local->byte; + local->total_bytes + += output_constructor (local->val, 0, 0, &output_state); + local->byte = output_state.byte; + return; + } + + /* Otherwise, we must split the element into pieces that fall within + separate bytes, and combine each byte with previous or following + bit-fields. */ + while (next_offset < end_offset) + { + int this_time; + int shift; + HOST_WIDE_INT value; + HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT; + HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT; + + /* Advance from byte to byte + within this element when necessary. */ + while (next_byte != local->total_bytes) + { + assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1); + local->total_bytes++; + local->byte = 0; + } + + /* Number of bits we can process at once + (all part of the same byte). */ + this_time = MIN (end_offset - next_offset, + BITS_PER_UNIT - next_bit); + if (BYTES_BIG_ENDIAN) + { + /* On big-endian machine, take the most significant bits + first (of the bits that are significant) + and put them into bytes from the most significant end. */ + shift = end_offset - next_offset - this_time; + + /* Don't try to take a bunch of bits that cross + the word boundary in the INTEGER_CST. We can + only select bits from the LOW or HIGH part + not from both. */ + if (shift < HOST_BITS_PER_WIDE_INT + && shift + this_time > HOST_BITS_PER_WIDE_INT) + { + this_time = shift + this_time - HOST_BITS_PER_WIDE_INT; + shift = HOST_BITS_PER_WIDE_INT; + } + + /* Now get the bits from the appropriate constant word. */ + if (shift < HOST_BITS_PER_WIDE_INT) + value = TREE_INT_CST_LOW (local->val); + else + { + gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT); + value = TREE_INT_CST_HIGH (local->val); + shift -= HOST_BITS_PER_WIDE_INT; + } + + /* Get the result. This works only when: + 1 <= this_time <= HOST_BITS_PER_WIDE_INT. */ + local->byte |= (((value >> shift) + & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1)) + << (BITS_PER_UNIT - this_time - next_bit)); + } + else + { + /* On little-endian machines, + take first the least significant bits of the value + and pack them starting at the least significant + bits of the bytes. */ + shift = next_offset - byte_relative_ebitpos; + + /* Don't try to take a bunch of bits that cross + the word boundary in the INTEGER_CST. We can + only select bits from the LOW or HIGH part + not from both. */ + if (shift < HOST_BITS_PER_WIDE_INT + && shift + this_time > HOST_BITS_PER_WIDE_INT) + this_time = (HOST_BITS_PER_WIDE_INT - shift); + + /* Now get the bits from the appropriate constant word. */ + if (shift < HOST_BITS_PER_WIDE_INT) + value = TREE_INT_CST_LOW (local->val); + else + { + gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT); + value = TREE_INT_CST_HIGH (local->val); + shift -= HOST_BITS_PER_WIDE_INT; + } + + /* Get the result. This works only when: + 1 <= this_time <= HOST_BITS_PER_WIDE_INT. */ + local->byte |= (((value >> shift) + & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1)) + << next_bit); + } + + next_offset += this_time; + local->byte_buffer_in_use = true; + } +} + +/* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants). + Generate at least SIZE bytes, padding if necessary. OUTER designates the + caller output state of relevance in recursive invocations. */ + +static unsigned HOST_WIDE_INT output_constructor (tree exp, unsigned HOST_WIDE_INT size, - unsigned int align) -{ - tree type = TREE_TYPE (exp); - tree field = 0; - tree min_index = 0; - /* Number of bytes output or skipped so far. - In other words, current position within the constructor. */ - HOST_WIDE_INT total_bytes = 0; - /* Nonzero means BYTE contains part of a byte, to be output. */ - int byte_buffer_in_use = 0; - int byte = 0; + unsigned int align, oc_outer_state * outer) +{ unsigned HOST_WIDE_INT cnt; constructor_elt *ce; + oc_local_state local; + + /* Setup our local state to communicate with helpers. */ + local.exp = exp; + local.size = size; + local.align = align; + + local.total_bytes = 0; + local.byte_buffer_in_use = outer != NULL; + local.byte = outer ? outer->byte : 0; + + local.type = TREE_TYPE (exp); + + local.last_relative_index = -1; + + local.min_index = NULL_TREE; + if (TREE_CODE (local.type) == ARRAY_TYPE + && TYPE_DOMAIN (local.type) != NULL_TREE) + local.min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (local.type)); + gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT); - if (TREE_CODE (type) == RECORD_TYPE) - field = TYPE_FIELDS (type); - - if (TREE_CODE (type) == ARRAY_TYPE - && TYPE_DOMAIN (type) != 0) - min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); - - /* As LINK goes through the elements of the constant, - FIELD goes through the structure fields, if the constant is a structure. - if the constant is a union, then we override this, - by getting the field from the TREE_LIST element. + /* As CE goes through the elements of the constant, FIELD goes through the + structure fields if the constant is a structure. If the constant is a + union, we override this by getting the field from the TREE_LIST element. But the constant could also be an array. Then FIELD is zero. There is always a maximum of one element in the chain LINK for unions (even if the initializer in a source program incorrectly contains more one). */ + + local.field = NULL_TREE; + if (TREE_CODE (local.type) == RECORD_TYPE) + local.field = TYPE_FIELDS (local.type); + for (cnt = 0; VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce); - cnt++, field = field ? TREE_CHAIN (field) : 0) + cnt++, local.field = local.field ? TREE_CHAIN (local.field) : 0) { - tree val = ce->value; - tree index = 0; + local.val = ce->value; + local.index = NULL_TREE; /* The element in a union constructor specifies the proper field or index. */ - if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == QUAL_UNION_TYPE) - && ce->index != 0) - field = ce->index; - - else if (TREE_CODE (type) == ARRAY_TYPE) - index = ce->index; + if ((TREE_CODE (local.type) == RECORD_TYPE + || TREE_CODE (local.type) == UNION_TYPE + || TREE_CODE (local.type) == QUAL_UNION_TYPE) + && ce->index != NULL_TREE) + local.field = ce->index; + + else if (TREE_CODE (local.type) == ARRAY_TYPE) + local.index = ce->index; #ifdef ASM_COMMENT_START - if (field && flag_verbose_asm) + if (local.field && flag_verbose_asm) fprintf (asm_out_file, "%s %s:\n", ASM_COMMENT_START, - DECL_NAME (field) - ? IDENTIFIER_POINTER (DECL_NAME (field)) + DECL_NAME (local.field) + ? IDENTIFIER_POINTER (DECL_NAME (local.field)) : "<anonymous>"); #endif /* Eliminate the marker that makes a cast not be an lvalue. */ - if (val != 0) - STRIP_NOPS (val); - - if (index && TREE_CODE (index) == RANGE_EXPR) - { - unsigned HOST_WIDE_INT fieldsize - = int_size_in_bytes (TREE_TYPE (type)); - HOST_WIDE_INT lo_index = tree_low_cst (TREE_OPERAND (index, 0), 0); - HOST_WIDE_INT hi_index = tree_low_cst (TREE_OPERAND (index, 1), 0); - HOST_WIDE_INT index; - unsigned int align2 = min_align (align, fieldsize * BITS_PER_UNIT); - - for (index = lo_index; index <= hi_index; index++) - { - /* Output the element's initial value. */ - if (val == 0) - assemble_zeros (fieldsize); - else - output_constant (val, fieldsize, align2); - - /* Count its size. */ - total_bytes += fieldsize; - } - } - else if (field == 0 || !DECL_BIT_FIELD (field)) - { - /* An element that is not a bit-field. */ - - unsigned HOST_WIDE_INT fieldsize; - /* Since this structure is static, - we know the positions are constant. */ - HOST_WIDE_INT pos = field ? int_byte_position (field) : 0; - unsigned int align2; - - if (index != 0) - pos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (val)), 1) - * (tree_low_cst (index, 0) - tree_low_cst (min_index, 0))); - - /* Output any buffered-up bit-fields preceding this element. */ - if (byte_buffer_in_use) - { - assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1); - total_bytes++; - byte_buffer_in_use = 0; - } - - /* Advance to offset of this element. - Note no alignment needed in an array, since that is guaranteed - if each element has the proper size. */ - if ((field != 0 || index != 0) && pos != total_bytes) - { - gcc_assert (pos >= total_bytes); - assemble_zeros (pos - total_bytes); - total_bytes = pos; - } - - /* Find the alignment of this element. */ - align2 = min_align (align, BITS_PER_UNIT * pos); - - /* Determine size this element should occupy. */ - if (field) - { - fieldsize = 0; - - /* If this is an array with an unspecified upper bound, - the initializer determines the size. */ - /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL, - but we cannot do this until the deprecated support for - initializing zero-length array members is removed. */ - if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE - && TYPE_DOMAIN (TREE_TYPE (field)) - && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field)))) - { - fieldsize = array_size_for_constructor (val); - /* Given a non-empty initialization, this field had - better be last. */ - gcc_assert (!fieldsize || !TREE_CHAIN (field)); - } - else if (DECL_SIZE_UNIT (field)) - { - /* ??? This can't be right. If the decl size overflows - a host integer we will silently emit no data. */ - if (host_integerp (DECL_SIZE_UNIT (field), 1)) - fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1); - } - } - else - fieldsize = int_size_in_bytes (TREE_TYPE (type)); - - /* Output the element's initial value. */ - if (val == 0) - assemble_zeros (fieldsize); - else - output_constant (val, fieldsize, align2); - - /* Count its size. */ - total_bytes += fieldsize; - } - else if (val != 0 && TREE_CODE (val) != INTEGER_CST) - error ("invalid initial value for member %qs", - IDENTIFIER_POINTER (DECL_NAME (field))); + if (local.val != NULL_TREE) + STRIP_NOPS (local.val); + + /* Output the current element, using the appropriate helper ... */ + + /* For an array slice not part of an outer bitfield. */ + if (!outer + && local.index != NULL_TREE + && TREE_CODE (local.index) == RANGE_EXPR) + output_constructor_array_range (&local); + + /* For a field that is neither a true bitfield nor part of an outer one, + known to be at least byte aligned and multiple-of-bytes long. */ + else if (!outer + && (local.field == NULL_TREE + || !CONSTRUCTOR_BITFIELD_P (local.field))) + output_constructor_regular_field (&local); + + /* For a true bitfield or part of an outer one. */ else + output_constructor_bitfield (&local, outer); + } + + /* If we are not at toplevel, save the pending data for our caller. + Otherwise output the pending data and padding zeros as needed. */ + if (outer) + outer->byte = local.byte; + else + { + if (local.byte_buffer_in_use) { - /* Element that is a bit-field. */ - - HOST_WIDE_INT next_offset = int_bit_position (field); - HOST_WIDE_INT end_offset - = (next_offset + tree_low_cst (DECL_SIZE (field), 1)); - - if (val == 0) - val = integer_zero_node; - - /* If this field does not start in this (or, next) byte, - skip some bytes. */ - if (next_offset / BITS_PER_UNIT != total_bytes) - { - /* Output remnant of any bit field in previous bytes. */ - if (byte_buffer_in_use) - { - assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1); - total_bytes++; - byte_buffer_in_use = 0; - } - - /* If still not at proper byte, advance to there. */ - if (next_offset / BITS_PER_UNIT != total_bytes) - { - gcc_assert (next_offset / BITS_PER_UNIT >= total_bytes); - assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes); - total_bytes = next_offset / BITS_PER_UNIT; - } - } - - if (! byte_buffer_in_use) - byte = 0; - - /* We must split the element into pieces that fall within - separate bytes, and combine each byte with previous or - following bit-fields. */ - - /* next_offset is the offset n fbits from the beginning of - the structure to the next bit of this element to be processed. - end_offset is the offset of the first bit past the end of - this element. */ - while (next_offset < end_offset) - { - int this_time; - int shift; - HOST_WIDE_INT value; - HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT; - HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT; - - /* Advance from byte to byte - within this element when necessary. */ - while (next_byte != total_bytes) - { - assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1); - total_bytes++; - byte = 0; - } - - /* Number of bits we can process at once - (all part of the same byte). */ - this_time = MIN (end_offset - next_offset, - BITS_PER_UNIT - next_bit); - if (BYTES_BIG_ENDIAN) - { - /* On big-endian machine, take the most significant bits - first (of the bits that are significant) - and put them into bytes from the most significant end. */ - shift = end_offset - next_offset - this_time; - - /* Don't try to take a bunch of bits that cross - the word boundary in the INTEGER_CST. We can - only select bits from the LOW or HIGH part - not from both. */ - if (shift < HOST_BITS_PER_WIDE_INT - && shift + this_time > HOST_BITS_PER_WIDE_INT) - { - this_time = shift + this_time - HOST_BITS_PER_WIDE_INT; - shift = HOST_BITS_PER_WIDE_INT; - } - - /* Now get the bits from the appropriate constant word. */ - if (shift < HOST_BITS_PER_WIDE_INT) - value = TREE_INT_CST_LOW (val); - else - { - gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT); - value = TREE_INT_CST_HIGH (val); - shift -= HOST_BITS_PER_WIDE_INT; - } - - /* Get the result. This works only when: - 1 <= this_time <= HOST_BITS_PER_WIDE_INT. */ - byte |= (((value >> shift) - & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1)) - << (BITS_PER_UNIT - this_time - next_bit)); - } - else - { - /* On little-endian machines, - take first the least significant bits of the value - and pack them starting at the least significant - bits of the bytes. */ - shift = next_offset - int_bit_position (field); - - /* Don't try to take a bunch of bits that cross - the word boundary in the INTEGER_CST. We can - only select bits from the LOW or HIGH part - not from both. */ - if (shift < HOST_BITS_PER_WIDE_INT - && shift + this_time > HOST_BITS_PER_WIDE_INT) - this_time = (HOST_BITS_PER_WIDE_INT - shift); - - /* Now get the bits from the appropriate constant word. */ - if (shift < HOST_BITS_PER_WIDE_INT) - value = TREE_INT_CST_LOW (val); - else - { - gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT); - value = TREE_INT_CST_HIGH (val); - shift -= HOST_BITS_PER_WIDE_INT; - } - - /* Get the result. This works only when: - 1 <= this_time <= HOST_BITS_PER_WIDE_INT. */ - byte |= (((value >> shift) - & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1)) - << next_bit); - } - - next_offset += this_time; - byte_buffer_in_use = 1; - } + assemble_integer (GEN_INT (local.byte), 1, BITS_PER_UNIT, 1); + local.total_bytes++; + } + + if ((unsigned HOST_WIDE_INT)local.total_bytes < local.size) + { + assemble_zeros (local.size - local.total_bytes); + local.total_bytes = local.size; } } - if (byte_buffer_in_use) - { - assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1); - total_bytes++; - } - - if ((unsigned HOST_WIDE_INT)total_bytes < size) - assemble_zeros (size - total_bytes); + return local.total_bytes; } /* Mark DECL as weak. */ @@ -5071,9 +5227,6 @@ warning (0, "weak declaration of %q+D not supported", decl); mark_weak (decl); - if (!lookup_attribute ("weak", DECL_ATTRIBUTES (decl))) - DECL_ATTRIBUTES (decl) - = tree_cons (get_identifier ("weak"), NULL, DECL_ATTRIBUTES (decl)); } static void @@ -5143,7 +5296,8 @@ if (! decl) { - decl = build_decl (TREE_CODE (alias_decl), target, + decl = build_decl (DECL_SOURCE_LOCATION (alias_decl), + TREE_CODE (alias_decl), target, TREE_TYPE (alias_decl)); DECL_EXTERNAL (decl) = 1; @@ -5239,21 +5393,7 @@ 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 alias_pair GTY(()) -{ - 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. */ @@ -5279,13 +5419,7 @@ if (fnode) { - /* We can't mark function nodes as used after cgraph global info - is finished. This wouldn't generally be necessary, but C++ - virtual table thunks are introduced late in the game and - might seem like they need marking, although in fact they - don't. */ - if (! cgraph_global_info_ready) - cgraph_mark_needed_node (fnode); + cgraph_mark_needed_node (fnode); return fnode->decl; } else if (vnode) @@ -5332,7 +5466,8 @@ #else if (!SUPPORTS_WEAK) { - error ("%Jweakref is not supported in this configuration", decl); + error_at (DECL_SOURCE_LOCATION (decl), + "weakref is not supported in this configuration"); return; } #endif @@ -5396,6 +5531,39 @@ #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. */ @@ -5413,13 +5581,18 @@ if (target_decl == NULL) { if (! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))) - error ("%q+D aliased to undefined symbol %qs", - p->decl, IDENTIFIER_POINTER (p->target)); + error ("%q+D aliased to undefined symbol %qE", + p->decl, p->target); } else if (DECL_EXTERNAL (target_decl) + /* We use local aliases for C++ thunks to force the tailcall + to bind locally. Of course this is a hack - to keep it + working do the following (which is not strictly correct). */ + && (! TREE_CODE (target_decl) == FUNCTION_DECL + || ! DECL_VIRTUAL_P (target_decl)) && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))) - error ("%q+D aliased to external symbol %qs", - p->decl, IDENTIFIER_POINTER (p->target)); + error ("%q+D aliased to external symbol %qE", + p->decl, p->target); } } @@ -5472,12 +5645,14 @@ { #if !defined (ASM_OUTPUT_DEF) # if !defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL) - error ("%Jalias definitions not supported in this configuration", decl); + error_at (DECL_SOURCE_LOCATION (decl), + "alias definitions not supported in this configuration"); return; # else if (!DECL_WEAK (decl)) { - error ("%Jonly weak aliases are supported in this configuration", decl); + error_at (DECL_SOURCE_LOCATION (decl), + "only weak aliases are supported in this configuration"); return; } # endif @@ -5575,7 +5750,7 @@ translation units without generating a linker error. */ void -make_decl_one_only (tree decl) +make_decl_one_only (tree decl, tree comdat_group) { gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL); @@ -5587,7 +5762,7 @@ #ifdef MAKE_DECL_ONE_ONLY MAKE_DECL_ONE_ONLY (decl); #endif - DECL_ONE_ONLY (decl) = 1; + DECL_COMDAT_GROUP (decl) = comdat_group; } else if (TREE_CODE (decl) == VAR_DECL && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)) @@ -5847,8 +6022,13 @@ if (flags & SECTION_ENTSIZE) fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE); if (HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE)) - fprintf (asm_out_file, ",%s,comdat", - lang_hooks.decls.comdat_group (decl)); + { + if (TREE_CODE (decl) == IDENTIFIER_NODE) + fprintf (asm_out_file, ",%s,comdat", IDENTIFIER_POINTER (decl)); + else + fprintf (asm_out_file, ",%s,comdat", + IDENTIFIER_POINTER (DECL_COMDAT_GROUP (decl))); + } } putc ('\n', asm_out_file); @@ -6165,7 +6345,7 @@ /* If we're using one_only, then there needs to be a .gnu.linkonce prefix to the section name. */ linkonce = one_only ? ".gnu.linkonce" : ""; - + string = ACONCAT ((linkonce, prefix, ".", name, NULL)); DECL_SECTION_NAME (decl) = build_string (strlen (string), string); @@ -6265,8 +6445,8 @@ flags |= SYMBOL_FLAG_FUNCTION; if (targetm.binds_local_p (decl)) flags |= SYMBOL_FLAG_LOCAL; - if (targetm.have_tls && TREE_CODE (decl) == VAR_DECL - && DECL_THREAD_LOCAL_P (decl)) + if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl) + && DECL_TLS_MODEL (decl) != TLS_MODEL_EMULATED) flags |= DECL_TLS_MODEL (decl) << SYMBOL_FLAG_TLS_SHIFT; else if (targetm.in_small_data_p (decl)) flags |= SYMBOL_FLAG_SMALL; @@ -6400,14 +6580,6 @@ return local_p; } -/* Determine whether or not a pointer mode is valid. Assume defaults - of ptr_mode or Pmode - can be overridden. */ -bool -default_valid_pointer_mode (enum machine_mode mode) -{ - return (mode == ptr_mode || mode == Pmode); -} - /* Default function to output code that will globalize a label. A target must define GLOBAL_ASM_OP or provide its own function to globalize a label. */