/* Output variables, constants and external declarations, for GNU compiler.
- Copyright (C) 1987, 88, 89, 92-5, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
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"
#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"
#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. */
/* 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;
tree last_assemble_variable_decl;
-
-#ifdef HANDLE_PRAGMA_WEAK
-/* Any weak symbol declarations waiting to be emitted. */
-
-struct weak_syms
-{
- struct weak_syms *next;
- char *name;
- char *value;
-};
-
-static struct weak_syms *weak_decls;
-#endif
-
/* Nonzero if at least one function definition has been seen. */
static int function_defined;
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));
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 */
\f
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
, EXTRA_SECTIONS
#endif
{
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;
}
}
{
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;
}
#endif
}
-/* Determine if we're in the text section. */
+/* Determine if we're in the text section. */
int
in_text_section ()
return in_section == in_text;
}
-/* Determine if we're in the data section. */
+/* Determine if we're in the data section. */
int
in_data_section ()
/* 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_CLASS (TREE_CODE (decl)) != 'd')
if (in_section != in_named || strcmp (name, in_named_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
- 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 (decl, name)
+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
+ 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);
- }
+ fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP);
in_section = in_bss;
}
support is localized here. */
static void
-asm_output_bss (file, name, size, rounded)
+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);
}
support is localized here. */
static void
-asm_output_aligned_bss (file, name, size, align)
+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);
- ASM_OUTPUT_SKIP (file, size);
+#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.
{
if (decl != NULL_TREE
&& DECL_SECTION_NAME (decl) != NULL_TREE)
- named_section (decl, (char *) 0);
+ named_section (decl, (char *) 0, 0);
else
text_section ();
}
int reloc;
{
if (IN_NAMED_SECTION (decl))
- named_section (decl, NULL);
+ named_section (decl, NULL, reloc);
else
{
/* C++ can have const variables that get initialized from constructors,
#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))
+ 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
+}
\f
/* Create the rtl to represent a function, for a function definition.
DECL is a FUNCTION_DECL node which describes which function.
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
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
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))
- 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 *
static struct { char *name; int number; } table[]
= ADDITIONAL_REGISTER_NAMES;
- for (i = 0; i < sizeof (table) / sizeof (table[0]); i++)
+ for (i = 0; i < (int)(sizeof (table) / sizeof (table[0])); i++)
if (! strcmp (asmspec, table[i].name))
return table[i].number;
}
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)
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 (TREE_CODE (decl) != FUNCTION_DECL
&& DECL_REGISTER (decl) && reg_number == -1)
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;
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))
- {
- 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) = 0;
/* Now handle ordinary static variables and functions (in memory).
Also handle vars declared register invalidly. */
/* 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;
if (name == 0)
abort ();
- DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl),
- gen_rtx (SYMBOL_REF, Pmode, name));
- DECL_ASSEMBLER_NAME (decl) = get_identifier (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
#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
}
}
assemble_asm (string)
tree string;
{
- if (output_bytecode)
- {
- error ("asm statements not allowed in interpreter");
- return;
- }
-
app_enable ();
if (TREE_CODE (string) == ADDR_EXPR)
#endif
}
\f
+/* 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
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
- }
+ 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);
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
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 */
- if (output_bytecode)
- BC_OUTPUT_LABEL (asm_out_file, fnname);
- else
- {
#ifdef ASM_DECLARE_FUNCTION_NAME
- ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
+ 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);
+ /* 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
#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 ();
}
\f
/* Assemble code to leave SIZE bytes of zeros. */
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. */
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. */
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)
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);
-}
\f
/* Assemble everything that is needed for a variable or function declaration.
Not used for automatic variables, and not used for function definitions.
void
assemble_variable (decl, top_level, at_end, dont_output_data)
tree decl;
- int top_level;
+ int top_level ATTRIBUTE_UNUSED;
int at_end;
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
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
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;
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. */
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) || ! TREE_PUBLIC (decl))
+ && DECL_COMMON (decl)
#endif
&& ! 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)
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)
{
#ifdef ASM_OUTPUT_SHARED_BSS
if (flag_shared_data)
- ASM_OUTPUT_SHARED_BSS (asm_out_file, name, size, rounded);
+ 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, name, size,
+ ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size,
DECL_ALIGN (decl));
#else
- ASM_OUTPUT_BSS (asm_out_file, name, size, rounded);
+ ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded);
#endif
}
}
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;
/* 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);
else if (DECL_INITIAL (decl))
reloc = output_addressed_constants (DECL_INITIAL (decl));
+#ifdef ASM_OUTPUT_SECTION_NAME
+ if ((flag_data_sections != 0
+ && DECL_SECTION_NAME (decl) == NULL_TREE)
+ || UNIQUE_SECTION_P (decl))
+ UNIQUE_SECTION (decl, reloc);
+#endif
+
/* Switch to the appropriate section. */
variable_section (decl, reloc);
if (in_section != saved_in_section)
variable_section (decl, reloc);
- /* 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;
-
+ /* 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. */
- if (output_bytecode)
- BC_OUTPUT_LABEL (asm_out_file, name);
- else
- {
#ifdef ASM_DECLARE_OBJECT_NAME
- last_assemble_variable_decl = decl;
- ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
+ 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);
+ /* 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)
{
}
}
-/* 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. */
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))
void
assemble_external_libcall (fun)
- rtx fun;
+ rtx fun ATTRIBUTE_UNUSED;
{
#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
}
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.
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
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)
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;
}
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
#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);
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
\f
int force;
{
/* First try to use the standard 1, 2, 4, 8, and 16 byte
- ASM_OUTPUT... macros. */
+ ASM_OUTPUT... macros. */
switch (size)
{
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)
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)
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.
{
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. */
/* 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
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);
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;
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;
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;
+
+ case STRING_CST:
+ p = TREE_STRING_POINTER (exp);
+ len = TREE_STRING_LENGTH (exp);
+ 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 COMPLEX_CST:
+ return (const_hash (TREE_REALPART (exp)) * 5
+ + const_hash (TREE_IMAGPART (exp)));
- return hi;
- }
- else if (code == ADDR_EXPR)
- {
- struct addr_const value;
- decode_addr_const (exp, &value);
- if (GET_CODE (value.base) == SYMBOL_REF)
+ 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
+ {
+ 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;
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)
- {
+ break;
+
+ case 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)
- {
- 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))
+ if (p == 0)
return 0;
- p += sizeof xlen;
- }
- else if (code == CONSTRUCTOR)
- {
- register tree link;
- int length = list_length (CONSTRUCTOR_ELTS (exp));
- tree type;
- if (bcmp ((char *) &length, p, sizeof length))
- return 0;
- p += sizeof length;
+ return compare_constant_1 (TREE_IMAGPART (exp), p);
+
+ case CONSTRUCTOR:
+ if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
+ {
+ 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 xlen;
+ break;
+ }
+ else
+ {
+ 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;
- /* 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;
+ p += sizeof type;
- /* 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));
- if (bcmp ((char *) &size, p, sizeof size))
+ if (bcmp ((char *) &have_purpose, p, sizeof have_purpose))
return 0;
- p += sizeof size;
- }
- for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
- {
- if (TREE_VALUE (link))
+ 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:
+ case RANGE_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. */
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),
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);
}
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;
case PLUS_EXPR:
case MINUS_EXPR:
+ case RANGE_EXPR:
record_constant_1 (TREE_OPERAND (exp, 0));
record_constant_1 (TREE_OPERAND (exp, 1));
return;
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;
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. */
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:
case NOP_EXPR:
case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
return build1 (TREE_CODE (exp), TREE_TYPE (exp),
copy_constant (TREE_OPERAND (exp, 0)));
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);
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;
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));
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++);
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. */
#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);
int labelno;
int align;
int offset;
+ int mark;
};
/* Pointers to first and last constant in pool. */
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)
\f
/* Initialize constant pool hashing for next function. */
/* 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
first_pool = p->first_pool;
last_pool = p->last_pool;
pool_offset = p->pool_offset;
+ const_double_chain = p->const_double_chain;
}
\f
enum kind { RTX_DOUBLE, RTX_INT };
*p++ = 0;
}
- value->kind = RTX_INT; /* Most usual kind. */
+ value->kind = RTX_INT; /* Most usual kind. */
value->mode = mode;
switch (GET_CODE (x))
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;
}
}
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);
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 ();
}
pool->labelno = const_labelno;
pool->align = align;
pool->offset = pool_offset;
+ pool->mark = 1;
pool->next = 0;
if (last_pool == 0)
/* 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. */
void
output_constant_pool (fnname, fndecl)
- char *fnname;
- tree fndecl;
+ char *fnname ATTRIBUTE_UNUSED;
+ tree fndecl ATTRIBUTE_UNUSED;
{
struct pool_constant *pool;
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
{
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
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 ();
+ }
+ }
+}
\f
/* 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.
}
break;
- case ERROR_MARK:
+ default:
break;
}
return reloc;
register int size;
{
register enum tree_code code = TREE_CODE (TREE_TYPE (exp));
- rtx x;
if (size == 0)
return;
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;
}
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. */
-}
\f
/* Subroutine of output_constant, used for CONSTRUCTORs
(aggregate constants).
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. */
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;
}
}
/* 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)
{
assemble_zeros (size - total_bytes);
}
-/* Output asm to handle ``#pragma weak'' */
-void
-handle_pragma_weak (what, name, value)
- enum pragma_state what;
- char *name, *value;
-{
-#ifdef HANDLE_PRAGMA_WEAK
- if (what == ps_name || what == ps_value)
- {
- struct weak_syms *weak =
- (struct weak_syms *)permalloc (sizeof (struct weak_syms));
- weak->next = weak_decls;
- weak->name = permalloc (strlen (name) + 1);
- strcpy (weak->name, name);
-
- if (what != ps_value)
- weak->value = NULL_PTR;
-
- else
- {
- weak->value = permalloc (strlen (value) + 1);
- strcpy (weak->value, value);
- }
-
- weak_decls = weak;
- }
- else if (! (what == ps_done || what == ps_start))
- warning ("malformed `#pragma weak'");
-#endif /* HANDLE_PRAGMA_WEAK */
-}
-
/* Declare DECL to be a weak symbol. */
void
/* Emit any pending weak declarations. */
+#ifdef HANDLE_PRAGMA_WEAK
+struct weak_syms * weak_decls;
+#endif
+
void
weak_finish ()
{
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))
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 ();
}