summaryrefslogtreecommitdiff
path: root/gcc/config/frv/frv.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/frv/frv.c')
-rw-r--r--gcc/config/frv/frv.c941
1 files changed, 703 insertions, 238 deletions
diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c
index 1773a825d6a..92daeaa2f6d 100644
--- a/gcc/config/frv/frv.c
+++ b/gcc/config/frv/frv.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2004
+/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004
Free Software Foundation, Inc.
Contributed by Red Hat, Inc.
@@ -48,11 +48,21 @@ Boston, MA 02111-1307, USA. */
#include <ctype.h>
#include "target.h"
#include "target-def.h"
+#include "integrate.h"
#ifndef FRV_INLINE
#define FRV_INLINE inline
#endif
+/* Information about a relocation unspec. SYMBOL is the relocation symbol
+ (a SYMBOL_REF or LABEL_REF), RELOC is the type of relocation and OFFSET
+ is the constant addend. */
+struct frv_unspec {
+ rtx symbol;
+ int reloc;
+ HOST_WIDE_INT offset;
+};
+
/* Temporary register allocation support structure. */
typedef struct frv_tmp_reg_struct
{
@@ -199,8 +209,8 @@ int frv_sched_lookahead = 4; /* -msched-lookahead=n */
/* Forward references */
static int frv_default_flags_for_cpu (void);
static int frv_string_begins_with (tree, const char *);
-static FRV_INLINE int const_small_data_p (rtx);
-static FRV_INLINE int plus_small_data_p (rtx, rtx);
+static FRV_INLINE bool frv_small_data_reloc_p (rtx, int);
+static FRV_INLINE bool frv_const_unspec_p (rtx, struct frv_unspec *);
static void frv_print_operand_memory_reference_reg
(FILE *, rtx);
static void frv_print_operand_memory_reference (FILE *, rtx, int);
@@ -270,6 +280,11 @@ static rtx frv_expand_builtin_saveregs (void);
static bool frv_rtx_costs (rtx, int, int, int*);
static void frv_asm_out_constructor (rtx, int);
static void frv_asm_out_destructor (rtx, int);
+static bool frv_function_symbol_referenced_p (rtx);
+static bool frv_cannot_force_const_mem (rtx);
+static const char *unspec_got_name (int);
+static void frv_output_const_unspec (FILE *,
+ const struct frv_unspec *);
static rtx frv_struct_value_rtx (tree, int);
/* Initialize the GCC target structure. */
@@ -304,6 +319,9 @@ static rtx frv_struct_value_rtx (tree, int);
#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE frv_use_dfa_pipeline_interface
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM frv_cannot_force_const_mem
+
#undef TARGET_STRUCT_VALUE_RTX
#define TARGET_STRUCT_VALUE_RTX frv_struct_value_rtx
@@ -314,47 +332,74 @@ static rtx frv_struct_value_rtx (tree, int);
struct gcc_target targetm = TARGET_INITIALIZER;
-/* Given a CONST, return true if the symbol_ref points to small data. */
+/* Return true if SYMBOL is a small data symbol and relocation RELOC
+ can be used to access it directly in a load or store. */
-static FRV_INLINE int
-const_small_data_p (rtx x)
+static FRV_INLINE bool
+frv_small_data_reloc_p (rtx symbol, int reloc)
{
- rtx x0, x1;
+ return (GET_CODE (symbol) == SYMBOL_REF
+ && SYMBOL_REF_SMALL_P (symbol)
+ && (!TARGET_FDPIC || flag_pic == 1)
+ && (reloc == R_FRV_GOTOFF12 || reloc == R_FRV_GPREL12));
+}
- if (GET_CODE (XEXP (x, 0)) != PLUS)
- return FALSE;
+/* Return true if X is a valid relocation unspec. If it is, fill in UNSPEC
+ appropriately. */
- x0 = XEXP (XEXP (x, 0), 0);
- if (GET_CODE (x0) != SYMBOL_REF || !SYMBOL_REF_SMALL_P (x0))
- return FALSE;
+static FRV_INLINE bool
+frv_const_unspec_p (rtx x, struct frv_unspec *unspec)
+{
+ if (GET_CODE (x) == CONST)
+ {
+ unspec->offset = 0;
+ x = XEXP (x, 0);
+ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ unspec->offset += INTVAL (XEXP (x, 1));
+ x = XEXP (x, 0);
+ }
+ if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_GOT)
+ {
+ unspec->symbol = XVECEXP (x, 0, 0);
+ unspec->reloc = INTVAL (XVECEXP (x, 0, 1));
- x1 = XEXP (XEXP (x, 0), 1);
- if (GET_CODE (x1) != CONST_INT
- || !IN_RANGE_P (INTVAL (x1), -2048, 2047))
- return FALSE;
+ if (unspec->offset == 0)
+ return true;
- return TRUE;
+ if (frv_small_data_reloc_p (unspec->symbol, unspec->reloc)
+ && unspec->offset > 0
+ && (unsigned HOST_WIDE_INT) unspec->offset < g_switch_value)
+ return true;
+ }
+ }
+ return false;
}
-/* Given a PLUS, return true if this is a small data reference. */
+/* Decide whether we can force certain constants to memory. If we
+ decide we can't, the caller should be able to cope with it in
+ another way.
-static FRV_INLINE int
-plus_small_data_p (rtx op0, rtx op1)
-{
- if (GET_MODE (op0) == SImode
- && GET_CODE (op0) == REG
- && REGNO (op0) == SDA_BASE_REG)
- {
- if (GET_CODE (op1) == SYMBOL_REF)
- return SYMBOL_REF_SMALL_P (op1);
+ We never allow constants to be forced into memory for TARGET_FDPIC.
+ This is necessary for several reasons:
- if (GET_CODE (op1) == CONST)
- return const_small_data_p (op1);
- }
+ 1. Since LEGITIMATE_CONSTANT_P rejects constant pool addresses, the
+ target-independent code will try to force them into the constant
+ pool, thus leading to infinite recursion.
- return FALSE;
-}
+ 2. We can never introduce new constant pool references during reload.
+ Any such reference would require use of the pseudo FDPIC register.
+ 3. We can't represent a constant added to a function pointer (which is
+ not the same as a pointer to a function+constant).
+
+ 4. In many cases, it's more efficient to calculate the constant in-line. */
+
+static bool
+frv_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
+{
+ return TARGET_FDPIC;
+}
static int
frv_default_flags_for_cpu (void)
@@ -577,13 +622,18 @@ frv_override_options (void)
reg_class_from_letter['A'] = QUAD_ACC_REGS;
reg_class_from_letter['B'] = ACCG_REGS;
reg_class_from_letter['C'] = CR_REGS;
+ reg_class_from_letter['W'] = FDPIC_CALL_REGS; /* gp14+15 */
+ reg_class_from_letter['Z'] = FDPIC_REGS; /* gp15 */
/* There is no single unaligned SI op for PIC code. Sometimes we
need to use ".4byte" and sometimes we need to use ".picptr".
See frv_assemble_integer for details. */
- if (flag_pic)
+ if (flag_pic || TARGET_FDPIC)
targetm.asm_out.unaligned_op.si = 0;
+ if ((target_flags_explicit & MASK_LINKED_FP) == 0)
+ target_flags |= MASK_LINKED_FP;
+
init_machine_status = frv_init_machine_status;
}
@@ -686,6 +736,10 @@ frv_conditional_register_usage (void)
fixed_regs[FCR_FIRST] = call_used_regs[FCR_FIRST] = 1;
}
+ if (TARGET_FDPIC)
+ fixed_regs[GPR_FIRST + 16] = fixed_regs[GPR_FIRST + 17] =
+ call_used_regs[GPR_FIRST + 16] = call_used_regs[GPR_FIRST + 17] = 0;
+
#if 0
/* If -fpic, SDA_BASE_REG is the PIC register. */
if (g_switch_value == 0 && !flag_pic)
@@ -966,7 +1020,8 @@ frv_stack_info (void)
if ((regs_ever_live[regno] && !call_used_regs[regno])
|| (current_function_calls_eh_return
&& (regno >= FIRST_EH_REGNUM && regno <= LAST_EH_REGNUM))
- || (flag_pic && cfun->uses_pic_offset_table && regno == PIC_REGNO))
+ || (!TARGET_FDPIC && flag_pic
+ && cfun->uses_pic_offset_table && regno == PIC_REGNO))
{
info_ptr->save_p[regno] = REG_SAVE_1WORD;
size_1word += UNITS_PER_WORD;
@@ -982,8 +1037,11 @@ frv_stack_info (void)
case STACK_REGS_LR:
if (regs_ever_live[LR_REGNO]
|| profile_flag
- || frame_pointer_needed
- || (flag_pic && cfun->uses_pic_offset_table))
+ /* This is set for __builtin_return_address, etc. */
+ || cfun->machine->frame_needed
+ || (TARGET_LINKED_FP && frame_pointer_needed)
+ || (!TARGET_FDPIC && flag_pic
+ && cfun->uses_pic_offset_table))
{
info_ptr->save_p[LR_REGNO] = REG_SAVE_1WORD;
size_1word += UNITS_PER_WORD;
@@ -1077,6 +1135,7 @@ frv_stack_info (void)
/* See if we need to create a frame at all, if so add header area. */
if (info_ptr->total_size > 0
+ || frame_pointer_needed
|| info_ptr->regs[STACK_REGS_LR].size_1word > 0
|| info_ptr->regs[STACK_REGS_STRUCT].size_1word > 0)
{
@@ -1652,7 +1711,7 @@ frv_expand_prologue (void)
emit_insn (gen_blockage ());
/* Set up pic register/small data register for this function. */
- if (flag_pic && cfun->uses_pic_offset_table)
+ if (!TARGET_FDPIC && flag_pic && cfun->uses_pic_offset_table)
emit_insn (gen_pic_prologue (gen_rtx_REG (Pmode, PIC_REGNO),
gen_rtx_REG (Pmode, LR_REGNO),
gen_rtx_REG (SImode, OFFSET_REGNO)));
@@ -1787,7 +1846,31 @@ frv_asm_output_mi_thunk (FILE *file,
fprintf (file, "\tadd %s,%s,%s\n", name_add, name_arg0, name_arg0);
}
- if (!flag_pic)
+ if (TARGET_FDPIC)
+ {
+ const char *name_pic = reg_names[FDPIC_REGNO];
+ name_jmp = reg_names[FDPIC_FPTR_REGNO];
+
+ if (flag_pic != 1)
+ {
+ fprintf (file, "\tsethi%s #gotofffuncdeschi(", parallel);
+ assemble_name (file, name_func);
+ fprintf (file, "),%s\n", name_jmp);
+
+ fprintf (file, "\tsetlo #gotofffuncdesclo(");
+ assemble_name (file, name_func);
+ fprintf (file, "),%s\n", name_jmp);
+
+ fprintf (file, "\tldd @(%s,%s), %s\n", name_jmp, name_pic, name_jmp);
+ }
+ else
+ {
+ fprintf (file, "\tlddo @(%s,#gotofffuncdesc12(", name_pic);
+ assemble_name (file, name_func);
+ fprintf (file, "\t)), %s\n", name_jmp);
+ }
+ }
+ else if (!flag_pic)
{
fprintf (file, "\tsethi%s #hi(", parallel);
assemble_name (file, name_func);
@@ -1852,6 +1935,11 @@ frv_asm_output_mi_thunk (FILE *file,
int
frv_frame_pointer_required (void)
{
+ /* If we forgoing the usual linkage requirements, we only need
+ a frame pointer if the stack pointer might change. */
+ if (!TARGET_LINKED_FP)
+ return !current_function_sp_is_unchanging;
+
if (! current_function_is_leaf)
return TRUE;
@@ -1864,7 +1952,7 @@ frv_frame_pointer_required (void)
if (!current_function_sp_is_unchanging)
return TRUE;
- if (flag_pic && cfun->uses_pic_offset_table)
+ if (!TARGET_FDPIC && flag_pic && cfun->uses_pic_offset_table)
return TRUE;
if (profile_flag)
@@ -2292,8 +2380,10 @@ frv_dynamic_chain_address (rtx frame)
address of other frames. */
rtx
-frv_return_addr_rtx (int count ATTRIBUTE_UNUSED, rtx frame)
+frv_return_addr_rtx (int count, rtx frame)
{
+ if (count != 0)
+ return const0_rtx;
cfun->machine->frame_needed = 1;
return gen_rtx_MEM (Pmode, plus_constant (frame, 8));
}
@@ -2366,6 +2456,7 @@ frv_print_operand_memory_reference_reg (FILE * stream, rtx x)
static void
frv_print_operand_memory_reference (FILE * stream, rtx x, int addr_offset)
{
+ struct frv_unspec unspec;
rtx x0 = NULL_RTX;
rtx x1 = NULL_RTX;
@@ -2434,29 +2525,10 @@ frv_print_operand_memory_reference (FILE * stream, rtx x, int addr_offset)
fprintf (stream, "%ld", (long) (INTVAL (x1) + addr_offset));
break;
- case SYMBOL_REF:
- if (x0 && GET_CODE (x0) == REG && REGNO (x0) == SDA_BASE_REG
- && SYMBOL_REF_SMALL_P (x1))
- {
- fputs ("#gprel12(", stream);
- assemble_name (stream, XSTR (x1, 0));
- fputs (")", stream);
- }
- else
- fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
- break;
-
case CONST:
- if (x0 && GET_CODE (x0) == REG && REGNO (x0) == SDA_BASE_REG
- && const_small_data_p (x1))
- {
- fputs ("#gprel12(", stream);
- assemble_name (stream, XSTR (XEXP (XEXP (x1, 0), 0), 0));
- fprintf (stream, "+"HOST_WIDE_INT_PRINT_DEC")",
- INTVAL (XEXP (XEXP (x1, 0), 1)));
- }
- else
- fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
+ if (!frv_const_unspec_p (x1, &unspec))
+ fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x1);
+ frv_output_const_unspec (stream, &unspec);
break;
default:
@@ -2573,6 +2645,7 @@ frv_print_operand_jump_hint (rtx insn)
void
frv_print_operand (FILE * file, rtx x, int code)
{
+ struct frv_unspec unspec;
HOST_WIDE_INT value;
int offset;
@@ -2726,6 +2799,13 @@ frv_print_operand (FILE * file, rtx x, int code)
}
break;
+ case 'g':
+ /* Print appropriate GOT function. */
+ if (GET_CODE (x) != CONST_INT)
+ fatal_insn ("Bad insn to frv_print_operand, 'g' modifier:", x);
+ fputs (unspec_got_name (INTVAL (x)), file);
+ break;
+
case 'I':
/* Print 'i' if the operand is a constant, or is a memory reference that
adds a constant. */
@@ -2733,6 +2813,8 @@ frv_print_operand (FILE * file, rtx x, int code)
x = ((GET_CODE (XEXP (x, 0)) == PLUS)
? XEXP (XEXP (x, 0), 1)
: XEXP (x, 0));
+ else if (GET_CODE (x) == PLUS)
+ x = XEXP (x, 1);
switch (GET_CODE (x))
{
@@ -2861,6 +2943,9 @@ frv_print_operand (FILE * file, rtx x, int code)
|| GET_CODE (x) == CONST_DOUBLE)
fprintf (file, "%s%ld", IMMEDIATE_PREFIX, (long) value);
+ else if (frv_const_unspec_p (x, &unspec))
+ frv_output_const_unspec (file, &unspec);
+
else if (GET_CODE (x) == MEM)
frv_print_operand_address (file, XEXP (x, 0));
@@ -3202,7 +3287,8 @@ int
frv_legitimate_address_p (enum machine_mode mode,
rtx x,
int strict_p,
- int condexec_p)
+ int condexec_p,
+ int allow_double_reg_p)
{
rtx x0, x1;
int ret = 0;
@@ -3284,7 +3370,7 @@ frv_legitimate_address_p (enum machine_mode mode,
case REG:
/* Do not allow reg+reg addressing for modes > 1 word if we
can't depend on having move double instructions. */
- if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+ if (!allow_double_reg_p && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
ret = FALSE;
else
ret = frv_regno_ok_for_base_p (REGNO (x1), strict_p);
@@ -3306,15 +3392,8 @@ frv_legitimate_address_p (enum machine_mode mode,
}
break;
- case SYMBOL_REF:
- if (!condexec_p
- && regno0 == SDA_BASE_REG
- && SYMBOL_REF_SMALL_P (x1))
- ret = TRUE;
- break;
-
case CONST:
- if (!condexec_p && regno0 == SDA_BASE_REG && const_small_data_p (x1))
+ if (!condexec_p && got12_operand (x1, VOIDmode))
ret = TRUE;
break;
@@ -3334,54 +3413,107 @@ frv_legitimate_address_p (enum machine_mode mode,
}
-/* A C compound statement that attempts to replace X with a valid memory
- address for an operand of mode MODE. WIN will be a C statement label
- elsewhere in the code; the macro definition may use
+/* Test whether a local function descriptor is canonical, i.e.,
+ whether we can use FUNCDESC_GOTOFF to compute the address of the
+ function. */
+
+static bool
+frv_local_funcdesc_p (rtx fnx)
+{
+ tree fn;
+ enum symbol_visibility vis;
+ bool ret;
- GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN);
+ if (! SYMBOL_REF_LOCAL_P (fnx))
+ return FALSE;
+
+ fn = SYMBOL_REF_DECL (fnx);
+
+ if (! fn)
+ return FALSE;
- to avoid further processing if the address has become legitimate.
+ vis = DECL_VISIBILITY (fn);
- X will always be the result of a call to `break_out_memory_refs', and OLDX
- will be the operand that was given to that function to produce X.
+ if (vis == VISIBILITY_PROTECTED)
+ /* Private function descriptors for protected functions are not
+ canonical. Temporarily change the visibility to global. */
+ vis = VISIBILITY_DEFAULT;
+ else if (flag_shlib)
+ /* If we're already compiling for a shared library (that, unlike
+ executables, can't assume that the existence of a definition
+ implies local binding), we can skip the re-testing. */
+ return TRUE;
- The code generated by this macro should not alter the substructure of X. If
- it transforms X into a more legitimate form, it should assign X (which will
- always be a C variable) a new value.
+ ret = default_binds_local_p_1 (fn, flag_pic);
- It is not necessary for this macro to come up with a legitimate address.
- The compiler has standard ways of doing so in all cases. In fact, it is
- safe for this macro to do nothing. But often a machine-dependent strategy
- can generate better code. */
+ DECL_VISIBILITY (fn) = vis;
+
+ return ret;
+}
+
+/* Load the _gp symbol into DEST. SRC is supposed to be the FDPIC
+ register. */
rtx
-frv_legitimize_address (rtx x,
- rtx oldx ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- rtx ret = NULL_RTX;
-
- /* Don't try to legitimize addresses if we are not optimizing, since the
- address we generate is not a general operand, and will horribly mess
- things up when force_reg is called to try and put it in a register because
- we aren't optimizing. */
- if (optimize
- && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_SMALL_P (x))
- || (GET_CODE (x) == CONST && const_small_data_p (x))))
- {
- ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, SDA_BASE_REG), x);
- if (flag_pic)
- cfun->uses_pic_offset_table = TRUE;
- }
+frv_gen_GPsym2reg (rtx dest, rtx src)
+{
+ tree gp = get_identifier ("_gp");
+ rtx gp_sym = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (gp));
- if (TARGET_DEBUG_ADDR && ret != NULL_RTX)
+ return gen_symGOT2reg (dest, gp_sym, src, GEN_INT (R_FRV_GOT12));
+}
+
+static const char *
+unspec_got_name (int i)
+{
+ switch (i)
{
- fprintf (stderr, "\n========== LEGITIMIZE_ADDRESS, mode = %s, modified address\n",
- GET_MODE_NAME (mode));
- debug_rtx (ret);
+ case R_FRV_GOT12: return "got12";
+ case R_FRV_GOTHI: return "gothi";
+ case R_FRV_GOTLO: return "gotlo";
+ case R_FRV_FUNCDESC: return "funcdesc";
+ case R_FRV_FUNCDESC_GOT12: return "gotfuncdesc12";
+ case R_FRV_FUNCDESC_GOTHI: return "gotfuncdeschi";
+ case R_FRV_FUNCDESC_GOTLO: return "gotfuncdesclo";
+ case R_FRV_FUNCDESC_VALUE: return "funcdescvalue";
+ case R_FRV_FUNCDESC_GOTOFF12: return "gotofffuncdesc12";
+ case R_FRV_FUNCDESC_GOTOFFHI: return "gotofffuncdeschi";
+ case R_FRV_FUNCDESC_GOTOFFLO: return "gotofffuncdesclo";
+ case R_FRV_GOTOFF12: return "gotoff12";
+ case R_FRV_GOTOFFHI: return "gotoffhi";
+ case R_FRV_GOTOFFLO: return "gotofflo";
+ case R_FRV_GPREL12: return "gprel12";
+ case R_FRV_GPRELHI: return "gprelhi";
+ case R_FRV_GPRELLO: return "gprello";
+ default: abort ();
}
+}
- return ret;
+/* Write the assembler syntax for UNSPEC to STREAM. Note that any offset
+ is added inside the relocation operator. */
+
+static void
+frv_output_const_unspec (FILE *stream, const struct frv_unspec *unspec)
+{
+ fprintf (stream, "#%s(", unspec_got_name (unspec->reloc));
+ output_addr_const (stream, plus_constant (unspec->symbol, unspec->offset));
+ fputs (")", stream);
+}
+
+/* Implement FIND_BASE_TERM. See whether ORIG_X represents #gprel12(foo)
+ or #gotoff12(foo) for some small data symbol foo. If so, return foo,
+ otherwise return ORIG_X. */
+
+rtx
+frv_find_base_term (rtx x)
+{
+ struct frv_unspec unspec;
+
+ if (frv_const_unspec_p (x, &unspec)
+ && frv_small_data_reloc_p (unspec.symbol, unspec.reloc))
+ return plus_constant (unspec.symbol, unspec.offset);
+
+ return x;
}
/* Return 1 if operand is a valid FRV address. CONDEXEC_P is true if
@@ -3393,9 +3525,109 @@ frv_legitimate_memory_operand (rtx op, enum machine_mode mode, int condexec_p)
return ((GET_MODE (op) == mode || mode == VOIDmode)
&& GET_CODE (op) == MEM
&& frv_legitimate_address_p (mode, XEXP (op, 0),
- reload_completed, condexec_p));
+ reload_completed, condexec_p, FALSE));
+}
+
+void
+frv_expand_fdpic_call (rtx *operands, int ret_value)
+{
+ rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
+ rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REG);
+ rtx c, rvrtx=0;
+ rtx addr;
+
+ if (ret_value)
+ {
+ rvrtx = operands[0];
+ operands ++;
+ }
+
+ addr = XEXP (operands[0], 0);
+
+ /* Inline PLTs if we're optimizing for speed. We'd like to inline
+ any calls that would involve a PLT, but can't tell, since we
+ don't know whether an extern function is going to be provided by
+ a separate translation unit or imported from a separate module.
+ When compiling for shared libraries, if the function has default
+ visibility, we assume it's overridable, so we inline the PLT, but
+ for executables, we don't really have a way to make a good
+ decision: a function is as likely to be imported from a shared
+ library as it is to be defined in the executable itself. We
+ assume executables will get global functions defined locally,
+ whereas shared libraries will have them potentially overridden,
+ so we only inline PLTs when compiling for shared libraries.
+
+ In order to mark a function as local to a shared library, any
+ non-default visibility attribute suffices. Unfortunately,
+ there's no simple way to tag a function declaration as ``in a
+ different module'', which we could then use to trigger PLT
+ inlining on executables. There's -minline-plt, but it affects
+ all external functions, so one would have to also mark function
+ declarations available in the same module with non-default
+ visibility, which is advantageous in itself. */
+ if (GET_CODE (addr) == SYMBOL_REF && !SYMBOL_REF_LOCAL_P (addr)
+ && TARGET_INLINE_PLT)
+ {
+ rtx x, dest;
+ dest = gen_reg_rtx (SImode);
+ if (flag_pic != 1)
+ x = gen_symGOTOFF2reg_hilo (dest, addr, OUR_FDPIC_REG,
+ GEN_INT (R_FRV_FUNCDESC_GOTOFF12));
+ else
+ x = gen_symGOTOFF2reg (dest, addr, OUR_FDPIC_REG,
+ GEN_INT (R_FRV_FUNCDESC_GOTOFF12));
+ emit_insn (x);
+ cfun->uses_pic_offset_table = TRUE;
+ addr = dest;
+ }
+ else if (GET_CODE (addr) == SYMBOL_REF)
+ {
+ /* These are always either local, or handled through a local
+ PLT. */
+ if (ret_value)
+ c = gen_call_value_fdpicsi (rvrtx, addr, operands[1],
+ operands[2], picreg, lr);
+ else
+ c = gen_call_fdpicsi (addr, operands[1], operands[2], picreg, lr);
+ emit_call_insn (c);
+ return;
+ }
+ else if (! ldd_address_operand (addr, Pmode))
+ addr = force_reg (Pmode, addr);
+
+ picreg = gen_reg_rtx (DImode);
+ emit_insn (gen_movdi_ldd (picreg, addr));
+
+ if (ret_value)
+ c = gen_call_value_fdpicdi (rvrtx, picreg, const0_rtx, lr);
+ else
+ c = gen_call_fdpicdi (picreg, const0_rtx, lr);
+ emit_call_insn (c);
}
+/* An address operand that may use a pair of registers, an addressing
+ mode that we reject in general. */
+
+int
+ldd_address_operand (rtx x, enum machine_mode mode)
+{
+ if (GET_MODE (x) != mode && GET_MODE (x) != VOIDmode)
+ return FALSE;
+
+ return frv_legitimate_address_p (DImode, x, reload_completed, FALSE, TRUE);
+}
+
+int
+fdpic_fptr_operand (rtx op, enum machine_mode mode)
+{
+ if (GET_MODE (op) != mode && mode != VOIDmode)
+ return FALSE;
+ if (GET_CODE (op) != REG)
+ return FALSE;
+ if (REGNO (op) != FDPIC_FPTR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
+ return FALSE;
+ return TRUE;
+}
/* Return 1 is OP is a memory operand, or will be turned into one by
reload. */
@@ -3456,6 +3688,9 @@ gpr_or_int12_operand (rtx op, enum machine_mode mode)
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -2048, 2047);
+ if (got12_operand (op, mode))
+ return true;
+
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
@@ -3638,7 +3873,7 @@ uint1_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
to load up and can be split into sethi/setlo instructions.. */
int
-int_2word_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+int_2word_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
HOST_WIDE_INT value;
REAL_VALUE_TYPE rv;
@@ -3650,13 +3885,24 @@ int_2word_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
break;
case LABEL_REF:
+ if (TARGET_FDPIC)
+ return FALSE;
+
return (flag_pic == 0);
case CONST:
- /* small data references are already 1 word */
- return (flag_pic == 0) && (! const_small_data_p (op));
+ if (flag_pic || TARGET_FDPIC)
+ return FALSE;
+
+ op = XEXP (op, 0);
+ if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
+ op = XEXP (op, 0);
+ return GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF;
case SYMBOL_REF:
+ if (TARGET_FDPIC)
+ return FALSE;
+
/* small data references are already 1 word */
return (flag_pic == 0) && (! SYMBOL_REF_SMALL_P (op));
@@ -3682,85 +3928,6 @@ int_2word_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
return FALSE;
}
-/* Return 1 if operand is the pic address register. */
-int
-pic_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (! flag_pic)
- return FALSE;
-
- if (GET_CODE (op) != REG)
- return FALSE;
-
- if (REGNO (op) != PIC_REGNO)
- return FALSE;
-
- return TRUE;
-}
-
-/* Return 1 if operand is a symbolic reference when a PIC option is specified
- that takes 3 separate instructions to form. */
-
-int
-pic_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (! flag_pic)
- return FALSE;
-
- switch (GET_CODE (op))
- {
- default:
- break;
-
- case LABEL_REF:
- return TRUE;
-
- case SYMBOL_REF:
- /* small data references are already 1 word */
- return ! SYMBOL_REF_SMALL_P (op);
-
- case CONST:
- /* small data references are already 1 word */
- return ! const_small_data_p (op);
- }
-
- return FALSE;
-}
-
-/* Return 1 if operand is the small data register. */
-int
-small_data_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) != REG)
- return FALSE;
-
- if (REGNO (op) != SDA_BASE_REG)
- return FALSE;
-
- return TRUE;
-}
-
-/* Return 1 if operand is a symbolic reference to a small data area static or
- global object. */
-
-int
-small_data_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- switch (GET_CODE (op))
- {
- default:
- break;
-
- case CONST:
- return const_small_data_p (op);
-
- case SYMBOL_REF:
- return SYMBOL_REF_SMALL_P (op);
- }
-
- return FALSE;
-}
-
/* Return 1 if operand is a 16 bit unsigned immediate. */
int
@@ -4103,7 +4270,7 @@ dbl_memory_one_insn_operand (rtx op, enum machine_mode mode)
if (GET_CODE (addr0) != REG)
return FALSE;
- if (plus_small_data_p (addr0, addr1))
+ if (got12_operand (addr1, VOIDmode))
return TRUE;
if (GET_CODE (addr1) != CONST_INT)
@@ -4164,7 +4331,7 @@ move_destination_operand (rtx op, enum machine_mode mode)
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
- reload_completed, FALSE);
+ reload_completed, FALSE, FALSE);
return (code == REG);
@@ -4184,6 +4351,53 @@ move_destination_operand (rtx op, enum machine_mode mode)
return FALSE;
}
+/* Look for a SYMBOL_REF of a function in an rtx. We always want to
+ process these separately from any offsets, such that we add any
+ offsets to the function descriptor (the actual pointer), not to the
+ function address. */
+
+static bool
+frv_function_symbol_referenced_p (rtx x)
+{
+ const char *format;
+ int length;
+ int j;
+
+ if (GET_CODE (x) == SYMBOL_REF)
+ return SYMBOL_REF_FUNCTION_P (x);
+
+ length = GET_RTX_LENGTH (GET_CODE (x));
+ format = GET_RTX_FORMAT (GET_CODE (x));
+
+ for (j = 0; j < length; ++j)
+ {
+ switch (format[j])
+ {
+ case 'e':
+ if (frv_function_symbol_referenced_p (XEXP (x, j)))
+ return TRUE;
+ break;
+
+ case 'V':
+ case 'E':
+ if (XVEC (x, j) != 0)
+ {
+ int k;
+ for (k = 0; k < XVECLEN (x, j); ++k)
+ if (frv_function_symbol_referenced_p (XVECEXP (x, j, k)))
+ return TRUE;
+ }
+ break;
+
+ default:
+ /* Nothing to do. */
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
/* Return true if operand is something that can be an input for a move
operation. */
@@ -4200,9 +4414,6 @@ move_source_operand (rtx op, enum machine_mode mode)
case CONST_INT:
case CONST_DOUBLE:
- case SYMBOL_REF:
- case LABEL_REF:
- case CONST:
return immediate_operand (op, mode);
case SUBREG:
@@ -4213,7 +4424,7 @@ move_source_operand (rtx op, enum machine_mode mode)
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
- reload_completed, FALSE);
+ reload_completed, FALSE, FALSE);
return (code == REG);
@@ -4255,7 +4466,7 @@ condexec_dest_operand (rtx op, enum machine_mode mode)
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
- reload_completed, TRUE);
+ reload_completed, TRUE, FALSE);
return (code == REG);
@@ -4301,7 +4512,7 @@ condexec_source_operand (rtx op, enum machine_mode mode)
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
- reload_completed, TRUE);
+ reload_completed, TRUE, FALSE);
return (code == REG);
@@ -4364,6 +4575,53 @@ lr_operand (rtx op, enum machine_mode mode)
return TRUE;
}
+/* Return true if operand is the uClinux PIC register. */
+
+int
+fdpic_operand (rtx op, enum machine_mode mode)
+{
+ if (!TARGET_FDPIC)
+ return FALSE;
+
+ if (GET_CODE (op) != REG)
+ return FALSE;
+
+ if (GET_MODE (op) != mode && mode != VOIDmode)
+ return FALSE;
+
+ if (REGNO (op) != FDPIC_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
+ return FALSE;
+
+ return TRUE;
+}
+
+int
+got12_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ struct frv_unspec unspec;
+
+ if (frv_const_unspec_p (op, &unspec))
+ switch (unspec.reloc)
+ {
+ case R_FRV_GOT12:
+ case R_FRV_GOTOFF12:
+ case R_FRV_FUNCDESC_GOT12:
+ case R_FRV_FUNCDESC_GOTOFF12:
+ case R_FRV_GPREL12:
+ return true;
+ }
+ return false;
+}
+
+/* Return true if OP is a valid const-unspec expression. */
+
+int
+const_unspec_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ struct frv_unspec unspec;
+
+ return frv_const_unspec_p (op, &unspec);
+}
/* Return true if operand is a gpr register or a valid memory operation. */
int
@@ -4939,7 +5197,7 @@ condexec_memory_operand (rtx op, enum machine_mode mode)
if (GET_CODE (addr) == ADDRESSOF)
return TRUE;
- return frv_legitimate_address_p (mode, addr, reload_completed, TRUE);
+ return frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE);
}
/* Return true if operator is an integer binary operator that can be combined
@@ -5133,6 +5391,9 @@ int
frv_emit_movsi (rtx dest, rtx src)
{
int base_regno = -1;
+ int unspec = 0;
+ rtx sym = src;
+ struct frv_unspec old_unspec;
if (!reload_in_progress
&& !reload_completed
@@ -5157,22 +5418,142 @@ frv_emit_movsi (rtx dest, rtx src)
break;
case LABEL_REF:
- if (flag_pic)
+ handle_label:
+ if (TARGET_FDPIC)
+ {
+ /* Using GPREL12, we use a single GOT entry for all symbols
+ in read-only sections, but trade sequences such as:
+
+ sethi #gothi(label), gr#
+ setlo #gotlo(label), gr#
+ ld @(gr15,gr#), gr#
+
+ for
+
+ ld @(gr15,#got12(_gp)), gr#
+ sethi #gprelhi(label), gr##
+ setlo #gprello(label), gr##
+ add gr#, gr##, gr##
+
+ We may often be able to share gr# for multiple
+ computations of GPREL addresses, and we may often fold
+ the final add into the pair of registers of a load or
+ store instruction, so it's often profitable. Even when
+ optimizing for size, we're trading a GOT entry for an
+ additional instruction, which trades GOT space
+ (read-write) for code size (read-only, shareable), as
+ long as the symbol is not used in more than two different
+ locations.
+
+ With -fpie/-fpic, we'd be trading a single load for a
+ sequence of 4 instructions, because the offset of the
+ label can't be assumed to be addressible with 12 bits, so
+ we don't do this. */
+ if (TARGET_GPREL_RO)
+ unspec = R_FRV_GPREL12;
+ else
+ unspec = R_FRV_GOT12;
+ }
+ else if (flag_pic)
base_regno = PIC_REGNO;
break;
case CONST:
- if (const_small_data_p (src))
- base_regno = SDA_BASE_REG;
-
- else if (flag_pic)
- base_regno = PIC_REGNO;
+ if (frv_const_unspec_p (src, &old_unspec))
+ break;
+ if (TARGET_FDPIC && frv_function_symbol_referenced_p (XEXP (src, 0)))
+ {
+ handle_whatever:
+ src = force_reg (GET_MODE (XEXP (src, 0)), XEXP (src, 0));
+ emit_move_insn (dest, src);
+ return TRUE;
+ }
+ else
+ {
+ sym = XEXP (sym, 0);
+ if (GET_CODE (sym) == PLUS
+ && GET_CODE (XEXP (sym, 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (sym, 1)) == CONST_INT)
+ sym = XEXP (sym, 0);
+ if (GET_CODE (sym) == SYMBOL_REF)
+ goto handle_sym;
+ else if (GET_CODE (sym) == LABEL_REF)
+ goto handle_label;
+ else
+ goto handle_whatever;
+ }
break;
case SYMBOL_REF:
- if (SYMBOL_REF_SMALL_P (src))
+ handle_sym:
+ if (TARGET_FDPIC)
+ {
+ if (SYMBOL_REF_FUNCTION_P (sym))
+ {
+ if (frv_local_funcdesc_p (sym))
+ unspec = R_FRV_FUNCDESC_GOTOFF12;
+ else
+ unspec = R_FRV_FUNCDESC_GOT12;
+ }
+ else
+ {
+ if (CONSTANT_POOL_ADDRESS_P (sym))
+ switch (GET_CODE (get_pool_constant (sym)))
+ {
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ if (flag_pic)
+ {
+ unspec = R_FRV_GOTOFF12;
+ break;
+ }
+ /* Fall through. */
+ default:
+ if (TARGET_GPREL_RO)
+ unspec = R_FRV_GPREL12;
+ else
+ unspec = R_FRV_GOT12;
+ break;
+ }
+ else if (SYMBOL_REF_LOCAL_P (sym)
+ && !SYMBOL_REF_EXTERNAL_P (sym)
+ && SYMBOL_REF_DECL (sym)
+ && (!DECL_P (SYMBOL_REF_DECL (sym))
+ || !DECL_COMMON (SYMBOL_REF_DECL (sym))))
+ {
+ tree decl = SYMBOL_REF_DECL (sym);
+ tree init = TREE_CODE (decl) == VAR_DECL
+ ? DECL_INITIAL (decl)
+ : TREE_CODE (decl) == CONSTRUCTOR
+ ? decl : 0;
+ int reloc = 0;
+ bool named_section, readonly;
+
+ if (init && init != error_mark_node)
+ reloc = compute_reloc_for_constant (init);
+
+ named_section = TREE_CODE (decl) == VAR_DECL
+ && lookup_attribute ("section", DECL_ATTRIBUTES (decl));
+ readonly = decl_readonly_section (decl, reloc);
+
+ if (named_section)
+ unspec = R_FRV_GOT12;
+ else if (!readonly)
+ unspec = R_FRV_GOTOFF12;
+ else if (readonly && TARGET_GPREL_RO)
+ unspec = R_FRV_GPREL12;
+ else
+ unspec = R_FRV_GOT12;
+ }
+ else
+ unspec = R_FRV_GOT12;
+ }
+ }
+
+ else if (SYMBOL_REF_SMALL_P (sym))
base_regno = SDA_BASE_REG;
else if (flag_pic)
@@ -5183,17 +5564,65 @@ frv_emit_movsi (rtx dest, rtx src)
if (base_regno >= 0)
{
- emit_insn (gen_rtx_SET (VOIDmode, dest,
- gen_rtx_PLUS (Pmode,
- gen_rtx_REG (Pmode, base_regno),
- src)));
-
+ if (GET_CODE (sym) == SYMBOL_REF && SYMBOL_REF_SMALL_P (sym))
+ emit_insn (gen_symGOTOFF2reg (dest, src,
+ gen_rtx_REG (Pmode, base_regno),
+ GEN_INT (R_FRV_GPREL12)));
+ else
+ emit_insn (gen_symGOTOFF2reg_hilo (dest, src,
+ gen_rtx_REG (Pmode, base_regno),
+ GEN_INT (R_FRV_GPREL12)));
if (base_regno == PIC_REGNO)
cfun->uses_pic_offset_table = TRUE;
+ return TRUE;
+ }
+ if (unspec)
+ {
+ rtx x;
+
+ /* Since OUR_FDPIC_REG is a pseudo register, we can't safely introduce
+ new uses of it once reload has begun. */
+ if (reload_in_progress || reload_completed)
+ abort ();
+
+ switch (unspec)
+ {
+ case R_FRV_GOTOFF12:
+ if (!frv_small_data_reloc_p (sym, unspec))
+ x = gen_symGOTOFF2reg_hilo (dest, src, OUR_FDPIC_REG,
+ GEN_INT (unspec));
+ else
+ x = gen_symGOTOFF2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
+ break;
+ case R_FRV_GPREL12:
+ if (!frv_small_data_reloc_p (sym, unspec))
+ x = gen_symGPREL2reg_hilo (dest, src, OUR_FDPIC_REG,
+ GEN_INT (unspec));
+ else
+ x = gen_symGPREL2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
+ break;
+ case R_FRV_FUNCDESC_GOTOFF12:
+ if (flag_pic != 1)
+ x = gen_symGOTOFF2reg_hilo (dest, src, OUR_FDPIC_REG,
+ GEN_INT (unspec));
+ else
+ x = gen_symGOTOFF2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
+ break;
+ default:
+ if (flag_pic != 1)
+ x = gen_symGOT2reg_hilo (dest, src, OUR_FDPIC_REG,
+ GEN_INT (unspec));
+ else
+ x = gen_symGOT2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
+ break;
+ }
+ emit_insn (x);
+ cfun->uses_pic_offset_table = TRUE;
return TRUE;
}
+
return FALSE;
}
@@ -5280,11 +5709,6 @@ output_move_single (rtx operands[], rtx insn)
|| GET_CODE (src) == LABEL_REF
|| GET_CODE (src) == CONST)
{
- /* Silently fix up instances where the small data pointer is not
- used in the address. */
- if (small_data_symbolic_operand (src, GET_MODE (src)))
- return "addi %@, #gprel12(%1), %0";
-
return "#";
}
}
@@ -6794,17 +7218,14 @@ frv_ifcvt_rewrite_mem (rtx mem, enum machine_mode mode, rtx insn)
{
rtx addr = XEXP (mem, 0);
- if (!frv_legitimate_address_p (mode, addr, reload_completed, TRUE))
+ if (!frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE))
{
if (GET_CODE (addr) == PLUS)
{
rtx addr_op0 = XEXP (addr, 0);
rtx addr_op1 = XEXP (addr, 1);
- if (plus_small_data_p (addr_op0, addr_op1))
- addr = frv_ifcvt_load_value (addr, insn);
-
- else if (GET_CODE (addr_op0) == REG && CONSTANT_P (addr_op1))
+ if (GET_CODE (addr_op0) == REG && CONSTANT_P (addr_op1))
{
rtx reg = frv_ifcvt_load_value (addr_op1, insn);
if (!reg)
@@ -6957,18 +7378,7 @@ frv_ifcvt_modify_insn (ce_if_block_t *ce_info,
op0 = XEXP (src, 0);
op1 = XEXP (src, 1);
- /* Special case load of small data address which looks like:
- r16+symbol_ref */
- if (GET_CODE (src) == PLUS && plus_small_data_p (op0, op1))
- {
- src = frv_ifcvt_load_value (src, insn);
- if (src)
- COND_EXEC_CODE (pattern) = gen_rtx_SET (VOIDmode, dest, src);
- else
- goto fail;
- }
-
- else if (integer_register_operand (op0, SImode) && CONSTANT_P (op1))
+ if (integer_register_operand (op0, SImode) && CONSTANT_P (op1))
{
op1 = frv_ifcvt_load_value (op1, insn);
if (op1)
@@ -7241,7 +7651,11 @@ frv_ifcvt_modify_cancel (ce_if_block_t *ce_info ATTRIBUTE_UNUSED)
int
frv_trampoline_size (void)
{
- return 5 /* instructions */ * 4 /* instruction size */;
+ if (TARGET_FDPIC)
+ /* Allocate room for the function descriptor and the lddi
+ instruction. */
+ return 8 + 6 * 4;
+ return 5 /* instructions */ * 4 /* instruction size. */;
}
@@ -7697,6 +8111,22 @@ frv_legitimate_constant_p (rtx x)
{
enum machine_mode mode = GET_MODE (x);
+ /* frv_cannot_force_const_mem always returns true for FDPIC. This
+ means that the move expanders will be expected to deal with most
+ kinds of constant, regardless of what we return here.
+
+ However, among its other duties, LEGITIMATE_CONSTANT_P decides whether
+ a constant can be entered into reg_equiv_constant[]. If we return true,
+ reload can create new instances of the constant whenever it likes.
+
+ The idea is therefore to accept as many constants as possible (to give
+ reload more freedom) while rejecting constants that can only be created
+ at certain times. In particular, anything with a symbolic component will
+ require use of the pseudo FDPIC register, which is only available before
+ reload. */
+ if (TARGET_FDPIC)
+ return LEGITIMATE_PIC_OPERAND_P (x);
+
/* All of the integer constants are ok. */
if (GET_CODE (x) != CONST_DOUBLE)
return TRUE;
@@ -7833,13 +8263,24 @@ frv_register_move_cost (enum reg_class from, enum reg_class to)
static bool
frv_assemble_integer (rtx value, unsigned int size, int aligned_p)
{
- if (flag_pic && size == UNITS_PER_WORD)
+ if ((flag_pic || TARGET_FDPIC) && size == UNITS_PER_WORD)
{
if (GET_CODE (value) == CONST
|| GET_CODE (value) == SYMBOL_REF
|| GET_CODE (value) == LABEL_REF)
{
- if (aligned_p)
+ if (TARGET_FDPIC && GET_CODE (value) == SYMBOL_REF
+ && SYMBOL_REF_FUNCTION_P (value))
+ {
+ fputs ("\t.picptr\tfuncdesc(", asm_out_file);
+ output_addr_const (asm_out_file, value);
+ fputs (")\n", asm_out_file);
+ return true;
+ }
+ else if (TARGET_FDPIC && GET_CODE (value) == CONST
+ && frv_function_symbol_referenced_p (value))
+ return false;
+ if (aligned_p && !TARGET_FDPIC)
{
static int label_num = 0;
char buf[256];
@@ -9433,6 +9874,14 @@ frv_rtx_costs (rtx x,
int outer_code ATTRIBUTE_UNUSED,
int *total)
{
+ if (outer_code == MEM)
+ {
+ /* Don't differentiate between memory addresses. All the ones
+ we accept have equal cost. */
+ *total = COSTS_N_INSNS (0);
+ return true;
+ }
+
switch (code)
{
case CONST_INT:
@@ -9484,6 +9933,10 @@ frv_rtx_costs (rtx x,
*total = COSTS_N_INSNS (18);
return true;
+ case MEM:
+ *total = COSTS_N_INSNS (3);
+ return true;
+
default:
return false;
}
@@ -9494,6 +9947,12 @@ frv_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
{
ctors_section ();
assemble_align (POINTER_SIZE);
+ if (TARGET_FDPIC)
+ {
+ if (!frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1))
+ abort ();
+ return;
+ }
assemble_integer_with_op ("\t.picptr\t", symbol);
}
@@ -9502,6 +9961,12 @@ frv_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
{
dtors_section ();
assemble_align (POINTER_SIZE);
+ if (TARGET_FDPIC)
+ {
+ if (!frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1))
+ abort ();
+ return;
+ }
assemble_integer_with_op ("\t.picptr\t", symbol);
}