/* Output variables, constants and external declarations, for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
/* Number for making the label on the next
constant that is stored in memory. */
-int const_labelno;
+static GTY(()) int const_labelno;
/* Number for making the label on the next
static variable internal to a function. */
-int var_labelno;
+static GTY(()) int var_labelno;
/* Carry information from ASM_DECLARE_OBJECT_NAME
to ASM_FINISH_DECLARE_OBJECT. */
#endif
#ifdef BSS_SECTION_ASM_OP
#ifdef ASM_OUTPUT_ALIGNED_BSS
-static void asm_output_aligned_bss PARAMS ((FILE *, tree, const char *,
- int, int));
+static void asm_output_aligned_bss
+ PARAMS ((FILE *, tree, const char *, int, int)) ATTRIBUTE_UNUSED;
#endif
#endif /* BSS_SECTION_ASM_OP */
static hashval_t const_str_htab_hash PARAMS ((const void *x));
static void resolve_unique_section PARAMS ((tree, int, int));
static void mark_weak PARAMS ((tree));
\f
-static enum in_section { no_section, in_text, in_data, in_named
+enum in_section { no_section, in_text, in_data, in_named
#ifdef BSS_SECTION_ASM_OP
, in_bss
#endif
#ifdef EXTRA_SECTIONS
, EXTRA_SECTIONS
#endif
-} in_section = no_section;
+};
+static GTY(()) enum in_section in_section = no_section;
/* Return a nonzero value if DECL has a section attribute. */
#ifndef IN_NAMED_SECTION
#endif
/* Text of section name when in_section == in_named. */
-static const char *in_named_name;
+static GTY(()) const char *in_named_name;
/* Hash table of flags that have been used for a particular named section. */
-struct in_named_entry
+struct in_named_entry GTY(())
{
const char *name;
unsigned int flags;
bool declared;
};
-static htab_t in_named_htab;
+static GTY((param_is (struct in_named_entry))) htab_t in_named_htab;
/* Define functions like text_section for any extra sections. */
#ifdef EXTRA_SECTION_FUNCTIONS
}
}
-/* Tell assembler to ALWAYS switch to data section, in case
- it's not sure where it is. */
-
-void
-force_data_section ()
-{
- in_section = no_section;
- data_section ();
-}
-
/* Tell assembler to switch to read-only data section. This is normally
the text section. */
if (!entry)
{
- entry = (struct in_named_entry *) xmalloc (sizeof (*entry));
+ entry = (struct in_named_entry *) ggc_alloc (sizeof (*entry));
*slot = entry;
entry->name = ggc_strdup (section);
entry->flags = flags;
const char *name;
int size, align;
{
- (*targetm.asm_out.globalize_label) (file, name);
bss_section ();
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
#ifdef ASM_DECLARE_OBJECT_NAME
(*targetm.asm_out.select_section) (decl, reloc, DECL_ALIGN (decl));
}
-/* Tell assembler to switch to the section for the exception handling
- table. */
-
-void
-default_exception_section ()
-{
- 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
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
}
- /* If this variable is to be treated as volatile, show its
- 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
- && (TREE_PUBLIC (decl) || TREE_STATIC (decl)))))
- TREE_SIDE_EFFECTS (decl) = 1;
-
x = gen_rtx_MEM (DECL_MODE (decl), gen_rtx_SYMBOL_REF (Pmode, name));
SYMBOL_REF_WEAK (XEXP (x, 0)) = DECL_WEAK (decl);
if (TREE_CODE (decl) != FUNCTION_DECL)
MEM_VOLATILE_P (DECL_RTL (var)) = 1;
}
\f
-/* Output alignment directive to align for constant expression EXP. */
-
-void
-assemble_constant_align (exp)
- tree 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 (align > BITS_PER_UNIT)
- {
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
- }
-}
-
/* Output a string of literal assembler code
for an `asm' keyword used between functions. */
/* Tell assembler to move to target machine's alignment for functions. */
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+ if (align < force_align_functions_log)
+ align = force_align_functions_log;
if (align > 0)
{
ASM_OUTPUT_ALIGN (asm_out_file, align);
else if (DECL_INITIAL (decl) == 0
|| DECL_INITIAL (decl) == error_mark_node
|| (flag_zero_initialized_in_bss
+ /* Leave constant zeroes in .rodata so they can be shared. */
+ && !TREE_READONLY (decl)
&& initializer_zerop (DECL_INITIAL (decl))))
{
unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
ASM_OUTPUT_ALIGN (asm_out_file, align);
}
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LTRAMP", 0);
+ (*targetm.asm_out.internal_label) (asm_out_file, "LTRAMP", 0);
TRAMPOLINE_TEMPLATE (asm_out_file);
/* Record the rtl to refer to it. */
ENUM_BITFIELD(kind) kind : 16;
ENUM_BITFIELD(machine_mode) mode : 16;
union rtx_const_un {
- REAL_VALUE_TYPE du;
- struct addr_const GTY ((tag ("1"))) addr;
+ REAL_VALUE_TYPE GTY ((tag ("4"))) du;
+ struct rtx_const_u_addr {
+ rtx base;
+ const char *symbol;
+ HOST_WIDE_INT offset;
+ } GTY ((tag ("1"))) addr;
struct rtx_const_u_di {
HOST_WIDE_INT high;
HOST_WIDE_INT low;
} GTY ((tag ("0"))) di;
- /* The max vector size we have is 8 wide; two variants for
+ /* The max vector size we have is 16 wide; two variants for
integral and floating point vectors. */
struct rtx_const_int_vec {
HOST_WIDE_INT high;
HOST_WIDE_INT low;
- } GTY ((tag ("2"))) int_vec[8];
+ } GTY ((tag ("2"))) int_vec[16];
REAL_VALUE_TYPE GTY ((tag ("3"))) fp_vec[8];
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))
+#define STRHASH(x) htab_hash_pointer (x)
struct deferred_string GTY(())
{
}
/* Output the label itself. */
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
+ (*targetm.asm_out.internal_label) (asm_out_file, "LC", labelno);
/* Output the value of EXP. */
output_constant (exp,
/* More constant_descriptors with the same hash code. */
struct constant_descriptor_rtx *next;
- /* The label of the constant. */
- const char *label;
-
/* A MEM for the constant. */
rtx rtl;
if (value->kind >= RTX_INT && value->un.addr.base != 0)
switch (GET_CODE (value->un.addr.base))
{
-#if 0
case SYMBOL_REF:
/* Use the string's address, not the SYMBOL_REF's address,
for the sake of addresses of library routines. */
- value->un.addr.base = (rtx) XSTR (value->un.addr.base, 0);
+ value->un.addr.symbol = XSTR (value->un.addr.base, 0);
+ value->un.addr.base = NULL_RTX;
break;
-#endif
case LABEL_REF:
/* For a LABEL_REF, compare labels. */
if (val0.kind >= RTX_INT
&& val0.kind == val1.kind
- && val0.un.addr.base == val1.un.addr.base)
+ && val0.un.addr.base == val1.un.addr.base
+ && val0.un.addr.symbol == val1.un.addr.symbol)
return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
return x;
struct pool_constant *pool;
unsigned int align;
+ /* If we're not allowed to drop X into the constant pool, don't. */
+ if ((*targetm.cannot_force_const_mem) (x))
+ return NULL_RTX;
+
/* Compute hash code of X. Search the descriptors for that hash code
to see if any of them describes X. If yes, we have an rtx to use. */
hash = const_hash_rtx (mode, x);
assemble_align (pool->align);
/* Output the label. */
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", pool->labelno);
+ (*targetm.asm_out.internal_label) (asm_out_file, "LC", pool->labelno);
/* Output the value of the constant itself. */
switch (GET_MODE_CLASS (pool->mode))
abort ();
}
+ /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
+ sections have proper size. */
+ if (pool->align > GET_MODE_BITSIZE (pool->mode)
+ && in_section == in_named
+ && get_named_section_flags (in_named_name) & SECTION_MERGE)
+ assemble_align (pool->align);
+
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
done: ;
#endif
output_addressed_constants (exp)
tree exp;
{
- int reloc = 0;
+ int reloc = 0, reloc2;
tree tem;
/* Give the front-end a chance to convert VALUE to something that
break;
case PLUS_EXPR:
- case MINUS_EXPR:
reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
reloc |= output_addressed_constants (TREE_OPERAND (exp, 1));
break;
+ case MINUS_EXPR:
+ reloc = output_addressed_constants (TREE_OPERAND (exp, 0));
+ reloc2 = output_addressed_constants (TREE_OPERAND (exp, 1));
+ /* The difference of two local labels is computable at link time. */
+ if (reloc == 1 && reloc2 == 1)
+ reloc = 0;
+ else
+ reloc |= reloc2;
+ break;
+
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
op1 = TREE_OPERAND (value, 1);
/* Like STRIP_NOPS except allow the operand mode to widen.
- This works around a feature of fold that simplfies
+ This works around a feature of fold that simplifies
(int)(p1 - p2) to ((int)p1 - (int)p2) under the theory
that the narrower operation is cheaper. */
enum tree_code code;
HOST_WIDE_INT thissize;
- /* Some front-ends use constants other than the standard language-indepdent
+ /* Some front-ends use constants other than the standard language-independent
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);
/* 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. */
+ /* Nonzero means BYTE contains part of a byte, to be output. */
int byte_buffer_in_use = 0;
int byte = 0;
for (t = weak_decls; t; t = TREE_CHAIN (t))
{
tree decl = TREE_VALUE (t);
- const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+#if defined (ASM_WEAKEN_DECL) || defined (ASM_WEAKEN_LABEL)
+ const char *const name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+#endif
if (! TREE_USED (decl))
continue;
}
/* Emit an assembler directive to set symbol for DECL visibility to
- VISIBILITY_TYPE. */
+ the visibility type VIS, which must not be VISIBILITY_DEFAULT. */
void
-default_assemble_visibility (decl, visibility_type)
+default_assemble_visibility (decl, vis)
tree decl;
- const char *visibility_type ATTRIBUTE_UNUSED;
+ int vis;
{
- const char *name;
+ static const char * const visibility_types[] = {
+ NULL, "internal", "hidden", "protected"
+ };
+
+ const char *name, *type;
name = (* targetm.strip_name_encoding)
(IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ type = visibility_types[vis];
#ifdef HAVE_GAS_HIDDEN
- fprintf (asm_out_file, "\t.%s\t%s\n", visibility_type, name);
+ fprintf (asm_out_file, "\t.%s\t%s\n", type, name);
#else
warning ("visibility attribute not supported in this configuration; ignored");
#endif
maybe_assemble_visibility (decl)
tree decl;
{
- tree visibility = lookup_attribute ("visibility", DECL_ATTRIBUTES (decl));
- if (visibility)
- {
- const char *type
- = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (visibility)));
- (* targetm.asm_out.visibility) (decl, type);
- }
+ enum symbol_visibility vis = decl_visibility (decl);
+
+ if (vis != VISIBILITY_DEFAULT)
+ (* targetm.asm_out.visibility) (decl, vis);
}
/* Returns 1 if the target configuration supports defining public symbols
DECL_ONE_ONLY (decl) = 1;
}
else if (SUPPORTS_WEAK)
- DECL_WEAK (decl) = 1;
+ declare_weak (decl);
else
abort ();
}
{
const_str_htab = htab_create_ggc (128, const_str_htab_hash,
const_str_htab_eq, NULL);
- in_named_htab = htab_create (31, in_named_entry_hash,
- in_named_entry_eq, NULL);
+ in_named_htab = htab_create_ggc (31, in_named_entry_hash,
+ in_named_entry_eq, NULL);
const_alias_set = new_alias_set ();
}
+enum tls_model
+decl_tls_model (decl)
+ tree decl;
+{
+ enum tls_model kind;
+ tree attr = lookup_attribute ("tls_model", DECL_ATTRIBUTES (decl));
+ bool is_local;
+
+ if (attr)
+ {
+ attr = TREE_VALUE (TREE_VALUE (attr));
+ if (TREE_CODE (attr) != STRING_CST)
+ abort ();
+ if (!strcmp (TREE_STRING_POINTER (attr), "local-exec"))
+ kind = TLS_MODEL_LOCAL_EXEC;
+ else if (!strcmp (TREE_STRING_POINTER (attr), "initial-exec"))
+ kind = TLS_MODEL_INITIAL_EXEC;
+ else if (!strcmp (TREE_STRING_POINTER (attr), "local-dynamic"))
+ kind = optimize ? TLS_MODEL_LOCAL_DYNAMIC : TLS_MODEL_GLOBAL_DYNAMIC;
+ else if (!strcmp (TREE_STRING_POINTER (attr), "global-dynamic"))
+ kind = TLS_MODEL_GLOBAL_DYNAMIC;
+ else
+ abort ();
+ return kind;
+ }
+
+ is_local = (*targetm.binds_local_p) (decl);
+ if (!flag_pic)
+ {
+ if (is_local)
+ kind = TLS_MODEL_LOCAL_EXEC;
+ else
+ kind = TLS_MODEL_INITIAL_EXEC;
+ }
+ /* Local dynamic is inefficient when we're not combining the
+ parts of the address. */
+ else if (optimize && is_local)
+ kind = TLS_MODEL_LOCAL_DYNAMIC;
+ else
+ kind = TLS_MODEL_GLOBAL_DYNAMIC;
+ if (kind < flag_tls_default)
+ kind = flag_tls_default;
+
+ return kind;
+}
+
+enum symbol_visibility
+decl_visibility (decl)
+ tree decl;
+{
+ tree attr = lookup_attribute ("visibility", DECL_ATTRIBUTES (decl));
+
+ if (attr)
+ {
+ const char *which = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)));
+
+ if (strcmp (which, "default") == 0)
+ return VISIBILITY_DEFAULT;
+ if (strcmp (which, "internal") == 0)
+ return VISIBILITY_INTERNAL;
+ if (strcmp (which, "hidden") == 0)
+ return VISIBILITY_HIDDEN;
+ if (strcmp (which, "protected") == 0)
+ return VISIBILITY_PROTECTED;
+
+ abort ();
+ }
+
+ return VISIBILITY_DEFAULT;
+}
+
/* Select a set of attributes for section NAME based on the properties
of DECL and whether or not RELOC indicates that DECL's initializer
might contain runtime relocations.
|| strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
flags |= SECTION_TLS;
+ /* These three sections have special ELF types. They are neither
+ SHT_PROGBITS nor SHT_NOBITS, so when changing sections we don't
+ want to print a section type (@progbits or @nobits). If someone
+ is silly enough to emit code or TLS variables to one of these
+ sections, then don't handle them specially. */
+ if (!(flags & (SECTION_CODE | SECTION_BSS | SECTION_TLS))
+ && (strcmp (name, ".init_array") == 0
+ || strcmp (name, ".fini_array") == 0
+ || strcmp (name, ".preinit_array") == 0))
+ flags |= SECTION_NOTYPE;
+
return flags;
}
unsigned int flags;
{
char flagchars[10], *f = flagchars;
- const char *type;
if (! named_section_first_declaration (name))
{
*f++ = 'T';
*f = '\0';
- if (flags & SECTION_BSS)
- type = "nobits";
- else
- type = "progbits";
+ fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
- 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);
+ if (!(flags & SECTION_NOTYPE))
+ {
+ const char *type;
+
+ if (flags & SECTION_BSS)
+ type = "nobits";
+ else
+ type = "progbits";
+
+ fprintf (asm_out_file, ",@%s", type);
+
+ if (flags & SECTION_ENTSIZE)
+ fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
+ }
+
+ putc ('\n', asm_out_file);
}
void
ret = SECCAT_DATA_REL_RO;
else if (shlib && reloc)
ret = SECCAT_DATA_REL_RO_LOCAL;
- else if (flag_merge_constants < 2)
+ else if (reloc || flag_merge_constants < 2)
/* C and C++ don't allow different variables to share the same
location. -fmerge-all-constants allows even that (at the
expense of not conforming). */
else if (! TREE_PUBLIC (exp))
local_p = true;
/* A variable is local if the user tells us so. */
- else if (MODULE_LOCAL_P (exp))
+ else if (decl_visibility (exp) != VISIBILITY_DEFAULT)
local_p = true;
/* Otherwise, variables defined outside this object may not be local. */
else if (DECL_EXTERNAL (exp))
return local_p;
}
+/* Determine whether or not a pointer mode is valid. Assume defaults
+ of ptr_mode or Pmode - can be overridden. */
+bool
+default_valid_pointer_mode (mode)
+ enum machine_mode mode;
+{
+ return (mode == ptr_mode || mode == Pmode);
+}
+
/* Default function to output code that will globalize a label. A
target must define GLOBAL_ASM_OP or provide it's own function to
globalize a label. */
}
#endif /* GLOBAL_ASM_OP */
+/* This is how to output an internal numbered label where PREFIX is
+ the class of label and LABELNO is the number within the class. */
+
+void
+default_internal_label (stream, prefix, labelno)
+ FILE *stream;
+ const char *prefix;
+ unsigned long labelno;
+{
+ char *const buf = alloca (40 + strlen (prefix));
+ ASM_GENERATE_INTERNAL_LABEL (buf, prefix, labelno);
+ ASM_OUTPUT_LABEL (stream, buf);
+}
+
#include "gt-varasm.h"