#include "debug.h"
#include "target.h"
#include "cgraph.h"
+#include "cfglayout.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data
tree last_assemble_variable_decl;
+/* The following global variable indicates if the section label for the
+ "cold" section of code has been output yet to the assembler. The
+ label is useful when running gdb. This is part of the optimization that
+ partitions hot and cold basic blocks into separate sections of the .o
+ file. */
+
+bool unlikely_section_label_printed = false;
+
/* 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
unsigned HOST_WIDE_INT);
static void mark_weak (tree);
\f
-enum in_section { no_section, in_text, in_data, in_named
+enum in_section { no_section, in_text, in_unlikely_executed_text, in_data,
+ in_named
#ifdef BSS_SECTION_ASM_OP
, in_bss
#endif
{
in_section = in_text;
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
+ ASM_OUTPUT_ALIGN (asm_out_file, 2);
+ }
+}
+
+/* Tell assembler to switch to unlikely-to-be-executed text section. */
+
+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))
+ {
+ if (targetm.have_named_sections)
+ named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
+ else
+ {
+ in_section = in_unlikely_executed_text;
+ fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
+ ASM_OUTPUT_ALIGN (asm_out_file, 2);
+ }
+
+ if (!unlikely_section_label_printed)
+ {
+ fprintf (asm_out_file, "__%s_unlikely_section:\n",
+ current_function_name ());
+ unlikely_section_label_printed = true;
+ }
}
}
return in_section == in_text;
}
+/* Determine if we're in the unlikely-to-be-executed text section. */
+
+int
+in_unlikely_text_section (void)
+{
+ return in_section == in_unlikely_executed_text;
+}
+
/* Determine if we're in the data section. */
int
if (! set_named_section_flags (name, flags))
abort ();
- (*targetm.asm_out.named_section) (name, flags);
+ targetm.asm_out.named_section (name, flags);
if (flags & SECTION_FORGET)
in_section = no_section;
if (name == NULL)
name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
- flags = (* targetm.section_type_flags) (decl, name, reloc);
+ flags = targetm.section_type_flags (decl, name, reloc);
/* Sanity check user variables for flag changes. Non-user
section flag changes will abort in named_section_flags.
&& targetm.have_named_sections
&& (flag_function_or_data_sections
|| DECL_ONE_ONLY (decl)))
- (*targetm.asm_out.unique_section) (decl, reloc);
+ targetm.asm_out.unique_section (decl, reloc);
}
#ifdef BSS_SECTION_ASM_OP
unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT rounded)
{
- (*targetm.asm_out.globalize_label) (file, name);
+ targetm.asm_out.globalize_label (file, name);
bss_section ();
#ifdef ASM_DECLARE_OBJECT_NAME
last_assemble_variable_decl = decl;
void
function_section (tree decl)
{
- if (decl != NULL_TREE
- && DECL_SECTION_NAME (decl) != NULL_TREE)
- named_section (decl, (char *) 0, 0);
+ if (scan_ahead_for_unlikely_executed_note (get_insns()))
+ unlikely_text_section ();
else
- text_section ();
+ {
+ if (decl != NULL_TREE
+ && DECL_SECTION_NAME (decl) != NULL_TREE)
+ named_section (decl, (char *) 0, 0);
+ else
+ text_section ();
+ }
}
/* Switch to section for variable DECL. RELOC is the same as the
if (IN_NAMED_SECTION (decl))
named_section (decl, NULL, reloc);
else
- (*targetm.asm_out.select_section) (decl, reloc, DECL_ALIGN (decl));
+ targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl));
}
/* Tell assembler to switch to the section for string merging. */
/* Let the target reassign the RTL if it wants.
This is necessary, for example, when one machine specific
decl attribute overrides another. */
- (* targetm.encode_section_info) (decl, DECL_RTL (decl), false);
+ targetm.encode_section_info (decl, DECL_RTL (decl), false);
return;
}
such as that it is a function name.
If the name is changed, the macro ASM_OUTPUT_LABELREF
will have to know how to strip this information. */
- (* targetm.encode_section_info) (decl, DECL_RTL (decl), true);
+ targetm.encode_section_info (decl, DECL_RTL (decl), true);
}
/* Make the rtl for variable VAR be volatile.
char *name;
rtx decl_rtl = DECL_RTL (decl);
- p = (* targetm.strip_name_encoding) (XSTR (XEXP (decl_rtl, 0), 0));
+ p = targetm.strip_name_encoding (XSTR (XEXP (decl_rtl, 0), 0));
name = xstrdup (p);
*type = name;
{
int align;
+ unlikely_section_label_printed = false;
+
/* The following code does not need preprocessing in the assembler. */
app_disable ();
#ifdef ASM_NO_SKIP_IN_TEXT
/* The `space' pseudo in the text section outputs nop insns rather than 0s,
so we must output 0s explicitly in the text section. */
- if (ASM_NO_SKIP_IN_TEXT && in_text_section ())
+ if ((ASM_NO_SKIP_IN_TEXT && in_text_section ())
+ || (ASM_NO_SKIP_IN_TEXT && in_unlikely_text_section ()))
{
unsigned HOST_WIDE_INT i;
for (i = 0; i < size; i++)
rtx decl_rtl;
if (lang_hooks.decls.prepare_assemble_variable)
- (*lang_hooks.decls.prepare_assemble_variable) (decl);
+ lang_hooks.decls.prepare_assemble_variable (decl);
last_assemble_variable_decl = 0;
variable_section (decl, reloc);
/* dbxout.c needs to know this. */
- if (in_text_section ())
+ if (in_text_section () || in_unlikely_text_section ())
DECL_IN_TEXT_SECTION (decl) = 1;
/* Output the alignment of this data. */
if (! SYMBOL_REF_USED (fun))
{
SYMBOL_REF_USED (fun) = 1;
- (*targetm.asm_out.external_libcall) (fun);
+ targetm.asm_out.external_libcall (fun);
}
}
const char *real_name;
tree id;
- real_name = (* targetm.strip_name_encoding) (name);
+ real_name = targetm.strip_name_encoding (name);
id = maybe_get_identifier (real_name);
if (id)
ASM_OUTPUT_ALIGN (asm_out_file, align);
}
- (*targetm.asm_out.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. */
aligned_p = (align >= MIN (size * BITS_PER_UNIT, BIGGEST_ALIGNMENT));
/* See if the target hook can handle this kind of object. */
- if ((*targetm.asm_out.integer) (x, size, aligned_p))
+ if (targetm.asm_out.integer (x, size, aligned_p))
return true;
/* If the object is a multi-byte one, try splitting it up. Split
return real_hash (TREE_REAL_CST_PTR (exp));
case STRING_CST:
- if (flag_writable_strings)
- {
- p = (char *) &exp;
- len = sizeof exp;
- }
- else
- {
- p = TREE_STRING_POINTER (exp);
- len = TREE_STRING_LENGTH (exp);
- }
+ p = TREE_STRING_POINTER (exp);
+ len = TREE_STRING_LENGTH (exp);
break;
case COMPLEX_CST:
return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
case STRING_CST:
- if (flag_writable_strings)
- return t1 == t2;
-
if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
return 0;
default:
{
tree nt1, nt2;
- nt1 = (*lang_hooks.expand_constant) (t1);
- nt2 = (*lang_hooks.expand_constant) (t2);
+ nt1 = lang_hooks.expand_constant (t1);
+ nt2 = lang_hooks.expand_constant (t2);
if (nt1 != t1 || nt2 != t2)
return compare_constant (nt1, nt2);
else
default:
{
tree t;
- t = (*lang_hooks.expand_constant) (exp);
+ t = lang_hooks.expand_constant (exp);
if (t != exp)
return copy_constant (t);
else
struct constant_descriptor_tree *desc;
desc = ggc_alloc (sizeof (*desc));
- if (flag_writable_strings && TREE_CODE (exp) == STRING_CST)
- desc->value = exp;
- else
- desc->value = copy_constant (exp);
+ desc->value = copy_constant (exp);
/* Create a string containing the label name, in LABEL. */
labelno = const_labelno++;
information. This call might invalidate our local variable
SYMBOL; we can't use it afterward. */
- (*targetm.encode_section_info) (exp, rtl, true);
+ targetm.encode_section_info (exp, rtl, true);
desc->rtl = rtl;
/* Already output; don't do it again. */
return;
- /* The only constants that cannot safely be deferred, assuming the
- context allows it, are strings under flag_writable_strings. */
- if (defer && (TREE_CODE (exp) != STRING_CST || !flag_writable_strings))
+ /* We can always defer constants as long as the context allows
+ doing so. */
+ if (defer)
{
/* Increment n_deferred_constants if it exists. It needs to be at
least as large as the number of constants actually referred to
if (IN_NAMED_SECTION (exp))
named_section (exp, NULL, reloc);
else
- (*targetm.asm_out.select_section) (exp, reloc, align);
+ targetm.asm_out.select_section (exp, reloc, align);
if (align > BITS_PER_UNIT)
{
void **slot;
/* If we're not allowed to drop X into the constant pool, don't. */
- if ((*targetm.cannot_force_const_mem) (x))
+ if (targetm.cannot_force_const_mem (x))
return NULL_RTX;
/* Lookup the value in the hashtable. */
align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
#ifdef CONSTANT_ALIGNMENT
{
- tree type = (*lang_hooks.types.type_for_mode) (mode, 0);
+ tree type = lang_hooks.types.type_for_mode (mode, 0);
if (type != NULL_TREE)
align = CONSTANT_ALIGNMENT (make_tree (type, x), align);
}
/* Construct the MEM. */
desc->mem = def = gen_rtx_MEM (mode, symbol);
- set_mem_attributes (def, (*lang_hooks.types.type_for_mode) (mode, 0), 1);
+ 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
}
/* First switch to correct section. */
- (*targetm.asm_out.select_rtx_section) (desc->mode, x, desc->align);
+ targetm.asm_out.select_rtx_section (desc->mode, x, desc->align);
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
assemble_align (desc->align);
/* Output the label. */
- (*targetm.asm_out.internal_label) (asm_out_file, "LC", desc->labelno);
+ targetm.asm_out.internal_label (asm_out_file, "LC", desc->labelno);
/* Output the data. */
output_constant_pool_2 (desc->mode, x, desc->align);
/* Give the front-end a chance to convert VALUE to something that
looks more like a constant to the back-end. */
- exp = (*lang_hooks.expand_constant) (exp);
+ exp = lang_hooks.expand_constant (exp);
switch (TREE_CODE (exp))
{
/* Give the front-end a chance to convert VALUE to something that
looks more like a constant to the back-end. */
- exp = (*lang_hooks.expand_constant) (exp);
+ exp = lang_hooks.expand_constant (exp);
switch (TREE_CODE (exp))
{
{
/* Give the front-end a chance to convert VALUE to something that
looks more like a constant to the back-end. */
- value = (*lang_hooks.expand_constant) (value);
+ value = lang_hooks.expand_constant (value);
switch (TREE_CODE (value))
{
endtype);
}
- /* Allow conversions to union types if the value inside is okay. */
- if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
+ /* Allow conversions to struct or union types if the value
+ inside is okay. */
+ if (TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
break;
/* 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);
+ exp = lang_hooks.expand_constant (exp);
if (size == 0 || flag_syntax_only)
return;
}
return;
}
+#elif defined(ASM_MAKE_LABEL_LINKONCE)
+ if (DECL_ONE_ONLY (decl))
+ ASM_MAKE_LABEL_LINKONCE (asm_out_file, name);
#endif
- (*targetm.asm_out.globalize_label) (asm_out_file, name);
+ targetm.asm_out.globalize_label (asm_out_file, name);
}
/* Emit an assembler directive to make the symbol for DECL an alias to
enum symbol_visibility vis = DECL_VISIBILITY (decl);
if (vis != VISIBILITY_DEFAULT)
- (* targetm.asm_out.visibility) (decl, vis);
+ targetm.asm_out.visibility (decl, vis);
}
/* Returns 1 if the target configuration supports defining public symbols
TREE_PUBLIC (decl) = 1;
- if (TREE_CODE (decl) == VAR_DECL
- && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
- DECL_COMMON (decl) = 1;
- else if (SUPPORTS_ONE_ONLY)
+ if (SUPPORTS_ONE_ONLY)
{
#ifdef MAKE_DECL_ONE_ONLY
MAKE_DECL_ONE_ONLY (decl);
#endif
DECL_ONE_ONLY (decl) = 1;
}
+ else if (TREE_CODE (decl) == VAR_DECL
+ && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
+ DECL_COMMON (decl) = 1;
else if (SUPPORTS_WEAK)
DECL_WEAK (decl) = 1;
else
return kind;
}
- is_local = (*targetm.binds_local_p) (decl);
+ is_local = targetm.binds_local_p (decl);
if (!flag_pic)
{
if (is_local)
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)
+ flags = SECTION_CODE;
else
flags = SECTION_WRITE;
readonly = true;
}
else if (TREE_CODE (decl) == STRING_CST)
- readonly = !flag_writable_strings;
+ readonly = true;
else if (! (flag_pic && reloc))
readonly = true;
if (TREE_CODE (decl) == FUNCTION_DECL)
return SECCAT_TEXT;
else if (TREE_CODE (decl) == STRING_CST)
- {
- if (flag_writable_strings)
- return SECCAT_DATA;
- else
- return SECCAT_RODATA_MERGE_STR;
- }
+ return SECCAT_RODATA_MERGE_STR;
else if (TREE_CODE (decl) == VAR_DECL)
{
if (DECL_INITIAL (decl) == NULL
}
/* If the target uses small data sections, select it. */
- else if ((*targetm.in_small_data_p) (decl))
+ else if (targetm.in_small_data_p (decl))
{
if (ret == SECCAT_BSS)
ret = SECCAT_SBSS;
plen = strlen (prefix);
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- name = (* targetm.strip_name_encoding) (name);
+ name = targetm.strip_name_encoding (name);
nlen = strlen (name);
string = alloca (nlen + plen + 1);
flags = 0;
if (TREE_CODE (decl) == FUNCTION_DECL)
flags |= SYMBOL_FLAG_FUNCTION;
- if ((*targetm.binds_local_p) (decl))
+ if (targetm.binds_local_p (decl))
flags |= SYMBOL_FLAG_LOCAL;
- if ((*targetm.in_small_data_p) (decl))
+ 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;
}
#endif /* GLOBAL_ASM_OP */
+/* 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. */
+void
+default_emit_unwind_label (FILE * stream ATTRIBUTE_UNUSED,
+ tree decl ATTRIBUTE_UNUSED,
+ int empty ATTRIBUTE_UNUSED)
+{
+}
+
/* This is how to output an internal numbered label where PREFIX is
the class of label and LABELNO is the number within the class. */