/* 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"
#endif
#ifndef ASM_STABS_OP
-#define ASM_STABS_OP ".stabs"
+#define ASM_STABS_OP "\t.stabs\t"
#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. */
const char *first_global_object_name;
const char *weak_global_object_name;
-extern struct obstack *current_obstack;
-extern struct obstack *saveable_obstack;
-extern struct obstack *rtl_obstack;
extern struct obstack permanent_obstack;
#define obstack_chunk_alloc xmalloc
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 *
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;
+ /* 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. */
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));
+ SET_DECL_RTL (decl, gen_rtx_MEM (DECL_MODE (decl),
+ gen_rtx_SYMBOL_REF (Pmode, name)));
+ SYMBOL_REF_WEAK (XEXP (DECL_RTL (decl), 0)) = DECL_WEAK (decl);
if (TREE_CODE (decl) != FUNCTION_DECL)
set_mem_attributes (DECL_RTL (decl), decl, 1);
{
/* 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);
+ fprintf (asm_out_file, "%s\"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
assemble_name (asm_out_file, name);
fputc ('\n', asm_out_file);
}
{
/* 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);
+ fprintf (asm_out_file, "%s\"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
assemble_name (asm_out_file, name);
fputc ('\n', asm_out_file);
}
if (flag_gnu_linker)
{
/* 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);
+ fprintf (asm_out_file, "%s\"___PTR_LIST__\",22,0,0,", ASM_STABS_OP);
assemble_name (asm_out_file, name);
fputc ('\n', asm_out_file);
}
{
#ifdef ASM_BYTE_OP
fprintf (asm_out_file,
- "%s 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n", ASM_BYTE_OP);
+ "%s0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n", ASM_BYTE_OP);
#else
fprintf (asm_out_file,
"\tbyte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n");
if (i < size)
{
#ifdef ASM_BYTE_OP
- fprintf (asm_out_file, "%s 0", ASM_BYTE_OP);
+ fprintf (asm_out_file, "%s0", ASM_BYTE_OP);
#else
fprintf (asm_out_file, "\tbyte 0");
#endif
last_assemble_variable_decl = 0;
- if (GET_CODE (DECL_RTL (decl)) == REG)
+ if (DECL_RTL_SET_P (decl) && GET_CODE (DECL_RTL (decl)) == REG)
{
/* Do output symbol info for global register variables, but do nothing
else for them. */
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);
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
{
error ("floating point trap outputting a constant");
#ifdef REAL_IS_NOT_DOUBLE
- bzero ((char *) &d, sizeof d);
+ memset ((char *) &d, 0, sizeof d);
d = dconst0;
#else
d = 0;
abort ();
}
- set_float_handler (NULL_PTR);
+ set_float_handler (NULL);
}
\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);
&& GET_MODE (r) == mode)
return r;
- /* No; make a new one and add it to the chain.
-
- We may be called by an optimizer which may be discarding any memory
- allocated during its processing (such as combine and loop). However,
- we will be leaving this constant on the chain, so we cannot tolerate
- freed memory. So switch to saveable_obstack for this allocation
- and then switch back if we were in current_obstack. */
-
- push_obstacks_nochange ();
- rtl_in_saveable_obstack ();
+ /* No; make a new one and add it to the chain. */
r = gen_rtx_CONST_DOUBLE (mode, const0_rtx, i0, i1);
- pop_obstacks ();
/* Don't touch const_double_chain if not inside any function. */
if (current_function_decl != 0)
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;
We may be called by an optimizer which may be discarding any memory
allocated during its processing (such as combine and loop). However,
we will be leaving this constant on the chain, so we cannot tolerate
- freed memory. So switch to saveable_obstack for this allocation
- and then switch back if we were in current_obstack. */
- push_obstacks_nochange ();
- rtl_in_saveable_obstack ();
+ freed memory. */
r = rtx_alloc (CONST_DOUBLE);
- pop_obstacks ();
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. */
value->offset = offset;
}
\f
+enum kind { RTX_DOUBLE, RTX_INT };
+struct rtx_const
+{
+ ENUM_BITFIELD(kind) kind : 16;
+ ENUM_BITFIELD(machine_mode) mode : 16;
+ union {
+ union real_extract du;
+ struct addr_const addr;
+ struct {HOST_WIDE_INT high, low;} di;
+ } un;
+};
+
/* Uniquize all constants that appear in memory.
Each constant in memory thus far output is recorded
in `const_hash_table' with a `struct constant_descriptor'
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
default:
/* A language specific constant. Just hash the code. */
- return code % MAX_HASH_TABLE;
+ 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
- in the permanent obstack. We could also construct this in the
- obstack of EXP and put it into TREE_CST_RTL, but we have no way
- of knowing what obstack it is (e.g., it might be in a function
- obstack of a function we are nested inside). */
-
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
+ /* We have a symbol name; construct the SYMBOL_REF and the MEM. */
desc->rtl
= gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
gen_rtx_SYMBOL_REF (Pmode, desc->label));
set_mem_attributes (desc->rtl, exp, 1);
- pop_obstacks ();
found = 0;
}
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 = (struct deferred_constant *) xmalloc (sizeof (struct deferred_constant));
- push_obstacks_nochange ();
- suspend_momentary ();
p->exp = copy_constant (exp);
- pop_obstacks ();
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) */
f->varasm = p;
p->x_const_rtx_hash_table
= ((struct constant_descriptor **)
- xmalloc (MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *)));
+ xcalloc (MAX_RTX_HASH_TABLE, sizeof (struct constant_descriptor *)));
p->x_const_rtx_sym_hash_table
- = ((struct pool_sym **)
- xmalloc (MAX_RTX_HASH_TABLE * sizeof (struct pool_sym *)));
- bzero ((char *) p->x_const_rtx_hash_table,
- MAX_RTX_HASH_TABLE * sizeof (struct constant_descriptor *));
- bzero ((char *) p->x_const_rtx_sym_hash_table,
- 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;
{
while (pc)
{
+ ggc_mark (pc);
ggc_mark_rtx (pc->constant);
pc = pc->next;
}
}
-/* 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);
}
struct function *f;
{
struct varasm_status *p;
+ int i;
p = f->varasm;
+
+ /* Clear out the hash tables. */
+ for (i = 0; i < MAX_RTX_HASH_TABLE; ++i)
+ {
+ struct constant_descriptor* cd;
+
+ cd = p->x_const_rtx_hash_table[i];
+ while (cd) {
+ struct constant_descriptor* next = cd->next;
+ free (cd);
+ cd = next;
+ }
+ }
+
free (p->x_const_rtx_hash_table);
free (p->x_const_rtx_sym_hash_table);
free (p);
f->varasm = NULL;
}
\f
-enum kind { RTX_DOUBLE, RTX_INT };
-
-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
- union {
- union real_extract du;
- struct addr_const addr;
- struct {HOST_WIDE_INT high, low;} di;
- } un;
-};
/* 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. */
-
- {
- int *p = (int *) value;
- int *end = (int *) (value + 1);
- while (p < end)
- *p++ = 0;
- }
+ 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;
rtx x;
{
struct constant_descriptor *ptr;
- char *label;
- rtx rtl;
- struct rtx_const value;
- decode_rtx_const (mode, x, &value);
-
- /* Put these things in the saveable obstack so we can ensure it won't
- be freed if we are called from combine or some other phase that discards
- memory allocated from function_obstack (current_obstack). */
- obstack_grow (saveable_obstack, &ptr, sizeof ptr);
- obstack_grow (saveable_obstack, &label, sizeof label);
- obstack_grow (saveable_obstack, &rtl, sizeof rtl);
-
- /* Record constant contents. */
- obstack_grow (saveable_obstack, &value, sizeof value);
+ ptr = ((struct constant_descriptor *)
+ xcalloc (1, (offsetof (struct constant_descriptor, u)
+ + sizeof (struct rtx_const))));
+ decode_rtx_const (mode, x, (struct rtx_const *) ptr->u.contents);
- return (struct constant_descriptor *) obstack_finish (saveable_obstack);
+ return ptr;
}
\f
/* Given a constant rtx X, make (or find) a memory constant for its value
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.
pool_offset += align - 1;
pool_offset &= ~ (align - 1);
- /* If RTL is not being placed into the saveable obstack, make a
- copy of X that is in the saveable obstack in case we are
- being called from combine or some other phase that discards
- memory it allocates. We used to only do this if it is a
- CONST; however, reload can allocate a CONST_INT when
- eliminating registers. */
- if (rtl_obstack != saveable_obstack
- && (GET_CODE (x) == CONST || GET_CODE (x) == CONST_INT))
- {
- push_obstacks_nochange ();
- rtl_in_saveable_obstack ();
-
- if (GET_CODE (x) == CONST)
- x = gen_rtx_CONST (GET_MODE (x),
- gen_rtx_PLUS (GET_MODE (x),
- XEXP (XEXP (x, 0), 0),
- XEXP (XEXP (x, 0), 1)));
- else
- x = GEN_INT (INTVAL (x));
-
- pop_obstacks ();
- }
+ 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. */
- pool = (struct pool_constant *) savealloc (sizeof (struct pool_constant));
+ pool = (struct pool_constant *) ggc_alloc (sizeof (struct pool_constant));
pool->desc = desc;
pool->constant = x;
pool->mode = mode;
++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 *) savealloc (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 ();
}
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
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);
- 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);
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. */