OSDN Git Service

Revert:
[pf3gnuchains/gcc-fork.git] / gcc / config / darwin.c
index e486594..6c63d7a 100644 (file)
@@ -1,6 +1,6 @@
 /* Functions for generic Darwin as target machine for GNU C compiler.
    Copyright (C) 1989, 1990, 1991, 1992, 1993, 2000, 2001, 2002, 2003, 2004,
-   2005
+   2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Apple Computer Inc.
 
@@ -8,7 +8,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -17,9 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -45,6 +44,10 @@ Boston, MA 02110-1301, USA.  */
 #include "tm_p.h"
 #include "toplev.h"
 #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
@@ -187,10 +190,8 @@ machopic_symbol_defined_p (rtx sym_ref)
 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
@@ -220,7 +221,8 @@ indirect_data (rtx sym_ref)
   int lprefix;
   const char *name;
 
-  /* If we aren't generating fix-and-continue code, don't do anything special.  */
+  /* If we aren't generating fix-and-continue code, don't do anything
+     special.  */
   if (TARGET_FIX_AND_CONTINUE == 0)
     return 0;
 
@@ -265,45 +267,26 @@ machopic_define_symbol (rtx mem)
   SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_DEFINED;
 }
 
-static GTY(()) 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 =
-      (char *) ggc_alloc_string ("<pic base>", sizeof ("<pic base>"));
-
-  current_function_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;
@@ -331,7 +314,7 @@ machopic_output_function_base_name (FILE *file)
 /* 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;
@@ -365,7 +348,8 @@ machopic_indirection_hash (const void *slot)
 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
@@ -379,7 +363,6 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
   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;
@@ -402,7 +385,6 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
 
   if (name[0] == '*')
     {
-      saw_star = true;
       prefix = "";
       ++name;
       --namelen;
@@ -419,7 +401,7 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
   else
     suffix = NON_LAZY_POINTER_SUFFIX;
 
-  buffer = alloca (strlen ("&L")
+  buffer = XALLOCAVEC (char, strlen ("&L")
                   + strlen (prefix)
                   + namelen
                   + strlen (suffix)
@@ -514,7 +496,7 @@ machopic_indirect_data_reference (rtx orig, rtx reg)
        {
 #if defined (TARGET_TOC)
          /* Create a new register for CSE opportunities.  */
-         rtx hi_reg = (no_new_pseudos ? reg : gen_reg_rtx (Pmode));
+         rtx hi_reg = (!can_create_pseudo_p () ? reg : gen_reg_rtx (Pmode));
          emit_insn (gen_macho_high (hi_reg, orig));
          emit_insn (gen_macho_low (reg, hi_reg, orig));
 #else
@@ -526,12 +508,13 @@ machopic_indirect_data_reference (rtx orig, rtx reg)
       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 */
-         rtx hi_sum_reg = (no_new_pseudos ? reg : gen_reg_rtx (Pmode));
+         rtx hi_sum_reg = (!can_create_pseudo_p ()
+                           ? reg
+                           : gen_reg_rtx (Pmode));
 
          gcc_assert (reg);
 
@@ -539,7 +522,8 @@ machopic_indirect_data_reference (rtx orig, rtx reg)
                              gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
                                       gen_rtx_HIGH (Pmode, offset))));
          emit_insn (gen_rtx_SET (Pmode, reg,
-                                 gen_rtx_LO_SUM (Pmode, hi_sum_reg, offset)));
+                                 gen_rtx_LO_SUM (Pmode, hi_sum_reg,
+                                                 copy_rtx (offset))));
 
          orig = reg;
 #else
@@ -549,8 +533,9 @@ machopic_indirect_data_reference (rtx orig, rtx reg)
          emit_insn (gen_rtx_SET (VOIDmode, reg,
                                  gen_rtx_HIGH (Pmode, offset)));
          emit_insn (gen_rtx_SET (VOIDmode, reg,
-                                 gen_rtx_LO_SUM (Pmode, reg, offset)));
-         emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+                                 gen_rtx_LO_SUM (Pmode, reg,
+                                                 copy_rtx (offset))));
+         emit_use (pic_offset_table_rtx);
 
          orig = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, reg);
 #endif
@@ -669,8 +654,6 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
          ))
     {
       /* addr(foo) = &func+(foo-func) */
-      rtx pic_base;
-
       orig = machopic_indirect_data_reference (orig, reg);
 
       if (GET_CODE (orig) == PLUS
@@ -683,12 +666,6 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
          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)
@@ -703,16 +680,20 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
                  || GET_CODE (XEXP (orig, 0)) == LABEL_REF))
            {
 #if defined (TARGET_TOC)       /* ppc  */
-             rtx temp_reg = (no_new_pseudos) ? reg : gen_reg_rtx (Pmode);
+             rtx temp_reg = (!can_create_pseudo_p ()
+                             ? reg :
+                             gen_reg_rtx (Pmode));
              rtx asym = XEXP (orig, 0);
              rtx mem;
 
              emit_insn (gen_macho_high (temp_reg, asym));
              mem = gen_const_mem (GET_MODE (orig),
-                                  gen_rtx_LO_SUM (Pmode, temp_reg, asym));
+                                  gen_rtx_LO_SUM (Pmode, temp_reg,
+                                                  copy_rtx (asym)));
              emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
 #else
-             /* Some other CPU -- WriteMe! but right now there are no other platform that can use dynamic-no-pic  */
+             /* Some other CPU -- WriteMe! but right now there are no other
+                platforms that can use dynamic-no-pic  */
              gcc_unreachable ();
 #endif
              pic_ref = reg;
@@ -721,11 +702,13 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
          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.  */
-              rtx hi_sum_reg = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
+              rtx hi_sum_reg = (!can_create_pseudo_p ()
+                               ? reg
+                               : gen_reg_rtx (Pmode));
              rtx mem;
              rtx insn;
              rtx sum;
@@ -738,16 +721,14 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
 
              mem = gen_const_mem (GET_MODE (orig),
                                  gen_rtx_LO_SUM (Pmode,
-                                                 hi_sum_reg, offset));
+                                                 hi_sum_reg,
+                                                 copy_rtx (offset)));
              insn = emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
-             REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, pic_ref,
-                                                   REG_NOTES (insn));
+             set_unique_reg_note (insn, REG_EQUAL, pic_ref);
 
              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,
@@ -755,7 +736,8 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
                                                                   offset))));
              emit_insn (gen_rtx_SET (VOIDmode, reg,
                                  gen_rtx_LO_SUM (Pmode, reg,
-                                          gen_rtx_CONST (Pmode, offset))));
+                                          gen_rtx_CONST (Pmode,
+                                                         copy_rtx (offset)))));
              pic_ref = gen_rtx_PLUS (Pmode,
                                      pic_offset_table_rtx, reg);
 #endif
@@ -770,16 +752,13 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
                  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)
-               regs_ever_live[REGNO (pic)] = 1;
+               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)
@@ -794,7 +773,7 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
          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;
 
@@ -815,13 +794,15 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
                                                                    offset))));
              emit_insn (gen_rtx_SET (VOIDmode, reg,
                                      gen_rtx_LO_SUM (Pmode,
-                                                     hi_sum_reg, offset)));
+                                                     hi_sum_reg,
+                                                     copy_rtx (offset))));
              pic_ref = reg;
 #else
              emit_insn (gen_rtx_SET (VOIDmode, reg,
                                      gen_rtx_HIGH (Pmode, offset)));
              emit_insn (gen_rtx_SET (VOIDmode, reg,
-                                     gen_rtx_LO_SUM (Pmode, reg, offset)));
+                                     gen_rtx_LO_SUM (Pmode, reg,
+                                                     copy_rtx (offset))));
              pic_ref = gen_rtx_PLUS (Pmode,
                                      pic_offset_table_rtx, reg);
 #endif
@@ -843,14 +824,13 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx 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)
-                   regs_ever_live[REGNO (pic)] = 1;
+                   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));
                }
            }
        }
@@ -960,7 +940,7 @@ machopic_output_indirection (void **slot, void *data)
            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] == '+')
@@ -968,7 +948,7 @@ machopic_output_indirection (void **slot, void *data)
       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
@@ -992,6 +972,30 @@ machopic_output_indirection (void **slot, void *data)
       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");
 
@@ -1030,27 +1034,12 @@ int
 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
@@ -1093,135 +1082,226 @@ darwin_mark_decl_preserved (const char *name)
   fputc ('\n', asm_out_file);
 }
 
-section *
-machopic_select_section (tree exp, int reloc,
-                        unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
+static section *
+darwin_text_section (int reloc, int weak)
 {
-  section *base_section;
-  bool weak_p = (DECL_P (exp) && DECL_WEAK (exp)
-                && (lookup_attribute ("weak", DECL_ATTRIBUTES (exp))
-                    || ! lookup_attribute ("weak_import",
-                                           DECL_ATTRIBUTES (exp))));
-
-  if (TREE_CODE (exp) == FUNCTION_DECL)
-    {
-      if (reloc == 1)
-       base_section = (weak_p
-                       ? darwin_sections[text_unlikely_coal_section]
-                       : unlikely_text_section ());
-      else
-       base_section = weak_p ? darwin_sections[text_coal_section] : text_section;
-    }
-  else if (decl_readonly_section_1 (exp, reloc, MACHOPIC_INDIRECT))
-    base_section = weak_p ? darwin_sections[const_coal_section] : darwin_sections[const_section];
-  else if (TREE_READONLY (exp) || TREE_CONSTANT (exp))
-    base_section = weak_p ? darwin_sections[const_data_coal_section] : darwin_sections[const_data_section];
+  if (reloc)
+    return (weak
+           ? darwin_sections[text_unlikely_coal_section]
+           : unlikely_text_section ());
   else
-    base_section = weak_p ? darwin_sections[data_coal_section] : data_section;
+    return (weak
+           ? darwin_sections[text_coal_section]
+           : text_section);
+}
+
+static section *
+darwin_rodata_section (int weak)
+{
+  return (weak
+         ? darwin_sections[const_coal_section]
+         : darwin_sections[const_section]);
+}
 
-  if (TREE_CODE (exp) == STRING_CST
+static section *
+darwin_mergeable_string_section (tree exp,
+                                unsigned HOST_WIDE_INT align)
+{
+  if (flag_merge_constants
+      && TREE_CODE (exp) == STRING_CST
+      && TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
+      && align <= 256
+      && (int_size_in_bytes (TREE_TYPE (exp))
+         == TREE_STRING_LENGTH (exp))
       && ((size_t) TREE_STRING_LENGTH (exp)
          == strlen (TREE_STRING_POINTER (exp)) + 1))
     return darwin_sections[cstring_section];
-  else if ((TREE_CODE (exp) == INTEGER_CST || TREE_CODE (exp) == REAL_CST)
-          && flag_merge_constants)
+
+  return readonly_data_section;
+}
+
+#ifndef HAVE_GAS_LITERAL16
+#define HAVE_GAS_LITERAL16 0
+#endif
+
+static section *
+darwin_mergeable_constant_section (tree exp,
+                                  unsigned HOST_WIDE_INT align)
+{
+  enum machine_mode mode = DECL_MODE (exp);
+  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)
     {
       tree size = TYPE_SIZE_UNIT (TREE_TYPE (exp));
 
-      if (TREE_CODE (size) == INTEGER_CST &&
-         TREE_INT_CST_LOW (size) == 4 &&
-         TREE_INT_CST_HIGH (size) == 0)
-       return darwin_sections[literal4_section];
-      else if (TREE_CODE (size) == INTEGER_CST &&
-              TREE_INT_CST_LOW (size) == 8 &&
-              TREE_INT_CST_HIGH (size) == 0)
-       return darwin_sections[literal8_section];
-      else if (TARGET_64BIT
-              && TREE_CODE (size) == INTEGER_CST
-              && TREE_INT_CST_LOW (size) == 16
+      if (TREE_CODE (size) == INTEGER_CST
+         && TREE_INT_CST_LOW (size) == 4
+         && TREE_INT_CST_HIGH (size) == 0)
+        return darwin_sections[literal4_section];
+      else if (TREE_CODE (size) == INTEGER_CST
+              && TREE_INT_CST_LOW (size) == 8
               && TREE_INT_CST_HIGH (size) == 0)
-       return darwin_sections[literal16_section];
+        return darwin_sections[literal8_section];
+      else if (HAVE_GAS_LITERAL16
+              && TARGET_64BIT
+               && TREE_CODE (size) == INTEGER_CST
+               && TREE_INT_CST_LOW (size) == 16
+               && TREE_INT_CST_HIGH (size) == 0)
+        return darwin_sections[literal16_section];
       else
-       return base_section;
+        return readonly_data_section;
     }
-  else if (TREE_CODE (exp) == CONSTRUCTOR
-          && TREE_TYPE (exp)
-          && TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
-          && TYPE_NAME (TREE_TYPE (exp)))
+
+  return readonly_data_section;
+}
+
+int
+machopic_reloc_rw_mask (void)
+{
+  return MACHOPIC_INDIRECT ? 3 : 0;
+}
+
+section *
+machopic_select_section (tree decl,
+                        int reloc,
+                        unsigned HOST_WIDE_INT align)
+{
+  bool weak = (DECL_P (decl)
+              && DECL_WEAK (decl)
+              && !lookup_attribute ("weak_import",
+                                    DECL_ATTRIBUTES (decl)));
+  section *base_section;
+
+  switch (categorize_decl_for_section (decl, reloc))
     {
-      tree name = TYPE_NAME (TREE_TYPE (exp));
+    case SECCAT_TEXT:
+      base_section = darwin_text_section (reloc, weak);
+      break;
+
+    case SECCAT_RODATA:
+    case SECCAT_SRODATA:
+      base_section = darwin_rodata_section (weak);
+      break;
+
+    case SECCAT_RODATA_MERGE_STR:
+      base_section = darwin_mergeable_string_section (decl, align);
+      break;
+
+    case SECCAT_RODATA_MERGE_STR_INIT:
+      base_section = darwin_mergeable_string_section (DECL_INITIAL (decl), align);
+      break;
+
+    case SECCAT_RODATA_MERGE_CONST:
+      base_section =  darwin_mergeable_constant_section (decl, align);
+      break;
+
+    case SECCAT_DATA:
+    case SECCAT_DATA_REL:
+    case SECCAT_DATA_REL_LOCAL:
+    case SECCAT_DATA_REL_RO:
+    case SECCAT_DATA_REL_RO_LOCAL:
+    case SECCAT_SDATA:
+    case SECCAT_TDATA:
+    case SECCAT_BSS:
+    case SECCAT_SBSS:
+    case SECCAT_TBSS:
+      if (TREE_READONLY (decl) || TREE_CONSTANT (decl))
+       base_section = weak ? darwin_sections[const_data_coal_section]
+                           : darwin_sections[const_data_section];
+      else
+       base_section = weak ? darwin_sections[data_coal_section] : data_section;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  /* Darwin weird special cases.  */
+  if (TREE_CODE (decl) == CONSTRUCTOR
+      && TREE_TYPE (decl)
+      && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+      && TYPE_NAME (TREE_TYPE (decl)))
+    {
+      tree name = TYPE_NAME (TREE_TYPE (decl));
       if (TREE_CODE (name) == TYPE_DECL)
-       name = DECL_NAME (name);
+        name = DECL_NAME (name);
 
       if (!strcmp (IDENTIFIER_POINTER (name), "__builtin_ObjCString"))
-       {
-         if (flag_next_runtime)
-           return darwin_sections[objc_constant_string_object_section];
-         else
-           return darwin_sections[objc_string_object_section];
-       }
+        {
+          if (flag_next_runtime)
+            return darwin_sections[objc_constant_string_object_section];
+          else
+            return darwin_sections[objc_string_object_section];
+        }
       else
-       return base_section;
+        return base_section;
     }
-  else if (TREE_CODE (exp) == VAR_DECL &&
-          DECL_NAME (exp) &&
-          TREE_CODE (DECL_NAME (exp)) == IDENTIFIER_NODE &&
-          IDENTIFIER_POINTER (DECL_NAME (exp)) &&
-          !strncmp (IDENTIFIER_POINTER (DECL_NAME (exp)), "_OBJC_", 6))
+  else if (TREE_CODE (decl) == VAR_DECL
+          && DECL_NAME (decl)
+          && TREE_CODE (DECL_NAME (decl)) == IDENTIFIER_NODE
+          && IDENTIFIER_POINTER (DECL_NAME (decl))
+          && !strncmp (IDENTIFIER_POINTER (DECL_NAME (decl)), "_OBJC_", 6))
     {
-      const char *name = IDENTIFIER_POINTER (DECL_NAME (exp));
+      const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
 
       if (!strncmp (name, "_OBJC_CLASS_METHODS_", 20))
-       return darwin_sections[objc_cls_meth_section];
+        return darwin_sections[objc_cls_meth_section];
       else if (!strncmp (name, "_OBJC_INSTANCE_METHODS_", 23))
-       return darwin_sections[objc_inst_meth_section];
+        return darwin_sections[objc_inst_meth_section];
       else if (!strncmp (name, "_OBJC_CATEGORY_CLASS_METHODS_", 20))
-       return darwin_sections[objc_cat_cls_meth_section];
+        return darwin_sections[objc_cat_cls_meth_section];
       else if (!strncmp (name, "_OBJC_CATEGORY_INSTANCE_METHODS_", 23))
-       return darwin_sections[objc_cat_inst_meth_section];
+        return darwin_sections[objc_cat_inst_meth_section];
       else if (!strncmp (name, "_OBJC_CLASS_VARIABLES_", 22))
-       return darwin_sections[objc_class_vars_section];
+        return darwin_sections[objc_class_vars_section];
       else if (!strncmp (name, "_OBJC_INSTANCE_VARIABLES_", 25))
-       return darwin_sections[objc_instance_vars_section];
+        return darwin_sections[objc_instance_vars_section];
       else if (!strncmp (name, "_OBJC_CLASS_PROTOCOLS_", 22))
-       return darwin_sections[objc_cat_cls_meth_section];
+        return darwin_sections[objc_cat_cls_meth_section];
       else if (!strncmp (name, "_OBJC_CLASS_NAME_", 17))
-       return darwin_sections[objc_class_names_section];
+        return darwin_sections[objc_class_names_section];
       else if (!strncmp (name, "_OBJC_METH_VAR_NAME_", 20))
-       return darwin_sections[objc_meth_var_names_section];
+        return darwin_sections[objc_meth_var_names_section];
       else if (!strncmp (name, "_OBJC_METH_VAR_TYPE_", 20))
-       return darwin_sections[objc_meth_var_types_section];
+        return darwin_sections[objc_meth_var_types_section];
       else if (!strncmp (name, "_OBJC_CLASS_REFERENCES", 22))
-       return darwin_sections[objc_cls_refs_section];
+        return darwin_sections[objc_cls_refs_section];
       else if (!strncmp (name, "_OBJC_CLASS_", 12))
-       return darwin_sections[objc_class_section];
+        return darwin_sections[objc_class_section];
       else if (!strncmp (name, "_OBJC_METACLASS_", 16))
-       return darwin_sections[objc_meta_class_section];
+        return darwin_sections[objc_meta_class_section];
       else if (!strncmp (name, "_OBJC_CATEGORY_", 15))
-       return darwin_sections[objc_category_section];
+        return darwin_sections[objc_category_section];
       else if (!strncmp (name, "_OBJC_SELECTOR_REFERENCES", 25))
-       return darwin_sections[objc_selector_refs_section];
+        return darwin_sections[objc_selector_refs_section];
       else if (!strncmp (name, "_OBJC_SELECTOR_FIXUP", 20))
-       return darwin_sections[objc_selector_fixup_section];
+        return darwin_sections[objc_selector_fixup_section];
       else if (!strncmp (name, "_OBJC_SYMBOLS", 13))
-       return darwin_sections[objc_symbols_section];
+        return darwin_sections[objc_symbols_section];
       else if (!strncmp (name, "_OBJC_MODULES", 13))
-       return darwin_sections[objc_module_info_section];
+        return darwin_sections[objc_module_info_section];
       else if (!strncmp (name, "_OBJC_IMAGE_INFO", 16))
-       return darwin_sections[objc_image_info_section];
+        return darwin_sections[objc_image_info_section];
       else if (!strncmp (name, "_OBJC_PROTOCOL_INSTANCE_METHODS_", 32))
-       return darwin_sections[objc_cat_inst_meth_section];
+        return darwin_sections[objc_cat_inst_meth_section];
       else if (!strncmp (name, "_OBJC_PROTOCOL_CLASS_METHODS_", 29))
-       return darwin_sections[objc_cat_cls_meth_section];
+        return darwin_sections[objc_cat_cls_meth_section];
       else if (!strncmp (name, "_OBJC_PROTOCOL_REFS_", 20))
-       return darwin_sections[objc_cat_cls_meth_section];
+        return darwin_sections[objc_cat_cls_meth_section];
       else if (!strncmp (name, "_OBJC_PROTOCOL_", 15))
-       return darwin_sections[objc_protocol_section];
+        return darwin_sections[objc_protocol_section];
       else
-       return base_section;
+        return base_section;
     }
-  else
-    return base_section;
+
+  return base_section;
 }
 
 /* This can be called with address expressions as "rtx".
@@ -1239,7 +1319,8 @@ machopic_select_rtx_section (enum machine_mode mode, rtx x,
           && (GET_CODE (x) == CONST_INT
               || GET_CODE (x) == CONST_DOUBLE))
     return darwin_sections[literal4_section];
-  else if (TARGET_64BIT
+  else if (HAVE_GAS_LITERAL16
+          && TARGET_64BIT
           && GET_MODE_SIZE (mode) == 16
           && (GET_CODE (x) == CONST_INT
               || GET_CODE (x) == CONST_DOUBLE
@@ -1289,12 +1370,108 @@ darwin_globalize_label (FILE *stream, const char *name)
     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 (&lto_section_names_obstack, '\t');
+      obstack_grow (&lto_section_names_obstack, ".ascii ", 7);
+      obstack_1grow (&lto_section_names_obstack, '"');
+      obstack_grow (&lto_section_names_obstack, name, strlen (name));
+      obstack_grow (&lto_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
@@ -1303,6 +1480,42 @@ darwin_unique_section (tree decl ATTRIBUTE_UNUSED, int reloc ATTRIBUTE_UNUSED)
   /* Darwin does not use unique sections.  */
 }
 
+/* Handle __attribute__ ((apple_kext_compatibility)).
+   This only applies to darwin kexts for 2.95 compatibility -- it shrinks the
+   vtable for classes with this attribute (and their descendants) by not
+   outputting the new 3.0 nondeleting destructor.  This means that such
+   objects CANNOT be allocated on the stack or as globals UNLESS they have
+   a completely empty `operator delete'.
+   Luckily, this fits in with the Darwin kext model.
+
+   This attribute also disables gcc3's potential overlaying of derived
+   class data members on the padding at the end of the base class.  */
+
+tree
+darwin_handle_kext_attribute (tree *node, tree name,
+                             tree args ATTRIBUTE_UNUSED,
+                             int flags ATTRIBUTE_UNUSED,
+                             bool *no_add_attrs)
+{
+  /* APPLE KEXT stuff -- only applies with pure static C++ code.  */
+  if (! TARGET_KEXTABI)
+    {
+      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, "%qE 2.95 vtable-compatibility attribute applies "
+              "only to C++ classes", name);
+
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "weak_import" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -1314,8 +1527,8 @@ darwin_handle_weak_import_attribute (tree *node, tree name,
 {
   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
@@ -1324,12 +1537,6 @@ darwin_handle_weak_import_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
-static void
-no_dead_strip (FILE *file, const char *lab)
-{
-  fprintf (file, ".no_dead_strip %s\n", lab);
-}
-
 /* Emit a label for an FDE, making it global and/or weak if appropriate.
    The third parameter is nonzero if this is for exception handling.
    The fourth parameter is nonzero if this is just a placeholder for an
@@ -1338,43 +1545,44 @@ no_dead_strip (FILE *file, const char *lab)
 void
 darwin_emit_unwind_label (FILE *file, tree decl, int for_eh, int empty)
 {
-  tree id = DECL_ASSEMBLER_NAME (decl)
-    ? DECL_ASSEMBLER_NAME (decl)
-    : DECL_NAME (decl);
-
-  const char *base = IDENTIFIER_POINTER (id);
-
-  bool need_quotes = name_needs_quotes (base);
   char *lab;
 
   if (! for_eh)
     return;
 
-  lab = concat (need_quotes ? "\"" : "", user_label_prefix, base, ".eh",
-               need_quotes ? "\"" : "", NULL);
+  lab = concat (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), ".eh", NULL);
 
   if (TREE_PUBLIC (decl))
-    fprintf (file, "\t%s %s\n",
-            (DECL_VISIBILITY (decl) != VISIBILITY_HIDDEN
-             ? ".globl"
-             : ".private_extern"),
-            lab);
+    {
+      targetm.asm_out.globalize_label (file, lab);
+      if (DECL_VISIBILITY (decl) == VISIBILITY_HIDDEN)
+       {
+         fputs ("\t.private_extern ", file);
+         assemble_name (file, lab);
+         fputc ('\n', file);
+       }
+    }
 
   if (DECL_WEAK (decl))
-    fprintf (file, "\t.weak_definition %s\n", lab);
+    {
+      fputs ("\t.weak_definition ", file);
+      assemble_name (file, lab);
+      fputc ('\n', file);
+    }
 
+  assemble_name (file, lab);
   if (empty)
     {
-      fprintf (file, "%s = 0\n", lab);
+      fputs (" = 0\n", file);
 
       /* Mark the absolute .eh and .eh1 style labels as needed to
         ensure that we don't dead code strip them and keep such
         labels from another instantiation point until we can fix this
         properly with group comdat support.  */
-      no_dead_strip (file, lab);
+      darwin_mark_decl_preserved (lab);
     }
   else
-    fprintf (file, "%s:\n", lab);
+    fputs (":\n", file);
 
   free (lab);
 }
@@ -1456,7 +1664,8 @@ darwin_asm_output_dwarf_delta (FILE *file, int size,
     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)
 {
@@ -1472,6 +1681,7 @@ darwin_file_start (void)
          DEBUG_LINE_SECTION,
          DEBUG_LOC_SECTION,
          DEBUG_PUBNAMES_SECTION,
+         DEBUG_PUBTYPES_SECTION,
          DEBUG_STR_SECTION,
          DEBUG_RANGES_SECTION
        };
@@ -1490,6 +1700,11 @@ 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 (&lto_section_names_obstack);
+  lto_section_names_offset = 0;
 }
 
 /* Output an offset in a DWARF section on Darwin.  On Darwin, DWARF section
@@ -1516,6 +1731,8 @@ darwin_asm_output_dwarf_offset (FILE *file, int size, const char * lab,
 void
 darwin_file_end (void)
 {
+  const char *lto_section_names;
+
   machopic_finish (asm_out_file);
   if (strcmp (lang_hooks.name, "GNU C++") == 0)
     {
@@ -1523,16 +1740,66 @@ darwin_file_end (void)
       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 (&lto_section_names_obstack, '\0');
+  lto_section_names = XOBFINISH (&lto_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 (&lto_section_names_obstack, NULL);
+
   fprintf (asm_out_file, "\t.subsections_via_symbols\n");
 }
 
+/* TODO: Add a language hook for identifying if a decl is a vtable.  */
+#define DARWIN_VTABLE_P(DECL) 0
+
 /* Cross-module name binding.  Darwin does not support overriding
-   functions at dynamic-link time.  */
+   functions at dynamic-link time, except for vtables in kexts.  */
 
 bool
-darwin_binds_local_p (tree decl)
+darwin_binds_local_p (const_tree decl)
 {
-  return default_binds_local_p_1 (decl, 0);
+  return default_binds_local_p_1 (decl,
+                                 TARGET_KEXTABI && DARWIN_VTABLE_P (decl));
 }
 
 #if 0
@@ -1562,4 +1829,93 @@ darwin_set_default_type_attributes (tree type)
                                         TYPE_ATTRIBUTES (type));
 }
 
+/* True, iff we're generating code for loadable kernel extensions.  */
+
+bool
+darwin_kextabi_p (void) {
+  return flag_apple_kext;
+}
+
+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++ */
+      if (strcmp (lang_hooks.name, "GNU C++") == 0)
+       flag_apple_kext = 1;
+
+      flag_no_common = 1;
+
+      /* No EH in kexts.  */
+      flag_exceptions = 0;
+      /* No -fnon-call-exceptions data in kexts.  */
+      flag_non_call_exceptions = 0;
+    }
+  if (flag_var_tracking
+      && strverscmp (darwin_macosx_version_min, "10.5") >= 0
+      && debug_info_level >= DINFO_LEVEL_NORMAL
+      && debug_hooks->var_location != do_nothing_debug_hooks.var_location)
+    flag_var_tracking_uninit = 1;
+}
+
+/* Add $LDBL128 suffix to long double builtins.  */
+
+static void
+darwin_patch_builtin (int fncode)
+{
+  tree fn = built_in_decls[fncode];
+  tree sym;
+  char *newname;
+
+  if (!fn)
+    return;
+
+  sym = DECL_ASSEMBLER_NAME (fn);
+  newname = ACONCAT (("_", IDENTIFIER_POINTER (sym), "$LDBL128", NULL));
+
+  set_user_assembler_name (fn, newname);
+
+  fn = implicit_built_in_decls[fncode];
+  if (fn)
+    set_user_assembler_name (fn, newname);
+}
+
+void
+darwin_patch_builtins (void)
+{
+  if (LONG_DOUBLE_TYPE_SIZE != 128)
+    return;
+
+#define PATCH_BUILTIN(fncode) darwin_patch_builtin (fncode);
+#define PATCH_BUILTIN_NO64(fncode)             \
+  if (!TARGET_64BIT)                           \
+    darwin_patch_builtin (fncode);
+#define PATCH_BUILTIN_VARIADIC(fncode)                           \
+  if (!TARGET_64BIT                                              \
+      && (strverscmp (darwin_macosx_version_min, "10.3.9") >= 0)) \
+    darwin_patch_builtin (fncode);
+#include "darwin-ppc-ldouble-patch.def"
+#undef PATCH_BUILTIN
+#undef PATCH_BUILTIN_NO64
+#undef PATCH_BUILTIN_VARIADIC
+}
+
+
 #include "gt-darwin.h"