diff options
author | obrien <obrien@FreeBSD.org> | 1999-08-26 09:30:50 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 1999-08-26 09:30:50 +0000 |
commit | 0bedf4fb30066e5e1d4342a1d3914dae7d37cba7 (patch) | |
tree | 68d8110b41afd0ebbf39167b1a4918eea667a7c5 /contrib/gcc/varasm.c | |
parent | d4db5fb866b7ad5216abd5047774a3973b9901a9 (diff) | |
download | FreeBSD-src-0bedf4fb30066e5e1d4342a1d3914dae7d37cba7.zip FreeBSD-src-0bedf4fb30066e5e1d4342a1d3914dae7d37cba7.tar.gz |
Virgin import of gcc from EGCS 1.1.2
Diffstat (limited to 'contrib/gcc/varasm.c')
-rw-r--r-- | contrib/gcc/varasm.c | 1860 |
1 files changed, 1098 insertions, 762 deletions
diff --git a/contrib/gcc/varasm.c b/contrib/gcc/varasm.c index 12c935e..0055d68 100644 --- a/contrib/gcc/varasm.c +++ b/contrib/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-97, 1998 Free Software Foundation, Inc. This file is part of GNU CC. @@ -26,13 +26,14 @@ Boston, MA 02111-1307, USA. */ We also output the assembler code for constants stored in memory and are responsible for combining constants with the same value. */ -#include <stdio.h> +#include "config.h" +#include "system.h" #include <setjmp.h> /* #include <stab.h> */ -#include "config.h" #include "rtl.h" #include "tree.h" #include "flags.h" +#include "except.h" #include "function.h" #include "expr.h" #include "output.h" @@ -40,7 +41,9 @@ Boston, MA 02111-1307, USA. */ #include "regs.h" #include "defaults.h" #include "real.h" -#include "bytecode.h" +#include "toplev.h" +#include "dbxout.h" +#include "sdbout.h" #include "obstack.h" #include "c-pragma.h" @@ -49,12 +52,26 @@ Boston, MA 02111-1307, USA. */ #include "xcoffout.h" #endif -#include <ctype.h> +#ifndef TRAMPOLINE_ALIGNMENT +#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY +#endif #ifndef ASM_STABS_OP #define ASM_STABS_OP ".stabs" #endif +/* Define the prefix to use when check_memory_usage_flag is enable. */ +#ifdef NO_DOLLAR_IN_LABEL +#ifdef NO_DOT_IN_LABEL +#define CHKR_PREFIX "chkr_prefix_" +#else /* !NO_DOT_IN_LABEL */ +#define CHKR_PREFIX "chkr." +#endif +#else /* !NO_DOLLAR_IN_LABEL */ +#define CHKR_PREFIX "chkr$" +#endif +#define CHKR_PREFIX_SIZE (sizeof (CHKR_PREFIX) - 1) + /* This macro gets just the user-specified name out of the string in a SYMBOL_REF. On most machines, we discard the * if any and that's all. */ @@ -69,6 +86,7 @@ extern FILE *asm_out_file; /* The (assembler) name of the first globally-visible object output. */ char *first_global_object_name; +char *weak_global_object_name; extern struct obstack *current_obstack; extern struct obstack *saveable_obstack; @@ -121,9 +139,7 @@ struct constant_descriptor; struct rtx_const; struct pool_constant; -static void bc_make_decl_rtl PROTO((tree, char *, int)); static char *strip_reg_name PROTO((char *)); -static void bc_output_ascii PROTO((FILE *, char *, int)); static int contains_pointers_p PROTO((tree)); static void decode_addr_const PROTO((tree, struct addr_const *)); static int const_hash PROTO((tree)); @@ -142,17 +158,31 @@ 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 bc_assemble_integer PROTO((tree, int)); +static void output_after_function_constants PROTO((void)); static void output_constructor PROTO((tree, int)); +#ifdef ASM_OUTPUT_BSS +static void asm_output_bss PROTO((FILE *, tree, char *, int, int)); +#endif +#ifdef BSS_SECTION_ASM_OP +#ifdef ASM_OUTPUT_ALIGNED_BSS +static void asm_output_aligned_bss PROTO((FILE *, tree, char *, int, int)); +#endif +#endif /* BSS_SECTION_ASM_OP */ +static enum in_section { no_section, in_text, in_data, in_named +#ifdef BSS_SECTION_ASM_OP + , in_bss +#endif +#ifdef EH_FRAME_SECTION_ASM_OP + , in_eh_frame +#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) \ @@ -174,11 +204,7 @@ text_section () { if (in_section != in_text) { - if (output_bytecode) - bc_text (); - else - fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); - + fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); in_section = in_text; } } @@ -190,21 +216,16 @@ data_section () { if (in_section != in_data) { - if (output_bytecode) - bc_data (); - else + if (flag_shared_data) { - if (flag_shared_data) - { #ifdef SHARED_SECTION_ASM_OP - fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP); + fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP); #else - fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP); + fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP); #endif - } - else - fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP); } + else + fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP); in_section = in_data; } @@ -223,7 +244,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,37 +252,162 @@ 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. */ + If NAME is NULL, get the name from DECL. + If RELOC is 1, the initializer for DECL contains relocs. */ void -named_section (decl, name) +named_section (decl, name, reloc) tree decl; char *name; + int reloc; { 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_section = in_named; - #ifdef ASM_OUTPUT_SECTION_NAME - ASM_OUTPUT_SECTION_NAME (asm_out_file, decl, name); + ASM_OUTPUT_SECTION_NAME (asm_out_file, decl, name, reloc); #else /* Section attributes are not supported if this macro isn't provided - some host formats don't support them at all. The front-end should already have flagged this as an error. */ abort (); #endif + + in_named_name = obstack_alloc (&permanent_obstack, strlen (name) + 1); + strcpy (in_named_name, name); + in_section = in_named; + } +} + +#ifdef ASM_OUTPUT_SECTION_NAME +#ifndef UNIQUE_SECTION +#define UNIQUE_SECTION(DECL,RELOC) \ +do { \ + int len; \ + char *name, *string; \ + \ + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \ + /* Strip off any encoding in name. */ \ + STRIP_NAME_ENCODING (name, name); \ + \ + len = strlen (name) + 1; \ + string = alloca (len + 1); \ + sprintf (string, ".%s", name); \ + \ + DECL_SECTION_NAME (DECL) = build_string (len, string); \ +} while (0) +#endif +#ifndef UNIQUE_SECTION_P +#define UNIQUE_SECTION_P(DECL) 0 +#endif +#endif + +#ifdef BSS_SECTION_ASM_OP + +/* Tell the assembler to switch to the bss section. */ + +void +bss_section () +{ + if (in_section != in_bss) + { +#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 */ + +#ifdef EH_FRAME_SECTION_ASM_OP +void +eh_frame_section () +{ + if (in_section != in_eh_frame) + { + fprintf (asm_out_file, "%s\n", EH_FRAME_SECTION_ASM_OP); + in_section = in_eh_frame; + } +} +#endif + /* Switch to the section for function DECL. If DECL is NULL_TREE, switch to the text section. @@ -274,9 +420,66 @@ function_section (decl) { if (decl != NULL_TREE && DECL_SECTION_NAME (decl) != NULL_TREE) - named_section (decl, (char *) 0); - else - text_section (); + named_section (decl, (char *) 0, 0); + 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, reloc); + 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 (DECL_READONLY_SECTION (decl, reloc)) + readonly_data_section (); + else + data_section (); +#endif + } +} + +/* Tell assembler to switch to the section for the exception handling + table. */ + +void +exception_section () +{ +#if defined (EXCEPTION_SECTION) + EXCEPTION_SECTION (); +#else +#ifdef ASM_OUTPUT_SECTION_NAME + named_section (NULL_TREE, ".gcc_except_table", 0); +#else + if (flag_pic) + data_section (); + else + readonly_data_section (); +#endif +#endif } /* Create the rtl to represent a function, for a function definition. @@ -288,16 +491,7 @@ make_function_rtl (decl) tree decl; { char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - - if (output_bytecode) - { - if (DECL_RTL (decl) == 0) - DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0); - - /* Record that at least one function has been defined. */ - function_defined = 1; - return; - } + char *new_name = name; /* Rename a nested function to avoid conflicts. */ if (decl_function_context (decl) != 0 @@ -311,12 +505,26 @@ make_function_rtl (decl) name = obstack_copy0 (saveable_obstack, label, strlen (label)); var_labelno++; } + else + { + /* When -fprefix-function-name is used, every function name is + prefixed. Even static functions are prefixed because they + could be declared latter. Note that a nested function name + is not prefixed. */ + if (flag_prefix_function_name) + { + new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE + 1); + strcpy (new_name, CHKR_PREFIX); + strcpy (new_name + CHKR_PREFIX_SIZE, name); + name = obstack_copy0 (saveable_obstack, new_name, strlen (new_name)); + } + } if (DECL_RTL (decl) == 0) { DECL_RTL (decl) - = gen_rtx (MEM, DECL_MODE (decl), - gen_rtx (SYMBOL_REF, Pmode, name)); + = gen_rtx_MEM (DECL_MODE (decl), + gen_rtx_SYMBOL_REF (Pmode, name)); /* Optionally set flags or add text to the name to record information such as that it is a function name. If the name is changed, the macro @@ -325,54 +533,25 @@ make_function_rtl (decl) ENCODE_SECTION_INFO (decl); #endif } + else + { + /* ??? Another way to do this would be to do what halfpic.c does + and maintain a hashed table of such critters. */ + /* ??? Another way to do this would be to pass a flag bit to + ENCODE_SECTION_INFO saying whether this is a new decl or not. */ + /* Let the target reassign the RTL if it wants. + This is necessary, for example, when one machine specific + decl attribute overrides another. */ +#ifdef REDO_SECTION_INFO_P + if (REDO_SECTION_INFO_P (decl)) + ENCODE_SECTION_INFO (decl); +#endif + } /* Record at least one function has been defined. */ function_defined = 1; } -/* Create the DECL_RTL for a declaration for a static or external - variable or static or external function. - ASMSPEC, if not 0, is the string which the user specified - as the assembler symbol name. - TOP_LEVEL is nonzero if this is a file-scope variable. - This is never called for PARM_DECLs. */ - -static void -bc_make_decl_rtl (decl, asmspec, top_level) - tree decl; - char *asmspec; - int top_level; -{ - register char *name = TREE_STRING_POINTER (DECL_ASSEMBLER_NAME (decl)); - - if (DECL_RTL (decl) == 0) - { - /* Print an error message for register variables. */ - if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL) - error ("function declared `register'"); - else if (DECL_REGISTER (decl)) - error ("global register variables not supported in the interpreter"); - - /* Handle ordinary static variables and functions. */ - if (DECL_RTL (decl) == 0) - { - /* Can't use just the variable's own name for a variable - whose scope is less than the whole file. - Concatenate a distinguishing number. */ - if (!top_level && !DECL_EXTERNAL (decl) && asmspec == 0) - { - char *label; - - ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno); - name = obstack_copy0 (saveable_obstack, label, strlen (label)); - var_labelno++; - } - - DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0); - } - } -} - /* Given NAME, a putative register name, discard any customary prefixes. */ static char * @@ -465,12 +644,6 @@ make_decl_rtl (decl, asmspec, top_level) register char *name = 0; int reg_number; - if (output_bytecode) - { - bc_make_decl_rtl (decl, asmspec, top_level); - return; - } - reg_number = decode_reg_name (asmspec); if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE) @@ -489,33 +662,35 @@ make_decl_rtl (decl, asmspec, top_level) same DECL node. Don't discard the RTL already made. */ if (DECL_RTL (decl) == 0) { - DECL_RTL (decl) = 0; - /* First detect errors in declaring global registers. */ - if (DECL_REGISTER (decl) && reg_number == -1) + if (TREE_CODE (decl) != FUNCTION_DECL + && DECL_REGISTER (decl) && reg_number == -1) error_with_decl (decl, "register name not specified for `%s'"); - else if (DECL_REGISTER (decl) && reg_number < 0) + else if (TREE_CODE (decl) != FUNCTION_DECL + && DECL_REGISTER (decl) && reg_number < 0) error_with_decl (decl, "invalid register name for `%s'"); - else if ((reg_number >= 0 || reg_number == -3) && ! DECL_REGISTER (decl)) + else if ((reg_number >= 0 || reg_number == -3) + && (TREE_CODE (decl) == FUNCTION_DECL + && ! DECL_REGISTER (decl))) error_with_decl (decl, "register name given for non-register variable `%s'"); - else if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL) - error ("function declared `register'"); - else if (DECL_REGISTER (decl) && TYPE_MODE (TREE_TYPE (decl)) == BLKmode) - error_with_decl (decl, "data type of `%s' isn't suitable for a register"); - else if (DECL_REGISTER (decl) - && ! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl)))) - error_with_decl (decl, "register number for `%s' isn't suitable for the data type"); + else if (TREE_CODE (decl) != FUNCTION_DECL + && DECL_REGISTER (decl) + && TYPE_MODE (TREE_TYPE (decl)) == BLKmode) + error_with_decl (decl, + "data type of `%s' isn't suitable for a register"); + else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl) + && ! HARD_REGNO_MODE_OK (reg_number, + TYPE_MODE (TREE_TYPE (decl)))) + error_with_decl (decl, + "register number for `%s' isn't suitable for data type"); /* Now handle properly declared static register variables. */ - else if (DECL_REGISTER (decl)) + else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl)) { int nregs; -#if 0 /* yylex should print the warning for this */ - if (pedantic) - pedwarn ("ANSI C forbids global register variables"); -#endif + if (DECL_INITIAL (decl) != 0 && top_level) { DECL_INITIAL (decl) = 0; @@ -534,7 +709,7 @@ make_decl_rtl (decl, asmspec, top_level) kludge to avoid setting DECL_RTL to frame_pointer_rtx. */ DECL_RTL (decl) - = gen_rtx (REG, DECL_MODE (decl), FIRST_PSEUDO_REGISTER); + = gen_rtx_REG (DECL_MODE (decl), FIRST_PSEUDO_REGISTER); REGNO (DECL_RTL (decl)) = reg_number; REG_USERVAR_P (DECL_RTL (decl)) = 1; @@ -547,24 +722,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. */ @@ -573,7 +737,7 @@ make_decl_rtl (decl, asmspec, top_level) /* Can't use just the variable's own name for a variable whose scope is less than the whole file. Concatenate a distinguishing number. */ - if (!top_level && !DECL_EXTERNAL (decl) && asmspec == 0) + if (!top_level && !TREE_PUBLIC (decl) && asmspec == 0) { char *label; @@ -585,9 +749,24 @@ make_decl_rtl (decl, asmspec, top_level) if (name == 0) abort (); - DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl), - gen_rtx (SYMBOL_REF, Pmode, name)); + /* When -fprefix-function-name is used, the functions + names are prefixed. Only nested function names are not + prefixed. */ + if (flag_prefix_function_name && TREE_CODE (decl) == FUNCTION_DECL) + { + char *new_name; + new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE + + 1); + strcpy (new_name, CHKR_PREFIX); + strcpy (new_name + CHKR_PREFIX_SIZE, name); + name = obstack_copy0 (saveable_obstack, + new_name, strlen (new_name)); + } + DECL_RTL (decl) = gen_rtx_MEM (DECL_MODE (decl), + gen_rtx_SYMBOL_REF (Pmode, name)); + MEM_ALIAS_SET (DECL_RTL (decl)) = get_alias_set (decl); + /* If this variable is to be treated as volatile, show its tree node has side effects. If it has side effects, either because of this test or from TREE_THIS_VOLATILE also @@ -612,11 +791,26 @@ make_decl_rtl (decl, asmspec, top_level) #endif } } - /* If the old RTL had the wrong mode, fix the mode. */ - else if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl)) + else { - rtx rtl = DECL_RTL (decl); - PUT_MODE (rtl, DECL_MODE (decl)); + /* If the old RTL had the wrong mode, fix the mode. */ + if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl)) + { + rtx rtl = DECL_RTL (decl); + PUT_MODE (rtl, DECL_MODE (decl)); + } + + /* ??? Another way to do this would be to do what halfpic.c does + and maintain a hashed table of such critters. */ + /* ??? Another way to do this would be to pass a flag bit to + ENCODE_SECTION_INFO saying whether this is a new decl or not. */ + /* Let the target reassign the RTL if it wants. + This is necessary, for example, when one machine specific + decl attribute overrides another. */ +#ifdef REDO_SECTION_INFO_P + if (REDO_SECTION_INFO_P (decl)) + ENCODE_SECTION_INFO (decl); +#endif } } @@ -658,12 +852,6 @@ void assemble_asm (string) tree string; { - if (output_bytecode) - { - error ("asm statements not allowed in interpreter"); - return; - } - app_enable (); if (TREE_CODE (string) == ADDR_EXPR) @@ -751,6 +939,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 @@ -767,19 +965,24 @@ 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) + || UNIQUE_SECTION_P (decl)) + UNIQUE_SECTION (decl, 0); +#endif function_section (decl); /* Tell assembler to move to target machine's alignment for functions. */ align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); if (align > 0) - { - if (output_bytecode) - BC_OUTPUT_ALIGN (asm_out_file, align); - else - ASM_OUTPUT_ALIGN (asm_out_file, align); - } + ASM_OUTPUT_ALIGN (asm_out_file, align); #ifdef ASM_OUTPUT_FUNCTION_PREFIX ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname); @@ -801,13 +1004,19 @@ assemble_start_function (decl, fnname) if (TREE_PUBLIC (decl)) { - if (!first_global_object_name) + if (! first_global_object_name) { char *p; + char **name; + + if (! DECL_WEAK (decl) && ! DECL_ONE_ONLY (decl)) + name = &first_global_object_name; + else + name = &weak_global_object_name; STRIP_NAME_ENCODING (p, fnname); - first_global_object_name = permalloc (strlen (p) + 1); - strcpy (first_global_object_name, p); + *name = permalloc (strlen (p) + 1); + strcpy (*name, p); } #ifdef ASM_WEAKEN_LABEL @@ -815,10 +1024,7 @@ assemble_start_function (decl, fnname) ASM_WEAKEN_LABEL (asm_out_file, fnname); else #endif - if (output_bytecode) - BC_GLOBALIZE_LABEL (asm_out_file, fnname); - else - ASM_GLOBALIZE_LABEL (asm_out_file, fnname); + ASM_GLOBALIZE_LABEL (asm_out_file, fnname); } /* Do any machine/system dependent processing of the function name */ @@ -826,10 +1032,7 @@ assemble_start_function (decl, fnname) 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); + ASM_OUTPUT_LABEL (asm_out_file, fnname); #endif /* ASM_DECLARE_FUNCTION_NAME */ } @@ -844,6 +1047,14 @@ 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); + function_section (decl); /* need to switch back */ + } + + /* Output any constants which should appear after the function. */ + output_after_function_constants (); } /* Assemble code to leave SIZE bytes of zeros. */ @@ -852,12 +1063,6 @@ void assemble_zeros (size) int size; { - if (output_bytecode) - { - bc_emit_const_skip (size); - return; - } - #ifdef ASM_NO_SKIP_IN_TEXT /* The `space' pseudo in the text section outputs nop insns rather than 0s, so we must output 0s explicitly in the text section. */ @@ -891,12 +1096,7 @@ assemble_zeros (size) else #endif if (size > 0) - { - if (output_bytecode) - BC_OUTPUT_SKIP (asm_out_file, size); - else - ASM_OUTPUT_SKIP (asm_out_file, size); - } + ASM_OUTPUT_SKIP (asm_out_file, size); } /* Assemble an alignment pseudo op for an ALIGN-bit boundary. */ @@ -916,16 +1116,9 @@ assemble_string (p, size) char *p; int size; { - register int i; int pos = 0; int maximum = 2000; - if (output_bytecode) - { - bc_emit (p, size); - return; - } - /* If the string is very long, split it up. */ while (pos < size) @@ -934,26 +1127,13 @@ assemble_string (p, size) if (thissize > maximum) thissize = maximum; - if (output_bytecode) - bc_output_ascii (asm_out_file, p, thissize); - else - { - ASM_OUTPUT_ASCII (asm_out_file, p, thissize); - } + ASM_OUTPUT_ASCII (asm_out_file, p, thissize); pos += thissize; p += thissize; } } -static void -bc_output_ascii (file, p, size) - FILE *file; - char *p; - int size; -{ - BC_OUTPUT_ASCII (file, p, size); -} /* Assemble everything that is needed for a variable or function declaration. Not used for automatic variables, and not used for function definitions. @@ -973,16 +1153,13 @@ assemble_variable (decl, top_level, at_end, dont_output_data) int dont_output_data; { register char *name; - int align; + unsigned int align; tree size_tree; int reloc = 0; enum in_section saved_in_section; last_assemble_variable_decl = 0; - if (output_bytecode) - return; - if (GET_CODE (DECL_RTL (decl)) == REG) { /* Do output symbol info for global register variables, but do nothing @@ -992,22 +1169,19 @@ assemble_variable (decl, top_level, at_end, dont_output_data) return; TREE_ASM_WRITTEN (decl) = 1; - if (!output_bytecode) - { #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) - /* File-scope global variables are output here. */ - if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) - && top_level) - dbxout_symbol (decl, 0); + /* File-scope global variables are output here. */ + if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) + && top_level) + dbxout_symbol (decl, 0); #endif #ifdef SDB_DEBUGGING_INFO - if (write_symbols == SDB_DEBUG && top_level - /* Leave initialized global vars for end of compilation; - see comment in compile_file. */ - && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0)) - sdbout_symbol (decl, 0); + if (write_symbols == SDB_DEBUG && top_level + /* Leave initialized global vars for end of compilation; + see comment in compile_file. */ + && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0)) + sdbout_symbol (decl, 0); #endif - } /* Don't output any DWARF debugging information for variables here. In the case of local variables, the information for them is output @@ -1066,14 +1240,18 @@ assemble_variable (decl, top_level, at_end, dont_output_data) if (! dont_output_data) { + int size; + if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) goto finish; /* 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) + size = TREE_INT_CST_LOW (size_tree); + if (TREE_INT_CST_HIGH (size_tree) != 0 + || size != TREE_INT_CST_LOW (size_tree)) { error_with_decl (decl, "size of variable `%s' is too large"); goto finish; @@ -1082,23 +1260,70 @@ 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); + } + + /* Compute the alignment of this data. */ + + align = DECL_ALIGN (decl); + + /* In the case for initialing an array whose length isn't specified, + where we have not yet been able to do the layout, + figure out the proper alignment now. */ + if (dont_output_data && DECL_SIZE (decl) == 0 + && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl)))); + + /* Some object file formats have a maximum alignment which they support. + In particular, a.out format supports a maximum alignment of 4. */ +#ifndef MAX_OFILE_ALIGNMENT +#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT +#endif + if (align > MAX_OFILE_ALIGNMENT) + { + warning_with_decl (decl, + "alignment of `%s' is greater than maximum object file alignment. Using %d.", + MAX_OFILE_ALIGNMENT/BITS_PER_UNIT); + align = MAX_OFILE_ALIGNMENT; + } + + /* On some machines, it is good to increase alignment sometimes. */ +#ifdef DATA_ALIGNMENT + align = DATA_ALIGNMENT (TREE_TYPE (decl), align); +#endif +#ifdef CONSTANT_ALIGNMENT + if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node) + align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align); +#endif + + /* Reset the alignment in case we have made it tighter, so we can benefit + from it in get_pointer_alignment. */ + DECL_ALIGN (decl) = align; + /* 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; @@ -1107,7 +1332,13 @@ assemble_variable (decl, top_level, at_end, dont_output_data) rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1; rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); - + +#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS) + if ( (DECL_ALIGN (decl) / BITS_PER_UNIT) > rounded) + warning_with_decl + (decl, "requested alignment for %s is greater than implemented alignment of %d.",rounded); +#endif + #ifdef DBX_DEBUGGING_INFO /* File-scope global variables are output here. */ if (write_symbols == DBX_DEBUG && top_level) @@ -1129,31 +1360,55 @@ 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) ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded); else #endif - if (output_bytecode) - { - BC_OUTPUT_COMMON (asm_out_file, name, size, rounded); - } - else { +#ifdef ASM_OUTPUT_ALIGNED_DECL_COMMON + ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size, + DECL_ALIGN (decl)); +#else #ifdef ASM_OUTPUT_ALIGNED_COMMON ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl)); #else ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded); #endif +#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 + { +#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 @@ -1161,37 +1416,30 @@ assemble_variable (decl, top_level, at_end, dont_output_data) ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded); else #endif - if (output_bytecode) - { - BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded); - } - else { +#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL + ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size, + DECL_ALIGN (decl)); +#else #ifdef ASM_OUTPUT_ALIGNED_LOCAL ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl)); #else ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); #endif +#endif } } 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); @@ -1215,33 +1463,13 @@ 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 (); +#ifdef ASM_OUTPUT_SECTION_NAME + if (UNIQUE_SECTION_P (decl)) + UNIQUE_SECTION (decl, reloc); #endif - } + + /* Switch to the appropriate section. */ + variable_section (decl, reloc); /* dbxout.c needs to know this. */ if (in_text_section ()) @@ -1276,64 +1504,12 @@ 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 - } - - /* Compute and output the alignment of this data. */ - - align = DECL_ALIGN (decl); - /* In the case for initialing an array whose length isn't specified, - where we have not yet been able to do the layout, - figure out the proper alignment now. */ - if (dont_output_data && DECL_SIZE (decl) == 0 - && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) - align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl)))); - - /* Some object file formats have a maximum alignment which they support. - In particular, a.out format supports a maximum alignment of 4. */ -#ifndef MAX_OFILE_ALIGNMENT -#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT -#endif - if (align > MAX_OFILE_ALIGNMENT) - { - warning_with_decl (decl, - "alignment of `%s' is greater than maximum object file alignment"); - align = MAX_OFILE_ALIGNMENT; - } -#ifdef DATA_ALIGNMENT - /* On some machines, it is good to increase alignment sometimes. */ - align = DATA_ALIGNMENT (TREE_TYPE (decl), align); -#endif -#ifdef CONSTANT_ALIGNMENT - if (DECL_INITIAL (decl)) - align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align); -#endif - - /* Reset the alignment in case we have made it tighter, so we can benefit - from it in get_pointer_alignment. */ - DECL_ALIGN (decl) = align; + variable_section (decl, reloc); + /* Output the alignment of this data. */ if (align > BITS_PER_UNIT) - { - if (output_bytecode) - BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); - else - ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); - } + ASM_OUTPUT_ALIGN (asm_out_file, + floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT)); /* Do any machine/system dependent processing of the object. */ #ifdef ASM_DECLARE_OBJECT_NAME @@ -1341,10 +1517,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data) 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); + ASM_OUTPUT_LABEL (asm_out_file, name); #endif /* ASM_DECLARE_OBJECT_NAME */ if (!dont_output_data) @@ -1373,22 +1546,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. */ @@ -1433,55 +1591,6 @@ contains_pointers_p (type) } } -/* Output text storage for constructor CONSTR. */ - -void -bc_output_constructor (constr, size) - tree constr; - int size; -{ - int i; - - /* Must always be a literal; non-literal constructors are handled - differently. */ - - if (!TREE_CONSTANT (constr)) - abort (); - - /* Always const */ - text_section (); - - /* Align */ - for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++) - ; - - if (i > 0) - BC_OUTPUT_ALIGN (asm_out_file, i); - - /* Output data */ - output_constant (constr, size); -} - -/* Create storage for constructor CONSTR. */ - -void -bc_output_data_constructor (constr) - tree constr; -{ - int i; - - /* Put in data section */ - data_section (); - - /* Align */ - for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++); - if (i > 0) - BC_OUTPUT_ALIGN (asm_out_file, i); - - /* The constructor is filled in at runtime. */ - BC_OUTPUT_SKIP (asm_out_file, int_size_in_bytes (TREE_TYPE (constr))); -} - /* Output something to declare an external symbol to the assembler. (Most assemblers don't need this, so we normally output nothing.) Do nothing if DECL is not external. */ @@ -1490,9 +1599,6 @@ void assemble_external (decl) tree decl; { - if (output_bytecode) - return; - #ifdef ASM_OUTPUT_EXTERNAL if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd' && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl)) @@ -1517,14 +1623,11 @@ assemble_external_libcall (fun) rtx fun; { #ifdef ASM_OUTPUT_EXTERNAL_LIBCALL - if (!output_bytecode) + /* Declare library function name external when first used, if nec. */ + if (! SYMBOL_REF_USED (fun)) { - /* Declare library function name external when first used, if nec. */ - if (! SYMBOL_REF_USED (fun)) - { - SYMBOL_REF_USED (fun) = 1; - ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun); - } + SYMBOL_REF_USED (fun) = 1; + ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun); } #endif } @@ -1544,10 +1647,7 @@ void assemble_label (name) char *name; { - if (output_bytecode) - BC_OUTPUT_LABEL (asm_out_file, name); - else - ASM_OUTPUT_LABEL (asm_out_file, name); + ASM_OUTPUT_LABEL (asm_out_file, name); } /* Output to FILE a reference to the assembler name of a C-level name NAME. @@ -1562,30 +1662,21 @@ 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); + if (flag_prefix_function_name + && ! bcmp (real_name, CHKR_PREFIX, CHKR_PREFIX_SIZE)) + real_name = real_name + CHKR_PREFIX_SIZE; - /* 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] == '*') - { - if (output_bytecode) - bc_emit_labelref (name, 0); - else - fputs (&name[1], file); - } + fputs (&name[1], file); else - { - if (output_bytecode) - BC_OUTPUT_LABELREF (file, name); - else - ASM_OUTPUT_LABELREF (file, name); - } + ASM_OUTPUT_LABELREF (file, name); } /* Allocate SIZE bytes writable static space with a gensym name @@ -1598,11 +1689,6 @@ assemble_static_space (size) char name[12]; char *namestring; rtx x; - /* Round size up to multiple of BIGGEST_ALIGNMENT bits - so that each uninitialized object starts on such a boundary. */ - int rounded = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1) - / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); #if 0 if (flag_shared_data) @@ -1616,23 +1702,25 @@ assemble_static_space (size) strlen (name) + 2); strcpy (namestring, name); - if (output_bytecode) - x = bc_gen_rtx (namestring, 0, (struct bc_label *) 0); - else - x = gen_rtx (SYMBOL_REF, Pmode, namestring); + x = gen_rtx_SYMBOL_REF (Pmode, namestring); - if (output_bytecode) - { - BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded); - } - else - { +#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL + ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size, + BIGGEST_ALIGNMENT); +#else #ifdef ASM_OUTPUT_ALIGNED_LOCAL - ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT); + ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT); #else - ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); + { + /* Round size up to multiple of BIGGEST_ALIGNMENT bits + so that each uninitialized object starts on such a boundary. */ + int rounded = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1) + / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) + * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); + ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); + } +#endif #endif - } return x; } @@ -1648,10 +1736,6 @@ assemble_trampoline_template () char *name; int align; - /* Shouldn't get here */ - if (output_bytecode) - abort (); - /* By default, put trampoline templates in read-only data section. */ #ifdef TRAMPOLINE_SECTION @@ -1661,7 +1745,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); @@ -1672,7 +1756,7 @@ assemble_trampoline_template () ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0); name = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label)); - return gen_rtx (SYMBOL_REF, Pmode, name); + return gen_rtx_SYMBOL_REF (Pmode, name); } #endif @@ -1689,7 +1773,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) { @@ -1861,7 +1945,6 @@ immed_double_const (i0, i1, mode) enum machine_mode mode; { register rtx r; - int in_current_obstack; if (GET_MODE_CLASS (mode) == MODE_INT || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) @@ -1912,7 +1995,7 @@ immed_double_const (i0, i1, mode) is being broken. */ if (width <= HOST_BITS_PER_WIDE_INT) - i1 = (i0 < 0) ? ~0 : 0; + i1 = (i0 < 0) ? ~(HOST_WIDE_INT) 0 : 0; /* If this integer fits in one word, return a CONST_INT. */ if ((i1 == 0 && i0 >= 0) @@ -1941,7 +2024,7 @@ immed_double_const (i0, i1, mode) push_obstacks_nochange (); rtl_in_saveable_obstack (); - r = gen_rtx (CONST_DOUBLE, mode, 0, i0, i1); + r = gen_rtx_CONST_DOUBLE (mode, NULL_RTX, i0, i1); pop_obstacks (); /* Don't touch const_double_chain in nested function; see force_const_mem. @@ -1970,7 +2053,6 @@ immed_real_const_1 (d, mode) { union real_extract u; register rtx r; - int in_current_obstack; /* Get the desired `double' value as a sequence of ints since that is how they are stored in a CONST_DOUBLE. */ @@ -1979,8 +2061,7 @@ immed_real_const_1 (d, mode) /* Detect special cases. */ - /* Avoid REAL_VALUES_EQUAL here in order to distinguish minus zero. */ - if (!bcmp ((char *) &dconst0, (char *) &d, sizeof d)) + if (REAL_VALUES_IDENTICAL (dconst0, d)) return CONST0_RTX (mode); /* Check for NaN first, because some ports (specifically the i386) do not emit correct ieee-fp code by default, and thus will generate a core @@ -1989,6 +2070,8 @@ immed_real_const_1 (d, mode) else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d)) return CONST1_RTX (mode); + if (sizeof u == sizeof (HOST_WIDE_INT)) + return immed_double_const (u.i[0], 0, mode); if (sizeof u == 2 * sizeof (HOST_WIDE_INT)) return immed_double_const (u.i[0], u.i[1], mode); @@ -2120,19 +2203,16 @@ decode_addr_const (exp, value) break; case LABEL_DECL: - if (output_bytecode) - /* FIXME: this may not be correct, check it */ - x = bc_gen_rtx (TREE_STRING_POINTER (target), 0, (struct bc_label *) 0); - else - x = gen_rtx (MEM, FUNCTION_MODE, - gen_rtx (LABEL_REF, VOIDmode, - label_rtx (TREE_OPERAND (exp, 0)))); + x = gen_rtx_MEM (FUNCTION_MODE, + gen_rtx_LABEL_REF (VOIDmode, + label_rtx (TREE_OPERAND (exp, 0)))); break; case REAL_CST: case STRING_CST: case COMPLEX_CST: case CONSTRUCTOR: + case INTEGER_CST: x = TREE_CST_RTL (target); break; @@ -2140,12 +2220,9 @@ decode_addr_const (exp, value) abort (); } - if (!output_bytecode) - { - if (GET_CODE (x) != MEM) - abort (); - x = XEXP (x, 0); - } + if (GET_CODE (x) != MEM) + abort (); + x = XEXP (x, 0); value->base = x; value->offset = offset; @@ -2181,80 +2258,103 @@ 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) + { + len = int_size_in_bytes (TREE_TYPE (exp)); + p = (char *) alloca (len); + get_set_constructor_bytes (exp, (unsigned char *) p, len); + break; + } + else { - /* 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])); + 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 = ((unsigned long) 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; } - 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; + 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; + } 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; + + default: + abort (); } - 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 +2393,189 @@ 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; + + if (*p++ != TYPE_MODE (TREE_TYPE (exp))) + 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; + int have_purpose = 0; + + for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) + if (TREE_PURPOSE (link)) + have_purpose = 1; + + 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. + Then insist that either both or none have any TREE_PURPOSE + values. */ + 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; + + if (bcmp ((char *) &have_purpose, p, sizeof have_purpose)) + return 0; + + p += sizeof have_purpose; + + /* 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) + HOST_WIDE_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; + } + + if (TREE_PURPOSE (link) + && TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL) + { + if (bcmp ((char *) &TREE_PURPOSE (link), p, + sizeof TREE_PURPOSE (link))) + return 0; + + p += sizeof TREE_PURPOSE (link); + } + else if (TREE_PURPOSE (link)) + { + if ((p = compare_constant_1 (TREE_PURPOSE (link), p)) == 0) + return 0; + } + else if (have_purpose) + { + int zero = 0; + + 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); + + default: + abort (); } /* Compare constant contents. */ @@ -2468,6 +2638,7 @@ record_constant_1 (exp) if (flag_writable_strings) return; + obstack_1grow (&permanent_obstack, TYPE_MODE (TREE_TYPE (exp))); strp = TREE_STRING_POINTER (exp); len = TREE_STRING_LENGTH (exp); obstack_grow (&permanent_obstack, (char *) &TREE_STRING_LENGTH (exp), @@ -2486,7 +2657,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 @@ -2494,21 +2666,30 @@ record_constant_1 (exp) register tree link; int length = list_length (CONSTRUCTOR_ELTS (exp)); tree type; + int have_purpose = 0; + + for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) + if (TREE_PURPOSE (link)) + have_purpose = 1; obstack_grow (&permanent_obstack, (char *) &length, sizeof length); /* For record constructors, insist that the types match. - For arrays, just verify both constructors are for arrays. */ + For arrays, just verify both constructors are for arrays. + Then insist that either both or none have any TREE_PURPOSE + values. */ if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE) type = TREE_TYPE (exp); else type = 0; obstack_grow (&permanent_obstack, (char *) &type, sizeof type); + obstack_grow (&permanent_obstack, (char *) &have_purpose, + sizeof have_purpose); /* For arrays, insist that the size in bytes match. */ if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE) { - int size = int_size_in_bytes (TREE_TYPE (exp)); + HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); obstack_grow (&permanent_obstack, (char *) &size, sizeof size); } @@ -2523,6 +2704,21 @@ record_constant_1 (exp) obstack_grow (&permanent_obstack, (char *) &zero, sizeof zero); } + + if (TREE_PURPOSE (link) + && TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL) + obstack_grow (&permanent_obstack, + (char *) &TREE_PURPOSE (link), + sizeof TREE_PURPOSE (link)); + else if (TREE_PURPOSE (link)) + record_constant_1 (TREE_PURPOSE (link)); + else if (have_purpose) + { + int zero = 0; + + obstack_grow (&permanent_obstack, + (char *) &zero, sizeof zero); + } } } return; @@ -2574,6 +2770,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 +2809,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 +2851,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 +2863,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 +2910,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); @@ -2743,10 +2959,10 @@ output_constant_def (exp) if (TREE_PERMANENT (exp)) end_temporary_allocation (); - def = gen_rtx (SYMBOL_REF, Pmode, desc->label); + def = gen_rtx_SYMBOL_REF (Pmode, desc->label); TREE_CST_RTL (exp) - = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def); + = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), def); RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1; if (AGGREGATE_TYPE_P (TREE_TYPE (exp))) MEM_IN_STRUCT_P (TREE_CST_RTL (exp)) = 1; @@ -2764,7 +2980,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 +2999,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++); @@ -2797,7 +3029,7 @@ output_constant_def_contents (exp, reloc, labelno) int align; if (IN_NAMED_SECTION (exp)) - named_section (exp, NULL); + named_section (exp, NULL, reloc); else { /* First switch to text section, except for writable strings. */ @@ -2819,16 +3051,7 @@ output_constant_def_contents (exp, reloc, labelno) #endif if (align > BITS_PER_UNIT) - { - if (!output_bytecode) - { - ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); - } - else - { - BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); - } - } + ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); /* Output the label itself. */ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno); @@ -2869,6 +3092,7 @@ struct pool_constant int labelno; int align; int offset; + int mark; }; /* Pointers to first and last constant in pool. */ @@ -2896,7 +3120,7 @@ static struct pool_sym **const_rtx_sym_hash_table; The argument is XSTR (... , 0) */ #define SYMHASH(LABEL) \ - ((((HOST_WIDE_INT) (LABEL)) & ((1 << HASHBITS) - 1)) % MAX_RTX_HASH_TABLE) + ((((unsigned long) (LABEL)) & ((1 << HASHBITS) - 1)) % MAX_RTX_HASH_TABLE) /* Initialize constant pool hashing for next function. */ @@ -2921,14 +3145,20 @@ init_const_rtx_hash_table () /* Save and restore status for a nested function. */ void -save_varasm_status (p) +save_varasm_status (p, context) struct function *p; + tree context; { p->const_rtx_hash_table = const_rtx_hash_table; p->const_rtx_sym_hash_table = const_rtx_sym_hash_table; p->first_pool = first_pool; p->last_pool = last_pool; p->pool_offset = pool_offset; + p->const_double_chain = const_double_chain; + + /* If we are pushing to toplevel, we can't reuse const_double_chain. */ + if (context == NULL_TREE) + const_double_chain = 0; } void @@ -2940,6 +3170,7 @@ restore_varasm_status (p) first_pool = p->first_pool; last_pool = p->last_pool; pool_offset = p->pool_offset; + const_double_chain = p->const_double_chain; } enum kind { RTX_DOUBLE, RTX_INT }; @@ -2979,7 +3210,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)) @@ -3042,6 +3273,9 @@ decode_rtx_const (mode, x, value) for the sake of addresses of library routines. For a LABEL_REF, compare labels. */ value->un.addr.base = XEXP (value->un.addr.base, 0); + + default: + break; } } @@ -3069,7 +3303,8 @@ const_hash_rtx (mode, x) enum machine_mode mode; rtx x; { - register int hi, i; + register int hi; + register size_t i; struct rtx_const value; decode_rtx_const (mode, x, &value); @@ -3200,24 +3435,34 @@ force_const_mem (mode, x) align = (mode == VOIDmode) ? UNITS_PER_WORD : GET_MODE_SIZE (mode); if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT) align = BIGGEST_ALIGNMENT / BITS_PER_UNIT; +#ifdef CONSTANT_ALIGNMENT + align = CONSTANT_ALIGNMENT (make_tree (type_for_mode (mode, 0), x), + align * BITS_PER_UNIT) / BITS_PER_UNIT; +#endif pool_offset += align - 1; 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 +3475,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) @@ -3259,7 +3505,7 @@ force_const_mem (mode, x) /* We have a symbol name; construct the SYMBOL_REF and the MEM. */ - def = gen_rtx (MEM, mode, gen_rtx (SYMBOL_REF, Pmode, found)); + def = gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (Pmode, found)); RTX_UNCHANGING_P (def) = 1; /* Mark the symbol_ref as belonging to this constants pool. */ @@ -3343,6 +3589,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 +3603,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 @@ -3403,12 +3658,113 @@ output_constant_pool (fnname, fndecl) abort (); } +#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY done: ; +#endif + } +#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; + } + /* Never search inside a CONST_DOUBLE, because CONST_DOUBLE_MEM may be + a MEM, but does not constitute a use of that MEM. This is particularly + important inside a nested function, because CONST_DOUBLE_MEM may be + a reference to a MEM in the parent's constant pool. See the comment + in force_const_mem. */ + else if (GET_CODE (x) == CONST_DOUBLE) + 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. @@ -3461,7 +3817,7 @@ output_addressed_constants (exp) } break; - case ERROR_MARK: + default: break; } return reloc; @@ -3491,7 +3847,6 @@ output_constant (exp, size) register int size; { register enum tree_code code = TREE_CODE (TREE_TYPE (exp)); - rtx x; if (size == 0) return; @@ -3509,10 +3864,7 @@ output_constant (exp, size) This means to fill the space with zeros. */ if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0) { - if (output_bytecode) - bc_emit_const_skip (size); - else - assemble_zeros (size); + assemble_zeros (size); return; } @@ -3597,110 +3949,15 @@ output_constant (exp, size) else error ("unknown set constructor type"); return; + + default: + break; /* ??? */ } if (size > 0) assemble_zeros (size); } -/* Bytecode specific code to output assembler for integer. */ - -static void -bc_assemble_integer (exp, size) - tree exp; - int size; -{ - tree const_part; - tree addr_part; - tree tmp; - - /* FIXME: is this fold() business going to be as good as the - expand_expr() using EXPAND_SUM above in the RTL case? I - hate RMS. - FIXME: Copied as is from BC-GCC1; may need work. Don't hate. -bson */ - - exp = fold (exp); - - while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR) - exp = TREE_OPERAND (exp, 0); - if (TREE_CODE (exp) == INTEGER_CST) - { - const_part = exp; - addr_part = 0; - } - else if (TREE_CODE (exp) == PLUS_EXPR) - { - const_part = TREE_OPERAND (exp, 0); - while (TREE_CODE (const_part) == NOP_EXPR - || TREE_CODE (const_part) == CONVERT_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) - addr_part = TREE_OPERAND (addr_part, 0); - if (TREE_CODE (const_part) != INTEGER_CST) - tmp = const_part, const_part = addr_part, addr_part = tmp; - if (TREE_CODE (const_part) != INTEGER_CST - || TREE_CODE (addr_part) != ADDR_EXPR) - abort (); /* FIXME: we really haven't considered - all the possible cases here. */ - } - else if (TREE_CODE (exp) == ADDR_EXPR) - { - const_part = integer_zero_node; - addr_part = exp; - } - else - abort (); /* FIXME: ditto previous. */ - - if (addr_part == 0) - { - if (size == 1) - { - char c = TREE_INT_CST_LOW (const_part); - bc_emit (&c, 1); - size -= 1; - } - else if (size == 2) - { - short s = TREE_INT_CST_LOW (const_part); - bc_emit ((char *) &s, 2); - size -= 2; - } - else if (size == 4) - { - int i = TREE_INT_CST_LOW (const_part); - bc_emit ((char *) &i, 4); - size -= 4; - } - else if (size == 8) - { - if (WORDS_BIG_ENDIAN) - { - int i = TREE_INT_CST_HIGH (const_part); - bc_emit ((char *) &i, 4); - i = TREE_INT_CST_LOW (const_part); - bc_emit ((char *) &i, 4); - } - else - { - int i = TREE_INT_CST_LOW (const_part); - bc_emit ((char *) &i, 4); - i = TREE_INT_CST_HIGH (const_part); - bc_emit ((char *) &i, 4); - } - size -= 8; - } - } - else - if (size == 4 - && TREE_CODE (TREE_OPERAND (addr_part, 0)) == VAR_DECL) - bc_emit_labelref (IDENTIFIER_POINTER - (DECL_ASSEMBLER_NAME (TREE_OPERAND (addr_part, 0))), - TREE_INT_CST_LOW (const_part)); - else - abort (); /* FIXME: there may be more cases. */ -} /* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants). @@ -3761,7 +4018,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. */ @@ -3789,10 +4065,7 @@ output_constructor (exp, size) if each element has the proper size. */ if ((field != 0 || index != 0) && bitpos != total_bytes) { - if (!output_bytecode) - assemble_zeros (bitpos - total_bytes); - else - bc_emit_const_skip (bitpos - total_bytes); + assemble_zeros (bitpos - total_bytes); total_bytes = bitpos; } @@ -3942,7 +4215,7 @@ output_constructor (exp, size) } /* Now get the bits from the appropriate constant word. */ - if (shift < HOST_BITS_PER_INT) + if (shift < HOST_BITS_PER_WIDE_INT) value = TREE_INT_CST_LOW (val); else if (shift < 2 * HOST_BITS_PER_WIDE_INT) { @@ -3970,6 +4243,7 @@ output_constructor (exp, size) } /* Output asm to handle ``#pragma weak'' */ + void handle_pragma_weak (what, name, value) enum pragma_state what; @@ -4012,6 +4286,13 @@ declare_weak (decl) error_with_decl (decl, "weak declaration of `%s' must precede definition"); else if (SUPPORTS_WEAK) DECL_WEAK (decl) = 1; + +#ifdef HANDLE_PRAGMA_WEAK + /* Make sure this function name gets on the weak declaration list. */ + handle_pragma_weak (ps_name, + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), + NULL); +#endif } /* Emit any pending weak declarations. */ @@ -4037,12 +4318,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)) @@ -4052,15 +4333,70 @@ assemble_alias (decl, target) ASM_WEAKEN_LABEL (asm_out_file, name); else #endif - if (output_bytecode) - BC_GLOBALIZE_LABEL (asm_out_file, name); - else ASM_GLOBALIZE_LABEL (asm_out_file, name); } 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 (); } |