?? m68k.c
字號:
/* Subroutines for insn-output.c for Motorola 68000 family. Copyright (C) 1987, 93-98, 1999 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 "config.h"#include "system.h"#include "tree.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"#include "recog.h"#include "toplev.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 ();/* Alignment to use for loops and jumps *//* Specify power of two alignment used for loops. */const char *m68k_align_loops_string;/* Specify power of two alignment used for non-loop jumps. */const char *m68k_align_jumps_string;/* Specify power of two alignment used for functions. */const char *m68k_align_funcs_string;/* Specify power of two alignment used for loops. */int m68k_align_loops;/* Specify power of two alignment used for non-loop jumps. */int m68k_align_jumps;/* Specify power of two alignment used for functions. */int m68k_align_funcs;/* Nonzero if the last compare/test insn had FP operands. The sCC expanders peek at this to determine what to do for the 68060, which has no fsCC instructions. */int m68k_last_compare_had_fp_operands;/* Sometimes certain combinations of command options do not make sense on a particular target machine. You can define a macro `OVERRIDE_OPTIONS' to take account of this. This macro, if defined, is executed once just after all the command options have been parsed. Don't use this macro to turn on various extra optimizations for `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */voidoverride_options (){ int def_align; def_align = 1; /* Validate -malign-loops= value, or provide default */ if (m68k_align_loops_string) { m68k_align_loops = atoi (m68k_align_loops_string); if (m68k_align_loops < 1 || m68k_align_loops > MAX_CODE_ALIGN) fatal ("-malign-loops=%d is not between 1 and %d", m68k_align_loops, MAX_CODE_ALIGN); } else m68k_align_loops = def_align; /* Validate -malign-jumps= value, or provide default */ if (m68k_align_jumps_string) { m68k_align_jumps = atoi (m68k_align_jumps_string); if (m68k_align_jumps < 1 || m68k_align_jumps > MAX_CODE_ALIGN) fatal ("-malign-jumps=%d is not between 1 and %d", m68k_align_jumps, MAX_CODE_ALIGN); } else m68k_align_jumps = def_align; /* Validate -malign-functions= value, or provide default */ if (m68k_align_funcs_string) { m68k_align_funcs = atoi (m68k_align_funcs_string); if (m68k_align_funcs < 1 || m68k_align_funcs > MAX_CODE_ALIGN) fatal ("-malign-functions=%d is not between 1 and %d", m68k_align_funcs, MAX_CODE_ALIGN); } else m68k_align_funcs = def_align;}/* 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; int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset; 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 } if (dwarf2out_do_frame ()) { char *l; l = (char *) dwarf2out_cfi_label (); cfa_store_offset += 4; cfa_offset = cfa_store_offset; dwarf2out_def_cfa (l, FRAME_POINTER_REGNUM, cfa_offset); dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, -cfa_store_offset); cfa_store_offset += fsize; } } else if (fsize) { if (fsize + 4 < 0x8000) {#ifndef NO_ADDSUB_Q if (fsize + 4 <= 8) { if (!TARGET_5200) { /* asm_fprintf() cannot handle %. */#ifdef MOTOROLA asm_fprintf (stream, "\tsubq.w %0I%d,%Rsp\n", fsize + 4);#else asm_fprintf (stream, "\tsubqw %0I%d,%Rsp\n", fsize + 4);#endif } else { /* asm_fprintf() cannot handle %. */#ifdef MOTOROLA asm_fprintf (stream, "\tsubq.l %0I%d,%Rsp\n", fsize + 4);#else asm_fprintf (stream, "\tsubql %0I%d,%Rsp\n", fsize + 4);#endif } } else if (fsize + 4 <= 16 && TARGET_CPU32) { /* On the CPU32 it is faster to use two subqw instructions to subtract a small integer (8 < N <= 16) to a register. */ /* asm_fprintf() cannot handle %. */#ifdef MOTOROLA asm_fprintf (stream, "\tsubq.w %0I8,%Rsp\n\tsubq.w %0I%d,%Rsp\n", fsize + 4 - 8);#else asm_fprintf (stream, "\tsubqw %0I8,%Rsp\n\tsubqw %0I%d,%Rsp\n", fsize + 4 - 8);#endif } else #endif /* not NO_ADDSUB_Q */ if (TARGET_68040) { /* Adding negative number is faster on the 68040. */ /* 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 {#ifdef MOTOROLA asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", - (fsize + 4));#else asm_fprintf (stream, "\tlea %Rsp@(%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 } if (dwarf2out_do_frame ()) { cfa_store_offset += fsize; cfa_offset = cfa_store_offset; dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset); } }#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 if (dwarf2out_do_frame ()) { char *l = dwarf2out_cfi_label (); cfa_store_offset += 8; if (! frame_pointer_needed) { cfa_offset = cfa_store_offset; dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); } dwarf2out_reg_save (l, regno, -cfa_store_offset); } }#endif if (TARGET_68881) { for (regno = 16; regno < 24; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) { mask |= 1 << (regno - 16); num_saved_regs++; } 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 if (dwarf2out_do_frame ()) { char *l = (char *) dwarf2out_cfi_label (); int n_regs; cfa_store_offset += num_saved_regs * 12; if (! frame_pointer_needed) { cfa_offset = cfa_store_offset; dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); } for (regno = 16, n_regs = 0; regno < 24; regno++) if (mask & (1 << (regno - 16))) dwarf2out_reg_save (l, regno, -cfa_store_offset + n_regs++ * 12); } } mask = 0; num_saved_regs = 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 (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) { mask |= 1 << (15 - PIC_OFFSET_TABLE_REGNUM); num_saved_regs++; }#if NEED_PROBE#ifdef MOTOROLA#ifdef CRDS asm_fprintf (stream, "\ttstl %d(%Rsp)\n", NEED_PROBE - num_saved_regs * 4);#else asm_fprintf (stream, "\ttst.l %d(%Rsp)\n", NEED_PROBE - num_saved_regs * 4);#endif#else asm_fprintf (stream, "\ttstl %Rsp@(%d)\n", NEED_PROBE - num_saved_regs * 4);#endif#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]); if (dwarf2out_do_frame ()) { char *l = (char *) dwarf2out_cfi_label (); cfa_store_offset += 4; if (! frame_pointer_needed) { cfa_offset = cfa_store_offset; dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); } dwarf2out_reg_save (l, 15 - i, -cfa_store_offset); } } } else if (mask) { if (TARGET_5200) { /* The coldfire does not support the predecrement form of the movml instruction, so we must adjust the stack pointer and then use the plain address register indirect mode. We also have to invert the register save mask to use the new mode. FIXME: if num_saved_regs was calculated earlier, we could combine the stack pointer adjustment with any adjustment done when the initial stack frame is created. This would save an instruction */ int newmask = 0; int i; for (i = 0; i < 16; i++) if (mask & (1 << i)) newmask |= (1 << (15-i));#ifdef MOTOROLA asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", -num_saved_regs*4); asm_fprintf (stream, "\tmovm.l %0I0x%x,(%Rsp)\n", newmask);#else asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", -num_saved_regs*4); asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@\n", newmask);#endif } else {#ifdef MOTOROLA asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask);#else asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask);#endif } if (dwarf2out_do_frame ()) { char *l = (char *) dwarf2out_cfi_label (); int n_regs; cfa_store_offset += num_saved_regs * 4; if (! frame_pointer_needed) { cfa_offset = cfa_store_offset; dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); } for (regno = 0, n_regs = 0; regno < 16; regno++) if (mask & (1 << (15 - regno))) dwarf2out_reg_save (l, regno, -cfa_store_offset + n_regs++ * 4); } } 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",
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -