#include "config.h"
#ifdef MACHO_PIC
#include <stdio.h>
#include "tree.h"
#include "obcp/cp-tree.h"
#include "rtl.h"
#include "output.h"
#include "apple/machopic.h"
#include "insn-config.h"
#include "insn-flags.h"
#include "regs.h"
#ifdef TARGET_TOC
#include "flags.h"
#endif
int mcount_called = 0;
#define MAX_NAME_LEN 1024
static tree machopic_defined_list = 0;
extern int flag_dave_indirect;
void machopic_define_decl (decl, name)
tree decl;
const char *name;
{
if (flag_pic)
{
if (TREE_CODE (decl) == FUNCTION_DECL)
{
TREE_ASM_WRITTEN (get_identifier (name)) = 1;
}
}
}
enum machopic_addr_class
machopic_classify_ident (ident)
tree ident;
{
const char *name = IDENTIFIER_POINTER (ident);
int lprefix = ((name[0] == '*'
&& (name[1] == 'L' || (name[1] == '"' && name[2] == 'L')))
|| ( name[0] == '_'
&& name[1] == 'O'
&& name[2] == 'B'
&& name[3] == 'J'
&& name[4] == 'C'
&& name[5] == '_'));
tree temp, decl = lookup_name (ident, 0);
if (!decl)
{
if (lprefix)
{
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 (TREE_CODE (decl) == VAR_DECL)
{
#ifdef HAVE_COALESCED_SYMBOLS
if (DECL_COALESCED (decl))
return MACHOPIC_UNDEFINED_DATA;
#endif
if ((DECL_INITIAL (decl)
|| TREE_STATIC (decl))
&& ! TREE_PUBLIC (decl))
return MACHOPIC_DEFINED_DATA;
}
else if (TREE_CODE (decl) == FUNCTION_DECL
&& (!DECL_EXTERNAL (decl)))
{
#ifdef HAVE_COALESCED_SYMBOLS
if (DECL_COALESCED (decl))
return MACHOPIC_UNDEFINED_FUNCTION;
#endif
if (TREE_STATIC (decl)
|| TREE_ASM_WRITTEN (decl))
return MACHOPIC_DEFINED_FUNCTION;
}
#ifdef HAVE_COALESCED_SYMBOLS
if (DECL_COALESCED (decl))
return (TREE_CODE (decl) == FUNCTION_DECL) ? MACHOPIC_UNDEFINED_FUNCTION :
MACHOPIC_UNDEFINED_DATA;
#endif
for (temp = machopic_defined_list;
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
if (ident == TREE_VALUE (temp))
if (TREE_CODE (decl) == FUNCTION_DECL)
return MACHOPIC_DEFINED_FUNCTION;
else
return MACHOPIC_DEFINED_DATA;
}
if (TREE_CODE (decl) == FUNCTION_DECL)
{
if (lprefix)
return MACHOPIC_DEFINED_FUNCTION;
else
return MACHOPIC_UNDEFINED_FUNCTION;
}
else
{
if (lprefix)
return MACHOPIC_DEFINED_DATA;
else
return MACHOPIC_UNDEFINED_DATA;
}
}
enum machopic_addr_class
machopic_classify_name (name)
const char *name;
{
return machopic_classify_ident (get_identifier (name));
}
int
machopic_ident_defined_p (ident)
tree ident;
{
switch (machopic_classify_ident (ident))
{
case MACHOPIC_UNDEFINED:
case MACHOPIC_UNDEFINED_DATA:
case MACHOPIC_UNDEFINED_FUNCTION:
return 0;
default:
return 1;
}
}
int
machopic_data_defined_p (name)
const char *name;
{
switch (machopic_classify_ident (get_identifier (name)))
{
case MACHOPIC_DEFINED_DATA:
return 1;
default:
return 0;
}
}
int
machopic_name_defined_p (name)
const char *name;
{
return machopic_ident_defined_p (get_identifier (name));
}
void
machopic_define_ident (ident)
tree ident;
{
if (!machopic_ident_defined_p (ident))
machopic_defined_list =
perm_tree_cons (NULL_TREE, ident, machopic_defined_list);
}
void
machopic_define_name (name)
const char *name;
{
machopic_define_ident (get_identifier (name));
}
static char function_base[MAX_NAME_LEN];
int current_machopic_label_num = 0;
char*
machopic_function_base_name ()
{
static char *name = 0, *curr_name;
static int base = 0;
curr_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
if (name != curr_name)
{
current_function_uses_pic_offset_table = 1;
++current_machopic_label_num;
if (*curr_name == '+' || *curr_name == '-')
sprintf (function_base, "*\"L-%d$pb\"", current_machopic_label_num);
else
sprintf (function_base, "*L%d$pb", current_machopic_label_num);
name = curr_name;
}
return function_base;
}
#define MACHOPIC_STUB_HASH_SIZE 37
static tree machopic_non_lazy_pointers[MACHOPIC_STUB_HASH_SIZE] = {0};
static int name_needs_quotes(const char *name)
{
int c;
while ((c = *name++) != '\0')
{
if (! ((c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9')
|| c == '_'))
return 1;
}
return 0;
}
enum machopic_name_type { NORMAL_NAME, STUB_NAME, LAZY_PTR_NAME };
static unsigned int
MACHOPIC_STUB_HASH (const char *name, enum machopic_name_type ntype)
{
unsigned int hash = 0;
char buffer[MAX_NAME_LEN];
const char *np = name;
if (ntype != NORMAL_NAME)
{
int quoted = FALSE;
char *cp = buffer;
if (*np++ != '*')
abort ();
if (ntype == STUB_NAME && *np == '\"')
{
quoted = TRUE;
++np;
}
if (*np++ != 'L')
abort ();
if (*np++ != '_')
abort ();
while (*np)
{
if (*np == '$')
{
if (! strcmp (np+1, (ntype == LAZY_PTR_NAME) ? "non_lazy_ptr"
: (quoted) ? "stub\"" : "stub"))
break;
}
*cp++ = *np++;
}
*cp = 0;
np = buffer;
}
while (*np)
{
unsigned int g;
hash <<= 4;
hash += *np;
g = hash & 0xF0000000;
if (g)
{
hash ^= (g >> 24);
hash ^= g;
}
++np;
}
return hash % MACHOPIC_STUB_HASH_SIZE;
}
char*
machopic_non_lazy_ptr_name (name)
const char *name;
{
tree temp, ident = get_identifier (name);
unsigned int idx = MACHOPIC_STUB_HASH (name, NORMAL_NAME);
for (temp = machopic_non_lazy_pointers[idx];
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
if (ident == TREE_VALUE (temp))
return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
}
{
char buffer[MAX_NAME_LEN];
tree ptr_name;
if (name[0] == '*')
{
strcpy (buffer, "*L");
strcat (buffer, name+1);
}
else
{
strcpy (buffer, "*L_");
strcat (buffer, name);
}
strcat (buffer, "$non_lazy_ptr");
ptr_name = get_identifier (buffer);
machopic_non_lazy_pointers[idx]
= perm_tree_cons (ptr_name, ident, machopic_non_lazy_pointers[idx]);
TREE_USED (machopic_non_lazy_pointers[idx]) = 0;
return IDENTIFIER_POINTER (ptr_name);
}
}
static tree machopic_stubs[MACHOPIC_STUB_HASH_SIZE] = {0};
char*
machopic_stub_name (name)
const char *name;
{
tree temp, ident = get_identifier (name);
unsigned idx = MACHOPIC_STUB_HASH (name, NORMAL_NAME);
for (temp = machopic_stubs[idx];
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
if (ident == TREE_VALUE (temp))
return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
}
{
char buffer[MAX_NAME_LEN];
tree ptr_name;
int needs_quotes = name_needs_quotes(name);
if (name[0] == '*')
{
strcpy (buffer, (needs_quotes) ? "*\"L" : "*L");
strcat (buffer, name+1);
}
else
{
strcpy (buffer, (needs_quotes) ? "*\"L_" : "*L_");
strcat (buffer, name);
}
strcat (buffer, (needs_quotes) ? "$stub\"" : "$stub");
ptr_name = get_identifier (buffer);
machopic_stubs[idx] = perm_tree_cons (ptr_name,
ident, machopic_stubs[idx]);
TREE_USED (machopic_stubs[idx]) = 0;
return IDENTIFIER_POINTER (ptr_name);
}
}
void
machopic_validate_stub_or_non_lazy_ptr (name, validate_stub)
const char *name;
int validate_stub;
{
tree temp, ident = get_identifier (name);
unsigned idx = MACHOPIC_STUB_HASH (name,
(validate_stub) ? STUB_NAME : LAZY_PTR_NAME);
for (temp = validate_stub ? machopic_stubs[idx]
: machopic_non_lazy_pointers[idx];
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
if (ident == TREE_PURPOSE (temp))
{
TREE_USED (temp) = 1;
ident = TREE_VALUE (temp);
if (TREE_CODE (ident) == IDENTIFIER_NODE)
TREE_SYMBOL_REFERENCED (ident) = 1;
return;
}
abort ();
}
rtx
machopic_indirect_data_reference (orig, reg)
rtx orig, reg;
{
rtx ptr_ref = orig;
if (! MACHOPIC_INDIRECT)
return orig;
if (GET_CODE (orig) == SYMBOL_REF)
{
const char *name = XSTR (orig, 0);
if (machopic_data_defined_p (name))
{
rtx pic_base = gen_rtx (SYMBOL_REF, Pmode,
machopic_function_base_name ());
rtx offset = gen_rtx (CONST, Pmode,
gen_rtx (MINUS, Pmode, orig, pic_base));
#if defined (HAVE_hi_sum) || defined (TARGET_TOC)
rtx hi_sum_reg =
#ifdef HI_SUM_TARGET_RTX
reload_in_progress ? HI_SUM_TARGET_RTX : gen_reg_rtx (SImode);
#else
reg;
#endif
if (reg == 0) 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)));
if (0)
{
rtx insn = get_last_insn ();
rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
if (note)
XEXP (note, 0) = orig;
else
REG_NOTES (insn) = gen_rtx (EXPR_LIST,
REG_EQUAL, orig, REG_NOTES (insn));
}
orig = reg;
#elif defined (HAVE_lo_sum)
if (reg == 0) abort ();
emit_insn (gen_rtx (SET, VOIDmode, reg,
gen_rtx (HIGH, Pmode, offset)));
emit_insn (gen_rtx (SET, VOIDmode, reg,
gen_rtx (LO_SUM, Pmode, reg, offset)));
emit_insn (gen_rtx (USE, VOIDmode,
gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)));
orig = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, reg);
#elif defined (MACHOPIC_M68K)
orig = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, offset);
#endif
return orig;
}
ptr_ref = gen_rtx (SYMBOL_REF, Pmode,
machopic_non_lazy_ptr_name (name));
ptr_ref = gen_rtx_MEM (Pmode, ptr_ref);
RTX_UNCHANGING_P (ptr_ref) = 1;
return ptr_ref;
}
else if (GET_CODE (orig) == CONST)
{
rtx base, offset, 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)
{
#ifdef INT_14_BITS
if (INT_14_BITS (orig))
{
#endif
result = plus_constant_for_output (base, INTVAL (orig));
#ifdef INT_14_BITS
}
else if (!reload_in_progress)
{
orig = force_reg (Pmode, orig);
result = gen_rtx (PLUS, Pmode, base, orig);
}
else
{
emit_insn (gen_rtx (SET, SImode, reg,
gen_rtx (PLUS, Pmode,
base, gen_rtx (HIGH, SImode, orig))));
emit_insn (gen_rtx (SET, SImode, reg,
gen_rtx (LO_SUM, SImode,
reg, orig)));
result = reg;
}
#endif
}
else
{
result = gen_rtx (PLUS, Pmode, base, orig);
}
if (RTX_UNCHANGING_P (base) && RTX_UNCHANGING_P (orig))
RTX_UNCHANGING_P (result) = 1;
if (MACHOPIC_JUST_INDIRECT && GET_CODE (base) == MEM)
{
if (reg)
{
emit_move_insn (reg, result);
result = reg;
}
else
{
result = force_reg (GET_MODE (result), result);
}
}
return result;
}
else if (GET_CODE (orig) == MEM)
XEXP (ptr_ref, 0) = machopic_indirect_data_reference (XEXP (orig, 0), reg);
#ifndef MACHOPIC_M68K
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;
}
#endif
return ptr_ref;
}
static
int
func_name_maybe_scoped (const char *const in_fname)
{
static signed char is_cplusplus = -1;
if (is_cplusplus < 0)
is_cplusplus = (strcmp (lang_identify (), "cplusplus") == 0);
if (is_cplusplus)
{
{
const char *fname = in_fname;
while (*fname == '_') ++fname;
while (*fname != 0)
{
if (fname[0] == '_' && fname[1] == '_'
&& (fname[2] == 'F' || (fname[2] >= '0' && fname[2] <= '9')))
return 0;
++fname;
}
if (! strncmp (in_fname,
"__static_initialization_and_destruction_", 40))
return 0;
return 1;
}
}
return 0;
}
rtx
machopic_indirect_call_target (target)
rtx target;
{
if (GET_CODE (target) != MEM)
return target;
if (MACHOPIC_INDIRECT && GET_CODE (XEXP (target, 0)) == SYMBOL_REF)
{
enum machine_mode mode = GET_MODE (XEXP (target, 0));
const char *name = XSTR (XEXP (target, 0), 0);
if (!machopic_name_defined_p (name) || func_name_maybe_scoped (name))
{
if (flag_dave_indirect)
{
XEXP (target, 0) = force_reg (Pmode, XEXP (target, 0));
}
else
{
const char *stub_name = machopic_stub_name (name);
XEXP (target, 0) = gen_rtx (SYMBOL_REF, mode, stub_name);
RTX_UNCHANGING_P (target) = 1;
}
}
}
return target;
}
rtx
machopic_legitimize_pic_address (orig, mode, reg)
rtx orig, reg;
enum machine_mode mode;
{
rtx pic_ref = orig;
if (! MACHOPIC_PURE)
return orig;
if (GET_CODE (orig) == LABEL_REF
|| (GET_CODE (orig) == SYMBOL_REF
))
{
rtx equiv = orig;
rtx pic_base;
orig = machopic_indirect_data_reference (orig, reg);
if (GET_CODE (orig) == PLUS
&& GET_CODE (XEXP (orig, 0)) == REG)
{
if (reg == 0)
return force_reg (mode, orig);
emit_move_insn (reg, orig);
return reg;
}
pic_base = gen_rtx (SYMBOL_REF, Pmode,
machopic_function_base_name ());
if (GET_CODE (orig) == MEM)
{
if (reg == 0)
if (reload_in_progress)
abort ();
else
reg = gen_reg_rtx (Pmode);
#ifdef HAVE_lo_sum
if (GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (orig, 0)) == LABEL_REF)
{
rtx offset = gen_rtx (CONST, Pmode,
gen_rtx (MINUS, Pmode,
XEXP (orig, 0), pic_base));
rtx mem;
#if defined (HAVE_hi_sum) || defined (TARGET_TOC)
rtx hi_sum_reg = reload_in_progress ?
#ifdef HI_SUM_TARGET_RTX
HI_SUM_TARGET_RTX :
#else
reg :
#endif
gen_reg_rtx (Pmode);
emit_insn (gen_rtx (SET, Pmode, hi_sum_reg,
gen_rtx (PLUS, Pmode,
pic_offset_table_rtx,
gen_rtx (HIGH, Pmode, offset))));
#if 1
mem = gen_rtx_MEM (GET_MODE (orig),
gen_rtx (LO_SUM, Pmode, hi_sum_reg, offset));
RTX_UNCHANGING_P (mem) = 1;
emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
#else
emit_insn (gen_rtx (SET, VOIDmode, reg,
gen_rtx (MEM, GET_MODE (orig),
gen_rtx (LO_SUM, Pmode,
hi_sum_reg, offset))));
#endif
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
#ifndef PIC_OFFSET_TABLE_RTX
#define PIC_OFFSET_TABLE_RTX pic_offset_table_rtx
#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
pic_ref = gen_rtx (PLUS, Pmode,
pic,
gen_rtx (CONST, Pmode,
gen_rtx (MINUS, Pmode,
XEXP (orig, 0),
pic_base)));
}
#if !defined (HAVE_hi_sum) && !defined (TARGET_TOC)
RTX_UNCHANGING_P (pic_ref) = 1;
emit_move_insn (reg, pic_ref);
pic_ref = gen_rtx (MEM, GET_MODE (orig), reg);
#endif
}
else
{
#ifdef HAVE_lo_sum
if (GET_CODE (orig) == SYMBOL_REF
|| GET_CODE (orig) == LABEL_REF)
{
rtx offset = gen_rtx (CONST, Pmode,
gen_rtx (MINUS, Pmode, orig, pic_base));
#if defined (HAVE_hi_sum) || defined (TARGET_TOC)
rtx hi_sum_reg;
if (reg == 0)
if (reload_in_progress)
abort ();
else
reg = gen_reg_rtx (SImode);
hi_sum_reg =
#ifdef HI_SUM_TARGET_RTX
reload_in_progress ? HI_SUM_TARGET_RTX : gen_reg_rtx (SImode);
#else
reg;
#endif
emit_insn (gen_rtx (SET, Pmode, hi_sum_reg,
gen_rtx (PLUS, Pmode,
pic_offset_table_rtx,
gen_rtx (HIGH, Pmode, offset))));
emit_insn (gen_rtx (SET, VOIDmode, reg,
gen_rtx (LO_SUM, Pmode,
hi_sum_reg, offset)));
pic_ref = reg;
#else
emit_insn (gen_rtx (SET, VOIDmode, reg,
gen_rtx (HIGH, Pmode, offset)));
emit_insn (gen_rtx (SET, VOIDmode, reg,
gen_rtx (LO_SUM, Pmode, reg, offset)));
pic_ref = gen_rtx (PLUS, Pmode,
pic_offset_table_rtx, reg);
#endif
}
else
#endif
if (GET_CODE (orig) == REG)
{
return orig;
}
else
{
rtx pic = PIC_OFFSET_TABLE_RTX;
if (GET_CODE (pic) != REG)
{
emit_move_insn (reg, pic);
pic = reg;
}
#if 0
emit_insn (gen_rtx (USE, VOIDmode,
pic_offset_table_rtx));
#endif
pic_ref = gen_rtx (PLUS, Pmode,
pic,
gen_rtx (CONST, Pmode,
gen_rtx (MINUS, Pmode,
orig, pic_base)));
}
}
RTX_UNCHANGING_P (pic_ref) = 1;
if (GET_CODE (pic_ref) != REG)
{
if (reg != 0)
{
emit_move_insn (reg, pic_ref);
return reg;
}
else
{
return force_reg (mode, pic_ref);
}
}
else
{
return pic_ref;
}
}
else if (GET_CODE (orig) == SYMBOL_REF)
return orig;
else if (GET_CODE (orig) == PLUS
&& (GET_CODE (XEXP (orig, 0)) == MEM
|| GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (orig, 0)) == LABEL_REF)
&& XEXP (orig, 0) != pic_offset_table_rtx
&& GET_CODE (XEXP (orig, 1)) != REG)
{
rtx base, offset;
int is_complex;
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)
{
#ifdef INT_14_BITS
if (INT_14_BITS (orig))
#endif
{
pic_ref = plus_constant_for_output (base, INTVAL (orig));
is_complex = 1;
}
#ifdef INT_14_BITS
else if (!reload_in_progress)
{
orig = force_reg (Pmode, orig);
pic_ref = gen_rtx (PLUS, Pmode, base, orig);
}
else
{
emit_insn (gen_rtx (SET, SImode, reg,
gen_rtx (PLUS, Pmode,
base, gen_rtx (HIGH, SImode, orig))));
emit_insn (gen_rtx (SET, SImode, reg,
gen_rtx (LO_SUM, SImode,
reg, orig)));
pic_ref = reg;
}
#endif
}
else
{
pic_ref = gen_rtx (PLUS, Pmode, base, orig);
}
if (RTX_UNCHANGING_P (base) && RTX_UNCHANGING_P (orig))
RTX_UNCHANGING_P (pic_ref) = 1;
if (reg && is_complex)
{
emit_move_insn (reg, pic_ref);
pic_ref = reg;
}
}
else if (GET_CODE (orig) == CONST)
{
return machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
}
else if (GET_CODE (orig) == MEM
&& GET_CODE (XEXP (orig, 0)) == SYMBOL_REF)
{
rtx addr = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
addr = gen_rtx (MEM, GET_MODE (orig), addr);
RTX_UNCHANGING_P (addr) = RTX_UNCHANGING_P (orig);
emit_move_insn (reg, addr);
pic_ref = reg;
}
return pic_ref;
}
#ifdef AS_SET_WORKS
static struct set_override {
const char *original, *override;
struct set_override *next;
} *overrides = 0;
static
void
remember_set (const char *original, const char *override)
{
struct set_override *p = malloc (sizeof (struct set_override));
p->original = original;
p->override = override;
p->next = overrides;
overrides = p;
}
#endif
void
machopic_finish (asm_out_file)
FILE *asm_out_file;
{
tree temp;
int idx;
#ifdef AS_SET_WORKS
struct set_override *p;
for (p = overrides; p != NULL; p = p->next)
fprintf (asm_out_file, "\t.set _%s,_%s\n", p->original, p->override);
#endif
for (idx = 0; idx < MACHOPIC_STUB_HASH_SIZE; ++idx)
for (temp = machopic_stubs[idx];
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
char symb[MAX_NAME_LEN];
char stub[MAX_NAME_LEN];
const char *symb_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
const char *stub_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
tree decl;
if (! TREE_USED (temp))
continue;
decl = lookup_name (TREE_VALUE (temp), 0);
if (decl
&& TREE_CODE (decl) == FUNCTION_DECL
&& DECL_INLINE (decl)
&& ! TREE_PUBLIC (decl)
&& ! TREE_ASM_WRITTEN (decl))
continue;
if (symb_name[0] == '*')
strcpy (symb, symb_name+1);
else if (symb_name[0] == '-' || symb_name[0] == '+')
strcpy (symb, symb_name);
else
symb[0] = '_', strcpy (symb+1, symb_name);
if (stub_name[0] == '*')
strcpy (stub, stub_name+1);
else
stub[0] = '_', strcpy (stub+1, stub_name);
machopic_output_stub (asm_out_file, symb, stub);
}
#if defined (I386) || defined (TARGET_TOC)
{
if (flag_pic && mcount_called)
machopic_output_stub (asm_out_file, "mcount", "Lmcount$stub");
}
#endif
for (idx = 0; idx < MACHOPIC_STUB_HASH_SIZE; ++idx)
for (temp = machopic_non_lazy_pointers[idx];
temp != NULL_TREE;
temp = TREE_CHAIN (temp))
{
const char *symb_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
const char *lazy_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
tree decl;
if (! TREE_USED (temp))
continue;
decl = lookup_name (TREE_VALUE (temp), 0);
if (machopic_ident_defined_p (TREE_VALUE (temp))
|| (decl && DECL_PRIVATE_EXTERN (decl)))
{
char symb[MAX_NAME_LEN];
if (symb_name[0] == '*')
strcpy (symb, symb_name+1);
else
strcpy (symb, symb_name);
data_section ();
assemble_align (UNITS_PER_WORD * BITS_PER_UNIT);
assemble_label (lazy_name);
assemble_integer (gen_rtx (SYMBOL_REF, Pmode, symb_name),
GET_MODE_SIZE (Pmode), 1);
}
else
{
machopic_nl_symbol_ptr_section ();
assemble_name (asm_out_file, lazy_name);
fprintf (asm_out_file, ":\n");
fprintf (asm_out_file, "\t.indirect_symbol ");
assemble_name (asm_out_file, symb_name);
fprintf (asm_out_file, "\n");
assemble_integer (const0_rtx, GET_MODE_SIZE (Pmode), 1);
}
}
}
int
machopic_operand_p (op)
rtx op;
{
if (MACHOPIC_JUST_INDIRECT)
{
while (GET_CODE (op) == CONST)
op = XEXP (op, 0);
if (GET_CODE (op) == SYMBOL_REF)
return machopic_name_defined_p (XSTR (op, 0));
else
return 0;
}
while (GET_CODE (op) == CONST)
op = XEXP (op, 0);
if (GET_CODE (op) == MINUS
&& GET_CODE (XEXP (op, 0)) == SYMBOL_REF
&& GET_CODE (XEXP (op, 1)) == SYMBOL_REF
&& machopic_name_defined_p (XSTR (XEXP (op, 0), 0))
&& machopic_name_defined_p (XSTR (XEXP (op, 1), 0)))
{
return 1;
}
#ifdef TARGET_TOC
else if (GET_CODE (op) == SYMBOL_REF
&& (machopic_classify_name (XSTR (op, 0))
== MACHOPIC_DEFINED_FUNCTION))
{
return 1;
}
#endif
return 0;
}
int Barfola (int x) {return x;}
void mangle_coalesced_item_name (tree decl, int output_stub)
{
const char *const sourcefile = DECL_SOURCE_FILE (decl);
const char *cp;
const char *name;
char sn[32], *override, *dp;
int i;
rtx x = 0;
if (! DECL_COALESCED (decl))
abort ();
if (TREE_CODE (decl) == FUNCTION_DECL)
{
x = DECL_RTL (decl);
if (GET_CODE (x) != MEM)
abort ();
x = XEXP (x, 0);
if (GET_CODE (x) != SYMBOL_REF)
abort ();
name = XSTR (x, 0);
}
else
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
if (0) fprintf (stderr, "# %s in '%s'\n", name, sourcefile);
cp = rindex (sourcefile, '/');
if (cp == NULL)
cp = sourcefile;
else
++cp;
sn[0] = '_';
for (i = 0; cp[i] != 0 && i < 16; ++i)
sn[i+1] = (isalnum(cp[i])) ? cp[i] : '_';
sn[i+1] = 0;
if (0)
{
char hstr[8];
sprintf (hstr, "_%d", DECL_SOURCE_LINE (decl));
strcat (sn, hstr);
}
else
{
unsigned int hash = DECL_SOURCE_LINE (decl);
static const char hc[32] = "0123456789abcdefghijklmnopqrstuv";
char hstr[8];
#if 1
cp = rindex (sourcefile, '/');
if (cp == NULL)
#endif
cp = sourcefile;
while (*cp)
{
if (isalnum (*cp))
{
unsigned int g;
hash <<= 4;
hash += *cp;
g = hash & 0xF0000000;
if (g)
{
hash ^= (g >> 24);
hash ^= g;
}
}
++cp;
}
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))
{
rtx insn = DECL_SAVED_INSNS (decl);
for (i = 0 ; insn != 0; insn = NEXT_INSN (insn))
if (GET_CODE (insn) != NOTE)
++i;
if (i)
{
hash <<= 4;
hash += i;
}
}
hstr[0] = '_'; hstr[1] = hc[hash & 0x1F];
hstr[2] = hc[(hash >> 5) & 0x1f];
hstr[3] = hc[(hash >> 10) & 0x1f];
hstr[4] = hc[(hash >> 15) & 0x1f];
hstr[5] = hc[(hash >> 20) & 0x1f];
hstr[6] = hc[(hash >> 25) & 0x1f];
hstr[7] = 0;
strcat (sn, hstr);
}
override = malloc (strlen (name) + strlen (sn) + 1);
strcpy (override, name);
strcat (override, sn);
#ifdef AS_SET_WORKS
remember_set (name, override);
#else
if (output_stub && TREE_CODE (decl) == FUNCTION_DECL)
{
DECL_COALESCED (decl) = 0;
function_section (decl);
DECL_COALESCED (decl) = 1;
i = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (i > 0)
ASM_OUTPUT_ALIGN (asm_out_file, i);
if (TREE_PUBLIC (decl))
ASM_GLOBALIZE_LABEL (asm_out_file, name);
ASM_OUTPUT_LABEL (asm_out_file, name);
MACHOPIC_DEFINE_DECL (decl, name);
#ifdef TARGET_TOC
fprintf (asm_out_file, "\tb ");
#else
fprintf (asm_out_file, "\tjmp ");
#endif
assemble_name (asm_out_file, machopic_stub_name (override));
fprintf (asm_out_file, "\n\n");
#if 0
DECL_SECTION_NAME (decl) = build_string (14, "__coal_inlines");
#endif
}
#endif
if (x)
XSTR (x, 0) = override;
else
DECL_ASSEMBLER_NAME (decl) = get_identifier (override);
}
int rtti_var_p (tree decl)
{
if (TREE_CODE (decl) == VAR_DECL && DECL_ARTIFICIAL (decl) && DECL_RTL (decl))
{
const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
if (!strncmp (name, "__ti", 4))
return 1;
}
return 0;
}
int rtti_func_p (tree decl)
{
if (TREE_CODE (decl) == FUNCTION_DECL)
{
const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
if (!strncmp (name, "__tf", 4))
return 1;
}
return 0;
}
int is_systemlib_rtti_p (tree decl)
{
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
{
const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
static const char libnames[][22] = {
"13bad_exception", "9exception", "9bad_alloc",
"10bad_typeid", "14__si_type_info", "16__user_type_info",
"17__class_type_info", "8bad_cast", "9type_info",
"16__attr_type_info", "16__func_type_info", "16__ptmd_type_info",
"16__ptmf_type_info", "17__array_type_info",
"19__builtin_type_info", "19__pointer_type_info"
};
static const char s_libnames[][3] = {
"Sc", "Uc", "Ui", "Ul", "Us", "Ux",
"b", "c", "d", "f", "i", "l",
"r", "s", "v", "w", "x"
};
int ix;
if (name[0] != '_' || name[1] != '_' || name[2] != 't')
return 0;
if (name[3] != 'f' && name[3] != 'i')
return 0;
name += 4;
for (ix = 0; ix < sizeof (libnames) / sizeof (libnames[0]); ++ix)
if (*name == libnames[ix][0] && !strcmp (name+1, libnames[ix]+1))
return 1;
for (ix = 0; ix < sizeof (s_libnames) / sizeof (s_libnames[0]); ++ix)
if (*name == s_libnames[ix][0] && !strcmp (name+1, s_libnames[ix]+1))
return 1;
}
return 0;
}
#endif