From: Stan Shebs Date: Thu, 12 Apr 2001 02:13:00 +0000 (+0000) Subject: Add Darwin (Mac OS X kernel) native support. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ee890fe2a15b3ed799f92a951ea64825793deec8;p=gcc.git Add Darwin (Mac OS X kernel) native support. * config.gcc (powerpc-*-darwin*): Add native bits. * config/darwin.c: New file, generic Darwin support functions. * config/darwin.h: New file, generic Darwin definitions. * config/darwin-protos.h: New file, generic Darwin prototypes. * rs6000/darwin.h: New file, Darwin for PowerPC. * rs6000/t-darwin: New file, Darwin makefile fragment. * rs6000/rs6000.h (OBJECT_MACHO): New macro. (TARGET_MACHO): Ditto. (rs6000_abi): Add ABI_DARWIN. (RS6000_REG_SAVE): Add ABI_DARWIN case. (RS6000_SAVE_AREA): Ditto. (FP_ARG_MAX_REG): Ditto. (RETURN_ADDRESS_OFFSET): Ditto. * rs6000/rs6000.c (rs6000_legitimize_address): Add TARGET_MACHO cases. (rs6000_emit_move): Add ABI_DARWIN cases. (print_operand): Ditto. (first_reg_to_save): Ditto. (rs6000_stack_info): Ditto, also align stack by 16 instead of 8. (debug_stack_info): Ditto. (rs6000_emit_prologue): Ditto. (rs6000_emit_epilogue): Ditto. (output_profiler_hook): Ditto. (output_function_profiler): Ditto. (rs6000_add_gc_roots): Call machopic_add_gc_roots if TARGET_MACHO. (output_mi_thunk): Add TARGET_MACHO case. (add_compiler_stub): Ditto. (output_compiler_stub): Ditto. (no_previous_def): Ditto. (output_call): Ditto. (machopic_output_stub): Ditto. (rs6000_machopic_legitimize_pic_address): Ditto. (toc_section): Ditto. * rs6000/rs6000.md (addsi3_high): New TARGET_MACHO pattern. (macho_high): Ditto. (macho_low): Ditto. (movsi_low): Ditto. (load_macho_picbase): Ditto. (call): Add TARGET_MACHO case to modify function. (call_value): Ditto. (call_nonlocal_sysv): Add ABI_DARWIN case. (call_value_nonlocal_sysv): Ditto. * rs6000/rs6000-protos.h (rs6000_machopic_legitimize_pic_address): Add prototype. (machopic_output_stub): Ditto. * ginclude/stddef.h: Test _BSD_WCHAR_T_DEFINED_. From-SVN: r41277 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8426f00efa3..094a78849c4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,53 @@ +2001-04-11 Stan Shebs + + Add Darwin (Mac OS X kernel) native support. + * config.gcc (powerpc-*-darwin*): Add native bits. + * config/darwin.c: New file, generic Darwin support functions. + * config/darwin.h: New file, generic Darwin definitions. + * config/darwin-protos.h: New file, generic Darwin prototypes. + * rs6000/darwin.h: New file, Darwin for PowerPC. + * rs6000/t-darwin: New file, Darwin makefile fragment. + * rs6000/rs6000.h (OBJECT_MACHO): New macro. + (TARGET_MACHO): Ditto. + (rs6000_abi): Add ABI_DARWIN. + (RS6000_REG_SAVE): Add ABI_DARWIN case. + (RS6000_SAVE_AREA): Ditto. + (FP_ARG_MAX_REG): Ditto. + (RETURN_ADDRESS_OFFSET): Ditto. + * rs6000/rs6000.c (rs6000_legitimize_address): Add TARGET_MACHO + cases. + (rs6000_emit_move): Add ABI_DARWIN cases. + (print_operand): Ditto. + (first_reg_to_save): Ditto. + (rs6000_stack_info): Ditto, also align stack by 16 instead of 8. + (debug_stack_info): Ditto. + (rs6000_emit_prologue): Ditto. + (rs6000_emit_epilogue): Ditto. + (output_profiler_hook): Ditto. + (output_function_profiler): Ditto. + (rs6000_add_gc_roots): Call machopic_add_gc_roots if TARGET_MACHO. + (output_mi_thunk): Add TARGET_MACHO case. + (add_compiler_stub): Ditto. + (output_compiler_stub): Ditto. + (no_previous_def): Ditto. + (output_call): Ditto. + (machopic_output_stub): Ditto. + (rs6000_machopic_legitimize_pic_address): Ditto. + (toc_section): Ditto. + * rs6000/rs6000.md (addsi3_high): New TARGET_MACHO pattern. + (macho_high): Ditto. + (macho_low): Ditto. + (movsi_low): Ditto. + (load_macho_picbase): Ditto. + (call): Add TARGET_MACHO case to modify function. + (call_value): Ditto. + (call_nonlocal_sysv): Add ABI_DARWIN case. + (call_value_nonlocal_sysv): Ditto. + * rs6000/rs6000-protos.h (rs6000_machopic_legitimize_pic_address): + Add prototype. + (machopic_output_stub): Ditto. + * ginclude/stddef.h: Test _BSD_WCHAR_T_DEFINED_. + 2001-04-11 Mark Mitchell * dwarf2out.c (modified_type_die): Don't create new types here. diff --git a/gcc/config.gcc b/gcc/config.gcc index 6fb9e99a528..07578f97eb3 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -2647,8 +2647,15 @@ powerpc-*-beos*) tmake_file=rs6000/t-beos ;; powerpc-*-darwin*) + cpu_type=rs6000 + tm_file="${tm_file} darwin.h rs6000/darwin.h" + tm_p_file="${tm_p_file} darwin-protos.h" + tmake_file=rs6000/t-darwin xm_file=rs6000/xm-darwin.h xmake_file=rs6000/x-darwin + extra_objs="darwin.o" + # Darwin linker does collect2 functionality + use_collect2=no ;; powerpc-*-sysv*) tm_file="${tm_file} svr4.h rs6000/sysv4.h" diff --git a/gcc/config/darwin-protos.h b/gcc/config/darwin-protos.h new file mode 100644 index 00000000000..b2326c050c0 --- /dev/null +++ b/gcc/config/darwin-protos.h @@ -0,0 +1,57 @@ +/* Prototypes. + Copyright (C) 2001 Free Software Foundation, 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. */ + +extern int name_needs_quotes PARAMS ((const char *)); + +extern void machopic_validate_stub_or_non_lazy_ptr PARAMS ((const char *, int)); + +extern char *machopic_function_base_name PARAMS ((void)); +extern char *machopic_non_lazy_ptr_name PARAMS ((const char*)); +extern char *machopic_stub_name PARAMS ((const char*)); + +extern void machopic_add_gc_roots PARAMS ((void)); + +extern void machopic_picsymbol_stub_section PARAMS ((void)); +extern void machopic_symbol_stub_section PARAMS ((void)); +extern void machopic_lazy_symbol_ptr_section PARAMS ((void)); +extern void machopic_nl_symbol_ptr_section PARAMS ((void)); + +#ifdef RTX_CODE + +extern int machopic_operand_p PARAMS ((rtx)); +extern enum machopic_addr_class machopic_classify_name PARAMS ((const char*)); + +extern rtx machopic_indirect_data_reference PARAMS ((rtx, rtx)); +extern rtx machopic_indirect_call_target PARAMS ((rtx)); +extern rtx machopic_legitimize_pic_address PARAMS ((rtx, enum machine_mode, rtx)); + +#endif /* RTX_CODE */ + +#ifdef TREE_CODE + +extern enum machopic_addr_class machopic_classify_ident PARAMS ((tree)); +extern void machopic_define_ident PARAMS ((tree)); +extern void machopic_define_name PARAMS ((const char*)); +extern int machopic_name_defined_p PARAMS ((const char*)); +extern int machopic_ident_defined_p PARAMS ((tree)); + +#endif /* TREE_CODE */ + +extern void machopic_finish PARAMS ((FILE *)); diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c new file mode 100644 index 00000000000..3e2a0008ef5 --- /dev/null +++ b/gcc/config/darwin.c @@ -0,0 +1,1002 @@ +/* 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" +/* need for IDENTIFIER_GLOBAL_VALUE and IDENTIFIER_LOCAL_VALUE */ +#include "c-tree.h" +#include "function.h" +#include "ggc.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 *)); + +/* Make everything that used to go in the text section really go there. */ + +int flag_no_mach_text_sections = 0; + +int +name_needs_quotes (name) + const char *name; +{ + int c; + while ((c = *name++) != '\0') + if (!isalnum (c) && 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, decl = lookup_name_darwin (ident); + + if (!decl) + { + 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; + } + + /* variable declarations */ + else if (TREE_CODE (decl) == VAR_DECL) + { + if ((DECL_INITIAL (decl) + || TREE_STATIC (decl)) + && ! TREE_PUBLIC (decl)) + return MACHOPIC_DEFINED_DATA; + } + + /* function declarations */ + else if (TREE_CODE (decl) == FUNCTION_DECL + && (!DECL_EXTERNAL (decl))) + { + if (TREE_STATIC (decl) + || TREE_ASM_WRITTEN (decl)) + return MACHOPIC_DEFINED_FUNCTION; + } + + for (temp = machopic_defined_list; temp != NULL_TREE; temp = TREE_CHAIN (temp)) + { + if (ident == TREE_VALUE (temp)) + { + if (TREE_CODE (decl) == FUNCTION_DECL) + return MACHOPIC_DEFINED_FUNCTION; + else + return MACHOPIC_DEFINED_DATA; + } + } + + if (TREE_CODE (decl) == FUNCTION_DECL) + { + 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)); +} + +tree +lookup_name_darwin (name) + tree name; +{ + tree val; + + if (!global_bindings_p() + && IDENTIFIER_LOCAL_VALUE (name)) + val = IDENTIFIER_LOCAL_VALUE (name); + else + val = IDENTIFIER_GLOBAL_VALUE (name); + return val; +} + +/* 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 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; +{ + 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)); + } + + { + 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); + + for (temp = machopic_stubs; + temp != NULL_TREE; + temp = TREE_CHAIN (temp)) + { + if (ident == TREE_VALUE (temp)) + return IDENTIFIER_POINTER (TREE_PURPOSE (temp)); + } + + { + 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; +{ + tree temp, ident = get_identifier (name); + + 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; + } +} + +/* 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_for_output (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; +} + +/* For MACHOPIC_INDIRECT_CALL_TARGET below, we need to beware of: + + extern "C" { int f(); } + struct X { int f(); int g(); }; + int X::f() { ::f(); } + int X::g() { ::f(); f();} + + This is hairy. Both calls to "::f()" need to be indirect (i.e., to + appropriate symbol stubs), but since MACHOPIC_NAME_DEFINED_P calls + GET_IDENTIFIER which treats "f" as "X::f", and "X::f" is indeed (being) + defined somewhere in "X"'s inheritance hierarchy, MACHOPIC_NAME_DEFINED_P + returns TRUE when called with "f", which means that + MACHOPIC_INDIRECT_CALL_TARGET uses an "internal" call instead of an + indirect one as it should. + + Our quick-n-dirty solution to this is to call the following + FUNC_NAME_MAYBE_SCOPED routine which (only for C++) checks whether + FNAME -- the name of the function which we're calling -- is NOT a + mangled C++ name, AND if the current function being compiled is a + method, and if so, use an "external" or "indirect" call. + + Note that this function will be called ONLY when MACHOPIC_INDIRECT_TARGET_P + has already indicated that the target is NOT indirect. + + This conservative solution will sometimes make indirect calls where + it might have been possible to make direct ones. + + FUNC_NAME_MAYBE_SCOPED returns 1 to indicate a "C" name (not scoped), + which in turns means we should create a stub for an indirect call. + */ + +static int is_cplusplus = -1; + +static int +func_name_maybe_scoped (fname) + const char *fname; +{ + + if (is_cplusplus < 0) + is_cplusplus = (strcmp (lang_identify (), "cplusplus") == 0); + + if (is_cplusplus) + { + /* If we have a method, then check whether the function we're trying to + call is a "C" function. If so, we should use an indirect call. + + It turns out to be hard to tell whether "we have a method", since + static member functions have a TREE_CODE of FUNCTION_TYPE, as do + namespace-level non-member functions. So here, we always look for + an extern-"C"-like name, and make stubs for them no matter the + calling context. This is temporary, and leaves nagging suspicion + that improvements should be possible here. (I.e., I suspect that + it can still sometimes make stubs where it needn't.) */ + + /* if (1 || TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE) */ + { + /* If fname is of the form "f__1X" or "f__Fv", it's C++. */ + while (*fname == '_') ++fname; /* skip leading underscores */ + while (*fname != 0) + { + if (fname[0] == '_' && fname[1] == '_' + && (fname[2] == 'F' || (fname[2] >= '0' && fname[2] <= '9'))) + return 0; + ++fname; + } + /* Not a C++ mangled name: must be "C", in which case play safe. */ + return 1; + } + } + return 0; +} + +/* 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 (!machopic_name_defined_p (name) || func_name_maybe_scoped (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_for_output (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)) + { + char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp)); + char *stub_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp)); + char *sym; + char *stub; + tree decl = lookup_name_darwin (TREE_VALUE (temp)); + + if (! TREE_USED (temp)) + continue; + + /* Don't emit stubs for static inline functions which have not + been compiled. */ + if (decl + && TREE_CODE (decl) == FUNCTION_DECL + && DECL_INLINE (decl) + && ! TREE_PUBLIC (decl) + && ! TREE_ASM_WRITTEN (decl)) + continue; + + 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 (UNITS_PER_WORD * BITS_PER_UNIT); + assemble_label (lazy_name); + assemble_integer (gen_rtx (SYMBOL_REF, Pmode, sym_name), + GET_MODE_SIZE (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), 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; +} diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h new file mode 100644 index 00000000000..269d78ce983 --- /dev/null +++ b/gcc/config/darwin.h @@ -0,0 +1,763 @@ +/* Target definitions for Darwin (Mac OS X) systems. + 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. */ + +/* The definitions in this file are common to all processor types + running Darwin, which is the kernel for Mac OS X. Darwin is + basically a BSD user layer laid over a Mach kernel, then evolved + for many years (at NeXT) in parallel with other Unix systems. So + while the runtime is a somewhat idiosyncratic Mach-based thing, + other definitions look like they would for a BSD variant. */ + +/* Although NeXT ran on many different architectures, as of Jan 2001 + the only supported Darwin targets are PowerPC and x86. */ + +/* Make the compiler look here for standard stuff. */ + +#undef STANDARD_EXEC_PREFIX +#define STANDARD_EXEC_PREFIX "/usr/libexec/" + +/* Name of the command that invokes the compiler - used in g++.c. */ + +#undef GCC_NAME +#define GCC_NAME "cc" + +/* Never try linking with -lm - used in g++.c. */ + +#define NO_MATH_LIBRARY + +/* We have atexit. */ + +#define HAVE_ATEXIT + +/* Define an empty body for the function do_global_dtors() in libgcc2.c. */ + +#define DO_GLOBAL_DTORS_BODY + +/* The string value for __SIZE_TYPE__. */ + +#ifndef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" +#endif + +/* Type used for ptrdiff_t, as a string used in a declaration. */ + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +/* wchar_t is int. */ + +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 32 + +/* Don't default to pcc-struct-return, because gcc is the only compiler, and + we want to retain compatibility with older gcc versions. */ + +#undef DEFAULT_PCC_STRUCT_RETURN +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* Don't warn about MacOS-style 'APPL' four-char-constants. */ + +#undef WARN_FOUR_CHAR_CONSTANTS +#define WARN_FOUR_CHAR_CONSTANTS 0 + +/* Machine dependent cpp options. */ + +/* The sequence here allows us to get a more specific version number + glued into __APPLE_CC__. Normally this number would be updated as + part of submitting to a release engineering organization. */ + +#ifndef APPLE_CC +#define APPLE_CC 999 +#endif + +#define STRINGIFY_THIS(x) # x +#define REALLY_STRINGIFY(x) STRINGIFY_THIS(x) + +#undef CPP_SPEC +#define CPP_SPEC "-D__APPLE_CC__=" REALLY_STRINGIFY(APPLE_CC) " \ + %{static:-D__STATIC__}%{!static:-D__DYNAMIC__}" + +/* Machine dependent libraries. */ + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{!static:%{!pg:-framework System}%{pg:-framework System,_profile}}" + +#undef LIBGCC_SPEC +#define LIBGCC_SPEC "%{!shared:%{static:-lcc} \ + %{!static:-lcc_dynamic}}" + +/* We specify crt0.o as -lcrt0.o so that ld will search the library path. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{pg:%{static:-lgcrt0.o}%{!static:-lgcrt1.o}} \ + %{!pg:%{static:-lcrt0.o}%{!static:-lcrt1.o}}" + +#undef DOLLARS_IN_IDENTIFIERS +#define DOLLARS_IN_IDENTIFIERS 2 + +/* Allow #sccs (but don't do anything). */ + +#define SCCS_DIRECTIVE + +/* We use Dbx symbol format. */ + +#define DBX_DEBUGGING_INFO + +/* When generating stabs debugging, use N_BINCL entries. */ + +#define DBX_USE_BINCL + +/* There is no limit to the length of stabs strings. */ + +#define DBX_CONTIN_LENGTH 0 + +/* gdb needs a null N_SO at the end of each file for scattered loading. */ + +#undef DBX_OUTPUT_MAIN_SOURCE_FILE_END +#define DBX_OUTPUT_MAIN_SOURCE_FILE_END(FILE, FILENAME) \ +do { text_section (); \ + fprintf (FILE, \ + "\t.stabs \"%s\",%d,0,0,Letext\nLetext:\n", "" , N_SO); \ + } while (0) + +/* Our profiling scheme doesn't LP labels and counter words. */ + +#define NO_PROFILE_COUNTERS + +/* Don't use .gcc_compiled symbols to communicate with GDB; + They interfere with numerically sorted symbol lists. */ + +#undef ASM_IDENTIFY_GCC +#define ASM_IDENTIFY_GCC(asm_out_file) + +#undef INIT_SECTION_ASM_OP +#define INIT_SECTION_ASM_OP + +#undef INVOKE__main + +#undef ASM_OUTPUT_CONSTRUCTOR +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { if (flag_pic) \ + mod_init_section (); \ + else \ + constructor_section (); \ + ASM_OUTPUT_ALIGN (FILE, 1); \ + fprintf (FILE, "\t.long "); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + if (!flag_pic) \ + fprintf (FILE, ".reference .constructors_used\n"); \ + } while (0) + +#undef ASM_OUTPUT_DESTRUCTOR +#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \ + do { if (flag_pic) \ + mod_term_section (); \ + else \ + destructor_section (); \ + ASM_OUTPUT_ALIGN (FILE, 1); \ + fprintf (FILE, "\t.long "); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + if (!flag_pic) \ + fprintf (FILE, ".reference .destructors_used\n"); \ + } while (0) + + +/* Don't output a .file directive. That is only used by the assembler for + error reporting. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) + +#undef ASM_FILE_END +#define ASM_FILE_END(FILE) \ + do { \ + extern const char *language_string; \ + machopic_finish (asm_out_file); \ + if (strcmp (language_string, "GNU C++") == 0) \ + { \ + constructor_section (); \ + destructor_section (); \ + ASM_OUTPUT_ALIGN (FILE, 1); \ + } \ + } while (0) + +/* Give ObjcC methods pretty symbol names. */ + +#undef OBJC_GEN_METHOD_LABEL +#define OBJC_GEN_METHOD_LABEL(BUF,IS_INST,CLASS_NAME,CAT_NAME,SEL_NAME,NUM) \ + do { if (CAT_NAME) \ + sprintf (BUF, "%c[%s(%s) %s]", (IS_INST) ? '-' : '+', \ + (CLASS_NAME), (CAT_NAME), (SEL_NAME)); \ + else \ + sprintf (BUF, "%c[%s %s]", (IS_INST) ? '-' : '+', \ + (CLASS_NAME), (SEL_NAME)); \ + } while (0) + +/* The RTTI data (e.g., __ti4name) is common and public (and static), + but it does need to be referenced via indirect PIC data pointers. + The machopic_define_name calls are telling the machopic subsystem + that the name *is* defined in this module, so it doesn't need to + make them indirect. */ + +#undef ASM_DECLARE_OBJECT_NAME +#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ + do { \ + char *xname = NAME; \ + if (GET_CODE (XEXP (DECL_RTL (DECL), 0)) != SYMBOL_REF) \ + xname = IDENTIFIER_POINTER (DECL_NAME (DECL)); \ + if ((TREE_STATIC (DECL) \ + && (!DECL_COMMON (DECL) || !TREE_PUBLIC (DECL))) \ + || DECL_INITIAL (DECL)) \ + machopic_define_name (xname); \ + ASM_OUTPUT_LABEL (FILE, xname); \ + } while (0) + +/* Wrap new method names in quotes so the assembler doesn't gag. + Make Objective-C internal symbols local. */ + +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + do { \ + if (NAME[0] == '&') \ + { \ + int len = strlen (NAME); \ + if (len > 6 && !strcmp ("$stub", NAME + len - 5)) \ + machopic_validate_stub_or_non_lazy_ptr (NAME, 1); \ + else if (len > 7 && !strcmp ("$stub\"", NAME + len - 6)) \ + machopic_validate_stub_or_non_lazy_ptr (NAME, 1); \ + else if (len > 14 && !strcmp ("$non_lazy_ptr", NAME + len - 13)) \ + machopic_validate_stub_or_non_lazy_ptr (NAME, 0); \ + fputs (&NAME[1], FILE); \ + } \ + else if (NAME[0] == '+' || NAME[0] == '-') \ + fprintf (FILE, "\"%s\"", NAME); \ + else if (!strncmp (NAME, "_OBJC_", 6)) \ + fprintf (FILE, "L%s", NAME); \ + else if (!strncmp (NAME, ".objc_class_name_", 17)) \ + fprintf (FILE, "%s", NAME); \ + else \ + fprintf (FILE, "_%s", NAME); \ + } while (0) + +#undef ALIGN_ASM_OP +#define ALIGN_ASM_OP ".align" + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) != 0) \ + fprintf (FILE, "\t%s %d\n", ALIGN_ASM_OP, (LOG)) + +/* Ensure correct alignment of bss data. */ + +#undef ASM_OUTPUT_ALIGNED_DECL_LOCAL +#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \ + do { \ + fputs (".lcomm ", (FILE)); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ",%u,%u\n", (SIZE), floor_log2 ((ALIGN) / BITS_PER_UNIT)); \ + if ((DECL) && ((TREE_STATIC (DECL) \ + && (!DECL_COMMON (DECL) || !TREE_PUBLIC (DECL))) \ + || DECL_INITIAL (DECL))) \ + machopic_define_name (NAME); \ + } while (0) + +/* Output nothing for #ident. */ + +#undef ASM_OUTPUT_IDENT +#define ASM_OUTPUT_IDENT(FILE, NAME) + +/* The maximum alignment which the object file format can support. + For Mach-O, this is 2^15. */ + +#undef MAX_OFILE_ALIGNMENT +#define MAX_OFILE_ALIGNMENT 0x8000 + +/* Create new Mach-O sections. */ + +#undef SECTION_FUNCTION +#define SECTION_FUNCTION(FUNCTION, SECTION, DIRECTIVE, WAS_TEXT, OBJC) \ +void \ +FUNCTION () \ +{ \ + extern void text_section (); \ + extern void objc_section_init (); \ + extern int flag_no_mach_text_sections; \ + \ + if (WAS_TEXT && flag_no_mach_text_sections) \ + text_section (); \ + else if (in_section != SECTION) \ + { \ + if (OBJC) \ + objc_section_init (); \ + data_section (); \ + if (asm_out_file) \ + fprintf (asm_out_file, "%s\n", DIRECTIVE); \ + in_section = SECTION; \ + } \ +} \ + +#define ALIAS_SECTION(enum_value, alias_name) \ +do { if (!strcmp (alias_name, name)) \ + section_alias[enum_value] = (alias ? get_identifier (alias) : 0); \ + } while (0) + +/* Darwin uses many types of special sections. */ + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS \ + in_const, in_const_data, in_cstring, in_literal4, in_literal8, \ + in_constructor, in_destructor, in_mod_init, in_mod_term, \ + in_objc_class, in_objc_meta_class, in_objc_category, \ + in_objc_class_vars, in_objc_instance_vars, \ + in_objc_cls_meth, in_objc_inst_meth, \ + in_objc_cat_cls_meth, in_objc_cat_inst_meth, \ + in_objc_selector_refs, \ + in_objc_selector_fixup, \ + in_objc_symbols, in_objc_module_info, \ + in_objc_protocol, in_objc_string_object, \ + in_objc_constant_string_object, \ + in_objc_class_names, in_objc_meth_var_names, \ + in_objc_meth_var_types, in_objc_cls_refs, \ + in_machopic_nl_symbol_ptr, \ + in_machopic_lazy_symbol_ptr, \ + in_machopic_symbol_stub, \ + in_machopic_picsymbol_stub, \ + num_sections + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ +SECTION_FUNCTION (const_section, \ + in_const, \ + ".const", 1, 0) \ +SECTION_FUNCTION (const_data_section, \ + in_const_data, \ + ".const_data", 1, 0) \ +SECTION_FUNCTION (cstring_section, \ + in_cstring, \ + ".cstring", 1, 0) \ +SECTION_FUNCTION (literal4_section, \ + in_literal4, \ + ".literal4", 1, 0) \ +SECTION_FUNCTION (literal8_section, \ + in_literal8, \ + ".literal8", 1, 0) \ +SECTION_FUNCTION (constructor_section, \ + in_constructor, \ + ".constructor", 0, 0) \ +SECTION_FUNCTION (mod_init_section, \ + in_mod_init, \ + ".mod_init_func", 0, 0) \ +SECTION_FUNCTION (mod_term_section, \ + in_mod_term, \ + ".mod_term_func", 0, 0) \ +SECTION_FUNCTION (destructor_section, \ + in_destructor, \ + ".destructor", 0, 0) \ +SECTION_FUNCTION (objc_class_section, \ + in_objc_class, \ + ".objc_class", 0, 1) \ +SECTION_FUNCTION (objc_meta_class_section, \ + in_objc_meta_class, \ + ".objc_meta_class", 0, 1) \ +SECTION_FUNCTION (objc_category_section, \ + in_objc_category, \ + ".objc_category", 0, 1) \ +SECTION_FUNCTION (objc_class_vars_section, \ + in_objc_class_vars, \ + ".objc_class_vars", 0, 1) \ +SECTION_FUNCTION (objc_instance_vars_section, \ + in_objc_instance_vars, \ + ".objc_instance_vars", 0, 1) \ +SECTION_FUNCTION (objc_cls_meth_section, \ + in_objc_cls_meth, \ + ".objc_cls_meth", 0, 1) \ +SECTION_FUNCTION (objc_inst_meth_section, \ + in_objc_inst_meth, \ + ".objc_inst_meth", 0, 1) \ +SECTION_FUNCTION (objc_cat_cls_meth_section, \ + in_objc_cat_cls_meth, \ + ".objc_cat_cls_meth", 0, 1) \ +SECTION_FUNCTION (objc_cat_inst_meth_section, \ + in_objc_cat_inst_meth, \ + ".objc_cat_inst_meth", 0, 1) \ +SECTION_FUNCTION (objc_selector_refs_section, \ + in_objc_selector_refs, \ + ".objc_message_refs", 0, 1) \ +SECTION_FUNCTION (objc_selector_fixup_section, \ + in_objc_selector_fixup, \ + ".section __OBJC, __sel_fixup", 0, 1) \ +SECTION_FUNCTION (objc_symbols_section, \ + in_objc_symbols, \ + ".objc_symbols", 0, 1) \ +SECTION_FUNCTION (objc_module_info_section, \ + in_objc_module_info, \ + ".objc_module_info", 0, 1) \ +SECTION_FUNCTION (objc_protocol_section, \ + in_objc_protocol, \ + ".objc_protocol", 0, 1) \ +SECTION_FUNCTION (objc_string_object_section, \ + in_objc_string_object, \ + ".objc_string_object", 0, 1) \ +SECTION_FUNCTION (objc_constant_string_object_section, \ + in_objc_constant_string_object, \ + ".section __OBJC, __cstring_object", 0, 1) \ +SECTION_FUNCTION (objc_class_names_section, \ + in_objc_class_names, \ + ".objc_class_names", 0, 1) \ +SECTION_FUNCTION (objc_meth_var_names_section, \ + in_objc_meth_var_names, \ + ".objc_meth_var_names", 0, 1) \ +SECTION_FUNCTION (objc_meth_var_types_section, \ + in_objc_meth_var_types, \ + ".objc_meth_var_types", 0, 1) \ +SECTION_FUNCTION (objc_cls_refs_section, \ + in_objc_cls_refs, \ + ".objc_cls_refs", 0, 1) \ + \ +SECTION_FUNCTION (machopic_lazy_symbol_ptr_section, \ + in_machopic_lazy_symbol_ptr, \ + ".lazy_symbol_pointer", 0, 0) \ +SECTION_FUNCTION (machopic_nl_symbol_ptr_section, \ + in_machopic_nl_symbol_ptr, \ + ".non_lazy_symbol_pointer", 0, 0) \ +SECTION_FUNCTION (machopic_symbol_stub_section, \ + in_machopic_symbol_stub, \ + ".symbol_stub", 0, 0) \ +SECTION_FUNCTION (machopic_picsymbol_stub_section, \ + in_machopic_picsymbol_stub, \ + ".picsymbol_stub", 0, 0) \ + \ +void \ +objc_section_init () \ +{ \ + static int been_here = 0; \ + \ + if (been_here == 0) \ + { \ + been_here = 1; \ + /* written, cold -> hot */ \ + objc_cat_cls_meth_section (); \ + objc_cat_inst_meth_section (); \ + objc_string_object_section (); \ + objc_constant_string_object_section (); \ + objc_selector_refs_section (); \ + objc_selector_fixup_section (); \ + objc_cls_refs_section (); \ + objc_class_section (); \ + objc_meta_class_section (); \ + /* shared, hot -> cold */ \ + objc_cls_meth_section (); \ + objc_inst_meth_section (); \ + objc_protocol_section (); \ + objc_class_names_section (); \ + objc_meth_var_types_section (); \ + objc_meth_var_names_section (); \ + objc_category_section (); \ + objc_class_vars_section (); \ + objc_instance_vars_section (); \ + objc_module_info_section (); \ + objc_symbols_section (); \ + } \ +} \ +static tree section_alias[(int) num_sections]; \ +void try_section_alias () \ +{ \ + if (section_alias[in_section] && asm_out_file) \ + fprintf (asm_out_file, "%s\n", \ + IDENTIFIER_POINTER (section_alias[in_section])); \ +} \ +void alias_section (name, alias) \ + char *name, *alias; \ +{ \ + ALIAS_SECTION (in_data, "data"); \ + ALIAS_SECTION (in_text, "text"); \ + ALIAS_SECTION (in_const, "const"); \ + ALIAS_SECTION (in_const_data, "const_data"); \ + ALIAS_SECTION (in_cstring, "cstring"); \ + ALIAS_SECTION (in_literal4, "literal4"); \ + ALIAS_SECTION (in_literal8, "literal8"); \ +} + +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION const_section + +#undef SELECT_SECTION +#define SELECT_SECTION(exp,reloc) \ + do \ + { \ + if (TREE_CODE (exp) == STRING_CST) \ + { \ + if (flag_writable_strings) \ + data_section (); \ + else if (TREE_STRING_LENGTH (exp) != \ + strlen (TREE_STRING_POINTER (exp)) + 1) \ + readonly_data_section (); \ + else \ + cstring_section (); \ + } \ + else if (TREE_CODE (exp) == INTEGER_CST \ + || TREE_CODE (exp) == REAL_CST) \ + { \ + tree size = TYPE_SIZE (TREE_TYPE (exp)); \ + \ + if (TREE_CODE (size) == INTEGER_CST && \ + TREE_INT_CST_LOW (size) == 4 && \ + TREE_INT_CST_HIGH (size) == 0) \ + literal4_section (); \ + else if (TREE_CODE (size) == INTEGER_CST && \ + TREE_INT_CST_LOW (size) == 8 && \ + TREE_INT_CST_HIGH (size) == 0) \ + literal8_section (); \ + else \ + readonly_data_section (); \ + } \ + else if (TREE_CODE (exp) == CONSTRUCTOR \ + && TREE_TYPE (exp) \ + && TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE \ + && TYPE_NAME (TREE_TYPE (exp))) \ + { \ + tree name = TYPE_NAME (TREE_TYPE (exp)); \ + if (TREE_CODE (name) == TYPE_DECL) \ + name = DECL_NAME (name); \ + if (!strcmp (IDENTIFIER_POINTER (name), "NSConstantString")) \ + objc_constant_string_object_section (); \ + else if (!strcmp (IDENTIFIER_POINTER (name), "NXConstantString")) \ + objc_string_object_section (); \ + else if (TREE_READONLY (exp) || TREE_CONSTANT (exp)) \ + { \ + if (TREE_SIDE_EFFECTS (exp) || flag_pic && reloc) \ + const_data_section (); \ + else \ + readonly_data_section (); \ + } \ + else \ + data_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)) \ + { \ + const char *name = IDENTIFIER_POINTER (DECL_NAME (exp)); \ + \ + if (!strncmp (name, "_OBJC_CLASS_METHODS_", 20)) \ + objc_cls_meth_section (); \ + else if (!strncmp (name, "_OBJC_INSTANCE_METHODS_", 23)) \ + objc_inst_meth_section (); \ + else if (!strncmp (name, "_OBJC_CATEGORY_CLASS_METHODS_", 20)) \ + objc_cat_cls_meth_section (); \ + else if (!strncmp (name, "_OBJC_CATEGORY_INSTANCE_METHODS_", 23)) \ + objc_cat_inst_meth_section (); \ + else if (!strncmp (name, "_OBJC_CLASS_VARIABLES_", 22)) \ + objc_class_vars_section (); \ + else if (!strncmp (name, "_OBJC_INSTANCE_VARIABLES_", 25)) \ + objc_instance_vars_section (); \ + else if (!strncmp (name, "_OBJC_CLASS_PROTOCOLS_", 22)) \ + objc_cat_cls_meth_section (); \ + else if (!strncmp (name, "_OBJC_CLASS_NAME_", 17)) \ + objc_class_names_section (); \ + else if (!strncmp (name, "_OBJC_METH_VAR_NAME_", 20)) \ + objc_meth_var_names_section (); \ + else if (!strncmp (name, "_OBJC_METH_VAR_TYPE_", 20)) \ + objc_meth_var_types_section (); \ + else if (!strncmp (name, "_OBJC_CLASS_REFERENCES", 22)) \ + objc_cls_refs_section (); \ + else if (!strncmp (name, "_OBJC_CLASS_", 12)) \ + objc_class_section (); \ + else if (!strncmp (name, "_OBJC_METACLASS_", 16)) \ + objc_meta_class_section (); \ + else if (!strncmp (name, "_OBJC_CATEGORY_", 15)) \ + objc_category_section (); \ + else if (!strncmp (name, "_OBJC_SELECTOR_REFERENCES", 25)) \ + objc_selector_refs_section (); \ + else if (!strncmp (name, "_OBJC_SELECTOR_FIXUP", 20)) \ + objc_selector_fixup_section (); \ + else if (!strncmp (name, "_OBJC_SYMBOLS", 13)) \ + objc_symbols_section (); \ + else if (!strncmp (name, "_OBJC_MODULES", 13)) \ + objc_module_info_section (); \ + else if (!strncmp (name, "_OBJC_PROTOCOL_INSTANCE_METHODS_", 32)) \ + objc_cat_inst_meth_section (); \ + else if (!strncmp (name, "_OBJC_PROTOCOL_CLASS_METHODS_", 29)) \ + objc_cat_cls_meth_section (); \ + else if (!strncmp (name, "_OBJC_PROTOCOL_REFS_", 20)) \ + objc_cat_cls_meth_section (); \ + else if (!strncmp (name, "_OBJC_PROTOCOL_", 15)) \ + objc_protocol_section (); \ + else if ((TREE_READONLY (exp) || TREE_CONSTANT (exp)) \ + && !TREE_SIDE_EFFECTS (exp)) \ + { if (flag_pic && reloc ) const_data_section (); \ + else readonly_data_section (); } \ + else \ + data_section (); \ + } \ + else if (TREE_READONLY (exp) || TREE_CONSTANT (exp)) \ + { \ + if (TREE_SIDE_EFFECTS (exp) || flag_pic && reloc) \ + const_data_section (); \ + else \ + readonly_data_section (); \ + } \ + else \ + data_section (); \ + try_section_alias (); \ + } \ + while (0) + +#undef SELECT_RTX_SECTION +#define SELECT_RTX_SECTION(mode, rtx) \ + do \ + { \ + if (GET_MODE_SIZE (mode) == 8) \ + literal8_section (); \ + else if (GET_MODE_SIZE (mode) == 4) \ + literal4_section (); \ + else \ + const_section (); \ + } \ + while (0) + +#define DECLARE_UNRESOLVED_REFERENCE(NAME) \ + do { extern FILE* asm_out_file; \ + if (asm_out_file) { \ + if (flag_pic) \ + fprintf (asm_out_file, "\t.lazy_reference "); \ + else \ + fprintf (asm_out_file, "\t.reference "); \ + assemble_name (asm_out_file, NAME); \ + fprintf (asm_out_file, "\n"); \ + } \ + } while (0) + +#define DECLARE_CLASS_REFERENCE(NAME) \ + do { extern FILE* asm_out_file; \ + if (asm_out_file) { \ + fprintf (asm_out_file, "\t"); \ + assemble_name (asm_out_file, NAME); \ + fprintf (asm_out_file, "=0\n"); \ + assemble_global (NAME); \ + } \ + } while (0) + +#undef ASM_GLOBALIZE_LABEL +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { const char* _x = (NAME); if (!!strncmp (_x, "_OBJC_", 6)) { \ + (fputs (".globl ", FILE), assemble_name (FILE, _x), fputs ("\n", FILE)); \ + }} while (0) + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* This is how to output an internal numbered label where PREFIX is + the class of label and NUM is the number within the class. */ + +#undef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* Since we have a separate readonly data section, define this so that + jump tables end up in text rather than data. */ + +#ifndef JUMP_TABLES_IN_TEXT_SECTION +#define JUMP_TABLES_IN_TEXT_SECTION 1 +#endif + +/* Symbolic names for various things we might know about a symbol. */ + +enum machopic_addr_class { + MACHOPIC_UNDEFINED, + MACHOPIC_DEFINED_DATA, + MACHOPIC_UNDEFINED_DATA, + MACHOPIC_DEFINED_FUNCTION, + MACHOPIC_UNDEFINED_FUNCTION +}; + +/* Macros defining the various PIC cases. */ + +#define MACHOPIC_INDIRECT (flag_pic) +#define MACHOPIC_JUST_INDIRECT (flag_pic == 1) +#define MACHOPIC_PURE (flag_pic == 2) + +#define GEN_BINDER_NAME_FOR_STUB(BUF,STUB,STUB_LENGTH) \ + do { \ + const char *stub_ = (STUB); \ + char *buffer_ = (BUF); \ + strcpy (buffer_, stub_); \ + if (stub_[0] == '"') \ + { \ + strcpy (buffer_ + (STUB_LENGTH) - 1, "_binder\""); \ + } \ + else \ + { \ + strcpy (buffer_ + (STUB_LENGTH), "_binder"); \ + } \ + } while (0) + +#define GEN_SYMBOL_NAME_FOR_SYMBOL(BUF,SYMBOL,SYMBOL_LENGTH) \ + do { \ + const char *symbol_ = (SYMBOL); \ + char *buffer_ = (BUF); \ + if (name_needs_quotes (symbol_) && symbol_[0] != '"') \ + { \ + sprintf (buffer_, "\"%s\"", symbol_); \ + } \ + else \ + { \ + strcpy (buffer_, symbol_); \ + } \ + } while (0) + +/* Given a symbol name string, create the lazy pointer version + of the symbol name. */ + +#define GEN_LAZY_PTR_NAME_FOR_SYMBOL(BUF,SYMBOL,SYMBOL_LENGTH) \ + do { \ + const char *symbol_ = (SYMBOL); \ + char *buffer_ = (BUF); \ + if (symbol_[0] == '"') \ + { \ + strcpy (buffer_, "\"L"); \ + strcpy (buffer_ + 2, symbol_ + 1); \ + strcpy (buffer_ + (SYMBOL_LENGTH), "$lazy_ptr\""); \ + } \ + else if (name_needs_quotes (symbol_)) \ + { \ + strcpy (buffer_, "\"L"); \ + strcpy (buffer_ + 2, symbol_); \ + strcpy (buffer_ + (SYMBOL_LENGTH) + 2, "$lazy_ptr\""); \ + } \ + else \ + { \ + strcpy (buffer_, "L"); \ + strcpy (buffer_ + 1, symbol_); \ + strcpy (buffer_ + (SYMBOL_LENGTH) + 1, "$lazy_ptr"); \ + } \ + } while (0) + diff --git a/gcc/config/rs6000/darwin.h b/gcc/config/rs6000/darwin.h new file mode 100644 index 00000000000..aef5d722e82 --- /dev/null +++ b/gcc/config/rs6000/darwin.h @@ -0,0 +1,175 @@ +/* Target definitions for PowerPC running Darwin (Mac OS X). + Copyright (C) 1997, 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. */ + +/* The "Darwin ABI" is mostly like AIX, but with some key differences. */ + +#define DEFAULT_ABI ABI_DARWIN + +/* The object file format is Mach-O. */ + +#define TARGET_OBJECT_FORMAT OBJECT_MACHO + +/* We're not ever going to do TOCs. */ + +#define TARGET_TOC 0 +#define TARGET_NO_TOC 1 + +#define CPP_PREDEFINES "-D__ppc__ -D__NATURAL_ALIGNMENT__ -D__MACH__ -D__BIG_ENDIAN__ -D__APPLE__" + +/* We want -fPIC by default, unless we're using -static to compile for + the kernel or some such. */ + +#define CC1_SPEC "%{!static:-fPIC}" + +#define FIXED_R13 0 + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_POWERPC | MASK_MULTIPLE | MASK_NEW_MNEMONICS \ + | MASK_NO_FP_IN_TOC | MASK_NO_SUM_IN_TOC) + +/* Base register for access to local variables of the function. */ + +#undef FRAME_POINTER_REGNUM +#define FRAME_POINTER_REGNUM 30 + +#undef PIC_OFFSET_TABLE_REGNUM +#define PIC_OFFSET_TABLE_REGNUM 31 + +#undef STACK_BOUNDARY +#define STACK_BOUNDARY 128 + +/* Pad the outgoing args area to 16 bytes instead of the usual 8. */ + +#undef STARTING_FRAME_OFFSET +#define STARTING_FRAME_OFFSET \ + (RS6000_ALIGN (current_function_outgoing_args_size, 16) \ + + RS6000_VARARGS_AREA \ + + RS6000_SAVE_AREA) + +#undef STACK_DYNAMIC_OFFSET +#define STACK_DYNAMIC_OFFSET(FUNDECL) \ + (RS6000_ALIGN (current_function_outgoing_args_size, 16) \ + + (STACK_POINTER_OFFSET)) + +/* Define cutoff for using external functions to save floating point. + Currently on Darwin, always use inline stores. */ + +#undef FP_SAVE_INLINE +#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 64) + +/* Always use the "debug" register names, they're what the assembler + wants to see. */ + +#undef REGISTER_NAMES +#define REGISTER_NAMES DEBUG_REGISTER_NAMES + +/* This outputs NAME to FILE. */ + +#undef RS6000_OUTPUT_BASENAME +#define RS6000_OUTPUT_BASENAME(FILE, NAME) \ + assemble_name (FILE, NAME); + +/* Output before instructions. */ +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#undef ASM_GLOBALIZE_LABEL +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs ("\t.globl ", FILE); \ + RS6000_OUTPUT_BASENAME (FILE, NAME); putc ('\n', FILE);} while (0) + +/* This is how to output an internal label prefix. rs6000.c uses this + when generating traceback tables. */ +/* Not really used for Darwin? */ + +#undef ASM_OUTPUT_INTERNAL_LABEL_PREFIX +#define ASM_OUTPUT_INTERNAL_LABEL_PREFIX(FILE,PREFIX) \ + fprintf (FILE, "%s", PREFIX) + +#undef TEXT_SECTION_ASM_OP +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#undef DATA_SECTION_ASM_OP +#define DATA_SECTION_ASM_OP ".data" + +/* This says how to output an assembler line to define a global common + symbol. */ +/* ? */ +#undef ASM_OUTPUT_ALIGNED_COMMON +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ + do { fputs (".comm ", (FILE)); \ + RS6000_OUTPUT_BASENAME ((FILE), (NAME)); \ + fprintf ((FILE), ",%d\n", (SIZE)); } while (0) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %d\n", SIZE) + +/* FP save and restore routines. */ +#define SAVE_FP_PREFIX "._savef" +#define SAVE_FP_SUFFIX "" +#define RESTORE_FP_PREFIX "._restf" +#define RESTORE_FP_SUFFIX "" + +/* Generate insns to call the profiler. */ + +#define PROFILE_HOOK(LABEL) output_profile_hook (LABEL) + +/* Function name to call to do profiling. */ + +#define RS6000_MCOUNT "*mcount" + +/* Since Darwin doesn't do TOCs, stub this out. */ + +#define ASM_OUTPUT_SPECIAL_POOL_ENTRY_P(X, MODE) 0 + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. + + On the RS/6000, we have to return NO_REGS when we want to reload a + floating-point CONST_DOUBLE to force it to be copied to memory. + + Don't allow R0 when loading the address of, or otherwise furtling with, + a SYMBOL_REF. */ + +#undef PREFERRED_RELOAD_CLASS +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + (((GET_CODE (X) == CONST_DOUBLE \ + && GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT) \ + ? NO_REGS \ + : (GET_MODE_CLASS (GET_MODE (X)) == MODE_INT \ + && (CLASS) == NON_SPECIAL_REGS) \ + ? GENERAL_REGS \ + : (GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == HIGH) \ + ? BASE_REGS \ + : (CLASS))) + +/* Fix for emit_group_load (): force large constants to be pushed via regs. */ +#define ALWAYS_PUSH_CONSTS_USING_REGS_P 1 diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 31e5716bcf8..9f8f984c7b1 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -108,8 +108,12 @@ extern void rs6000_emit_eh_toc_restore PARAMS ((rtx)); extern void rs6000_emit_move PARAMS ((rtx, rtx, enum machine_mode)); extern rtx rs6000_legitimize_address PARAMS ((rtx, rtx, enum machine_mode)); extern void rs6000_select_rtx_section PARAMS ((enum machine_mode, rtx)); + extern rtx rs6000_return_addr PARAMS ((int, rtx)); extern void rs6000_output_symbol_ref PARAMS ((FILE*, rtx)); + +extern rtx rs6000_machopic_legitimize_pic_address PARAMS ((rtx orig, enum machine_mode mode, rtx reg)); + #endif /* RTX_CODE */ #ifdef TREE_CODE @@ -139,6 +143,7 @@ extern void rs6000_unique_section PARAMS ((tree, int)); /* expr.h defines ARGS_SIZE_RTX and `enum direction' */ extern enum direction function_arg_padding PARAMS ((enum machine_mode, tree)); #endif /* ARGS_SIZE_RTX */ + #endif /* TREE_CODE */ extern void optimization_options PARAMS ((int, int)); @@ -172,3 +177,5 @@ extern void rs6000_emit_load_toc_table PARAMS ((int)); extern void rs6000_aix_emit_builtin_unwind_init PARAMS ((void)); extern void rs6000_emit_epilogue PARAMS ((int)); extern void debug_stack_info PARAMS ((rs6000_stack_t *)); + +extern void machopic_output_stub PARAMS ((FILE *, const char *, const char *)); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 4b24bfb800f..18e117ee3cb 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -1526,6 +1526,19 @@ rs6000_legitimize_address (x, oldx, mode) emit_insn (gen_elf_high (reg, (x))); return gen_rtx_LO_SUM (Pmode, reg, (x)); } + else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC + && ! flag_pic + && GET_CODE (x) != CONST_INT + && GET_CODE (x) != CONST_DOUBLE + && CONSTANT_P (x) + && (TARGET_HARD_FLOAT || mode != DFmode) + && mode != DImode + && mode != TImode) + { + rtx reg = gen_reg_rtx (Pmode); + emit_insn (gen_macho_high (reg, (x))); + return gen_rtx_LO_SUM (Pmode, reg, (x)); + } else if (TARGET_TOC && CONSTANT_POOL_EXPR_P (x) && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), Pmode)) @@ -1644,7 +1657,8 @@ rs6000_emit_move (dest, source, mode) return; } - if (TARGET_ELF && TARGET_NO_TOC && ! flag_pic + if ((TARGET_ELF || DEFAULT_ABI == ABI_DARWIN) + && TARGET_NO_TOC && ! flag_pic && mode == Pmode && CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != HIGH @@ -1670,6 +1684,13 @@ rs6000_emit_move (dest, source, mode) operands[1] = new_ref; } + if (DEFAULT_ABI == ABI_DARWIN) + { + emit_insn (gen_macho_high (target, operands[1])); + emit_insn (gen_macho_low (operands[0], target, operands[1])); + return; + } + emit_insn (gen_elf_high (target, operands[1])); emit_insn (gen_elf_low (operands[0], target, operands[1])); return; @@ -1708,6 +1729,21 @@ rs6000_emit_move (dest, source, mode) if (GET_CODE (operands[1]) != LABEL_REF) emit_insn (gen_rtx_USE (VOIDmode, operands[1])); + /* Darwin uses a special PIC legitimizer. */ + if (DEFAULT_ABI == ABI_DARWIN && flag_pic) + { + rtx temp_reg = ((reload_in_progress || reload_completed) + ? operands[0] : NULL); + +#if TARGET_MACHO + operands[1] = + rs6000_machopic_legitimize_pic_address (operands[1], mode, + temp_reg); +#endif + emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1])); + return; + } + /* If we are to limit the number of things we put in the TOC and this is a symbol plus a constant we can add in one insn, just put the symbol in the TOC and add the constant. Don't do @@ -4296,6 +4332,7 @@ print_operand (file, x, code) case ABI_V4: case ABI_AIX_NODESC: case ABI_SOLARIS: + case ABI_DARWIN: break; } } @@ -4655,8 +4692,10 @@ first_reg_to_save () if (regs_ever_live[first_reg] && (! call_used_regs[first_reg] || (first_reg == PIC_OFFSET_TABLE_REGNUM - && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) - && flag_pic == 1))) + && (((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) + && flag_pic == 1) + || (DEFAULT_ABI == ABI_DARWIN + && flag_pic))))) break; if (profile_flag) @@ -4665,7 +4704,7 @@ first_reg_to_save () before/after the .__mcount call plus an additional register for the static chain, if needed; use registers from 30 down to 22 to do this. */ - if (DEFAULT_ABI == ABI_AIX) + if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN) { int last_parm_reg, profile_first_reg; @@ -4683,6 +4722,12 @@ first_reg_to_save () Skip reg 31 which may contain the frame pointer. */ profile_first_reg = (33 - last_parm_reg - (current_function_needs_context ? 1 : 0)); +#if TARGET_MACHO + /* Need to skip another reg to account for R31 being PICBASE + (when flag_pic is set) or R30 being used as the frame + pointer (when flag_pic is not set). */ + --profile_first_reg; +#endif /* Do not save frame pointer if no parameters needs to be saved. */ if (profile_first_reg == 31) profile_first_reg = 32; @@ -4700,6 +4745,12 @@ first_reg_to_save () } } +#if TARGET_MACHO + if (flag_pic && current_function_uses_pic_offset_table && + (first_reg > PIC_OFFSET_TABLE_REGNUM)) + return PIC_OFFSET_TABLE_REGNUM; +#endif + return first_reg; } @@ -4722,7 +4773,7 @@ first_fp_reg_to_save () complicated by having two separate calling sequences, the AIX calling sequence and the V.4 calling sequence. - AIX stack frames look like: + AIX (and Darwin/Mac OS) stack frames look like: 32-bit 64-bit SP----> +---------------------------------------+ | back chain to caller | 0 0 @@ -4821,8 +4872,10 @@ rs6000_stack_info () info_ptr->first_gp_reg_save = first_reg_to_save (); /* Assume that we will have to save PIC_OFFSET_TABLE_REGNUM, even if it currently looks like we won't. */ - if (flag_pic == 1 - && (abi == ABI_V4 || abi == ABI_SOLARIS) + if (((flag_pic == 1 + && (abi == ABI_V4 || abi == ABI_SOLARIS)) + || (flag_pic && + abi == ABI_DARWIN)) && info_ptr->first_gp_reg_save > PIC_OFFSET_TABLE_REGNUM) info_ptr->gp_size = reg_size * (32 - PIC_OFFSET_TABLE_REGNUM); else @@ -4845,6 +4898,7 @@ rs6000_stack_info () && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save)) || (abi == ABI_V4 && current_function_calls_alloca) || (abi == ABI_SOLARIS && current_function_calls_alloca) + || (DEFAULT_ABI == ABI_DARWIN && flag_pic && current_function_uses_pic_offset_table) || info_ptr->calls_p) { info_ptr->lr_save_p = 1; @@ -4886,6 +4940,8 @@ rs6000_stack_info () + info_ptr->cr_size + info_ptr->lr_size + info_ptr->toc_size, 8); + if (DEFAULT_ABI == ABI_DARWIN) + info_ptr->save_size = RS6000_ALIGN (info_ptr->save_size, 16); /* Calculate the offsets */ switch (abi) @@ -4896,6 +4952,7 @@ rs6000_stack_info () case ABI_AIX: case ABI_AIX_NODESC: + case ABI_DARWIN: info_ptr->fp_save_offset = - info_ptr->fp_size; info_ptr->gp_save_offset = info_ptr->fp_save_offset - info_ptr->gp_size; info_ptr->ehrd_offset = info_ptr->gp_save_offset - ehrd_size; @@ -4942,7 +4999,7 @@ rs6000_stack_info () else info_ptr->push_p = (frame_pointer_needed - || write_symbols != NO_DEBUG + || (abi != ABI_DARWIN && write_symbols != NO_DEBUG) || ((total_raw_size - info_ptr->fixed_size) > (TARGET_32BIT ? 220 : 288))); @@ -4985,6 +5042,7 @@ debug_stack_info (info) case ABI_NONE: abi_string = "NONE"; break; case ABI_AIX: abi_string = "AIX"; break; case ABI_AIX_NODESC: abi_string = "AIX"; break; + case ABI_DARWIN: abi_string = "Darwin"; break; case ABI_V4: abi_string = "V.4"; break; case ABI_SOLARIS: abi_string = "Solaris"; break; } @@ -5740,8 +5798,10 @@ rs6000_emit_prologue () if ((regs_ever_live[info->first_gp_reg_save+i] && ! call_used_regs[info->first_gp_reg_save+i]) || (i+info->first_gp_reg_save == PIC_OFFSET_TABLE_REGNUM - && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) - && flag_pic == 1)) + && (((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) + && flag_pic == 1) + || (DEFAULT_ABI == ABI_DARWIN + && flag_pic)))) { rtx addr, reg, mem; reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); @@ -5858,6 +5918,18 @@ rs6000_emit_prologue () emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), gen_rtx_REG (Pmode, 11)); } + + if (DEFAULT_ABI == ABI_DARWIN + && flag_pic && current_function_uses_pic_offset_table) + { + rtx dest = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM); + + rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest))); + + rs6000_maybe_dead ( + emit_move_insn (gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM), + gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM))); + } } @@ -6051,8 +6123,10 @@ rs6000_emit_epilogue (sibcall) if ((regs_ever_live[info->first_gp_reg_save+i] && ! call_used_regs[info->first_gp_reg_save+i]) || (i+info->first_gp_reg_save == PIC_OFFSET_TABLE_REGNUM - && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) - && flag_pic == 1)) + && (((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) + && flag_pic == 1) + || (DEFAULT_ABI == ABI_DARWIN + && flag_pic)))) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->gp_save_offset @@ -6626,6 +6700,17 @@ output_mi_thunk (file, thunk_fndecl, delta, function) if (flag_pic) fputs ("@plt", file); putc ('\n', file); break; + +#if TARGET_MACHO + case ABI_DARWIN: + fprintf (file, "\tb %s", prefix); + if (flag_pic && !machopic_name_defined_p (fname)) + assemble_name (file, machopic_stub_name (fname)); + else + assemble_name (file, fname); + putc ('\n', file); + break; +#endif } } } @@ -7226,6 +7311,28 @@ output_profile_hook (labelno) emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 1, fun, Pmode); } + else if (DEFAULT_ABI == ABI_DARWIN) + { + char *mcount_name = RS6000_MCOUNT; + int caller_addr_regno = LINK_REGISTER_REGNUM; + + /* Be conservative and always set this, at least for now. */ + current_function_uses_pic_offset_table = 1; + +#if TARGET_MACHO + /* For PIC code, set up a stub and collect the caller's address + from r0, which is where the prologue puts it. */ + if (flag_pic) + { + mcount_name = machopic_stub_name (mcount_name); + if (current_function_uses_pic_offset_table) + caller_addr_regno = 0; + } +#endif + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, mcount_name), + 0, VOIDmode, 1, + gen_rtx_REG (Pmode, caller_addr_regno), Pmode); + } } /* Write function profiler code. */ @@ -7296,6 +7403,7 @@ output_function_profiler (file, labelno) break; case ABI_AIX: + case ABI_DARWIN: /* Don't do anything, done in output_profile_hook (). */ break; @@ -7834,4 +7942,325 @@ rs6000_add_gc_roots () toc_hash_table = htab_create (1021, toc_hash_function, toc_hash_eq, NULL); ggc_add_root (&toc_hash_table, 1, sizeof (toc_hash_table), toc_hash_mark_table); + +#if TARGET_MACHO + machopic_add_gc_roots (); +#endif +} + +#if TARGET_MACHO + +#if 0 +/* Returns 1 if OP is either a symbol reference or a sum of a symbol + reference and a constant. */ + +int +symbolic_operand (op) + register rtx op; +{ + switch (GET_CODE (op)) + { + case SYMBOL_REF: + case LABEL_REF: + return 1; + case CONST: + op = XEXP (op, 0); + return (GET_CODE (op) == SYMBOL_REF || + (GET_CODE (XEXP (op, 0)) == SYMBOL_REF + || GET_CODE (XEXP (op, 0)) == LABEL_REF) + && GET_CODE (XEXP (op, 1)) == CONST_INT); + default: + return 0; + } } +#endif + +#ifdef RS6000_LONG_BRANCH + +static tree stub_list = 0; + +/* ADD_COMPILER_STUB adds the compiler generated stub for handling + procedure calls to the linked list. */ + +void +add_compiler_stub (label_name, function_name, line_number) + tree label_name; + tree function_name; + int line_number; +{ + tree stub = build_tree_list (function_name, label_name); + TREE_TYPE (stub) = build_int_2 (line_number, 0); + TREE_CHAIN (stub) = stub_list; + stub_list = stub; +} + +#define STUB_LABEL_NAME(STUB) TREE_VALUE (STUB) +#define STUB_FUNCTION_NAME(STUB) TREE_PURPOSE (STUB) +#define STUB_LINE_NUMBER(STUB) TREE_INT_CST_LOW (TREE_TYPE (STUB)) + +/* OUTPUT_COMPILER_STUB outputs the compiler generated stub for handling + procedure calls from the linked list and initializes the linked list. */ + +void output_compiler_stub () +{ + char tmp_buf[256]; + char label_buf[256]; + char *label; + tree tmp_stub, stub; + + if (!flag_pic) + for (stub = stub_list; stub; stub = TREE_CHAIN (stub)) + { + fprintf (asm_out_file, + "%s:\n", IDENTIFIER_POINTER(STUB_LABEL_NAME(stub))); + +#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) + if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) + fprintf (asm_out_file, "\t.stabd 68,0,%d\n", STUB_LINE_NUMBER(stub)); +#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ + + if (IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub))[0] == '*') + strcpy (label_buf, + IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub))+1); + else + { + label_buf[0] = '_'; + strcpy (label_buf+1, + IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub))); + } + + strcpy (tmp_buf, "lis r12,hi16("); + strcat (tmp_buf, label_buf); + strcat (tmp_buf, ")\n\tori r12,r12,lo16("); + strcat (tmp_buf, label_buf); + strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr"); + output_asm_insn (tmp_buf, 0); + +#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) + if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) + fprintf(asm_out_file, "\t.stabd 68,0,%d\n", STUB_LINE_NUMBER (stub)); +#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ + } + + stub_list = 0; +} + +/* NO_PREVIOUS_DEF checks in the link list whether the function name is + already there or not. */ + +int no_previous_def (function_name) + tree function_name; +{ + tree stub; + for (stub = stub_list; stub; stub = TREE_CHAIN (stub)) + if (function_name == STUB_FUNCTION_NAME (stub)) + return 0; + return 1; +} + +/* GET_PREV_LABEL gets the label name from the previous definition of + the function. */ + +tree get_prev_label (function_name) + tree function_name; +{ + tree stub; + for (stub = stub_list; stub; stub = TREE_CHAIN (stub)) + if (function_name == STUB_FUNCTION_NAME (stub)) + return STUB_LABEL_NAME (stub); + return 0; +} + +/* INSN is either a function call or a millicode call. It may have an + unconditional jump in its delay slot. + + CALL_DEST is the routine we are calling. */ + +char * +output_call (insn, call_dest, operand_number) + rtx insn; + rtx call_dest; + int operand_number; +{ + static char buf[256]; + if (GET_CODE (call_dest) == SYMBOL_REF && TARGET_LONG_BRANCH && !flag_pic) + { + tree labelname; + tree funname = get_identifier (XSTR (call_dest, 0)); + + if (no_previous_def (funname)) + { + int line_number; + rtx label_rtx = gen_label_rtx (); + char *label_buf, temp_buf[256]; + ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L", + CODE_LABEL_NUMBER (label_rtx)); + label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf; + labelname = get_identifier (label_buf); + for (; insn && GET_CODE (insn) != NOTE; insn = PREV_INSN (insn)); + if (insn) + line_number = NOTE_LINE_NUMBER (insn); + add_compiler_stub (labelname, funname, line_number); + } + else + labelname = get_prev_label (funname); + + sprintf (buf, "jbsr %%z%d,%.246s", + operand_number, IDENTIFIER_POINTER (labelname)); + return buf; + } + else + { + sprintf (buf, "bl %%z%d", operand_number); + return buf; + } +} + +#endif /* RS6000_LONG_BRANCH */ + +#define GEN_LOCAL_LABEL_FOR_SYMBOL(BUF,SYMBOL,LENGTH,N) \ + do { \ + const char *symbol_ = (SYMBOL); \ + char *buffer_ = (BUF); \ + if (symbol_[0] == '"') \ + { \ + sprintf(buffer_, "\"L%d$%s", (N), symbol_+1); \ + } \ + else if (name_needs_quotes(symbol_)) \ + { \ + sprintf(buffer_, "\"L%d$%s\"", (N), symbol_); \ + } \ + else \ + { \ + sprintf(buffer_, "L%d$%s", (N), symbol_); \ + } \ + } while (0) + + +/* Generate PIC and indirect symbol stubs. */ + +void +machopic_output_stub (file, symb, stub) + FILE *file; + const char *symb, *stub; +{ + unsigned int length; + char *binder_name, *symbol_name, *lazy_ptr_name; + char *local_label_0, *local_label_1, *local_label_2; + static int label = 0; + + label += 1; + + length = strlen (stub); + binder_name = alloca (length + 32); + GEN_BINDER_NAME_FOR_STUB (binder_name, stub, length); + + length = strlen (symb); + symbol_name = alloca (length + 32); + GEN_SYMBOL_NAME_FOR_SYMBOL (symbol_name, symb, length); + + lazy_ptr_name = alloca (length + 32); + GEN_LAZY_PTR_NAME_FOR_SYMBOL (lazy_ptr_name, symb, length); + + local_label_0 = alloca (length + 32); + GEN_LOCAL_LABEL_FOR_SYMBOL (local_label_0, symb, length, 0); + + local_label_1 = alloca (length + 32); + GEN_LOCAL_LABEL_FOR_SYMBOL (local_label_1, symb, length, 1); + + local_label_2 = alloca (length + 32); + GEN_LOCAL_LABEL_FOR_SYMBOL (local_label_2, symb, length, 2); + + if (flag_pic == 2) + machopic_picsymbol_stub_section (); + else + machopic_symbol_stub_section (); + + fprintf (file, "%s:\n", stub); + fprintf (file, "\t.indirect_symbol %s\n", symbol_name); + + if (flag_pic == 2) + { + fprintf (file, "\tmflr r0\n"); + fprintf (file, "\tbcl 20,31,%s\n", local_label_0); + fprintf (file, "%s:\n\tmflr r11\n", local_label_0); + fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n", + lazy_ptr_name, local_label_0); + fprintf (file, "\tmtlr r0\n"); + fprintf (file, "\tlwz r12,lo16(%s-%s)(r11)\n", + lazy_ptr_name, local_label_0); + fprintf (file, "\tmtctr r12\n"); + fprintf (file, "\taddi r11,r11,lo16(%s-%s)\n", + lazy_ptr_name, local_label_0); + fprintf (file, "\tbctr\n"); + } + else + fprintf (file, "non-pure not supported\n"); + + machopic_lazy_symbol_ptr_section (); + fprintf (file, "%s:\n", lazy_ptr_name); + fprintf (file, "\t.indirect_symbol %s\n", symbol_name); + fprintf (file, "\t.long dyld_stub_binding_helper\n"); +} + +/* Legitimize PIC addresses. If the address is already + position-independent, we return ORIG. Newly generated + position-independent addresses go into a reg. This is REG if non + zero, otherwise we allocate register(s) as necessary. */ + +#define SMALL_INT(X) ((unsigned) (INTVAL(X) + 0x4000) < 0x8000) + +rtx +rs6000_machopic_legitimize_pic_address (orig, mode, reg) + rtx orig; + enum machine_mode mode; + rtx reg; +{ + rtx base, offset; + + if (reg == NULL && ! reload_in_progress && ! reload_completed) + reg = gen_reg_rtx (Pmode); + + if (GET_CODE (orig) == CONST) + { + if (GET_CODE (XEXP (orig, 0)) == PLUS + && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) + return orig; + + if (GET_CODE (XEXP (orig, 0)) == PLUS) + { + base = rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), + Pmode, reg); + offset = rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), + Pmode, reg); + } + else + abort (); + + if (GET_CODE (offset) == CONST_INT) + { + if (SMALL_INT (offset)) + return plus_constant_for_output (base, INTVAL (offset)); + else if (! reload_in_progress && ! reload_completed) + offset = force_reg (Pmode, offset); + else + abort (); + } + return gen_rtx (PLUS, Pmode, base, offset); + } + + /* Fall back on generic machopic code. */ + return machopic_legitimize_pic_address (orig, mode, reg); +} + +/* This is just a placeholder to make linking work without having to + add this to the generic Darwin EXTRA_SECTIONS. If -mcall-aix is + ever needed for Darwin (not too likely!) this would have to get a + real definition. */ + +void +toc_section () +{ +} + +#endif /* TARGET_MACHO */ diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index f0f65f5e9d9..c1b964400ca 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -30,10 +30,12 @@ Boston, MA 02111-1307, USA. */ #define OBJECT_XCOFF 1 #define OBJECT_ELF 2 #define OBJECT_PEF 3 +#define OBJECT_MACHO 4 #define TARGET_ELF (TARGET_OBJECT_FORMAT == OBJECT_ELF) #define TARGET_AIX (TARGET_OBJECT_FORMAT == OBJECT_XCOFF) #define TARGET_MACOS (TARGET_OBJECT_FORMAT == OBJECT_PEF) +#define TARGET_MACHO (TARGET_OBJECT_FORMAT == OBJECT_MACHO) /* Print subsidiary information on the compiler version in use. */ #define TARGET_VERSION ; @@ -861,6 +863,10 @@ extern int rs6000_debug_arg; /* debug argument handling */ && flag_pic == 1) \ fixed_regs[PIC_OFFSET_TABLE_REGNUM] \ = call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + if (DEFAULT_ABI == ABI_DARWIN && flag_pic) \ + global_regs[PIC_OFFSET_TABLE_REGNUM] \ + = fixed_regs[PIC_OFFSET_TABLE_REGNUM] \ + = call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ } /* Specify the registers used for certain standard purposes. @@ -1159,7 +1165,8 @@ enum rs6000_abi { ABI_AIX, /* IBM's AIX */ ABI_AIX_NODESC, /* AIX calling sequence minus function descriptors */ ABI_V4, /* System V.4/eabi */ - ABI_SOLARIS /* Solaris */ + ABI_SOLARIS, /* Solaris */ + ABI_DARWIN /* Apple's Darwin (OS X kernel) */ }; extern enum rs6000_abi rs6000_current_abi; /* available for use by subtarget */ @@ -1210,13 +1217,14 @@ typedef struct rs6000_stack { /* Size of the outgoing register save area */ #define RS6000_REG_SAVE ((DEFAULT_ABI == ABI_AIX \ - || DEFAULT_ABI == ABI_AIX_NODESC) \ + || DEFAULT_ABI == ABI_AIX_NODESC \ + || DEFAULT_ABI == ABI_DARWIN) \ ? (TARGET_64BIT ? 64 : 32) \ : 0) /* Size of the fixed area on the stack */ #define RS6000_SAVE_AREA \ - (((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_AIX_NODESC) ? 24 : 8) \ + (((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_DARWIN) ? 24 : 8) \ << (TARGET_64BIT ? 1 : 0)) /* MEM representing address to save the TOC register */ @@ -1351,7 +1359,8 @@ typedef struct rs6000_stack { #define FP_ARG_AIX_MAX_REG 45 #define FP_ARG_V4_MAX_REG 40 #define FP_ARG_MAX_REG ((DEFAULT_ABI == ABI_AIX \ - || DEFAULT_ABI == ABI_AIX_NODESC) \ + || DEFAULT_ABI == ABI_AIX_NODESC \ + || DEFAULT_ABI == ABI_DARWIN) \ ? FP_ARG_AIX_MAX_REG : FP_ARG_V4_MAX_REG) #define FP_ARG_NUM_REG (FP_ARG_MAX_REG - FP_ARG_MIN_REG + 1) @@ -1645,6 +1654,7 @@ typedef struct rs6000_args abi's store the return address. */ #define RETURN_ADDRESS_OFFSET \ ((DEFAULT_ABI == ABI_AIX \ + || DEFAULT_ABI == ABI_DARWIN \ || DEFAULT_ABI == ABI_AIX_NODESC) ? (TARGET_32BIT ? 8 : 16) : \ (DEFAULT_ABI == ABI_V4 \ || DEFAULT_ABI == ABI_SOLARIS) ? (TARGET_32BIT ? 4 : 8) : \ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 833e64096ca..6bea69bd8ab 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -1449,6 +1449,14 @@ {cau|addis} %0,%1,%v2" [(set_attr "length" "4,4,4,4")]) +(define_insn "addsi3_high" + [(set (match_operand:SI 0 "gpc_reg_operand" "=b") + (plus:SI (match_operand:SI 1 "gpc_reg_operand" "b") + (high:SI (match_operand 2 "" ""))))] + "TARGET_MACHO && !TARGET_64BIT" + "{cau|addis} %0,%1,ha16(%2)" + [(set_attr "length" "4")]) + (define_insn "*addsi3_internal2" [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") (compare:CC (plus:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r") @@ -7347,6 +7355,22 @@ {cal|la} %0,%2@l(%1) {ai|addic} %0,%1,%K2") +;; Mach-O PIC trickery. +(define_insn "macho_high" + [(set (match_operand:SI 0 "gpc_reg_operand" "=b*r") + (high:SI (match_operand 1 "" "")))] + "TARGET_MACHO && ! TARGET_64BIT" + "{liu|lis} %0,ha16(%1)") + +(define_insn "macho_low" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b,!*r") + (match_operand 2 "" "")))] + "TARGET_MACHO && ! TARGET_64BIT" + "@ + {cal %0,%a2@l(%1)|la %0,lo16(%2)(%1)} + {cal %0,%a2@l(%1)|addic %0,%1,lo16(%2)}") + ;; Set up a register with a value from the GOT table (define_expand "movsi_got" @@ -7406,6 +7430,15 @@ "" "{ rs6000_emit_move (operands[0], operands[1], SImode); DONE; }") +(define_insn "movsi_low" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mem:SI (lo_sum:SI (match_operand:SI 1 "register_operand" "b") + (match_operand 2 "" ""))))] + "TARGET_MACHO && ! TARGET_64BIT" + "{l|lwz} %0,lo16(%2)(%1)" + [(set_attr "type" "load") + (set_attr "length" "4")]) + (define_insn "*movsi_internal1" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h") (match_operand:SI 1 "input_operand" "r,U,m,r,I,L,n,R,*h,r,r,0"))] @@ -9257,6 +9290,21 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); "{l|lwz} %0,%2-%3(%1)" [(set_attr "type" "load")]) +(define_insn "load_macho_picbase" + [(set (match_operand:SI 0 "register_operand" "=l") + (unspec:SI [(const_int 0)] 15))] + "(DEFAULT_ABI == ABI_DARWIN) && flag_pic" + "* +{ +#if TARGET_MACHO + char *picbase = machopic_function_base_name (); + operands[1] = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (picbase, -1)); +#endif + return \"bcl 20,31,%1\\n%1:\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + ;; If the TOC is shared over a translation unit, as happens with all ;; the kinds of PIC that we support, we need to restore the TOC ;; pointer only when jumping over units of translation. @@ -9376,6 +9424,11 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); "" " { +#if TARGET_MACHO + if (flag_pic) + operands[0] = machopic_indirect_call_target (operands[0]); +#endif + if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != CONST_INT) abort (); @@ -9389,6 +9442,7 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC + || DEFAULT_ABI == ABI_DARWIN || DEFAULT_ABI == ABI_SOLARIS) operands[0] = force_reg (Pmode, operands[0]); @@ -9419,6 +9473,11 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); "" " { +#if TARGET_MACHO + if (flag_pic) + operands[1] = machopic_indirect_call_target (operands[1]); +#endif + if (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != CONST_INT) abort (); @@ -9432,6 +9491,7 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC + || DEFAULT_ABI == ABI_DARWIN || DEFAULT_ABI == ABI_SOLARIS) operands[0] = force_reg (Pmode, operands[0]); @@ -9664,6 +9724,7 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); (clobber (match_scratch:SI 3 "=l,l,l,l"))] "DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4 + || DEFAULT_ABI == ABI_DARWIN || DEFAULT_ABI == ABI_SOLARIS" "* { @@ -9696,6 +9757,7 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); (clobber (match_scratch:SI 4 "=l,l,l,l"))] "DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4 + || DEFAULT_ABI == ABI_DARWIN || DEFAULT_ABI == ABI_SOLARIS" "* { diff --git a/gcc/config/rs6000/t-darwin b/gcc/config/rs6000/t-darwin new file mode 100644 index 00000000000..c514fdaa000 --- /dev/null +++ b/gcc/config/rs6000/t-darwin @@ -0,0 +1,26 @@ +# Do not build libgcc1. +LIBGCC1 = +CROSS_LIBGCC1 = + +# We want fine grained libraries, so use the new code to build the +# floating point emulation libraries. +FPBIT = fp-bit.c +DPBIT = dp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + cat $(srcdir)/config/fp-bit.c > dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' > fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +darwin.o: $(srcdir)/config/darwin.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/darwin.c + +# Build the libraries for both hard and soft floating point + +MULTILIB_OPTIONS = msoft-float +MULTILIB_DIRNAMES = soft-float + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc/ginclude/stddef.h b/gcc/ginclude/stddef.h index 661d95d0785..081bcb2feb3 100644 --- a/gcc/ginclude/stddef.h +++ b/gcc/ginclude/stddef.h @@ -234,6 +234,7 @@ typedef long ssize_t; #ifndef __WCHAR_T #ifndef _WCHAR_T_ #ifndef _BSD_WCHAR_T_ +#ifndef _BSD_WCHAR_T_DEFINED_ /* Darwin */ #ifndef _WCHAR_T_DEFINED_ #ifndef _WCHAR_T_DEFINED #ifndef _WCHAR_T_H @@ -298,6 +299,7 @@ typedef __WCHAR_TYPE__ wchar_t; #endif #endif #endif +#endif #endif /* __wchar_t__ */ #undef __need_wchar_t #endif /* _STDDEF_H or __need_wchar_t. */