diff options
Diffstat (limited to 'gcc/config/iq2000/iq2000.c')
-rw-r--r-- | gcc/config/iq2000/iq2000.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/gcc/config/iq2000/iq2000.c b/gcc/config/iq2000/iq2000.c index d853b1fbfc6..3b9e1166b27 100644 --- a/gcc/config/iq2000/iq2000.c +++ b/gcc/config/iq2000/iq2000.c @@ -165,6 +165,7 @@ static void iq2000_setup_incoming_varargs (CUMULATIVE_ARGS *, static bool iq2000_rtx_costs (rtx, int, int, int *, bool); static int iq2000_address_cost (rtx, bool); static section *iq2000_select_section (tree, int, unsigned HOST_WIDE_INT); +static rtx iq2000_legitimize_address (rtx, rtx, enum machine_mode); static bool iq2000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, const_tree, bool); static int iq2000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, @@ -186,6 +187,9 @@ static void iq2000_va_start (tree, rtx); #undef TARGET_ASM_SELECT_SECTION #define TARGET_ASM_SELECT_SECTION iq2000_select_section +#undef TARGET_LEGITIMIZE_ADDRESS +#define TARGET_LEGITIMIZE_ADDRESS iq2000_legitimize_address + /* The assembler supports switchable .bss sections, but iq2000_select_section doesn't yet make use of them. */ #undef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS @@ -3214,6 +3218,73 @@ print_operand (FILE *file, rtx op, int letter) output_addr_const (file, op); } + +/* For the IQ2000, transform: + + memory(X + <large int>) + into: + Y = <large int> & ~0x7fff; + Z = X + Y + memory (Z + (<large int> & 0x7fff)); +*/ + +rtx +iq2000_legitimize_address (rtx xinsn, rtx old_x ATTRIBUTE_UNUSED, + enum machine_mode mode) +{ + if (TARGET_DEBUG_B_MODE) + { + GO_PRINTF ("\n========== LEGITIMIZE_ADDRESS\n"); + GO_DEBUG_RTX (xinsn); + } + + if (iq2000_check_split (xinsn, mode)) + { + return gen_rtx_LO_SUM (Pmode, + copy_to_mode_reg (Pmode, + gen_rtx_HIGH (Pmode, xinsn)), + xinsn); + } + + if (GET_CODE (xinsn) == PLUS) + { + rtx xplus0 = XEXP (xinsn, 0); + rtx xplus1 = XEXP (xinsn, 1); + enum rtx_code code0 = GET_CODE (xplus0); + enum rtx_code code1 = GET_CODE (xplus1); + + if (code0 != REG && code1 == REG) + { + xplus0 = XEXP (xinsn, 1); + xplus1 = XEXP (xinsn, 0); + code0 = GET_CODE (xplus0); + code1 = GET_CODE (xplus1); + } + + if (code0 == REG && REG_MODE_OK_FOR_BASE_P (xplus0, mode) + && code1 == CONST_INT && !SMALL_INT (xplus1)) + { + rtx int_reg = gen_reg_rtx (Pmode); + rtx ptr_reg = gen_reg_rtx (Pmode); + + emit_move_insn (int_reg, + GEN_INT (INTVAL (xplus1) & ~ 0x7fff)); + + emit_insn (gen_rtx_SET (VOIDmode, + ptr_reg, + gen_rtx_PLUS (Pmode, xplus0, int_reg))); + + return plus_constant (ptr_reg, INTVAL (xplus1) & 0x7fff); + } + } + + if (TARGET_DEBUG_B_MODE) + GO_PRINTF ("LEGITIMIZE_ADDRESS could not fix.\n"); + + return xinsn; +} + + static bool iq2000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int * total, bool speed ATTRIBUTE_UNUSED) |