gcc/ChangeLog:
* config/rx/rx.cc (rx_is_local_readonly_data_p): New.
(legitimize_pic_address): New.
(rx_legitimize_address): Add PIC support.
(rx_is_relocatable_operand_p): New.
(rx_is_legitimate_address): Add PIC rules.
(rx_is_pic_unspec_p): New.
(nonpic_symbol_mentioned_p): New.
(rx_print_operand_with_attrib): New.
(rx_print_operand_address): Add PIC symbol support.
(rx_assemble_integer): Add funcdesc output.
(rx_print_operand): Add PC relative output.
(rx_maybe_legitimize_pi_operand): Rename from rx_maybe_pidify_operand.
Unified modification pic and pid mode.
(rx_conditional_register_usage): mark used for pic reg.
(rx_get_stack_layout): Add PIC support.
(rx_expand_prologue): Add PIC prologue.
(rx_expand_epilogue): PIC epilogue.
(rx_elf_asm_cdtor): Add FDPIC output.
(rx_assemble_integer): Add PIC case output.
(rx_option_override): fdpic support.
(rx_function_ok_for_sibcall): Use relative call in fdpic mode.
(rx_is_legitimate_constant): Add PIC support.
(rx_legitimate_pic_operand_p): New.
(rx_get_fdpic_reg_initial_val) New.
(rx_mov_pic_operands): New.
(rx_asm_output_addr_const_extra) New.
(rx_const_not_ok_for_debug_p): New.
(rx_cannot_force_const_mem_p): New.
(rx_is_unspec_offset): New.
(rx_delegitimize_address): New.
(+rx_expand_pcrel): New.
(TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA): New.
(TARGET_CONST_NOT_OK_FOR_DEBUG_P): New.
(TARGET_CANNOT_FORCE_CONST_MEM): New.
(TARGET_DELEGITIMIZE_ADDRESS): New.
Signed-off-by: Yoshinori Sato <[email protected]>
---
gcc/config/rx/rx.cc | 574 ++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 555 insertions(+), 19 deletions(-)
diff --git a/gcc/config/rx/rx.cc b/gcc/config/rx/rx.cc
index 038f93431f4..9160d9ea2ee 100644
--- a/gcc/config/rx/rx.cc
+++ b/gcc/config/rx/rx.cc
@@ -143,11 +143,100 @@ rx_pid_data_operand (rtx op)
return PID_NOT_PID;
}
+/* Determine whether x is a local, read-only variable. */
+static bool
+rx_is_local_readonly_data_p (rtx x)
+{
+ return (SYMBOL_REF_P (x)
+ && SYMBOL_REF_DECL (x)
+ && TREE_READONLY (SYMBOL_REF_DECL (x))
+ && !SYMBOL_REF_EXTERNAL_P (x)
+ && !SYMBOL_REF_FUNCTION_P (x));
+}
+
+/* Convert a non-PIC address in `orig' to a PIC address using @GOT or
+ @GOTOFF in `reg'. */
+static rtx
+legitimize_pic_address (rtx x, rtx orig)
+{
+ rtx reg;
+ rtx inner = x;
+
+ if (GET_CODE (x) == CONST)
+ inner = XEXP (x, 0);
+
+ if ((GET_CODE (inner) == UNSPEC && XINT (inner, 1) == UNSPEC_PCREL)
+ && (!SYMBOL_REF_P (x) && !LABEL_REF_P (x) && GET_CODE (x) != CONST))
+ return x;
+
+ reg = gen_reg_rtx (Pmode);
+
+ if (flag_plt && (GET_CODE (orig) == LABEL_REF
+ || (GET_CODE (orig) == SYMBOL_REF
+ && !SYMBOL_REF_LOCAL_P (orig))))
+ {
+ if (TARGET_FDPIC)
+ {
+ if (GET_CODE (orig) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (orig))
+ {
+ if (SYMBOL_REF_LOCAL_P (orig))
+ emit_insn (gen_symGOTOFFFUNCDESC2reg (reg, orig));
+ else
+ emit_insn (gen_symGOTFUNCDESC2reg (reg, orig));
+ }
+ else
+ emit_insn (gen_symGOT2reg (reg, orig));
+ }
+ crtl->uses_pic_offset_table = 1;
+ return reg;
+ }
+ else if (GET_CODE (orig) == SYMBOL_REF)
+ {
+ if (TARGET_FDPIC && SYMBOL_REF_FUNCTION_P (orig))
+ {
+ if (SYMBOL_REF_LOCAL_P (orig))
+ emit_insn (gen_symGOTOFFFUNCDESC2reg (reg, orig));
+ else
+ emit_insn (gen_symGOTFUNCDESC2reg (reg, orig));
+ }
+ else
+ {
+ if (SYMBOL_REF_LOCAL_P (orig))
+ {
+ if (!rx_is_local_readonly_data_p (orig))
+ emit_insn (gen_symGOTOFF2reg (reg, orig));
+ else
+ emit_insn (gen_movsi_pcrel (reg, orig));
+ }
+ else
+ emit_insn (gen_symGOT2reg (reg, orig));
+ }
+ crtl->uses_pic_offset_table = 1;
+ return reg;
+ }
+ else if (flag_pic && rx_pcrel_label_operand (x, Pmode))
+ {
+ emit_insn (gen_movsi_pcrel (reg, orig));
+ return reg;
+ }
+ return x;
+}
+
static rtx
rx_legitimize_address (rtx x,
rtx oldx ATTRIBUTE_UNUSED,
machine_mode mode ATTRIBUTE_UNUSED)
{
+ rtx op0 = XEXP (x, 0);
+ rtx op1 = XEXP (x, 1);
+
+ if (flag_pic)
+ {
+ rtx newx = legitimize_pic_address (x, oldx);
+ if (newx != oldx)
+ return newx;
+ }
+
if (rx_pid_data_operand (x) == PID_UNENCODED)
{
rtx rv = gen_pid_addr (gen_rtx_REG (SImode, rx_pid_base_regnum ()), x);
@@ -156,9 +245,6 @@ rx_legitimize_address (rtx x,
if (GET_CODE (x) == PLUS)
{
- rtx op0 = XEXP (x, 0);
- rtx op1 = XEXP (x, 1);
-
if (GET_CODE (op0) == PLUS
&& REG_P (XEXP (op0, 0))
&& CONST_INT_P (op1))
@@ -188,6 +274,15 @@ rx_small_data_operand (rtx op)
return false;
}
+/* Determine whether x is an operand that may involve relocation. */
+static bool
+rx_is_relocatable_operand_p (rtx x)
+{
+ return (GET_CODE (x) == UNSPEC
+ || SYMBOL_REF_P (x)
+ || LABEL_REF_P (x));
+}
+
static bool
rx_is_legitimate_address (machine_mode mode, rtx x,
bool strict ATTRIBUTE_UNUSED,
@@ -212,6 +307,10 @@ rx_is_legitimate_address (machine_mode mode, rtx x,
if (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
return false;
+ /* Cannot relocate the address of the high-order word. */
+ if (flag_pic)
+ return false;
+
if (GET_CODE (x) == PLUS)
{
rtx base = XEXP (x, 0);
@@ -249,6 +348,22 @@ rx_is_legitimate_address (machine_mode mode, rtx x,
else
return false;
+ if (flag_pic && GET_CODE (arg2) == CONST)
+ {
+ rtx inner = XEXP (arg2, 0);
+
+ /* Cannot relocate the address of the high-order word. */
+ if (GET_MODE_SIZE (mode) == UNITS_PER_WORD * 2)
+ return false;
+
+ /* TODO:
+ Reject "mov.L symbol@GOTFUNCDESC[reg],reg"
+ because ld cannot relocate it. */
+ if (GET_CODE (inner) == UNSPEC
+ && XINT (inner, 1) == UNSPEC_GOTFUNCDESC)
+ return false;
+ }
+
switch (GET_CODE (index))
{
case CONST_INT:
@@ -294,16 +409,88 @@ rx_is_legitimate_address (machine_mode mode, rtx x,
&& CONST_INT_P (factor)
&& GET_MODE_SIZE (mode) == INTVAL (factor);
}
-
+ case CONST:
+ if (!flag_pic)
+ return false;
+ else
+ {
+ rtx inner = XEXP (index, 0);
+ if (GET_CODE (inner) == PLUS)
+ {
+ rtx op0 = XEXP (inner, 0);
+ rtx op1 = XEXP (inner, 1);
+ if (rx_is_relocatable_operand_p (op0)
+ || rx_is_relocatable_operand_p (op1))
+ return false;
+ }
+ return !rx_is_unspec_offset (index);
+ }
default:
return false;
}
}
+ if (flag_pic && GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == UNSPEC
+ && XINT (XEXP (x, 0), 1) == UNSPEC_PCREL)
+ return true;
/* Small data area accesses turn into register relative offsets. */
return rx_small_data_operand (x);
}
+/* Check if the x is PIC. */
+static bool
+rx_is_pic_unspec_p (rtx x)
+{
+ if (GET_CODE (x) != UNSPEC)
+ return false;
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_PIC:
+ case UNSPEC_GOT:
+ case UNSPEC_GOTOFF:
+ case UNSPEC_PLT:
+ case UNSPEC_GOTFUNCDESC:
+ case UNSPEC_GOTOFFFUNCDESC:
+ case UNSPEC_PCREL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Return TRUE if X references a SYMBOL_REF or LABEL_REF whose symbol
+ isn't protected by a PIC unspec. */
+bool
+nonpic_symbol_mentioned_p (rtx x)
+{
+ if (GET_CODE (x) == PC)
+ return true;
+
+ /* We don't want to look into the possible MEM location of a
+ CONST_DOUBLE, since we're not going to use it, in general. */
+ if (GET_CODE (x) == CONST_DOUBLE)
+ return false;
+
+ if (rx_is_pic_unspec_p (x))
+ return false;
+
+ const char* fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (int i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ for (int j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (nonpic_symbol_mentioned_p (XVECEXP (x, i, j)))
+ return true;
+ }
+ else if (fmt[i] == 'e' && nonpic_symbol_mentioned_p (XEXP (x, i)))
+ return true;
+ }
+
+ return false;
+}
+
/* Returns TRUE for simple memory addresses, ie ones
that do not involve register indirect addressing
or pre/post increment/decrement. */
@@ -419,6 +606,21 @@ rx_mode_dependent_address_p (const_rtx addr, addr_space_t
as ATTRIBUTE_UNUSED)
assembler syntax for an instruction operand that is a memory
reference whose address is ADDR. */
+static void
+rx_print_operand_with_attrib (FILE * file, const char *attrib,
+ rtx addr, bool immediate)
+{
+ if (SYMBOL_REF_P (addr))
+ {
+ if (immediate)
+ fprintf (file, "#");
+ output_addr_const (file, addr);
+ fprintf (file, "@%s", attrib);
+ }
+ else
+ rx_print_operand (file, addr, 0);
+}
+
static void
rx_print_operand_address (FILE * file, machine_mode /*mode*/, rtx addr)
{
@@ -453,7 +655,7 @@ rx_print_operand_address (FILE * file, machine_mode
/*mode*/, rtx addr)
else if (REG_P (arg2) && RTX_OK_FOR_BASE (arg2, true))
base = arg2, index = arg1;
else
- {
+ { /* symbol + offset[Rn] */
rx_print_operand (file, arg1, 0);
fprintf (file, " + ");
rx_print_operand (file, arg2, 0);
@@ -461,13 +663,19 @@ rx_print_operand_address (FILE * file, machine_mode
/*mode*/, rtx addr)
}
if (REG_P (index) || GET_CODE (index) == MULT)
- {
+ { /* [Ri, Rb] */
fprintf (file, "[");
rx_print_operand (file, index, 'A');
fprintf (file, ",");
}
- else /* GET_CODE (index) == CONST_INT */
- {
+ else
+ { /* dsp[Rn] */
+ if (GET_CODE (index) == CONST
+ && GET_CODE (XEXP (index, 0)) == UNSPEC
+ && (XINT (XEXP (index, 0), 1) == UNSPEC_GOTOFF
+ || XINT (XEXP (index, 0), 1) == UNSPEC_GOTOFFFUNCDESC))
+ /* Only simple offsets are accepted here. */
+ gcc_unreachable ();
rx_print_operand (file, index, 'A');
fprintf (file, "[");
}
@@ -493,8 +701,33 @@ rx_print_operand_address (FILE * file, machine_mode
/*mode*/, rtx addr)
break;
case UNSPEC:
- addr = XVECEXP (addr, 0, 0);
- /* Fall through. */
+ {
+ int post = XINT (addr, 1);
+ addr = XVECEXP (addr, 0, 0);
+
+ switch (post)
+ {
+ case UNSPEC_GOT:
+ rx_print_operand_with_attrib (file, "GOT", addr, false);
+ break;
+ case UNSPEC_GOTOFF:
+ rx_print_operand_with_attrib (file, "GOTOFF", addr, true);
+ break;
+ case UNSPEC_GOTFUNCDESC:
+ rx_print_operand_with_attrib (file, "GOTFUNCDESC", addr, true);
+ break;
+ case UNSPEC_GOTOFFFUNCDESC:
+ rx_print_operand_with_attrib (file, "GOTOFFFUNCDESC", addr, true);
+ break;
+ case UNSPEC_PLT:
+ rx_print_operand_with_attrib (file, "PLT", addr, false);
+ break;
+ case UNSPEC_PCREL:
+ output_addr_const (file, addr);
+ break;
+ }
+ break;
+ }
case LABEL_REF:
case SYMBOL_REF:
fprintf (file, "#");
@@ -522,6 +755,15 @@ rx_assemble_integer (rtx x, unsigned int size, int
is_aligned)
{
const char * op = integer_asm_op (size, is_aligned);
+ if (TARGET_FDPIC && size == UNITS_PER_WORD
+ && GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
+ {
+ fputs (op, asm_out_file);
+ output_addr_const (asm_out_file, x);
+ fputs ("@FUNCDESC\n", asm_out_file);
+ return true;
+ }
+
if (! CONST_INT_P (x))
return default_assemble_integer (x, size, is_aligned);
@@ -949,6 +1191,11 @@ rx_print_operand (FILE * file, rtx op, int letter)
fprintf (file, ")");
return;
}
+ case UNSPEC_PCREL:
+ if (print_hash)
+ fprintf (file, "#");
+ output_addr_const (file, XVECEXP (op, 0, 0));
+ return;
}
/* Fall through */
@@ -966,10 +1213,10 @@ rx_print_operand (FILE * file, rtx op, int letter)
}
}
-/* Maybe convert an operand into its PID format. */
+/* Maybe convert an operand into its PI (PIC/PID) format. */
rtx
-rx_maybe_pidify_operand (rtx op, int copy_to_reg)
+rx_maybe_legitimize_pi_operand (rtx op, int copy_to_reg)
{
if (rx_pid_data_operand (op) == PID_UNENCODED)
{
@@ -986,6 +1233,105 @@ rx_maybe_pidify_operand (rtx op, int copy_to_reg)
if (copy_to_reg)
op = copy_to_mode_reg (GET_MODE (op), op);
}
+ else if (flag_pic)
+ {
+ rtx picreg = gen_rtx_REG (Pmode, PIC_REG);
+ rtx t;
+
+ switch (GET_CODE (op))
+ {
+ case CONST:
+ {
+ rtx base, offset;
+ split_const (op, &base, &offset);
+
+ if (SYMBOL_REF_P (base) || LABEL_REF_P (base))
+ {
+ tree decl = SYMBOL_REF_P (base)
+ ? SYMBOL_REF_DECL (base) : NULL_TREE;
+ bool is_local_var = (decl
+ && TREE_CODE (decl) == VAR_DECL
+ && !TREE_PUBLIC (decl));
+
+ t = gen_reg_rtx (GET_MODE (op));
+
+ if (is_local_var || LABEL_REF_P (base))
+ {
+ /* PC relative with offset. */
+ rtx label = gen_sym2pcrel (base);
+ emit_insn (gen_movsi_pcrel (t, label));
+ }
+ else
+ {
+ crtl->uses_pic_offset_table = true;
+ if (SYMBOL_REF_LOCAL_P (base)
+ && !rx_is_local_readonly_data_p (base))
+ {
+ rtx gotoffsym = gen_sym2GOTOFF (base);
+ rtx src = gen_rtx_PLUS (Pmode, picreg, gotoffsym);
+ emit_move_insn (t, src);
+ }
+ else
+ {
+ rtx gotsym = gen_sym2GOT (base);
+ rtx got_addr = gen_rtx_PLUS (Pmode, picreg, gotsym);
+ rtx src = gen_rtx_MEM (GET_MODE (op), got_addr);
+ emit_move_insn (t, src);
+ }
+ }
+
+ if (offset != const0_rtx)
+ emit_insn (gen_addsi3 (t, t, offset));
+
+ return t;
+ }
+ break;
+ }
+ case SYMBOL_REF:
+ case LABEL_REF:
+ {
+ /* Local read-only symbols are accessed
+ using PC-relative addresses. */
+ if (GET_CODE (op) == LABEL_REF || rx_is_local_readonly_data_p (op))
+ return gen_sym2pcrel (op);
+
+ /* funcdesc case. */
+ if (TARGET_FDPIC
+ && SYMBOL_REF_FUNCTION_P (op)
+ && !RTX_FLAG (op, frame_related))
+ {
+ rtx t = gen_reg_rtx (Pmode);
+ rtx funcsym;
+ funcsym = SYMBOL_REF_LOCAL_P (op)
+ ? gen_sym2GOTOFFFUNCDESC (op) : gen_sym2GOTFUNCDESC (op);
+ emit_insn (gen_addsi3 (t, picreg, funcsym));
+ return t;
+ }
+ /* variable case. */
+ if (SYMBOL_REF_LOCAL_P (op))
+ {
+ if (rx_is_local_readonly_data_p (op))
+ return op;
+
+ rtx gotoffsym = gen_sym2GOTOFF (op);
+ return gen_rtx_PLUS (Pmode, picreg, gotoffsym);
+ }
+ else
+ {
+ crtl->uses_pic_offset_table = true;
+ rtx gotsym = gen_sym2GOT (op);
+ machine_mode mode = GET_MODE (op) != VOIDmode
+ ? GET_MODE (op) : Pmode;
+ return gen_rtx_MEM (mode,
+ gen_rtx_PLUS (Pmode, picreg, gotsym));
+ }
+ }
+ break;
+ default:
+ /* Nothing do. */
+ break;
+ }
+ }
return op;
}
@@ -1010,7 +1356,7 @@ rx_gen_move_template (rtx * operands, bool is_movu)
else
{
/* Otherwise, use the smaller size. */
- if (GET_MODE (src) == SIGN_EXTEND || GET_MODE (src) == ZERO_EXTEND)
+ if (GET_CODE (src) == SIGN_EXTEND || GET_CODE (src) == ZERO_EXTEND)
/* When expanding, the original size will be used. */
src_mode = GET_MODE (XEXP (src, 0));
else
@@ -1336,6 +1682,9 @@ rx_conditional_register_usage (void)
using_fixed_regs = use_fixed_regs;
}
+
+ if (flag_pic)
+ call_used_regs[PIC_REG] = 1;
}
struct decl_chain
@@ -1531,7 +1880,8 @@ rx_get_stack_layout (unsigned int * lowest,
to call-used by rx_conditional_register_usage. If so then
they can be used in the fast interrupt handler without
saving them on the stack. */
- || (is_fast_interrupt_func (NULL_TREE)
+ || is_fast_interrupt_func (NULL_TREE)
+ || ((flag_pic && reg == PIC_REG)
&& ! IN_RANGE (reg, 10, 13))))
{
if (low == 0)
@@ -1864,6 +2214,14 @@ rx_expand_prologue (void)
GEN_INT ((HOST_WIDE_INT) stack_size),
true);
}
+ if (crtl->uses_pic_offset_table && !TARGET_FDPIC)
+ {
+ rtx got_base = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+ rtx picreg = gen_rtx_REG (Pmode, PIC_REG);
+
+ got_base = gen_sym2pcrel (got_base);
+ emit_insn (gen_movsi_pcrel (picreg, got_base));
+ }
}
static void
@@ -2231,6 +2589,12 @@ rx_expand_epilogue (bool is_sibcall)
GEN_INT (total_size), false);
}
+ if (flag_pic)
+ {
+ rtx picreg = gen_rtx_REG (Pmode, PIC_REG);
+ emit_use (picreg);
+ }
+
if (low)
emit_jump_insn (gen_pop_and_return (GEN_INT (regs_size),
gen_rx_rtsd_vector (regs_size,
@@ -2714,7 +3078,14 @@ rx_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
switch_to_section (s);
assemble_align (POINTER_SIZE);
- assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+ if (!TARGET_FDPIC)
+ assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+ else
+ {
+ fputs ("\t.long\t", asm_out_file);
+ output_addr_const (asm_out_file, symbol);
+ fputs ("\n", asm_out_file);
+ }
}
static void
@@ -2865,6 +3236,13 @@ rx_option_override (void)
if (flag_strict_volatile_bitfields < 0 && abi_version_at_least(2))
flag_strict_volatile_bitfields = 1;
+ /* FDPIC code is a special form of PIC, and the vast majority of code
+ generation constraints that apply to PIC also apply to FDPIC, so we
+ set flag_pic to avoid the need to check TARGET_FDPIC everywhere
+ flag_pic is checked. */
+ if (TARGET_FDPIC && !flag_pic)
+ flag_pic = 2;
+
rx_override_options_after_change ();
/* These values are bytes, not log. */
@@ -2912,7 +3290,7 @@ rx_warn_func_return (tree decl)
static bool
rx_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
{
- if (TARGET_JSR)
+ if (TARGET_JSR || TARGET_FDPIC)
return false;
/* Do not allow indirect tailcalls. The
@@ -2949,6 +3327,25 @@ rx_is_ms_bitfield_layout (const_tree record_type
ATTRIBUTE_UNUSED)
bool
rx_is_legitimate_constant (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
{
+ if (flag_pic)
+ {
+ if (SYMBOL_REF_P (x) || LABEL_REF_P (x))
+ return false;
+ if (GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == UNSPEC)
+ {
+ rtx x0 = XVECEXP (XEXP (XEXP (x, 0), 0), 0, 0);
+ if (SYMBOL_REF_P (x0) || LABEL_REF_P (x0))
+ return false;
+ }
+
+ if (GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == UNSPEC
+ && XINT (XEXP (x, 0), 1) == UNSPEC_PCREL)
+ return false;
+ }
+
switch (GET_CODE (x))
{
case CONST:
@@ -2969,10 +3366,28 @@ rx_is_legitimate_constant (machine_mode mode
ATTRIBUTE_UNUSED, rtx x)
{
case LABEL_REF:
case SYMBOL_REF:
- return true;
+ return !flag_pic;
case UNSPEC:
- return XINT (x, 1) == UNSPEC_CONST || XINT (x, 1) == UNSPEC_PID_ADDR;
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_PCREL:
+ {
+ rtx xx = XVECEXP (x, 0, 0);
+ return !(GET_CODE (xx) == CONST || GET_CODE (xx) == UNSPEC);
+ }
+ case UNSPEC_CONST:
+ case UNSPEC_PID_ADDR:
+ case UNSPEC_GOT:
+ case UNSPEC_GOTOFF:
+ case UNSPEC_GOTFUNCDESC:
+ case UNSPEC_GOTOFFFUNCDESC:
+ case UNSPEC_PLT:
+ return true;
+ default:
+ return false;
+ }
+ break;
default:
/* FIXME: Can this ever happen ? */
@@ -3663,7 +4078,9 @@ rx_modes_tieable_p (machine_mode mode1, machine_mode
mode2)
return ((GET_MODE_CLASS (mode1) == MODE_FLOAT
|| GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)
== (GET_MODE_CLASS (mode2) == MODE_FLOAT
- || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
+ || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT))
+ || (GET_MODE_CLASS (mode1) == MODE_INT
+ && GET_MODE_CLASS (mode2) == MODE_INT);
}
/* Implement TARGET_C_MODE_FOR_FLOATING_TYPE. Return SFmode or DFmode
@@ -3730,6 +4147,113 @@ rx_relax_double_operands(rtx * operands, machine_mode
mode)
if (MEM_P (operands[0]) && !REG_P (operands[1]))
operands[1] = force_reg (mode, operands[1]);
}
+
+/* Implement LEGITIMATE_PIC_OPERAND_P. */
+bool
+rx_legitimate_pic_operand_p (rtx x)
+{
+ return (! nonpic_symbol_mentioned_p (x)
+ && GET_CODE (x) != SYMBOL_REF);
+}
+
+/* Return an rtx holding the initial value of the FDPIC register (the
+ FDPIC pointer passed in from the caller). */
+rtx
+rx_get_fdpic_reg_initial_val (void)
+{
+ return get_hard_reg_initial_val (Pmode, PIC_REG);
+}
+
+/* Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA. */
+static bool
+rx_asm_output_addr_const_extra (FILE *file ATTRIBUTE_UNUSED,
+ rtx x ATTRIBUTE_UNUSED)
+{
+ return false;
+}
+
+/* Implement TARGET_CONST_NOT_OK_FOR_DEBUG_P. */
+static bool
+rx_const_not_ok_for_debug_p (rtx p)
+{
+ return (GET_CODE (p) == SYMBOL_REF);
+}
+
+/* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
+bool
+rx_cannot_force_const_mem_p (machine_mode mode ATTRIBUTE_UNUSED,
+ rtx x ATTRIBUTE_UNUSED)
+{
+ return flag_pic;
+}
+
+/* Determine whether x is a valid UNSPEC as an offset. */
+bool
+rx_is_unspec_offset (rtx x)
+{
+ if (!flag_pic
+ || GET_CODE (x) != CONST
+ || GET_CODE (XEXP (x, 0)) != UNSPEC)
+ return false;
+
+ switch (XINT (XEXP (x, 0), 1))
+ {
+ case UNSPEC_PID_ADDR:
+ case UNSPEC_GOTOFF:
+ case UNSPEC_GOTOFFFUNCDESC:
+ case UNSPEC_PCREL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Implement TARGET_DELEGITIMIZE_ADDRESS. */
+static rtx
+rx_delegitimize_address (rtx x)
+{
+ x = delegitimize_mem_from_attrs (x);
+ if (rx_pcrel_label_operand (x, Pmode))
+ return XVECEXP (XEXP (x, 0), 0, 0);
+
+ return x;
+}
+
+/* expand for pc relative address load. */
+bool
+rx_expand_pcrel (rtx operands[], int sidx)
+{
+ rtx src = operands[sidx];
+ rtx dest = operands[0];
+ rtx pcrel_src = NULL_RTX;
+
+ if (!flag_pic)
+ return false;
+
+ if (rx_pcrel_label_operand (src, Pmode))
+ src = gen_rtx_CONST (Pmode,
+ gen_rtx_UNSPEC (Pmode, gen_rtvec (1, src),
+ UNSPEC_PCREL));
+ if (CONSTANT_P (src))
+ {
+ rtx inner = (GET_CODE (src) == CONST)
+ ? XEXP (src, 0) : src;
+ if (GET_CODE (inner) == UNSPEC && XINT (inner, 1) == UNSPEC_PCREL)
+ pcrel_src = XVECEXP (inner, 0, 0);
+ }
+
+ if (pcrel_src != NULL_RTX)
+ {
+ if (!REG_P (dest))
+ dest = gen_reg_rtx (Pmode);
+ emit_insn (gen_movsi_pcrel (dest, pcrel_src));
+ if (dest != operands[0])
+ emit_move_insn (operands[0], dest);
+ return true;
+ }
+ return false;
+}
+
#undef TARGET_NARROW_VOLATILE_BITFIELD
@@ -3896,6 +4420,18 @@ rx_relax_double_operands(rtx * operands, machine_mode
mode)
#undef TARGET_DOCUMENTATION_NAME
#define TARGET_DOCUMENTATION_NAME "RX"
+#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
+#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA rx_asm_output_addr_const_extra
+
+#undef TARGET_CONST_NOT_OK_FOR_DEBUG_P
+#define TARGET_CONST_NOT_OK_FOR_DEBUG_P rx_const_not_ok_for_debug_p
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM rx_cannot_force_const_mem_p
+
+#undef TARGET_DELEGITIMIZE_ADDRESS
+#define TARGET_DELEGITIMIZE_ADDRESS rx_delegitimize_address
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-rx.h"
--
2.47.3