#include "config.h"
#include "system.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "tree.h"
#include "expr.h"
#include "reload.h"
#include "function.h"
#include "ggc.h"
#include "langhooks.h"
#include "tm_p.h"
extern void machopic_output_stub PARAMS ((FILE *, const char *, const char *));
static int machopic_data_defined_p PARAMS ((const char *));
static void update_non_lazy_ptrs PARAMS ((const char *));
static void update_stubs PARAMS ((const char *));
static tree machopic_non_lazy_ptr_list_entry PARAMS ((const char*, int));
static tree machopic_stub_list_entry PARAMS ((const char *));
void
make_decl_coalesced (decl, private_extern_p)
tree decl;
int private_extern_p;
{
int no_toc_p = 1;
#if 0
const char *decl_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
#endif
static const char *const names[4] = {
"__TEXT,__textcoal,coalesced",
"__TEXT,__textcoal_nt,coalesced,no_toc",
"__DATA,__datacoal,coalesced",
"__DATA,__datacoal_nt,coalesced,no_toc",
};
const char *sec;
int idx;
if (!COALESCING_ENABLED_P())
return;
#if 0
if (strstr (decl_name, " *INTERNAL") != NULL)
return;
#endif
DECL_COALESCED (decl) = 1;
if (private_extern_p)
DECL_PRIVATE_EXTERN (decl) = 1;
TREE_PUBLIC (decl) = 1;
idx = 0;
if (TREE_CODE (decl) != FUNCTION_DECL)
idx = 2;
sec = names[idx + (no_toc_p ? 1 : 0)];
DECL_SECTION_NAME (decl) = build_string (strlen (sec), sec);
}
const char *darwin_one_byte_bool = 0;
int
name_needs_quotes (name)
const char *name;
{
int c;
while ((c = *name++) != '\0')
if (! ISIDNUM (c) && c != '.' && c != '$')
return 1;
return 0;
}
static GTY(()) tree machopic_defined_list;
enum machopic_addr_class
machopic_classify_ident (ident)
tree ident;
{
const char *name = IDENTIFIER_POINTER (ident);
int lprefix = (((name[0] == '*' || name[0] == '&')
&& (name[1] == 'L' || (name[1] == '"' && name[2] == 'L')))
|| ( name[0] == '_'
&& name[1] == 'O'
&& name[2] == 'B'
&& name[3] == 'J'
&& name[4] == 'C'
&& name[5] == '_'));
tree temp;
if (name[0] != '!')
{
if (lprefix)
{
const char *name = IDENTIFIER_POINTER (ident);
int len = strlen (name);
if ((len > 5 && !strcmp (name + len - 5, "$stub"))
|| (len > 6 && !strcmp (name + len - 6, "$stub\"")))
return MACHOPIC_DEFINED_FUNCTION;
return MACHOPIC_DEFINED_DATA;
}
for (temp = machopic_defined_list;
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
if (ident == TREE_VALUE (temp))
return MACHOPIC_DEFINED_DATA;
}
if (TREE_ASM_WRITTEN (ident))
return MACHOPIC_DEFINED_DATA;
return MACHOPIC_UNDEFINED;
}
else if (name[1] == 'D')
return MACHOPIC_DEFINED_DATA;
else if (name[1] == 'T')
return MACHOPIC_DEFINED_FUNCTION;
else if (name[1] == 'd' || name[1] == 't')
{
char *new_name;
new_name = (char *)alloca (strlen (name) + 1);
strcpy (new_name, name);
new_name[1] = (name[1] == 'd') ? 'D' : 'T';
if (maybe_get_identifier (new_name) != NULL)
return (name[1] == 'd') ? MACHOPIC_DEFINED_DATA
: MACHOPIC_DEFINED_FUNCTION;
}
for (temp = machopic_defined_list; temp != NULL_TREE; temp = TREE_CHAIN (temp))
{
if (ident == TREE_VALUE (temp))
{
if (name[1] == 'T')
return MACHOPIC_DEFINED_FUNCTION;
else
return MACHOPIC_DEFINED_DATA;
}
}
if (name[1] == 't' || name[1] == 'T')
{
if (lprefix)
return MACHOPIC_DEFINED_FUNCTION;
else
return MACHOPIC_UNDEFINED_FUNCTION;
}
else
{
if (lprefix)
return MACHOPIC_DEFINED_DATA;
else
return MACHOPIC_UNDEFINED_DATA;
}
}
enum machopic_addr_class
machopic_classify_name (name)
const char *name;
{
return machopic_classify_ident (get_identifier (name));
}
int
machopic_ident_defined_p (ident)
tree ident;
{
switch (machopic_classify_ident (ident))
{
case MACHOPIC_UNDEFINED:
case MACHOPIC_UNDEFINED_DATA:
case MACHOPIC_UNDEFINED_FUNCTION:
return 0;
default:
return 1;
}
}
static int
indirect_data (name)
const char *name;
{
int lprefix;
if (flag_indirect_data == 0)
return 0;
name = darwin_strip_name_encoding (name);
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] == '_'));
return ! lprefix;
}
static int
machopic_data_defined_p (name)
const char *name;
{
if (indirect_data (name))
return 0;
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));
}
static GTY(()) char * function_base;
static GTY(()) const char * function_base_func_name;
static GTY(()) int current_pic_label_num;
const char *
machopic_function_base_name ()
{
const char *current_name;
if (MACHO_DYNAMIC_NO_PIC_P ())
abort ();
current_name =
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
if (function_base_func_name != current_name)
{
current_function_uses_pic_offset_table = 1;
if (function_base == NULL)
function_base = ggc_alloc_string ("", sizeof ("*\"L12345678901$pb\""));
++current_pic_label_num;
if (*current_name == '+' || *current_name == '-')
sprintf (function_base, "*\"L-%010d$pb\"", current_pic_label_num);
else
sprintf (function_base, "*\"L%011d$pb\"", current_pic_label_num);
function_base_func_name = current_name;
}
return function_base;
}
static GTY(()) tree machopic_non_lazy_pointers;
static tree
machopic_non_lazy_ptr_list_entry (name, create_p)
const char *name;
int create_p;
{
tree temp, ident = (create_p) ? get_identifier (name) : NULL;
for (temp = machopic_non_lazy_pointers;
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
if (ident == TREE_VALUE (temp))
return temp;
}
name = darwin_strip_name_encoding (name);
for (temp = machopic_non_lazy_pointers;
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
if (TREE_VALUE (temp))
{
const char *temp_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
temp_name = darwin_strip_name_encoding (temp_name);
if (strcmp (name, temp_name) == 0)
return temp;
}
}
if (create_p) {
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 machopic_non_lazy_pointers;
}
return NULL;
}
int
machopic_var_referred_to_p (name)
const char *name;
{
return (machopic_non_lazy_ptr_list_entry (name, 0) != NULL);
}
const char *
machopic_non_lazy_ptr_name (name)
const char *name;
{
return IDENTIFIER_POINTER (TREE_PURPOSE
(machopic_non_lazy_ptr_list_entry (name, 1)));
}
static GTY(()) tree machopic_stubs;
static tree
machopic_stub_list_entry (name)
const char *name;
{
tree temp, ident = get_identifier (name);
const char *tname;
for (temp = machopic_stubs;
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
if (ident == TREE_VALUE (temp))
return temp;
tname = IDENTIFIER_POINTER (TREE_VALUE (temp));
if (strcmp (name, tname) == 0)
return temp;
if (name [0] == '!' && tname[0] == '!'
&& strcmp (name + 4, tname + 4) == 0)
return temp;
if (name[0] != '!'
&& tname[0] == '!'
&& strcmp (name, tname + 4) == 0)
return temp;
}
name = darwin_strip_name_encoding (name);
{
char *buffer;
tree ptr_name;
int needs_quotes = name_needs_quotes (name);
buffer = alloca (strlen (name) + 20);
if (needs_quotes)
strcpy (buffer, "&\"L");
else
strcpy (buffer, "&L");
if (name[0] == '*')
{
strcat (buffer, name+1);
}
else
{
strcat (buffer, "_");
strcat (buffer, name);
}
if (needs_quotes)
strcat (buffer, "$stub\"");
else
strcat (buffer, "$stub");
ptr_name = get_identifier (buffer);
machopic_stubs = tree_cons (ptr_name, ident, machopic_stubs);
TREE_USED (machopic_stubs) = 0;
return machopic_stubs;
}
}
const char *
machopic_stub_name (name)
const char *name;
{
return IDENTIFIER_POINTER (TREE_PURPOSE (machopic_stub_list_entry (name)));
}
void
machopic_validate_stub_or_non_lazy_ptr (name, validate_stub)
const char *name;
int validate_stub;
{
const char *real_name;
tree temp, ident = get_identifier (name), id2;
for (temp = (validate_stub ? machopic_stubs : machopic_non_lazy_pointers);
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
if (ident == TREE_PURPOSE (temp))
{
TREE_USED (temp) = 1;
if (TREE_CODE (TREE_VALUE (temp)) == IDENTIFIER_NODE)
TREE_SYMBOL_REFERENCED (TREE_VALUE (temp)) = 1;
real_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
real_name = darwin_strip_name_encoding (real_name);
id2 = maybe_get_identifier (real_name);
if (id2)
TREE_SYMBOL_REFERENCED (id2) = 1;
}
}
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);
int defined = machopic_data_defined_p (name);
tree sym;
if (defined && MACHO_DYNAMIC_NO_PIC_P ())
{
#if defined (TARGET_TOC)
emit_insn (gen_macho_high (reg, orig));
emit_insn (gen_macho_low (reg, reg, orig));
#else
abort ();
#endif
return reg;
}
else if (defined)
{
#if defined (TARGET_TOC) || defined (HAVE_lo_sum)
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));
#endif
#if defined (TARGET_TOC)
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, pic_offset_table_rtx));
orig = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, reg);
#endif
#endif
return orig;
}
sym = machopic_non_lazy_ptr_list_entry (name, 1);
IDENTIFIER_WEAK_IMPORT (TREE_PURPOSE (sym)) =
IDENTIFIER_WEAK_IMPORT (TREE_VALUE (sym)) =
SYMBOL_REF_WEAK_IMPORT (orig);
ptr_ref = gen_rtx (SYMBOL_REF, Pmode,
IDENTIFIER_POINTER (TREE_PURPOSE (sym)));
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;
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
{
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);
else if (GET_CODE (orig) == PLUS
&& GET_CODE (XEXP (orig, 0)) == REG
&& REGNO (XEXP (orig, 0)) == PIC_OFFSET_TABLE_REGNUM
#ifdef I386
&& GET_CODE (XEXP (orig, 1)) == CONST
#endif
&& reg)
{
emit_move_insn (reg, XEXP (orig, 0));
XEXP (ptr_ref, 0) = reg;
}
return ptr_ref;
}
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 (name[0] == '!' && name[1] == 'T')
return target;
if (!machopic_name_defined_p (name))
{
tree stub = machopic_stub_list_entry (name);
IDENTIFIER_WEAK_IMPORT (TREE_PURPOSE (stub)) =
IDENTIFIER_WEAK_IMPORT (TREE_VALUE (stub)) =
SYMBOL_REF_WEAK_IMPORT (XEXP (target, 0));
XEXP (target, 0) = gen_rtx (SYMBOL_REF, mode,
IDENTIFIER_POINTER (TREE_PURPOSE (stub)));
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_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 = CONST0_RTX (Pmode);
else
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 (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_rtx_MEM (GET_MODE (orig),
gen_rtx (LO_SUM, Pmode, temp_reg, asym));
RTX_UNCHANGING_P (mem) = 1;
emit_insn (gen_rtx (SET, VOIDmode, reg, mem));
#else
abort ();
#endif
pic_ref = reg;
}
else
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)
rtx hi_sum_reg =
(reload_in_progress ? reg : gen_reg_rtx (SImode));
rtx mem;
rtx insn;
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))));
mem = gen_rtx (MEM, GET_MODE (orig),
gen_rtx (LO_SUM, Pmode,
hi_sum_reg, offset));
RTX_UNCHANGING_P (mem) = 1;
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, pic_offset_table_rtx));
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;
}
pic_ref = gen_rtx (PLUS, Pmode,
pic,
gen_rtx (CONST, Pmode,
gen_rtx (MINUS, Pmode,
XEXP (orig, 0),
pic_base)));
}
#if !defined (TARGET_TOC)
emit_move_insn (reg, pic_ref);
pic_ref = gen_rtx (MEM, GET_MODE (orig), reg);
#endif
RTX_UNCHANGING_P (pic_ref) = 1;
}
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)
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,
(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;
RTX_UNCHANGING_P (pic_ref) = 1;
#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);
RTX_UNCHANGING_P (pic_ref) = 1;
#endif
}
else
#endif
{
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)));
}
}
}
if (GET_CODE (pic_ref) != REG)
{
if (reg != 0)
{
emit_move_insn (reg, pic_ref);
return reg;
}
else
{
return force_reg (mode, pic_ref);
}
}
else
{
return pic_ref;
}
}
else if (GET_CODE (orig) == SYMBOL_REF)
return orig;
else if (GET_CODE (orig) == PLUS
&& (GET_CODE (XEXP (orig, 0)) == MEM
|| GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (orig, 0)) == LABEL_REF)
&& XEXP (orig, 0) != pic_offset_table_rtx
&& GET_CODE (XEXP (orig, 1)) != REG)
{
rtx base;
int is_complex = (GET_CODE (XEXP (orig, 0)) == MEM);
base = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
orig = machopic_legitimize_pic_address (XEXP (orig, 1),
Pmode, (base == reg ? 0 : reg));
if (GET_CODE (orig) == CONST_INT)
{
pic_ref = plus_constant (base, INTVAL (orig));
is_complex = 1;
}
else
pic_ref = gen_rtx (PLUS, Pmode, base, orig);
if (RTX_UNCHANGING_P (base) && RTX_UNCHANGING_P (orig))
RTX_UNCHANGING_P (pic_ref) = 1;
#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 = gen_rtx (MEM, GET_MODE (orig), addr);
RTX_UNCHANGING_P (addr) = RTX_UNCHANGING_P (orig);
emit_move_insn (reg, addr);
pic_ref = reg;
}
return pic_ref;
}
void
machopic_finish (asm_out_file)
FILE *asm_out_file;
{
tree temp;
for (temp = machopic_stubs;
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
const char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
const char *stub_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
char *sym;
char *stub;
if (! TREE_USED (temp))
continue;
sym_name = darwin_strip_name_encoding (sym_name);
sym = alloca (strlen (sym_name) + 2);
if (sym_name[0] == '*' || sym_name[0] == '&')
strcpy (sym, sym_name + 1);
else if (sym_name[0] == '-'
|| sym_name[0] == '+'
|| sym_name[0] == '"'
|| name_needs_quotes (sym_name))
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);
if ( IDENTIFIER_WEAK_IMPORT (TREE_VALUE (temp)))
{
fprintf (asm_out_file, "\t.weak_reference ");
assemble_name (asm_out_file, sym_name);
fprintf (asm_out_file, "\n");
}
machopic_output_stub (asm_out_file, sym, stub);
}
for (temp = machopic_non_lazy_pointers;
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
const char *const sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
const char *const lazy_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
if (! TREE_USED (temp))
continue;
if (! indirect_data (sym_name)
&& (machopic_ident_defined_p (TREE_VALUE (temp))
|| (sym_name[0] == '!' && sym_name[2] == 'p')))
{
data_section ();
assemble_align (GET_MODE_ALIGNMENT (Pmode));
assemble_label (lazy_name);
assemble_integer (gen_rtx (SYMBOL_REF, Pmode, sym_name),
GET_MODE_SIZE (Pmode),
GET_MODE_ALIGNMENT (Pmode), 1);
}
else
{
rtx init = const0_rtx;
if ( IDENTIFIER_WEAK_IMPORT (TREE_VALUE (temp)))
{
fprintf (asm_out_file, "\t.weak_reference ");
assemble_name (asm_out_file, sym_name);
fprintf (asm_out_file, "\n");
}
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");
if (sym_name[3] == 's'
&& machopic_ident_defined_p (TREE_VALUE (temp)))
init = gen_rtx (SYMBOL_REF, Pmode, sym_name);
assemble_integer (init, GET_MODE_SIZE (Pmode),
GET_MODE_ALIGNMENT (Pmode), 1);
}
}
}
int
machopic_operand_p (op)
rtx op;
{
if (MACHOPIC_JUST_INDIRECT)
{
while (GET_CODE (op) == CONST)
op = XEXP (op, 0);
if (GET_CODE (op) == SYMBOL_REF)
return machopic_name_defined_p (XSTR (op, 0));
else
return 0;
}
while (GET_CODE (op) == CONST)
op = XEXP (op, 0);
if (GET_CODE (op) == MINUS
&& GET_CODE (XEXP (op, 0)) == SYMBOL_REF
&& GET_CODE (XEXP (op, 1)) == SYMBOL_REF
&& machopic_name_defined_p (XSTR (XEXP (op, 0), 0))
&& machopic_name_defined_p (XSTR (XEXP (op, 1), 0)))
return 1;
return 0;
}
void
darwin_encode_section_info (decl, first)
tree decl;
int first ATTRIBUTE_UNUSED;
{
char code = '\0';
int defined = 0;
rtx sym_ref;
const char *orig_str;
char *new_str;
size_t len, new_len;
if ((TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == VAR_DECL)
&& !DECL_EXTERNAL (decl)
#ifdef DECL_IS_COALESCED_OR_WEAK
&& ! DECL_IS_COALESCED_OR_WEAK (decl)
#endif
&& ((TREE_STATIC (decl)
&& (!DECL_COMMON (decl) || !TREE_PUBLIC (decl)))
|| (DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node)))
defined = 1;
if (TREE_CODE (decl) == VAR_DECL)
{
sym_ref = XEXP (DECL_RTL (decl), 0);
orig_str = XSTR (sym_ref, 0);
if ( orig_str[0] == '_'
&& orig_str[1] == 'O'
&& orig_str[2] == 'B'
&& orig_str[3] == 'J'
&& orig_str[4] == 'C'
&& orig_str[5] == '_')
defined = 1;
}
if (TREE_CODE (decl) == FUNCTION_DECL)
code = (defined ? 'T' : 't');
else if (TREE_CODE (decl) == VAR_DECL)
code = (defined ? 'D' : 'd');
if (code == '\0')
return;
sym_ref = XEXP (DECL_RTL (decl), 0);
orig_str = XSTR (sym_ref, 0);
len = strlen (orig_str) + 1;
if (orig_str[0] == '!')
{
if (code == orig_str[1])
return;
new_str = alloca (len);
memcpy (new_str, orig_str, len);
new_str[1] = code;
XSTR (sym_ref, 0) = ggc_alloc_string (new_str, len);
}
else
{
new_len = len + 4;
new_str = alloca (new_len);
new_str[0] = '!';
new_str[1] = code;
new_str[2] = '_';
if (DECL_PRIVATE_EXTERN (decl))
new_str[2] = 'p';
new_str[3] = '_';
if (indirect_data (orig_str)
&& ! TREE_PUBLIC (decl))
new_str[3] = 's';
memcpy (new_str + 4, orig_str, len);
XSTR (sym_ref, 0) = ggc_alloc_string (new_str, new_len);
}
if (TREE_CODE (decl) == VAR_DECL)
update_non_lazy_ptrs (XSTR (sym_ref, 0));
else
update_stubs (XSTR (sym_ref, 0));
}
const char *
darwin_strip_name_encoding (str)
const char *str;
{
return str[0] == '!' ? str + 4 : str;
}
static void
update_non_lazy_ptrs (name)
const char *name;
{
const char *name1, *name2;
tree temp;
name1 = darwin_strip_name_encoding (name);
for (temp = machopic_non_lazy_pointers;
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
const char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
if (*sym_name == '!')
{
name2 = darwin_strip_name_encoding (sym_name);
if (strcmp (name1, name2) == 0)
{
IDENTIFIER_POINTER (TREE_VALUE (temp)) = name;
break;
}
}
}
}
static void
update_stubs (name)
const char *name;
{
const char *name1, *name2;
tree temp;
name1 = darwin_strip_name_encoding (name);
for (temp = machopic_stubs;
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
const char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
if (*sym_name == '!')
{
name2 = darwin_strip_name_encoding (sym_name);
if (strcmp (name1, name2) == 0)
{
IDENTIFIER_POINTER (TREE_VALUE (temp)) = name;
break;
}
}
}
}
void
machopic_select_section (exp, reloc, align)
tree exp;
int reloc;
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
{
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)))
{
extern int flag_next_runtime;
extern const char *constant_string_class_name;
tree name = TYPE_NAME (TREE_TYPE (exp));
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
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 ();
}
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) || (MACHOPIC_INDIRECT && reloc))
const_data_section ();
else
readonly_data_section ();
}
else
data_section ();
}
else if (TREE_CODE (exp) == CONSTRUCTOR
&& TREE_TYPE (exp)
&& TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
&& TREE_OPERAND (exp, 1))
{
tree name = TREE_OPERAND (exp, 1);
if (TREE_CODE (name) == TREE_LIST && TREE_VALUE (name)
&& TREE_CODE (TREE_VALUE (name)) == NOP_EXPR
&& TREE_OPERAND (TREE_VALUE (name), 0)
&& TREE_OPERAND (TREE_OPERAND (TREE_VALUE (name), 0), 0))
name = TREE_OPERAND (TREE_OPERAND (TREE_VALUE (name), 0), 0);
if (TREE_CODE (name) == VAR_DECL
&& !strcmp (IDENTIFIER_POINTER (DECL_NAME (name)),
"__CFConstantStringClassReference"))
cfstring_constant_object_section ();
else if (TREE_READONLY (exp) || TREE_CONSTANT (exp))
{
if (TREE_SIDE_EFFECTS (exp) || (MACHOPIC_INDIRECT && 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_IMAGE_INFO", 16))
objc_image_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 (MACHOPIC_INDIRECT && reloc)
const_data_section ();
else
readonly_data_section ();
}
else
data_section ();
}
else if (darwin_set_section_for_var_p (exp, reloc, align))
;
else if (TREE_READONLY (exp) || TREE_CONSTANT (exp))
{
if (TREE_SIDE_EFFECTS (exp) || (MACHOPIC_INDIRECT && reloc))
const_data_section ();
else
readonly_data_section ();
}
else
data_section ();
}
void
machopic_select_rtx_section (mode, x, align)
enum machine_mode mode;
rtx x;
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
{
if (GET_MODE_SIZE (mode) == 8)
literal8_section ();
else if (GET_MODE_SIZE (mode) == 4
&& (GET_CODE (x) == CONST_INT
|| GET_CODE (x) == CONST_DOUBLE))
literal4_section ();
else
const_data_section ();
}
void
machopic_asm_out_constructor (symbol, priority)
rtx symbol;
int priority ATTRIBUTE_UNUSED;
{
if (MACHOPIC_INDIRECT)
mod_init_section ();
else
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 (symbol, priority)
rtx symbol;
int priority ATTRIBUTE_UNUSED;
{
if (MACHOPIC_INDIRECT)
mod_term_section ();
else
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 (stream, name)
FILE *stream;
const char *name;
{
if (!!strncmp (name, "_OBJC_", 6))
default_globalize_label (stream, name);
}
void
abort_assembly_and_exit (status)
int status;
{
if (status == FATAL_EXIT_CODE && asm_out_file != 0)
fprintf (asm_out_file, "\n.abort\n");
exit (status);
}
void
darwin_asm_named_section (name, flags)
const char *name;
unsigned int flags ATTRIBUTE_UNUSED;
{
fprintf (asm_out_file, ".section %s\n", name);
}
unsigned int
darwin_section_type_flags (decl, name, reloc)
tree decl;
const char *name;
int reloc;
{
unsigned int flags = default_section_type_flags (decl, name, reloc);
if (decl != 0 && TREE_CODE (decl) != FUNCTION_DECL
&& DECL_IS_COALESCED_OR_WEAK (decl))
flags |= SECTION_WRITE;
return flags;
}
#include "c-common.h"
extern int warning (const char *, ...);
tree
darwin_handle_odd_attribute (node, name, args, flags, no_add_attrs)
tree *node;
tree name;
tree args ATTRIBUTE_UNUSED;
int flags ATTRIBUTE_UNUSED;
bool *no_add_attrs;
{
if (! POSSIBLY_COMPILING_APPLE_KEXT_P ())
{
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;
}
tree
darwin_handle_objc_gc_attribute (node, name, args, flags, no_add_attrs)
tree *node;
tree name;
tree args ATTRIBUTE_UNUSED;
int flags ATTRIBUTE_UNUSED;
bool *no_add_attrs;
{
return NULL_TREE;
}
extern void cstring_section (void),
literal4_section (void), literal8_section (void);
int
darwin_set_section_for_var_p (exp, reloc, align)
tree exp;
int reloc;
int align;
{
if (!reloc && TREE_CODE (exp) == VAR_DECL
&& DECL_ALIGN (exp) == align
&& TREE_READONLY (exp) && DECL_INITIAL (exp))
{
if (! flag_writable_strings
&& 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 ( (unsigned) TREE_STRING_LENGTH (DECL_INITIAL(exp)),
int_size_in_bytes (TREE_TYPE (exp)))
== strlen (TREE_STRING_POINTER (DECL_INITIAL (exp))) + 1)
{
cstring_section ();
return 1;
}
else
{
const_section ();
return 1;
}
}
else
if (TREE_READONLY (TREE_TYPE (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;
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;
}
void
darwin_non_lazy_pcrel (FILE *file, rtx addr)
{
const char *str;
const char *nlp_name;
if (GET_CODE (addr) != SYMBOL_REF)
abort ();
str = darwin_strip_name_encoding (XSTR (addr, 0));
nlp_name = machopic_non_lazy_ptr_name (str);
fputs ("\t.long\t", file);
ASM_OUTPUT_LABELREF (file, nlp_name);
fputs ("-.", file);
}
tree
darwin_cw_asm_special_label (id)
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;
}
static int darwin_dwarf_label_counter;
void
darwin_asm_output_dwarf_delta (file, size, lab1, lab2)
FILE *file;
int size ATTRIBUTE_UNUSED;
const char *lab1, *lab2;
{
int islocaldiff = (lab1[0] == '*' && lab1[1] == 'L'
&& lab2[0] == '*' && lab2[1] == 'L');
if (islocaldiff)
fprintf (file, "\t.set L$set$%d,", darwin_dwarf_label_counter);
else
fprintf (file, "\t%s\t", ".long");
assemble_name (file, lab1);
fprintf (file, "-");
assemble_name (file, lab2);
if (islocaldiff)
fprintf (file, "\n\t.long L$set$%d", darwin_dwarf_label_counter++);
}
#include "gt-darwin.h"