diff options
Diffstat (limited to 'gcc/config/darwin.c')
-rw-r--r-- | gcc/config/darwin.c | 745 |
1 files changed, 656 insertions, 89 deletions
diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index de2f6e3e0b6..8a92e73e877 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -45,7 +45,21 @@ Boston, MA 02111-1307, USA. */ #include "tm_p.h" #include "errors.h" #include "hashtab.h" +/* APPLE LOCAL begin constant cfstrings */ +#include "toplev.h" +static tree darwin_build_constant_cfstring (tree); + +enum darwin_builtins +{ + DARWIN_BUILTIN_MIN = (int)END_BUILTINS, + + DARWIN_BUILTIN_CFSTRINGMAKECONSTANTSTRING, + DARWIN_BUILTIN_MAX +}; +/* APPLE LOCAL end constant cfstrings */ + +/* APPLE LOCAL begin mainline 5 nops */ /* Darwin supports a feature called fix-and-continue, which is used for rapid turn around debugging. When code is compiled with the -mfix-and-continue flag, two changes are made to the generated code @@ -59,8 +73,8 @@ Boston, MA 02111-1307, USA. */ existed in the unit to be replaced, and from the new translation unit, for new data. - The changes are to insert 4 nops at the beginning of all functions - and to use indirection to get at static duration data. The 4 nops + The changes are to insert 5 nops at the beginning of all functions + and to use indirection to get at static duration data. The 5 nops are required by consumers of the generated code. Currently, gdb uses this to patch in a jump to the overriding function, this allows all uses of the old name to forward to the replacement, @@ -75,12 +89,17 @@ Boston, MA 02111-1307, USA. */ the code that handles the extra indirection, and machopic_output_indirection and its use of MACHO_SYMBOL_STATIC for the code that handles @code{static} data indirection. */ - +/* APPLE LOCAL end mainline 5 nops */ /* Nonzero if the user passes the -mone-byte-bool switch, which forces sizeof(bool) to be 1. */ const char *darwin_one_byte_bool = 0; +/* APPLE LOCAL begin pragma reverse_bitfields */ +/* Shouldn't there be a comment here? */ +int darwin_reverse_bitfields = 0; +/* APPLE LOCAL end pragma reverse_bitfields */ + int name_needs_quotes (const char *name) { @@ -92,7 +111,8 @@ name_needs_quotes (const char *name) } /* Return true if SYM_REF can be used without an indirection. */ -static int +/* APPLE LOCAL what is this change for? */ +int machopic_symbol_defined_p (rtx sym_ref) { if (SYMBOL_REF_FLAGS (sym_ref) & MACHO_SYMBOL_FLAG_DEFINED) @@ -169,7 +189,8 @@ indirect_data (rtx sym_ref) lprefix = (((name[0] == '*' || name[0] == '&') && (name[1] == 'L' || (name[1] == '"' && name[2] == 'L'))) - || (strncmp (name, "_OBJC_", 6))); + /* APPLE LOCAL mainline */ + || (strncmp (name, "_OBJC_", 6) == 0)); return ! lprefix; } @@ -421,9 +442,12 @@ machopic_indirect_data_reference (rtx orig, rtx reg) if (! MACHOPIC_INDIRECT) return orig; - if (GET_CODE (orig) == SYMBOL_REF) + /* APPLE LOCAL begin dynamic-no-pic */ + switch (GET_CODE (orig)) { - int defined = machopic_data_defined_p (orig); + case SYMBOL_REF: + { + int defined = machopic_data_defined_p (orig); if (defined && MACHO_DYNAMIC_NO_PIC_P) { @@ -431,8 +455,12 @@ machopic_indirect_data_reference (rtx orig, rtx reg) emit_insn (gen_macho_high (reg, orig)); emit_insn (gen_macho_low (reg, reg, orig)); #else - /* some other cpu -- writeme! */ - abort (); +#if defined (TARGET_386) + return orig; +#else /* defined (TARGET_386) */ + /* some other cpu -- writeme! */ + abort (); +#endif /* defined (TARGET_386) */ #endif return reg; } @@ -482,63 +510,86 @@ machopic_indirect_data_reference (rtx orig, rtx reg) ptr_ref = gen_const_mem (Pmode, ptr_ref); machopic_define_symbol (ptr_ref); +#ifdef TARGET_386 + if (reg && TARGET_DYNAMIC_NO_PIC) + { + emit_insn (gen_rtx_SET (Pmode, reg, ptr_ref)); + ptr_ref = reg; + } +#endif /* TARGET_386 */ + 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 (MACHOPIC_JUST_INDIRECT && GET_CODE (base) == MEM) - { - if (reg) - { - emit_move_insn (reg, result); - result = reg; - } - else - { + break; + + case CONST: + { + /* If "(const (plus ...", walk the PLUS and return that result. + PLUS processing (below) will restore the "(const ..." if + appropriate. */ + if (GET_CODE (XEXP (orig, 0)) == PLUS) + return machopic_indirect_data_reference (XEXP (orig, 0), reg); + else + return orig; + } + break; + + case MEM: + { + XEXP (ptr_ref, 0) = machopic_indirect_data_reference (XEXP (orig, 0), reg); + return ptr_ref; + } + break; + + case PLUS: + { + rtx base, result; + + /* 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.) */ + if (GET_CODE (XEXP (orig, 0)) == REG + && REGNO (XEXP (orig, 0)) == PIC_OFFSET_TABLE_REGNUM +#ifdef TARGET_386 + /* 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; + } + + /* Legitimize both operands of the PLUS. */ + base = machopic_indirect_data_reference (XEXP (orig, 0), reg); + orig = machopic_indirect_data_reference (XEXP (orig, 1), + (base == reg ? 0 : reg)); + if (MACHOPIC_INDIRECT && GET_CODE (orig) == CONST_INT) + result = plus_constant (base, INTVAL (orig)); + else + result = gen_rtx_PLUS (Pmode, base, orig); + + 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; + } + return result; + } + break; - } - 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; - } + default: + break; + } /* End switch (GET_CODE (orig)) */ + /* APPLE LOCAL end dynamic-no-pic */ return ptr_ref; } @@ -824,6 +875,43 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg) else pic_ref = gen_rtx_PLUS (Pmode, base, orig); + /* APPLE LOCAL begin gen ADD */ +#ifdef MASK_80387 + { + rtx mem, other; + + if (GET_CODE (orig) == MEM) { + mem = orig; other = base; + /* Swap the kids only if there is only one MEM, and it's on the right. */ + if (GET_CODE (base) != MEM) { + XEXP (pic_ref, 0) = orig; + XEXP (pic_ref, 1) = base; + } + } + else if (GET_CODE (base) == MEM) { + mem = base; other = orig; + } else + mem = other = NULL_RTX; + + /* Both kids are MEMs. */ + if (other && GET_CODE (other) == MEM) + other = force_reg (GET_MODE (other), other); + + /* The x86 can't post-index a MEM; emit an ADD instruction to handle this. */ + if (mem && GET_CODE (mem) == MEM) { + if ( ! reload_in_progress) { + rtx set = gen_rtx_SET (VOIDmode, reg, pic_ref); + rtx clobber_cc = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); + pic_ref = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber_cc)); + emit_insn (pic_ref); + pic_ref = reg; + is_complex = 0; + } + } + } +#endif + /* APPLE LOCAL end gen ADD */ + if (reg && is_complex) { emit_move_insn (reg, pic_ref); @@ -840,7 +928,13 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx 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); + /* APPLE LOCAL begin use new pseudo for temp; reusing reg confuses PRE */ + rtx tempreg = reg; + rtx addr; + if ( !no_new_pseudos ) + tempreg = gen_reg_rtx (Pmode); + addr = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, tempreg); + /* APPLE LOCAL end use new pseudo for temp; reusing reg confuses PRE */ addr = replace_equiv_address (orig, addr); emit_move_insn (reg, addr); pic_ref = reg; @@ -998,6 +1092,14 @@ darwin_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED) && indirect_data (sym_ref) && ! TREE_PUBLIC (decl)) SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_STATIC; + + /* APPLE LOCAL begin fix OBJC codegen */ + if (TREE_CODE (decl) == VAR_DECL) + { + if (strncmp (XSTR (sym_ref, 0), "_OBJC_", 6) == 0) + SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_DEFINED; + } + /* APPLE LOCAL end fix OBJC codegen */ } void @@ -1016,7 +1118,7 @@ machopic_select_section (tree exp, int reloc, bool weak_p = DECL_P (exp) && DECL_WEAK (exp); static void (* const base_funs[][2])(void) = { { text_section, text_coal_section }, - { text_unlikely_section, text_unlikely_coal_section }, + { unlikely_text_section, text_unlikely_coal_section }, { readonly_data_section, const_coal_section }, { const_data_section, const_data_coal_section }, { data_section, data_coal_section } @@ -1031,10 +1133,13 @@ machopic_select_section (tree exp, int reloc, else base_function = base_funs[4][weak_p]; + /* APPLE LOCAL begin fwritable strings */ if (TREE_CODE (exp) == STRING_CST && ((size_t) TREE_STRING_LENGTH (exp) - == strlen (TREE_STRING_POINTER (exp)) + 1)) + == strlen (TREE_STRING_POINTER (exp)) + 1) + && ! flag_writable_strings) cstring_section (); + /* APPLE LOCAL end fwritable strings */ else if ((TREE_CODE (exp) == INTEGER_CST || TREE_CODE (exp) == REAL_CST) && flag_merge_constants) { @@ -1056,6 +1161,10 @@ machopic_select_section (tree exp, int reloc, && TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE && TYPE_NAME (TREE_TYPE (exp))) { + /* APPLE LOCAL begin constant strings */ + extern int flag_next_runtime; + extern const char *constant_string_class_name; + /* APPLE LOCAL end constant strings */ tree name = TYPE_NAME (TREE_TYPE (exp)); if (TREE_CODE (name) == TYPE_DECL) name = DECL_NAME (name); @@ -1063,6 +1172,19 @@ machopic_select_section (tree exp, int reloc, objc_constant_string_object_section (); else if (!strcmp (IDENTIFIER_POINTER (name), "NXConstantString")) objc_string_object_section (); + /* APPLE LOCAL begin constant strings */ + else if (!strcmp (IDENTIFIER_POINTER (name), "__builtin_CFString")) + cfstring_constant_object_section (); + else if (constant_string_class_name + && !strcmp (IDENTIFIER_POINTER (name), + constant_string_class_name)) + { + if (flag_next_runtime) + objc_constant_string_object_section (); + else + objc_string_object_section (); + } + /* APPLE LOCAL end constant strings */ else base_function (); } @@ -1123,28 +1245,12 @@ machopic_select_section (tree exp, int reloc, else base_function (); } - /* ::operator new and ::operator delete must be coalesced, even - if not weak. There are 8 variants that we look for. */ - else if (TREE_CODE (exp) == FUNCTION_DECL - && ! DECL_ONE_ONLY (exp)) - { - const char * name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (exp)); - if (name[0] == '_' && name[1] == 'Z' - && ((name[2] == 'n' && (name[3] == 'a' || name[3] == 'w') - && name[4] == 'm') - || (name[2] == 'd' && (name[3] == 'a' || name[3] == 'l') - && name[4] == 'P' && name[5] == 'v'))) - { - bool delete_p = name[2] == 'd'; - if (name[5 + delete_p] == 0 - || strcmp (name + 5 + delete_p, "KSt9nothrow_t") == 0) - base_funs[reloc][1] (); - else - base_function (); - } - else - base_function (); - } + /* APPLE LOCAL coalescing */ + /* Removed special handling of '::operator new' and '::operator delete'. */ + /* APPLE LOCAL begin darwin_set_section_for_var_p */ + else if (darwin_set_section_for_var_p (exp, reloc, align)) + ; + /* APPLE LOCAL end darwin_set_section_for_var_p */ else base_function (); } @@ -1156,7 +1262,9 @@ void machopic_select_rtx_section (enum machine_mode mode, rtx x, unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) { - if (GET_MODE_SIZE (mode) == 8) + if (GET_MODE_SIZE (mode) == 8 + && (GET_CODE (x) == CONST_INT + || GET_CODE (x) == CONST_DOUBLE)) literal8_section (); else if (GET_MODE_SIZE (mode) == 4 && (GET_CODE (x) == CONST_INT @@ -1206,6 +1314,153 @@ darwin_globalize_label (FILE *stream, const char *name) default_globalize_label (stream, name); } +/* APPLE LOCAL begin assembly "abort" directive */ +/* This can be called instead of EXIT. It will emit a '.abort' directive + into any existing assembly file, causing assembly to immediately abort, + thus preventing the assembler from spewing out numerous, irrelevant + error messages. */ + +void +abort_assembly_and_exit (int status) +{ + /* If we're aborting, get the assembler to abort, too. */ + if (status == FATAL_EXIT_CODE && asm_out_file != 0) + fprintf (asm_out_file, "\n.abort\n"); + + exit (status); +} +/* APPLE LOCAL end assembly "abort" directive */ + +/* APPLE LOCAL begin KEXT double destructor */ +#include "c-common.h" + +/* Handle __attribute__ ((apple_kext_compatibility)). + This only applies to darwin kexts for 2.95 compatibility -- it shrinks the + vtable for classes with this attribute (and their descendants) by not + outputting the new 3.0 nondeleting destructor. This means that such + objects CANNOT be allocated on the stack or as globals UNLESS they have + a completely empty `operator delete'. + Luckily, this fits in with the Darwin kext model. + + This attribute also disables gcc3's potential overlaying of derived + class data members on the padding at the end of the base class. */ + +tree +darwin_handle_odd_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) +{ + /* APPLE KEXT stuff -- only applies with pure static C++ code. */ + if (! flag_apple_kext || ! c_dialect_cxx ()) + { + warning ("`%s' 2.95 vtable-compatability attribute applies " + "only when compiling a kext", IDENTIFIER_POINTER (name)); + + *no_add_attrs = true; + } + else if (TREE_CODE (*node) != RECORD_TYPE) + { + warning ("`%s' 2.95 vtable-compatability attribute applies " + "only to C++ classes", IDENTIFIER_POINTER (name)); + + *no_add_attrs = true; + } + + return NULL_TREE; +} +/* APPLE LOCAL end KEXT double destructor */ + +/* APPLE LOCAL begin ObjC GC */ +tree +darwin_handle_objc_gc_attribute (tree *node ATTRIBUTE_UNUSED, + tree name ATTRIBUTE_UNUSED, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs ATTRIBUTE_UNUSED) +{ + return NULL_TREE; +} +/* APPLE LOCAL end ObjC GC */ + +/* APPLE LOCAL begin darwin_set_section_for_var_p 20020226 --turly */ + +/* This is specifically for any initialised static class constants + which may be output by the C++ front end at the end of compilation. + SELECT_SECTION () macro won't do because these are VAR_DECLs, not + STRING_CSTs or INTEGER_CSTs. And by putting 'em in appropriate + sections, we save space. + + FIXME: does this really do anything? Won't the DECL_WEAK test be + true 99% (or 100%) of the time? In the other 1% of the time, + shouldn't select_section be fixed instead of this hackery? */ + +extern void cstring_section (void), + literal4_section (void), literal8_section (void); +int +darwin_set_section_for_var_p (tree exp, int reloc, int align) +{ + if (!reloc && TREE_CODE (exp) == VAR_DECL + && DECL_ALIGN (exp) == align + && TREE_READONLY (exp) && DECL_INITIAL (exp) + && ! DECL_WEAK (exp)) + { + /* Put constant string vars in ".cstring" section. */ + + if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (exp))) == INTEGER_TYPE + && integer_onep (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (exp)))) + && TREE_CODE (DECL_INITIAL (exp)) == STRING_CST) + { + + /* Compare string length with actual number of characters + the compiler will write out (which is not necessarily + TREE_STRING_LENGTH, in the case of a constant array of + characters that is not null-terminated). Select appropriate + section accordingly. */ + + if (MIN ( TREE_STRING_LENGTH (DECL_INITIAL(exp)), + int_size_in_bytes (TREE_TYPE (exp))) + == (long) strlen (TREE_STRING_POINTER (DECL_INITIAL (exp))) + 1) + { + cstring_section (); + return 1; + } + else + { + const_section (); + return 1; + } + } + else + if (TREE_READONLY (exp) + && ((TREE_CODE (TREE_TYPE (exp)) == INTEGER_TYPE + && TREE_CODE (DECL_INITIAL (exp)) == INTEGER_CST) + || (TREE_CODE (TREE_TYPE (exp)) == REAL_TYPE + && TREE_CODE (DECL_INITIAL (exp)) == REAL_CST)) + && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (DECL_INITIAL (exp)))) + == INTEGER_CST) + { + tree size = TYPE_SIZE_UNIT (TREE_TYPE (DECL_INITIAL (exp))); + if (TREE_INT_CST_HIGH (size) != 0) + return 0; + + /* Put integer and float consts in the literal4|8 sections. */ + + if (TREE_INT_CST_LOW (size) == 4) + { + literal4_section (); + return 1; + } + else if (TREE_INT_CST_LOW (size) == 8) + { + literal8_section (); + return 1; + } + } + } + return 0; +} +/* APPLE LOCAL end darwin_set_section_for_var_p 20020226 --turly */ + void darwin_asm_named_section (const char *name, unsigned int flags ATTRIBUTE_UNUSED, @@ -1381,7 +1636,8 @@ void darwin_file_end (void) { machopic_finish (asm_out_file); - if (strcmp (lang_hooks.name, "GNU C++") == 0) + /* APPLE LOCAL constant cfstrings */ + if (darwin_running_cxx) { constructor_section (); destructor_section (); @@ -1399,4 +1655,315 @@ darwin_file_end (void) int darwin_fix_and_continue; const char *darwin_fix_and_continue_switch; +/* APPLE LOCAL begin KEXT */ +/* Ture, iff we're generating code for loadable kernel extentions. */ + +bool +flag_apple_kext_p (void) { + return flag_apple_kext; +} +/* APPLE LOCAL end KEXT */ + +/* APPLE LOCAL begin constant cfstrings */ +int darwin_constant_cfstrings = 0; +const char *darwin_constant_cfstrings_switch; +int darwin_warn_nonportable_cfstrings = 1; /* on by default. */ +const char *darwin_warn_nonportable_cfstrings_switch; +int darwin_pascal_strings = 0; +const char *darwin_pascal_strings_switch; +int darwin_running_cxx; + +static GTY(()) tree cfstring_class_reference = NULL_TREE; +static GTY(()) tree cfstring_type_node = NULL_TREE; +static GTY(()) tree ccfstring_type_node = NULL_TREE; +static GTY(()) tree pccfstring_type_node = NULL_TREE; +static GTY(()) tree pcint_type_node = NULL_TREE; +static GTY(()) tree pcchar_type_node = NULL_TREE; + +/* Store all constructed constant CFStrings in a hash table so that + they get uniqued properly. */ + +struct cfstring_descriptor GTY(()) +{ + /* The literal argument . */ + tree literal; + + /* The resulting constant CFString. */ + tree constructor; +}; + +static GTY((param_is (struct cfstring_descriptor))) htab_t cfstring_htab; + +static hashval_t cfstring_hash (const void *); +static int cfstring_eq (const void *, const void *); + +void +darwin_init_cfstring_builtins (void) +{ + tree field, fields, pccfstring_ftype_pcchar; + + /* struct __builtin_CFString { + const int *isa; (will point at + int flags; __CFConstantStringClassReference) + const char *str; + int length; + }; */ + + pcint_type_node + = build_pointer_type (build_qualified_type (integer_type_node, + TYPE_QUAL_CONST)); + pcchar_type_node + = build_pointer_type (build_qualified_type (char_type_node, + TYPE_QUAL_CONST)); + cfstring_type_node = (*lang_hooks.types.make_type) (RECORD_TYPE); + fields = build_decl (FIELD_DECL, NULL_TREE, pcint_type_node); + field = build_decl (FIELD_DECL, NULL_TREE, integer_type_node); + TREE_CHAIN (field) = fields; fields = field; + field = build_decl (FIELD_DECL, NULL_TREE, pcchar_type_node); + TREE_CHAIN (field) = fields; fields = field; + field = build_decl (FIELD_DECL, NULL_TREE, integer_type_node); + TREE_CHAIN (field) = fields; fields = field; + /* NB: The finish_builtin_struct() routine expects FIELD_DECLs in + reverse order! */ + finish_builtin_struct (cfstring_type_node, "__builtin_CFString", + fields, NULL_TREE); + + /* const struct __builtin_CFstring * + __builtin___CFStringMakeConstantString (const char *); */ + + ccfstring_type_node + = build_qualified_type (cfstring_type_node, TYPE_QUAL_CONST); + pccfstring_type_node + = build_pointer_type (ccfstring_type_node); + pccfstring_ftype_pcchar + = build_function_type_list (pccfstring_type_node, + pcchar_type_node, NULL_TREE); + lang_hooks.builtin_function ("__builtin___CFStringMakeConstantString", + pccfstring_ftype_pcchar, + DARWIN_BUILTIN_CFSTRINGMAKECONSTANTSTRING, + BUILT_IN_NORMAL, NULL, NULL_TREE); + + /* extern int __CFConstantStringClassReference[]; */ + cfstring_class_reference + = build_decl (VAR_DECL, + get_identifier ("__CFConstantStringClassReference"), + build_array_type (integer_type_node, NULL_TREE)); + TREE_PUBLIC (cfstring_class_reference) = 1; + TREE_USED (cfstring_class_reference) = 1; + DECL_ARTIFICIAL (cfstring_class_reference) = 1; + (*lang_hooks.decls.pushdecl) (cfstring_class_reference); + DECL_EXTERNAL (cfstring_class_reference) = 1; + rest_of_decl_compilation (cfstring_class_reference, 0, 0); + + /* Initialize the hash table used to hold the constant CFString objects. */ + cfstring_htab = htab_create_ggc (31, cfstring_hash, + cfstring_eq, NULL); +} + +tree +darwin_expand_tree_builtin (tree function, tree params, + tree coerced_params ATTRIBUTE_UNUSED) +{ + unsigned int fcode = DECL_FUNCTION_CODE (function); + + switch (fcode) + { + case DARWIN_BUILTIN_CFSTRINGMAKECONSTANTSTRING: + if (!darwin_constant_cfstrings) + { + error ("built-in function `%s' requires `-fconstant-cfstrings' flag", + IDENTIFIER_POINTER (DECL_NAME (function))); + return error_mark_node; + } + + return darwin_build_constant_cfstring (TREE_VALUE (params)); + default: + break; + } + + return NULL_TREE; +} + +static hashval_t +cfstring_hash (const void *ptr) +{ + tree str = ((struct cfstring_descriptor *)ptr)->literal; + const unsigned char *p = (const unsigned char *) TREE_STRING_POINTER (str); + int i, len = TREE_STRING_LENGTH (str); + hashval_t h = len; + + for (i = 0; i < len; i++) + h = ((h * 613) + p[i]); + + return h; +} + +static int +cfstring_eq (const void *ptr1, const void *ptr2) +{ + tree str1 = ((struct cfstring_descriptor *)ptr1)->literal; + tree str2 = ((struct cfstring_descriptor *)ptr2)->literal; + int len1 = TREE_STRING_LENGTH (str1); + + return (len1 == TREE_STRING_LENGTH (str2) + && !memcmp (TREE_STRING_POINTER (str1), TREE_STRING_POINTER (str2), + len1)); +} + +tree +darwin_construct_objc_string (tree str) +{ + if (!darwin_constant_cfstrings) + return NULL_TREE; /* Fall back to NSConstantString. */ + + return darwin_build_constant_cfstring (str); +} + +bool +darwin_constant_cfstring_p (tree str) +{ + struct cfstring_descriptor key; + void **loc; + + if (!str) + return false; + + STRIP_NOPS (str); + + if (TREE_CODE (str) == ADDR_EXPR) + str = TREE_OPERAND (str, 0); + + if (TREE_CODE (str) != STRING_CST) + return false; + + key.literal = str; + loc = htab_find_slot (cfstring_htab, &key, NO_INSERT); + + if (loc) + return true; + + return false; +} + +static tree +darwin_build_constant_cfstring (tree str) +{ + struct cfstring_descriptor *desc, key; + void **loc; + tree addr; + + if (!str) + goto invalid_string; + + STRIP_NOPS (str); + + if (TREE_CODE (str) == ADDR_EXPR) + str = TREE_OPERAND (str, 0); + + if (TREE_CODE (str) != STRING_CST) + { + invalid_string: + error ("CFString literal expression is not constant"); + return error_mark_node; + } + + /* Perhaps we already constructed a constant CFString just like this one? */ + key.literal = str; + loc = htab_find_slot (cfstring_htab, &key, INSERT); + desc = *loc; + + if (!desc) + { + tree initlist, constructor, field = TYPE_FIELDS (ccfstring_type_node); + tree var; + int length = TREE_STRING_LENGTH (str) - 1; + /* FIXME: The CFString functionality should probably reside + in darwin-c.c. */ + extern tree pushdecl_top_level (tree); + + if (darwin_warn_nonportable_cfstrings) + { + extern int isascii (int); + const char *s = TREE_STRING_POINTER (str); + int l = 0; + + for (l = 0; l < length; l++) + if (!s[l] || !isascii (s[l])) + { + warning ("%s in CFString literal", + s[l] ? "non-ASCII character" : "embedded NUL"); + break; + } + } + + *loc = desc = ggc_alloc (sizeof (*desc)); + desc->literal = str; + + initlist = build_tree_list + (field, build1 (ADDR_EXPR, pcint_type_node, + cfstring_class_reference)); + field = TREE_CHAIN (field); + initlist = tree_cons (field, build_int_cst (NULL_TREE, 0x000007c8), + initlist); + field = TREE_CHAIN (field); + initlist = tree_cons (field, + build1 (ADDR_EXPR, pcchar_type_node, + str), initlist); + field = TREE_CHAIN (field); + initlist = tree_cons (field, build_int_cst (NULL_TREE, length), + initlist); + + constructor = build_constructor (ccfstring_type_node, + nreverse (initlist)); + TREE_READONLY (constructor) = 1; + TREE_CONSTANT (constructor) = 1; + TREE_STATIC (constructor) = 1; + + /* Fromage: The C++ flavor of 'build_unary_op' expects constructor nodes + to have the TREE_HAS_CONSTRUCTOR (...) bit set. However, this file is + being built without any knowledge of C++ tree accessors; hence, we shall + use the generic accessor that TREE_HAS_CONSTRUCTOR actually maps to! */ + if (darwin_running_cxx) + TREE_LANG_FLAG_4 (constructor) = 1; /* TREE_HAS_CONSTRUCTOR */ + + /* Create an anonymous global variable for this CFString. */ + var = build_decl (CONST_DECL, NULL, TREE_TYPE (constructor)); + DECL_INITIAL (var) = constructor; + TREE_STATIC (var) = 1; + pushdecl_top_level (var); + desc->constructor = var; + } + + addr = build1 (ADDR_EXPR, pccfstring_type_node, desc->constructor); + TREE_CONSTANT (addr) = 1; + + return addr; +} + +/* APPLE LOCAL end constant cfstrings */ + +/* APPLE LOCAL begin CW asm blocks */ +/* Assume labels like L_foo$stub etc in CW-style inline code are + intended to be taken as literal labels, and return the identifier, + otherwise return NULL signifying that we have no special + knowledge. */ +tree +darwin_cw_asm_special_label (tree id) +{ + const char *name = IDENTIFIER_POINTER (id); + + if (name[0] == 'L') + { + int len = strlen (name); + + if ((len > 5 && strcmp (name + len - 5, "$stub") == 0) + || (len > 9 && strcmp (name + len - 9, "$lazy_ptr") == 0) + || (len > 13 && strcmp (name + len - 13, "$non_lazy_ptr") == 0)) + return id; + } + + return NULL_TREE; +} +/* APPLE LOCAL end CW asm blocks */ + #include "gt-darwin.h" |