📄 m68k.c
字号:
/* Subroutines for insn-output.c for Motorola 68000 family. Copyright (C) 1987, 1993, 1994, 1995 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. *//* Some output-actions in m68k.md need these. */#include <stdio.h>#include "config.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "insn-flags.h"#include "output.h"#include "insn-attr.h"/* Needed for use_return_insn. */#include "flags.h"#ifdef SUPPORT_SUN_FPA/* Index into this array by (register number >> 3) to find the smallest class which contains that register. */enum reg_class regno_reg_class[] = { DATA_REGS, ADDR_REGS, FP_REGS, LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS };#endif /* defined SUPPORT_SUN_FPA *//* This flag is used to communicate between movhi and ASM_OUTPUT_CASE_END, if SGS_SWITCH_TABLE. */int switch_table_difference_label_flag;static rtx find_addr_reg ();rtx legitimize_pic_address ();/* Emit a (use pic_offset_table_rtx) if we used PIC relocation in the function at any time during the compilation process. In the future we should try and eliminate the USE if we can easily determine that all PIC references were deleted from the current function. That would save an address register */ voidfinalize_pic (){ if (flag_pic && current_function_uses_pic_offset_table) { rtx insn = gen_rtx (USE, VOIDmode, pic_offset_table_rtx); emit_insn_after (insn, get_insns ()); emit_insn (insn); }}/* This function generates the assembly code for function entry. STREAM is a stdio stream to output the code to. SIZE is an int: how many units of temporary storage to allocate. Refer to the array `regs_ever_live' to determine which registers to save; `regs_ever_live[I]' is nonzero if register number I is ever used in the function. This function is responsible for knowing which registers should not be saved even if used. *//* Note that the order of the bit mask for fmovem is the opposite of the order for movem! */voidoutput_function_prologue (stream, size) FILE *stream; int size;{ register int regno; register int mask = 0; int num_saved_regs = 0; extern char call_used_regs[]; int fsize = (size + 3) & -4; if (frame_pointer_needed) { if (fsize == 0 && TARGET_68040) { /* on the 68040, pea + move is faster than link.w 0 */#ifdef MOTOROLA asm_fprintf (stream, "\tpea (%s)\n\tmove.l %s,%s\n", reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM], reg_names[FRAME_POINTER_REGNUM]);#else asm_fprintf (stream, "\tpea %s@\n\tmovel %s,%s\n", reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM], reg_names[FRAME_POINTER_REGNUM]);#endif } else if (fsize < 0x8000) {#ifdef MOTOROLA asm_fprintf (stream, "\tlink.w %s,%0I%d\n", reg_names[FRAME_POINTER_REGNUM], -fsize);#else asm_fprintf (stream, "\tlink %s,%0I%d\n", reg_names[FRAME_POINTER_REGNUM], -fsize);#endif } else if (TARGET_68020) {#ifdef MOTOROLA asm_fprintf (stream, "\tlink.l %s,%0I%d\n", reg_names[FRAME_POINTER_REGNUM], -fsize);#else asm_fprintf (stream, "\tlink %s,%0I%d\n", reg_names[FRAME_POINTER_REGNUM], -fsize);#endif } else { /* Adding negative number is faster on the 68040. */#ifdef MOTOROLA asm_fprintf (stream, "\tlink.w %s,%0I0\n\tadd.l %0I%d,%Rsp\n", reg_names[FRAME_POINTER_REGNUM], -fsize);#else asm_fprintf (stream, "\tlink %s,%0I0\n\taddl %0I%d,%Rsp\n", reg_names[FRAME_POINTER_REGNUM], -fsize);#endif } } else if (fsize) { /* Adding negative number is faster on the 68040. */ if (fsize + 4 < 0x8000) { /* asm_fprintf() cannot handle %. */#ifdef MOTOROLA asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4));#else asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4));#endif } else { /* asm_fprintf() cannot handle %. */#ifdef MOTOROLA asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - (fsize + 4));#else asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", - (fsize + 4));#endif } }#ifdef SUPPORT_SUN_FPA for (regno = 24; regno < 56; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) {#ifdef MOTOROLA asm_fprintf (stream, "\tfpmovd %s,-(%Rsp)\n", reg_names[regno]);#else asm_fprintf (stream, "\tfpmoved %s,%Rsp@-\n", reg_names[regno]);#endif }#endif for (regno = 16; regno < 24; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) mask |= 1 << (regno - 16); if ((mask & 0xff) != 0) {#ifdef MOTOROLA asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff);#else asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff);#endif } mask = 0; for (regno = 0; regno < 16; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) { mask |= 1 << (15 - regno); num_saved_regs++; } if (frame_pointer_needed) { mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM)); num_saved_regs--; }#if NEED_PROBE fprintf (stream, "\ttstl sp@(%d)\n", NEED_PROBE - num_saved_regs * 4);#endif if (num_saved_regs <= 2) { /* Store each separately in the same order moveml uses. Using two movel instructions instead of a single moveml is about 15% faster for the 68020 and 68030 at no expense in code size */ int i; /* Undo the work from above. */ for (i = 0; i< 16; i++) if (mask & (1 << i)) asm_fprintf (stream,#ifdef MOTOROLA "\t%Omove.l %s,-(%Rsp)\n",#else "\tmovel %s,%Rsp@-\n",#endif reg_names[15 - i]); } else if (mask) {#ifdef MOTOROLA asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask);#else asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);#endif } if (flag_pic && current_function_uses_pic_offset_table) {#ifdef MOTOROLA asm_fprintf (stream, "\t%Olea (%Rpc, %U_GLOBAL_OFFSET_TABLE_@GOTPC), %s\n", reg_names[PIC_OFFSET_TABLE_REGNUM]);#else asm_fprintf (stream, "\tmovel %0I__GLOBAL_OFFSET_TABLE_, %s\n", reg_names[PIC_OFFSET_TABLE_REGNUM]); asm_fprintf (stream, "\tlea %Rpc@(0,%s:l),%s\n", reg_names[PIC_OFFSET_TABLE_REGNUM], reg_names[PIC_OFFSET_TABLE_REGNUM]);#endif }}/* Return true if this function's epilogue can be output as RTL. */intuse_return_insn (){ int regno; if (!reload_completed || frame_pointer_needed || get_frame_size () != 0) return 0; /* Copied from output_function_epilogue (). We should probably create a separate layout routine to perform the common work. */ for (regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) return 0; return 1;}/* This function generates the assembly code for function exit, on machines that need it. Args are same as for FUNCTION_PROLOGUE. The function epilogue should not depend on the current stack pointer! It should use the frame pointer only, if there is a frame pointer. This is mandatory because of alloca; we also take advantage of it to omit stack adjustments before returning. */voidoutput_function_epilogue (stream, size) FILE *stream; int size;{ register int regno; register int mask, fmask; register int nregs; int offset, foffset, fpoffset; extern char call_used_regs[]; int fsize = (size + 3) & -4; int big = 0; rtx insn = get_last_insn (); /* If the last insn was a BARRIER, we don't have to write any code. */ if (GET_CODE (insn) == NOTE) insn = prev_nonnote_insn (insn); if (insn && GET_CODE (insn) == BARRIER) { /* Output just a no-op so that debuggers don't get confused about which function the pc is in at this address. */ asm_fprintf (stream, "\tnop\n"); return; }#ifdef FUNCTION_EXTRA_EPILOGUE FUNCTION_EXTRA_EPILOGUE (stream, size);#endif nregs = 0; fmask = 0; fpoffset = 0;#ifdef SUPPORT_SUN_FPA for (regno = 24 ; regno < 56 ; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) nregs++; fpoffset = nregs * 8;#endif nregs = 0; for (regno = 16; regno < 24; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) { nregs++; fmask |= 1 << (23 - regno); } foffset = fpoffset + nregs * 12; nregs = 0; mask = 0; if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; for (regno = 0; regno < 16; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) { nregs++; mask |= 1 << regno; } offset = foffset + nregs * 4; if (offset + fsize >= 0x8000 && frame_pointer_needed && (mask || fmask || fpoffset)) {#ifdef MOTOROLA asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra1\n", -fsize);#else asm_fprintf (stream, "\tmovel %0I%d,%Ra1\n", -fsize);#endif fsize = 0, big = 1; } if (nregs <= 2) { /* Restore each separately in the same order moveml does. Using two movel instructions instead of a single moveml is about 15% faster for the 68020 and 68030 at no expense in code size. */ int i; /* Undo the work from above. */ for (i = 0; i< 16; i++) if (mask & (1 << i)) { if (big) {#ifdef MOTOROLA asm_fprintf (stream, "\t%Omove.l -%d(%s,%Ra1.l),%s\n", offset + fsize, reg_names[FRAME_POINTER_REGNUM], reg_names[i]);#else asm_fprintf (stream, "\tmovel %s@(-%d,%Ra1:l),%s\n", reg_names[FRAME_POINTER_REGNUM], offset + fsize, reg_names[i]);#endif } else if (! frame_pointer_needed) {#ifdef MOTOROLA asm_fprintf (stream, "\t%Omove.l (%Rsp)+,%s\n", reg_names[i]);#else asm_fprintf (stream, "\tmovel %Rsp@+,%s\n", reg_names[i]);#endif } else {#ifdef MOTOROLA asm_fprintf (stream, "\t%Omove.l -%d(%s),%s\n", offset + fsize, reg_names[FRAME_POINTER_REGNUM], reg_names[i]);#else asm_fprintf (stream, "\tmovel %s@(-%d),%s\n", reg_names[FRAME_POINTER_REGNUM], offset + fsize, reg_names[i]);#endif } offset = offset - 4; } } else if (mask) { if (big) {#ifdef MOTOROLA asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra1.l),%0I0x%x\n", offset + fsize, reg_names[FRAME_POINTER_REGNUM], mask);#else asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra1:l),%0I0x%x\n", reg_names[FRAME_POINTER_REGNUM], offset + fsize, mask);#endif } else if (! frame_pointer_needed) {#ifdef MOTOROLA asm_fprintf (stream, "\tmovm.l (%Rsp)+,%0I0x%x\n", mask);#else asm_fprintf (stream, "\tmoveml %Rsp@+,%0I0x%x\n", mask);#endif } else {#ifdef MOTOROLA asm_fprintf (stream, "\tmovm.l -%d(%s),%0I0x%x\n", offset + fsize, reg_names[FRAME_POINTER_REGNUM], mask);#else asm_fprintf (stream, "\tmoveml %s@(-%d),%0I0x%x\n", reg_names[FRAME_POINTER_REGNUM], offset + fsize, mask);#endif } } if (fmask) { if (big) {#ifdef MOTOROLA asm_fprintf (stream, "\tfmovm -%d(%s,%Ra1.l),%0I0x%x\n", foffset + fsize, reg_names[FRAME_POINTER_REGNUM], fmask);#else asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra1:l),%0I0x%x\n", reg_names[FRAME_POINTER_REGNUM], foffset + fsize, fmask);#endif } else if (! frame_pointer_needed) {#ifdef MOTOROLA asm_fprintf (stream, "\tfmovm (%Rsp)+,%0I0x%x\n", fmask);#else asm_fprintf (stream, "\tfmovem %Rsp@+,%0I0x%x\n", fmask);#endif } else {#ifdef MOTOROLA asm_fprintf (stream, "\tfmovm -%d(%s),%0I0x%x\n", foffset + fsize, reg_names[FRAME_POINTER_REGNUM], fmask);#else asm_fprintf (stream, "\tfmovem %s@(-%d),%0I0x%x\n", reg_names[FRAME_POINTER_REGNUM], foffset + fsize, fmask);#endif } } if (fpoffset != 0) for (regno = 55; regno >= 24; regno--) if (regs_ever_live[regno] && ! call_used_regs[regno]) { if (big) {#ifdef MOTOROLA asm_fprintf (stream, "\tfpmovd -%d(%s,%Ra1.l), %s\n", fpoffset + fsize, reg_names[FRAME_POINTER_REGNUM], reg_names[regno]);#else asm_fprintf (stream, "\tfpmoved %s@(-%d,%Ra1:l), %s\n", reg_names[FRAME_POINTER_REGNUM], fpoffset + fsize, reg_names[regno]);#endif } else if (! frame_pointer_needed) {#ifdef MOTOROLA asm_fprintf (stream, "\tfpmovd (%Rsp)+,%s\n", reg_names[regno]);#else asm_fprintf (stream, "\tfpmoved %Rsp@+, %s\n", reg_names[regno]);#endif } else {#ifdef MOTOROLA asm_fprintf (stream, "\tfpmovd -%d(%s), %s\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -