diff options
author | obrien <obrien@FreeBSD.org> | 2002-02-01 18:16:02 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2002-02-01 18:16:02 +0000 |
commit | c9ab9ae440a8066b2c2b85b157b1fdadcf09916a (patch) | |
tree | 086d9d6c8fbd4fc8fe4495059332f66bc0f8d12b /contrib/gcc/config/darwin.c | |
parent | 2ecfd8bd04b63f335c1ec6295740a4bfd97a4fa6 (diff) | |
download | FreeBSD-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.c | 1141 |
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"); +} |