/* Functions for generic Darwin as target machine for GNU C compiler.
Copyright (C) 1989, 1990, 1991, 1992, 1993, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008
+ 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Contributed by Apple Computer Inc.
#include "hashtab.h"
#include "df.h"
#include "debug.h"
+#include "obstack.h"
+#include "lto-streamer.h"
/* Darwin supports a feature called fix-and-continue, which is used
for rapid turn around debugging. When code is compiled with the
enum machopic_addr_class
machopic_classify_symbol (rtx sym_ref)
{
- int flags;
bool function_p;
- flags = SYMBOL_REF_FLAGS (sym_ref);
function_p = SYMBOL_REF_FUNCTION_P (sym_ref);
if (machopic_symbol_defined_p (sym_ref))
return (function_p
SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_DEFINED;
}
-static GTY(()) const char * function_base;
+/* Return either ORIG or:
-const char *
-machopic_function_base_name (void)
-{
- /* if dynamic-no-pic is on, we should not get here */
- gcc_assert (!MACHO_DYNAMIC_NO_PIC_P);
-
- if (function_base == NULL)
- function_base = ggc_alloc_string ("<pic base>", sizeof ("<pic base>"));
-
- crtl->uses_pic_offset_table = 1;
-
- return function_base;
-}
-
-/* Return a SYMBOL_REF for the PIC function base. */
+ (const:P (unspec:P [ORIG] UNSPEC_MACHOPIC_OFFSET))
+ depending on MACHO_DYNAMIC_NO_PIC_P. */
rtx
-machopic_function_base_sym (void)
-{
- rtx sym_ref;
-
- sym_ref = gen_rtx_SYMBOL_REF (Pmode, machopic_function_base_name ());
- SYMBOL_REF_FLAGS (sym_ref)
- |= (MACHO_SYMBOL_FLAG_VARIABLE | MACHO_SYMBOL_FLAG_DEFINED);
- return sym_ref;
-}
-
-/* Return either ORIG or (const:P (minus:P ORIG PIC_BASE)), depending
- on whether pic_base is NULL or not. */
-static inline rtx
-gen_pic_offset (rtx orig, rtx pic_base)
+machopic_gen_offset (rtx orig)
{
- if (!pic_base)
+ if (MACHO_DYNAMIC_NO_PIC_P)
return orig;
else
- return gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, orig, pic_base));
+ {
+ /* Play games to avoid marking the function as needing pic if we
+ are being called as part of the cost-estimation process. */
+ if (current_ir_type () != IR_GIMPLE || currently_expanding_to_rtl)
+ crtl->uses_pic_offset_table = 1;
+ orig = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig),
+ UNSPEC_MACHOPIC_OFFSET);
+ return gen_rtx_CONST (Pmode, orig);
+ }
}
static GTY(()) const char * function_base_func_name;
/* The suffix attached to stub symbols. */
#define STUB_SUFFIX "$stub"
-typedef struct machopic_indirection GTY (())
+typedef struct GTY (()) machopic_indirection
{
/* The SYMBOL_REF for the entity referenced. */
rtx symbol;
static int
machopic_indirection_eq (const void *slot, const void *key)
{
- return strcmp (((const machopic_indirection *) slot)->ptr_name, key) == 0;
+ return strcmp (((const machopic_indirection *) slot)->ptr_name,
+ (const char *) key) == 0;
}
/* Return the name of the non-lazy pointer (if STUB_P is false) or
size_t namelen = strlen (name);
machopic_indirection *p;
void ** slot;
- bool saw_star = false;
bool needs_quotes;
const char *suffix;
const char *prefix = user_label_prefix;
if (name[0] == '*')
{
- saw_star = true;
prefix = "";
++name;
--namelen;
else
suffix = NON_LAZY_POINTER_SUFFIX;
- buffer = alloca (strlen ("&L")
+ buffer = XALLOCAVEC (char, strlen ("&L")
+ strlen (prefix)
+ namelen
+ strlen (suffix)
else if (defined)
{
#if defined (TARGET_TOC) || defined (HAVE_lo_sum)
- rtx pic_base = machopic_function_base_sym ();
- rtx offset = gen_pic_offset (orig, pic_base);
+ rtx offset = machopic_gen_offset (orig);
#endif
#if defined (TARGET_TOC) /* i.e., PowerPC */
emit_insn (gen_rtx_SET (VOIDmode, reg,
gen_rtx_LO_SUM (Pmode, reg,
copy_rtx (offset))));
- emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+ emit_use (pic_offset_table_rtx);
orig = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, reg);
#endif
))
{
/* addr(foo) = &func+(foo-func) */
- rtx pic_base;
-
orig = machopic_indirect_data_reference (orig, reg);
if (GET_CODE (orig) == PLUS
return reg;
}
- /* if dynamic-no-pic we don't have a pic base */
- if (MACHO_DYNAMIC_NO_PIC_P)
- pic_base = NULL;
- else
- pic_base = machopic_function_base_sym ();
-
if (GET_CODE (orig) == MEM)
{
if (reg == 0)
if (GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (orig, 0)) == LABEL_REF)
{
- rtx offset = gen_pic_offset (XEXP (orig, 0), pic_base);
+ rtx offset = machopic_gen_offset (XEXP (orig, 0));
#if defined (TARGET_TOC) /* i.e., PowerPC */
/* Generating a new reg may expose opportunities for
common subexpression elimination. */
pic_ref = reg;
#else
- emit_insn (gen_rtx_USE (VOIDmode,
- gen_rtx_REG (Pmode,
- PIC_OFFSET_TABLE_REGNUM)));
+ emit_use (gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM));
emit_insn (gen_rtx_SET (VOIDmode, reg,
gen_rtx_HIGH (Pmode,
pic = reg;
}
#if 0
- emit_insn (gen_rtx_USE (VOIDmode,
- gen_rtx_REG (Pmode,
- PIC_OFFSET_TABLE_REGNUM)));
+ emit_use (gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM));
#endif
if (reload_in_progress)
df_set_regs_ever_live (REGNO (pic), true);
pic_ref = gen_rtx_PLUS (Pmode, pic,
- gen_pic_offset (XEXP (orig, 0),
- pic_base));
+ machopic_gen_offset (XEXP (orig, 0)));
}
#if !defined (TARGET_TOC)
if (GET_CODE (orig) == SYMBOL_REF
|| GET_CODE (orig) == LABEL_REF)
{
- rtx offset = gen_pic_offset (orig, pic_base);
+ rtx offset = machopic_gen_offset (orig);
#if defined (TARGET_TOC) /* i.e., PowerPC */
rtx hi_sum_reg;
pic = reg;
}
#if 0
- emit_insn (gen_rtx_USE (VOIDmode,
- pic_offset_table_rtx));
+ emit_use (pic_offset_table_rtx);
#endif
if (reload_in_progress)
df_set_regs_ever_live (REGNO (pic), true);
pic_ref = gen_rtx_PLUS (Pmode,
pic,
- gen_pic_offset (orig, pic_base));
+ machopic_gen_offset (orig));
}
}
}
sym_name = IDENTIFIER_POINTER (id);
}
- sym = alloca (strlen (sym_name) + 2);
+ sym = XALLOCAVEC (char, strlen (sym_name) + 2);
if (sym_name[0] == '*' || sym_name[0] == '&')
strcpy (sym, sym_name + 1);
else if (sym_name[0] == '-' || sym_name[0] == '+')
else
sprintf (sym, "%s%s", user_label_prefix, sym_name);
- stub = alloca (strlen (ptr_name) + 2);
+ stub = XALLOCAVEC (char, strlen (ptr_name) + 2);
if (ptr_name[0] == '*' || ptr_name[0] == '&')
strcpy (stub, ptr_name + 1);
else
rtx init = const0_rtx;
switch_to_section (darwin_sections[machopic_nl_symbol_ptr_section]);
+
+ /* Mach-O symbols are passed around in code through indirect
+ references and the original symbol_ref hasn't passed through
+ the generic handling and reference-catching in
+ output_operand, so we need to manually mark weak references
+ as such. */
+ if (SYMBOL_REF_WEAK (symbol))
+ {
+ tree decl = SYMBOL_REF_DECL (symbol);
+ gcc_assert (DECL_P (decl));
+
+ if (decl != NULL_TREE
+ && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl)
+ /* Handle only actual external-only definitions, not
+ e.g. extern inline code or variables for which
+ storage has been allocated. */
+ && !TREE_STATIC (decl))
+ {
+ fputs ("\t.weak_reference ", asm_out_file);
+ assemble_name (asm_out_file, sym_name);
+ fputc ('\n', asm_out_file);
+ }
+ }
+
assemble_name (asm_out_file, ptr_name);
fprintf (asm_out_file, ":\n");
machopic_operand_p (rtx op)
{
if (MACHOPIC_JUST_INDIRECT)
- {
- while (GET_CODE (op) == CONST)
- op = XEXP (op, 0);
-
- if (GET_CODE (op) == SYMBOL_REF)
- return machopic_symbol_defined_p (op);
- else
- return 0;
- }
-
- while (GET_CODE (op) == CONST)
- op = XEXP (op, 0);
-
- if (GET_CODE (op) == MINUS
- && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
- && GET_CODE (XEXP (op, 1)) == SYMBOL_REF
- && machopic_symbol_defined_p (XEXP (op, 0))
- && machopic_symbol_defined_p (XEXP (op, 1)))
- return 1;
-
- return 0;
+ return (GET_CODE (op) == SYMBOL_REF
+ && machopic_symbol_defined_p (op));
+ else
+ return (GET_CODE (op) == CONST
+ && GET_CODE (XEXP (op, 0)) == UNSPEC
+ && XINT (XEXP (op, 0), 1) == UNSPEC_MACHOPIC_OFFSET);
}
/* This function records whether a given name corresponds to a defined
{
bool weak = (DECL_P (decl)
&& DECL_WEAK (decl)
- && (lookup_attribute ("weak", DECL_ATTRIBUTES (decl))
- || ! lookup_attribute ("weak_import",
- DECL_ATTRIBUTES (decl))));
+ && !lookup_attribute ("weak_import",
+ DECL_ATTRIBUTES (decl)));
section *base_section;
switch (categorize_decl_for_section (decl, reloc))
default_globalize_label (stream, name);
}
+/* This routine returns non-zero if 'name' starts with the special objective-c
+ anonymous file-scope static name. It accommodates c++'s mangling of such
+ symbols (in this case the symbols will have form _ZL{d}*_OBJC_* d=digit). */
+
+int
+darwin_label_is_anonymous_local_objc_name (const char *name)
+{
+ const unsigned char *p = (const unsigned char *) name;
+ if (*p != '_')
+ return 0;
+ if (p[1] == 'Z' && p[2] == 'L')
+ {
+ p += 3;
+ while (*p >= '0' && *p <= '9')
+ p++;
+ }
+ return (!strncmp ((const char *)p, "_OBJC_", 6));
+}
+
+/* LTO support for Mach-O. */
+
+/* Section names for LTO sections. */
+static unsigned int lto_section_names_offset = 0;
+
+/* This is the obstack which we use to allocate the many strings. */
+static struct obstack lto_section_names_obstack;
+
+/* Segment name for LTO sections. */
+#define LTO_SEGMENT_NAME "__GNU_LTO"
+
+/* Section name for LTO section names section. */
+#define LTO_NAMES_SECTION "__section_names"
+
+/* File to temporarily store LTO data. This is appended to asm_out_file
+ in darwin_end_file. */
+static FILE *lto_asm_out_file, *saved_asm_out_file;
+static char *lto_asm_out_name;
+
+/* Prepare asm_out_file for LTO output. For darwin, this means hiding
+ asm_out_file and switching to an alternative output file. */
+void
+darwin_asm_lto_start (void)
+{
+ gcc_assert (! saved_asm_out_file);
+ saved_asm_out_file = asm_out_file;
+ if (! lto_asm_out_name)
+ lto_asm_out_name = make_temp_file (".lto.s");
+ lto_asm_out_file = fopen (lto_asm_out_name, "a");
+ if (lto_asm_out_file == NULL)
+ fatal_error ("failed to open temporary file %s for LTO output",
+ lto_asm_out_name);
+ asm_out_file = lto_asm_out_file;
+}
+
+/* Restore asm_out_file. */
+void
+darwin_asm_lto_end (void)
+{
+ gcc_assert (saved_asm_out_file);
+ fclose (lto_asm_out_file);
+ asm_out_file = saved_asm_out_file;
+ saved_asm_out_file = NULL;
+}
+
void
darwin_asm_named_section (const char *name,
- unsigned int flags ATTRIBUTE_UNUSED,
+ unsigned int flags,
tree decl ATTRIBUTE_UNUSED)
{
- fprintf (asm_out_file, "\t.section %s\n", name);
+ /* LTO sections go in a special segment __GNU_LTO. We want to replace the
+ section name with something we can use to represent arbitrary-length
+ names (section names in Mach-O are at most 16 characters long). */
+ if (strncmp (name, LTO_SECTION_NAME_PREFIX,
+ strlen (LTO_SECTION_NAME_PREFIX)) == 0)
+ {
+ /* We expect certain flags to be set... */
+ gcc_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
+ == (SECTION_DEBUG | SECTION_NAMED));
+
+ /* Add the section name to the things to output when we end the
+ current assembler output file.
+ This is all not very efficient, but that doesn't matter -- this
+ shouldn't be a hot path in the compiler... */
+ obstack_1grow (<o_section_names_obstack, '\t');
+ obstack_grow (<o_section_names_obstack, ".ascii ", 7);
+ obstack_1grow (<o_section_names_obstack, '"');
+ obstack_grow (<o_section_names_obstack, name, strlen (name));
+ obstack_grow (<o_section_names_obstack, "\\0\"\n", 4);
+
+ /* Output the dummy section name. */
+ fprintf (asm_out_file, "\t# %s\n", name);
+ fprintf (asm_out_file, "\t.section %s,__%08X,regular,debug\n",
+ LTO_SEGMENT_NAME, lto_section_names_offset);
+
+ /* Update the offset for the next section name. Make sure we stay
+ within reasonable length. */
+ lto_section_names_offset += strlen (name) + 1;
+ gcc_assert (lto_section_names_offset > 0
+ && lto_section_names_offset < ((unsigned) 1 << 31));
+ }
+ else
+ fprintf (asm_out_file, "\t.section %s\n", name);
}
void
/* APPLE KEXT stuff -- only applies with pure static C++ code. */
if (! TARGET_KEXTABI)
{
- warning (0, "%<%s%> 2.95 vtable-compatibility attribute applies "
- "only when compiling a kext", IDENTIFIER_POINTER (name));
+ warning (0, "%qE 2.95 vtable-compatibility attribute applies "
+ "only when compiling a kext", name);
*no_add_attrs = true;
}
else if (TREE_CODE (*node) != RECORD_TYPE)
{
- warning (0, "%<%s%> 2.95 vtable-compatibility attribute applies "
- "only to C++ classes", IDENTIFIER_POINTER (name));
+ warning (0, "%qE 2.95 vtable-compatibility attribute applies "
+ "only to C++ classes", name);
*no_add_attrs = true;
}
{
if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)
{
- warning (OPT_Wattributes, "%qs attribute ignored",
- IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored",
+ name);
*no_add_attrs = true;
}
else
fprintf (file, "\n\t%s L$set$%d", directive, darwin_dwarf_label_counter++);
}
-/* Output labels for the start of the DWARF sections if necessary. */
+/* Output labels for the start of the DWARF sections if necessary.
+ Initialize the stuff we need for LTO long section names support. */
void
darwin_file_start (void)
{
fprintf (asm_out_file, "Lsection%.*s:\n", namelen, debugnames[i] + 8);
}
}
+
+ /* We fill this obstack with the complete section text for the lto section
+ names to write in darwin_file_end. */
+ obstack_init (<o_section_names_obstack);
+ lto_section_names_offset = 0;
}
/* Output an offset in a DWARF section on Darwin. On Darwin, DWARF section
void
darwin_file_end (void)
{
+ const char *lto_section_names;
+
machopic_finish (asm_out_file);
if (strcmp (lang_hooks.name, "GNU C++") == 0)
{
switch_to_section (darwin_sections[destructor_section]);
ASM_OUTPUT_ALIGN (asm_out_file, 1);
}
+
+ /* If there was LTO assembler output, append it to asm_out_file. */
+ if (lto_asm_out_name)
+ {
+ int n;
+ char *buf, *lto_asm_txt;
+
+ /* Shouldn't be here if we failed to switch back. */
+ gcc_assert (! saved_asm_out_file);
+
+ lto_asm_out_file = fopen (lto_asm_out_name, "r");
+ if (lto_asm_out_file == NULL)
+ fatal_error ("failed to open temporary file %s with LTO output",
+ lto_asm_out_name);
+ fseek (lto_asm_out_file, 0, SEEK_END);
+ n = ftell (lto_asm_out_file);
+ if (n > 0)
+ {
+ fseek (lto_asm_out_file, 0, SEEK_SET);
+ lto_asm_txt = buf = (char *) xmalloc (n + 1);
+ while (fgets (lto_asm_txt, n, lto_asm_out_file))
+ fputs (lto_asm_txt, asm_out_file);
+ }
+
+ /* Remove the temporary file. */
+ fclose (lto_asm_out_file);
+ unlink_if_ordinary (lto_asm_out_name);
+ free (lto_asm_out_name);
+ }
+
+ /* Finish the LTO section names obstack. Don't output anything if
+ there are no recorded section names. */
+ obstack_1grow (<o_section_names_obstack, '\0');
+ lto_section_names = XOBFINISH (<o_section_names_obstack, const char *);
+ if (strlen (lto_section_names) > 0)
+ {
+ fprintf (asm_out_file,
+ "\t.section %s,%s,regular,debug\n",
+ LTO_SEGMENT_NAME, LTO_NAMES_SECTION);
+ fprintf (asm_out_file,
+ "\t# Section names in %s are offsets into this table\n",
+ LTO_SEGMENT_NAME);
+ fprintf (asm_out_file, "%s\n", lto_section_names);
+ }
+ obstack_free (<o_section_names_obstack, NULL);
+
fprintf (asm_out_file, "\t.subsections_via_symbols\n");
}
void
darwin_override_options (void)
{
+ /* Don't emit DWARF3/4 unless specifically selected. This is a
+ workaround for tool bugs. */
+ if (dwarf_strict < 0)
+ dwarf_strict = 1;
+
+ /* Disable -freorder-blocks-and-partition for darwin_emit_unwind_label. */
+ if (flag_reorder_blocks_and_partition
+ && (targetm.asm_out.unwind_label == darwin_emit_unwind_label))
+ {
+ inform (input_location,
+ "-freorder-blocks-and-partition does not work with exceptions "
+ "on this architecture");
+ flag_reorder_blocks_and_partition = 0;
+ flag_reorder_blocks = 1;
+ }
+
if (flag_mkernel || flag_apple_kext)
{
/* -mkernel implies -fapple-kext for C++ */