summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/config/darwin.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2002-02-01 18:16:02 +0000
committerobrien <obrien@FreeBSD.org>2002-02-01 18:16:02 +0000
commitc9ab9ae440a8066b2c2b85b157b1fdadcf09916a (patch)
tree086d9d6c8fbd4fc8fe4495059332f66bc0f8d12b /contrib/gcc/config/darwin.c
parent2ecfd8bd04b63f335c1ec6295740a4bfd97a4fa6 (diff)
downloadFreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.zip
FreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.tar.gz
Enlist the FreeBSD-CURRENT users as testers of what is to become Gcc 3.1.0.
These bits are taken from the FSF anoncvs repo on 1-Feb-2002 08:20 PST.
Diffstat (limited to 'contrib/gcc/config/darwin.c')
-rw-r--r--contrib/gcc/config/darwin.c1141
1 files changed, 1141 insertions, 0 deletions
diff --git a/contrib/gcc/config/darwin.c b/contrib/gcc/config/darwin.c
new file mode 100644
index 0000000..6864f0c
--- /dev/null
+++ b/contrib/gcc/config/darwin.c
@@ -0,0 +1,1141 @@
+/* Functions for generic Darwin as target machine for GNU C compiler.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993, 2000, 2001
+ Free Software Foundation, Inc.
+ Contributed by Apple Computer Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-flags.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "tree.h"
+#include "expr.h"
+#include "reload.h"
+#include "function.h"
+#include "ggc.h"
+#include "langhooks.h"
+
+#include "darwin-protos.h"
+
+extern void machopic_output_stub PARAMS ((FILE *, const char *, const char *));
+
+static int machopic_data_defined_p PARAMS ((const char *));
+static int func_name_maybe_scoped PARAMS ((const char *));
+static void update_non_lazy_ptrs PARAMS ((const char *));
+static void update_stubs PARAMS ((const char *));
+
+int
+name_needs_quotes (name)
+ const char *name;
+{
+ int c;
+ while ((c = *name++) != '\0')
+ if (! ISIDNUM (c))
+ return 1;
+ return 0;
+}
+
+/*
+ * flag_pic = 1 ... generate only indirections
+ * flag_pic = 2 ... generate indirections and pure code
+ */
+
+/* This module assumes that (const (symbol_ref "foo")) is a legal pic
+ reference, which will not be changed. */
+
+static tree machopic_defined_list;
+
+enum machopic_addr_class
+machopic_classify_ident (ident)
+ tree ident;
+{
+ const char *name = IDENTIFIER_POINTER (ident);
+ int lprefix = (((name[0] == '*' || name[0] == '&')
+ && (name[1] == 'L' || (name[1] == '"' && name[2] == 'L')))
+ || ( name[0] == '_'
+ && name[1] == 'O'
+ && name[2] == 'B'
+ && name[3] == 'J'
+ && name[4] == 'C'
+ && name[5] == '_'));
+ tree temp;
+
+ if (name[0] != '!')
+ {
+ /* Here if no special encoding to be found. */
+ if (lprefix)
+ {
+ const char *name = IDENTIFIER_POINTER (ident);
+ int len = strlen (name);
+
+ if ((len > 5 && !strcmp (name + len - 5, "$stub"))
+ || (len > 6 && !strcmp (name + len - 6, "$stub\"")))
+ return MACHOPIC_DEFINED_FUNCTION;
+ return MACHOPIC_DEFINED_DATA;
+ }
+
+ for (temp = machopic_defined_list;
+ temp != NULL_TREE;
+ temp = TREE_CHAIN (temp))
+ {
+ if (ident == TREE_VALUE (temp))
+ return MACHOPIC_DEFINED_DATA;
+ }
+
+ if (TREE_ASM_WRITTEN (ident))
+ return MACHOPIC_DEFINED_DATA;
+
+ return MACHOPIC_UNDEFINED;
+ }
+
+ else if (name[1] == 'D')
+ return MACHOPIC_DEFINED_DATA;
+
+ else if (name[1] == 'T')
+ return MACHOPIC_DEFINED_FUNCTION;
+
+ /* It is possible that someone is holding a "stale" name, which has
+ since been defined. See if there is a "defined" name (i.e,
+ different from NAME only in having a '!D_' or a '!T_' instead of
+ a '!d_' or '!t_' prefix) in the identifier hash tables. If so, say
+ that this identifier is defined. */
+ else if (name[1] == 'd' || name[1] == 't')
+ {
+ char *new_name;
+ new_name = (char *)alloca (strlen (name) + 1);
+ strcpy (new_name, name);
+ new_name[1] = (name[1] == 'd') ? 'D' : 'T';
+ if (maybe_get_identifier (new_name) != NULL)
+ return (name[1] == 'd') ? MACHOPIC_DEFINED_DATA
+ : MACHOPIC_DEFINED_FUNCTION;
+ }
+
+ for (temp = machopic_defined_list; temp != NULL_TREE; temp = TREE_CHAIN (temp))
+ {
+ if (ident == TREE_VALUE (temp))
+ {
+ if (name[1] == 'T')
+ return MACHOPIC_DEFINED_FUNCTION;
+ else
+ return MACHOPIC_DEFINED_DATA;
+ }
+ }
+
+ if (name[1] == 't' || name[1] == 'T')
+ {
+ if (lprefix)
+ return MACHOPIC_DEFINED_FUNCTION;
+ else
+ return MACHOPIC_UNDEFINED_FUNCTION;
+ }
+ else
+ {
+ if (lprefix)
+ return MACHOPIC_DEFINED_DATA;
+ else
+ return MACHOPIC_UNDEFINED_DATA;
+ }
+}
+
+
+enum machopic_addr_class
+machopic_classify_name (name)
+ const char *name;
+{
+ return machopic_classify_ident (get_identifier (name));
+}
+
+int
+machopic_ident_defined_p (ident)
+ tree ident;
+{
+ switch (machopic_classify_ident (ident))
+ {
+ case MACHOPIC_UNDEFINED:
+ case MACHOPIC_UNDEFINED_DATA:
+ case MACHOPIC_UNDEFINED_FUNCTION:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+static int
+machopic_data_defined_p (name)
+ const char *name;
+{
+ switch (machopic_classify_ident (get_identifier (name)))
+ {
+ case MACHOPIC_DEFINED_DATA:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int
+machopic_name_defined_p (name)
+ const char *name;
+{
+ return machopic_ident_defined_p (get_identifier (name));
+}
+
+void
+machopic_define_ident (ident)
+ tree ident;
+{
+ if (!machopic_ident_defined_p (ident))
+ machopic_defined_list =
+ tree_cons (NULL_TREE, ident, machopic_defined_list);
+}
+
+void
+machopic_define_name (name)
+ const char *name;
+{
+ machopic_define_ident (get_identifier (name));
+}
+
+/* This is a static to make inline functions work. The rtx
+ representing the PIC base symbol always points to here. */
+
+static char function_base[32];
+
+static int current_pic_label_num;
+
+char *
+machopic_function_base_name ()
+{
+ static const char *name = NULL;
+ static const char *current_name;
+
+ current_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
+
+ if (name != current_name)
+ {
+ current_function_uses_pic_offset_table = 1;
+
+ /* Save mucho space and time. Some of the C++ mangled names are over
+ 700 characters long! Note that we produce a label containing a '-'
+ if the function we're compiling is an Objective-C method, as evinced
+ by the incredibly scientific test below. This is because code in
+ rs6000.c makes the same ugly test when loading the PIC reg. */
+
+ ++current_pic_label_num;
+ if (*current_name == '+' || *current_name == '-')
+ sprintf (function_base, "*\"L-%d$pb\"", current_pic_label_num);
+ else
+ sprintf (function_base, "*L%d$pb", current_pic_label_num);
+
+ name = current_name;
+ }
+
+ return function_base;
+}
+
+static tree machopic_non_lazy_pointers = NULL;
+
+/* Return a non-lazy pointer name corresponding to the given name,
+ either by finding it in our list of pointer names, or by generating
+ a new one. */
+
+char *
+machopic_non_lazy_ptr_name (name)
+ const char *name;
+{
+ char *temp_name;
+ tree temp, ident = get_identifier (name);
+
+ for (temp = machopic_non_lazy_pointers;
+ temp != NULL_TREE;
+ temp = TREE_CHAIN (temp))
+ {
+ if (ident == TREE_VALUE (temp))
+ return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
+ }
+
+ STRIP_NAME_ENCODING (name, name);
+
+ /* Try again, but comparing names this time. */
+ for (temp = machopic_non_lazy_pointers;
+ temp != NULL_TREE;
+ temp = TREE_CHAIN (temp))
+ {
+ if (TREE_VALUE (temp))
+ {
+ temp_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
+ STRIP_NAME_ENCODING (temp_name, temp_name);
+ if (strcmp (name, temp_name) == 0)
+ return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
+ }
+ }
+
+ {
+ char *buffer;
+ tree ptr_name;
+
+ buffer = alloca (strlen (name) + 20);
+
+ strcpy (buffer, "&L");
+ if (name[0] == '*')
+ strcat (buffer, name+1);
+ else
+ {
+ strcat (buffer, "_");
+ strcat (buffer, name);
+ }
+
+ strcat (buffer, "$non_lazy_ptr");
+ ptr_name = get_identifier (buffer);
+
+ machopic_non_lazy_pointers
+ = tree_cons (ptr_name, ident, machopic_non_lazy_pointers);
+
+ TREE_USED (machopic_non_lazy_pointers) = 0;
+
+ return IDENTIFIER_POINTER (ptr_name);
+ }
+}
+
+static tree machopic_stubs = 0;
+
+/* Make sure the GC knows about our homemade lists. */
+
+void
+machopic_add_gc_roots ()
+{
+ ggc_add_tree_root (&machopic_defined_list, 1);
+ ggc_add_tree_root (&machopic_non_lazy_pointers, 1);
+ ggc_add_tree_root (&machopic_stubs, 1);
+}
+
+/* Return the name of the stub corresponding to the given name,
+ generating a new stub name if necessary. */
+
+char *
+machopic_stub_name (name)
+ const char *name;
+{
+ tree temp, ident = get_identifier (name);
+ const char *tname;
+
+ for (temp = machopic_stubs;
+ temp != NULL_TREE;
+ temp = TREE_CHAIN (temp))
+ {
+ if (ident == TREE_VALUE (temp))
+ return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
+ tname = IDENTIFIER_POINTER (TREE_VALUE (temp));
+ if (strcmp (name, tname) == 0)
+ return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
+ /* A library call name might not be section-encoded yet, so try
+ it against a stripped name. */
+ if (name[0] != '!'
+ && tname[0] == '!'
+ && strcmp (name, tname + 4) == 0)
+ return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
+ }
+
+ STRIP_NAME_ENCODING (name, name);
+
+ {
+ char *buffer;
+ tree ptr_name;
+ int needs_quotes = name_needs_quotes (name);
+
+ buffer = alloca (strlen (name) + 20);
+
+ if (needs_quotes)
+ strcpy (buffer, "&\"L");
+ else
+ strcpy (buffer, "&L");
+ if (name[0] == '*')
+ {
+ strcat (buffer, name+1);
+ }
+ else
+ {
+ strcat (buffer, "_");
+ strcat (buffer, name);
+ }
+
+ if (needs_quotes)
+ strcat (buffer, "$stub\"");
+ else
+ strcat (buffer, "$stub");
+ ptr_name = get_identifier (buffer);
+
+ machopic_stubs = tree_cons (ptr_name, ident, machopic_stubs);
+ TREE_USED (machopic_stubs) = 0;
+
+ return IDENTIFIER_POINTER (ptr_name);
+ }
+}
+
+void
+machopic_validate_stub_or_non_lazy_ptr (name, validate_stub)
+ const char *name;
+ int validate_stub;
+{
+ char *real_name;
+ tree temp, ident = get_identifier (name), id2;
+
+ for (temp = (validate_stub ? machopic_stubs : machopic_non_lazy_pointers);
+ temp != NULL_TREE;
+ temp = TREE_CHAIN (temp))
+ if (ident == TREE_PURPOSE (temp))
+ {
+ /* Mark both the stub or non-lazy pointer as well as the
+ original symbol as being referenced. */
+ TREE_USED (temp) = 1;
+ if (TREE_CODE (TREE_VALUE (temp)) == IDENTIFIER_NODE)
+ TREE_SYMBOL_REFERENCED (TREE_VALUE (temp)) = 1;
+ STRIP_NAME_ENCODING (real_name, IDENTIFIER_POINTER (TREE_VALUE (temp)));
+ id2 = maybe_get_identifier (real_name);
+ if (id2)
+ TREE_SYMBOL_REFERENCED (id2) = 1;
+ }
+}
+
+/* Transform ORIG, which may be any data source, to the corresponding
+ source using indirections. */
+
+rtx
+machopic_indirect_data_reference (orig, reg)
+ rtx orig, reg;
+{
+ rtx ptr_ref = orig;
+
+ if (! MACHOPIC_INDIRECT)
+ return orig;
+
+ if (GET_CODE (orig) == SYMBOL_REF)
+ {
+ const char *name = XSTR (orig, 0);
+
+ if (machopic_data_defined_p (name))
+ {
+ rtx pic_base = gen_rtx (SYMBOL_REF, Pmode,
+ machopic_function_base_name ());
+ rtx offset = gen_rtx (CONST, Pmode,
+ gen_rtx (MINUS, Pmode, orig, pic_base));
+
+#if defined (TARGET_TOC) /* i.e., PowerPC */
+ rtx hi_sum_reg = reg;
+
+ if (reg == NULL)
+ abort ();
+
+ emit_insn (gen_rtx (SET, Pmode, hi_sum_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)));
+
+ orig = reg;
+#else
+#if defined (HAVE_lo_sum)
+ if (reg == 0) abort ();
+
+ 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,
+ gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)));
+
+ orig = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, reg);
+#endif
+#endif
+ return orig;
+ }
+
+ ptr_ref = gen_rtx (SYMBOL_REF, Pmode,
+ machopic_non_lazy_ptr_name (name));
+
+ ptr_ref = gen_rtx_MEM (Pmode, ptr_ref);
+ RTX_UNCHANGING_P (ptr_ref) = 1;
+
+ return ptr_ref;
+ }
+ else if (GET_CODE (orig) == CONST)
+ {
+ rtx base, result;
+
+ /* legitimize both operands of the PLUS */
+ if (GET_CODE (XEXP (orig, 0)) == PLUS)
+ {
+ base = machopic_indirect_data_reference (XEXP (XEXP (orig, 0), 0),
+ reg);
+ orig = machopic_indirect_data_reference (XEXP (XEXP (orig, 0), 1),
+ (base == reg ? 0 : reg));
+ }
+ else
+ return orig;
+
+ if (MACHOPIC_PURE && GET_CODE (orig) == CONST_INT)
+ result = plus_constant (base, INTVAL (orig));
+ else
+ result = gen_rtx (PLUS, Pmode, base, orig);
+
+ if (RTX_UNCHANGING_P (base) && RTX_UNCHANGING_P (orig))
+ RTX_UNCHANGING_P (result) = 1;
+
+ if (MACHOPIC_JUST_INDIRECT && GET_CODE (base) == MEM)
+ {
+ if (reg)
+ {
+ emit_move_insn (reg, result);
+ result = reg;
+ }
+ else
+ {
+ result = force_reg (GET_MODE (result), result);
+ }
+ }
+
+ return result;
+
+ }
+ else if (GET_CODE (orig) == MEM)
+ XEXP (ptr_ref, 0) = machopic_indirect_data_reference (XEXP (orig, 0), reg);
+ /* When the target is i386, this code prevents crashes due to the
+ compiler's ignorance on how to move the PIC base register to
+ other registers. (The reload phase sometimes introduces such
+ insns.) */
+ else if (GET_CODE (orig) == PLUS
+ && GET_CODE (XEXP (orig, 0)) == REG
+ && REGNO (XEXP (orig, 0)) == PIC_OFFSET_TABLE_REGNUM
+#ifdef I386
+ /* Prevent the same register from being erroneously used
+ as both the base and index registers. */
+ && GET_CODE (XEXP (orig, 1)) == CONST
+#endif
+ && reg)
+ {
+ emit_move_insn (reg, XEXP (orig, 0));
+ XEXP (ptr_ref, 0) = reg;
+ }
+ return ptr_ref;
+}
+
+/* Transform TARGET (a MEM), which is a function call target, to the
+ corresponding symbol_stub if necessary. Return a new MEM. */
+
+rtx
+machopic_indirect_call_target (target)
+ rtx target;
+{
+ if (GET_CODE (target) != MEM)
+ return target;
+
+ if (MACHOPIC_INDIRECT && GET_CODE (XEXP (target, 0)) == SYMBOL_REF)
+ {
+ enum machine_mode mode = GET_MODE (XEXP (target, 0));
+ const char *name = XSTR (XEXP (target, 0), 0);
+
+ /* If the name is already defined, we need do nothing. */
+ if (name[0] == '!' && name[1] == 'T')
+ return target;
+
+ if (!machopic_name_defined_p (name))
+ {
+ const char *stub_name = machopic_stub_name (name);
+
+ XEXP (target, 0) = gen_rtx (SYMBOL_REF, mode, stub_name);
+ RTX_UNCHANGING_P (target) = 1;
+ }
+ }
+
+ return target;
+}
+
+rtx
+machopic_legitimize_pic_address (orig, mode, reg)
+ rtx orig, reg;
+ enum machine_mode mode;
+{
+ rtx pic_ref = orig;
+
+ if (! MACHOPIC_PURE)
+ return orig;
+
+ /* First handle a simple SYMBOL_REF or LABEL_REF */
+ if (GET_CODE (orig) == LABEL_REF
+ || (GET_CODE (orig) == SYMBOL_REF
+ ))
+ {
+ /* addr(foo) = &func+(foo-func) */
+ rtx pic_base;
+
+ orig = machopic_indirect_data_reference (orig, reg);
+
+ if (GET_CODE (orig) == PLUS
+ && GET_CODE (XEXP (orig, 0)) == REG)
+ {
+ if (reg == 0)
+ return force_reg (mode, orig);
+
+ emit_move_insn (reg, orig);
+ return reg;
+ }
+
+ pic_base = gen_rtx (SYMBOL_REF, Pmode, machopic_function_base_name ());
+
+ if (GET_CODE (orig) == MEM)
+ {
+ if (reg == 0)
+ {
+ if (reload_in_progress)
+ abort ();
+ else
+ reg = gen_reg_rtx (Pmode);
+ }
+
+#ifdef HAVE_lo_sum
+ if (GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
+ || GET_CODE (XEXP (orig, 0)) == LABEL_REF)
+ {
+ rtx offset = gen_rtx (CONST, Pmode,
+ gen_rtx (MINUS, Pmode,
+ XEXP (orig, 0), pic_base));
+#if defined (TARGET_TOC) /* i.e., PowerPC */
+ /* Generating a new reg may expose opportunities for
+ common subexpression elimination. */
+ rtx hi_sum_reg =
+ (reload_in_progress ? reg : gen_reg_rtx (SImode));
+
+ emit_insn (gen_rtx (SET, Pmode, hi_sum_reg,
+ gen_rtx (PLUS, Pmode,
+ pic_offset_table_rtx,
+ gen_rtx (HIGH, Pmode, offset))));
+ emit_insn (gen_rtx (SET, VOIDmode, reg,
+ gen_rtx (MEM, GET_MODE (orig),
+ gen_rtx (LO_SUM, Pmode,
+ hi_sum_reg, offset))));
+ pic_ref = reg;
+
+#else
+ emit_insn (gen_rtx (USE, VOIDmode,
+ gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)));
+
+ emit_insn (gen_rtx (SET, VOIDmode, reg,
+ gen_rtx (HIGH, Pmode,
+ gen_rtx (CONST, Pmode, offset))));
+ emit_insn (gen_rtx (SET, VOIDmode, reg,
+ gen_rtx (LO_SUM, Pmode, reg,
+ gen_rtx (CONST, Pmode, offset))));
+ pic_ref = gen_rtx (PLUS, Pmode,
+ pic_offset_table_rtx, reg);
+#endif
+ }
+ else
+#endif /* HAVE_lo_sum */
+ {
+ rtx pic = pic_offset_table_rtx;
+ if (GET_CODE (pic) != REG)
+ {
+ emit_move_insn (reg, pic);
+ pic = reg;
+ }
+#if 0
+ emit_insn (gen_rtx (USE, VOIDmode,
+ gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM)));
+#endif
+
+ pic_ref = gen_rtx (PLUS, Pmode,
+ pic,
+ gen_rtx (CONST, Pmode,
+ gen_rtx (MINUS, Pmode,
+ XEXP (orig, 0),
+ pic_base)));
+ }
+
+#if !defined (TARGET_TOC)
+ RTX_UNCHANGING_P (pic_ref) = 1;
+ emit_move_insn (reg, pic_ref);
+ pic_ref = gen_rtx (MEM, GET_MODE (orig), reg);
+#endif
+ }
+ else
+ {
+
+#ifdef HAVE_lo_sum
+ if (GET_CODE (orig) == SYMBOL_REF
+ || GET_CODE (orig) == LABEL_REF)
+ {
+ rtx offset = gen_rtx (CONST, Pmode,
+ gen_rtx (MINUS, Pmode, orig, pic_base));
+#if defined (TARGET_TOC) /* i.e., PowerPC */
+ rtx hi_sum_reg;
+
+ if (reg == 0)
+ {
+ if (reload_in_progress)
+ abort ();
+ else
+ reg = gen_reg_rtx (SImode);
+ }
+
+ hi_sum_reg = reg;
+
+ emit_insn (gen_rtx (SET, Pmode, hi_sum_reg,
+ gen_rtx (PLUS, Pmode,
+ pic_offset_table_rtx,
+ gen_rtx (HIGH, Pmode, offset))));
+ emit_insn (gen_rtx (SET, VOIDmode, reg,
+ gen_rtx (LO_SUM, Pmode,
+ hi_sum_reg, 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)));
+ pic_ref = gen_rtx (PLUS, Pmode,
+ pic_offset_table_rtx, reg);
+#endif
+ }
+ else
+#endif /* HAVE_lo_sum */
+ {
+ if (GET_CODE (orig) == REG)
+ {
+ return orig;
+ }
+ else
+ {
+ rtx pic = pic_offset_table_rtx;
+ if (GET_CODE (pic) != REG)
+ {
+ emit_move_insn (reg, pic);
+ pic = reg;
+ }
+#if 0
+ emit_insn (gen_rtx (USE, VOIDmode,
+ pic_offset_table_rtx));
+#endif
+ pic_ref = gen_rtx (PLUS, Pmode,
+ pic,
+ gen_rtx (CONST, Pmode,
+ gen_rtx (MINUS, Pmode,
+ orig, pic_base)));
+ }
+ }
+ }
+
+ RTX_UNCHANGING_P (pic_ref) = 1;
+
+ if (GET_CODE (pic_ref) != REG)
+ {
+ if (reg != 0)
+ {
+ emit_move_insn (reg, pic_ref);
+ return reg;
+ }
+ else
+ {
+ return force_reg (mode, pic_ref);
+ }
+ }
+ else
+ {
+ return pic_ref;
+ }
+ }
+
+ else if (GET_CODE (orig) == SYMBOL_REF)
+ return orig;
+
+ else if (GET_CODE (orig) == PLUS
+ && (GET_CODE (XEXP (orig, 0)) == MEM
+ || GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
+ || GET_CODE (XEXP (orig, 0)) == LABEL_REF)
+ && XEXP (orig, 0) != pic_offset_table_rtx
+ && GET_CODE (XEXP (orig, 1)) != REG)
+
+ {
+ rtx base;
+ int is_complex = (GET_CODE (XEXP (orig, 0)) == MEM);
+
+ base = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
+ orig = machopic_legitimize_pic_address (XEXP (orig, 1),
+ Pmode, (base == reg ? 0 : reg));
+ if (GET_CODE (orig) == CONST_INT)
+ {
+ pic_ref = plus_constant (base, INTVAL (orig));
+ is_complex = 1;
+ }
+ else
+ pic_ref = gen_rtx (PLUS, Pmode, base, orig);
+
+ if (RTX_UNCHANGING_P (base) && RTX_UNCHANGING_P (orig))
+ RTX_UNCHANGING_P (pic_ref) = 1;
+
+ if (reg && is_complex)
+ {
+ emit_move_insn (reg, pic_ref);
+ pic_ref = reg;
+ }
+ /* Likewise, should we set special REG_NOTEs here? */
+ }
+
+ else if (GET_CODE (orig) == CONST)
+ {
+ return machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
+ }
+
+ else if (GET_CODE (orig) == MEM
+ && GET_CODE (XEXP (orig, 0)) == SYMBOL_REF)
+ {
+ rtx addr = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
+
+ addr = gen_rtx (MEM, GET_MODE (orig), addr);
+ RTX_UNCHANGING_P (addr) = RTX_UNCHANGING_P (orig);
+ emit_move_insn (reg, addr);
+ pic_ref = reg;
+ }
+
+ return pic_ref;
+}
+
+
+void
+machopic_finish (asm_out_file)
+ FILE *asm_out_file;
+{
+ tree temp;
+
+ for (temp = machopic_stubs;
+ temp != NULL_TREE;
+ temp = TREE_CHAIN (temp))
+ {
+ const char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
+ const char *stub_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
+ char *sym;
+ char *stub;
+
+ if (! TREE_USED (temp))
+ continue;
+
+ /* If the symbol is actually defined, we don't need a stub. */
+ if (sym_name[0] == '!' && sym_name[1] == 'T')
+ continue;
+
+ STRIP_NAME_ENCODING (sym_name, sym_name);
+
+ sym = alloca (strlen (sym_name) + 2);
+ if (sym_name[0] == '*' || sym_name[0] == '&')
+ strcpy (sym, sym_name + 1);
+ else if (sym_name[0] == '-' || sym_name[0] == '+')
+ strcpy (sym, sym_name);
+ else
+ sym[0] = '_', strcpy (sym + 1, sym_name);
+
+ stub = alloca (strlen (stub_name) + 2);
+ if (stub_name[0] == '*' || stub_name[0] == '&')
+ strcpy (stub, stub_name + 1);
+ else
+ stub[0] = '_', strcpy (stub + 1, stub_name);
+
+ machopic_output_stub (asm_out_file, sym, stub);
+ }
+
+ for (temp = machopic_non_lazy_pointers;
+ temp != NULL_TREE;
+ temp = TREE_CHAIN (temp))
+ {
+ char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
+ char *lazy_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
+#if 0
+ tree decl = lookup_name_darwin (TREE_VALUE (temp));
+#endif
+
+ if (! TREE_USED (temp))
+ continue;
+
+ if (machopic_ident_defined_p (TREE_VALUE (temp))
+#if 0 /* add back when we have private externs */
+ || (decl && DECL_PRIVATE_EXTERN (decl))
+#endif
+ )
+ {
+ data_section ();
+ assemble_align (GET_MODE_ALIGNMENT (Pmode));
+ assemble_label (lazy_name);
+ assemble_integer (gen_rtx (SYMBOL_REF, Pmode, sym_name),
+ GET_MODE_SIZE (Pmode),
+ GET_MODE_ALIGNMENT (Pmode), 1);
+ }
+ else
+ {
+ machopic_nl_symbol_ptr_section ();
+ assemble_name (asm_out_file, lazy_name);
+ fprintf (asm_out_file, ":\n");
+
+ fprintf (asm_out_file, "\t.indirect_symbol ");
+ assemble_name (asm_out_file, sym_name);
+ fprintf (asm_out_file, "\n");
+
+ assemble_integer (const0_rtx, GET_MODE_SIZE (Pmode),
+ GET_MODE_ALIGNMENT (Pmode), 1);
+ }
+ }
+}
+
+int
+machopic_operand_p (op)
+ rtx op;
+{
+ if (MACHOPIC_JUST_INDIRECT)
+ {
+ while (GET_CODE (op) == CONST)
+ op = XEXP (op, 0);
+
+ if (GET_CODE (op) == SYMBOL_REF)
+ return machopic_name_defined_p (XSTR (op, 0));
+ 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_name_defined_p (XSTR (XEXP (op, 0), 0))
+ && machopic_name_defined_p (XSTR (XEXP (op, 1), 0)))
+ return 1;
+
+#if 0 /*def TARGET_TOC*/ /* i.e., PowerPC */
+ /* Without this statement, the compiler crashes while compiling enquire.c
+ when targetting PowerPC. It is not known why this code is not needed
+ when targetting other processors. */
+ else if (GET_CODE (op) == SYMBOL_REF
+ && (machopic_classify_name (XSTR (op, 0))
+ == MACHOPIC_DEFINED_FUNCTION))
+ {
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+
+/* This function records whether a given name corresponds to a defined
+ or undefined function or variable, for machopic_classify_ident to
+ use later. */
+
+void
+darwin_encode_section_info (decl)
+ tree decl;
+{
+ char code = '\0';
+ int defined = 0;
+ rtx sym_ref;
+ const char *orig_str;
+ char *new_str;
+ size_t len, new_len;
+
+ if ((TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == VAR_DECL)
+ && !DECL_EXTERNAL (decl)
+ && ((TREE_STATIC (decl)
+ && (!DECL_COMMON (decl) || !TREE_PUBLIC (decl)))
+ || (DECL_INITIAL (decl)
+ && DECL_INITIAL (decl) != error_mark_node)))
+ defined = 1;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ code = (defined ? 'T' : 't');
+ else if (TREE_CODE (decl) == VAR_DECL)
+ code = (defined ? 'D' : 'd');
+
+ if (code == '\0')
+ return;
+
+ sym_ref = XEXP (DECL_RTL (decl), 0);
+ orig_str = XSTR (sym_ref, 0);
+ len = strlen (orig_str) + 1;
+
+ if (orig_str[0] == '!')
+ {
+ /* Already encoded; see if we need to change it. */
+ if (code == orig_str[1])
+ return;
+ /* Yes, tweak a copy of the name and put it in a new string. */
+ new_str = alloca (len);
+ memcpy (new_str, orig_str, len);
+ new_str[1] = code;
+ XSTR (sym_ref, 0) = ggc_alloc_string (new_str, len);
+ }
+ else
+ {
+ /* Add the encoding. */
+ new_len = len + 4;
+ new_str = alloca (new_len);
+ new_str[0] = '!';
+ new_str[1] = code;
+ new_str[2] = '_';
+ new_str[3] = '_';
+ memcpy (new_str + 4, orig_str, len);
+ XSTR (sym_ref, 0) = ggc_alloc_string (new_str, new_len);
+ }
+ /* The non-lazy pointer list may have captured references to the
+ old encoded name, change them. */
+ if (TREE_CODE (decl) == VAR_DECL)
+ update_non_lazy_ptrs (XSTR (sym_ref, 0));
+ else
+ update_stubs (XSTR (sym_ref, 0));
+}
+
+/* Scan the list of non-lazy pointers and update any recorded names whose
+ stripped name matches the argument. */
+
+static void
+update_non_lazy_ptrs (name)
+ const char *name;
+{
+ const char *name1, *name2;
+ tree temp;
+
+ STRIP_NAME_ENCODING (name1, name);
+
+ for (temp = machopic_non_lazy_pointers;
+ temp != NULL_TREE;
+ temp = TREE_CHAIN (temp))
+ {
+ char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
+
+ if (*sym_name == '!')
+ {
+ STRIP_NAME_ENCODING (name2, sym_name);
+ if (strcmp (name1, name2) == 0)
+ {
+ IDENTIFIER_POINTER (TREE_VALUE (temp)) = name;
+ break;
+ }
+ }
+ }
+}
+
+/* Function NAME is being defined, and its label has just been output.
+ If there's already a reference to a stub for this function, we can
+ just emit the stub label now and we don't bother emitting the stub later. */
+
+void
+machopic_output_possible_stub_label (file, name)
+ FILE *file;
+ const char *name;
+{
+ tree temp;
+
+
+ /* Ensure we're looking at a section-encoded name. */
+ if (name[0] != '!' || (name[1] != 't' && name[1] != 'T'))
+ return;
+
+ for (temp = machopic_stubs;
+ temp != NULL_TREE;
+ temp = TREE_CHAIN (temp))
+ {
+ const char *sym_name;
+
+ sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
+ if (sym_name[0] == '!' && sym_name[1] == 'T'
+ && ! strcmp (name+2, sym_name+2))
+ {
+ ASM_OUTPUT_LABEL (file, IDENTIFIER_POINTER (TREE_PURPOSE (temp)));
+ /* Avoid generating a stub for this. */
+ TREE_USED (temp) = 0;
+ break;
+ }
+ }
+}
+
+/* Scan the list of stubs and update any recorded names whose
+ stripped name matches the argument. */
+
+static void
+update_stubs (name)
+ const char *name;
+{
+ const char *name1, *name2;
+ tree temp;
+
+ STRIP_NAME_ENCODING (name1, name);
+
+ for (temp = machopic_stubs;
+ temp != NULL_TREE;
+ temp = TREE_CHAIN (temp))
+ {
+ char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
+
+ if (*sym_name == '!')
+ {
+ STRIP_NAME_ENCODING (name2, sym_name);
+ if (strcmp (name1, name2) == 0)
+ {
+ IDENTIFIER_POINTER (TREE_VALUE (temp)) = name;
+ break;
+ }
+ }
+ }
+}
+
+void
+machopic_asm_out_constructor (symbol, priority)
+ rtx symbol;
+ int priority ATTRIBUTE_UNUSED;
+{
+ if (flag_pic)
+ mod_init_section ();
+ else
+ constructor_section ();
+ assemble_align (POINTER_SIZE);
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+
+ if (!flag_pic)
+ fprintf (asm_out_file, ".reference .constructors_used\n");
+}
+
+void
+machopic_asm_out_destructor (symbol, priority)
+ rtx symbol;
+ int priority ATTRIBUTE_UNUSED;
+{
+ if (flag_pic)
+ mod_term_section ();
+ else
+ destructor_section ();
+ assemble_align (POINTER_SIZE);
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+
+ if (!flag_pic)
+ fprintf (asm_out_file, ".reference .destructors_used\n");
+}
OpenPOWER on IntegriCloud