#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "tree.h"
#include "expr.h"
#include "reload.h"
#include "function.h"
#include "ggc.h"
#include "langhooks.h"
#include "target.h"
#include "tm_p.h"
#include "toplev.h"
#include "hashtab.h"
#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
};
int darwin_reverse_bitfields = 0;
int darwin_stubs = false;
section * darwin_sections[NUM_DARWIN_SECTIONS];
int darwin_ms_struct = false;
static void
output_objc_section_asm_op (const void *directive)
{
static bool been_here = false;
if (! been_here)
{
static const enum darwin_section_enum tomark[] =
{
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,
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,
objc_protocol_ext_section,
objc_class_ext_section,
objc_prop_list_section
};
static const enum darwin_section_enum tomarkv2[] =
{
objc_v2_message_refs_section,
objc_v2_classdefs_section,
objc_v2_metadata_section,
objc_v2_classrefs_section,
objc_v2_classlist_section,
objc_v2_categorylist_section,
objc_v2_selector_refs_section,
objc_v2_nonlazy_class_section,
objc_v2_nonlazy_category_section,
objc_v2_protocollist_section,
objc_v2_protocolrefs_section,
objc_v2_super_classrefs_section,
objc_v2_image_info_section,
objc_v2_constant_string_object_section
} ;
size_t i;
been_here = true;
if (flag_objc_abi == 1)
for (i = 0; i < ARRAY_SIZE (tomark); i++)
switch_to_section (darwin_sections[tomark[i]]);
\
else if (flag_objc_abi == 2)
for (i = 0; i < ARRAY_SIZE (tomarkv2); i++)
switch_to_section (darwin_sections[tomarkv2[i]]);
}
output_section_asm_op (directive);
}
void
darwin_init_sections (void)
{
#define DEF_SECTION(NAME, FLAGS, DIRECTIVE, OBJC) \
darwin_sections[NAME] = \
get_unnamed_section (FLAGS, (OBJC \
? output_objc_section_asm_op \
: output_section_asm_op), \
"\t" DIRECTIVE);
#include "config/darwin-sections.def"
#undef DEF_SECTION
readonly_data_section = darwin_sections[const_section];
exception_section = darwin_sections[darwin_exception_section];
eh_frame_section = darwin_sections[darwin_eh_frame_section];
}
int
name_needs_quotes (const char *name)
{
int c;
while ((c = *name++) != '\0')
if (! ISIDNUM (c) && c != '.' && c != '$')
return 1;
return 0;
}
int
machopic_symbol_defined_p (rtx sym_ref)
{
if (SYMBOL_REF_FLAGS (sym_ref) & MACHO_SYMBOL_FLAG_DEFINED)
return true;
if (SYMBOL_REF_LOCAL_P (sym_ref) && ! SYMBOL_REF_EXTERNAL_P (sym_ref))
{
if (SYMBOL_REF_FLAGS (sym_ref) & MACHO_SYMBOL_FLAG_VARIABLE)
{
tree decl = SYMBOL_REF_DECL (sym_ref);
if (!decl)
return true;
if (DECL_COMMON (decl))
return false;
}
else if (SYMBOL_REF_FLAGS (sym_ref) & SYMBOL_FLAG_FUNCTION)
{
tree decl = SYMBOL_REF_DECL (sym_ref);
if (decl && DECL_WEAK (decl))
return false;
}
return true;
}
return false;
}
enum machopic_addr_class
machopic_classify_symbol (rtx sym_ref)
{
int flags;
bool function_p;
flags = SYMBOL_REF_FLAGS (sym_ref);
function_p = SYMBOL_REF_FUNCTION_P (sym_ref);
if (machopic_symbol_defined_p (sym_ref))
return (function_p
? MACHOPIC_DEFINED_FUNCTION : MACHOPIC_DEFINED_DATA);
else
return (function_p
? MACHOPIC_UNDEFINED_FUNCTION : MACHOPIC_UNDEFINED_DATA);
}
#ifndef TARGET_FIX_AND_CONTINUE
#define TARGET_FIX_AND_CONTINUE 0
#endif
int
indirect_data (rtx sym_ref)
{
int lprefix;
const char *name;
if (TARGET_FIX_AND_CONTINUE == 0)
return 0;
name = XSTR (sym_ref, 0);
lprefix = (((name[0] == '*' || name[0] == '&')
&& (name[1] == 'L'
|| (name[1] == '"' && name[2] == 'L')
|| (name[1] == 'l' && name[2] == 'C')))
|| (strncmp (name, "_OBJC_", 6) == 0)
|| objc_anonymous_local_objc_name (name));
return ! lprefix;
}
int
machopic_data_defined_p (rtx sym_ref)
{
if (indirect_data (sym_ref))
return 0;
switch (machopic_classify_symbol (sym_ref))
{
case MACHOPIC_DEFINED_DATA:
case MACHOPIC_DEFINED_FUNCTION:
return 1;
default:
return 0;
}
}
void
machopic_define_symbol (rtx mem)
{
rtx sym_ref;
gcc_assert (GET_CODE (mem) == MEM);
sym_ref = XEXP (mem, 0);
SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_DEFINED;
}
static GTY(()) char * function_base;
const char *
machopic_function_base_name (void)
{
gcc_assert (!MACHO_DYNAMIC_NO_PIC_P);
if (function_base == NULL)
function_base =
(char *) ggc_alloc_string ("<pic base>", sizeof ("<pic base>"));
current_function_uses_pic_offset_table = 1;
return function_base;
}
rtx
machopic_function_base_sym (void)
{
rtx sym_ref;
sym_ref = gen_rtx_SYMBOL_REF (Pmode, machopic_function_base_name ());
SYMBOL_REF_FLAGS (sym_ref)
|= (MACHO_SYMBOL_FLAG_VARIABLE | MACHO_SYMBOL_FLAG_DEFINED);
return sym_ref;
}
static inline rtx
gen_pic_offset (rtx orig, rtx pic_base)
{
if (!pic_base)
return orig;
else
return gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, orig, pic_base));
}
static GTY(()) const char * function_base_func_name;
static GTY(()) int current_pic_label_num;
void
machopic_output_function_base_name (FILE *file)
{
const char *current_name;
gcc_assert (!MACHO_DYNAMIC_NO_PIC_P);
current_name =
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
if (function_base_func_name != current_name)
{
++current_pic_label_num;
function_base_func_name = current_name;
}
fprintf (file, "\"L%011d$pb\"", current_pic_label_num);
}
#define NON_LAZY_POINTER_SUFFIX "$non_lazy_ptr"
#define STUB_SUFFIX "$stub"
typedef struct machopic_indirection GTY (())
{
rtx symbol;
const char * ptr_name;
bool stub_p;
bool used;
bool emitted;
} machopic_indirection;
static GTY ((param_is (struct machopic_indirection))) htab_t
machopic_indirections;
static GTY (()) bool indirection_uses_changed;
static hashval_t
machopic_indirection_hash (const void *slot)
{
const machopic_indirection *p = (const machopic_indirection *) slot;
return htab_hash_string (p->ptr_name);
}
static int
machopic_indirection_eq (const void *slot, const void *key)
{
return strcmp (((const machopic_indirection *) slot)->ptr_name, key) == 0;
}
const char *
machopic_indirection_name (rtx sym_ref, bool stub_p)
{
char *buffer;
const char *name = XSTR (sym_ref, 0);
size_t namelen = strlen (name);
machopic_indirection *p;
void ** slot;
bool saw_star = false;
bool needs_quotes;
const char *suffix;
const char *prefix = user_label_prefix;
const char *quote = "";
tree id;
id = maybe_get_identifier (name);
if (id)
{
tree id_orig = id;
while (IDENTIFIER_TRANSPARENT_ALIAS (id))
id = TREE_CHAIN (id);
if (id != id_orig)
{
name = IDENTIFIER_POINTER (id);
namelen = strlen (name);
}
}
if (name[0] == '*')
{
saw_star = true;
prefix = "";
++name;
--namelen;
}
needs_quotes = name_needs_quotes (name);
if (needs_quotes)
{
quote = "\"";
}
if (stub_p)
suffix = STUB_SUFFIX;
else
suffix = NON_LAZY_POINTER_SUFFIX;
buffer = alloca (strlen ("&L")
+ strlen (prefix)
+ namelen
+ strlen (suffix)
+ 2 * strlen (quote)
+ 1 );
sprintf (buffer, "&%sL%s%s%s%s", quote, prefix, name, suffix, quote);
if (!machopic_indirections)
machopic_indirections = htab_create_ggc (37,
machopic_indirection_hash,
machopic_indirection_eq,
NULL);
slot = htab_find_slot_with_hash (machopic_indirections, buffer,
htab_hash_string (buffer), INSERT);
if (*slot)
{
p = (machopic_indirection *) *slot;
}
else
{
p = (machopic_indirection *) ggc_alloc (sizeof (machopic_indirection));
p->symbol = sym_ref;
p->ptr_name = xstrdup (buffer);
p->stub_p = stub_p;
p->used = false;
p->emitted = false;
*slot = p;
}
return p->ptr_name;
}
const char*
machopic_mcount_stub_name (void)
{
rtx symbol = gen_rtx_SYMBOL_REF (Pmode, "*mcount");
return machopic_indirection_name (symbol, true);
}
int
machopic_lookup_stub_or_non_lazy_ptr (const char *name)
{
machopic_indirection *p;
if (! machopic_indirections)
return 0;
p = (machopic_indirection *)
htab_find_with_hash (machopic_indirections, name,
htab_hash_string (name));
if (p)
return 1;
else
return 0;
}
void
machopic_validate_stub_or_non_lazy_ptr (const char *name)
{
machopic_indirection *p;
p = ((machopic_indirection *)
(htab_find_with_hash (machopic_indirections, name,
htab_hash_string (name))));
if (p && ! p->used)
{
const char *real_name;
tree id;
p->used = true;
indirection_uses_changed = true;
if (SYMBOL_REF_DECL (p->symbol))
mark_decl_referenced (SYMBOL_REF_DECL (p->symbol));
real_name = targetm.strip_name_encoding (XSTR (p->symbol, 0));
id = maybe_get_identifier (real_name);
if (id)
mark_referenced (id);
}
}
rtx
machopic_indirect_data_reference (rtx orig, rtx reg)
{
rtx ptr_ref = orig;
if (! MACHOPIC_INDIRECT)
return orig;
switch (GET_CODE (orig))
{
case SYMBOL_REF:
{
int defined = machopic_data_defined_p (orig);
if (defined && MACHO_DYNAMIC_NO_PIC_P)
{
#if defined (TARGET_TOC)
rtx hi_reg = (no_new_pseudos ? reg : gen_reg_rtx (Pmode));
emit_insn (gen_macho_high (hi_reg, orig));
emit_insn (gen_macho_low (reg, hi_reg, orig));
#else
#if defined (TARGET_386)
return orig;
#else
gcc_unreachable ();
#endif
#endif
return reg;
}
else if (defined)
{
#if defined (TARGET_TOC) || defined (HAVE_lo_sum)
rtx pic_base = machopic_function_base_sym ();
rtx offset = gen_pic_offset (orig, pic_base);
#endif
#if defined (TARGET_TOC)
rtx hi_sum_reg = (no_new_pseudos ? reg : gen_reg_rtx (Pmode));
gcc_assert (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 (Pmode, reg,
gen_rtx_LO_SUM (Pmode, hi_sum_reg, offset)));
orig = reg;
#else
#if defined (HAVE_lo_sum)
gcc_assert (reg);
emit_insn (gen_rtx_SET (VOIDmode, reg,
gen_rtx_HIGH (Pmode, offset)));
emit_insn (gen_rtx_SET (VOIDmode, reg,
gen_rtx_LO_SUM (Pmode, reg, offset)));
emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
orig = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, reg);
#endif
#endif
return orig;
}
ptr_ref = (gen_rtx_SYMBOL_REF
(Pmode,
machopic_indirection_name (orig, false)));
SYMBOL_REF_DATA (ptr_ref) = SYMBOL_REF_DATA (orig);
ptr_ref = gen_const_mem (Pmode, ptr_ref);
machopic_define_symbol (ptr_ref);
#ifdef TARGET_386
if (reg && MACHO_DYNAMIC_NO_PIC_P)
{
emit_insn (gen_rtx_SET (Pmode, reg, ptr_ref));
ptr_ref = reg;
}
#endif
return ptr_ref;
}
break;
case CONST:
{
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;
if (GET_CODE (XEXP (orig, 0)) == REG
&& REGNO (XEXP (orig, 0)) == PIC_OFFSET_TABLE_REGNUM
#ifdef TARGET_386
&& GET_CODE (XEXP (orig, 1)) == CONST
#endif
&& reg)
{
emit_move_insn (reg, XEXP (orig, 0));
XEXP (ptr_ref, 0) = reg;
return ptr_ref;
}
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;
}
break;
default:
break;
}
return ptr_ref;
}
static inline rtx
machopic_force_stub (rtx target)
{
rtx sym_ref = XEXP (target, 0);
rtx new_target;
enum machine_mode mem_mode = GET_MODE (target);
enum machine_mode sym_mode = GET_MODE (XEXP (target, 0));
const char *stub_name = XSTR (sym_ref, 0);
stub_name = machopic_indirection_name (sym_ref, true);
new_target = gen_rtx_MEM (mem_mode, gen_rtx_SYMBOL_REF (sym_mode, stub_name));
SYMBOL_REF_DATA (XEXP (new_target, 0)) = SYMBOL_REF_DATA (sym_ref);
MEM_READONLY_P (new_target) = 1;
MEM_NOTRAP_P (new_target) = 1;
return new_target;
}
rtx
machopic_force_indirect_call_target (rtx target)
{
if (MEM_P (target))
{
rtx sym_ref = XEXP (target, 0);
const char *stub_name = XSTR (sym_ref, 0);
unsigned int stub_name_length = strlen (stub_name);
if (stub_name_length < 6 || strcmp ("$stub", stub_name + stub_name_length - 5))
target = machopic_force_stub (target);
}
return target;
}
rtx
machopic_indirect_call_target (rtx target)
{
if (! darwin_stubs)
return target;
if (GET_CODE (target) != MEM)
return target;
if (MACHOPIC_INDIRECT
&& GET_CODE (XEXP (target, 0)) == SYMBOL_REF
&& !(SYMBOL_REF_FLAGS (XEXP (target, 0))
& MACHO_SYMBOL_FLAG_DEFINED))
target = machopic_force_stub (target);
return target;
}
rtx
machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
{
rtx pic_ref = orig;
if (! MACHOPIC_INDIRECT)
return orig;
if (GET_CODE (orig) == LABEL_REF
|| (GET_CODE (orig) == SYMBOL_REF
))
{
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;
}
if (MACHO_DYNAMIC_NO_PIC_P)
pic_base = NULL;
else
pic_base = machopic_function_base_sym ();
if (GET_CODE (orig) == MEM)
{
if (reg == 0)
{
gcc_assert (!reload_in_progress);
reg = gen_reg_rtx (Pmode);
}
#ifdef HAVE_lo_sum
if (MACHO_DYNAMIC_NO_PIC_P
&& (GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (orig, 0)) == LABEL_REF))
{
#if defined (TARGET_TOC)
rtx temp_reg = (no_new_pseudos) ? reg : gen_reg_rtx (Pmode);
rtx asym = XEXP (orig, 0);
rtx mem;
emit_insn (gen_macho_high (temp_reg, asym));
mem = gen_const_mem (GET_MODE (orig),
gen_rtx_LO_SUM (Pmode, temp_reg, asym));
emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
#else
gcc_unreachable ();
#endif
pic_ref = reg;
}
else
if (GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (orig, 0)) == LABEL_REF)
{
rtx offset = gen_pic_offset (XEXP (orig, 0), pic_base);
#if defined (TARGET_TOC)
rtx hi_sum_reg = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
rtx mem;
rtx insn;
rtx sum;
sum = gen_rtx_HIGH (Pmode, offset);
if (! MACHO_DYNAMIC_NO_PIC_P)
sum = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, sum);
emit_insn (gen_rtx_SET (Pmode, hi_sum_reg, sum));
mem = gen_const_mem (GET_MODE (orig),
gen_rtx_LO_SUM (Pmode,
hi_sum_reg, offset));
insn = emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, pic_ref,
REG_NOTES (insn));
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
{
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
if (reload_in_progress)
regs_ever_live[REGNO (pic)] = 1;
pic_ref = gen_rtx_PLUS (Pmode, pic,
gen_pic_offset (XEXP (orig, 0),
pic_base));
}
#if !defined (TARGET_TOC)
emit_move_insn (reg, pic_ref);
pic_ref = gen_const_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_pic_offset (orig, pic_base);
#if defined (TARGET_TOC)
rtx hi_sum_reg;
if (reg == 0)
{
gcc_assert (!reload_in_progress);
reg = gen_reg_rtx (Pmode);
}
hi_sum_reg = reg;
emit_insn (gen_rtx_SET (Pmode, hi_sum_reg,
(MACHO_DYNAMIC_NO_PIC_P)
? gen_rtx_HIGH (Pmode, offset)
: 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
{
if (REG_P (orig)
|| GET_CODE (orig) == SUBREG)
{
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
if (reload_in_progress)
regs_ever_live[REGNO (pic)] = 1;
pic_ref = gen_rtx_PLUS (Pmode,
pic,
gen_pic_offset (orig, pic_base));
}
}
}
if (GET_CODE (pic_ref) != REG)
{
if (reg != 0)
{
emit_move_insn (reg, pic_ref);
return reg;
}
else
{
return force_reg (mode, pic_ref);
}
}
else
{
return pic_ref;
}
}
else if (GET_CODE (orig) == SYMBOL_REF)
return orig;
else if (GET_CODE (orig) == PLUS
&& (GET_CODE (XEXP (orig, 0)) == MEM
|| GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (orig, 0)) == LABEL_REF)
&& XEXP (orig, 0) != pic_offset_table_rtx
&& GET_CODE (XEXP (orig, 1)) != REG)
{
rtx base;
int is_complex = (GET_CODE (XEXP (orig, 0)) == MEM);
base = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
orig = machopic_legitimize_pic_address (XEXP (orig, 1),
Pmode, (base == reg ? 0 : reg));
if (GET_CODE (orig) == CONST_INT)
{
pic_ref = plus_constant (base, INTVAL (orig));
is_complex = 1;
}
else
pic_ref = gen_rtx_PLUS (Pmode, base, orig);
#ifdef MASK_80387
{
rtx mem, other;
if (GET_CODE (orig) == MEM) {
mem = orig; other = base;
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;
if (other && GET_CODE (other) == MEM)
other = force_reg (GET_MODE (other), other);
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
if (reg && is_complex)
{
emit_move_insn (reg, pic_ref);
pic_ref = reg;
}
}
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 tempreg = reg;
rtx addr;
if ( !no_new_pseudos )
tempreg = gen_reg_rtx (Pmode);
addr = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, tempreg);
addr = replace_equiv_address (orig, addr);
emit_move_insn (reg, addr);
pic_ref = reg;
}
return pic_ref;
}
static int
machopic_output_indirection (void **slot, void *data)
{
machopic_indirection *p = *((machopic_indirection **) slot);
FILE *asm_out_file = (FILE *) data;
rtx symbol;
const char *sym_name;
const char *ptr_name;
if (!p->used || p->emitted)
return 1;
symbol = p->symbol;
sym_name = XSTR (symbol, 0);
ptr_name = p->ptr_name;
if (p->stub_p)
{
char *sym;
char *stub;
tree id;
id = maybe_get_identifier (sym_name);
if (id)
{
tree id_orig = id;
while (IDENTIFIER_TRANSPARENT_ALIAS (id))
id = TREE_CHAIN (id);
if (id != id_orig)
sym_name = IDENTIFIER_POINTER (id);
}
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
sprintf (sym, "%s%s", user_label_prefix, sym_name);
stub = alloca (strlen (ptr_name) + 2);
if (ptr_name[0] == '*' || ptr_name[0] == '&')
strcpy (stub, ptr_name + 1);
else
sprintf (stub, "%s%s", user_label_prefix, ptr_name);
machopic_output_stub (asm_out_file, sym, stub);
}
else if (! indirect_data (symbol)
&& (machopic_symbol_defined_p (symbol)
|| SYMBOL_REF_LOCAL_P (symbol)))
{
switch_to_section (data_section);
assemble_align (GET_MODE_ALIGNMENT (Pmode));
assemble_label (ptr_name);
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, sym_name),
GET_MODE_SIZE (Pmode),
GET_MODE_ALIGNMENT (Pmode), 1);
}
else
{
rtx init = const0_rtx;
switch_to_section (darwin_sections[machopic_nl_symbol_ptr_section]);
assemble_name (asm_out_file, ptr_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");
if ((SYMBOL_REF_FLAGS (symbol) & MACHO_SYMBOL_STATIC)
&& machopic_symbol_defined_p (symbol))
init = gen_rtx_SYMBOL_REF (Pmode, sym_name);
assemble_integer (init, GET_MODE_SIZE (Pmode),
GET_MODE_ALIGNMENT (Pmode), 1);
}
p->emitted = true;
return 1;
}
void
machopic_finish (FILE *asm_out_file)
{
if (machopic_indirections)
do
{
indirection_uses_changed = false;
htab_traverse_noresize (machopic_indirections,
machopic_output_indirection,
asm_out_file);
}
while (indirection_uses_changed == true);
}
int
machopic_operand_p (rtx op)
{
if (MACHOPIC_JUST_INDIRECT)
{
while (GET_CODE (op) == CONST)
op = XEXP (op, 0);
if (GET_CODE (op) == SYMBOL_REF)
return machopic_symbol_defined_p (op);
else
return 0;
}
while (GET_CODE (op) == CONST)
op = XEXP (op, 0);
if (GET_CODE (op) == MINUS
&& GET_CODE (XEXP (op, 0)) == SYMBOL_REF
&& GET_CODE (XEXP (op, 1)) == SYMBOL_REF
&& machopic_symbol_defined_p (XEXP (op, 0))
&& machopic_symbol_defined_p (XEXP (op, 1)))
return 1;
return 0;
}
void
darwin_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
{
rtx sym_ref;
default_encode_section_info (decl, rtl, first);
if (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL)
return;
sym_ref = XEXP (rtl, 0);
if (TREE_CODE (decl) == VAR_DECL)
SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_VARIABLE;
if (!DECL_EXTERNAL (decl)
&& (!TREE_PUBLIC (decl) || !DECL_WEAK (decl))
&& ! lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
&& ((TREE_STATIC (decl)
&& (!DECL_COMMON (decl) || !TREE_PUBLIC (decl)))
|| (!DECL_COMMON (decl) && DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node)))
SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_DEFINED;
if (! TREE_PUBLIC (decl))
SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_STATIC;
if (TREE_CODE (decl) == VAR_DECL)
{
if (strncmp (XSTR (sym_ref, 0), "_OBJC_", 6) == 0)
SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_DEFINED;
}
}
void
darwin_mark_decl_preserved (const char *name)
{
fprintf (asm_out_file, ".no_dead_strip ");
assemble_name (asm_out_file, name);
fputc ('\n', asm_out_file);
}
int
machopic_reloc_rw_mask (void)
{
return MACHOPIC_INDIRECT ? 3 : 0;
}
static inline bool
objc_internal_variable_name (tree exp)
{
if (TREE_CODE (exp) == VAR_DECL)
{
tree decl_name = DECL_NAME (exp);
if (decl_name && TREE_CODE (decl_name) == IDENTIFIER_NODE
&& IDENTIFIER_POINTER (decl_name))
{
const char* name = IDENTIFIER_POINTER (decl_name);
return
(!strncmp (name, "_OBJC_", 6)
|| !strncmp (name, "OBJC_", 5)
|| !strncmp (name, "l_OBJC_", 7)
|| !strncmp (name, "l_objc_", 7));
}
}
return false;
}
section *
machopic_select_section (tree exp, int reloc,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
{
section *base_section;
bool weak_p = (DECL_P (exp) && DECL_WEAK (exp)
&& (lookup_attribute ("weak", DECL_ATTRIBUTES (exp))
|| ! lookup_attribute ("weak_import",
DECL_ATTRIBUTES (exp))));
if (TREE_CODE (exp) == FUNCTION_DECL)
{
if (reloc == 1)
base_section = (weak_p
? darwin_sections[text_unlikely_coal_section]
: unlikely_text_section ());
else
base_section = weak_p ? darwin_sections[text_coal_section] : text_section;
}
else if (decl_readonly_section (exp, reloc))
base_section = weak_p ? darwin_sections[const_coal_section] : darwin_sections[const_section];
else if (TREE_READONLY (exp) || TREE_CONSTANT (exp))
base_section = weak_p ? darwin_sections[const_data_coal_section] : darwin_sections[const_data_section];
else
base_section = weak_p ? darwin_sections[data_coal_section] : data_section;
if (TREE_CODE (exp) == STRING_CST
&& (MAX ((HOST_WIDE_INT)TREE_STRING_LENGTH (exp),
int_size_in_bytes (TREE_TYPE (exp)))
== (HOST_WIDE_INT) strlen (TREE_STRING_POINTER (exp)) + 1)
&& ! flag_writable_strings)
return darwin_sections[cstring_section];
else if ((TREE_CODE (exp) == INTEGER_CST || TREE_CODE (exp) == REAL_CST)
&& flag_merge_constants)
{
tree size = TYPE_SIZE_UNIT (TREE_TYPE (exp));
if (TREE_CODE (size) == INTEGER_CST &&
TREE_INT_CST_LOW (size) == 4 &&
TREE_INT_CST_HIGH (size) == 0)
return darwin_sections[literal4_section];
else if (TREE_CODE (size) == INTEGER_CST &&
TREE_INT_CST_LOW (size) == 8 &&
TREE_INT_CST_HIGH (size) == 0)
return darwin_sections[literal8_section];
#ifndef HAVE_GAS_LITERAL16
#define HAVE_GAS_LITERAL16 0
#endif
else if (HAVE_GAS_LITERAL16
&& TARGET_64BIT
&& TREE_CODE (size) == INTEGER_CST
&& TREE_INT_CST_LOW (size) == 16
&& TREE_INT_CST_HIGH (size) == 0)
return darwin_sections[literal16_section];
else
return base_section;
}
else if (TREE_CODE (exp) == CONSTRUCTOR
&& TREE_TYPE (exp)
&& TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
&& TYPE_NAME (TREE_TYPE (exp)))
{
extern int flag_next_runtime;
tree name = TYPE_NAME (TREE_TYPE (exp));
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
if (!strcmp (IDENTIFIER_POINTER (name), "__builtin_ObjCString"))
{
if (flag_next_runtime)
{
if (flag_objc_abi == 2)
return darwin_sections[objc_v2_constant_string_object_section];
else
return darwin_sections[objc_constant_string_object_section];
}
else
return darwin_sections[objc_string_object_section];
}
else if (!strcmp (IDENTIFIER_POINTER (name), "__builtin_CFString"))
return darwin_sections[cfstring_constant_object_section];
else
return base_section;
}
else if (objc_internal_variable_name (exp))
{
const char *name = IDENTIFIER_POINTER (DECL_NAME (exp));
if (flag_objc_abi == 1)
{
if (!strncmp (name, "_OBJC_CLASS_METHODS_", 20))
return darwin_sections[objc_cls_meth_section];
else if (!strncmp (name, "_OBJC_INSTANCE_METHODS_", 23))
return darwin_sections[objc_inst_meth_section];
else if (!strncmp (name, "_OBJC_CATEGORY_CLASS_METHODS_", 29))
return darwin_sections[objc_cat_cls_meth_section];
else if (!strncmp (name, "_OBJC_CATEGORY_INSTANCE_METHODS_", 32))
return darwin_sections[objc_cat_inst_meth_section];
else if (!strncmp (name, "_OBJC_CLASS_VARIABLES_", 22))
return darwin_sections[objc_class_vars_section];
else if (!strncmp (name, "_OBJC_INSTANCE_VARIABLES_", 25))
return darwin_sections[objc_instance_vars_section];
else if (!strncmp (name, "_OBJC_CLASS_PROTOCOLS_", 22))
return darwin_sections[objc_cat_cls_meth_section];
else if (!strncmp (name, "_OBJC_CLASS_NAME_", 17))
return darwin_sections[objc_class_names_section];
else if (!strncmp (name, "_OBJC_METH_VAR_NAME_", 20))
return darwin_sections[objc_meth_var_names_section];
else if (!strncmp (name, "_OBJC_METH_VAR_TYPE_", 20))
return darwin_sections[objc_meth_var_types_section];
else if (!strncmp (name, "_OBJC_CLASS_REFERENCES", 22))
return darwin_sections[objc_cls_refs_section];
else if (!strncmp (name, "_OBJC_CLASS_", 12))
return darwin_sections[objc_class_section];
else if (!strncmp (name, "_OBJC_METACLASS_", 16))
return darwin_sections[objc_meta_class_section];
else if (!strncmp (name, "_OBJC_CATEGORY_", 15))
return darwin_sections[objc_category_section];
else if (!strncmp (name, "_OBJC_SELECTOR_REFERENCES", 25))
return darwin_sections[objc_selector_refs_section];
else if (!strncmp (name, "_OBJC_SELECTOR_FIXUP", 20))
return darwin_sections[objc_selector_fixup_section];
else if (!strncmp (name, "_OBJC_SYMBOLS", 13))
return darwin_sections[objc_symbols_section];
else if (!strncmp (name, "_OBJC_MODULES", 13))
return darwin_sections[objc_module_info_section];
else if (!strncmp (name, "_OBJC_IMAGE_INFO", 16))
return darwin_sections[objc_image_info_section];
else if (!strncmp (name, "_OBJC_PROTOCOL_INSTANCE_METHODS_", 32))
return darwin_sections[objc_cat_inst_meth_section];
else if (!strncmp (name, "_OBJC_PROTOCOL_CLASS_METHODS_", 29))
return darwin_sections[objc_cat_cls_meth_section];
else if (!strncmp (name, "_OBJC_PROTOCOL_REFS_", 20))
return darwin_sections[objc_cat_cls_meth_section];
else if (!strncmp (name, "_OBJC_PROTOCOL_", 15))
return darwin_sections[objc_protocol_section];
else if (!strncmp (name, "_OBJC_CLASSEXT_", 15))
return darwin_sections[objc_class_ext_section];
else if (!strncmp (name, "_OBJC_$_PROP_LIST", 17)
|| !strncmp (name, "_OBJC_$_PROP_PROTO", 18))
return darwin_sections[objc_prop_list_section];
else if (!strncmp (name, "_OBJC_PROTOCOLEXT", 17))
return darwin_sections[objc_protocol_ext_section];
else if (!strncmp (name, "_OBJC_PROP_NAME_ATTR_", 21))
return darwin_sections[cstring_section];
else
return base_section;
}
else
{
if (!strncmp (name, "_OBJC_PROP_NAME_ATTR_", 21)
|| !strncmp (name, "_OBJC_CLASS_NAME_", 17)
|| !strncmp (name, "_OBJC_METH_VAR_NAME_", 20)
|| !strncmp (name, "_OBJC_METH_VAR_TYPE_", 20))
return darwin_sections[cstring_section];
else if (!strncmp (name, "_OBJC_CLASSLIST_REFERENCES_", 27))
return darwin_sections[objc_v2_classrefs_section];
else if (!strncmp (name, "_OBJC_CLASSLIST_SUP_REFS_", 25))
return darwin_sections[objc_v2_super_classrefs_section];
else if (!strncmp (name, "l_objc_msgSend", 14))
return darwin_sections[objc_v2_message_refs_section];
else if (!strncmp (name, "_OBJC_LABEL_CLASS_", 18))
return darwin_sections[objc_v2_classlist_section];
else if (!strncmp (name, "l_OBJC_LABEL_PROTOCOL_", 22))
return darwin_sections[objc_v2_protocollist_section];
else if (!strncmp (name, "_OBJC_LABEL_CATEGORY_", 21))
return darwin_sections[objc_v2_categorylist_section];
else if (!strncmp (name, "_OBJC_LABEL_NONLAZY_CLASS_", 26))
return darwin_sections[objc_v2_nonlazy_class_section];
else if (!strncmp (name, "_OBJC_LABEL_NONLAZY_CATEGORY_", 29))
return darwin_sections[objc_v2_nonlazy_category_section];
else if (!strncmp (name, "l_OBJC_PROTOCOL_REFERENCE_", 26))
return darwin_sections[objc_v2_protocolrefs_section];
else if (!strncmp (name, "_OBJC_SELECTOR_REFERENCES", 25))
return darwin_sections[objc_v2_selector_refs_section];
else if (!strncmp (name, "_OBJC_IMAGE_INFO", 16))
return darwin_sections[objc_v2_image_info_section];
else if (!strncmp (name, "OBJC_CLASS_$_", 13)
|| !strncmp (name, "OBJC_METACLASS_$_", 17))
return darwin_sections[objc_v2_classdefs_section];
else
return (base_section == data_section) ?
darwin_sections[objc_v2_metadata_section] : base_section;
}
}
else
return darwin_set_section_for_var_p (exp, reloc, align, base_section);
}
section *
machopic_select_rtx_section (enum machine_mode mode, rtx x,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
{
if (GET_MODE_SIZE (mode) == 8
&& (GET_CODE (x) == CONST_INT
|| GET_CODE (x) == CONST_DOUBLE))
return darwin_sections[literal8_section];
else if (GET_MODE_SIZE (mode) == 4
&& (GET_CODE (x) == CONST_INT
|| GET_CODE (x) == CONST_DOUBLE))
return darwin_sections[literal4_section];
else if (HAVE_GAS_LITERAL16
&& TARGET_64BIT
&& GET_MODE_SIZE (mode) == 16
&& (GET_CODE (x) == CONST_INT
|| GET_CODE (x) == CONST_DOUBLE
|| GET_CODE (x) == CONST_VECTOR))
return darwin_sections[literal16_section];
else if (MACHOPIC_INDIRECT
&& (GET_CODE (x) == SYMBOL_REF
|| GET_CODE (x) == CONST
|| GET_CODE (x) == LABEL_REF))
return darwin_sections[const_data_section];
else
return darwin_sections[const_section];
}
void
machopic_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
{
if (MACHOPIC_INDIRECT)
switch_to_section (darwin_sections[mod_init_section]);
else
switch_to_section (darwin_sections[constructor_section]);
assemble_align (POINTER_SIZE);
assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
if (! MACHOPIC_INDIRECT)
fprintf (asm_out_file, ".reference .constructors_used\n");
}
void
machopic_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
{
if (MACHOPIC_INDIRECT)
switch_to_section (darwin_sections[mod_term_section]);
else
switch_to_section (darwin_sections[destructor_section]);
assemble_align (POINTER_SIZE);
assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
if (! MACHOPIC_INDIRECT)
fprintf (asm_out_file, ".reference .destructors_used\n");
}
void
darwin_globalize_label (FILE *stream, const char *name)
{
if (!!strncmp (name, "_OBJC_", 6))
default_globalize_label (stream, name);
}
void
abort_assembly_and_exit (int status)
{
if (status == FATAL_EXIT_CODE && asm_out_file != 0)
fprintf (asm_out_file, "\n.abort\n");
exit (status);
}
tree
darwin_handle_objc_gc_attribute (tree *node,
tree name,
tree args,
int flags ATTRIBUTE_UNUSED,
bool *no_add_attrs)
{
tree orig = *node, type;
while (POINTER_TYPE_P (orig)
|| TREE_CODE (orig) == FUNCTION_TYPE
|| TREE_CODE (orig) == METHOD_TYPE
|| TREE_CODE (orig) == ARRAY_TYPE)
orig = TREE_TYPE (orig);
type = build_type_attribute_variant (orig,
tree_cons (name, args,
TYPE_ATTRIBUTES (orig)));
if (TYPE_MAIN_VARIANT (orig) != TYPE_MAIN_VARIANT (type))
{
TYPE_MAIN_VARIANT (type) = TYPE_MAIN_VARIANT (orig);
TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (orig);
TYPE_NEXT_VARIANT (orig) = type;
}
*node = reconstruct_complex_type (*node, type);
*no_add_attrs = true;
return NULL_TREE;
}
tree
darwin_handle_nsobject_attribute (tree *node,
tree name,
tree args ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED,
bool *no_add_attrs)
{
tree orig = *node, type;
if (!POINTER_TYPE_P (orig) || TREE_CODE (TREE_TYPE (orig)) != RECORD_TYPE)
{
error ("__attribute ((NSObject)) is for pointer types only");
return NULL_TREE;
}
type = build_type_attribute_variant (orig,
tree_cons (name, NULL_TREE,
TYPE_ATTRIBUTES (orig)));
if (TYPE_MAIN_VARIANT (orig) != TYPE_MAIN_VARIANT (type))
{
TYPE_MAIN_VARIANT (type) = TYPE_MAIN_VARIANT (orig);
TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (orig);
TYPE_NEXT_VARIANT (orig) = type;
}
*node = type;
*no_add_attrs = true;
return NULL_TREE;
}
section*
darwin_set_section_for_var_p (tree exp, int reloc, int align, section* base_section)
{
if (!reloc && TREE_CODE (exp) == VAR_DECL
&& DECL_ALIGN (exp) == align
&& TREE_READONLY (exp) && DECL_INITIAL (exp)
&& ! DECL_WEAK (exp))
{
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)
{
if (MIN ( TREE_STRING_LENGTH (DECL_INITIAL(exp)),
int_size_in_bytes (TREE_TYPE (exp)))
== (long) strlen (TREE_STRING_POINTER (DECL_INITIAL (exp))) + 1)
return darwin_sections[cstring_section];
else
return darwin_sections[const_section];
}
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 base_section;
if (TREE_INT_CST_LOW (size) == 4)
return darwin_sections[literal4_section];
else if (TREE_INT_CST_LOW (size) == 8)
return darwin_sections[literal8_section];
else if (HAVE_GAS_LITERAL16
&& TARGET_64BIT
&& TREE_INT_CST_LOW (size) == 16)
return darwin_sections[literal16_section];
}
}
return base_section;
}
void
darwin_asm_named_section (const char *name,
unsigned int flags ATTRIBUTE_UNUSED,
tree decl ATTRIBUTE_UNUSED)
{
fprintf (asm_out_file, "\t.section %s\n", name);
}
void
darwin_unique_section (tree decl ATTRIBUTE_UNUSED, int reloc ATTRIBUTE_UNUSED)
{
}
tree
darwin_handle_kext_attribute (tree *node, tree name,
tree args ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED,
bool *no_add_attrs)
{
if (! TARGET_KEXTABI)
{
warning (0, "%<%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 (0, "%<%s%> 2.95 vtable-compatability attribute applies "
"only to C++ classes", IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
return NULL_TREE;
}
extern bool objc_method_decl (enum tree_code ARG_UNUSED (opcode));
tree
darwin_handle_weak_import_attribute (tree *node, tree name,
tree ARG_UNUSED (args),
int ARG_UNUSED (flags),
bool * no_add_attrs)
{
if (objc_method_decl (TREE_CODE (*node)))
return NULL_TREE;
if (in_objc_property_decl_context ())
{
*no_add_attrs = true;
return NULL_TREE;
}
if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)
{
warning (OPT_Wattributes, "%qs attribute ignored",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
else
declare_weak (*node);
return NULL_TREE;
}
\
\
void
darwin_emit_unwind_label (FILE *file, tree decl, int for_eh, int empty)
{
\
char *lab;
if (! for_eh)
return;
lab = concat (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), ".eh", NULL);
if (TREE_PUBLIC (decl))
{
targetm.asm_out.globalize_label (file, lab);
if (DECL_VISIBILITY (decl) == VISIBILITY_HIDDEN)
{
fputs ("\t.private_extern ", file);
assemble_name (file, lab);
fputc ('\n', file);
}
}
if (DECL_WEAK (decl))
{
fputs ("\t.weak_definition ", file);
assemble_name (file, lab);
fputc ('\n', file);
}
assemble_name (file, lab);
if (empty)
{
fputs (" = 0\n", file);
darwin_mark_decl_preserved (lab);
}
else
fputs (":\n", file);
\
free (lab);
}
static GTY(()) unsigned long except_table_label_num;
void
darwin_emit_except_table_label (FILE *file)
{
char section_start_label[30];
ASM_GENERATE_INTERNAL_LABEL (section_start_label, "GCC_except_table",
except_table_label_num++);
ASM_OUTPUT_LABEL (file, section_start_label);
}
void
darwin_non_lazy_pcrel (FILE *file, rtx addr)
{
const char *nlp_name;
gcc_assert (GET_CODE (addr) == SYMBOL_REF);
nlp_name = machopic_indirection_name (addr, false);
fputs ("\t.long\t", file);
ASM_OUTPUT_LABELREF (file, nlp_name);
fputs ("-.", file);
}
void
darwin_assemble_visibility (tree decl, int vis)
{
if (vis == VISIBILITY_DEFAULT)
;
else if (vis == VISIBILITY_HIDDEN)
{
fputs ("\t.private_extern ", asm_out_file);
assemble_name (asm_out_file,
(IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
fputs ("\n", asm_out_file);
}
else
warning (OPT_Wattributes, "internal and protected visibility attributes "
"not supported in this configuration; ignored");
}
static int darwin_dwarf_label_counter;
void
darwin_asm_output_dwarf_delta (FILE *file, int size,
const char *lab1, const char *lab2)
{
int islocaldiff = (lab1[0] == '*' && lab1[1] == 'L'
&& lab2[0] == '*' && lab2[1] == 'L');
const char *directive = (size == 8 ? ".quad" : ".long");
if (islocaldiff)
fprintf (file, "\t.set L$set$%d,", darwin_dwarf_label_counter);
else
fprintf (file, "\t%s\t", directive);
assemble_name_raw (file, lab1);
fprintf (file, "-");
assemble_name_raw (file, lab2);
if (islocaldiff)
fprintf (file, "\n\t%s L$set$%d", directive, darwin_dwarf_label_counter++);
}
void
darwin_file_start (void)
{
if (write_symbols == DWARF2_DEBUG)
{
static const char * const debugnames[] =
{
DEBUG_FRAME_SECTION,
DEBUG_INFO_SECTION,
DEBUG_ABBREV_SECTION,
DEBUG_ARANGES_SECTION,
DEBUG_MACINFO_SECTION,
DEBUG_LINE_SECTION,
DEBUG_LOC_SECTION,
DEBUG_PUBNAMES_SECTION,
DEBUG_PUBTYPES_SECTION,
DEBUG_INLINED_SECTION,
DEBUG_STR_SECTION,
DEBUG_RANGES_SECTION
};
size_t i;
for (i = 0; i < ARRAY_SIZE (debugnames); i++)
{
int namelen;
switch_to_section (get_section (debugnames[i], SECTION_DEBUG, NULL));
gcc_assert (strncmp (debugnames[i], "__DWARF,", 8) == 0);
gcc_assert (strchr (debugnames[i] + 8, ','));
namelen = strchr (debugnames[i] + 8, ',') - (debugnames[i] + 8);
fprintf (asm_out_file, "Lsection%.*s:\n", namelen, debugnames[i] + 8);
}
}
}
void
darwin_asm_output_dwarf_offset (FILE *file, int size, const char * lab,
section *base)
{
char sname[64];
int namelen;
gcc_assert (base->common.flags & SECTION_NAMED);
gcc_assert (strncmp (base->named.name, "__DWARF,", 8) == 0);
gcc_assert (strchr (base->named.name + 8, ','));
namelen = strchr (base->named.name + 8, ',') - (base->named.name + 8);
sprintf (sname, "*Lsection%.*s", namelen, base->named.name + 8);
darwin_asm_output_dwarf_delta (file, size, lab, sname);
}
void
darwin_file_end (void)
{
machopic_finish (asm_out_file);
if (darwin_running_cxx)
{
switch_to_section (darwin_sections[constructor_section]);
switch_to_section (darwin_sections[destructor_section]);
ASM_OUTPUT_ALIGN (asm_out_file, 1);
}
if (! has_alternative_entry_points ())
fprintf (asm_out_file, "\t.subsections_via_symbols\n");
}
#define DARWIN_VTABLE_P(DECL) lang_hooks.vtable_p (DECL)
bool
darwin_binds_local_p (tree decl)
{
return default_binds_local_p_1 (decl,
TARGET_KEXTABI && DARWIN_VTABLE_P (decl));
}
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;
struct cfstring_descriptor GTY(())
{
tree literal;
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;
int save_warn_padded;
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, long_integer_type_node);
TREE_CHAIN (field) = fields; fields = field;
save_warn_padded = warn_padded;
warn_padded = 0;
finish_builtin_struct (cfstring_type_node, "__builtin_CFString",
fields, NULL_TREE);
warn_padded = save_warn_padded;
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);
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);
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)
{
struct cfstring_descriptor key;
void **loc;
key.literal = str;
loc = htab_find_slot (cfstring_htab, &key, INSERT);
if (!*loc)
{
*loc = ggc_alloc_cleared (sizeof (struct cfstring_descriptor));
((struct cfstring_descriptor *)*loc)->literal = str;
}
return NULL_TREE;
}
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;
}
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;
extern tree pushdecl_top_level (tree);
extern int isascii (int);
bool cvt_utf = false;
tree utf16_str = NULL_TREE;
const char *s = TREE_STRING_POINTER (str);
int l;
for (l = 0; l < length; l++)
if (!s[l] || !isascii (s[l]))
{
cvt_utf = true;
break;
}
if (cvt_utf)
{
size_t numUniChars;
const unsigned char *inbuf = (unsigned char *)TREE_STRING_POINTER (str);
utf16_str = create_init_utf16_var (inbuf, length, &numUniChars);
if (!utf16_str)
{
warning (0, "input conversion stopped due to an input byte "
"that does not belong to the input codeset UTF-8");
cvt_utf = false;
}
else
length = (numUniChars >> 1);
}
*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, utf16_str ? 0x000007d0 : 0x000007c8),
initlist);
field = TREE_CHAIN (field);
initlist = tree_cons (field,
build1 (ADDR_EXPR, pcchar_type_node,
utf16_str ? utf16_str : str), initlist);
field = TREE_CHAIN (field);
initlist = tree_cons (field, build_int_cst (TREE_TYPE (field), length),
initlist);
constructor = build_constructor_from_list (ccfstring_type_node,
nreverse (initlist));
TREE_READONLY (constructor) = 1;
TREE_CONSTANT (constructor) = 1;
TREE_STATIC (constructor) = 1;
if (darwin_running_cxx)
TREE_LANG_FLAG_4 (constructor) = 1;
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;
}
tree
darwin_iasm_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;
}
#if 0
void
darwin_asm_output_anchor (rtx symbol)
{
fprintf (asm_out_file, "\t.set\t");
assemble_name (asm_out_file, XSTR (symbol, 0));
fprintf (asm_out_file, ", . + " HOST_WIDE_INT_PRINT_DEC "\n",
SYMBOL_REF_BLOCK_OFFSET (symbol));
}
#endif
void
darwin_set_default_type_attributes (tree type)
{
if (darwin_ms_struct
&& TREE_CODE (type) == RECORD_TYPE)
TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("ms_struct"),
NULL_TREE,
TYPE_ATTRIBUTES (type));
}
bool
darwin_kextabi_p (void) {
return TARGET_KEXTABI == 1;
}
#ifndef TARGET_SUPPORTS_KEXTABI1
#define TARGET_SUPPORTS_KEXTABI1 0
#endif
void
darwin_override_options (void)
{
#if 0
if (flag_apple_kext && strcmp (lang_hooks.name, "GNU C++") != 0)
{
warning (0, "command line option %<-fapple-kext%> is only valid for C++");
flag_apple_kext = 0;
}
#endif
if (flag_mkernel || flag_apple_kext)
{
if (strcmp (lang_hooks.name, "GNU C++") == 0)
flag_apple_kext = 1;
flag_no_common = 1;
flag_exceptions = 0;
flag_asynchronous_unwind_tables = 0;
flag_non_call_exceptions = 0;
if (flag_apple_kext &&
! TARGET_SUPPORTS_KEXTABI1)
flag_apple_kext = 2;
}
if (darwin_macosx_version_min
&& strverscmp (darwin_macosx_version_min, "10.5") < 0)
darwin_stubs = true;
if (flag_stack_protect == -1
&& darwin_macosx_version_min
&& ((! flag_mkernel && ! flag_apple_kext
&& strverscmp (darwin_macosx_version_min, "10.5") >= 0)
|| strverscmp (darwin_macosx_version_min, "10.6") >= 0))
flag_stack_protect = 1;
}
bool
darwin_cfstring_type_node (tree type_node)
{
return type_node == ccfstring_type_node;
}
#include "gt-darwin.h"