/* Output variables, constants and external declarations, for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "config.h"
#include "system.h"
-#include <setjmp.h>
#include "rtl.h"
#include "tree.h"
#include "flags.h"
#include "expr.h"
#include "hard-reg-set.h"
#include "regs.h"
-#include "defaults.h"
#include "output.h"
#include "real.h"
#include "toplev.h"
-#include "dbxout.h"
-#include "sdbout.h"
#include "obstack.h"
+#include "hashtab.h"
#include "c-pragma.h"
#include "ggc.h"
#include "tm_p.h"
+#include "debug.h"
+#include "target.h"
#ifdef XCOFF_DEBUGGING_INFO
-#include "xcoffout.h"
+#include "xcoffout.h" /* Needed for external data
+ declarations for e.g. AIX 4.x. */
#endif
#ifndef TRAMPOLINE_ALIGNMENT
#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 "_CHKR_"
#define CHKR_PREFIX_SIZE (sizeof (CHKR_PREFIX) - 1)
-/* File in which assembler code is being written. */
-
-extern FILE *asm_out_file;
-
/* The (assembler) name of the first globally-visible object output. */
const char *first_global_object_name;
const char *weak_global_object_name;
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;
+ struct pool_constant **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. */
+ header). */
int x_pool_offset;
/* Chain of all CONST_DOUBLE rtx's constructed for the current function.
static const char *strip_reg_name PARAMS ((const char *));
static int contains_pointers_p PARAMS ((tree));
+static void assemble_real_1 PARAMS ((PTR));
static void decode_addr_const PARAMS ((tree, struct addr_const *));
static int const_hash PARAMS ((tree));
static int compare_constant PARAMS ((tree,
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 mark_constant PARAMS ((rtx *current_rtx, void *data));
static int output_addressed_constants PARAMS ((tree));
static void output_after_function_constants PARAMS ((void));
+static unsigned HOST_WIDE_INT array_size_for_constructor PARAMS ((tree));
static void output_constructor PARAMS ((tree, int));
#ifdef ASM_WEAKEN_LABEL
static void remove_from_pending_weak_list PARAMS ((const char *));
#endif
+static int in_named_entry_eq PARAMS ((const PTR, const PTR));
+static hashval_t in_named_entry_hash PARAMS ((const PTR));
#ifdef ASM_OUTPUT_BSS
static void asm_output_bss PARAMS ((FILE *, tree, const char *, int, int));
#endif
#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 int mark_const_str_htab_1 PARAMS ((void **, void *));
+static void mark_const_str_htab PARAMS ((void *));
+static hashval_t const_str_htab_hash PARAMS ((const void *x));
+static int const_str_htab_eq PARAMS ((const void *x, const void *y));
+static void const_str_htab_del PARAMS ((void *));
static void asm_emit_uninitialised PARAMS ((tree, const char*, int, int));
+static void resolve_unique_section PARAMS ((tree, int));
\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
+#ifdef CTORS_SECTION_ASM_OP
+ , in_ctors
+#endif
+#ifdef DTORS_SECTION_ASM_OP
+ , in_dtors
#endif
#ifdef EXTRA_SECTIONS
, EXTRA_SECTIONS
#endif
/* Text of section name when in_section == in_named. */
-static char *in_named_name;
+static const char *in_named_name;
+
+/* Hash table of flags that have been used for a particular named section. */
+
+struct in_named_entry
+{
+ const char *name;
+ unsigned int flags;
+};
+
+static htab_t in_named_htab;
/* Define functions like text_section for any extra sections. */
#ifdef EXTRA_SECTION_FUNCTIONS
{
if (in_section != in_text)
{
+#ifdef TEXT_SECTION
+ TEXT_SECTION ();
+#else
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
+#endif
in_section = in_text;
}
}
}
}
/* Tell assembler to ALWAYS switch to data section, in case
- it's not sure where it it. */
+ it's not sure where it is. */
void
force_data_section ()
return in_section == in_data;
}
+/* Helper routines for maintaining in_named_htab. */
+
+static int
+in_named_entry_eq (p1, p2)
+ const PTR p1;
+ const PTR p2;
+{
+ const struct in_named_entry *old = p1;
+ const char *new = p2;
+
+ return strcmp (old->name, new) == 0;
+}
+
+static hashval_t
+in_named_entry_hash (p)
+ const PTR p;
+{
+ const struct in_named_entry *old = p;
+ return htab_hash_string (old->name);
+}
+
+/* If SECTION has been seen before as a named section, return the flags
+ that were used. Otherwise, return 0. Note, that 0 is a perfectly valid
+ set of flags for a section to have, so 0 does not mean that the section
+ has not been seen. */
+
+unsigned int
+get_named_section_flags (section)
+ const char *section;
+{
+ struct in_named_entry **slot;
+
+ slot = (struct in_named_entry**)
+ htab_find_slot_with_hash (in_named_htab, section,
+ htab_hash_string (section), NO_INSERT);
+
+ return slot ? (*slot)->flags : 0;
+}
+
+/* Record FLAGS for SECTION. If SECTION was previously recorded with a
+ different set of flags, return false. */
+
+bool
+set_named_section_flags (section, flags)
+ const char *section;
+ unsigned int flags;
+{
+ struct in_named_entry **slot, *entry;
+
+ slot = (struct in_named_entry**)
+ htab_find_slot_with_hash (in_named_htab, section,
+ htab_hash_string (section), INSERT);
+ entry = *slot;
+
+ if (!entry)
+ {
+ entry = (struct in_named_entry *) xmalloc (sizeof (*entry));
+ *slot = entry;
+ entry->name = ggc_strdup (section);
+ entry->flags = flags;
+ }
+ else if (entry->flags != flags)
+ return false;
+
+ return true;
+}
+
+/* Tell assembler to change to section NAME with attributes FLAGS. */
+
+void
+named_section_flags (name, flags)
+ const char *name;
+ unsigned int flags;
+{
+ if (in_section != in_named || strcmp (name, in_named_name) != 0)
+ {
+ if (! set_named_section_flags (name, flags))
+ abort ();
+
+ (* targetm.asm_out.named_section) (name, flags);
+
+ if (flags & SECTION_FORGET)
+ in_section = no_section;
+ else
+ {
+ in_named_name = ggc_strdup (name);
+ in_section = in_named;
+ }
+ }
+}
+
/* 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.
named_section (decl, name, reloc)
tree decl;
const char *name;
- int reloc ATTRIBUTE_UNUSED;
+ int reloc;
{
+ unsigned int flags;
+
if (decl != NULL_TREE && !DECL_P (decl))
abort ();
if (name == NULL)
name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
- if (in_section != in_named || strcmp (name, in_named_name))
- {
-#ifdef ASM_OUTPUT_SECTION_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
+ flags = (* targetm.section_type_flags) (decl, name, reloc);
- in_named_name = ggc_alloc_string (name, -1);
- in_section = in_named;
+ /* Sanity check user variables for flag changes. Non-user
+ section flag changes will abort in named_section_flags. */
+ if (decl && ! set_named_section_flags (name, flags))
+ {
+ error_with_decl (decl, "%s causes a section type conflict");
+ flags = get_named_section_flags (name);
}
+
+ named_section_flags (name, flags);
}
-#ifdef ASM_OUTPUT_SECTION_NAME
-#ifndef UNIQUE_SECTION
-#define UNIQUE_SECTION(DECL,RELOC) \
-do { \
- int len; \
- const char *name; \
- char *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
+/* If required, set DECL_SECTION_NAME to a unique name. */
+
+static void
+resolve_unique_section (decl, reloc)
+ tree decl;
+ int reloc ATTRIBUTE_UNUSED;
+{
+ if (DECL_SECTION_NAME (decl) == NULL_TREE
+ && (flag_function_sections
+ || (targetm.have_named_sections
+ && DECL_ONE_ONLY (decl))))
+ UNIQUE_SECTION (decl, reloc);
+}
#ifdef BSS_SECTION_ASM_OP
#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 defined (EXCEPTION_SECTION)
EXCEPTION_SECTION ();
#else
-#ifdef ASM_OUTPUT_SECTION_NAME
- named_section (NULL_TREE, ".gcc_except_table", 0);
-#else
- if (flag_pic)
+ if (targetm.have_named_sections)
+ 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.
- The rtl is stored into DECL. */
-
-void
-make_function_rtl (decl)
- tree decl;
-{
- const char *name;
- const char *new_name;
-
- if (DECL_RTL (decl) != 0)
- {
- /* ??? 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
- return;
- }
-
- name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- new_name = name;
-
- /* 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)
- {
- char *label;
- ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
- var_labelno++;
- new_name = label;
- }
- /* 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. */
- else if (flag_prefix_function_name)
- {
- size_t name_len = IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (decl));
- char *pname;
-
- pname = alloca (name_len + CHKR_PREFIX_SIZE + 1);
- memcpy (pname, CHKR_PREFIX, CHKR_PREFIX_SIZE);
- memcpy (pname + CHKR_PREFIX_SIZE, name, name_len + 1);
- new_name = pname;
- }
-
- if (name != new_name)
- {
- DECL_ASSEMBLER_NAME (decl) = get_identifier (new_name);
- name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- }
-
- DECL_RTL (decl)
- = 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 ASM_OUTPUT_LABELREF will have to know
- how to strip this information. */
-#ifdef ENCODE_SECTION_INFO
- ENCODE_SECTION_INFO (decl);
-#endif
-}
-
-
/* Given NAME, a putative register name, discard any customary prefixes. */
static const char *
return -1;
}
\f
-/* 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.
+/* Create the DECL_RTL for a VAR_DECL or FUNCTION_DECL. DECL should
+ have static storage duration. In other words, it should not be an
+ automatic variable, including PARM_DECLs.
+
+ There is, however, one exception: this function handles variables
+ explicitly placed in a particular register by the user.
+
+ ASMSPEC, if not 0, is the string which the user specified as the
+ assembler symbol name.
This is never called for PARM_DECL nodes. */
void
-make_decl_rtl (decl, asmspec, top_level)
+make_decl_rtl (decl, asmspec)
tree decl;
const char *asmspec;
- int top_level;
{
+ int top_level = (DECL_CONTEXT (decl) == NULL_TREE);
const char *name = 0;
const char *new_name = 0;
int reg_number;
+ rtx x;
+
+ /* Check that we are not being given an automatic variable. */
+ /* A weak alias has TREE_PUBLIC set but not the other bits. */
+ if (TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == RESULT_DECL
+ || (TREE_CODE (decl) == VAR_DECL
+ && !TREE_STATIC (decl)
+ && !TREE_PUBLIC (decl)
+ && !DECL_EXTERNAL (decl)
+ && !DECL_REGISTER (decl)))
+ abort ();
+ /* And that we were not given a type or a label. */
+ else if (TREE_CODE (decl) == TYPE_DECL
+ || TREE_CODE (decl) == LABEL_DECL)
+ abort ();
/* For a duplicate declaration, we can be called twice on the
same DECL node. Don't discard the RTL already made. */
- if (DECL_RTL (decl) != 0)
+ if (DECL_RTL_SET_P (decl))
{
/* If the old RTL had the wrong mode, fix the mode. */
if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
{
int nregs;
- if (DECL_INITIAL (decl) != 0 && top_level)
+ if (DECL_INITIAL (decl) != 0 && TREE_STATIC (decl))
{
DECL_INITIAL (decl) = 0;
error ("global register variable has initial value");
usage is somewhat suspect, we nevertheless use the following
kludge to avoid setting DECL_RTL to frame_pointer_rtx. */
- DECL_RTL (decl)
- = gen_rtx_REG (DECL_MODE (decl), FIRST_PSEUDO_REGISTER);
+ SET_DECL_RTL (decl,
+ gen_rtx_REG (DECL_MODE (decl),
+ FIRST_PSEUDO_REGISTER));
REGNO (DECL_RTL (decl)) = reg_number;
REG_USERVAR_P (DECL_RTL (decl)) = 1;
- if (top_level)
+ if (TREE_STATIC (decl))
{
/* Make this register global, so not usable for anything
else. */
"register name given for non-register variable `%s'");
/* Specifying a section attribute on a variable forces it into a
- non-.bss section, and thus it cannot be common. */
+ non-.bss section, and thus it cannot be common. */
if (TREE_CODE (decl) == VAR_DECL
&& DECL_SECTION_NAME (decl) != NULL_TREE
&& DECL_INITIAL (decl) == NULL_TREE
Concatenate a distinguishing number. */
if (!top_level && !TREE_PUBLIC (decl)
&& ! (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
- && asmspec == 0)
+ && asmspec == 0
+ && name == IDENTIFIER_POINTER (DECL_NAME (decl)))
{
char *label;
ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
if (name != new_name)
{
- DECL_ASSEMBLER_NAME (decl) = get_identifier (new_name);
+ SET_DECL_ASSEMBLER_NAME (decl, get_identifier (new_name));
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
}
&& (TREE_PUBLIC (decl) || TREE_STATIC (decl)))))
TREE_SIDE_EFFECTS (decl) = 1;
- DECL_RTL (decl) = gen_rtx_MEM (DECL_MODE (decl),
- gen_rtx_SYMBOL_REF (Pmode, name));
+ x = gen_rtx_MEM (DECL_MODE (decl), gen_rtx_SYMBOL_REF (Pmode, name));
+ SYMBOL_REF_WEAK (XEXP (x, 0)) = DECL_WEAK (decl);
if (TREE_CODE (decl) != FUNCTION_DECL)
- set_mem_attributes (DECL_RTL (decl), decl, 1);
+ set_mem_attributes (x, decl, 1);
+ SET_DECL_RTL (decl, x);
/* Optionally set flags or add text to the name to record information
such as that it is a function name.
fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));
}
-#if 0 /* This should no longer be needed, because
- flag_gnu_linker should be 0 on these systems,
- which should prevent any output
- if ASM_OUTPUT_CONSTRUCTOR and ASM_OUTPUT_DESTRUCTOR are absent. */
-#if !(defined(DBX_DEBUGGING_INFO) && !defined(FASCIST_ASSEMBLER))
-#ifndef ASM_OUTPUT_CONSTRUCTOR
-#define ASM_OUTPUT_CONSTRUCTOR(file, name)
-#endif
-#ifndef ASM_OUTPUT_DESTRUCTOR
-#define ASM_OUTPUT_DESTRUCTOR(file, name)
-#endif
-#endif
-#endif /* 0 */
+/* Record an element in the table of global destructors. SYMBOL is
+ a SYMBOL_REF of the function to be called; PRIORITY is a number
+ between 0 and MAX_INIT_PRIORITY. */
-/* Record an element in the table of global destructors.
- How this is done depends on what sort of assembler and linker
- are in use.
+void
+default_stabs_asm_out_destructor (symbol, priority)
+ rtx symbol;
+ int priority ATTRIBUTE_UNUSED;
+{
+ /* Tell GNU LD that this is part of the static destructor set.
+ This will work for any system that uses stabs, most usefully
+ aout systems. */
+ fprintf (asm_out_file, "%s\"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
+ assemble_name (asm_out_file, XSTR (symbol, 0));
+ fputc ('\n', asm_out_file);
+}
+
+void
+default_named_section_asm_out_destructor (symbol, priority)
+ rtx symbol;
+ int priority;
+{
+ const char *section = ".dtors";
+ char buf[16];
- NAME should be the name of a global function to be called
- at exit time. This name is output using assemble_name. */
+ /* ??? This only works reliably with the GNU linker. */
+ if (priority != DEFAULT_INIT_PRIORITY)
+ {
+ sprintf (buf, ".dtors.%.5u",
+ /* Invert the numbering so the linker puts us in the proper
+ order; constructors are run from right to left, and the
+ linker sorts in increasing order. */
+ MAX_INIT_PRIORITY - priority);
+ section = buf;
+ }
+ named_section_flags (section, SECTION_WRITE);
+ assemble_align (POINTER_SIZE);
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+}
+
+#ifdef DTORS_SECTION_ASM_OP
void
-assemble_destructor (name)
- const char *name;
+dtors_section ()
{
-#ifdef ASM_OUTPUT_DESTRUCTOR
- ASM_OUTPUT_DESTRUCTOR (asm_out_file, name);
-#else
- if (flag_gnu_linker)
+ if (in_section != in_dtors)
{
- /* Now tell GNU LD that this is part of the static destructor set. */
- /* This code works for any machine provided you use GNU as/ld. */
- fprintf (asm_out_file, "%s\"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
- assemble_name (asm_out_file, name);
+ in_section = in_dtors;
+ fputs (DTORS_SECTION_ASM_OP, asm_out_file);
fputc ('\n', asm_out_file);
}
-#endif
}
+void
+default_dtor_section_asm_out_destructor (symbol, priority)
+ rtx symbol;
+ int priority ATTRIBUTE_UNUSED;
+{
+ dtors_section ();
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+}
+#endif
+
/* Likewise for global constructors. */
void
-assemble_constructor (name)
- const char *name;
+default_stabs_asm_out_constructor (symbol, priority)
+ rtx symbol;
+ int priority ATTRIBUTE_UNUSED;
{
-#ifdef ASM_OUTPUT_CONSTRUCTOR
- ASM_OUTPUT_CONSTRUCTOR (asm_out_file, name);
-#else
- if (flag_gnu_linker)
+ /* Tell GNU LD that this is part of the static destructor set.
+ This will work for any system that uses stabs, most usefully
+ aout systems. */
+ fprintf (asm_out_file, "%s\"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
+ assemble_name (asm_out_file, XSTR (symbol, 0));
+ fputc ('\n', asm_out_file);
+}
+
+void
+default_named_section_asm_out_constructor (symbol, priority)
+ rtx symbol;
+ int priority;
+{
+ const char *section = ".ctors";
+ char buf[16];
+
+ /* ??? This only works reliably with the GNU linker. */
+ if (priority != DEFAULT_INIT_PRIORITY)
{
- /* Now tell GNU LD that this is part of the static constructor set. */
- /* This code works for any machine provided you use GNU as/ld. */
- fprintf (asm_out_file, "%s\"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
- assemble_name (asm_out_file, name);
- fputc ('\n', asm_out_file);
+ sprintf (buf, ".ctors.%.5u",
+ /* Invert the numbering so the linker puts us in the proper
+ order; constructors are run from right to left, and the
+ linker sorts in increasing order. */
+ MAX_INIT_PRIORITY - priority);
+ section = buf;
}
-#endif
-}
-/* Likewise for entries we want to record for garbage collection.
- Garbage collection is still under development. */
+ named_section_flags (section, SECTION_WRITE);
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+}
+#ifdef CTORS_SECTION_ASM_OP
void
-assemble_gc_entry (name)
- const char *name;
+ctors_section ()
{
-#ifdef ASM_OUTPUT_GC_ENTRY
- ASM_OUTPUT_GC_ENTRY (asm_out_file, name);
-#else
- if (flag_gnu_linker)
+ if (in_section != in_ctors)
{
- /* Now tell GNU LD that this is part of the static constructor set. */
- fprintf (asm_out_file, "%s\"___PTR_LIST__\",22,0,0,", ASM_STABS_OP);
- assemble_name (asm_out_file, name);
+ in_section = in_ctors;
+ fputs (CTORS_SECTION_ASM_OP, asm_out_file);
fputc ('\n', asm_out_file);
}
-#endif
}
+
+void
+default_ctor_section_asm_out_constructor (symbol, priority)
+ rtx symbol;
+ int priority ATTRIBUTE_UNUSED;
+{
+ ctors_section ();
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
+}
+#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
if (CONSTANT_POOL_BEFORE_FUNCTION)
output_constant_pool (fnname, decl);
-#ifdef ASM_OUTPUT_SECTION_NAME
- /* If the function is to be put in its own section and it's not in a section
- already, indicate so. */
- if ((flag_function_sections
- && DECL_SECTION_NAME (decl) == NULL_TREE)
- || UNIQUE_SECTION_P (decl))
- UNIQUE_SECTION (decl, 0);
-#endif
-
+ resolve_unique_section (decl, 0);
function_section (decl);
/* Tell assembler to move to target machine's alignment for functions. */
ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
#endif
-#ifdef SDB_DEBUGGING_INFO
- /* Output SDB definition of the function. */
- if (write_symbols == SDB_DEBUG)
- sdbout_mark_begin_function ();
-#endif
-
-#ifdef DBX_DEBUGGING_INFO
- /* Output DBX definition of the function. */
- if (write_symbols == DBX_DEBUG)
- dbxout_begin_function (decl);
-#endif
+ (*debug_hooks->begin_function) (decl);
/* Make function name accessible from other files, if appropriate. */
}
}
-#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, 0);
-#endif
-
+ resolve_unique_section (decl, 0);
+
switch (destination)
{
#ifdef ASM_EMIT_BSS
register const char *name;
unsigned int align;
int reloc = 0;
- enum in_section saved_in_section;
+ rtx decl_rtl;
last_assemble_variable_decl = 0;
- if (GET_CODE (DECL_RTL (decl)) == REG)
- {
- /* Do output symbol info for global register variables, but do nothing
- else for them. */
-
- if (TREE_ASM_WRITTEN (decl))
- 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)
- && 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);
-#endif
-
- /* Don't output any DWARF debugging information for variables here.
- In the case of local variables, the information for them is output
- when we do our recursive traversal of the tree representation for
- the entire containing function. In the case of file-scope variables,
- we output information for all of them at the very end of compilation
- while we are doing our final traversal of the chain of file-scope
- declarations. */
-
- return;
- }
-
/* Normally no need to say anything here for external references,
since assemble_external is called by the language-specific code
when a declaration is first seen. */
if (TREE_CODE (decl) == FUNCTION_DECL)
return;
+ /* Do nothing for global register variables. */
+ if (DECL_RTL_SET_P (decl) && GET_CODE (DECL_RTL (decl)) == REG)
+ {
+ TREE_ASM_WRITTEN (decl) = 1;
+ return;
+ }
+
/* If type was incomplete when the variable was declared,
see if it is complete now. */
if (TREE_ASM_WRITTEN (decl))
return;
+ /* Make sure ENCODE_SECTION_INFO is invoked before we set ASM_WRITTEN. */
+ decl_rtl = DECL_RTL (decl);
+
TREE_ASM_WRITTEN (decl) = 1;
/* Do no output if -fsyntax-only. */
&& ! host_integerp (DECL_SIZE_UNIT (decl), 1))
{
error_with_decl (decl, "size of variable `%s' is too large");
- goto finish;
+ return;
}
- name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+ name = XSTR (XEXP (decl_rtl, 0), 0);
if (TREE_PUBLIC (decl) && DECL_NAME (decl)
&& ! first_global_object_name
&& ! (DECL_COMMON (decl) && (DECL_INITIAL (decl) == 0
}
/* On some machines, it is good to increase alignment sometimes. */
+ if (! DECL_USER_ALIGN (decl))
+ {
#ifdef DATA_ALIGNMENT
- align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
+ 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);
+ 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, "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)
- 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);
-#endif
-
- /* Don't output any DWARF debugging information for variables here.
- In the case of local variables, the information for them is output
- when we do our recursive traversal of the tree representation for
- the entire containing function. In the case of file-scope variables,
- we output information for all of them at the very end of compilation
- while we are doing our final traversal of the chain of file-scope
- declarations. */
-
-#if 0 /* ??? We should either delete this or add a comment describing what
- it was intended to do and why we shouldn't delete it. */
- if (flag_shared_data)
- data_section ();
-#endif
asm_emit_uninitialised (decl, name, size, rounded);
- goto finish;
+ return;
}
/* Handle initialized definitions.
#endif
ASM_GLOBALIZE_LABEL (asm_out_file, name);
}
-#if 0
- for (d = equivalents; d; d = TREE_CHAIN (d))
- {
- tree e = TREE_VALUE (d);
- if (TREE_PUBLIC (e) && DECL_NAME (e))
- ASM_GLOBALIZE_LABEL (asm_out_file,
- XSTR (XEXP (DECL_RTL (e), 0), 0));
- }
-#endif
/* Output any data that we will need to use the address of. */
if (DECL_INITIAL (decl) == error_mark_node)
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. */
+ resolve_unique_section (decl, reloc);
variable_section (decl, reloc);
/* dbxout.c needs to know this. */
if (in_text_section ())
DECL_IN_TEXT_SECTION (decl) = 1;
- /* Record current section so we can restore it if dbxout.c clobbers it. */
- saved_in_section = in_section;
-
- /* Output the dbx info now that we have chosen the section. */
-
-#ifdef DBX_DEBUGGING_INFO
- /* File-scope global variables are output here. */
- if (write_symbols == DBX_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);
-#endif
-
- /* Don't output any DWARF debugging information for variables here.
- In the case of local variables, the information for them is output
- when we do our recursive traversal of the tree representation for
- the entire containing function. In the case of file-scope variables,
- we output information for all of them at the very end of compilation
- while we are doing our final traversal of the chain of file-scope
- declarations. */
-
- /* If the debugging output changed sections, reselect the section
- that's supposed to be selected. */
- if (in_section != saved_in_section)
- variable_section (decl, reloc);
-
/* Output the alignment of this data. */
if (align > BITS_PER_UNIT)
ASM_OUTPUT_ALIGN (asm_out_file,
/* Leave space for it. */
assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
}
-
- finish:
-#ifdef XCOFF_DEBUGGING_INFO
- /* Unfortunately, the IBM assembler cannot handle stabx before the actual
- declaration. When something like ".stabx "aa:S-2",aa,133,0" is emitted
- and `aa' hasn't been output yet, the assembler generates a stab entry with
- a value of zero, in addition to creating an unnecessary external entry
- for `aa'. Hence, we must postpone dbxout_symbol to here at the end. */
-
- /* File-scope global variables are output here. */
- if (write_symbols == XCOFF_DEBUG && top_level)
- {
- saved_in_section = in_section;
-
- dbxout_symbol (decl, 0);
-
- if (in_section != saved_in_section)
- variable_section (decl, reloc);
- }
-#else
- /* There must be a statement after a label. */
- ;
-#endif
}
/* Return 1 if type TYPE contains any pointers. */
assemble_external (decl)
tree decl ATTRIBUTE_UNUSED;
{
+ /* Because most platforms do not define ASM_OUTPUT_EXTERNAL, the
+ main body of this code is only rarely exercised. To provide some
+ testing, on all platforms, we make sure that the ASM_OUT_FILE is
+ open. If it's not, we should not be calling this function. */
+ if (!asm_out_file)
+ abort ();
+
#ifdef ASM_OUTPUT_EXTERNAL
if (DECL_P (decl) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
{
STRIP_NAME_ENCODING (real_name, name);
if (flag_prefix_function_name
- && ! bcmp (real_name, CHKR_PREFIX, CHKR_PREFIX_SIZE))
+ && ! memcmp (real_name, CHKR_PREFIX, CHKR_PREFIX_SIZE))
real_name = real_name + CHKR_PREFIX_SIZE;
id = maybe_get_identifier (real_name);
int size;
{
char name[12];
- char *namestring;
+ const char *namestring;
rtx x;
#if 0
ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno);
++const_labelno;
- namestring = ggc_alloc_string (name, -1);
+ namestring = ggc_strdup (name);
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. */
- /* Variable `rounded' might or might not be used in ASM_OUTPUT_LOCAL. */
+ /* 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)
assemble_trampoline_template ()
{
char label[256];
- char *name;
+ const char *name;
int align;
/* By default, put trampoline templates in read-only data section. */
/* Record the rtl to refer to it. */
ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0);
- name = ggc_alloc_string (label, -1);
+ name = ggc_strdup (label);
return gen_rtx_SYMBOL_REF (Pmode, name);
}
#endif
}
\f
/* Assemble the floating-point constant D into an object of size MODE. */
-
-void
-assemble_real (d, mode)
- REAL_VALUE_TYPE d;
- enum machine_mode mode;
+struct assemble_real_args
{
- jmp_buf output_constant_handler;
-
- if (setjmp (output_constant_handler))
- {
- error ("floating point trap outputting a constant");
-#ifdef REAL_IS_NOT_DOUBLE
- bzero ((char *) &d, sizeof d);
- d = dconst0;
-#else
- d = 0;
-#endif
- }
+ REAL_VALUE_TYPE *d;
+ enum machine_mode mode;
+};
- set_float_handler (output_constant_handler);
+static void
+assemble_real_1 (p)
+ PTR p;
+{
+ struct assemble_real_args *args = (struct assemble_real_args *) p;
+ REAL_VALUE_TYPE *d = args->d;
+ enum machine_mode mode = args->mode;
switch (mode)
{
#ifdef ASM_OUTPUT_BYTE_FLOAT
case QFmode:
- ASM_OUTPUT_BYTE_FLOAT (asm_out_file, d);
+ ASM_OUTPUT_BYTE_FLOAT (asm_out_file, *d);
break;
#endif
#ifdef ASM_OUTPUT_SHORT_FLOAT
case HFmode:
- ASM_OUTPUT_SHORT_FLOAT (asm_out_file, d);
+ ASM_OUTPUT_SHORT_FLOAT (asm_out_file, *d);
break;
#endif
#ifdef ASM_OUTPUT_THREE_QUARTER_FLOAT
case TQFmode:
- ASM_OUTPUT_THREE_QUARTER_FLOAT (asm_out_file, d);
+ ASM_OUTPUT_THREE_QUARTER_FLOAT (asm_out_file, *d);
break;
#endif
#ifdef ASM_OUTPUT_FLOAT
case SFmode:
- ASM_OUTPUT_FLOAT (asm_out_file, d);
+ ASM_OUTPUT_FLOAT (asm_out_file, *d);
break;
#endif
#ifdef ASM_OUTPUT_DOUBLE
case DFmode:
- ASM_OUTPUT_DOUBLE (asm_out_file, d);
+ ASM_OUTPUT_DOUBLE (asm_out_file, *d);
break;
#endif
#ifdef ASM_OUTPUT_LONG_DOUBLE
case XFmode:
case TFmode:
- ASM_OUTPUT_LONG_DOUBLE (asm_out_file, d);
+ ASM_OUTPUT_LONG_DOUBLE (asm_out_file, *d);
break;
#endif
default:
abort ();
}
+}
+
+void
+assemble_real (d, mode)
+ REAL_VALUE_TYPE d;
+ enum machine_mode mode;
+{
+ struct assemble_real_args args;
+ args.d = &d;
+ args.mode = mode;
- set_float_handler (NULL_PTR);
+ if (do_float_handler (assemble_real_1, (PTR) &args))
+ return;
+
+ internal_error ("floating point trap outputting a constant");
}
\f
/* Here we combine duplicate floating constants to make
represented as a 64 bit value -1, and not as 0x00000000ffffffff.
The later confuses the sparc backend. */
- if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
+ if (width < HOST_BITS_PER_WIDE_INT
&& (i0 & ((HOST_WIDE_INT) 1 << (width - 1))))
i0 |= ((HOST_WIDE_INT) (-1) << width);
u.d = d;
- /* Detect special cases. But be careful we don't use a CONST_DOUBLE
- that's from a parent function since it may be in its constant pool. */
- if (REAL_VALUES_IDENTICAL (dconst0, d)
- && (cfun == 0 || decl_function_context (current_function_decl) == 0))
+ /* Detect special cases. */
+ 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
dump here if we pass a NaN to REAL_VALUES_EQUAL and if REAL_VALUES_EQUAL
does a floating point comparison. */
- else if ((! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d))
- && (cfun == 0
- || decl_function_context (current_function_decl) == 0))
+ else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d))
return CONST1_RTX (mode);
if (sizeof u == sizeof (HOST_WIDE_INT))
If one is found, return it. */
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)
+ if (! memcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
&& GET_MODE (r) == mode)
return r;
freed memory. */
r = rtx_alloc (CONST_DOUBLE);
PUT_MODE (r, mode);
- bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (r), sizeof u);
+ memcpy ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u);
/* If we aren't inside a function, don't put r on the
const_double_chain. */
clear_const_double_mem ()
{
register rtx r, next;
+ enum machine_mode mode;
+ int i;
for (r = const_double_chain; r; r = next)
{
CONST_DOUBLE_MEM (r) = cc0_rtx;
}
const_double_chain = 0;
+
+ for (i = 0; i <= 2; i++)
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ r = const_tiny_rtx[i][(int) mode];
+ CONST_DOUBLE_CHAIN (r) = 0;
+ CONST_DOUBLE_MEM (r) = cc0_rtx;
+ }
}
\f
/* Given an expression EXP with a constant value,
offset += int_byte_position (TREE_OPERAND (target, 1));
target = TREE_OPERAND (target, 0);
}
- else if (TREE_CODE (target) == ARRAY_REF)
+ else if (TREE_CODE (target) == ARRAY_REF
+ || TREE_CODE (target) == ARRAY_RANGE_REF)
{
offset += (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (target)), 1)
* tree_low_cst (TREE_OPERAND (target, 1), 0));
value->offset = offset;
}
\f
+enum kind { RTX_DOUBLE, RTX_INT };
struct rtx_const
{
-#ifdef ONLY_INT_FIELDS
- unsigned int kind : 16;
- unsigned int mode : 16;
-#else
- enum kind kind : 16;
- enum machine_mode mode : 16;
-#endif
+ ENUM_BITFIELD(kind) kind : 16;
+ ENUM_BITFIELD(machine_mode) mode : 16;
union {
union real_extract du;
struct addr_const addr;
struct constant_descriptor
{
struct constant_descriptor *next;
- char *label;
+ const char *label;
rtx rtl;
- unsigned char contents[1];
+ /* Make sure the data is reasonably aligned. */
+ union
+ {
+ unsigned char contents[1];
+#ifdef HAVE_LONG_DOUBLE
+ long double d;
+#else
+ double d;
+#endif
+ } u;
};
#define HASHBITS 30
#define MAX_HASH_TABLE 1009
static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
+#define STRHASH(x) ((hashval_t)((long)(x) >> 3))
+
+struct deferred_string
+{
+ const char *label;
+ tree exp;
+ int labelno;
+};
+
+static htab_t const_str_htab;
+
/* Mark a const_hash_table descriptor for GC. */
static void
while (desc)
{
- ggc_mark_string ((const char *)desc->label);
ggc_mark_rtx (desc->rtl);
desc = desc->next;
}
}
+/* Mark the hash-table element X (which is really a pointer to an
+ struct deferred_string *). */
+
+static int
+mark_const_str_htab_1 (x, data)
+ void **x;
+ void *data ATTRIBUTE_UNUSED;
+{
+ ggc_mark_tree (((struct deferred_string *) *x)->exp);
+ return 1;
+}
+
+/* Mark a const_str_htab for GC. */
+
+static void
+mark_const_str_htab (htab)
+ void *htab;
+{
+ htab_traverse (*((htab_t *) htab), mark_const_str_htab_1, NULL);
+}
+
+/* Returns a hash code for X (which is a really a
+ struct deferred_string *). */
+
+static hashval_t
+const_str_htab_hash (x)
+ const void *x;
+{
+ return STRHASH (((const struct deferred_string *) x)->label);
+}
+
+/* Returns non-zero if the value represented by X (which is really a
+ struct deferred_string *) is the same as that given by Y
+ (which is really a char *). */
+
+static int
+const_str_htab_eq (x, y)
+ const void *x;
+ const void *y;
+{
+ return (((const struct deferred_string *) x)->label == (const char *) y);
+}
+
+/* Delete the hash table entry dfsp. */
+
+static void
+const_str_htab_del (dfsp)
+ void *dfsp;
+{
+ free (dfsp);
+}
+
/* Compute a hash code for a constant expression. */
static int
return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
default:
- /* A language specific constant. Just hash the code. */
- return code % MAX_HASH_TABLE;
+ /* A language specific constant. Just hash the code. */
+ return (int) code % MAX_HASH_TABLE;
}
/* Compute hashing function */
tree exp;
struct constant_descriptor *desc;
{
- return 0 != compare_constant_1 (exp, desc->contents);
+ return 0 != compare_constant_1 (exp, desc->u.contents);
}
/* Compare constant expression EXP with a substring P of a constant descriptor.
if ((enum machine_mode) *p++ != TYPE_MODE (TREE_TYPE (exp)))
return 0;
- strp = (unsigned char *)TREE_STRING_POINTER (exp);
+ strp = (const unsigned char *)TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
- if (bcmp ((char *) &TREE_STRING_LENGTH (exp), p,
+ if (memcmp ((char *) &TREE_STRING_LENGTH (exp), p,
sizeof TREE_STRING_LENGTH (exp)))
return 0;
get_set_constructor_bytes (exp, tmp, len);
strp = (unsigned char *) tmp;
- if (bcmp ((char *) &xlen, p, sizeof xlen))
+ if (memcmp ((char *) &xlen, p, sizeof xlen))
return 0;
p += sizeof xlen;
if (TREE_PURPOSE (link))
have_purpose = 1;
- if (bcmp ((char *) &length, p, sizeof length))
+ if (memcmp ((char *) &length, p, sizeof length))
return 0;
p += sizeof length;
else
type = 0;
- if (bcmp ((char *) &type, p, sizeof type))
+ if (memcmp ((char *) &type, p, sizeof type))
return 0;
if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
{
- if (bcmp ((char *) &mode, p, sizeof mode))
+ if (memcmp ((char *) &mode, p, sizeof mode))
return 0;
p += sizeof mode;
p += sizeof type;
- if (bcmp ((char *) &have_purpose, p, sizeof have_purpose))
+ if (memcmp ((char *) &have_purpose, p, sizeof have_purpose))
return 0;
p += sizeof have_purpose;
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
- if (bcmp ((char *) &size, p, sizeof size))
+ if (memcmp ((char *) &size, p, sizeof size))
return 0;
p += sizeof size;
{
tree zero = 0;
- if (bcmp ((char *) &zero, p, sizeof zero))
+ if (memcmp ((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,
+ if (memcmp ((char *) &TREE_PURPOSE (link), p,
sizeof TREE_PURPOSE (link)))
return 0;
{
int zero = 0;
- if (bcmp ((char *) &zero, p, sizeof zero))
+ if (memcmp ((char *) &zero, p, sizeof zero))
return 0;
p += sizeof zero;
return 0;
/* Compare symbol name. */
- strp = (unsigned char *) XSTR (value.base, 0);
- len = strlen ((char *) strp) + 1;
+ strp = (const unsigned char *) XSTR (value.base, 0);
+ len = strlen ((const char *) strp) + 1;
}
break;
struct constant_descriptor *next = 0;
char *label = 0;
rtx rtl = 0;
+ int pad;
/* 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);
+
+ /* Align the descriptor for the data payload. */
+ pad = (offsetof (struct constant_descriptor, u)
+ - offsetof(struct constant_descriptor, rtl)
+ - sizeof(next->rtl));
+ if (pad > 0)
+ obstack_blank (&permanent_obstack, pad);
+
record_constant_1 (exp);
return (struct constant_descriptor *) obstack_finish (&permanent_obstack);
}
record_constant_1 (exp)
tree exp;
{
- register unsigned char *strp;
+ register const unsigned char *strp;
register int len;
register enum tree_code code = TREE_CODE (exp);
return;
obstack_1grow (&permanent_obstack, TYPE_MODE (TREE_TYPE (exp)));
- strp = (unsigned char *) TREE_STRING_POINTER (exp);
+ strp = (const unsigned char *) TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
obstack_grow (&permanent_obstack, (char *) &TREE_STRING_LENGTH (exp),
sizeof TREE_STRING_LENGTH (exp));
Otherwise, output such a constant in memory (or defer it for later)
and generate an rtx for it.
+ If DEFER is non-zero, the output of string constants can be deferred
+ and output only if referenced in the function after all optimizations.
+
The TREE_CST_RTL of EXP is set up to point to that rtx.
The const_hash_table records which constants already have label strings. */
rtx
-output_constant_def (exp)
+output_constant_def (exp, defer)
tree exp;
+ int defer;
{
register int hash;
register struct constant_descriptor *desc;
+ struct deferred_string **defstr;
char label[256];
int reloc;
int found = 1;
+ int after_function = 0;
+ int labelno = -1;
if (TREE_CST_RTL (exp))
return TREE_CST_RTL (exp);
future calls to this function to find. */
/* Create a string containing the label name, in LABEL. */
- ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
+ labelno = const_labelno++;
+ ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
desc = record_constant (exp);
desc->next = const_hash_table[hash];
- desc->label = ggc_alloc_string (label, -1);
+ desc->label = ggc_strdup (label);
const_hash_table[hash] = desc;
/* We have a symbol name; construct the SYMBOL_REF and the MEM. */
such as that it is a function name. If the name is changed, the macro
ASM_OUTPUT_LABELREF will have to know how to strip this information. */
#ifdef ENCODE_SECTION_INFO
- ENCODE_SECTION_INFO (exp);
-#endif
-
- /* If this is the first time we've seen this particular constant,
- output it (or defer its output for later). */
+ /* A previously-processed constant would already have section info
+ encoded in it. */
if (! found)
{
- int after_function = 0;
+ ENCODE_SECTION_INFO (exp);
+ desc->rtl = TREE_CST_RTL (exp);
+ desc->label = XSTR (XEXP (desc->rtl, 0), 0);
+ }
+#endif
#ifdef CONSTANT_AFTER_FUNCTION_P
- if (current_function_decl != 0
- && CONSTANT_AFTER_FUNCTION_P (exp))
- after_function = 1;
+ if (current_function_decl != 0
+ && CONSTANT_AFTER_FUNCTION_P (exp))
+ after_function = 1;
#endif
+ if (found
+ && STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0))
+ && (!defer || defer_addressed_constants_flag || after_function))
+ {
+ defstr = (struct deferred_string **)
+ htab_find_slot_with_hash (const_str_htab, desc->label,
+ STRHASH (desc->label), NO_INSERT);
+ if (defstr)
+ {
+ /* If the string is currently deferred but we need to output it now,
+ remove it from deferred string hash table. */
+ found = 0;
+ labelno = (*defstr)->labelno;
+ STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)) = 0;
+ htab_clear_slot (const_str_htab, (void **) defstr);
+ }
+ }
+
+ /* If this is the first time we've seen this particular constant,
+ output it (or defer its output for later). */
+ if (! found)
+ {
if (defer_addressed_constants_flag || after_function)
{
struct deferred_constant *p;
p->exp = copy_constant (exp);
p->reloc = reloc;
- p->labelno = const_labelno++;
+ p->labelno = labelno;
if (after_function)
{
p->next = after_function_constants;
{
/* Do no output if -fsyntax-only. */
if (! flag_syntax_only)
- output_constant_def_contents (exp, reloc, const_labelno);
- ++const_labelno;
+ {
+ if (TREE_CODE (exp) != STRING_CST
+ || !defer
+ || flag_writable_strings
+ || (defstr = (struct deferred_string **)
+ htab_find_slot_with_hash (const_str_htab,
+ desc->label,
+ STRHASH (desc->label),
+ INSERT)) == NULL)
+ output_constant_def_contents (exp, reloc, labelno);
+ else
+ {
+ struct deferred_string *p;
+
+ p = (struct deferred_string *)
+ xmalloc (sizeof (struct deferred_string));
+
+ p->exp = copy_constant (exp);
+ p->label = desc->label;
+ p->labelno = labelno;
+ *defstr = p;
+ STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)) = 1;
+ }
+ }
}
}
/* Output the value of EXP. */
output_constant (exp,
(TREE_CODE (exp) == STRING_CST
- ? TREE_STRING_LENGTH (exp)
+ ? MAX (TREE_STRING_LENGTH (exp),
+ int_size_in_bytes (TREE_TYPE (exp)))
: int_size_in_bytes (TREE_TYPE (exp))));
}
struct pool_constant
{
struct constant_descriptor *desc;
- struct pool_constant *next;
- enum machine_mode mode;
+ struct pool_constant *next, *next_sym;
+ const char *label;
rtx constant;
+ enum machine_mode mode;
int labelno;
int align;
int offset;
int mark;
};
-/* Structure used to maintain hash table mapping symbols used to their
- corresponding constants. */
-
-struct pool_sym
-{
- char *label;
- struct pool_constant *pool;
- struct pool_sym *next;
-};
-
/* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true.
The argument is XSTR (... , 0) */
= ((struct constant_descriptor **)
xcalloc (MAX_RTX_HASH_TABLE, sizeof (struct constant_descriptor *)));
p->x_const_rtx_sym_hash_table
- = ((struct pool_sym **)
- xcalloc (MAX_RTX_HASH_TABLE, sizeof (struct pool_sym *)));
+ = ((struct pool_constant **)
+ xcalloc (MAX_RTX_HASH_TABLE, sizeof (struct pool_constant *)));
p->x_first_pool = p->x_last_pool = 0;
p->x_pool_offset = 0;
}
}
-/* 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
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);
}
for (i = 0; i < MAX_RTX_HASH_TABLE; ++i)
{
struct constant_descriptor* cd;
- struct pool_sym *ps;
cd = p->x_const_rtx_hash_table[i];
while (cd) {
free (cd);
cd = next;
}
-
- ps = p->x_const_rtx_sym_hash_table[i];
- while (ps) {
- struct pool_sym *next = ps->next;
- free (ps);
- ps = next;
- }
}
free (p->x_const_rtx_hash_table);
f->varasm = NULL;
}
\f
-enum kind { RTX_DOUBLE, RTX_INT };
/* Express an rtx for a constant integer (perhaps symbolic)
as the sum of a symbol or label plus an explicit integer.
struct rtx_const *value;
{
/* Clear the whole structure, including any gaps. */
- bzero (value, sizeof (struct rtx_const));
+ memset (value, 0, sizeof (struct rtx_const));
value->kind = RTX_INT; /* Most usual kind. */
value->mode = mode;
if (GET_MODE (x) != VOIDmode)
{
value->mode = GET_MODE (x);
- bcopy ((char *) &CONST_DOUBLE_LOW (x),
- (char *) &value->un.du, sizeof value->un.du);
+ memcpy ((char *) &value->un.du,
+ (char *) &CONST_DOUBLE_LOW (x), sizeof value->un.du);
}
else
{
case CONST:
x = XEXP (x, 0);
- if (GET_CODE (x) == PLUS)
+ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
{
value->un.addr.base = XEXP (x, 0);
- if (GET_CODE (XEXP (x, 1)) != CONST_INT)
- abort ();
value->un.addr.offset = INTVAL (XEXP (x, 1));
}
- else if (GET_CODE (x) == MINUS)
+ else if (GET_CODE (x) == MINUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
{
value->un.addr.base = XEXP (x, 0);
- if (GET_CODE (XEXP (x, 1)) != CONST_INT)
- abort ();
value->un.addr.offset = - INTVAL (XEXP (x, 1));
}
else
- abort ();
+ {
+ value->un.addr.base = x;
+ value->un.addr.offset = 0;
+ }
break;
default:
rtx x;
struct constant_descriptor *desc;
{
- register int *p = (int *) desc->contents;
+ register int *p = (int *) desc->u.contents;
register int *strp;
register int len;
struct rtx_const value;
struct constant_descriptor *ptr;
ptr = ((struct constant_descriptor *)
- xcalloc (1,
- (sizeof (struct constant_descriptor)
- + sizeof (struct rtx_const) - 1)));
- decode_rtx_const (mode, x, (struct rtx_const *) ptr->contents);
+ xcalloc (1, (offsetof (struct constant_descriptor, u)
+ + sizeof (struct rtx_const))));
+ decode_rtx_const (mode, x, (struct rtx_const *) ptr->u.contents);
return ptr;
}
register int hash;
register struct constant_descriptor *desc;
char label[256];
- char *found = 0;
+ const char *found = 0;
rtx def;
/* If we want this CONST_DOUBLE in the same mode as it is in memory
if (found == 0)
{
register struct pool_constant *pool;
- register struct pool_sym *sym;
int align;
/* No constant equal to X is known to have been output.
const_rtx_hash_table[hash] = desc;
/* Align the location counter as required by EXP's data type. */
- align = (mode == VOIDmode) ? UNITS_PER_WORD : GET_MODE_SIZE (mode);
- if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
- align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+ align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
#ifdef CONSTANT_ALIGNMENT
align = CONSTANT_ALIGNMENT (make_tree (type_for_mode (mode, 0), x),
- align * BITS_PER_UNIT) / BITS_PER_UNIT;
+ align);
#endif
- pool_offset += align - 1;
- pool_offset &= ~ (align - 1);
+ pool_offset += (align / BITS_PER_UNIT) - 1;
+ pool_offset &= ~ ((align / BITS_PER_UNIT) - 1);
+
+ if (GET_CODE (x) == LABEL_REF)
+ LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
/* Allocate a pool constant descriptor, fill it in, and chain it in. */
++const_labelno;
- desc->label = found = ggc_alloc_string (label, -1);
+ desc->label = found = ggc_strdup (label);
/* Add label to symbol hash table. */
hash = SYMHASH (found);
- sym = (struct pool_sym *) xmalloc (sizeof (struct pool_sym));
- sym->label = found;
- sym->pool = pool;
- sym->next = const_rtx_sym_hash_table[hash];
- const_rtx_sym_hash_table[hash] = sym;
+ pool->label = found;
+ pool->next_sym = const_rtx_sym_hash_table[hash];
+ const_rtx_sym_hash_table[hash] = pool;
}
/* We have a symbol name; construct the SYMBOL_REF and the MEM. */
struct function *f;
rtx addr;
{
- struct pool_sym *sym;
+ struct pool_constant *pool;
const char *label = XSTR (addr, 0);
- for (sym = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; sym;
- sym = sym->next)
- if (sym->label == label)
- return sym->pool;
+ for (pool = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; pool;
+ pool = pool->next_sym)
+ if (pool->label == label)
+ return pool;
abort ();
}
pool->align, pool->labelno, done);
#endif
- if (pool->align > 1)
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (pool->align));
+ assemble_align (pool->align);
/* Output the label. */
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", pool->labelno);
if (GET_CODE (x) != CONST_DOUBLE)
abort ();
- bcopy ((char *) &CONST_DOUBLE_LOW (x), (char *) &u, sizeof u);
+ memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (x), sizeof u);
assemble_real (u.d, pool->mode);
break;
}
/* Look through the instructions for this function, and mark all the
- entries in the constant pool which are actually being used. */
+ entries in the constant pool which are actually being used.
+ Emit used deferred strings. */
static void
mark_constant_pool ()
register rtx insn;
struct pool_constant *pool;
- if (first_pool == 0)
+ if (first_pool == 0 && htab_elements (const_str_htab) == 0)
return;
for (pool = first_pool; pool; pool = pool->next)
insn = XEXP (insn, 1))
if (INSN_P (insn))
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. */
- }
}
+/* Look through appropriate parts of X, marking all entries in the
+ constant pool which are actually being used. Entries that are only
+ referenced by other constants are also marked as used. Emit
+ deferred strings that are used. */
+
static void
mark_constants (x)
- register rtx x;
+ rtx x;
{
register int i;
register const char *format_ptr;
if (GET_CODE (x) == SYMBOL_REF)
{
- if (CONSTANT_POOL_ADDRESS_P (x))
- find_pool_constant (cfun, x)->mark = 1;
+ mark_constant (&x, NULL);
return;
}
/* Never search inside a CONST_DOUBLE, because CONST_DOUBLE_MEM may be
}
}
}
+
+/* Given a SYMBOL_REF CURRENT_RTX, mark it and all constants it refers
+ to as used. Emit referenced deferred strings. This function can
+ be used with for_each_rtx () to mark all SYMBOL_REFs in an rtx. */
+
+static int
+mark_constant (current_rtx, data)
+ rtx *current_rtx;
+ void *data ATTRIBUTE_UNUSED;
+{
+ rtx x = *current_rtx;
+
+ if (x == NULL_RTX)
+ return 0;
+ else if (GET_CODE(x) == CONST_DOUBLE)
+ /* Never search inside a CONST_DOUBLE because CONST_DOUBLE_MEM may
+ be a MEM but does not constitute a use of that MEM. */
+ return -1;
+ else if (GET_CODE (x) == SYMBOL_REF)
+ {
+ if (CONSTANT_POOL_ADDRESS_P (x))
+ {
+ struct pool_constant *pool = find_pool_constant (cfun, x);
+ if (pool->mark == 0) {
+ pool->mark = 1;
+ for_each_rtx (&(pool->constant), &mark_constant, NULL);
+ }
+ else
+ return -1;
+ }
+ else if (STRING_POOL_ADDRESS_P (x))
+ {
+ struct deferred_string **defstr;
+
+ defstr = (struct deferred_string **)
+ htab_find_slot_with_hash (const_str_htab, XSTR (x, 0),
+ STRHASH (XSTR (x, 0)), NO_INSERT);
+ if (defstr)
+ {
+ struct deferred_string *p = *defstr;
+
+ STRING_POOL_ADDRESS_P (x) = 0;
+ output_constant_def_contents (p->exp, 0, p->labelno);
+ htab_clear_slot (const_str_htab, (void **) defstr);
+ }
+ }
+ }
+ return 0;
+}
\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.
{
int reloc = 0;
+ /* 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)
+ exp = (*lang_expand_constant) (exp);
+
switch (TREE_CODE (exp))
{
case ADDR_EXPR:
|| TREE_CODE (constant) == CONSTRUCTOR)
/* No need to do anything here
for addresses of variables or functions. */
- output_constant_def (constant);
+ output_constant_def (constant, 0);
}
reloc = 1;
break;
Then the value is absolute. */
if (valid0 == valid1 && valid0 != 0)
return null_pointer_node;
+
+ /* Since GCC guarantees that string constants are unique in the
+ generated code, a subtraction between two copies of the same
+ constant string is absolute. */
+ if (valid0 && TREE_CODE (valid0) == STRING_CST &&
+ valid1 && TREE_CODE (valid1) == STRING_CST &&
+ TREE_STRING_POINTER (valid0) == TREE_STRING_POINTER (valid1))
+ return null_pointer_node;
}
/* Support differences between labels. */
directly. Give the front-end a chance to convert EXP to a
language-independent representation. */
if (lang_expand_constant)
- exp = (*lang_expand_constant) (exp);
+ {
+ exp = (*lang_expand_constant) (exp);
+ code = TREE_CODE (TREE_TYPE (exp));
+ }
if (size == 0 || flag_syntax_only)
return;
}
\f
-/* Subroutine of output_constant, used for CONSTRUCTORs
- (aggregate constants).
+/* Subroutine of output_constructor, used for computing the size of
+ arrays of unspecified length. VAL must be a CONSTRUCTOR of an array
+ type with an unspecified upper bound. */
+
+static unsigned HOST_WIDE_INT
+array_size_for_constructor (val)
+ tree val;
+{
+ tree max_index, i;
+
+ max_index = NULL_TREE;
+ for (i = CONSTRUCTOR_ELTS (val); i ; i = TREE_CHAIN (i))
+ {
+ tree index = TREE_PURPOSE (i);
+
+ if (TREE_CODE (index) == RANGE_EXPR)
+ index = TREE_OPERAND (index, 1);
+ if (max_index == NULL_TREE || tree_int_cst_lt (max_index, index))
+ max_index = index;
+ }
+
+ if (max_index == NULL_TREE)
+ return 0;
+
+ /* Compute the total number of array elements. */
+ i = size_binop (MINUS_EXPR, convert (sizetype, max_index),
+ convert (sizetype,
+ TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)))));
+ i = size_binop (PLUS_EXPR, i, convert (sizetype, integer_one_node));
+
+ /* Multiply by the array element unit size to find number of bytes. */
+ i = size_binop (MULT_EXPR, i, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
+
+ return tree_low_cst (i, 1);
+}
+
+/* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants).
Generate at least SIZE bytes, padding if necessary. */
static void
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). */
+ more one). */
for (link = CONSTRUCTOR_ELTS (exp);
link;
link = TREE_CHAIN (link),
if (index && TREE_CODE (index) == RANGE_EXPR)
{
- register int fieldsize
+ unsigned HOST_WIDE_INT fieldsize
= int_size_in_bytes (TREE_TYPE (type));
HOST_WIDE_INT lo_index = tree_low_cst (TREE_OPERAND (index, 0), 0);
HOST_WIDE_INT hi_index = tree_low_cst (TREE_OPERAND (index, 1), 0);
{
/* An element that is not a bit-field. */
- register int fieldsize;
+ unsigned HOST_WIDE_INT fieldsize;
/* Since this structure is static,
we know the positions are constant. */
HOST_WIDE_INT pos = field ? int_byte_position (field) : 0;
/* Determine size this element should occupy. */
if (field)
- fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
+ {
+ fieldsize = 0;
+
+ /* If this is an array with an unspecified upper bound,
+ the initializer determines the size. */
+ /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
+ but we cannot do this until the deprecated support for
+ initializing zero-length array members is removed. */
+ if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+ && TYPE_DOMAIN (TREE_TYPE (field))
+ && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
+ {
+ fieldsize = array_size_for_constructor (val);
+ /* Given a non-empty initialization, this field had
+ better be last. */
+ if (fieldsize != 0 && TREE_CHAIN (field) != NULL_TREE)
+ abort ();
+ }
+ else if (DECL_SIZE_UNIT (field))
+ {
+ /* ??? This can't be right. If the decl size overflows
+ a host integer we will silently emit no data. */
+ if (host_integerp (DECL_SIZE_UNIT (field), 1))
+ fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
+ }
+ }
else
fieldsize = int_size_in_bytes (TREE_TYPE (type));
for (t = weak_decls; t; t = t->next)
{
if (t->name)
- {
- ASM_WEAKEN_LABEL (asm_out_file, t->name);
- if (t->value)
- ASM_OUTPUT_DEF (asm_out_file, t->name, t->value);
- }
+ ASM_OUTPUT_WEAK_ALIAS (asm_out_file, t->name, t->value);
}
}
#endif
{
const char *name;
- make_decl_rtl (decl, (char *) 0, 1);
- name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+ /* We must force creation of DECL_RTL for debug info generation, even though
+ we don't use it here. */
+ make_decl_rtl (decl, NULL);
+
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
#ifdef ASM_OUTPUT_DEF
/* Make name accessible from other files, if appropriate. */
#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
void
init_varasm_once ()
{
+ const_str_htab = htab_create (128, const_str_htab_hash, const_str_htab_eq,
+ const_str_htab_del);
+ in_named_htab = htab_create (31, in_named_entry_hash,
+ in_named_entry_eq, NULL);
+
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);
+ ggc_add_root (&const_str_htab, 1, sizeof const_str_htab,
+ mark_const_str_htab);
}
-/* Extra support for EH values. */
-void
-assemble_eh_label (name)
+/* Select a set of attributes for section NAME based on the properties
+ of DECL and whether or not RELOC indicates that DECL's initializer
+ might contain runtime relocations.
+
+ We make the section read-only and executable for a function decl,
+ read-only for a const data decl, and writable for a non-const data decl. */
+
+unsigned int
+default_section_type_flags (decl, name, reloc)
+ tree decl;
const char *name;
+ int reloc;
{
-#ifdef ASM_OUTPUT_EH_LABEL
- ASM_OUTPUT_EH_LABEL (asm_out_file, name);
-#else
- assemble_label (name);
-#endif
+ unsigned int flags;
+
+ if (decl && TREE_CODE (decl) == FUNCTION_DECL)
+ flags = SECTION_CODE;
+ else if (decl && DECL_READONLY_SECTION (decl, reloc))
+ flags = 0;
+ else
+ flags = SECTION_WRITE;
+
+ if (decl && DECL_ONE_ONLY (decl))
+ flags |= SECTION_LINKONCE;
+
+ if (strcmp (name, ".bss") == 0
+ || strncmp (name, ".bss.", 5) == 0
+ || strncmp (name, ".gnu.linkonce.b.", 16) == 0
+ || strcmp (name, ".sbss") == 0
+ || strncmp (name, ".sbss.", 6) == 0
+ || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
+ flags |= SECTION_BSS;
+
+ return flags;
}
-/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
+/* Output assembly to switch to section NAME with attribute FLAGS.
+ Four variants for common object file formats. */
void
-assemble_eh_align (align)
- int align;
+default_no_named_section (name, flags)
+ const char *name ATTRIBUTE_UNUSED;
+ unsigned int flags ATTRIBUTE_UNUSED;
{
-#ifdef ASM_OUTPUT_EH_ALIGN
- if (align > BITS_PER_UNIT)
- ASM_OUTPUT_EH_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
-#else
- assemble_align (align);
-#endif
+ /* Some object formats don't support named sections at all. The
+ front-end should already have flagged this as an error. */
+ abort ();
}
-
-/* On some platforms, we may want to specify a special mechansim to
- output EH data when generating with a function.. */
-int
-assemble_eh_integer (x, size, force)
- rtx x;
- int size;
- int force;
+void
+default_elf_asm_named_section (name, flags)
+ const char *name;
+ unsigned int flags;
{
+ char flagchars[8], *f = flagchars;
+ const char *type;
+
+ if (!(flags & SECTION_DEBUG))
+ *f++ = 'a';
+ if (flags & SECTION_WRITE)
+ *f++ = 'w';
+ if (flags & SECTION_CODE)
+ *f++ = 'x';
+ if (flags & SECTION_SMALL)
+ *f++ = 's';
+ *f = '\0';
+
+ if (flags & SECTION_BSS)
+ type = "nobits";
+ else
+ type = "progbits";
- switch (size)
- {
-#ifdef ASM_OUTPUT_EH_CHAR
- case 1:
- ASM_OUTPUT_EH_CHAR (asm_out_file, x);
- return 1;
-#endif
-
-#ifdef ASM_OUTPUT_EH_SHORT
- case 2:
- ASM_OUTPUT_EH_SHORT (asm_out_file, x);
- return 1;
-#endif
+ fprintf (asm_out_file, "\t.section\t%s,\"%s\",@%s\n",
+ name, flagchars, type);
+}
-#ifdef ASM_OUTPUT_EH_INT
- case 4:
- ASM_OUTPUT_EH_INT (asm_out_file, x);
- return 1;
-#endif
+void
+default_coff_asm_named_section (name, flags)
+ const char *name;
+ unsigned int flags;
+{
+ char flagchars[8], *f = flagchars;
-#ifdef ASM_OUTPUT_EH_DOUBLE_INT
- case 8:
- ASM_OUTPUT_EH_DOUBLE_INT (asm_out_file, x);
- return 1;
-#endif
+ if (flags & SECTION_WRITE)
+ *f++ = 'w';
+ if (flags & SECTION_CODE)
+ *f++ = 'x';
+ *f = '\0';
- default:
- break;
- }
- return (assemble_integer (x, size, force));
+ fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars);
}
+void
+default_pe_asm_named_section (name, flags)
+ const char *name;
+ unsigned int flags;
+{
+ default_coff_asm_named_section (name, flags);
-
+ if (flags & SECTION_LINKONCE)
+ {
+ /* Functions may have been compiled at various levels of
+ optimization so we can't use `same_size' here.
+ Instead, have the linker pick one. */
+ fprintf (asm_out_file, "\t.linkonce %s\n",
+ (flags & SECTION_CODE ? "discard" : "same_size"));
+ }
+}