#include "hashtab.h"
#include "c-pragma.h"
#include "ggc.h"
+#include "langhooks.h"
#include "tm_p.h"
#include "debug.h"
#include "target.h"
#define ASM_STABS_OP "\t.stabs\t"
#endif
-/* Define the prefix to use when check_memory_usage_flag is enable. */
-#define CHKR_PREFIX "_CHKR_"
-#define CHKR_PREFIX_SIZE (sizeof (CHKR_PREFIX) - 1)
-
/* The (assembler) name of the first globally-visible object output. */
const char *first_global_object_name;
const char *weak_global_object_name;
/* Current offset in constant pool (does not include any machine-specific
header). */
- int x_pool_offset;
+ HOST_WIDE_INT x_pool_offset;
/* Chain of all CONST_DOUBLE rtx's constructed for the current function.
- They are chained through the CONST_DOUBLE_CHAIN.
- A CONST_DOUBLE rtx has CONST_DOUBLE_MEM != cc0_rtx iff it is on this chain.
- In that case, CONST_DOUBLE_MEM is either a MEM,
- or const0_rtx if no MEM has been made for this CONST_DOUBLE yet. */
+ They are chained through the CONST_DOUBLE_CHAIN. */
rtx x_const_double_chain;
};
tree last_assemble_variable_decl;
+/* RTX_UNCHANGING_P in a MEM can mean it is stored into, for initialization.
+ So giving constant the alias set for the type will allow such
+ initializations to appear to conflict with the load of the constant. We
+ avoid this by giving all constants an alias set for just constants.
+ Since there will be no stores to that a alias set, nothing will ever
+ conflict with them. */
+
+static HOST_WIDE_INT const_alias_set;
+
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 output_after_function_constants PARAMS ((void));
static unsigned HOST_WIDE_INT array_size_for_constructor PARAMS ((tree));
static unsigned min_align PARAMS ((unsigned, unsigned));
-static void output_constructor PARAMS ((tree, int, unsigned));
+static void output_constructor PARAMS ((tree, HOST_WIDE_INT,
+ unsigned 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
((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
&& DECL_SECTION_NAME (DECL) != NULL_TREE)
#endif
-
+
/* Text of section name when in_section == in_named. */
static const char *in_named_name;
{
const char *name;
unsigned int flags;
+ bool declared;
};
static htab_t in_named_htab;
return slot ? (*slot)->flags : 0;
}
+/* Returns true if the section has been declared before. Sets internal
+ flag on this section in in_named_hash so subsequent calls on this
+ section will return false. */
+
+bool
+named_section_first_declaration (name)
+ const char *name;
+{
+ struct in_named_entry **slot;
+
+ slot = (struct in_named_entry**)
+ htab_find_slot_with_hash (in_named_htab, name,
+ htab_hash_string (name), NO_INSERT);
+ if (! (*slot)->declared)
+ {
+ (*slot)->declared = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
/* Record FLAGS for SECTION. If SECTION was previously recorded with a
different set of flags, return false. */
*slot = entry;
entry->name = ggc_strdup (section);
entry->flags = flags;
+ entry->declared = false;
}
else if (entry->flags != flags)
return false;
static void
asm_output_aligned_bss (file, decl, name, size, align)
FILE *file;
- tree decl;
+ tree decl ATTRIBUTE_UNUSED;
const char *name;
int size, align;
{
for them. */
#ifdef SELECT_SECTION
- SELECT_SECTION (decl, reloc);
+ SELECT_SECTION (decl, reloc, DECL_ALIGN (decl));
#else
if (DECL_READONLY_SECTION (decl, reloc))
readonly_data_section ();
table. */
void
-exception_section ()
+default_exception_section ()
{
-#if defined (EXCEPTION_SECTION)
- EXCEPTION_SECTION ();
-#else
if (targetm.have_named_sections)
named_section (NULL_TREE, ".gcc_except_table", 0);
else if (flag_pic)
data_section ();
else
readonly_data_section ();
+}
+
+/* Tell assembler to switch to the section for string merging. */
+
+void
+mergeable_string_section (decl, align, flags)
+ tree decl ATTRIBUTE_UNUSED;
+ unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+ unsigned int flags ATTRIBUTE_UNUSED;
+{
+#ifdef HAVE_GAS_SHF_MERGE
+ if (flag_merge_constants
+ && TREE_CODE (decl) == STRING_CST
+ && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+ && align <= 256
+ && TREE_STRING_LENGTH (decl) >= int_size_in_bytes (TREE_TYPE (decl)))
+ {
+ enum machine_mode mode;
+ unsigned int modesize;
+ const char *str;
+ int i, j, len, unit;
+ char name[30];
+
+ mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl)));
+ modesize = GET_MODE_BITSIZE (mode);
+ if (modesize >= 8 && modesize <= 256
+ && (modesize & (modesize - 1)) == 0)
+ {
+ if (align < modesize)
+ align = modesize;
+
+ str = TREE_STRING_POINTER (decl);
+ len = TREE_STRING_LENGTH (decl);
+ unit = GET_MODE_SIZE (mode);
+
+ /* Check for embedded NUL characters. */
+ for (i = 0; i < len; i += unit)
+ {
+ for (j = 0; j < unit; j++)
+ if (str [i + j] != '\0')
+ break;
+ if (j == unit)
+ break;
+ }
+ if (i == len - unit)
+ {
+ sprintf (name, ".rodata.str%d.%d", modesize / 8,
+ (int) (align / 8));
+ flags |= (modesize / 8) | SECTION_MERGE | SECTION_STRINGS;
+ if (!i && modesize < align)
+ {
+ /* A "" string with requested alignment greater than
+ character size might cause a problem:
+ if some other string required even bigger
+ alignment than "", then linker might think the
+ "" is just part of padding after some other string
+ and not put it into the hash table initially.
+ But this means "" could have smaller alignment
+ than requested. */
+#ifdef ASM_OUTPUT_SECTION_START
+ named_section_flags (name, flags);
+ ASM_OUTPUT_SECTION_START (asm_out_file);
+#else
+ readonly_data_section ();
+#endif
+ return;
+ }
+
+ named_section_flags (name, flags);
+ return;
+ }
+ }
+ }
+#endif
+ readonly_data_section ();
+}
+
+/* Tell assembler to switch to the section for constant merging. */
+
+void
+mergeable_constant_section (mode, align, flags)
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+ unsigned int flags ATTRIBUTE_UNUSED;
+{
+#ifdef HAVE_GAS_SHF_MERGE
+ unsigned int modesize = GET_MODE_BITSIZE (mode);
+
+ if (flag_merge_constants
+ && mode != VOIDmode
+ && mode != BLKmode
+ && modesize <= align
+ && align >= 8
+ && align <= 256
+ && (align & (align - 1)) == 0)
+ {
+ char name[24];
+
+ sprintf (name, ".rodata.cst%d", (int) (align / 8));
+ flags |= (align / 8) | SECTION_MERGE;
+ named_section_flags (name, flags);
+ return;
+ }
#endif
+ readonly_data_section ();
}
\f
/* Given NAME, a putative register name, discard any customary prefixes. */
/* Get rid of confusing prefixes. */
asmspec = strip_reg_name (asmspec);
-
+
/* Allow a decimal number as a "register name". */
for (i = strlen (asmspec) - 1; i >= 0; i--)
- if (! (asmspec[i] >= '0' && asmspec[i] <= '9'))
+ if (! ISDIGIT (asmspec[i]))
break;
if (asmspec[0] != 0 && i < 0)
{
#ifdef ADDITIONAL_REGISTER_NAMES
{
- static struct { const char *name; int number; } table[]
+ static const struct { const char *const name; const int number; } table[]
= ADDITIONAL_REGISTER_NAMES;
for (i = 0; i < (int) ARRAY_SIZE (table); i++)
&& !DECL_REGISTER (decl)))
abort ();
/* And that we were not given a type or a label. */
- else if (TREE_CODE (decl) == TYPE_DECL
+ else if (TREE_CODE (decl) == TYPE_DECL
|| TREE_CODE (decl) == LABEL_DECL)
abort ();
kludge to avoid setting DECL_RTL to frame_pointer_rtx. */
SET_DECL_RTL (decl,
- gen_rtx_REG (DECL_MODE (decl),
+ gen_rtx_REG (DECL_MODE (decl),
FIRST_PSEUDO_REGISTER));
REGNO (DECL_RTL (decl)) = reg_number;
REG_USERVAR_P (DECL_RTL (decl)) = 1;
&& name == IDENTIFIER_POINTER (DECL_NAME (decl)))
{
char *label;
+
ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
var_labelno++;
new_name = label;
}
- /* When -fprefix-function-name is used, the functions
- names are prefixed. Only nested function names are not
- prefixed. */
- else if (flag_prefix_function_name && TREE_CODE (decl) == FUNCTION_DECL)
- {
- 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)
{
SET_DECL_ASSEMBLER_NAME (decl, get_identifier (new_name));
}
/* If this variable is to be treated as volatile, show its
- tree node has side effects. */
+ tree node has side effects. */
if ((flag_volatile_global && TREE_CODE (decl) == VAR_DECL
&& TREE_PUBLIC (decl))
|| ((flag_volatile_static && TREE_CODE (decl) == VAR_DECL
#endif
if (align > BITS_PER_UNIT)
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ {
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ }
}
/* Output a string of literal assembler code
const char *section = ".dtors";
char buf[16];
- /* ??? This only works reliably with the GNU linker. */
+ /* ??? This only works reliably with the GNU linker. */
if (priority != DEFAULT_INIT_PRIORITY)
{
sprintf (buf, ".dtors.%.5u",
const char *section = ".ctors";
char buf[16];
- /* ??? This only works reliably with the GNU linker. */
+ /* ??? This only works reliably with the GNU linker. */
if (priority != DEFAULT_INIT_PRIORITY)
{
sprintf (buf, ".ctors.%.5u",
/* Tell assembler to move to target machine's alignment for functions. */
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0)
- ASM_OUTPUT_ALIGN (asm_out_file, align);
+ {
+ ASM_OUTPUT_ALIGN (asm_out_file, align);
+ }
/* Handle a user-specified function alignment.
Note that we still need to align to FUNCTION_BOUNDARY, as above,
if (align_functions_log > align)
{
#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
- ASM_OUTPUT_MAX_SKIP_ALIGN (asm_out_file,
+ ASM_OUTPUT_MAX_SKIP_ALIGN (asm_out_file,
align_functions_log, align_functions-1);
#else
ASM_OUTPUT_ALIGN (asm_out_file, align_functions_log);
int align;
{
if (align > BITS_PER_UNIT)
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ {
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ }
}
/* Assemble a string constant with the specified C string as contents. */
asm_dest_local
}
destination = asm_dest_local;
-
+
if (TREE_PUBLIC (decl))
{
#if defined ASM_EMIT_BSS
if (! DECL_COMMON (decl))
destination = asm_dest_bss;
else
-#endif
+#endif
destination = asm_dest_common;
}
int at_end ATTRIBUTE_UNUSED;
int dont_output_data;
{
- register const char *name;
+ const char *name;
unsigned int align;
int reloc = 0;
rtx decl_rtl;
/* 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. */
if (align > MAX_OFILE_ALIGNMENT)
{
warning_with_decl (decl,
- "alignment of `%s' is greater than maximum object file alignment. Using %d.",
+ "alignment of `%s' is greater than maximum object file alignment. Using %d",
MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
align = MAX_OFILE_ALIGNMENT;
}
/* Reset the alignment in case we have made it tighter, so we can benefit
from it in get_pointer_alignment. */
DECL_ALIGN (decl) = align;
+ set_mem_align (decl_rtl, align);
/* Handle uninitialized definitions. */
rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
* (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
-
+
/* Don't continue this line--convex cc version 4.1 would lose. */
#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
if ((unsigned HOST_WIDE_INT) DECL_ALIGN (decl) / BITS_PER_UNIT > rounded)
- warning_with_decl
- (decl, "requested alignment for %s is greater than implemented alignment of %d.",rounded);
+ warning_with_decl
+ (decl, "requested alignment for %s is greater than implemented alignment of %d",rounded);
#endif
-
+
asm_emit_uninitialised (decl, name, size, rounded);
return;
if (TREE_PUBLIC (decl) && DECL_NAME (decl))
{
#ifdef ASM_WEAKEN_LABEL
- if (DECL_WEAK (decl))
+ if (DECL_WEAK (decl))
{
ASM_WEAKEN_LABEL (asm_out_file, name);
/* Remove this variable from the pending weak list so that
/* Output any data that we will need to use the address of. */
if (DECL_INITIAL (decl) == error_mark_node)
- reloc = contains_pointers_p (TREE_TYPE (decl));
+ reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
else if (DECL_INITIAL (decl))
reloc = output_addressed_constants (DECL_INITIAL (decl));
/* Output the alignment of this data. */
if (align > BITS_PER_UNIT)
- ASM_OUTPUT_ALIGN (asm_out_file,
- floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT));
+ {
+ ASM_OUTPUT_ALIGN (asm_out_file,
+ floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT));
+ }
/* Do any machine/system dependent processing of the object. */
#ifdef ASM_DECLARE_OBJECT_NAME
void
assemble_global (name)
- const char *name;
+ const char *name ATTRIBUTE_UNUSED;
{
ASM_GLOBALIZE_LABEL (asm_out_file, name);
}
tree id;
STRIP_NAME_ENCODING (real_name, name);
- if (flag_prefix_function_name
- && ! memcmp (real_name, CHKR_PREFIX, CHKR_PREFIX_SIZE))
- real_name = real_name + CHKR_PREFIX_SIZE;
id = maybe_get_identifier (real_name);
if (id)
/* Write the assembler code to define one. */
align = floor_log2 (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
if (align > 0)
- ASM_OUTPUT_ALIGN (asm_out_file, align);
+ {
+ ASM_OUTPUT_ALIGN (asm_out_file, align);
+ }
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LTRAMP", 0);
TRAMPOLINE_TEMPLATE (asm_out_file);
/* First try to use the standard 1, 2, 4, 8, and 16 byte
ASM_OUTPUT... macros. */
- if (align >= size * BITS_PER_UNIT)
+ if (align >= MIN (size * BITS_PER_UNIT, BIGGEST_ALIGNMENT))
switch (size)
{
#ifdef ASM_OUTPUT_CHAR
{
enum machine_mode omode, imode;
unsigned int i;
-
+
omode = mode_for_size (BITS_PER_UNIT, MODE_INT, 0);
imode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
HOST_WIDE_INT i0, i1;
enum machine_mode mode;
{
- register rtx r;
+ rtx r;
if (GET_MODE_CLASS (mode) == MODE_INT
|| GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
return r;
/* No; make a new one and add it to the chain. */
- r = gen_rtx_CONST_DOUBLE (mode, const0_rtx, i0, i1);
+ r = gen_rtx_CONST_DOUBLE (mode, i0, i1);
/* Don't touch const_double_chain if not inside any function. */
if (current_function_decl != 0)
enum machine_mode mode;
{
union real_extract u;
- register rtx r;
+ rtx r;
/* Get the desired `double' value as a sequence of ints
since that is how they are stored in a CONST_DOUBLE. */
u.d = d;
- /* Detect special cases. */
- if (REAL_VALUES_IDENTICAL (dconst0, d))
+ /* Detect special cases. 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. */
+ if (! REAL_VALUE_ISNAN (d) && 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))
return CONST1_RTX (mode);
+ else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst2, d))
+ return CONST2_RTX (mode);
if (sizeof u == sizeof (HOST_WIDE_INT))
return immed_double_const (u.i[0], 0, mode);
else
CONST_DOUBLE_CHAIN (r) = NULL_RTX;
- /* Store const0_rtx in CONST_DOUBLE_MEM since this CONST_DOUBLE is on the
- chain, but has not been allocated memory. Actual use of CONST_DOUBLE_MEM
- is only through force_const_mem. */
-
- CONST_DOUBLE_MEM (r) = const0_rtx;
-
return r;
}
void
clear_const_double_mem ()
{
- register rtx r, next;
- enum machine_mode mode;
- int i;
+ rtx r, next;
for (r = const_double_chain; r; r = next)
{
next = CONST_DOUBLE_CHAIN (r);
CONST_DOUBLE_CHAIN (r) = 0;
- 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,
tree exp;
struct addr_const *value;
{
- register tree target = TREE_OPERAND (exp, 0);
- register int offset = 0;
- register rtx x;
+ tree target = TREE_OPERAND (exp, 0);
+ int offset = 0;
+ rtx x;
while (1)
{
const char *label;
rtx rtl;
/* Make sure the data is reasonably aligned. */
- union
+ union
{
unsigned char contents[1];
#ifdef HAVE_LONG_DOUBLE
#define MAX_HASH_TABLE 1009
static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];
+/* We maintain a hash table of STRING_CST values. Unless we are asked to force
+ out a string constant, we defer output of the constants until we know
+ they are actually used. This will be if something takes its address or if
+ there is a usage of the string in the RTL of a function. */
+
#define STRHASH(x) ((hashval_t)((long)(x) >> 3))
struct deferred_string
/* Mark a const_hash_table descriptor for GC. */
-static void
+static void
mark_const_hash_entry (ptr)
void *ptr;
{
/* 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;
/* Mark a const_str_htab for GC. */
-static void
+static void
mark_const_str_htab (htab)
void *htab;
{
const_hash (exp)
tree exp;
{
- register const char *p;
- register int len, hi, i;
- register enum tree_code code = TREE_CODE (exp);
+ const char *p;
+ int len, hi, i;
+ enum tree_code code = TREE_CODE (exp);
/* Either set P and LEN to the address and len of something to hash and
exit the switch or return a value. */
}
else
{
- register tree link;
+ tree link;
/* For record type, include the type in the hashing.
We do not do so for array types
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
-
+
default:
/* A language specific constant. Just hash the code. */
return (int) code % MAX_HASH_TABLE;
tree exp;
const unsigned char *p;
{
- register const unsigned char *strp;
- register int len;
- register enum tree_code code = TREE_CODE (exp);
+ const unsigned char *strp;
+ int len;
+ enum tree_code code = TREE_CODE (exp);
if (code != (enum tree_code) *p++)
return 0;
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)))
+ sizeof TREE_STRING_LENGTH (exp)))
return 0;
p += sizeof TREE_STRING_LENGTH (exp);
}
else
{
- register tree link;
+ tree link;
int length = list_length (CONSTRUCTOR_ELTS (exp));
tree type;
enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
p += sizeof length;
/* For record constructors, insist that the types match.
- For arrays, just verify both constructors are for arrays.
+ For arrays, just verify both constructors are for arrays.
Then insist that either both or none have any TREE_PURPOSE
values. */
if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
return compare_constant_1 (TREE_OPERAND (exp, 0), p);
default:
- if (lang_expand_constant)
- {
- exp = (*lang_expand_constant) (exp);
- return compare_constant_1 (exp, p);
- }
- return 0;
+ {
+ tree new = (*lang_hooks.expand_constant) (exp);
+
+ if (new != exp)
+ return compare_constant_1 (new, p);
+ else
+ return 0;
+ }
}
/* Compare constant contents. */
record_constant_1 (exp)
tree exp;
{
- register const unsigned char *strp;
- register int len;
- register enum tree_code code = TREE_CODE (exp);
+ const unsigned char *strp;
+ int len;
+ enum tree_code code = TREE_CODE (exp);
obstack_1grow (&permanent_obstack, (unsigned int) code);
}
else
{
- register tree link;
+ tree link;
int length = list_length (CONSTRUCTOR_ELTS (exp));
enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
tree type;
obstack_grow (&permanent_obstack, (char *) &type, sizeof type);
if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
obstack_grow (&permanent_obstack, &mode, sizeof mode);
-
+
obstack_grow (&permanent_obstack, (char *) &have_purpose,
sizeof have_purpose);
return;
default:
- if (lang_expand_constant)
- {
- exp = (*lang_expand_constant) (exp);
+ {
+ tree new = (*lang_hooks.expand_constant) (exp);
+
+ if (new != exp)
record_constant_1 (exp);
- }
- return;
+ return;
+ }
}
/* Record constant contents. */
tree exp;
int defer;
{
- register int hash;
- register struct constant_descriptor *desc;
+ int hash;
+ struct constant_descriptor *desc;
struct deferred_string **defstr;
char label[256];
int reloc;
int found = 1;
int after_function = 0;
int labelno = -1;
+ rtx rtl;
- if (TREE_CST_RTL (exp))
+ /* We can't just use the saved RTL if this is a defererred string constant
+ and we are not to defer anymode. */
+ if (TREE_CODE (exp) != INTEGER_CST && TREE_CST_RTL (exp)
+ && (defer || !STRING_POOL_ADDRESS_P (XEXP (TREE_CST_RTL (exp), 0))))
return TREE_CST_RTL (exp);
/* Make sure any other constants whose addresses appear in EXP
the label number already assigned. */
hash = const_hash (exp) % MAX_HASH_TABLE;
-
+
for (desc = const_hash_table[hash]; desc; desc = desc->next)
if (compare_constant (exp, desc))
break;
-
+
if (desc == 0)
{
/* No constant equal to EXP is known to have been output.
Make a constant descriptor to enter EXP in the hash table.
Assign the label number and record it in the descriptor for
future calls to this function to find. */
-
+
/* Create a string containing the label name, in LABEL. */
labelno = const_labelno++;
ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
desc->next = const_hash_table[hash];
desc->label = ggc_strdup (label);
const_hash_table[hash] = desc;
-
+
/* We have a symbol name; construct the SYMBOL_REF and the MEM. */
- desc->rtl
+ rtl = desc->rtl
= gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
gen_rtx_SYMBOL_REF (Pmode, desc->label));
- set_mem_attributes (desc->rtl, exp, 1);
+ set_mem_attributes (rtl, exp, 1);
+ set_mem_alias_set (rtl, 0);
+ set_mem_alias_set (rtl, const_alias_set);
found = 0;
}
+ else
+ rtl = desc->rtl;
- TREE_CST_RTL (exp) = desc->rtl;
+ if (TREE_CODE (exp) != INTEGER_CST)
+ TREE_CST_RTL (exp) = rtl;
/* Optionally set flags or add text to the name to record information
such as that it is a function name. If the name is changed, the macro
if (! found)
{
ENCODE_SECTION_INFO (exp);
- desc->rtl = TREE_CST_RTL (exp);
+ desc->rtl = rtl;
desc->label = XSTR (XEXP (desc->rtl, 0), 0);
}
#endif
#endif
if (found
- && STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0))
+ && STRING_POOL_ADDRESS_P (XEXP (rtl, 0))
&& (!defer || defer_addressed_constants_flag || after_function))
{
defstr = (struct deferred_string **)
remove it from deferred string hash table. */
found = 0;
labelno = (*defstr)->labelno;
- STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)) = 0;
+ STRING_POOL_ADDRESS_P (XEXP (rtl, 0)) = 0;
htab_clear_slot (const_str_htab, (void **) defstr);
}
}
{
if (defer_addressed_constants_flag || after_function)
{
- struct deferred_constant *p;
- p = (struct deferred_constant *) xmalloc (sizeof (struct deferred_constant));
+ struct deferred_constant *p
+ = (struct deferred_constant *)
+ xmalloc (sizeof (struct deferred_constant));
p->exp = copy_constant (exp);
p->reloc = reloc;
p->label = desc->label;
p->labelno = labelno;
*defstr = p;
- STRING_POOL_ADDRESS_P (XEXP (desc->rtl, 0)) = 1;
+ STRING_POOL_ADDRESS_P (XEXP (rtl, 0)) = 1;
}
}
}
}
- return TREE_CST_RTL (exp);
+ return rtl;
}
/* Now output assembler code to define the label for EXP,
{
int align;
+ /* Align the location counter as required by EXP's data type. */
+ align = TYPE_ALIGN (TREE_TYPE (exp));
+#ifdef CONSTANT_ALIGNMENT
+ align = CONSTANT_ALIGNMENT (exp, align);
+#endif
+
if (IN_NAMED_SECTION (exp))
named_section (exp, NULL, reloc);
else
{
/* First switch to text section, except for writable strings. */
#ifdef SELECT_SECTION
- SELECT_SECTION (exp, reloc);
+ SELECT_SECTION (exp, reloc, align);
#else
if (((TREE_CODE (exp) == STRING_CST) && flag_writable_strings)
|| (flag_pic && reloc))
#endif
}
- /* Align the location counter as required by EXP's data type. */
- align = TYPE_ALIGN (TREE_TYPE (exp));
-#ifdef CONSTANT_ALIGNMENT
- align = CONSTANT_ALIGNMENT (exp, align);
-#endif
-
if (align > BITS_PER_UNIT)
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ {
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ }
/* Output the label itself. */
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
{
struct constant_descriptor *desc;
struct pool_constant *next, *next_sym;
- const char *label;
rtx constant;
enum machine_mode mode;
int labelno;
- int align;
- int offset;
+ unsigned int align;
+ HOST_WIDE_INT offset;
int mark;
};
/* Mark PC for GC. */
-static void
+static void
mark_pool_constant (pc)
struct pool_constant *pc;
{
{
ggc_mark (pc);
ggc_mark_rtx (pc->constant);
+ ggc_mark_rtx (pc->desc->rtl);
pc = pc->next;
}
}
/* Clear out the hash tables. */
for (i = 0; i < MAX_RTX_HASH_TABLE; ++i)
{
- struct constant_descriptor* cd;
+ struct constant_descriptor *cd;
cd = p->x_const_rtx_hash_table[i];
- while (cd) {
- struct constant_descriptor* next = cd->next;
- free (cd);
- cd = next;
- }
+ 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
case LABEL_REF:
/* For a LABEL_REF, compare labels. */
value->un.addr.base = XEXP (value->un.addr.base, 0);
-
+
default:
break;
}
enum machine_mode mode;
rtx x;
{
- register int hi;
- register size_t i;
+ int hi;
+ size_t i;
struct rtx_const value;
decode_rtx_const (mode, x, &value);
rtx x;
struct constant_descriptor *desc;
{
- register int *p = (int *) desc->u.contents;
- register int *strp;
- register int len;
+ int *p = (int *) desc->u.contents;
+ int *strp;
+ int len;
struct rtx_const value;
decode_rtx_const (mode, x, &value);
{
struct constant_descriptor *ptr;
- ptr = ((struct constant_descriptor *)
+ 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 ptr;
}
\f
+/* Given a constant rtx X, return a MEM for the location in memory at which
+ this constant has been placed. Return 0 if it not has been placed yet. */
+
+rtx
+mem_for_const_double (x)
+ rtx x;
+{
+ enum machine_mode mode = GET_MODE (x);
+ struct constant_descriptor *desc;
+
+ for (desc = const_rtx_hash_table[const_hash_rtx (mode, x)]; desc;
+ desc = desc->next)
+ if (compare_constant_rtx (mode, x, desc))
+ return desc->rtl;
+
+ return 0;
+}
+
/* Given a constant rtx X, make (or find) a memory constant for its value
and return a MEM rtx to refer to it in memory. */
enum machine_mode mode;
rtx x;
{
- register int hash;
- register struct constant_descriptor *desc;
+ int hash;
+ struct constant_descriptor *desc;
char label[256];
- const char *found = 0;
rtx def;
-
- /* If we want this CONST_DOUBLE in the same mode as it is in memory
- (this will always be true for floating CONST_DOUBLEs that have been
- placed in memory, but not for VOIDmode (integer) CONST_DOUBLEs),
- use the previous copy. Otherwise, make a new one. Note that in
- the unlikely event that this same CONST_DOUBLE is used in two different
- modes in an alternating fashion, we will allocate a lot of different
- memory locations, but this should be extremely rare. */
-
- if (GET_CODE (x) == CONST_DOUBLE
- && GET_CODE (CONST_DOUBLE_MEM (x)) == MEM
- && GET_MODE (CONST_DOUBLE_MEM (x)) == mode)
- return CONST_DOUBLE_MEM (x);
+ struct pool_constant *pool;
+ unsigned int align;
/* Compute hash code of X. Search the descriptors for that hash code
- to see if any of them describes X. If yes, the descriptor records
- the label number already assigned. */
-
+ to see if any of them describes X. If yes, we have an rtx to use. */
hash = const_hash_rtx (mode, x);
-
for (desc = const_rtx_hash_table[hash]; desc; desc = desc->next)
if (compare_constant_rtx (mode, x, desc))
- {
- found = desc->label;
- break;
- }
-
- if (found == 0)
- {
- register struct pool_constant *pool;
- int align;
-
- /* No constant equal to X is known to have been output.
- Make a constant descriptor to enter X in the hash table.
- Assign the label number and record it in the descriptor for
- future calls to this function to find. */
-
- desc = record_constant_rtx (mode, x);
- desc->next = const_rtx_hash_table[hash];
- const_rtx_hash_table[hash] = desc;
-
- /* Align the location counter as required by EXP's data type. */
- align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
+ return desc->rtl;
+
+ /* No constant equal to X is known to have been output.
+ Make a constant descriptor to enter X in the hash table
+ and make a MEM for it. */
+ desc = record_constant_rtx (mode, x);
+ desc->next = const_rtx_hash_table[hash];
+ const_rtx_hash_table[hash] = desc;
+
+ /* Align the location counter as required by EXP's data type. */
+ align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
#ifdef CONSTANT_ALIGNMENT
- align = CONSTANT_ALIGNMENT (make_tree (type_for_mode (mode, 0), x),
- align);
+ align = CONSTANT_ALIGNMENT (make_tree (type_for_mode (mode, 0), x), align);
#endif
- 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. */
-
- pool = (struct pool_constant *) ggc_alloc (sizeof (struct pool_constant));
- pool->desc = desc;
- pool->constant = x;
- pool->mode = mode;
- pool->labelno = const_labelno;
- pool->align = align;
- pool->offset = pool_offset;
- pool->mark = 1;
- pool->next = 0;
-
- if (last_pool == 0)
- first_pool = pool;
- else
- last_pool->next = pool;
-
- last_pool = pool;
- pool_offset += GET_MODE_SIZE (mode);
-
- /* Create a string containing the label name, in LABEL. */
- ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
-
- ++const_labelno;
+ 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. */
+ pool = (struct pool_constant *) ggc_alloc (sizeof (struct pool_constant));
+ pool->desc = desc;
+ pool->constant = x;
+ pool->mode = mode;
+ pool->labelno = const_labelno;
+ pool->align = align;
+ pool->offset = pool_offset;
+ pool->mark = 1;
+ pool->next = 0;
+
+ if (last_pool == 0)
+ first_pool = pool;
+ else
+ last_pool->next = pool;
+
+ last_pool = pool;
+ pool_offset += GET_MODE_SIZE (mode);
- desc->label = found = ggc_strdup (label);
+ /* Create a string containing the label name, in LABEL. */
+ ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
- /* Add label to symbol hash table. */
- hash = SYMHASH (found);
- pool->label = found;
- pool->next_sym = const_rtx_sym_hash_table[hash];
- const_rtx_sym_hash_table[hash] = pool;
- }
+ ++const_labelno;
- /* We have a symbol name; construct the SYMBOL_REF and the MEM. */
+ /* Construct the SYMBOL_REF and the MEM. */
- def = gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (Pmode, found));
+ pool->desc->rtl = def
+ = gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label)));
+ set_mem_alias_set (def, const_alias_set);
set_mem_attributes (def, type_for_mode (mode, 0), 1);
RTX_UNCHANGING_P (def) = 1;
+ /* Add label to symbol hash table. */
+ hash = SYMHASH (XSTR (XEXP (def, 0), 0));
+ pool->next_sym = const_rtx_sym_hash_table[hash];
+ const_rtx_sym_hash_table[hash] = pool;
+
/* Mark the symbol_ref as belonging to this constants pool. */
CONSTANT_POOL_ADDRESS_P (XEXP (def, 0)) = 1;
current_function_uses_const_pool = 1;
- if (GET_CODE (x) == CONST_DOUBLE)
- {
- if (CONST_DOUBLE_MEM (x) == cc0_rtx)
- {
- CONST_DOUBLE_CHAIN (x) = const_double_chain;
- const_double_chain = x;
- }
- CONST_DOUBLE_MEM (x) = def;
- }
-
return def;
}
\f
for (pool = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; pool;
pool = pool->next_sym)
- if (pool->label == label)
+ if (XSTR (XEXP (pool->desc->rtl, 0), 0) == label)
return pool;
abort ();
x = const0_rtx;
}
break;
-
+
default:
break;
}
/* First switch to correct section. */
#ifdef SELECT_RTX_SECTION
- SELECT_RTX_SECTION (pool->mode, x);
+ SELECT_RTX_SECTION (pool->mode, x, pool->align);
#else
readonly_data_section ();
#endif
static void
mark_constant_pool ()
{
- register rtx insn;
+ rtx insn;
struct pool_constant *pool;
if (first_pool == 0 && htab_elements (const_str_htab) == 0)
mark_constants (x)
rtx x;
{
- register int i;
- register const char *format_ptr;
+ int i;
+ const char *format_ptr;
if (x == 0)
return;
mark_constant (&x, NULL);
return;
}
- /* Never search inside a CONST_DOUBLE, because CONST_DOUBLE_MEM may be
- a MEM, but does not constitute a use of that MEM. */
- else if (GET_CODE (x) == CONST_DOUBLE)
- return;
/* Insns may appear inside a SEQUENCE. Only check the patterns of
insns, not any notes that may be attached. We don't want to mark
case 'E':
if (XVEC (x, i) != 0)
{
- register int j;
+ int j;
for (j = 0; j < XVECLEN (x, i); j++)
mark_constants (XVECEXP (x, i, j));
/* 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. */
+ be used with for_each_rtx to mark all SYMBOL_REFs in an rtx. */
static int
mark_constant (current_rtx, data)
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))
tree exp;
{
int reloc = 0;
+ tree tem;
/* 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);
+ exp = (*lang_hooks.expand_constant) (exp);
switch (TREE_CODE (exp))
{
case ADDR_EXPR:
- {
- register tree constant = TREE_OPERAND (exp, 0);
-
- while (TREE_CODE (constant) == COMPONENT_REF)
- {
- constant = TREE_OPERAND (constant, 0);
- }
-
- if (TREE_CODE_CLASS (TREE_CODE (constant)) == 'c'
- || TREE_CODE (constant) == CONSTRUCTOR)
- /* No need to do anything here
- for addresses of variables or functions. */
- output_constant_def (constant, 0);
- }
- reloc = 1;
+ /* Go inside any operations that get_inner_reference can handle and see
+ if what's inside is a constant: no need to do anything here for
+ addresses of variables or functions. */
+ for (tem = TREE_OPERAND (exp, 0); handled_component_p (tem);
+ tem = TREE_OPERAND (tem, 0))
+ ;
+
+ if (TREE_CODE_CLASS (TREE_CODE (tem)) == 'c'
+ || TREE_CODE (tem) == CONSTRUCTOR)
+ output_constant_def (tem, 0);
+
+ if (TREE_PUBLIC (tem))
+ reloc |= 2;
+ else
+ reloc |= 1;
break;
case PLUS_EXPR:
break;
case CONSTRUCTOR:
- {
- register tree link;
- for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
- if (TREE_VALUE (link) != 0)
- reloc |= output_addressed_constants (TREE_VALUE (link));
- }
+ for (tem = CONSTRUCTOR_ELTS (exp); tem; tem = TREE_CHAIN (tem))
+ if (TREE_VALUE (tem) != 0)
+ reloc |= output_addressed_constants (TREE_VALUE (tem));
+
break;
default:
{
/* Give the front-end a chance to convert VALUE to something that
looks more like a constant to the back-end. */
- if (lang_expand_constant)
- value = (*lang_expand_constant) (value);
+ value = (*lang_hooks.expand_constant) (value);
switch (TREE_CODE (value))
{
return
initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
endtype);
-
+
return TREE_STATIC (value) ? null_pointer_node : 0;
case INTEGER_CST:
return null_pointer_node;
case ADDR_EXPR:
+ case FDESC_EXPR:
return staticp (TREE_OPERAND (value, 0)) ? TREE_OPERAND (value, 0) : 0;
+ case VIEW_CONVERT_EXPR:
case NON_LVALUE_EXPR:
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
void
output_constant (exp, size, align)
tree exp;
- int size;
+ HOST_WIDE_INT size;
unsigned int align;
{
- register enum tree_code code = TREE_CODE (TREE_TYPE (exp));
+ enum tree_code code;
+ HOST_WIDE_INT thissize;
- /* Some front-ends use constants other than the standard
- language-indepdent varieties, but which may still be output
- directly. Give the front-end a chance to convert EXP to a
- language-independent representation. */
- if (lang_expand_constant)
- {
- exp = (*lang_expand_constant) (exp);
- code = TREE_CODE (TREE_TYPE (exp));
- }
+ /* Some front-ends use constants other than the standard language-indepdent
+ varieties, but which may still be output directly. Give the front-end a
+ chance to convert EXP to a language-independent representation. */
+ exp = (*lang_hooks.expand_constant) (exp);
if (size == 0 || flag_syntax_only)
return;
- /* Eliminate the NON_LVALUE_EXPR_EXPR that makes a cast not be an lvalue.
- That way we get the constant (we hope) inside it. Also, strip off any
- NOP_EXPR that converts between two record, union, array, or set types
- or a CONVERT_EXPR that converts to a union TYPE. */
- while ((TREE_CODE (exp) == NOP_EXPR
- && (TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))
- || AGGREGATE_TYPE_P (TREE_TYPE (exp))))
- || (TREE_CODE (exp) == CONVERT_EXPR
- && code == UNION_TYPE)
- || TREE_CODE (exp) == NON_LVALUE_EXPR)
- {
- exp = TREE_OPERAND (exp, 0);
- code = TREE_CODE (TREE_TYPE (exp));
- }
+ /* Eliminate any conversions since we'll be outputting the underlying
+ constant. */
+ while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
+ || TREE_CODE (exp) == NON_LVALUE_EXPR
+ || TREE_CODE (exp) == VIEW_CONVERT_EXPR)
+ exp = TREE_OPERAND (exp, 0);
+
+ code = TREE_CODE (TREE_TYPE (exp));
+ thissize = int_size_in_bytes (TREE_TYPE (exp));
/* Allow a constructor with no elements for any data type.
This means to fill the space with zeros. */
return;
}
+ if (TREE_CODE (exp) == FDESC_EXPR)
+ {
+#ifdef ASM_OUTPUT_FDESC
+ HOST_WIDE_INT part = tree_low_cst (TREE_OPERAND (exp, 1), 0);
+ tree decl = TREE_OPERAND (exp, 0);
+ ASM_OUTPUT_FDESC (asm_out_file, decl, part);
+#else
+ abort ();
+#endif
+ return;
+ }
+
+ /* Now output the underlying data. If we've handling the padding, return.
+ Otherwise, break and ensure THISSIZE is the size written. */
switch (code)
{
case CHAR_TYPE:
case ENUMERAL_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
- /* ??? What about (int)((float)(int)&foo + 4) */
- while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
- || TREE_CODE (exp) == NON_LVALUE_EXPR)
- exp = TREE_OPERAND (exp, 0);
-
if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
EXPAND_INITIALIZER),
size, align, 0))
error ("initializer for integer value is too complicated");
- size = 0;
break;
case REAL_TYPE:
assemble_real (TREE_REAL_CST (exp),
mode_for_size (size * BITS_PER_UNIT, MODE_FLOAT, 0),
align);
- size = 0;
break;
case COMPLEX_TYPE:
- output_constant (TREE_REALPART (exp), size / 2, align);
- output_constant (TREE_IMAGPART (exp), size / 2,
- min_align (align, BITS_PER_UNIT * (size / 2)));
- size -= (size / 2) * 2;
+ output_constant (TREE_REALPART (exp), thissize / 2, align);
+ output_constant (TREE_IMAGPART (exp), thissize / 2,
+ min_align (align, BITS_PER_UNIT * (thissize / 2)));
break;
case ARRAY_TYPE:
}
else if (TREE_CODE (exp) == STRING_CST)
{
- int excess = 0;
-
- if (size > TREE_STRING_LENGTH (exp))
- {
- excess = size - TREE_STRING_LENGTH (exp);
- size = TREE_STRING_LENGTH (exp);
- }
-
- assemble_string (TREE_STRING_POINTER (exp), size);
- size = excess;
+ thissize = MIN (TREE_STRING_LENGTH (exp), size);
+ assemble_string (TREE_STRING_POINTER (exp), thissize);
}
else
abort ();
if (TREE_CODE (exp) == INTEGER_CST)
assemble_integer (expand_expr (exp, NULL_RTX,
VOIDmode, EXPAND_INITIALIZER),
- size, align, 1);
+ thissize, align, 1);
else if (TREE_CODE (exp) == CONSTRUCTOR)
{
- unsigned char *buffer = (unsigned char *) alloca (size);
- if (get_set_constructor_bytes (exp, buffer, size))
+ unsigned char *buffer = (unsigned char *) alloca (thissize);
+ if (get_set_constructor_bytes (exp, buffer, thissize))
abort ();
- assemble_string ((char *) buffer, size);
+ assemble_string ((char *) buffer, thissize);
}
else
error ("unknown set constructor type");
return;
+ case ERROR_MARK:
+ return;
+
default:
- break; /* ??? */
+ abort ();
}
+ size -= thissize;
if (size > 0)
assemble_zeros (size);
}
{
tree max_index, i;
+ /* This code used to attempt to handle string constants that are not
+ arrays of single-bytes, but nothing else does, so there's no point in
+ doing it here. */
+ if (TREE_CODE (val) == STRING_CST)
+ return TREE_STRING_LENGTH (val);
+
max_index = NULL_TREE;
for (i = CONSTRUCTOR_ELTS (val); i ; i = TREE_CHAIN (i))
{
return 0;
/* Compute the total number of array elements. */
- i = size_binop (MINUS_EXPR, convert (sizetype, max_index),
+ 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));
static void
output_constructor (exp, size, align)
tree exp;
- int size;
+ HOST_WIDE_INT size;
unsigned int align;
{
tree type = TREE_TYPE (exp);
- register tree link, field = 0;
+ tree link, field = 0;
tree min_index = 0;
/* Number of bytes output or skipped so far.
In other words, current position within the constructor. */
HOST_WIDE_INT total_bytes = 0;
/* Non-zero means BYTE contains part of a byte, to be output. */
int byte_buffer_in_use = 0;
- register int byte = 0;
+ int byte = 0;
if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
abort ();
/* Output any buffered-up bit-fields preceding this element. */
if (byte_buffer_in_use)
{
- ASM_OUTPUT_BYTE (asm_out_file, byte);
+ assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
total_bytes++;
byte_buffer_in_use = 0;
}
/* Find the alignment of this element. */
align2 = min_align (align, BITS_PER_UNIT * pos);
-
+
/* Determine size this element should occupy. */
if (field)
{
/* Output remnant of any bit field in previous bytes. */
if (byte_buffer_in_use)
{
- ASM_OUTPUT_BYTE (asm_out_file, byte);
+ assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
total_bytes++;
byte_buffer_in_use = 0;
}
within this element when necessary. */
while (next_byte != total_bytes)
{
- ASM_OUTPUT_BYTE (asm_out_file, byte);
+ assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
total_bytes++;
byte = 0;
}
if (byte_buffer_in_use)
{
- ASM_OUTPUT_BYTE (asm_out_file, byte);
+ assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
total_bytes++;
}
assemble_zeros (size - total_bytes);
}
-/* This structure contains any weak symbol declarations waiting to be
- emitted. */
+/* This structure contains any weak symbol declarations waiting
+ to be emitted. */
struct weak_syms
{
struct weak_syms * next;
static struct weak_syms * weak_decls;
/* Add function NAME to the weak symbols list. VALUE is a weak alias
- associatd with NAME. */
-
+ associated with NAME. */
+
int
add_weak (name, value)
const char *name;
/* Remove NAME from the pending list of weak symbols. This prevents
the compiler from emitting multiple .weak directives which confuses
some assemblers. */
-
+#ifdef ASM_WEAKEN_LABEL
static void
remove_from_pending_weak_list (name)
const char *name;
{
t = *p;
if (strcmp (name, t->name) == 0)
- {
- *p = t->next;
- free (t);
- }
+ {
+ *p = t->next;
+ free (t);
+ }
else
- p = &(t->next);
+ p = &(t->next);
}
}
+#endif /* ASM_WEAKEN_LABEL */
/* Emit an assembler directive to make the symbol for DECL an alias to
the symbol for TARGET. */
mark_const_hash_entry);
ggc_add_root (&const_str_htab, 1, sizeof const_str_htab,
mark_const_str_htab);
+
+ const_alias_set = new_alias_set ();
}
/* Select a set of attributes for section NAME based on the properties
const char *name;
unsigned int flags;
{
- char flagchars[8], *f = flagchars;
+ char flagchars[10], *f = flagchars;
const char *type;
+ if (! named_section_first_declaration (name))
+ {
+ fprintf (asm_out_file, "\t.section\t%s\n", name);
+ return;
+ }
+
if (!(flags & SECTION_DEBUG))
*f++ = 'a';
if (flags & SECTION_WRITE)
*f++ = 'x';
if (flags & SECTION_SMALL)
*f++ = 's';
+ if (flags & SECTION_MERGE)
+ *f++ = 'M';
+ if (flags & SECTION_STRINGS)
+ *f++ = 'S';
*f = '\0';
if (flags & SECTION_BSS)
else
type = "progbits";
- fprintf (asm_out_file, "\t.section\t%s,\"%s\",@%s\n",
- name, flagchars, type);
+ if (flags & SECTION_ENTSIZE)
+ fprintf (asm_out_file, "\t.section\t%s,\"%s\",@%s,%d\n",
+ name, flagchars, type, flags & SECTION_ENTSIZE);
+ else
+ fprintf (asm_out_file, "\t.section\t%s,\"%s\",@%s\n",
+ name, flagchars, type);
}
void
(flags & SECTION_CODE ? "discard" : "same_size"));
}
}
+\f
+/* Used for vtable gc in GNU binutils. Record that the pointer at OFFSET
+ from SYMBOL is used in all classes derived from SYMBOL. */
+
+void
+assemble_vtable_entry (symbol, offset)
+ rtx symbol;
+ HOST_WIDE_INT offset;
+{
+ fputs ("\t.vtable_entry ", asm_out_file);
+ output_addr_const (asm_out_file, symbol);
+ fputs (", ", asm_out_file);
+ fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, offset);
+ fputc ('\n', asm_out_file);
+}
+
+/* Used for vtable gc in GNU binutils. Record the class hierarchy by noting
+ that the vtable symbol CHILD is derived from the vtable symbol PARENT. */
+
+void
+assemble_vtable_inherit (child, parent)
+ rtx child, parent;
+{
+ fputs ("\t.vtable_inherit ", asm_out_file);
+ output_addr_const (asm_out_file, child);
+ fputs (", ", asm_out_file);
+ output_addr_const (asm_out_file, parent);
+ fputc ('\n', asm_out_file);
+}