/* 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 "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"
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 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
#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));
\f
static enum in_section { no_section, in_text, in_data, in_named
#endif
/* Text of section name when in_section == in_named. */
-static char *in_named_name;
+static const char *in_named_name;
/* Define functions like text_section for any extra sections. */
#ifdef EXTRA_SECTION_FUNCTIONS
abort ();
#endif
- in_named_name = ggc_alloc_string (name, -1);
+ in_named_name = ggc_strdup (name);
in_section = in_named;
}
}
-#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
-
#ifdef BSS_SECTION_ASM_OP
/* Tell the assembler to switch to the bss section. */
#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 *
or static or external function.
ASMSPEC, if not 0, is the string which the user specified
as the assembler symbol name.
- TOP_LEVEL is nonzero if this is a file-scope variable.
This is never called for PARM_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;
{
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");
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. */
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);
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
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
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 (memcmp ((char *) &TREE_STRING_LENGTH (exp), p,
sizeof TREE_STRING_LENGTH (exp)))
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;
+ }
+ }
}
}
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);
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_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 ();
}
}
/* 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. */
}
\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
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));
{
const char *name;
- make_decl_rtl (decl, (char *) 0, 1);
+ make_decl_rtl (decl, (char *) 0);
name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
#ifdef ASM_OUTPUT_DEF
#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);
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. */