declarations for e.g. AIX 4.x. */
#endif
-#ifndef ASM_STABS_OP
-#define ASM_STABS_OP "\t.stabs\t"
-#endif
-
/* The (assembler) name of the first globally-visible object output. */
const char *first_global_object_name;
const char *weak_global_object_name;
partitions hot and cold basic blocks into separate sections of the .o
file. */
-bool unlikely_section_label_printed = false;
+static bool unlikely_section_label_printed = false;
+
+/* The following global variable indicates the label name to be put at
+ the start of the first cold section within each function, when
+ partitioning basic blocks into hot and cold sections. */
+
+static char *unlikely_section_label = NULL;
+
+/* The following global variable indicates the section name to be used
+ for the current cold section, when partitioning hot and cold basic
+ blocks into separate sections. */
+
+static char *unlikely_text_section_name = NULL;
-/* 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 alias set, nothing will ever
- conflict with them. */
+/* We give all constants their own alias set. Perhaps redundant with
+ MEM_READONLY_P, but pre-dates it. */
static HOST_WIDE_INT const_alias_set;
static void maybe_assemble_visibility (tree);
static int in_named_entry_eq (const void *, const void *);
static hashval_t in_named_entry_hash (const void *);
+#ifdef BSS_SECTION_ASM_OP
#ifdef ASM_OUTPUT_BSS
static void asm_output_bss (FILE *, tree, const char *,
unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
#endif
-#ifdef BSS_SECTION_ASM_OP
#ifdef ASM_OUTPUT_ALIGNED_BSS
static void asm_output_aligned_bss (FILE *, tree, const char *,
unsigned HOST_WIDE_INT, int)
{
in_section = in_text;
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
- ASM_OUTPUT_ALIGN (asm_out_file, 2);
}
}
void
unlikely_text_section (void)
{
- if ((in_section != in_unlikely_executed_text)
- && (in_section != in_named
- || strcmp (in_named_name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) != 0))
+ const char *name;
+ int len;
+
+ if (! unlikely_text_section_name)
{
- if (targetm.have_named_sections)
- named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
+ if (DECL_SECTION_NAME (current_function_decl)
+ && (strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME
+ (current_function_decl)),
+ HOT_TEXT_SECTION_NAME) != 0)
+ && (strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME
+ (current_function_decl)),
+ UNLIKELY_EXECUTED_TEXT_SECTION_NAME) != 0))
+ {
+ name = TREE_STRING_POINTER (DECL_SECTION_NAME
+ (current_function_decl));
+ len = strlen (name);
+ unlikely_text_section_name = xmalloc ((len + 10) * sizeof (char));
+ strcpy (unlikely_text_section_name, name);
+ strcat (unlikely_text_section_name, "_unlikely");
+ }
else
{
- in_section = in_unlikely_executed_text;
- fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
+ len = strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
+ unlikely_text_section_name = xmalloc (len+1 * sizeof (char));
+ strcpy (unlikely_text_section_name,
+ UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
}
-
+ }
+
+ if ((in_section != in_unlikely_executed_text)
+ && (in_section != in_named
+ || strcmp (in_named_name, unlikely_text_section_name) != 0))
+ {
+ named_section (NULL_TREE, unlikely_text_section_name, 0);
+ in_section = in_unlikely_executed_text;
+
if (!unlikely_section_label_printed)
{
- fprintf (asm_out_file, "__%s_unlikely_section:\n",
- current_function_name ());
+ ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
unlikely_section_label_printed = true;
-
- /* Make sure that we have appropriate alignment for instructions
- in this section. */
- assemble_align (FUNCTION_BOUNDARY);
}
}
}
int
in_unlikely_text_section (void)
{
- return in_section == in_unlikely_executed_text;
+ bool ret_val;
+
+ ret_val = ((in_section == in_unlikely_executed_text)
+ || (in_section == in_named
+ && unlikely_text_section_name
+ && strcmp (in_named_name, unlikely_text_section_name) == 0));
+
+ return ret_val;
}
/* Determine if we're in the data section. */
set of flags for a section to have, so 0 does not mean that the section
has not been seen. */
-unsigned int
+static unsigned int
get_named_section_flags (const char *section)
{
struct in_named_entry **slot;
return true;
}
-/* Tell assembler to change to section NAME with attributes FLAGS. */
+/* Tell assembler to change to section NAME with attributes FLAGS. If
+ DECL is non-NULL, it is the VAR_DECL or FUNCTION_DECL with which
+ this section is associated. */
void
-named_section_flags (const char *name, unsigned int flags)
+named_section_real (const char *name, unsigned int flags, tree decl)
{
if (in_section != in_named || strcmp (name, in_named_name) != 0)
{
if (! set_named_section_flags (name, flags))
abort ();
- targetm.asm_out.named_section (name, flags);
+ targetm.asm_out.named_section (name, flags, decl);
if (flags & SECTION_FORGET)
in_section = no_section;
if (name == NULL)
name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+ if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0
+ && !unlikely_text_section_name)
+ {
+ unlikely_text_section_name = xmalloc
+ (strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME) + 1
+ * sizeof (char));
+ strcpy (unlikely_text_section_name,
+ UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
+ }
+
flags = targetm.section_type_flags (decl, name, reloc);
/* Sanity check user variables for flag changes. Non-user
error ("%J%D causes a section type conflict", decl, decl);
}
- named_section_flags (name, flags);
+ named_section_real (name, flags, decl);
}
/* If required, set DECL_SECTION_NAME to a unique name. */
/* Switch to the section for function DECL.
- If DECL is NULL_TREE, switch to the text section.
- ??? It's not clear that we will ever be passed NULL_TREE, but it's
- safer to handle it. */
+ If DECL is NULL_TREE, switch to the text section. We can be passed
+ NULL_TREE under some circumstances by dbxout.c at least. */
void
function_section (tree decl)
{
- if (scan_ahead_for_unlikely_executed_note (get_insns()))
- unlikely_text_section ();
+ if (decl == NULL_TREE)
+ text_section ();
else
{
- if (decl != NULL_TREE
- && DECL_SECTION_NAME (decl) != NULL_TREE)
- named_section (decl, (char *) 0, 0);
+ /* ??? Typical use of this function maybe shouldn't be looking
+ for unlikely blocks at all - in the event that an entire
+ function is going into the unlikely-execute section, that
+ should be reflected in its DECL_SECTION_NAME. */
+ rtx insns = cfun && cfun->emit ? get_insns () : 0;
+ bool unlikely = insns && scan_ahead_for_unlikely_executed_note (insns);
+
+#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
+ targetm.asm_out.select_section (decl, unlikely, DECL_ALIGN (decl));
+#else
+ if (unlikely)
+ unlikely_text_section ();
+ else if (DECL_SECTION_NAME (decl))
+ named_section (decl, 0, 0);
else
- text_section ();
+ text_section ();
+#endif
}
}
+/* Switch to read-only data section associated with function DECL. */
+
+void
+default_function_rodata_section (tree decl)
+{
+ if (decl != NULL_TREE && DECL_SECTION_NAME (decl))
+ {
+ const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+
+ /* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo. */
+ if (DECL_ONE_ONLY (decl) && strncmp (name, ".gnu.linkonce.t.", 16) == 0)
+ {
+ size_t len = strlen (name) + 1;
+ char *rname = alloca (len);
+
+ memcpy (rname, name, len);
+ rname[14] = 'r';
+ named_section_real (rname, SECTION_LINKONCE, decl);
+ return;
+ }
+ /* For .text.foo we want to use .rodata.foo. */
+ else if (flag_function_sections && flag_data_sections
+ && strncmp (name, ".text.", 6) == 0)
+ {
+ size_t len = strlen (name) + 1;
+ char *rname = alloca (len + 2);
+
+ memcpy (rname, ".rodata", 7);
+ memcpy (rname + 7, name + 5, len - 5);
+ named_section_flags (rname, 0);
+ return;
+ }
+ }
+
+ readonly_data_section ();
+}
+
+/* Switch to read-only data section associated with function DECL
+ for targets where that section should be always the single
+ readonly data section. */
+
+void
+default_no_function_rodata_section (tree decl ATTRIBUTE_UNUSED)
+{
+ readonly_data_section ();
+}
+
/* Switch to section for variable DECL. RELOC is the same as the
argument to SELECT_SECTION. */
return name;
}
\f
+/* The user has asked for a DECL to have a particular name. Set (or
+ change) it in such a way that we don't prefix an underscore to
+ it. */
+void
+set_user_assembler_name (tree decl, const char *name)
+{
+ char *starred = alloca (strlen (name) + 2);
+ starred[0] = '*';
+ strcpy (starred + 1, name);
+ change_decl_assembler_name (decl, get_identifier (starred));
+ SET_DECL_RTL (decl, NULL_RTX);
+}
+\f
/* Decode an `asm' spec for a declaration as a register name.
Return the register number, or -1 if nothing specified,
or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,
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 (tree decl, const char *asmspec)
+make_decl_rtl (tree decl)
{
const char *name = 0;
int reg_number;
SET_DECL_RTL (decl, adjust_address_nv (DECL_RTL (decl),
DECL_MODE (decl), 0));
+ if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
+ return;
+
/* ??? Another way to do this would be to maintain a hashed
table of such critters. Instead of adding stuff to a DECL
to give certain attributes to it, we could use an external
return;
}
- reg_number = decode_reg_name (asmspec);
- if (reg_number == -2)
- {
- /* ASMSPEC is given, and not the name of a register. Mark the
- name with a star so assemble_name won't munge it. */
- char *starred = alloca (strlen (asmspec) + 2);
- starred[0] = '*';
- strcpy (starred + 1, asmspec);
- change_decl_assembler_name (decl, get_identifier (starred));
- }
-
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+
if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
{
+ reg_number = decode_reg_name (name);
/* First detect errors in declaring global registers. */
if (reg_number == -1)
- error ("%Jregister name not specified for '%D'", decl, decl);
+ error ("%Jregister name not specified for %qD", decl, decl);
else if (reg_number < 0)
- error ("%Jinvalid register name for '%D'", decl, decl);
+ error ("%Jinvalid register name for %qD", decl, decl);
else if (TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
- error ("%Jdata type of '%D' isn't suitable for a register",
+ error ("%Jdata type of %qD isn%'t suitable for a register",
decl, decl);
else if (! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
- error ("%Jregister specified for '%D' isn't suitable for data type",
+ error ("%Jregister specified for %qD isn%'t suitable for data type",
decl, decl);
/* Now handle properly declared static register variables. */
else
error ("global register variable has initial value");
}
if (TREE_THIS_VOLATILE (decl))
- warning ("volatile register variables don't work as you might wish");
+ warning ("volatile register variables don%'t "
+ "work as you might wish");
/* If the user specified one of the eliminables registers here,
e.g., FRAME_POINTER_REGNUM, we don't want to get this variable
return;
}
}
-
/* Now handle ordinary static variables and functions (in memory).
Also handle vars declared register invalidly. */
-
- if (reg_number >= 0 || reg_number == -3)
- error ("%Jregister name given for non-register variable '%D'", decl, decl);
+ else if (name[0] == '*')
+ {
+#ifdef REGISTER_PREFIX
+ if (strlen (REGISTER_PREFIX) != 0)
+ {
+ reg_number = decode_reg_name (name);
+ if (reg_number >= 0 || reg_number == -3)
+ error ("%Jregister name given for non-register variable %qD", decl, decl);
+ }
+#endif
+ }
/* Specifying a section attribute on a variable forces it into a
non-.bss section, and thus it cannot be common. */
void
make_var_volatile (tree var)
{
- if (GET_CODE (DECL_RTL (var)) != MEM)
+ if (!MEM_P (DECL_RTL (var)))
abort ();
MEM_VOLATILE_P (DECL_RTL (var)) = 1;
between 0 and MAX_INIT_PRIORITY. */
void
-default_stabs_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
+default_stabs_asm_out_destructor (rtx symbol ATTRIBUTE_UNUSED,
+ int priority ATTRIBUTE_UNUSED)
{
+#if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO
/* Tell GNU LD that this is part of the static destructor set.
This will work for any system that uses stabs, most usefully
aout systems. */
- fprintf (asm_out_file, "%s\"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);
- assemble_name (asm_out_file, XSTR (symbol, 0));
- fputc ('\n', asm_out_file);
+ dbxout_begin_simple_stabs ("___DTOR_LIST__", 22 /* N_SETT */);
+ dbxout_stab_value_label (XSTR (symbol, 0));
+#else
+ sorry ("global destructors not supported on this target");
+#endif
}
void
/* Likewise for global constructors. */
void
-default_stabs_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
+default_stabs_asm_out_constructor (rtx symbol ATTRIBUTE_UNUSED,
+ int priority ATTRIBUTE_UNUSED)
{
+#if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO
/* Tell GNU LD that this is part of the static destructor set.
This will work for any system that uses stabs, most usefully
aout systems. */
- fprintf (asm_out_file, "%s\"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP);
- assemble_name (asm_out_file, XSTR (symbol, 0));
- fputc ('\n', asm_out_file);
+ dbxout_begin_simple_stabs ("___CTOR_LIST__", 22 /* N_SETT */);
+ dbxout_stab_value_label (XSTR (symbol, 0));
+#else
+ sorry ("global constructors not supported on this target");
+#endif
}
void
|| (DECL_COMMON (decl)
&& (DECL_INITIAL (decl) == 0
|| DECL_INITIAL (decl) == error_mark_node))))
- || GET_CODE (DECL_RTL (decl)) != MEM)
+ || !MEM_P (DECL_RTL (decl)))
return;
/* We win when global object is found, but it is useful to know about weak
{
int align;
- unlikely_section_label_printed = false;
+ if (unlikely_text_section_name)
+ free (unlikely_text_section_name);
+ unlikely_section_label_printed = false;
+ unlikely_text_section_name = NULL;
+
+ unlikely_section_label = reconcat (unlikely_section_label,
+ fnname, ".unlikely_section", NULL);
+
/* The following code does not need preprocessing in the assembler. */
app_disable ();
if (CONSTANT_POOL_BEFORE_FUNCTION)
output_constant_pool (fnname, decl);
+ /* Make sure the cold text (code) section is properly aligned. This
+ is necessary here in the case where the function has both hot and
+ cold sections, because we don't want to re-set the alignment when the
+ section switch happens mid-function. We don't need to set the hot
+ section alignment here, because code further down in this function
+ sets the alignment for whichever section comes first, and if there
+ is a hot section it is guaranteed to be first. */
+
+ if (flag_reorder_blocks_and_partition)
+ {
+ unlikely_text_section ();
+ assemble_align (FUNCTION_BOUNDARY);
+ }
+
resolve_unique_section (decl, 0, flag_function_sections);
function_section (decl);
maybe_assemble_visibility (decl);
}
+ if (DECL_PRESERVE_P (decl))
+ targetm.asm_out.mark_decl_preserved (fnname);
+
/* Do any machine/system dependent processing of the function name. */
#ifdef ASM_DECLARE_FUNCTION_NAME
ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
/* Standard thing is just output label for the function. */
ASM_OUTPUT_LABEL (asm_out_file, fnname);
#endif /* ASM_DECLARE_FUNCTION_NAME */
+
+ if (in_unlikely_text_section ()
+ && !unlikely_section_label_printed)
+ {
+ ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
+ unlikely_section_label_printed = true;
+ }
}
/* Output assembler code associated with defining the size of the
return;
/* Do nothing for global register variables. */
- if (DECL_RTL_SET_P (decl) && GET_CODE (DECL_RTL (decl)) == REG)
+ if (DECL_RTL_SET_P (decl) && REG_P (DECL_RTL (decl)))
{
TREE_ASM_WRITTEN (decl) = 1;
return;
if (!dont_output_data && DECL_SIZE (decl) == 0)
{
- error ("%Jstorage size of `%D' isn't known", decl, decl);
+ error ("%Jstorage size of %qD isn%'t known", decl, decl);
TREE_ASM_WRITTEN (decl) = 1;
return;
}
if (! dont_output_data
&& ! host_integerp (DECL_SIZE_UNIT (decl), 1))
{
- error ("%Jsize of variable '%D' is too large", decl, decl);
+ error ("%Jsize of variable %qD is too large", decl, decl);
return;
}
/* Some object file formats have a maximum alignment which they support.
In particular, a.out format supports a maximum alignment of 4. */
-#ifndef MAX_OFILE_ALIGNMENT
-#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
-#endif
if (align > MAX_OFILE_ALIGNMENT)
{
- warning ("%Jalignment of '%D' is greater than maximum object "
+ warning ("%Jalignment of %qD is greater than maximum object "
"file alignment. Using %d", decl, decl,
MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
align = MAX_OFILE_ALIGNMENT;
if (TREE_PUBLIC (decl))
maybe_assemble_visibility (decl);
+ if (DECL_PRESERVE_P (decl))
+ targetm.asm_out.mark_decl_preserved (name);
+
/* 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)) ? 3 : 0;
* (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
#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 ("%Jrequested alignment for '%D' is greater than "
+ if ((unsigned HOST_WIDE_INT) DECL_ALIGN_UNIT (decl) > rounded)
+ warning ("%Jrequested alignment for %qD is greater than "
"implemented alignment of %d", decl, decl, rounded);
#endif
/* 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_UNIT (decl)));
/* Do any machine/system dependent processing of the object. */
#ifdef ASM_DECLARE_OBJECT_NAME
if (!dont_output_data)
{
- if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)
+ if (DECL_INITIAL (decl)
+ && DECL_INITIAL (decl) != error_mark_node
+ && !initializer_zerop (DECL_INITIAL (decl)))
/* Output the actual data. */
output_constant (DECL_INITIAL (decl),
tree_low_cst (DECL_SIZE_UNIT (decl), 1),
{
rtx rtl = DECL_RTL (decl);
- if (GET_CODE (rtl) == MEM && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
+ if (MEM_P (rtl) && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
&& !SYMBOL_REF_USED (XEXP (rtl, 0))
&& !incorporeal_function_p (decl))
{
int aligned_p ATTRIBUTE_UNUSED)
{
const char *op = integer_asm_op (size, aligned_p);
+ /* Avoid GAS bugs for large values. Specifically negative values whose
+ absolute value fits in a bfd_vma, but not in a bfd_signed_vma. */
+ if (size > UNITS_PER_WORD && size > POINTER_SIZE / BITS_PER_UNIT)
+ return false;
return op && (assemble_integer_with_op (op, x), true);
}
abort ();
}
- if (GET_CODE (x) != MEM)
+ if (!MEM_P (x))
abort ();
x = XEXP (x, 0);
case ADDR_EXPR:
/* For ADDR_EXPR, we do not want to copy the decl whose address
is requested. We do want to copy constants though. */
- if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == 'c')
+ if (CONSTANT_CLASS_P (TREE_OPERAND (exp, 0)))
return build1 (TREE_CODE (exp), TREE_TYPE (exp),
copy_constant (TREE_OPERAND (exp, 0)));
else
case PLUS_EXPR:
case MINUS_EXPR:
- return build (TREE_CODE (exp), TREE_TYPE (exp),
- copy_constant (TREE_OPERAND (exp, 0)),
- copy_constant (TREE_OPERAND (exp, 1)));
+ return build2 (TREE_CODE (exp), TREE_TYPE (exp),
+ copy_constant (TREE_OPERAND (exp, 0)),
+ copy_constant (TREE_OPERAND (exp, 1)));
case NOP_EXPR:
case CONVERT_EXPR:
desc = ggc_alloc (sizeof (*desc));
desc->value = copy_constant (exp);
- /* Propagate marked-ness to copied constant. */
+ /* Propagate marked-ness to copied constant. */
if (flag_mudflap && mf_marked_p (exp))
mf_mark (desc->value);
int reloc = compute_reloc_for_constant (exp);
/* Align the location counter as required by EXP's data type. */
- int align = TYPE_ALIGN (TREE_TYPE (exp));
+ unsigned int align = TYPE_ALIGN (TREE_TYPE (exp));
#ifdef CONSTANT_ALIGNMENT
align = CONSTANT_ALIGNMENT (exp, align);
#endif
*slot = desc;
/* Construct the MEM. */
- desc->mem = def = gen_rtx_MEM (mode, symbol);
+ desc->mem = def = gen_const_mem (mode, symbol);
set_mem_attributes (def, lang_hooks.types.type_for_mode (mode, 0), 1);
- RTX_UNCHANGING_P (def) = 1;
/* If we're dropping a label to the constant pool, make sure we
don't delete it. */
return find_pool_constant (cfun->varasm->pool, addr)->mode;
}
-enum machine_mode
-get_pool_mode_for_function (struct function *f, rtx addr)
-{
- return find_pool_constant (f->varasm->pool, addr)->mode;
-}
-
-/* Similar, return the offset in the constant pool. */
-
-int
-get_pool_offset (rtx addr)
-{
- return find_pool_constant (cfun->varasm->pool, addr)->offset;
-}
-
/* Return the size of the constant pool. */
int
case LABEL_REF:
tmp = XEXP (x, 0);
if (INSN_DELETED_P (tmp)
- || (GET_CODE (tmp) == NOTE
+ || (NOTE_P (tmp)
&& NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
{
abort ();
tem = TREE_OPERAND (tem, 0))
;
- if (TREE_CODE_CLASS (TREE_CODE (tem)) == 'c'
- || TREE_CODE (tem) == CONSTRUCTOR)
+ /* If we have an initialized CONST_DECL, retrieve the initializer. */
+ if (TREE_CODE (tem) == CONST_DECL && DECL_INITIAL (tem))
+ tem = DECL_INITIAL (tem);
+
+ if (CONSTANT_CLASS_P (tem) || TREE_CODE (tem) == CONSTRUCTOR)
output_constant_def (tem, 0);
break;
case ADDR_EXPR:
case FDESC_EXPR:
- return staticp (TREE_OPERAND (value, 0)) ? TREE_OPERAND (value, 0) : 0;
+ value = staticp (TREE_OPERAND (value, 0));
+ /* "&(*a).f" is like unto pointer arithmetic. If "a" turns out to
+ be a constant, this is old-skool offsetof-like nonsense. */
+ if (value
+ && TREE_CODE (value) == INDIRECT_REF
+ && TREE_CONSTANT (TREE_OPERAND (value, 0)))
+ return null_pointer_node;
+ return value;
case VIEW_CONVERT_EXPR:
case NON_LVALUE_EXPR:
/* 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))
+ if (valid0 && TREE_CODE (valid0) == STRING_CST
+ && valid1 && TREE_CODE (valid1) == STRING_CST
+ && operand_equal_p (valid0, valid1, 1))
return null_pointer_node;
}
- /* Support differences between labels. */
+ /* Support narrowing differences. */
if (INTEGRAL_TYPE_P (endtype))
{
tree op0, op1;
+
op0 = TREE_OPERAND (value, 0);
op1 = TREE_OPERAND (value, 1);
op1 = inner;
}
- if (TREE_CODE (op0) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
- && TREE_CODE (op1) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL)
- return null_pointer_node;
+ op0 = initializer_constant_valid_p (op0, endtype);
+ op1 = initializer_constant_valid_p (op1, endtype);
+
+ /* Both initializers must be known. */
+ if (op0 && op1)
+ {
+ if (op0 == op1)
+ return null_pointer_node;
+
+ /* Support differences between labels. */
+ if (TREE_CODE (op0) == LABEL_DECL
+ && TREE_CODE (op1) == LABEL_DECL)
+ return null_pointer_node;
+
+ if (TREE_CODE (op0) == STRING_CST
+ && TREE_CODE (op1) == STRING_CST
+ && operand_equal_p (op0, op1, 1))
+ return null_pointer_node;
+ }
}
break;
}
/* Now output the underlying data. If we've handling the padding, return.
- Otherwise, break and ensure THISSIZE is the size written. */
+ Otherwise, break and ensure SIZE is the size written. */
switch (code)
{
case CHAR_TYPE:
case OFFSET_TYPE:
if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
EXPAND_INITIALIZER),
- size, align, 0))
+ MIN (size, thissize), align, 0))
error ("initializer for integer value is too complicated");
break;
unsigned int nalign;
enum machine_mode inner;
- inner = GET_MODE_INNER (TYPE_MODE (TREE_TYPE (exp)));
+ inner = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
nalign = MIN (align, GET_MODE_ALIGNMENT (inner));
- elt_size = GET_MODE_UNIT_SIZE (TYPE_MODE (TREE_TYPE (exp)));
+ elt_size = GET_MODE_SIZE (inner);
link = TREE_VECTOR_CST_ELTS (exp);
output_constant (TREE_VALUE (link), elt_size, align);
total_bytes += fieldsize;
}
else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
- error ("invalid initial value for member `%s'",
+ error ("invalid initial value for member %qs",
IDENTIFIER_POINTER (DECL_NAME (field)));
else
{
DECL_WEAK (decl) = 1;
if (DECL_RTL_SET_P (decl)
- && GET_CODE (DECL_RTL (decl)) == MEM
+ && MEM_P (DECL_RTL (decl))
&& XEXP (DECL_RTL (decl), 0)
&& GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF)
SYMBOL_REF_WEAK (XEXP (DECL_RTL (decl), 0)) = 1;
declare_weak because the NEWDECL and OLDDECL was not yet
been merged; therefore, TREE_ASM_WRITTEN was not set. */
if (TREE_ASM_WRITTEN (olddecl))
- error ("%Jweak declaration of '%D' must precede definition",
+ error ("%Jweak declaration of %qD must precede definition",
newdecl, newdecl);
/* If we've already generated rtl referencing OLDDECL, we may
a weak symbol. */
else if (TREE_USED (olddecl)
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (olddecl)))
- warning ("%Jweak declaration of '%D' after first use results "
+ warning ("%Jweak declaration of %qD after first use results "
"in unspecified behavior", newdecl, newdecl);
if (SUPPORTS_WEAK)
declare_weak (tree decl)
{
if (! TREE_PUBLIC (decl))
- error ("%Jweak declaration of '%D' must be public", decl, decl);
+ error ("%Jweak declaration of %qD must be public", decl, decl);
else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_ASM_WRITTEN (decl))
- error ("%Jweak declaration of '%D' must precede definition", decl, decl);
+ error ("%Jweak declaration of %qD must precede definition", decl, decl);
else if (SUPPORTS_WEAK)
{
if (! DECL_WEAK (decl))
weak_decls = tree_cons (NULL, decl, weak_decls);
}
else
- warning ("%Jweak declaration of '%D' not supported", decl, decl);
+ warning ("%Jweak declaration of %qD not supported", decl, decl);
mark_weak (decl);
}
/* We must force creation of DECL_RTL for debug info generation, even though
we don't use it here. */
- make_decl_rtl (decl, NULL);
+ make_decl_rtl (decl);
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
const_alias_set = new_alias_set ();
}
-enum tls_model
+static enum tls_model
decl_tls_model (tree decl)
{
enum tls_model kind;
flags = SECTION_CODE;
else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
flags = 0;
- else if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
+ else if (unlikely_text_section_name
+ && strcmp (name, unlikely_text_section_name) == 0)
flags = SECTION_CODE;
else
flags = SECTION_WRITE;
void
default_no_named_section (const char *name ATTRIBUTE_UNUSED,
- unsigned int flags ATTRIBUTE_UNUSED)
+ unsigned int flags ATTRIBUTE_UNUSED,
+ tree decl ATTRIBUTE_UNUSED)
{
/* Some object formats don't support named sections at all. The
front-end should already have flagged this as an error. */
}
void
-default_elf_asm_named_section (const char *name, unsigned int flags)
+default_elf_asm_named_section (const char *name, unsigned int flags,
+ tree decl ATTRIBUTE_UNUSED)
{
char flagchars[10], *f = flagchars;
- if (! named_section_first_declaration (name))
+ /* If we have already declared this section, we can use an
+ abbreviated form to switch back to it -- unless this section is
+ part of a COMDAT groups, in which case GAS requires the full
+ declaration every time. */
+ if (!(HAVE_GAS_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+ && ! named_section_first_declaration (name))
{
fprintf (asm_out_file, "\t.section\t%s\n", name);
return;
*f++ = 'S';
if (flags & SECTION_TLS)
*f++ = 'T';
+ if (HAVE_GAS_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+ *f++ = 'G';
*f = '\0';
fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
if (!(flags & SECTION_NOTYPE))
{
const char *type;
+ const char *format;
if (flags & SECTION_BSS)
type = "nobits";
else
type = "progbits";
- fprintf (asm_out_file, ",@%s", type);
+ format = ",@%s";
+#ifdef ASM_COMMENT_START
+ /* On platforms that use "@" as the assembly comment character,
+ use "%" instead. */
+ if (strcmp (ASM_COMMENT_START, "@") == 0)
+ format = ",%%%s";
+#endif
+ fprintf (asm_out_file, format, type);
if (flags & SECTION_ENTSIZE)
fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
+ if (HAVE_GAS_COMDAT_GROUP && (flags & SECTION_LINKONCE))
+ fprintf (asm_out_file, ",%s,comdat",
+ lang_hooks.decls.comdat_group (decl));
}
putc ('\n', asm_out_file);
}
void
-default_coff_asm_named_section (const char *name, unsigned int flags)
+default_coff_asm_named_section (const char *name, unsigned int flags,
+ tree decl ATTRIBUTE_UNUSED)
{
char flagchars[8], *f = flagchars;
}
void
-default_pe_asm_named_section (const char *name, unsigned int flags)
+default_pe_asm_named_section (const char *name, unsigned int flags,
+ tree decl)
{
- default_coff_asm_named_section (name, flags);
+ default_coff_asm_named_section (name, flags, decl);
if (flags & SECTION_LINKONCE)
{
else if (TREE_CODE (decl) == VAR_DECL)
{
if (DECL_INITIAL (decl) == NULL
- || DECL_INITIAL (decl) == error_mark_node)
+ || 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))))
ret = SECCAT_BSS;
else if (! TREE_READONLY (decl)
|| TREE_SIDE_EFFECTS (decl)
/* There are no read-only thread-local sections. */
if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
{
- if (ret == SECCAT_BSS)
+ /* Note that this would be *just* SECCAT_BSS, except that there's
+ no concept of a read-only thread-local-data section. */
+ if (ret == SECCAT_BSS
+ || (flag_zero_initialized_in_bss
+ && initializer_zerop (DECL_INITIAL (decl))))
ret = SECCAT_TBSS;
else
ret = SECCAT_TDATA;
default_elf_select_section_1 (tree decl, int reloc,
unsigned HOST_WIDE_INT align, int shlib)
{
+ const char *sname;
switch (categorize_decl_for_section (decl, reloc, shlib))
{
case SECCAT_TEXT:
abort ();
case SECCAT_RODATA:
readonly_data_section ();
- break;
+ return;
case SECCAT_RODATA_MERGE_STR:
mergeable_string_section (decl, align, 0);
- break;
+ return;
case SECCAT_RODATA_MERGE_STR_INIT:
mergeable_string_section (DECL_INITIAL (decl), align, 0);
- break;
+ return;
case SECCAT_RODATA_MERGE_CONST:
mergeable_constant_section (DECL_MODE (decl), align, 0);
- break;
+ return;
case SECCAT_SRODATA:
- named_section (NULL_TREE, ".sdata2", reloc);
+ sname = ".sdata2";
break;
case SECCAT_DATA:
data_section ();
- break;
+ return;
case SECCAT_DATA_REL:
- named_section (NULL_TREE, ".data.rel", reloc);
+ sname = ".data.rel";
break;
case SECCAT_DATA_REL_LOCAL:
- named_section (NULL_TREE, ".data.rel.local", reloc);
+ sname = ".data.rel.local";
break;
case SECCAT_DATA_REL_RO:
- named_section (NULL_TREE, ".data.rel.ro", reloc);
+ sname = ".data.rel.ro";
break;
case SECCAT_DATA_REL_RO_LOCAL:
- named_section (NULL_TREE, ".data.rel.ro.local", reloc);
+ sname = ".data.rel.ro.local";
break;
case SECCAT_SDATA:
- named_section (NULL_TREE, ".sdata", reloc);
+ sname = ".sdata";
break;
case SECCAT_TDATA:
- named_section (NULL_TREE, ".tdata", reloc);
+ sname = ".tdata";
break;
case SECCAT_BSS:
#ifdef BSS_SECTION_ASM_OP
bss_section ();
+ return;
#else
- named_section (NULL_TREE, ".bss", reloc);
-#endif
+ sname = ".bss";
break;
+#endif
case SECCAT_SBSS:
- named_section (NULL_TREE, ".sbss", reloc);
+ sname = ".sbss";
break;
case SECCAT_TBSS:
- named_section (NULL_TREE, ".tbss", reloc);
+ sname = ".tbss";
break;
default:
abort ();
}
+
+ if (!DECL_P (decl))
+ decl = NULL_TREE;
+ named_section (decl, sname, reloc);
}
/* Construct a unique section name based on the decl name and the
int flags;
/* Careful not to prod global register variables. */
- if (GET_CODE (rtl) != MEM)
+ if (!MEM_P (rtl))
return;
symbol = XEXP (rtl, 0);
if (GET_CODE (symbol) != SYMBOL_REF)
flags |= SYMBOL_FLAG_FUNCTION;
if (targetm.binds_local_p (decl))
flags |= SYMBOL_FLAG_LOCAL;
- if (targetm.in_small_data_p (decl))
- flags |= SYMBOL_FLAG_SMALL;
if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
flags |= decl_tls_model (decl) << SYMBOL_FLAG_TLS_SHIFT;
+ else if (targetm.in_small_data_p (decl))
+ flags |= SYMBOL_FLAG_SMALL;
/* ??? Why is DECL_EXTERNAL ever set for non-PUBLIC names? Without
being PUBLIC, the thing *must* be defined in this translation unit.
Prevent this buglet from being propagated into rtl code as well. */
/* Static variables are always local. */
else if (! TREE_PUBLIC (exp))
local_p = true;
- /* A variable is local if the user tells us so. */
- else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+ /* A variable is local if the user explicitly tells us so. */
+ else if (DECL_VISIBILITY_SPECIFIED (exp) && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
local_p = true;
/* Otherwise, variables defined outside this object may not be local. */
else if (DECL_EXTERNAL (exp))
/* Linkonce and weak data are never local. */
else if (DECL_ONE_ONLY (exp) || DECL_WEAK (exp))
local_p = false;
+ /* If none of the above and visibility is not default, make local. */
+ else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+ local_p = true;
/* If PIC, then assume that any global name can be overridden by
symbols resolved from other modules. */
else if (shlib)
/* Default function to output a label for unwind information. The
default is to do nothing. A target that needs nonlocal labels for
- unwind information must provide its own function to do this. */
+ unwind information must provide its own function to do this. */
void
default_emit_unwind_label (FILE * stream ATTRIBUTE_UNUSED,
tree decl ATTRIBUTE_UNUSED,
+ int for_eh ATTRIBUTE_UNUSED,
int empty ATTRIBUTE_UNUSED)
{
}