diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/config/m68k/m68k.c | 128 | ||||
-rw-r--r-- | gcc/config/m68k/m68k.h | 10 |
3 files changed, 98 insertions, 51 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e974798..7cac0a2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,16 @@ 2007-03-06 Richard Sandiford <richard@codesourcery.com> + * config/m68k/m68k.h (PIC_OFFSET_TABLE_REGNUM): Use the REGNO + of pic_offset_table_rtx if reload_completed. + (CONDITIONAL_REGISTER_USAGE): Use PIC_REG instead of + PIC_OFFSET_TABLE_REGNUM. + * config/m68k/m68k.c (TARGET_ASM_CAN_OUTPUT_MI_THUNK): Always + return true. + (m68k_save_reg): Use PIC_REG instead of PIC_OFFSET_TABLE_REGNO. + (m68k_output_mi_thunk): Rewrite to use RTL. Honor vcall_offset. + +2007-03-06 Richard Sandiford <richard@codesourcery.com> + * config/m68k/m68k.c (m68k_save_reg): Save the PIC register in functions that call eh_return. diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c index 642927e..99dedb8 100644 --- a/gcc/config/m68k/m68k.c +++ b/gcc/config/m68k/m68k.c @@ -191,7 +191,7 @@ int m68k_last_compare_had_fp_operands; #undef TARGET_ASM_OUTPUT_MI_THUNK #define TARGET_ASM_OUTPUT_MI_THUNK m68k_output_mi_thunk #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK -#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall +#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true #undef TARGET_ASM_FILE_START_APP_OFF #define TARGET_ASM_FILE_START_APP_OFF true @@ -745,7 +745,7 @@ m68k_initial_elimination_offset (int from, int to) static bool m68k_save_reg (unsigned int regno, bool interrupt_handler) { - if (flag_pic && regno == PIC_OFFSET_TABLE_REGNUM) + if (flag_pic && regno == PIC_REG) { /* A function that receives a nonlocal goto must save all call-saved registers. */ @@ -4083,59 +4083,93 @@ m68k_coff_asm_named_section (const char *name, unsigned int flags, static void m68k_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, - HOST_WIDE_INT delta, - HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, tree function) { - rtx xops[1]; - const char *fmt; - - if (delta > 0 && delta <= 8) - asm_fprintf (file, (MOTOROLA - ? "\taddq.l %I%d,4(%Rsp)\n" - : "\taddql %I%d,%Rsp@(4)\n"), - (int) delta); - else if (delta < 0 && delta >= -8) - asm_fprintf (file, (MOTOROLA - ? "\tsubq.l %I%d,4(%Rsp)\n" - : "\tsubql %I%d,%Rsp@(4)\n"), - (int) -delta); - else if (TARGET_COLDFIRE) + rtx this_slot, offset, addr, mem, insn; + + /* Pretend to be a post-reload pass while generating rtl. */ + no_new_pseudos = 1; + reload_completed = 1; + reset_block_changes (); + allocate_reg_info (FIRST_PSEUDO_REGISTER, true, true); + + /* The "this" pointer is stored at 4(%sp). */ + this_slot = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx, 4)); + + /* Add DELTA to THIS. */ + if (delta != 0) { - /* ColdFire can't add/sub a constant to memory unless it is in - the range of addq/subq. So load the value into %d0 and - then add it to 4(%sp). */ - if (delta >= -128 && delta <= 127) - asm_fprintf (file, (MOTOROLA - ? "\tmoveq.l %I%wd,%Rd0\n" - : "\tmoveql %I%wd,%Rd0\n"), - delta); - else - asm_fprintf (file, (MOTOROLA - ? "\tmove.l %I%wd,%Rd0\n" - : "\tmovel %I%wd,%Rd0\n"), - delta); - asm_fprintf (file, (MOTOROLA - ? "\tadd.l %Rd0,4(%Rsp)\n" - : "\taddl %Rd0,%Rsp@(4)\n")); + /* Make the offset a legitimate operand for memory addition. */ + offset = GEN_INT (delta); + if ((delta < -8 || delta > 8) + && (TARGET_COLDFIRE || USE_MOVQ (delta))) + { + emit_move_insn (gen_rtx_REG (Pmode, D0_REG), offset); + offset = gen_rtx_REG (Pmode, D0_REG); + } + emit_insn (gen_add3_insn (copy_rtx (this_slot), + copy_rtx (this_slot), offset)); } - else - asm_fprintf (file, (MOTOROLA - ? "\tadd.l %I%wd,4(%Rsp)\n" - : "\taddl %I%wd,%Rsp@(4)\n"), - delta); - xops[0] = DECL_RTL (function); + /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */ + if (vcall_offset != 0) + { + /* Set the static chain register to *THIS. */ + emit_move_insn (static_chain_rtx, this_slot); + emit_move_insn (static_chain_rtx, gen_rtx_MEM (Pmode, static_chain_rtx)); + + /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */ + addr = plus_constant (static_chain_rtx, vcall_offset); + if (!m68k_legitimate_address_p (Pmode, addr, true)) + { + emit_insn (gen_rtx_SET (VOIDmode, static_chain_rtx, addr)); + addr = static_chain_rtx; + } - gcc_assert (MEM_P (xops[0]) - && symbolic_operand (XEXP (xops[0], 0), VOIDmode)); - xops[0] = XEXP (xops[0], 0); + /* Load the offset into %d0 and add it to THIS. */ + emit_move_insn (gen_rtx_REG (Pmode, D0_REG), + gen_rtx_MEM (Pmode, addr)); + emit_insn (gen_add3_insn (copy_rtx (this_slot), + copy_rtx (this_slot), + gen_rtx_REG (Pmode, D0_REG))); + } - fmt = m68k_symbolic_jump; - if (m68k_symbolic_jump == NULL) - fmt = "move.l %%a1@GOT(%%a5), %%a1\n\tjmp (%%a1)"; + /* Jump to the target function. Use a sibcall if direct jumps are + allowed, otherwise load the address into a register first. */ + mem = DECL_RTL (function); + if (!sibcall_operand (XEXP (mem, 0), VOIDmode)) + { + gcc_assert (flag_pic); - output_asm_insn (fmt, xops); + if (!TARGET_SEP_DATA) + { + /* Use the static chain register as a temporary (call-clobbered) + GOT pointer for this function. We can use the static chain + register because it isn't live on entry to the thunk. */ + REGNO (pic_offset_table_rtx) = STATIC_CHAIN_REGNUM; + emit_insn (gen_load_got (pic_offset_table_rtx)); + } + legitimize_pic_address (XEXP (mem, 0), Pmode, static_chain_rtx); + mem = replace_equiv_address (mem, static_chain_rtx); + } + insn = emit_call_insn (gen_sibcall (mem, const0_rtx)); + SIBLING_CALL_P (insn) = 1; + + /* Run just enough of rest_of_compilation. */ + insn = get_insns (); + split_all_insns_noflow (); + final_start_function (insn, file, 1); + final (insn, file, 1); + final_end_function (); + + /* Clean up the vars set above. */ + reload_completed = 0; + no_new_pseudos = 0; + + /* Restore the original PIC register. */ + if (flag_pic) + REGNO (pic_offset_table_rtx) = PIC_REG; } /* Worker function for TARGET_STRUCT_VALUE_RTX. */ diff --git a/gcc/config/m68k/m68k.h b/gcc/config/m68k/m68k.h index 9d7843d..5c5d59e 100644 --- a/gcc/config/m68k/m68k.h +++ b/gcc/config/m68k/m68k.h @@ -316,7 +316,10 @@ Boston, MA 02110-1301, USA. */ #define FIRST_PSEUDO_REGISTER 25 /* All m68k targets (except AmigaOS) use %a5 as the PIC register */ -#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 13 : INVALID_REGNUM) +#define PIC_OFFSET_TABLE_REGNUM \ + (!flag_pic ? INVALID_REGNUM \ + : reload_completed ? REGNO (pic_offset_table_rtx) \ + : PIC_REG) /* 1 for registers that have pervasive standard uses and are not available for the register allocator. @@ -383,9 +386,8 @@ Boston, MA 02110-1301, USA. */ if (TEST_HARD_REG_BIT (x, i)) \ fixed_regs[i] = call_used_regs[i] = 1; \ } \ - if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) \ - fixed_regs[PIC_OFFSET_TABLE_REGNUM] \ - = call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + if (flag_pic) \ + fixed_regs[PIC_REG] = call_used_regs[PIC_REG] = 1; \ } /* On the m68k, ordinary registers hold 32 bits worth; |