/* Output variables, constants and external declarations, for GNU compiler.
- Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "config.h"
#include "system.h"
#include <setjmp.h>
-/* #include <stab.h> */
#include "rtl.h"
#include "tree.h"
#include "flags.h"
-#include "except.h"
#include "function.h"
#include "expr.h"
#include "output.h"
#include "toplev.h"
#include "dbxout.h"
#include "sdbout.h"
-
#include "obstack.h"
#include "c-pragma.h"
+#include "ggc.h"
+#include "tm_p.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#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. */
-#ifndef STRIP_NAME_ENCODING
-#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \
- (VAR) = ((SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*'))
-#endif
-
/* File in which assembler code is being written. */
extern FILE *asm_out_file;
extern struct obstack permanent_obstack;
#define obstack_chunk_alloc xmalloc
+struct addr_const;
+struct constant_descriptor;
+struct rtx_const;
+struct pool_constant;
+
+#define MAX_RTX_HASH_TABLE 61
+
+struct varasm_status
+{
+ /* Hash facility for making memory-constants
+ from constant rtl-expressions. It is used on RISC machines
+ where immediate integer arguments and constant addresses are restricted
+ so that such constants must be stored in memory.
+
+ This pool of constants is reinitialized for each function
+ so each function gets its own constants-pool that comes right before
+ it. */
+ struct constant_descriptor **x_const_rtx_hash_table;
+ struct pool_sym **x_const_rtx_sym_hash_table;
+
+ /* Pointers to first and last constant in pool. */
+ struct pool_constant *x_first_pool, *x_last_pool;
+
+ /* Current offset in constant pool (does not include any machine-specific
+ header. */
+ int x_pool_offset;
+
+ /* Chain of all CONST_DOUBLE rtx's constructed for the current function.
+ They are chained through the CONST_DOUBLE_CHAIN.
+ A CONST_DOUBLE rtx has CONST_DOUBLE_MEM != cc0_rtx iff it is on this chain.
+ In that case, CONST_DOUBLE_MEM is either a MEM,
+ or const0_rtx if no MEM has been made for this CONST_DOUBLE yet. */
+ rtx x_const_double_chain;
+};
+
+#define const_rtx_hash_table (cfun->varasm->x_const_rtx_hash_table)
+#define const_rtx_sym_hash_table (cfun->varasm->x_const_rtx_sym_hash_table)
+#define first_pool (cfun->varasm->x_first_pool)
+#define last_pool (cfun->varasm->x_last_pool)
+#define pool_offset (cfun->varasm->x_pool_offset)
+#define const_double_chain (cfun->varasm->x_const_double_chain)
+
/* Number for making the label on the next
constant that is stored in memory. */
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 addr_const;
-struct constant_descriptor;
-struct rtx_const;
-struct pool_constant;
-
-static char *strip_reg_name PROTO((char *));
-static int contains_pointers_p PROTO((tree));
-static void decode_addr_const PROTO((tree, struct addr_const *));
-static int const_hash PROTO((tree));
-static int compare_constant PROTO((tree,
+static const char *strip_reg_name PARAMS ((const char *));
+static int contains_pointers_p PARAMS ((tree));
+static void decode_addr_const PARAMS ((tree, struct addr_const *));
+static int const_hash PARAMS ((tree));
+static int compare_constant PARAMS ((tree,
struct constant_descriptor *));
-static char *compare_constant_1 PROTO((tree, char *));
-static struct constant_descriptor *record_constant PROTO((tree));
-static void record_constant_1 PROTO((tree));
-static tree copy_constant PROTO((tree));
-static void output_constant_def_contents PROTO((tree, int, int));
-static void decode_rtx_const PROTO((enum machine_mode, rtx,
+static char *compare_constant_1 PARAMS ((tree, char *));
+static struct constant_descriptor *record_constant PARAMS ((tree));
+static void record_constant_1 PARAMS ((tree));
+static tree copy_constant PARAMS ((tree));
+static void output_constant_def_contents PARAMS ((tree, int, int));
+static void decode_rtx_const PARAMS ((enum machine_mode, rtx,
struct rtx_const *));
-static int const_hash_rtx PROTO((enum machine_mode, rtx));
-static int compare_constant_rtx PROTO((enum machine_mode, rtx,
+static int const_hash_rtx PARAMS ((enum machine_mode, rtx));
+static int compare_constant_rtx PARAMS ((enum machine_mode, rtx,
struct constant_descriptor *));
-static struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode,
+static struct constant_descriptor *record_constant_rtx PARAMS ((enum machine_mode,
rtx));
-static struct pool_constant *find_pool_constant PROTO((rtx));
-static void mark_constant_pool PROTO((void));
-static void mark_constants PROTO((rtx));
-static int output_addressed_constants PROTO((tree));
-static void output_after_function_constants PROTO((void));
-static void output_constructor PROTO((tree, int));
+static struct pool_constant *find_pool_constant PARAMS ((struct function *, rtx));
+static void mark_constant_pool PARAMS ((void));
+static void mark_constants PARAMS ((rtx));
+static int output_addressed_constants PARAMS ((tree));
+static void output_after_function_constants PARAMS ((void));
+static void output_constructor PARAMS ((tree, int));
+#ifdef ASM_WEAKEN_LABEL
+static void remove_from_pending_weak_list PARAMS ((char *));
+#endif
#ifdef ASM_OUTPUT_BSS
-static void asm_output_bss PROTO((FILE *, tree, char *, int, int));
+static void asm_output_bss PARAMS ((FILE *, tree, const 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));
+static void asm_output_aligned_bss PARAMS ((FILE *, tree, const char *,
+ int, int));
#endif
#endif /* BSS_SECTION_ASM_OP */
+static void mark_pool_constant PARAMS ((struct pool_constant *));
+static void mark_pool_sym_hash_table PARAMS ((struct pool_sym **));
+static void mark_const_hash_entry PARAMS ((void *));
+static void asm_emit_uninitialised PARAMS ((tree, const char*, int, int));
\f
static enum in_section { no_section, in_text, in_data, in_named
#ifdef BSS_SECTION_ASM_OP
} in_section = no_section;
/* Return a non-zero value if DECL has a section attribute. */
+#ifndef IN_NAMED_SECTION
#define IN_NAMED_SECTION(DECL) \
((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
&& DECL_SECTION_NAME (DECL) != NULL_TREE)
-
+#endif
+
/* Text of section name when in_section == in_named. */
static char *in_named_name;
in_section = in_data;
}
}
+/* Tell assembler to ALWAYS switch to data section, in case
+ it's not sure where it it. */
+
+void
+force_data_section ()
+{
+ in_section = no_section;
+ data_section ();
+}
/* Tell assembler to switch to read-only data section. This is normally
the text section. */
void
named_section (decl, name, reloc)
tree decl;
- char *name;
- int reloc;
+ const char *name;
+ int reloc ATTRIBUTE_UNUSED;
{
- if (decl != NULL_TREE
- && TREE_CODE_CLASS (TREE_CODE (decl)) != 'd')
+ if (decl != NULL_TREE && !DECL_P (decl))
abort ();
if (name == NULL)
name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
abort ();
#endif
- in_named_name = obstack_alloc (&permanent_obstack, strlen (name) + 1);
- strcpy (in_named_name, name);
+ in_named_name = ggc_alloc_string (name, -1);
in_section = in_named;
}
}
#define UNIQUE_SECTION(DECL,RELOC) \
do { \
int len; \
- char *name, *string; \
+ const char *name; \
+ char *string; \
\
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \
/* Strip off any encoding in name. */ \
static void
asm_output_bss (file, decl, name, size, rounded)
FILE *file;
- tree decl;
- char *name;
- int size, rounded;
+ tree decl ATTRIBUTE_UNUSED;
+ const char *name;
+ int size ATTRIBUTE_UNUSED, rounded;
{
ASM_GLOBALIZE_LABEL (file, name);
bss_section ();
asm_output_aligned_bss (file, decl, name, size, align)
FILE *file;
tree decl;
- char *name;
+ const char *name;
int size, align;
{
ASM_GLOBALIZE_LABEL (file, name);
char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *new_name = name;
- /* Rename a nested function to avoid conflicts. */
+ /* Rename a nested function to avoid conflicts, unless it's a member of
+ a local class, in which case the class name is already unique. */
if (decl_function_context (decl) != 0
+ && ! TYPE_P (DECL_CONTEXT (decl))
&& DECL_INITIAL (decl) != 0
&& DECL_RTL (decl) == 0)
{
name = IDENTIFIER_POINTER (DECL_NAME (decl));
ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
- name = obstack_copy0 (saveable_obstack, label, strlen (label));
+ name = ggc_alloc_string (label, -1);
var_labelno++;
}
else
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));
+ size_t name_len = strlen (name);
+
+ new_name = ggc_alloc_string (NULL, name_len + CHKR_PREFIX_SIZE);
+ memcpy (new_name, CHKR_PREFIX, CHKR_PREFIX_SIZE);
+ memcpy (new_name + CHKR_PREFIX_SIZE, name, name_len + 1);
+ name = new_name;
}
}
if (DECL_RTL (decl) == 0)
{
+ DECL_ASSEMBLER_NAME (decl) = get_identifier (name);
DECL_RTL (decl)
= gen_rtx_MEM (DECL_MODE (decl),
gen_rtx_SYMBOL_REF (Pmode, name));
ENCODE_SECTION_INFO (decl);
#endif
}
-
- /* Record at least one function has been defined. */
- function_defined = 1;
}
/* Given NAME, a putative register name, discard any customary prefixes. */
-static char *
+static const char *
strip_reg_name (name)
- char *name;
+ const char *name;
{
#ifdef REGISTER_PREFIX
if (!strncmp (name, REGISTER_PREFIX, strlen (REGISTER_PREFIX)))
int
decode_reg_name (asmspec)
- char *asmspec;
+ const char *asmspec;
{
if (asmspec != 0)
{
#ifdef ADDITIONAL_REGISTER_NAMES
{
- static struct { char *name; int number; } table[]
+ static struct { const 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;
}
void
make_decl_rtl (decl, asmspec, top_level)
tree decl;
- char *asmspec;
+ const char *asmspec;
int top_level;
{
register char *name = 0;
if (reg_number == -2)
{
/* ASMSPEC is given, and not the name of a register. */
- name = (char *) obstack_alloc (saveable_obstack,
- strlen (asmspec) + 2);
+ size_t len = strlen (asmspec);
+
+ name = ggc_alloc_string (NULL, len + 1);
name[0] = '*';
- strcpy (&name[1], asmspec);
+ memcpy (&name[1], asmspec, len + 1);
}
/* For a duplicate declaration, we can be called twice on the
DECL_INITIAL (decl) = 0;
error ("global register variable has initial value");
}
- if (fixed_regs[reg_number] == 0
- && function_defined && top_level)
- error ("global register variable follows a function definition");
if (TREE_THIS_VOLATILE (decl))
warning ("volatile register variables don't work as you might wish");
{
/* Make this register global, so not usable for anything
else. */
+#ifdef ASM_DECLARE_REGISTER_GLOBAL
+ ASM_DECLARE_REGISTER_GLOBAL (asm_out_file, decl, reg_number, name);
+#endif
nregs = HARD_REGNO_NREGS (reg_number, DECL_MODE (decl));
while (nregs > 0)
globalize_reg (reg_number + --nregs);
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.
+ whose scope is less than the whole file, unless it's a member
+ of a local class (which will already be unambiguous).
Concatenate a distinguishing number. */
- if (!top_level && !TREE_PUBLIC (decl) && asmspec == 0)
+ if (!top_level && !TREE_PUBLIC (decl)
+ && ! (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
+ && asmspec == 0)
{
char *label;
ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
- name = obstack_copy0 (saveable_obstack, label, strlen (label));
+ name = ggc_alloc_string (label, -1);
var_labelno++;
}
prefixed. */
if (flag_prefix_function_name && TREE_CODE (decl) == FUNCTION_DECL)
{
+ size_t name_len = strlen (name);
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));
+
+ new_name = ggc_alloc_string (NULL, name_len + CHKR_PREFIX_SIZE);
+ memcpy (new_name, CHKR_PREFIX, CHKR_PREFIX_SIZE);
+ memcpy (new_name + CHKR_PREFIX_SIZE, name, name_len + 1);
+ name = new_name;
}
+ DECL_ASSEMBLER_NAME (decl)
+ = get_identifier (name[0] == '*' ? name + 1 : 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
if (flag_volatile_global && TREE_CODE (decl) == VAR_DECL
&& TREE_PUBLIC (decl))
TREE_SIDE_EFFECTS (decl) = 1;
+ else if (flag_volatile_static && TREE_CODE (decl) == VAR_DECL
+ && (TREE_PUBLIC (decl) || TREE_STATIC (decl)))
+ TREE_SIDE_EFFECTS (decl) = 1;
+
if (TREE_SIDE_EFFECTS (decl))
MEM_VOLATILE_P (DECL_RTL (decl)) = 1;
if (TREE_READONLY (decl))
RTX_UNCHANGING_P (DECL_RTL (decl)) = 1;
- MEM_IN_STRUCT_P (DECL_RTL (decl))
- = AGGREGATE_TYPE_P (TREE_TYPE (decl));
+ MEM_SET_IN_STRUCT_P (DECL_RTL (decl),
+ AGGREGATE_TYPE_P (TREE_TYPE (decl)));
/* Optionally set flags or add text to the name to record information
such as that it is a function name.
void
assemble_destructor (name)
- char *name;
+ const char *name;
{
#ifdef ASM_OUTPUT_DESTRUCTOR
ASM_OUTPUT_DESTRUCTOR (asm_out_file, name);
void
assemble_constructor (name)
- char *name;
+ const char *name;
{
#ifdef ASM_OUTPUT_CONSTRUCTOR
ASM_OUTPUT_CONSTRUCTOR (asm_out_file, name);
void
assemble_gc_entry (name)
- char *name;
+ const char *name;
{
#ifdef ASM_OUTPUT_GC_ENTRY
ASM_OUTPUT_GC_ENTRY (asm_out_file, name);
void
assemble_start_function (decl, fnname)
tree decl;
- char *fnname;
+ const char *fnname;
{
int align;
if (align > 0)
ASM_OUTPUT_ALIGN (asm_out_file, align);
+ /* Handle a user-specified function alignment.
+ Note that we still need to align to FUNCTION_BOUNDARY, as above,
+ because ASM_OUTPUT_MAX_SKIP_ALIGN might not do any alignment at all. */
+ if (align_functions_log > align)
+ {
+#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
+ ASM_OUTPUT_MAX_SKIP_ALIGN (asm_out_file,
+ align_functions_log, align_functions-1);
+#else
+ ASM_OUTPUT_ALIGN (asm_out_file, align_functions_log);
+#endif
+ }
+
#ifdef ASM_OUTPUT_FUNCTION_PREFIX
ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
#endif
{
if (! first_global_object_name)
{
- char *p;
+ const char *p;
char **name;
if (! DECL_WEAK (decl) && ! DECL_ONE_ONLY (decl))
#ifdef ASM_WEAKEN_LABEL
if (DECL_WEAK (decl))
- ASM_WEAKEN_LABEL (asm_out_file, fnname);
+ {
+ ASM_WEAKEN_LABEL (asm_out_file, fnname);
+ /* Remove this function from the pending weak list so that
+ we do not emit multiple .weak directives for it. */
+ remove_from_pending_weak_list
+ (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ }
else
#endif
ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
void
assemble_end_function (decl, fnname)
tree decl;
- char *fnname;
+ const char *fnname;
{
#ifdef ASM_DECLARE_FUNCTION_SIZE
ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
assemble_zeros (size)
int size;
{
+ /* Do no output if -fsyntax-only. */
+ if (flag_syntax_only)
+ 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. */
void
assemble_string (p, size)
- char *p;
+ const char *p;
int size;
{
int pos = 0;
}
\f
+#if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL
+#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
+ ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size, DECL_ALIGN (decl))
+#else
+#if defined ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
+ ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl))
+#else
+#define ASM_EMIT_LOCAL(decl, name, size, rounded) \
+ ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded)
+#endif
+#endif
+
+#if defined ASM_OUTPUT_ALIGNED_BSS
+#define ASM_EMIT_BSS(decl, name, size, rounded) \
+ ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size, DECL_ALIGN (decl))
+#else
+#if defined ASM_OUTPUT_BSS
+#define ASM_EMIT_BSS(decl, name, size, rounded) \
+ ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded)
+#else
+#undef ASM_EMIT_BSS
+#endif
+#endif
+
+#if defined ASM_OUTPUT_ALIGNED_DECL_COMMON
+#define ASM_EMIT_COMMON(decl, name, size, rounded) \
+ ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size, DECL_ALIGN (decl))
+#else
+#if defined ASM_OUTPUT_ALIGNED_COMMON
+#define ASM_EMIT_COMMON(decl, name, size, rounded) \
+ ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size, DECL_ALIGN (decl))
+#else
+#define ASM_EMIT_COMMON(decl, name, size, rounded) \
+ ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded)
+#endif
+#endif
+
+static void
+asm_emit_uninitialised (decl, name, size, rounded)
+ tree decl;
+ const char * name;
+ int size ATTRIBUTE_UNUSED;
+ int rounded ATTRIBUTE_UNUSED;
+{
+ enum
+ {
+ asm_dest_common,
+ asm_dest_bss,
+ asm_dest_local
+ }
+ destination = asm_dest_local;
+
+ if (TREE_PUBLIC (decl))
+ {
+#if defined ASM_EMIT_BSS
+ if (! DECL_COMMON (decl))
+ destination = asm_dest_bss;
+ else
+#endif
+ destination = asm_dest_common;
+ }
+
+ if (flag_shared_data)
+ {
+ switch (destination)
+ {
+#ifdef ASM_OUTPUT_SHARED_BSS
+ case asm_dest_bss:
+ ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded);
+ return;
+#endif
+#ifdef ASM_OUTPUT_SHARED_COMMON
+ case asm_dest_common:
+ ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
+ return;
+#endif
+#ifdef ASM_OUTPUT_SHARED_LOCAL
+ case asm_dest_local:
+ ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
+ return;
+#endif
+ default:
+ break;
+ }
+ }
+
+#ifdef ASM_OUTPUT_SECTION_NAME
+ /* We already know that DECL_SECTION_NAME() == NULL. */
+ if (flag_data_sections != 0 || UNIQUE_SECTION_P (decl))
+ UNIQUE_SECTION (decl, NULL);
+#endif
+
+ switch (destination)
+ {
+#ifdef ASM_EMIT_BSS
+ case asm_dest_bss:
+ ASM_EMIT_BSS (decl, name, size, rounded);
+ break;
+#endif
+ case asm_dest_common:
+ ASM_EMIT_COMMON (decl, name, size, rounded);
+ break;
+ case asm_dest_local:
+ ASM_EMIT_LOCAL (decl, name, size, rounded);
+ break;
+ default:
+ abort ();
+ }
+
+ return;
+}
+
/* Assemble everything that is needed for a variable or function declaration.
Not used for automatic variables, and not used for function definitions.
Should not be called for variables of incomplete structure type.
void
assemble_variable (decl, top_level, at_end, dont_output_data)
tree decl;
- int top_level;
- int at_end;
+ int top_level ATTRIBUTE_UNUSED;
+ int at_end ATTRIBUTE_UNUSED;
int dont_output_data;
{
- register char *name;
+ register const char *name;
unsigned int align;
- tree size_tree;
int reloc = 0;
enum in_section saved_in_section;
return;
TREE_ASM_WRITTEN (decl) = 1;
+ /* Do no output if -fsyntax-only. */
+ if (flag_syntax_only)
+ return;
+
#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)
TREE_ASM_WRITTEN (decl) = 1;
+ /* Do no output if -fsyntax-only. */
+ if (flag_syntax_only)
+ return;
+
app_disable ();
- if (! dont_output_data)
+ if (! dont_output_data
+ && ! host_integerp (DECL_SIZE_UNIT (decl), 1))
{
- 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));
-
- 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;
- }
+ 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_WEAK (decl)
&& ! DECL_ONE_ONLY (decl))
{
- char *p;
+ const char *p;
STRIP_NAME_ENCODING (p, name);
first_global_object_name = permalloc (strlen (p) + 1);
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)
+#if ! defined ASM_EMIT_BSS
&& DECL_COMMON (decl)
#endif
+ && DECL_SECTION_NAME (decl) == NULL_TREE
&& ! dont_output_data)
{
- int size = TREE_INT_CST_LOW (size_tree);
- int rounded = size;
+ unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ unsigned HOST_WIDE_INT rounded = size;
/* Don't allocate zero bytes of common,
since that means "undefined external" in the linker. */
- if (size == 0) rounded = 1;
+ if (size == 0)
+ rounded = 1;
+
/* Round size up to multiple of BIGGEST_ALIGNMENT bits
so that each uninitialized object starts on such a boundary. */
rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
* (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
- if ( (DECL_ALIGN (decl) / BITS_PER_UNIT) > rounded)
+ 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
if (flag_shared_data)
data_section ();
#endif
+ asm_emit_uninitialised (decl, name, size, rounded);
- 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
- {
-#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
- if (flag_shared_data)
- ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
- else
-#endif
- {
-#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;
}
if (TREE_PUBLIC (decl) && DECL_NAME (decl))
{
#ifdef ASM_WEAKEN_LABEL
- if (DECL_WEAK (decl))
- ASM_WEAKEN_LABEL (asm_out_file, name);
+ if (DECL_WEAK (decl))
+ {
+ ASM_WEAKEN_LABEL (asm_out_file, name);
+ /* Remove this variable from the pending weak list so that
+ we do not emit multiple .weak directives for it. */
+ remove_from_pending_weak_list
+ (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ }
else
#endif
ASM_GLOBALIZE_LABEL (asm_out_file, name);
reloc = output_addressed_constants (DECL_INITIAL (decl));
#ifdef ASM_OUTPUT_SECTION_NAME
- if (UNIQUE_SECTION_P (decl))
+ if ((flag_data_sections != 0 && DECL_SECTION_NAME (decl) == NULL_TREE)
+ || UNIQUE_SECTION_P (decl))
UNIQUE_SECTION (decl, reloc);
#endif
{
if (DECL_INITIAL (decl))
/* Output the actual data. */
- output_constant (DECL_INITIAL (decl), TREE_INT_CST_LOW (size_tree));
+ output_constant (DECL_INITIAL (decl),
+ tree_low_cst (DECL_SIZE_UNIT (decl), 1));
else
/* Leave space for it. */
- assemble_zeros (TREE_INT_CST_LOW (size_tree));
+ assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
}
finish:
void
assemble_external (decl)
- tree decl;
+ tree decl ATTRIBUTE_UNUSED;
{
#ifdef ASM_OUTPUT_EXTERNAL
- if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'
- && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
+ if (DECL_P (decl) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
{
rtx rtl = DECL_RTL (decl);
void
assemble_external_libcall (fun)
- rtx fun;
+ rtx fun ATTRIBUTE_UNUSED;
{
#ifdef ASM_OUTPUT_EXTERNAL_LIBCALL
/* Declare library function name external when first used, if nec. */
void
assemble_global (name)
- char *name;
+ const char *name;
{
ASM_GLOBALIZE_LABEL (asm_out_file, name);
}
void
assemble_label (name)
- char *name;
+ const char *name;
{
ASM_OUTPUT_LABEL (asm_out_file, name);
}
void
assemble_name (file, name)
FILE *file;
- char *name;
+ const char *name;
{
- char *real_name;
+ const char *real_name;
tree id;
STRIP_NAME_ENCODING (real_name, name);
ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
++const_labelno;
-
- namestring = (char *) obstack_alloc (saveable_obstack,
- strlen (name) + 2);
- strcpy (namestring, name);
+ namestring = ggc_alloc_string (name, -1);
x = gen_rtx_SYMBOL_REF (Pmode, namestring);
{
/* 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));
+ /* Variable `rounded' might or might not be used in ASM_OUTPUT_LOCAL. */
+ int rounded ATTRIBUTE_UNUSED
+ = ((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
/* Record the rtl to refer to it. */
ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0);
- name
- = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
+ name = ggc_alloc_string (label, -1);
return gen_rtx_SYMBOL_REF (Pmode, name);
}
#endif
/* Here we combine duplicate floating constants to make
CONST_DOUBLE rtx's, and force those out to memory when necessary. */
-/* Chain of all CONST_DOUBLE rtx's constructed for the current function.
- They are chained through the CONST_DOUBLE_CHAIN.
- A CONST_DOUBLE rtx has CONST_DOUBLE_MEM != cc0_rtx iff it is on this chain.
- In that case, CONST_DOUBLE_MEM is either a MEM,
- or const0_rtx if no MEM has been made for this CONST_DOUBLE yet.
-
- (CONST_DOUBLE_MEM is used only for top-level functions.
- See force_const_mem for explanation.) */
-
-static rtx const_double_chain;
-
/* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair of ints.
For an integer, I0 is the low-order word and I1 is the high-order word.
For a real number, I0 is the word with the low address
/* Search the chain for an existing CONST_DOUBLE with the right value.
If one is found, return it. */
-
- for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
- if (CONST_DOUBLE_LOW (r) == i0 && CONST_DOUBLE_HIGH (r) == i1
- && GET_MODE (r) == mode)
- return r;
+ if (cfun != 0)
+ for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
+ if (CONST_DOUBLE_LOW (r) == i0 && CONST_DOUBLE_HIGH (r) == i1
+ && GET_MODE (r) == mode)
+ return r;
/* No; make a new one and add it to the chain.
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.
- Also, don't touch it if not inside any function. */
- if (outer_function_chain == 0 && current_function_decl != 0)
+ /* Don't touch const_double_chain if not inside any function. */
+ if (current_function_decl != 0)
{
CONST_DOUBLE_CHAIN (r) = const_double_chain;
const_double_chain = r;
/* Search the chain for an existing CONST_DOUBLE with the right value.
If one is found, return it. */
-
- for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
- if (! bcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
- && GET_MODE (r) == mode)
- return r;
+ if (cfun != 0)
+ for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
+ if (! bcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
+ && GET_MODE (r) == mode)
+ return r;
/* No; make a new one and add it to the chain.
we will be leaving this constant on the chain, so we cannot tolerate
freed memory. So switch to saveable_obstack for this allocation
and then switch back if we were in current_obstack. */
-
push_obstacks_nochange ();
rtl_in_saveable_obstack ();
r = rtx_alloc (CONST_DOUBLE);
+ pop_obstacks ();
PUT_MODE (r, mode);
bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (r), sizeof u);
- pop_obstacks ();
- /* Don't touch const_double_chain in nested function; see force_const_mem.
- Also, don't touch it if not inside any function. */
- if (outer_function_chain == 0 && current_function_decl != 0)
+ /* Don't touch const_double_chain if not inside any function. */
+ if (current_function_decl != 0)
{
CONST_DOUBLE_CHAIN (r) = const_double_chain;
const_double_chain = r;
{
register rtx r, next;
- /* Don't touch CONST_DOUBLE_MEM for nested functions.
- See force_const_mem for explanation. */
- if (outer_function_chain != 0)
- return;
-
for (r = const_double_chain; r; r = next)
{
next = CONST_DOUBLE_CHAIN (r);
while (1)
{
if (TREE_CODE (target) == COMPONENT_REF
- && (TREE_CODE (DECL_FIELD_BITPOS (TREE_OPERAND (target, 1)))
- == INTEGER_CST))
+ && host_integerp (byte_position (TREE_OPERAND (target, 1)), 0))
+
{
- offset += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (target, 1))) / BITS_PER_UNIT;
+ offset += int_byte_position (TREE_OPERAND (target, 1));
target = TREE_OPERAND (target, 0);
}
else if (TREE_CODE (target) == ARRAY_REF)
{
- if (TREE_CODE (TREE_OPERAND (target, 1)) != INTEGER_CST
- || TREE_CODE (TYPE_SIZE (TREE_TYPE (target))) != INTEGER_CST)
- abort ();
- offset += ((TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (target)))
- * TREE_INT_CST_LOW (TREE_OPERAND (target, 1)))
- / BITS_PER_UNIT);
+ offset += (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (target)), 1)
+ * tree_low_cst (TREE_OPERAND (target, 1), 0));
target = TREE_OPERAND (target, 0);
}
else
{
struct constant_descriptor *next;
char *label;
+ rtx rtl;
char contents[1];
};
#define MAX_HASH_TABLE 1009
static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
+/* Mark a const_hash_table descriptor for GC. */
+
+static void
+mark_const_hash_entry (ptr)
+ void *ptr;
+{
+ struct constant_descriptor *desc = * (struct constant_descriptor **) ptr;
+
+ while (desc)
+ {
+ ggc_mark_string (desc->label);
+ ggc_mark_rtx (desc->rtl);
+ desc = desc->next;
+ }
+}
+
/* Compute a hash code for a constant expression. */
static int
const_hash (exp)
tree exp;
{
- register char *p;
+ register const char *p;
register int len, hi, i;
register enum tree_code code = TREE_CODE (exp);
case CONSTRUCTOR:
if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
{
+ char *tmp;
+
len = int_size_in_bytes (TREE_TYPE (exp));
- p = (char *) alloca (len);
- get_set_constructor_bytes (exp, (unsigned char *) p, len);
+ tmp = (char *) alloca (len);
+ get_set_constructor_bytes (exp, (unsigned char *) tmp, len);
+ p = tmp;
break;
}
else
}
else if (GET_CODE (value.base) == LABEL_REF)
hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
+ else
+ abort();
hi &= (1 << HASHBITS) - 1;
hi %= MAX_HASH_TABLE;
tree exp;
char *p;
{
- register char *strp;
+ register const char *strp;
register int len;
register enum tree_code code = TREE_CODE (exp);
if (flag_writable_strings)
return 0;
- if (*p++ != TYPE_MODE (TREE_TYPE (exp)))
+ if ((enum machine_mode) *p++ != TYPE_MODE (TREE_TYPE (exp)))
return 0;
strp = TREE_STRING_POINTER (exp);
if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
{
int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
+ unsigned char *tmp = (unsigned char *) alloca (len);
- strp = (char *) alloca (len);
- get_set_constructor_bytes (exp, (unsigned char *) strp, len);
+ get_set_constructor_bytes (exp, (unsigned char *) tmp, len);
+ strp = tmp;
if (bcmp ((char *) &xlen, p, sizeof xlen))
return 0;
register tree link;
int length = list_length (CONSTRUCTOR_ELTS (exp));
tree type;
+ enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
int have_purpose = 0;
for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
if (bcmp ((char *) &type, p, sizeof type))
return 0;
+ if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+ {
+ if (bcmp ((char *) &mode, p, sizeof mode))
+ return 0;
+
+ p += sizeof mode;
+ }
+
p += sizeof type;
if (bcmp ((char *) &have_purpose, p, sizeof have_purpose))
{
struct constant_descriptor *next = 0;
char *label = 0;
+ rtx rtl = 0;
- /* Make a struct constant_descriptor. The first two pointers will
+ /* Make a struct constant_descriptor. The first three pointers will
be filled in later. Here we just leave space for them. */
obstack_grow (&permanent_obstack, (char *) &next, sizeof next);
obstack_grow (&permanent_obstack, (char *) &label, sizeof label);
+ obstack_grow (&permanent_obstack, (char *) &rtl, sizeof rtl);
record_constant_1 (exp);
return (struct constant_descriptor *) obstack_finish (&permanent_obstack);
}
{
register tree link;
int length = list_length (CONSTRUCTOR_ELTS (exp));
+ enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
tree type;
int have_purpose = 0;
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.
- Then insist that either both or none have any TREE_PURPOSE
- values. */
+ For arrays, just verify both constructors are for arrays
+ of the same mode. 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);
+ if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+ obstack_grow (&permanent_obstack, &mode, sizeof mode);
+
obstack_grow (&permanent_obstack, (char *) &have_purpose,
sizeof have_purpose);
register int hash;
register struct constant_descriptor *desc;
char label[256];
- char *found = 0;
int reloc;
- register rtx def;
+ int found = 1;
if (TREE_CST_RTL (exp))
return TREE_CST_RTL (exp);
for (desc = const_hash_table[hash]; desc; desc = desc->next)
if (compare_constant (exp, desc))
- {
- found = desc->label;
- break;
- }
+ break;
- if (found == 0)
+ if (desc == 0)
{
/* No constant equal to EXP is known to have been output.
Make a constant descriptor to enter EXP in the hash table.
desc = record_constant (exp);
desc->next = const_hash_table[hash];
- desc->label
- = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
+ desc->label = ggc_alloc_string (label, -1);
const_hash_table[hash] = desc;
- }
- else
- {
- /* Create a string containing the label name, in LABEL. */
- ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
- }
- /* We have a symbol name; construct the SYMBOL_REF and the MEM. */
+ /* We have a symbol name; construct the SYMBOL_REF and the MEM
+ in the permanent obstack. We could also construct this in the
+ obstack of EXP and put it into TREE_CST_RTL, but we have no way
+ of knowing what obstack it is (e.g., it might be in a function
+ obstack of a function we are nested inside). */
- push_obstacks_nochange ();
- if (TREE_PERMANENT (exp))
- end_temporary_allocation ();
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
- def = gen_rtx_SYMBOL_REF (Pmode, desc->label);
-
- TREE_CST_RTL (exp)
- = 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;
+ desc->rtl
+ = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
+ gen_rtx_SYMBOL_REF (Pmode, desc->label));
- pop_obstacks ();
+ RTX_UNCHANGING_P (desc->rtl) = 1;
+ if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
+ MEM_SET_IN_STRUCT_P (desc->rtl, 1);
+
+ pop_obstacks ();
+
+ found = 0;
+ }
+
+ TREE_CST_RTL (exp) = desc->rtl;
/* 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
/* If this is the first time we've seen this particular constant,
output it (or defer its output for later). */
- if (found == 0)
+ if (! found)
{
int after_function = 0;
}
}
else
- output_constant_def_contents (exp, reloc, const_labelno++);
+ {
+ /* Do no output if -fsyntax-only. */
+ if (! flag_syntax_only)
+ output_constant_def_contents (exp, reloc, const_labelno);
+ ++const_labelno;
+ }
}
return TREE_CST_RTL (exp);
}
\f
-/* Similar hash facility for making memory-constants
- from constant rtl-expressions. It is used on RISC machines
- where immediate integer arguments and constant addresses are restricted
- so that such constants must be stored in memory.
-
- This pool of constants is reinitialized for each function
- so each function gets its own constants-pool that comes right before it.
-
- All structures allocated here are discarded when functions are saved for
- inlining, so they do not need to be allocated permanently. */
-
-#define MAX_RTX_HASH_TABLE 61
-static struct constant_descriptor **const_rtx_hash_table;
-
/* Structure to represent sufficient information about a constant so that
it can be output when the constant pool is output, so that function
integration can be done, and to simplify handling on machines that reference
int mark;
};
-/* Pointers to first and last constant in pool. */
-
-static struct pool_constant *first_pool, *last_pool;
-
-/* Current offset in constant pool (does not include any machine-specific
- header. */
-
-static int pool_offset;
-
/* Structure used to maintain hash table mapping symbols used to their
corresponding constants. */
struct pool_sym *next;
};
-static struct pool_sym **const_rtx_sym_hash_table;
-
/* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true.
The argument is XSTR (... , 0) */
#define SYMHASH(LABEL) \
((((unsigned long) (LABEL)) & ((1 << HASHBITS) - 1)) % MAX_RTX_HASH_TABLE)
\f
-/* Initialize constant pool hashing for next function. */
+/* Initialize constant pool hashing for a new function. */
void
-init_const_rtx_hash_table ()
+init_varasm_status (f)
+ struct function *f;
{
- const_rtx_hash_table
+ struct varasm_status *p;
+ p = (struct varasm_status *) xmalloc (sizeof (struct varasm_status));
+ f->varasm = p;
+ p->x_const_rtx_hash_table
= ((struct constant_descriptor **)
- oballoc (MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *)));
- const_rtx_sym_hash_table
+ xmalloc (MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *)));
+ p->x_const_rtx_sym_hash_table
= ((struct pool_sym **)
- oballoc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *)));
- bzero ((char *) const_rtx_hash_table,
+ xmalloc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *)));
+ bzero ((char *) p->x_const_rtx_hash_table,
MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *));
- bzero ((char *) const_rtx_sym_hash_table,
+ bzero ((char *) p->x_const_rtx_sym_hash_table,
MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *));
- first_pool = last_pool = 0;
- pool_offset = 0;
+ p->x_first_pool = p->x_last_pool = 0;
+ p->x_pool_offset = 0;
+ p->x_const_double_chain = 0;
+}
+
+/* Mark PC for GC. */
+
+static void
+mark_pool_constant (pc)
+ struct pool_constant *pc;
+{
+ while (pc)
+ {
+ ggc_mark_rtx (pc->constant);
+ pc = pc->next;
+ }
}
-/* Save and restore status for a nested function. */
+/* Mark PPS for GC. */
+
+static void
+mark_pool_sym_hash_table (pps)
+ struct pool_sym **pps;
+{
+ struct pool_sym *ps;
+ int i;
+
+ for (i = 0; i < MAX_RTX_HASH_TABLE; ++i)
+ for (ps = pps[i]; ps ; ps = ps->next)
+ ggc_mark_string (ps->label);
+}
+
+/* Mark P for GC. */
void
-save_varasm_status (p, context)
- struct function *p;
- tree context;
+mark_varasm_status (p)
+ struct varasm_status *p;
{
- 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;
+ if (p == NULL)
+ return;
+
+ mark_pool_constant (p->x_first_pool);
+ mark_pool_sym_hash_table (p->x_const_rtx_sym_hash_table);
+ ggc_mark_rtx (p->x_const_double_chain);
}
+/* Clear out all parts of the state in F that can safely be discarded
+ after the function has been compiled, to let garbage collection
+ reclaim the memory. */
+
void
-restore_varasm_status (p)
- struct function *p;
+free_varasm_status (f)
+ struct function *f;
{
- const_rtx_hash_table = p->const_rtx_hash_table;
- const_rtx_sym_hash_table = p->const_rtx_sym_hash_table;
- first_pool = p->first_pool;
- last_pool = p->last_pool;
- pool_offset = p->pool_offset;
- const_double_chain = p->const_double_chain;
+ struct varasm_status *p;
+
+ p = f->varasm;
+ free (p->x_const_rtx_hash_table);
+ free (p->x_const_rtx_sym_hash_table);
+ free (p);
+ f->varasm = NULL;
}
\f
enum kind { RTX_DOUBLE, RTX_INT };
switch (GET_CODE (value->un.addr.base))
{
case SYMBOL_REF:
- case LABEL_REF:
/* Use the string's address, not the SYMBOL_REF's address,
- for the sake of addresses of library routines.
- For a LABEL_REF, compare labels. */
+ for the sake of addresses of library routines. */
+ value->un.addr.base = (rtx) XSTR (value->un.addr.base, 0);
+ break;
+
+ case LABEL_REF:
+ /* For a LABEL_REF, compare labels. */
value->un.addr.base = XEXP (value->un.addr.base, 0);
default:
{
struct constant_descriptor *ptr;
char *label;
+ rtx rtl;
struct rtx_const value;
decode_rtx_const (mode, x, &value);
memory allocated from function_obstack (current_obstack). */
obstack_grow (saveable_obstack, &ptr, sizeof ptr);
obstack_grow (saveable_obstack, &label, sizeof label);
+ obstack_grow (saveable_obstack, &rtl, sizeof rtl);
/* Record constant contents. */
obstack_grow (saveable_obstack, &value, sizeof value);
modes in an alternating fashion, we will allocate a lot of different
memory locations, but this should be extremely rare. */
- /* Don't use CONST_DOUBLE_MEM in a nested function.
- Nested functions have their own constant pools,
- so they can't share the same values in CONST_DOUBLE_MEM
- with the containing function. */
- if (outer_function_chain == 0)
- if (GET_CODE (x) == CONST_DOUBLE
- && GET_CODE (CONST_DOUBLE_MEM (x)) == MEM
- && GET_MODE (CONST_DOUBLE_MEM (x)) == mode)
- return CONST_DOUBLE_MEM (x);
+ if (GET_CODE (x) == CONST_DOUBLE
+ && GET_CODE (CONST_DOUBLE_MEM (x)) == MEM
+ && GET_MODE (CONST_DOUBLE_MEM (x)) == mode)
+ return CONST_DOUBLE_MEM (x);
/* Compute hash code of X. Search the descriptors for that hash code
to see if any of them describes X. If yes, the descriptor records
++const_labelno;
- desc->label = found
- = (char *) obstack_copy0 (saveable_obstack, label, strlen (label));
+ desc->label = found = ggc_alloc_string (label, -1);
/* Add label to symbol hash table. */
hash = SYMHASH (found);
CONSTANT_POOL_ADDRESS_P (XEXP (def, 0)) = 1;
current_function_uses_const_pool = 1;
- if (outer_function_chain == 0)
- if (GET_CODE (x) == CONST_DOUBLE)
- {
- if (CONST_DOUBLE_MEM (x) == cc0_rtx)
- {
- CONST_DOUBLE_CHAIN (x) = const_double_chain;
- const_double_chain = x;
- }
- CONST_DOUBLE_MEM (x) = def;
- }
+ if (GET_CODE (x) == CONST_DOUBLE)
+ {
+ if (CONST_DOUBLE_MEM (x) == cc0_rtx)
+ {
+ CONST_DOUBLE_CHAIN (x) = const_double_chain;
+ const_double_chain = x;
+ }
+ CONST_DOUBLE_MEM (x) = def;
+ }
return def;
}
the corresponding pool_constant structure. */
static struct pool_constant *
-find_pool_constant (addr)
+find_pool_constant (f, addr)
+ struct function *f;
rtx addr;
{
struct pool_sym *sym;
- char *label = XSTR (addr, 0);
+ const char *label = XSTR (addr, 0);
- for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym; sym = sym->next)
+ for (sym = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; sym; sym = sym->next)
if (sym->label == label)
return sym->pool;
get_pool_constant (addr)
rtx addr;
{
- return (find_pool_constant (addr))->constant;
+ return (find_pool_constant (cfun, addr))->constant;
+}
+
+/* Likewise, but for the constant pool of a specific function. */
+
+rtx
+get_pool_constant_for_function (f, addr)
+ struct function *f;
+ rtx addr;
+{
+ return (find_pool_constant (f, addr))->constant;
}
/* Similar, return the mode. */
get_pool_mode (addr)
rtx addr;
{
- return (find_pool_constant (addr))->mode;
+ return (find_pool_constant (cfun, addr))->mode;
+}
+
+enum machine_mode
+get_pool_mode_for_function (f, addr)
+ struct function *f;
+ rtx addr;
+{
+ return (find_pool_constant (f, addr))->mode;
}
/* Similar, return the offset in the constant pool. */
get_pool_offset (addr)
rtx addr;
{
- return (find_pool_constant (addr))->offset;
+ return (find_pool_constant (cfun, addr))->offset;
}
/* Return the size of the constant pool. */
void
output_constant_pool (fnname, fndecl)
- char *fnname;
- tree fndecl;
+ const char *fnname ATTRIBUTE_UNUSED;
+ tree fndecl ATTRIBUTE_UNUSED;
{
struct pool_constant *pool;
rtx x;
/* 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 ();
+ mark_constant_pool ();
#ifdef ASM_OUTPUT_POOL_PROLOGUE
ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset);
#endif
if (pool->align > 1)
- ASM_OUTPUT_ALIGN (asm_out_file, exact_log2 (pool->align));
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (pool->align));
/* Output the label. */
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", pool->labelno);
insn = XEXP (insn, 1))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
mark_constants (PATTERN (insn));
+
+ /* It's possible that the only reference to a symbol is in a symbol
+ that's in the constant pool. This happens in Fortran under some
+ situations. (When the constant contains the address of another
+ constant, and only the first is used directly in an insn.)
+ This is potentially suboptimal if there's ever a possibility of
+ backwards (in pool order) 2'd level references. However, it's
+ not clear that 2'd level references can happen. */
+ for (pool = first_pool; pool; pool = pool->next)
+ {
+ struct pool_sym *sym;
+ const char *label;
+
+ /* skip unmarked entries; no insn refers to them. */
+ if (!pool->mark)
+ continue;
+
+ /* Skip everything except SYMBOL_REFs. */
+ if (GET_CODE (pool->constant) != SYMBOL_REF)
+ continue;
+ label = XSTR (pool->constant, 0);
+
+ /* Be sure the symbol's value is marked. */
+ for (sym = const_rtx_sym_hash_table[SYMHASH (label)]; sym;
+ sym = sym->next)
+ if (sym->label == label)
+ sym->pool->mark = 1;
+ /* If we didn't find it, there's something truly wrong here, but it
+ will be announced by the assembler. */
+ }
}
static void
register rtx x;
{
register int i;
- register char *format_ptr;
+ register const 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;
+ find_pool_constant (cfun, 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. */
+ a MEM, but does not constitute a use of that MEM. */
else if (GET_CODE (x) == CONST_DOUBLE)
return;
return reloc;
}
\f
+/* Return nonzero if VALUE is a valid constant-valued expression
+ for use in initializing a static variable; one that can be an
+ element of a "constant" initializer.
+
+ Return null_pointer_node if the value is absolute;
+ if it is relocatable, return the variable that determines the relocation.
+ We assume that VALUE has been folded as much as possible;
+ therefore, we do not need to check for such things as
+ arithmetic-combinations of integers. */
+
+tree
+initializer_constant_valid_p (value, endtype)
+ tree value;
+ tree endtype;
+{
+ /* Give the front-end a chance to convert VALUE to something that
+ looks more like a constant to the back-end. */
+ if (lang_expand_constant)
+ value = (*lang_expand_constant) (value);
+
+ switch (TREE_CODE (value))
+ {
+ case CONSTRUCTOR:
+ if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
+ && TREE_CONSTANT (value)
+ && CONSTRUCTOR_ELTS (value))
+ return
+ initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
+ endtype);
+
+ return TREE_STATIC (value) ? null_pointer_node : 0;
+
+ case INTEGER_CST:
+ case REAL_CST:
+ case STRING_CST:
+ case COMPLEX_CST:
+ return null_pointer_node;
+
+ case ADDR_EXPR:
+ return TREE_OPERAND (value, 0);
+
+ case NON_LVALUE_EXPR:
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+ /* Allow conversions between pointer types. */
+ if (POINTER_TYPE_P (TREE_TYPE (value))
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ /* Allow conversions between real types. */
+ if (FLOAT_TYPE_P (TREE_TYPE (value))
+ && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ /* Allow length-preserving conversions between integer types. */
+ if (INTEGRAL_TYPE_P (TREE_TYPE (value))
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
+ && (TYPE_PRECISION (TREE_TYPE (value))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ /* Allow conversions between other integer types only if
+ explicit value. */
+ if (INTEGRAL_TYPE_P (TREE_TYPE (value))
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+ {
+ tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ if (inner == null_pointer_node)
+ return null_pointer_node;
+ break;
+ }
+
+ /* Allow (int) &foo provided int is as wide as a pointer. */
+ if (INTEGRAL_TYPE_P (TREE_TYPE (value))
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
+ && (TYPE_PRECISION (TREE_TYPE (value))
+ >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+
+ /* Likewise conversions from int to pointers, but also allow
+ conversions from 0. */
+ if (POINTER_TYPE_P (TREE_TYPE (value))
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+ {
+ if (integer_zerop (TREE_OPERAND (value, 0)))
+ return null_pointer_node;
+ else if (TYPE_PRECISION (TREE_TYPE (value))
+ <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ }
+
+ /* Allow conversions to union types if the value inside is okay. */
+ if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ break;
+
+ case PLUS_EXPR:
+ if (! INTEGRAL_TYPE_P (endtype)
+ || TYPE_PRECISION (endtype) >= POINTER_SIZE)
+ {
+ tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
+ endtype);
+ /* If either term is absolute, use the other terms relocation. */
+ if (valid0 == null_pointer_node)
+ return valid1;
+ if (valid1 == null_pointer_node)
+ return valid0;
+ }
+ break;
+
+ case MINUS_EXPR:
+ if (! INTEGRAL_TYPE_P (endtype)
+ || TYPE_PRECISION (endtype) >= POINTER_SIZE)
+ {
+ tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
+ endtype);
+ /* Win if second argument is absolute. */
+ if (valid1 == null_pointer_node)
+ return valid0;
+ /* Win if both arguments have the same relocation.
+ Then the value is absolute. */
+ if (valid0 == valid1 && valid0 != 0)
+ return null_pointer_node;
+ }
+
+ /* Support differences between labels. */
+ if (INTEGRAL_TYPE_P (endtype))
+ {
+ tree op0, op1;
+ op0 = TREE_OPERAND (value, 0);
+ op1 = TREE_OPERAND (value, 1);
+ STRIP_NOPS (op0);
+ STRIP_NOPS (op1);
+
+ if (TREE_CODE (op0) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
+ && TREE_CODE (op1) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL)
+ return null_pointer_node;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+\f
/* Output assembler code for constant EXP to FILE, with no label.
This includes the pseudo-op such as ".int" or ".byte", and a newline.
Assumes output_addressed_constants has been done on EXP already.
{
register enum tree_code code = TREE_CODE (TREE_TYPE (exp));
- if (size == 0)
+ /* Some front-ends use constants other than the standard
+ language-indepdent varieties, but which may still be output
+ directly. Give the front-end a chance to convert EXP to a
+ language-independent representation. */
+ if (lang_expand_constant)
+ exp = (*lang_expand_constant) (exp);
+
+ if (size == 0 || flag_syntax_only)
return;
/* Eliminate the NON_LVALUE_EXPR_EXPR that makes a cast not be an lvalue.
That way we get the constant (we hope) inside it. Also, strip off any
- NOP_EXPR that converts between two record, union, array, or set types. */
+ NOP_EXPR that converts between two record, union, array, or set types
+ or a CONVERT_EXPR that converts to a union TYPE. */
while ((TREE_CODE (exp) == NOP_EXPR
&& (TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))
|| AGGREGATE_TYPE_P (TREE_TYPE (exp))))
+ || (TREE_CODE (exp) == CONVERT_EXPR
+ && code == UNION_TYPE)
|| TREE_CODE (exp) == NON_LVALUE_EXPR)
- exp = TREE_OPERAND (exp, 0);
+ {
+ exp = TREE_OPERAND (exp, 0);
+ code = TREE_CODE (TREE_TYPE (exp));
+ }
/* Allow a constructor with no elements for any data type.
This means to fill the space with zeros. */
int total_bytes = 0;
/* Non-zero means BYTE contains part of a byte, to be output. */
int byte_buffer_in_use = 0;
- register int byte;
+ register int byte = 0;
if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
abort ();
FIELD goes through the structure fields, if the constant is a structure.
if the constant is a union, then we override this,
by getting the field from the TREE_LIST element.
- But the constant could also be an array. Then FIELD is zero. */
+ But the constant could also be an array. Then FIELD is zero.
+
+ There is always a maximum of one element in the chain LINK for unions
+ (even if the initializer in a source program incorrectly contains
+ more one). */
for (link = CONSTRUCTOR_ELTS (exp);
link;
link = TREE_CHAIN (link),
register int fieldsize;
/* Since this structure is static,
we know the positions are constant. */
- int bitpos = (field ? (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field))
- / BITS_PER_UNIT)
- : 0);
+ HOST_WIDE_INT bitpos = field ? int_byte_position (field) : 0;
+
if (index != 0)
- bitpos = (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (val)))
- / BITS_PER_UNIT
- * (TREE_INT_CST_LOW (index) - min_index));
+ bitpos
+ = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (val)), 1)
+ * (tree_low_cst (index, 0) - min_index));
/* Output any buffered-up bit-fields preceding this element. */
if (byte_buffer_in_use)
/* Determine size this element should occupy. */
if (field)
{
- if (TREE_CODE (DECL_SIZE (field)) != INTEGER_CST)
+ if (TREE_CODE (DECL_SIZE_UNIT (field)) != INTEGER_CST)
abort ();
- if (TREE_INT_CST_LOW (DECL_SIZE (field)) > 100000)
- {
- /* This avoids overflow trouble. */
- tree size_tree = size_binop (CEIL_DIV_EXPR,
- DECL_SIZE (field),
- size_int (BITS_PER_UNIT));
- fieldsize = TREE_INT_CST_LOW (size_tree);
- }
- else
- {
- fieldsize = TREE_INT_CST_LOW (DECL_SIZE (field));
- fieldsize = (fieldsize + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
- }
+
+ fieldsize = TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
}
else
fieldsize = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
{
/* Element that is a bit-field. */
- int next_offset = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
- int end_offset
- = (next_offset + TREE_INT_CST_LOW (DECL_SIZE (field)));
+ HOST_WIDE_INT next_offset = int_bit_position (field);
+ HOST_WIDE_INT end_offset
+ = (next_offset + tree_low_cst (DECL_SIZE (field), 1));
if (val == 0)
val = integer_zero_node;
and put them into bytes from the most significant end. */
shift = end_offset - next_offset - this_time;
/* Don't try to take a bunch of bits that cross
- the word boundary in the INTEGER_CST. */
+ the word boundary in the INTEGER_CST. We can
+ only select bits from the LOW or HIGH part
+ not from both. */
if (shift < HOST_BITS_PER_WIDE_INT
&& shift + this_time > HOST_BITS_PER_WIDE_INT)
{
- this_time -= (HOST_BITS_PER_WIDE_INT - shift);
+ this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
shift = HOST_BITS_PER_WIDE_INT;
}
}
else
abort ();
+ /* Get the result. This works only when:
+ 1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
byte |= (((value >> shift)
- & (((HOST_WIDE_INT) 1 << this_time) - 1))
+ & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
<< (BITS_PER_UNIT - this_time - next_bit));
}
else
take first the least significant bits of the value
and pack them starting at the least significant
bits of the bytes. */
- shift = (next_offset
- - TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)));
+ shift = next_offset - int_bit_position (field);
+
/* Don't try to take a bunch of bits that cross
- the word boundary in the INTEGER_CST. */
+ the word boundary in the INTEGER_CST. We can
+ only select bits from the LOW or HIGH part
+ not from both. */
if (shift < HOST_BITS_PER_WIDE_INT
&& shift + this_time > HOST_BITS_PER_WIDE_INT)
- {
- this_time -= (HOST_BITS_PER_WIDE_INT - shift);
- shift = HOST_BITS_PER_WIDE_INT;
- }
+ this_time = (HOST_BITS_PER_WIDE_INT - shift);
/* Now get the bits from the appropriate constant word. */
if (shift < HOST_BITS_PER_WIDE_INT)
}
else
abort ();
+
+ /* Get the result. This works only when:
+ 1 <= this_time <= HOST_BITS_PER_WIDE_INT. */
byte |= (((value >> shift)
- & (((HOST_WIDE_INT) 1 << this_time) - 1))
+ & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
<< next_bit);
}
next_offset += this_time;
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);
+/* Add function NAME to the weak symbols list. VALUE is a weak alias
+ associatd with NAME. */
+
+int
+add_weak (name, value)
+ char *name;
+ char *value;
+{
+ struct weak_syms *weak;
- if (what != ps_value)
- weak->value = NULL_PTR;
+ weak = (struct weak_syms *) permalloc (sizeof (struct weak_syms));
- else
- {
- weak->value = permalloc (strlen (value) + 1);
- strcpy (weak->value, value);
- }
+ if (weak == NULL)
+ return 0;
- weak_decls = weak;
- }
- else if (! (what == ps_done || what == ps_start))
- warning ("malformed `#pragma weak'");
-#endif /* HANDLE_PRAGMA_WEAK */
+ weak->next = weak_decls;
+ weak->name = name;
+ weak->value = value;
+ weak_decls = weak;
+
+ return 1;
}
+#endif /* HANDLE_PRAGMA_WEAK */
/* Declare DECL to be a weak symbol. */
error_with_decl (decl, "weak declaration of `%s' must precede definition");
else if (SUPPORTS_WEAK)
DECL_WEAK (decl) = 1;
+#ifdef HANDLE_PRAGMA_WEAK
+ add_weak (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), NULL);
+#endif
}
/* Emit any pending weak declarations. */
+#ifdef HANDLE_PRAGMA_WEAK
+struct weak_syms * weak_decls;
+#endif
+
void
weak_finish ()
{
struct weak_syms *t;
for (t = weak_decls; t; t = t->next)
{
- ASM_WEAKEN_LABEL (asm_out_file, t->name);
- if (t->value)
- ASM_OUTPUT_DEF (asm_out_file, t->name, t->value);
+ if (t->name)
+ {
+ ASM_WEAKEN_LABEL (asm_out_file, t->name);
+ if (t->value)
+ ASM_OUTPUT_DEF (asm_out_file, t->name, t->value);
+ }
+ }
+ }
+#endif
+}
+
+/* Remove NAME from the pending list of weak symbols. This prevents
+ the compiler from emitting multiple .weak directives which confuses
+ some assemblers. */
+#ifdef ASM_WEAKEN_LABEL
+static void
+remove_from_pending_weak_list (name)
+ char *name ATTRIBUTE_UNUSED;
+{
+#ifdef HANDLE_PRAGMA_WEAK
+ if (HANDLE_PRAGMA_WEAK)
+ {
+ struct weak_syms *t;
+ for (t = weak_decls; t; t = t->next)
+ {
+ if (t->name && strcmp (name, t->name) == 0)
+ t->name = NULL;
}
}
#endif
}
+#endif
void
assemble_alias (decl, target)
- tree decl, target;
+ tree decl, target ATTRIBUTE_UNUSED;
{
- char *name;
+ const char *name;
make_decl_rtl (decl, (char *) 0, 1);
name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
{
#ifdef ASM_WEAKEN_LABEL
if (DECL_WEAK (decl))
- ASM_WEAKEN_LABEL (asm_out_file, name);
+ {
+ ASM_WEAKEN_LABEL (asm_out_file, name);
+ /* Remove this function from the pending weak list so that
+ we do not emit multiple .weak directives for it. */
+ remove_from_pending_weak_list
+ (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ }
else
#endif
ASM_GLOBALIZE_LABEL (asm_out_file, name);
}
+#ifdef ASM_OUTPUT_DEF_FROM_DECLS
+ ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
+#else
ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
+#endif
TREE_ASM_WRITTEN (decl) = 1;
#else
#ifdef ASM_OUTPUT_WEAK_ALIAS
else
abort ();
}
+
+void
+init_varasm_once ()
+{
+ ggc_add_root (const_hash_table, MAX_HASH_TABLE, sizeof const_hash_table[0],
+ mark_const_hash_entry);
+ ggc_add_string_root (&in_named_name, 1);
+}