X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fvarasm.c;h=c422fbc3a08f7062f71d49ca2953a243053ae812;hb=a5b6178ad69416a75e853de5e30edf2da815af22;hp=d725754c7e473fc2cb75790d2f54fa3184d9b5a7;hpb=b4cc3359b4d527f6be3e4c4a78d3b1dfd8b2008b;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/varasm.c b/gcc/varasm.c index d725754c7e4..c422fbc3a08 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -1,5 +1,5 @@ /* Output variables, constants and external declarations, for GNU compiler. - Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc. + Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc. This file is part of GNU CC. @@ -33,6 +33,7 @@ Boston, MA 02111-1307, USA. */ #include "rtl.h" #include "tree.h" #include "flags.h" +#include "except.h" #include "function.h" #include "expr.h" #include "output.h" @@ -51,6 +52,10 @@ Boston, MA 02111-1307, USA. */ #include +#ifndef TRAMPOLINE_ALIGNMENT +#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY +#endif + #ifndef ASM_STABS_OP #define ASM_STABS_OP ".stabs" #endif @@ -142,17 +147,21 @@ static int compare_constant_rtx PROTO((enum machine_mode, rtx, static struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode, rtx)); static struct pool_constant *find_pool_constant PROTO((rtx)); +static void mark_constant_pool PROTO((void)); +static void mark_constants PROTO((rtx)); static int output_addressed_constants PROTO((tree)); +static void output_after_function_constants PROTO((void)); static void bc_assemble_integer PROTO((tree, int)); static void output_constructor PROTO((tree, int)); +static enum in_section { no_section, in_text, in_data, in_named +#ifdef BSS_SECTION_ASM_OP + , in_bss +#endif #ifdef EXTRA_SECTIONS -static enum in_section {no_section, in_text, in_data, in_named, EXTRA_SECTIONS} in_section - = no_section; -#else -static enum in_section {no_section, in_text, in_data, in_named} in_section - = no_section; + , EXTRA_SECTIONS #endif +} in_section = no_section; /* Return a non-zero value if DECL has a section attribute. */ #define IN_NAMED_SECTION(DECL) \ @@ -223,7 +232,7 @@ readonly_data_section () #endif } -/* Determine if we're in the text section. */ +/* Determine if we're in the text section. */ int in_text_section () @@ -231,6 +240,14 @@ in_text_section () return in_section == in_text; } +/* Determine if we're in the data section. */ + +int +in_data_section () +{ + return in_section == in_data; +} + /* Tell assembler to change to section NAME for DECL. If DECL is NULL, just switch to section NAME. If NAME is NULL, get the name from DECL. */ @@ -241,14 +258,15 @@ named_section (decl, name) char *name; { if (decl != NULL_TREE - && (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL)) + && TREE_CODE_CLASS (TREE_CODE (decl)) != 'd') abort (); if (name == NULL) name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); if (in_section != in_named || strcmp (name, in_named_name)) { - in_named_name = name; + in_named_name = obstack_alloc (&permanent_obstack, strlen (name) + 1); + strcpy (in_named_name, name); in_section = in_named; #ifdef ASM_OUTPUT_SECTION_NAME @@ -262,6 +280,90 @@ named_section (decl, name) } } +#ifdef BSS_SECTION_ASM_OP + +/* Tell the assembler to switch to the bss section. */ + +void +bss_section () +{ + if (in_section != in_bss) + { + if (output_bytecode) + bc_data (); + else + { +#ifdef SHARED_BSS_SECTION_ASM_OP + if (flag_shared_data) + fprintf (asm_out_file, "%s\n", SHARED_BSS_SECTION_ASM_OP); + else +#endif + fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP); + } + + in_section = in_bss; + } +} + +#ifdef ASM_OUTPUT_BSS + +/* Utility function for ASM_OUTPUT_BSS for targets to use if + they don't support alignments in .bss. + ??? It is believed that this function will work in most cases so such + support is localized here. */ + +static void +asm_output_bss (file, decl, name, size, rounded) + FILE *file; + tree decl; + char *name; + int size, rounded; +{ + ASM_GLOBALIZE_LABEL (file, name); + bss_section (); +#ifdef ASM_DECLARE_OBJECT_NAME + last_assemble_variable_decl = decl; + ASM_DECLARE_OBJECT_NAME (file, name, decl); +#else + /* Standard thing is just output label for the object. */ + ASM_OUTPUT_LABEL (file, name); +#endif /* ASM_DECLARE_OBJECT_NAME */ + ASM_OUTPUT_SKIP (file, rounded); +} + +#endif + +#ifdef ASM_OUTPUT_ALIGNED_BSS + +/* Utility function for targets to use in implementing + ASM_OUTPUT_ALIGNED_BSS. + ??? It is believed that this function will work in most cases so such + support is localized here. */ + +static void +asm_output_aligned_bss (file, decl, name, size, align) + FILE *file; + tree decl; + char *name; + int size, align; +{ + ASM_GLOBALIZE_LABEL (file, name); + bss_section (); + ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); +#ifdef ASM_DECLARE_OBJECT_NAME + last_assemble_variable_decl = decl; + ASM_DECLARE_OBJECT_NAME (file, name, decl); +#else + /* Standard thing is just output label for the object. */ + ASM_OUTPUT_LABEL (file, name); +#endif /* ASM_DECLARE_OBJECT_NAME */ + ASM_OUTPUT_SKIP (file, size ? size : 1); +} + +#endif + +#endif /* BSS_SECTION_ASM_OP */ + /* Switch to the section for function DECL. If DECL is NULL_TREE, switch to the text section. @@ -278,6 +380,68 @@ function_section (decl) else text_section (); } + +/* Switch to section for variable DECL. + + RELOC is the `reloc' argument to SELECT_SECTION. */ + +void +variable_section (decl, reloc) + tree decl; + int reloc; +{ + if (IN_NAMED_SECTION (decl)) + named_section (decl, NULL); + else + { + /* C++ can have const variables that get initialized from constructors, + and thus can not be in a readonly section. We prevent this by + verifying that the initial value is constant for objects put in a + readonly section. + + error_mark_node is used by the C front end to indicate that the + initializer has not been seen yet. In this case, we assume that + the initializer must be constant. + + C++ uses error_mark_node for variables that have complicated + initializers, but these variables go in BSS so we won't be called + for them. */ + +#ifdef SELECT_SECTION + SELECT_SECTION (decl, reloc); +#else + if (TREE_READONLY (decl) + && ! TREE_THIS_VOLATILE (decl) + && DECL_INITIAL (decl) + && (DECL_INITIAL (decl) == error_mark_node + || TREE_CONSTANT (DECL_INITIAL (decl))) + && ! (flag_pic && reloc)) + readonly_data_section (); + else + data_section (); +#endif + } +} + +/* Tell assembler to switch to the section for the exception handling + table. */ + +void +exception_section () +{ +#ifdef ASM_OUTPUT_SECTION_NAME + named_section (NULL_TREE, ".gcc_except_table"); +#else + if (flag_pic) + data_section (); + else +#if defined (EXCEPTION_SECTION) + EXCEPTION_SECTION (); +#else + readonly_data_section (); +#endif +#endif +} /* Create the rtl to represent a function, for a function definition. DECL is a FUNCTION_DECL node which describes which function. @@ -549,24 +713,13 @@ make_decl_rtl (decl, asmspec, top_level) globalize_reg (reg_number + --nregs); } } - /* Specifying a section attribute on an uninitialized variable does not - (and cannot) cause it to be put in the given section. The linker - can only put initialized objects in specific sections, everything - else goes in bss for the linker to sort out later (otherwise the - linker would give a duplicate definition error for each compilation - unit that behaved thusly). So warn the user. */ + /* Specifying a section attribute on a variable forces it into a + non-.bss section, and thus it cannot be common. */ else if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE - && DECL_COMMON (decl) - && ! flag_no_common) - { - warning_with_decl (decl, - "section attribute ignored for uninitialized variable `%s'"); - /* Remove the section name so subsequent declarations won't see it. - We are ignoring it, remember. */ - DECL_SECTION_NAME (decl) = NULL_TREE; - } + && DECL_COMMON (decl)) + DECL_COMMON (decl) = 0; /* Now handle ordinary static variables and functions (in memory). Also handle vars declared register invalidly. */ @@ -753,6 +906,16 @@ assemble_gc_entry (name) #endif } +/* CONSTANT_POOL_BEFORE_FUNCTION may be defined as an expression with + a non-zero value if the constant pool should be output before the + start of the function, or a zero value if the pool should output + after the end of the function. The default is to put it before the + start. */ + +#ifndef CONSTANT_POOL_BEFORE_FUNCTION +#define CONSTANT_POOL_BEFORE_FUNCTION 1 +#endif + /* Output assembler code for the constant pool of a function and associated with defining the name of the function. DECL describes the function. NAME is the function's name. For the constant pool, we use the current @@ -769,7 +932,25 @@ assemble_start_function (decl, fnname) app_disable (); - output_constant_pool (fnname, decl); + if (CONSTANT_POOL_BEFORE_FUNCTION) + output_constant_pool (fnname, decl); + +#ifdef ASM_OUTPUT_SECTION_NAME + /* If the function is to be put in its own section and it's not in a section + already, indicate so. */ + if (flag_function_sections + && DECL_SECTION_NAME (decl) == NULL_TREE) + { +#ifdef UNIQUE_SECTION + DECL_SECTION_NAME(decl) = UNIQUE_SECTION (decl); +#else + char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + /* Strip off any encoding in name. */ + STRIP_NAME_ENCODING (name, name); + DECL_SECTION_NAME (decl) = build_string (strlen (name), name); +#endif + } +#endif function_section (decl); @@ -803,7 +984,8 @@ assemble_start_function (decl, fnname) if (TREE_PUBLIC (decl)) { - if (!first_global_object_name) + if (!first_global_object_name && ! DECL_WEAK (decl) + && ! DECL_ONE_ONLY (decl)) { char *p; @@ -824,15 +1006,17 @@ assemble_start_function (decl, fnname) } /* Do any machine/system dependent processing of the function name */ -#ifdef ASM_DECLARE_FUNCTION_NAME - ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl); -#else - /* Standard thing is just output label for the function. */ if (output_bytecode) BC_OUTPUT_LABEL (asm_out_file, fnname); else - ASM_OUTPUT_LABEL (asm_out_file, fnname); + { +#ifdef ASM_DECLARE_FUNCTION_NAME + ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl); +#else + /* Standard thing is just output label for the function. */ + ASM_OUTPUT_LABEL (asm_out_file, fnname); #endif /* ASM_DECLARE_FUNCTION_NAME */ + } } /* Output assembler code associated with defining the size of the @@ -846,6 +1030,11 @@ assemble_end_function (decl, fnname) #ifdef ASM_DECLARE_FUNCTION_SIZE ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl); #endif + if (! CONSTANT_POOL_BEFORE_FUNCTION) + output_constant_pool (fnname, decl); + + /* Output any constants which should appear after the function. */ + output_after_function_constants (); } /* Assemble code to leave SIZE bytes of zeros. */ @@ -1073,7 +1262,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data) /* This is better than explicit arithmetic, since it avoids overflow. */ size_tree = size_binop (CEIL_DIV_EXPR, - DECL_SIZE (decl), size_int (BITS_PER_UNIT)); + DECL_SIZE (decl), size_int (BITS_PER_UNIT)); if (TREE_INT_CST_HIGH (size_tree) != 0) { @@ -1084,23 +1273,33 @@ assemble_variable (decl, top_level, at_end, dont_output_data) name = XSTR (XEXP (DECL_RTL (decl), 0), 0); + if (TREE_PUBLIC (decl) && DECL_NAME (decl) + && ! first_global_object_name + && ! (DECL_COMMON (decl) && (DECL_INITIAL (decl) == 0 + || DECL_INITIAL (decl) == error_mark_node)) + && ! DECL_WEAK (decl) + && ! DECL_ONE_ONLY (decl)) + { + char *p; + + STRIP_NAME_ENCODING (p, name); + first_global_object_name = permalloc (strlen (p) + 1); + strcpy (first_global_object_name, p); + } + /* Handle uninitialized definitions. */ - /* ANSI specifies that a tentative definition which is not merged with - a non-tentative definition behaves exactly like a definition with an - initializer equal to zero. (Section 3.7.2) - -fno-common gives strict ANSI behavior. Usually you don't want it. - This matters only for variables with external linkage. */ - if ((! flag_no_common || ! TREE_PUBLIC (decl)) + if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node) + /* If the target can't output uninitialized but not common global data + in .bss, then we have to use .data. */ +#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS) && DECL_COMMON (decl) - && ! dont_output_data - && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)) +#endif + && ! dont_output_data) { int size = TREE_INT_CST_LOW (size_tree); int rounded = size; - if (TREE_INT_CST_HIGH (size_tree) != 0) - error_with_decl (decl, "size of variable `%s' is too large"); /* Don't allocate zero bytes of common, since that means "undefined external" in the linker. */ if (size == 0) rounded = 1; @@ -1131,11 +1330,17 @@ assemble_variable (decl, top_level, at_end, dont_output_data) while we are doing our final traversal of the chain of file-scope declarations. */ -#if 0 +#if 0 /* ??? We should either delete this or add a comment describing what + it was intended to do and why we shouldn't delete it. */ if (flag_shared_data) data_section (); #endif - if (TREE_PUBLIC (decl)) + + if (TREE_PUBLIC (decl) +#if defined (ASM_OUTPUT_BSS) || defined (ASM_OUTPUT_ALIGNED_BSS) + && DECL_COMMON (decl) +#endif + ) { #ifdef ASM_OUTPUT_SHARED_COMMON if (flag_shared_data) @@ -1156,6 +1361,29 @@ assemble_variable (decl, top_level, at_end, dont_output_data) #endif } } +#if defined (ASM_OUTPUT_BSS) || defined (ASM_OUTPUT_ALIGNED_BSS) + else if (TREE_PUBLIC (decl)) + { +#ifdef ASM_OUTPUT_SHARED_BSS + if (flag_shared_data) + ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded); + else +#endif + if (output_bytecode) + { + BC_OUTPUT_BSS (asm_out_file, name, size, rounded); + } + else + { +#ifdef ASM_OUTPUT_ALIGNED_BSS + ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, + DECL_ALIGN (decl)); +#else + ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded); +#endif + } + } +#endif /* ASM_OUTPUT_BSS || ASM_OUTPUT_ALIGNED_BSS */ else { #ifdef ASM_OUTPUT_SHARED_LOCAL @@ -1180,20 +1408,13 @@ assemble_variable (decl, top_level, at_end, dont_output_data) goto finish; } - /* Handle initialized definitions. */ + /* Handle initialized definitions. + Also handle uninitialized global definitions if -fno-common and the + target doesn't support ASM_OUTPUT_BSS. */ /* First make the assembler name(s) global if appropriate. */ if (TREE_PUBLIC (decl) && DECL_NAME (decl)) { - if (!first_global_object_name) - { - char *p; - - STRIP_NAME_ENCODING (p, name); - first_global_object_name = permalloc (strlen (p) + 1); - strcpy (first_global_object_name, p); - } - #ifdef ASM_WEAKEN_LABEL if (DECL_WEAK (decl)) ASM_WEAKEN_LABEL (asm_out_file, name); @@ -1217,33 +1438,8 @@ assemble_variable (decl, top_level, at_end, dont_output_data) else if (DECL_INITIAL (decl)) reloc = output_addressed_constants (DECL_INITIAL (decl)); - /* Switch to the proper section for this data. */ - if (IN_NAMED_SECTION (decl)) - named_section (decl, NULL); - else - { - /* C++ can have const variables that get initialized from constructors, - and thus can not be in a readonly section. We prevent this by - verifying that the initial value is constant for objects put in a - readonly section. - - error_mark_node is used by the C front end to indicate that the - initializer has not been seen yet. In this case, we assume that - the initializer must be constant. */ -#ifdef SELECT_SECTION - SELECT_SECTION (decl, reloc); -#else - if (TREE_READONLY (decl) - && ! TREE_THIS_VOLATILE (decl) - && DECL_INITIAL (decl) - && (DECL_INITIAL (decl) == error_mark_node - || TREE_CONSTANT (DECL_INITIAL (decl))) - && ! (flag_pic && reloc)) - readonly_data_section (); - else - data_section (); -#endif - } + /* Switch to the appropriate section. */ + variable_section (decl, reloc); /* dbxout.c needs to know this. */ if (in_text_section ()) @@ -1278,22 +1474,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data) /* If the debugging output changed sections, reselect the section that's supposed to be selected. */ if (in_section != saved_in_section) - { - /* Switch to the proper section for this data. */ -#ifdef SELECT_SECTION - SELECT_SECTION (decl, reloc); -#else - if (TREE_READONLY (decl) - && ! TREE_THIS_VOLATILE (decl) - && DECL_INITIAL (decl) - && (DECL_INITIAL (decl) == error_mark_node - || TREE_CONSTANT (DECL_INITIAL (decl))) - && ! (flag_pic && reloc)) - readonly_data_section (); - else - data_section (); -#endif - } + variable_section (decl, reloc); /* Compute and output the alignment of this data. */ @@ -1338,16 +1519,18 @@ assemble_variable (decl, top_level, at_end, dont_output_data) } /* Do any machine/system dependent processing of the object. */ -#ifdef ASM_DECLARE_OBJECT_NAME - last_assemble_variable_decl = decl; - ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl); -#else - /* Standard thing is just output label for the object. */ if (output_bytecode) BC_OUTPUT_LABEL (asm_out_file, name); else - ASM_OUTPUT_LABEL (asm_out_file, name); + { +#ifdef ASM_DECLARE_OBJECT_NAME + last_assemble_variable_decl = decl; + ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl); +#else + /* Standard thing is just output label for the object. */ + ASM_OUTPUT_LABEL (asm_out_file, name); #endif /* ASM_DECLARE_OBJECT_NAME */ + } if (!dont_output_data) { @@ -1375,22 +1558,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data) dbxout_symbol (decl, 0); if (in_section != saved_in_section) - { - /* Switch to the proper section for this data. */ -#ifdef SELECT_SECTION - SELECT_SECTION (decl, reloc); -#else - if (TREE_READONLY (decl) - && ! TREE_THIS_VOLATILE (decl) - && DECL_INITIAL (decl) - && (DECL_INITIAL (decl) == error_mark_node - || TREE_CONSTANT (DECL_INITIAL (decl))) - && ! (flag_pic && reloc)) - readonly_data_section (); - else - data_section (); -#endif - } + variable_section (decl, reloc); } #else /* There must be a statement after a label. */ @@ -1435,7 +1603,7 @@ contains_pointers_p (type) } } -/* Output text storage for constructor CONSTR. */ +/* Output text storage for constructor CONSTR. */ void bc_output_constructor (constr, size) @@ -1445,7 +1613,7 @@ bc_output_constructor (constr, size) int i; /* Must always be a literal; non-literal constructors are handled - differently. */ + differently. */ if (!TREE_CONSTANT (constr)) abort (); @@ -1464,7 +1632,7 @@ bc_output_constructor (constr, size) output_constant (constr, size); } -/* Create storage for constructor CONSTR. */ +/* Create storage for constructor CONSTR. */ void bc_output_data_constructor (constr) @@ -1480,7 +1648,7 @@ bc_output_data_constructor (constr) if (i > 0) BC_OUTPUT_ALIGN (asm_out_file, i); - /* The constructor is filled in at runtime. */ + /* The constructor is filled in at runtime. */ BC_OUTPUT_SKIP (asm_out_file, int_size_in_bytes (TREE_TYPE (constr))); } @@ -1564,15 +1732,13 @@ assemble_name (file, name) char *name; { char *real_name; - int save_warn_id_clash = warn_id_clash; + tree id; STRIP_NAME_ENCODING (real_name, name); - /* Don't warn about an identifier name length clash on this name, since - it can be a user symbol suffixed by a number. */ - warn_id_clash = 0; - TREE_SYMBOL_REFERENCED (get_identifier (real_name)) = 1; - warn_id_clash = save_warn_id_clash; + id = maybe_get_identifier (real_name); + if (id) + TREE_SYMBOL_REFERENCED (id) = 1; if (name[0] == '*') { @@ -1642,6 +1808,7 @@ assemble_static_space (size) This is done at most once per compilation. Returns an RTX for the address of the template. */ +#ifdef TRAMPOLINE_TEMPLATE rtx assemble_trampoline_template () { @@ -1662,7 +1829,7 @@ assemble_trampoline_template () #endif /* Write the assembler code to define one. */ - align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); + align = floor_log2 (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT); if (align > 0) ASM_OUTPUT_ALIGN (asm_out_file, align); @@ -1675,6 +1842,7 @@ assemble_trampoline_template () = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label)); return gen_rtx (SYMBOL_REF, Pmode, name); } +#endif /* Assemble the integer constant X into an object of SIZE bytes. X must be either a CONST_INT or CONST_DOUBLE. @@ -1689,7 +1857,7 @@ assemble_integer (x, size, force) int force; { /* First try to use the standard 1, 2, 4, 8, and 16 byte - ASM_OUTPUT... macros. */ + ASM_OUTPUT... macros. */ switch (size) { @@ -2133,6 +2301,7 @@ decode_addr_const (exp, value) case STRING_CST: case COMPLEX_CST: case CONSTRUCTOR: + case INTEGER_CST: x = TREE_CST_RTL (target); break; @@ -2181,80 +2350,100 @@ const_hash (exp) register int len, hi, i; register enum tree_code code = TREE_CODE (exp); - if (code == INTEGER_CST) + /* Either set P and LEN to the address and len of something to hash and + exit the switch or return a value. */ + + switch (code) { + case INTEGER_CST: p = (char *) &TREE_INT_CST_LOW (exp); len = 2 * sizeof TREE_INT_CST_LOW (exp); - } - else if (code == REAL_CST) - { + break; + + case REAL_CST: p = (char *) &TREE_REAL_CST (exp); len = sizeof TREE_REAL_CST (exp); - } - else if (code == STRING_CST) - p = TREE_STRING_POINTER (exp), len = TREE_STRING_LENGTH (exp); - else if (code == COMPLEX_CST) - return const_hash (TREE_REALPART (exp)) * 5 - + const_hash (TREE_IMAGPART (exp)); - else if (code == CONSTRUCTOR && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE) - { - len = int_size_in_bytes (TREE_TYPE (exp)); - p = (char*) alloca (len); - get_set_constructor_bytes (exp, (unsigned char *) p, len); - } - else if (code == CONSTRUCTOR) - { - register tree link; - - /* For record type, include the type in the hashing. - We do not do so for array types - because (1) the sizes of the elements are sufficient - and (2) distinct array types can have the same constructor. - Instead, we include the array size because the constructor could - be shorter. */ - if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE) - hi = ((HOST_WIDE_INT) TREE_TYPE (exp) & ((1 << HASHBITS) - 1)) - % MAX_HASH_TABLE; - else - hi = ((5 + int_size_in_bytes (TREE_TYPE (exp))) - & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE; + break; - for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) - if (TREE_VALUE (link)) - hi = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE; + case STRING_CST: + p = TREE_STRING_POINTER (exp); + len = TREE_STRING_LENGTH (exp); + break; - return hi; - } - else if (code == ADDR_EXPR) - { - struct addr_const value; - decode_addr_const (exp, &value); - if (GET_CODE (value.base) == SYMBOL_REF) + case COMPLEX_CST: + return (const_hash (TREE_REALPART (exp)) * 5 + + const_hash (TREE_IMAGPART (exp))); + + case CONSTRUCTOR: + if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE) { - /* Don't hash the address of the SYMBOL_REF; - only use the offset and the symbol name. */ - hi = value.offset; - p = XSTR (value.base, 0); - for (i = 0; p[i] != 0; i++) - hi = ((hi * 613) + (unsigned)(p[i])); + len = int_size_in_bytes (TREE_TYPE (exp)); + p = (char *) alloca (len); + get_set_constructor_bytes (exp, (unsigned char *) p, len); + break; } - else if (GET_CODE (value.base) == LABEL_REF) - hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13; + else + { + register tree link; + + /* For record type, include the type in the hashing. + We do not do so for array types + because (1) the sizes of the elements are sufficient + and (2) distinct array types can have the same constructor. + Instead, we include the array size because the constructor could + be shorter. */ + if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE) + hi = ((HOST_WIDE_INT) TREE_TYPE (exp) & ((1 << HASHBITS) - 1)) + % MAX_HASH_TABLE; + else + hi = ((5 + int_size_in_bytes (TREE_TYPE (exp))) + & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE; + + for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) + if (TREE_VALUE (link)) + hi + = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE; + + return hi; + } + + case ADDR_EXPR: + { + struct addr_const value; + + decode_addr_const (exp, &value); + if (GET_CODE (value.base) == SYMBOL_REF) + { + /* Don't hash the address of the SYMBOL_REF; + only use the offset and the symbol name. */ + hi = value.offset; + p = XSTR (value.base, 0); + for (i = 0; p[i] != 0; i++) + hi = ((hi * 613) + (unsigned) (p[i])); + } + else if (GET_CODE (value.base) == LABEL_REF) + hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13; - hi &= (1 << HASHBITS) - 1; - hi %= MAX_HASH_TABLE; + hi &= (1 << HASHBITS) - 1; + hi %= MAX_HASH_TABLE; + } return hi; + + case PLUS_EXPR: + case MINUS_EXPR: + return (const_hash (TREE_OPERAND (exp, 0)) * 9 + + const_hash (TREE_OPERAND (exp, 1))); + + case NOP_EXPR: + case CONVERT_EXPR: + case NON_LVALUE_EXPR: + return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2; } - else if (code == PLUS_EXPR || code == MINUS_EXPR) - return const_hash (TREE_OPERAND (exp, 0)) * 9 - + const_hash (TREE_OPERAND (exp, 1)); - else if (code == NOP_EXPR || code == CONVERT_EXPR) - return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2; /* Compute hashing function */ hi = len; for (i = 0; i < len; i++) - hi = ((hi * 613) + (unsigned)(p[i])); + hi = ((hi * 613) + (unsigned) (p[i])); hi &= (1 << HASHBITS) - 1; hi %= MAX_HASH_TABLE; @@ -2293,119 +2482,146 @@ compare_constant_1 (exp, p) if (code != (enum tree_code) *p++) return 0; - if (code == INTEGER_CST) + /* Either set STRP, P and LEN to pointers and length to compare and exit the + switch, or return the result of the comparison. */ + + switch (code) { + case INTEGER_CST: /* Integer constants are the same only if the same width of type. */ if (*p++ != TYPE_PRECISION (TREE_TYPE (exp))) return 0; + strp = (char *) &TREE_INT_CST_LOW (exp); len = 2 * sizeof TREE_INT_CST_LOW (exp); - } - else if (code == REAL_CST) - { + break; + + case REAL_CST: /* Real constants are the same only if the same width of type. */ if (*p++ != TYPE_PRECISION (TREE_TYPE (exp))) return 0; + strp = (char *) &TREE_REAL_CST (exp); len = sizeof TREE_REAL_CST (exp); - } - else if (code == STRING_CST) - { + break; + + case STRING_CST: if (flag_writable_strings) return 0; + strp = TREE_STRING_POINTER (exp); len = TREE_STRING_LENGTH (exp); if (bcmp ((char *) &TREE_STRING_LENGTH (exp), p, sizeof TREE_STRING_LENGTH (exp))) return 0; + p += sizeof TREE_STRING_LENGTH (exp); - } - else if (code == COMPLEX_CST) - { - p = compare_constant_1 (TREE_REALPART (exp), p); - if (p == 0) return 0; - p = compare_constant_1 (TREE_IMAGPART (exp), p); - return p; - } - else if (code == CONSTRUCTOR && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE) - { - len = int_size_in_bytes (TREE_TYPE (exp)); - strp = (char*) alloca (len); - get_set_constructor_bytes (exp, (unsigned char *) strp, len); - } - else if (code == CONSTRUCTOR) - { - register tree link; - int length = list_length (CONSTRUCTOR_ELTS (exp)); - tree type; + break; - if (bcmp ((char *) &length, p, sizeof length)) + case COMPLEX_CST: + p = compare_constant_1 (TREE_REALPART (exp), p); + if (p == 0) return 0; - p += sizeof length; - /* For record constructors, insist that the types match. - For arrays, just verify both constructors are for arrays. */ - if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE) - type = TREE_TYPE (exp); - else - type = 0; - if (bcmp ((char *) &type, p, sizeof type)) - return 0; - p += sizeof type; + return compare_constant_1 (TREE_IMAGPART (exp), p); - /* For arrays, insist that the size in bytes match. */ - if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE) + case CONSTRUCTOR: + if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE) { - int size = int_size_in_bytes (TREE_TYPE (exp)); - if (bcmp ((char *) &size, p, sizeof size)) + int xlen = len = int_size_in_bytes (TREE_TYPE (exp)); + + strp = (char *) alloca (len); + get_set_constructor_bytes (exp, (unsigned char *) strp, len); + if (bcmp ((char *) &xlen, p, sizeof xlen)) return 0; - p += sizeof size; - } - for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) + p += sizeof xlen; + break; + } + else { - if (TREE_VALUE (link)) + register tree link; + int length = list_length (CONSTRUCTOR_ELTS (exp)); + tree type; + + if (bcmp ((char *) &length, p, sizeof length)) + return 0; + + p += sizeof length; + + /* For record constructors, insist that the types match. + For arrays, just verify both constructors are for arrays. */ + if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE) + type = TREE_TYPE (exp); + else + type = 0; + + if (bcmp ((char *) &type, p, sizeof type)) + return 0; + + p += sizeof type; + + /* For arrays, insist that the size in bytes match. */ + if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE) { - if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0) + int size = int_size_in_bytes (TREE_TYPE (exp)); + if (bcmp ((char *) &size, p, sizeof size)) return 0; + + p += sizeof size; } - else + + for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) { - tree zero = 0; + if (TREE_VALUE (link)) + { + if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0) + return 0; + } + else + { + tree zero = 0; - if (bcmp ((char *) &zero, p, sizeof zero)) - return 0; - p += sizeof zero; + if (bcmp ((char *) &zero, p, sizeof zero)) + return 0; + + p += sizeof zero; + } } + + return p; } - return p; - } - else if (code == ADDR_EXPR) - { - struct addr_const value; - decode_addr_const (exp, &value); - strp = (char *) &value.offset; - len = sizeof value.offset; - /* Compare the offset. */ - while (--len >= 0) - if (*p++ != *strp++) - return 0; - /* Compare symbol name. */ - strp = XSTR (value.base, 0); - len = strlen (strp) + 1; - } - else if (code == PLUS_EXPR || code == MINUS_EXPR) - { - p = compare_constant_1 (TREE_OPERAND (exp, 0), p); - if (p == 0) return 0; - p = compare_constant_1 (TREE_OPERAND (exp, 1), p); - return p; - } - else if (code == NOP_EXPR || code == CONVERT_EXPR) - { + case ADDR_EXPR: + { + struct addr_const value; + + decode_addr_const (exp, &value); + strp = (char *) &value.offset; + len = sizeof value.offset; + /* Compare the offset. */ + while (--len >= 0) + if (*p++ != *strp++) + return 0; + + /* Compare symbol name. */ + strp = XSTR (value.base, 0); + len = strlen (strp) + 1; + } + break; + + case PLUS_EXPR: + case MINUS_EXPR: p = compare_constant_1 (TREE_OPERAND (exp, 0), p); - return p; + if (p == 0) + return 0; + + return compare_constant_1 (TREE_OPERAND (exp, 1), p); + + case NOP_EXPR: + case CONVERT_EXPR: + case NON_LVALUE_EXPR: + return compare_constant_1 (TREE_OPERAND (exp, 0), p); } /* Compare constant contents. */ @@ -2486,7 +2702,8 @@ record_constant_1 (exp) obstack_grow (&permanent_obstack, &nbytes, sizeof (nbytes)); obstack_blank (&permanent_obstack, nbytes); get_set_constructor_bytes - (exp, (unsigned char *) permanent_obstack.next_free, nbytes); + (exp, (unsigned char *) permanent_obstack.next_free-nbytes, + nbytes); return; } else @@ -2574,6 +2791,10 @@ struct deferred_constant static struct deferred_constant *deferred_constants; +/* Another list of constants which should be output after the + function. */ +static struct deferred_constant *after_function_constants; + /* Nonzero means defer output of addressed subconstants (i.e., those for which output_constant_def is called.) */ static int defer_addressed_constants_flag; @@ -2609,6 +2830,23 @@ output_deferred_addressed_constants () deferred_constants = 0; } +/* Output any constants which should appear after a function. */ + +static void +output_after_function_constants () +{ + struct deferred_constant *p, *next; + + for (p = after_function_constants; p; p = next) + { + output_constant_def_contents (p->exp, p->reloc, p->labelno); + next = p->next; + free (p); + } + + after_function_constants = 0; +} + /* Make a copy of the whole tree structure for a constant. This handles the same types of nodes that compare_constant and record_constant handle. */ @@ -2634,7 +2872,8 @@ copy_constant (exp) return copy_node (exp); case COMPLEX_CST: - return build_complex (copy_constant (TREE_REALPART (exp)), + return build_complex (TREE_TYPE (exp), + copy_constant (TREE_REALPART (exp)), copy_constant (TREE_IMAGPART (exp))); case PLUS_EXPR: @@ -2645,6 +2884,7 @@ copy_constant (exp) case NOP_EXPR: case CONVERT_EXPR: + case NON_LVALUE_EXPR: return build1 (TREE_CODE (exp), TREE_TYPE (exp), copy_constant (TREE_OPERAND (exp, 0))); @@ -2691,9 +2931,6 @@ output_constant_def (exp) int reloc; register rtx def; - if (TREE_CODE (exp) == INTEGER_CST) - abort (); /* No TREE_CST_RTL slot in these. */ - if (TREE_CST_RTL (exp)) return TREE_CST_RTL (exp); @@ -2764,7 +3001,15 @@ output_constant_def (exp) output it (or defer its output for later). */ if (found == 0) { - if (defer_addressed_constants_flag) + int after_function = 0; + +#ifdef CONSTANT_AFTER_FUNCTION_P + if (current_function_decl != 0 + && CONSTANT_AFTER_FUNCTION_P (exp)) + after_function = 1; +#endif + + if (defer_addressed_constants_flag || after_function) { struct deferred_constant *p; p = (struct deferred_constant *) xmalloc (sizeof (struct deferred_constant)); @@ -2775,8 +3020,16 @@ output_constant_def (exp) pop_obstacks (); p->reloc = reloc; p->labelno = const_labelno++; - p->next = deferred_constants; - deferred_constants = p; + if (after_function) + { + p->next = after_function_constants; + after_function_constants = p; + } + else + { + p->next = deferred_constants; + deferred_constants = p; + } } else output_constant_def_contents (exp, reloc, const_labelno++); @@ -2869,6 +3122,7 @@ struct pool_constant int labelno; int align; int offset; + int mark; }; /* Pointers to first and last constant in pool. */ @@ -2979,7 +3233,7 @@ decode_rtx_const (mode, x, value) *p++ = 0; } - value->kind = RTX_INT; /* Most usual kind. */ + value->kind = RTX_INT; /* Most usual kind. */ value->mode = mode; switch (GET_CODE (x)) @@ -3205,19 +3459,25 @@ force_const_mem (mode, x) pool_offset &= ~ (align - 1); /* If RTL is not being placed into the saveable obstack, make a - copy of X that is in the saveable obstack in case we are being - called from combine or some other phase that discards memory - it allocates. We need only do this if it is a CONST, since - no other RTX should be allocated in this situation. */ + copy of X that is in the saveable obstack in case we are + being called from combine or some other phase that discards + memory it allocates. We used to only do this if it is a + CONST; however, reload can allocate a CONST_INT when + eliminating registers. */ if (rtl_obstack != saveable_obstack - && GET_CODE (x) == CONST) + && (GET_CODE (x) == CONST || GET_CODE (x) == CONST_INT)) { push_obstacks_nochange (); rtl_in_saveable_obstack (); - x = gen_rtx (CONST, GET_MODE (x), - gen_rtx (PLUS, GET_MODE (x), - XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 0), 1))); + if (GET_CODE (x) == CONST) + x = gen_rtx (CONST, GET_MODE (x), + gen_rtx (PLUS, GET_MODE (x), + XEXP (XEXP (x, 0), 0), + XEXP (XEXP (x, 0), 1))); + else + x = GEN_INT (INTVAL (x)); + pop_obstacks (); } @@ -3230,6 +3490,7 @@ force_const_mem (mode, x) pool->labelno = const_labelno; pool->align = align; pool->offset = pool_offset; + pool->mark = 1; pool->next = 0; if (last_pool == 0) @@ -3343,6 +3604,12 @@ output_constant_pool (fnname, fndecl) rtx x; union real_extract u; + /* It is possible for gcc to call force_const_mem and then to later + discard the instructions which refer to the constant. In such a + case we do not need to output the constant. */ + if (optimize >= 0 && flag_expensive_optimizations) + mark_constant_pool (); + #ifdef ASM_OUTPUT_POOL_PROLOGUE ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset); #endif @@ -3351,6 +3618,9 @@ output_constant_pool (fnname, fndecl) { x = pool->constant; + if (! pool->mark) + continue; + /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF) whose CODE_LABEL has been deleted. This can occur if a jump table is eliminated by optimization. If so, write a constant of zero @@ -3406,9 +3676,100 @@ output_constant_pool (fnname, fndecl) done: ; } +#ifdef ASM_OUTPUT_POOL_EPILOGUE + ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool_offset); +#endif + /* Done with this pool. */ first_pool = last_pool = 0; } + +/* Look through the instructions for this function, and mark all the + entries in the constant pool which are actually being used. */ + +static void +mark_constant_pool () +{ + register rtx insn; + struct pool_constant *pool; + + if (first_pool == 0) + return; + + for (pool = first_pool; pool; pool = pool->next) + pool->mark = 0; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + mark_constants (PATTERN (insn)); + + for (insn = current_function_epilogue_delay_list; + insn; + insn = XEXP (insn, 1)) + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + mark_constants (PATTERN (insn)); +} + +static void +mark_constants (x) + register rtx x; +{ + register int i; + register char *format_ptr; + + if (x == 0) + return; + + if (GET_CODE (x) == SYMBOL_REF) + { + if (CONSTANT_POOL_ADDRESS_P (x)) + find_pool_constant (x)->mark = 1; + return; + } + + /* Insns may appear inside a SEQUENCE. Only check the patterns of + insns, not any notes that may be attached. We don't want to mark + a constant just because it happens to appear in a REG_EQUIV note. */ + if (GET_RTX_CLASS (GET_CODE (x)) == 'i') + { + mark_constants (PATTERN (x)); + return; + } + + format_ptr = GET_RTX_FORMAT (GET_CODE (x)); + + for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++) + { + switch (*format_ptr++) + { + case 'e': + mark_constants (XEXP (x, i)); + break; + + case 'E': + if (XVEC (x, i) != 0) + { + register int j; + + for (j = 0; j < XVECLEN (x, i); j++) + mark_constants (XVECEXP (x, i, j)); + } + break; + + case 'S': + case 's': + case '0': + case 'i': + case 'w': + case 'n': + case 'u': + break; + + default: + abort (); + } + } +} /* Find all the constants whose addresses are referenced inside of EXP, and make sure assembler code with a label has been output for each one. @@ -3603,7 +3964,7 @@ output_constant (exp, size) assemble_zeros (size); } -/* Bytecode specific code to output assembler for integer. */ +/* Bytecode specific code to output assembler for integer. */ static void bc_assemble_integer (exp, size) @@ -3621,7 +3982,8 @@ bc_assemble_integer (exp, size) exp = fold (exp); - while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR) + while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR + || TREE_CODE (exp) == NON_LVALUE_EXPR) exp = TREE_OPERAND (exp, 0); if (TREE_CODE (exp) == INTEGER_CST) { @@ -3632,11 +3994,13 @@ bc_assemble_integer (exp, size) { const_part = TREE_OPERAND (exp, 0); while (TREE_CODE (const_part) == NOP_EXPR - || TREE_CODE (const_part) == CONVERT_EXPR) + || TREE_CODE (const_part) == CONVERT_EXPR + || TREE_CODE (const_part) == NON_LVALUE_EXPR) const_part = TREE_OPERAND (const_part, 0); addr_part = TREE_OPERAND (exp, 1); while (TREE_CODE (addr_part) == NOP_EXPR - || TREE_CODE (addr_part) == CONVERT_EXPR) + || TREE_CODE (addr_part) == CONVERT_EXPR + || TREE_CODE (addr_part) == NON_LVALUE_EXPR) addr_part = TREE_OPERAND (addr_part, 0); if (TREE_CODE (const_part) != INTEGER_CST) tmp = const_part, const_part = addr_part, addr_part = tmp; @@ -3761,7 +4125,26 @@ output_constructor (exp, size) if (val != 0) STRIP_NOPS (val); - if (field == 0 || !DECL_BIT_FIELD (field)) + if (index && TREE_CODE (index) == RANGE_EXPR) + { + register int fieldsize + = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp))); + HOST_WIDE_INT lo_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 0)); + HOST_WIDE_INT hi_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 1)); + HOST_WIDE_INT index; + 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); + + /* Count its size. */ + total_bytes += fieldsize; + } + } + else if (field == 0 || !DECL_BIT_FIELD (field)) { /* An element that is not a bit-field. */ @@ -3970,6 +4353,7 @@ output_constructor (exp, size) } /* Output asm to handle ``#pragma weak'' */ + void handle_pragma_weak (what, name, value) enum pragma_state what; @@ -4037,12 +4421,12 @@ void assemble_alias (decl, target) tree decl, target; { -#ifdef ASM_OUTPUT_DEF char *name; - make_decl_rtl (decl, (char*)0, 1); + make_decl_rtl (decl, (char *) 0, 1); name = XSTR (XEXP (DECL_RTL (decl), 0), 0); +#ifdef ASM_OUTPUT_DEF /* Make name accessible from other files, if appropriate. */ if (TREE_PUBLIC (decl)) @@ -4061,6 +4445,64 @@ assemble_alias (decl, target) ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target)); TREE_ASM_WRITTEN (decl) = 1; #else - warning ("alias definitions not supported in this configuration"); +#ifdef ASM_OUTPUT_WEAK_ALIAS + if (! DECL_WEAK (decl)) + warning ("only weak aliases are supported in this configuration"); + + ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target)); + TREE_ASM_WRITTEN (decl) = 1; +#else + warning ("alias definitions not supported in this configuration; ignored"); +#endif +#endif +} + +/* This determines whether or not we support link-once semantics. */ +#ifndef SUPPORTS_ONE_ONLY +#ifdef MAKE_DECL_ONE_ONLY +#define SUPPORTS_ONE_ONLY 1 +#else +#define SUPPORTS_ONE_ONLY 0 +#endif #endif + +/* Returns 1 if the target configuration supports defining public symbols + so that one of them will be chosen at link time instead of generating a + multiply-defined symbol error, whether through the use of weak symbols or + a target-specific mechanism for having duplicates discarded. */ + +int +supports_one_only () +{ + if (SUPPORTS_ONE_ONLY) + return 1; + return SUPPORTS_WEAK; +} + +/* Set up DECL as a public symbol that can be defined in multiple + translation units without generating a linker error. */ + +void +make_decl_one_only (decl) + tree decl; +{ + if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) + abort (); + + TREE_PUBLIC (decl) = 1; + + if (TREE_CODE (decl) == VAR_DECL + && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)) + DECL_COMMON (decl) = 1; + else if (SUPPORTS_ONE_ONLY) + { +#ifdef MAKE_DECL_ONE_ONLY + MAKE_DECL_ONE_ONLY (decl); +#endif + DECL_ONE_ONLY (decl) = 1; + } + else if (SUPPORTS_WEAK) + DECL_WEAK (decl) = 1; + else + abort (); }