📄 h8300.c
字号:
/* Subroutines for insn-output.c for Hitachi H8/300. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Steve Chamberlain (sac@cygnus.com), Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).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. */#include "config.h"#include "system.h"#include "rtl.h"#include "tree.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "output.h"#include "insn-attr.h"#include "flags.h"#include "recog.h"#include "expr.h"#include "function.h"#include "toplev.h"#include "c-pragma.h"#include "tm_p.h"#include "ggc.h"#include "target.h"#include "target-def.h"/* Forward declarations. */static const char *byte_reg PARAMS ((rtx, int));static int h8300_interrupt_function_p PARAMS ((tree));static int h8300_monitor_function_p PARAMS ((tree));static int h8300_os_task_function_p PARAMS ((tree));static void dosize PARAMS ((FILE *, int, unsigned int));static int round_frame_size PARAMS ((int));static unsigned int compute_saved_regs PARAMS ((void));static void push PARAMS ((FILE *, int));static void pop PARAMS ((FILE *, int));static const char *cond_string PARAMS ((enum rtx_code));static unsigned int h8300_asm_insn_count PARAMS ((const char *));const struct attribute_spec h8300_attribute_table[];static tree h8300_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));static tree h8300_handle_eightbit_data_attribute PARAMS ((tree *, tree, tree, int, bool *));static tree h8300_handle_tiny_data_attribute PARAMS ((tree *, tree, tree, int, bool *));static void h8300_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void h8300_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));static void h8300_insert_attributes PARAMS ((tree, tree *));#ifndef OBJECT_FORMAT_ELFstatic void h8300_asm_named_section PARAMS ((const char *, unsigned int));#endifstatic void h8300_encode_label PARAMS ((tree));static void h8300_encode_section_info PARAMS ((tree, int));static const char *h8300_strip_name_encoding PARAMS ((const char *));/* CPU_TYPE, says what cpu we're compiling for. */int cpu_type;/* True if the current function is an interrupt handler (either via #pragma or an attribute specification). */static int interrupt_handler;/* True if the current function is an OS Task (via an attribute specification). */static int os_task;/* True if the current function is a monitor (via an attribute specification). */static int monitor;/* True if a #pragma saveall has been seen for the current function. */static int pragma_saveall;static const char *const names_big[] ={ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" };static const char *const names_extended[] ={ "er0", "er1", "er2", "er3", "er4", "er5", "er6", "er7" };static const char *const names_upper_extended[] ={ "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7" };/* Points to one of the above. *//* ??? The above could be put in an array indexed by CPU_TYPE. */const char * const *h8_reg_names;/* Various operations needed by the following, indexed by CPU_TYPE. */const char *h8_push_op, *h8_pop_op, *h8_mov_op;/* Initialize the GCC target structure. */#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE h8300_attribute_table#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE h8300_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE h8300_output_function_epilogue#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO h8300_encode_section_info#undef TARGET_STRIP_NAME_ENCODING#define TARGET_STRIP_NAME_ENCODING h8300_strip_name_encoding#undef TARGET_INSERT_ATTRIBUTES#define TARGET_INSERT_ATTRIBUTES h8300_insert_attributesstruct gcc_target targetm = TARGET_INITIALIZER;/* See below where shifts are handled for explanation of this enum. */enum shift_alg{ SHIFT_INLINE, SHIFT_ROT_AND, SHIFT_SPECIAL, SHIFT_LOOP};/* Symbols of the various shifts which can be used as indices. */enum shift_type{ SHIFT_ASHIFT, SHIFT_LSHIFTRT, SHIFT_ASHIFTRT};/* Macros to keep the shift algorithm tables small. */#define INL SHIFT_INLINE#define ROT SHIFT_ROT_AND#define LOP SHIFT_LOOP#define SPC SHIFT_SPECIAL/* The shift algorithms for each machine, mode, shift type, and shift count are defined below. The three tables below correspond to QImode, HImode, and SImode, respectively. Each table is organized by, in the order of indecies, machine, shift type, and shift count. */static enum shift_alg shift_alg_qi[3][3][8] = { { /* TARGET_H8300 */ /* 0 1 2 3 4 5 6 7 */ { INL, INL, INL, INL, INL, ROT, ROT, ROT }, /* SHIFT_ASHIFT */ { INL, INL, INL, INL, INL, ROT, ROT, ROT }, /* SHIFT_LSHIFTRT */ { INL, INL, INL, INL, INL, LOP, LOP, SPC } /* SHIFT_ASHIFTRT */ }, { /* TARGET_H8300H */ /* 0 1 2 3 4 5 6 7 */ { INL, INL, INL, INL, INL, ROT, ROT, ROT }, /* SHIFT_ASHIFT */ { INL, INL, INL, INL, INL, ROT, ROT, ROT }, /* SHIFT_LSHIFTRT */ { INL, INL, INL, INL, INL, LOP, LOP, SPC } /* SHIFT_ASHIFTRT */ }, { /* TARGET_H8300S */ /* 0 1 2 3 4 5 6 7 */ { INL, INL, INL, INL, INL, INL, ROT, ROT }, /* SHIFT_ASHIFT */ { INL, INL, INL, INL, INL, INL, ROT, ROT }, /* SHIFT_LSHIFTRT */ { INL, INL, INL, INL, INL, INL, INL, SPC } /* SHIFT_ASHIFTRT */ }};static enum shift_alg shift_alg_hi[3][3][16] = { { /* TARGET_H8300 */ /* 0 1 2 3 4 5 6 7 */ /* 8 9 10 11 12 13 14 15 */ { INL, INL, INL, INL, INL, INL, INL, SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFT */ { INL, INL, INL, INL, INL, LOP, LOP, SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_LSHIFTRT */ { INL, INL, INL, INL, INL, LOP, LOP, SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFTRT */ }, { /* TARGET_H8300H */ /* 0 1 2 3 4 5 6 7 */ /* 8 9 10 11 12 13 14 15 */ { INL, INL, INL, INL, INL, INL, INL, SPC, SPC, SPC, SPC, SPC, SPC, ROT, ROT, ROT }, /* SHIFT_ASHIFT */ { INL, INL, INL, INL, INL, INL, INL, SPC, SPC, SPC, SPC, SPC, SPC, ROT, ROT, ROT }, /* SHIFT_LSHIFTRT */ { INL, INL, INL, INL, INL, INL, INL, SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFTRT */ }, { /* TARGET_H8300S */ /* 0 1 2 3 4 5 6 7 */ /* 8 9 10 11 12 13 14 15 */ { INL, INL, INL, INL, INL, INL, INL, INL, SPC, SPC, SPC, SPC, SPC, ROT, ROT, ROT }, /* SHIFT_ASHIFT */ { INL, INL, INL, INL, INL, INL, INL, INL, SPC, SPC, SPC, SPC, SPC, ROT, ROT, ROT }, /* SHIFT_LSHIFTRT */ { INL, INL, INL, INL, INL, INL, INL, INL, SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFTRT */ }};static enum shift_alg shift_alg_si[3][3][32] = { { /* TARGET_H8300 */ /* 0 1 2 3 4 5 6 7 */ /* 8 9 10 11 12 13 14 15 */ /* 16 17 18 19 20 21 22 23 */ /* 24 25 26 27 28 29 30 31 */ { INL, INL, INL, LOP, LOP, LOP, LOP, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, LOP, SPC, SPC, SPC, SPC, SPC, LOP, LOP, LOP, SPC, SPC, SPC, SPC, LOP, LOP, LOP, SPC }, /* SHIFT_ASHIFT */ { INL, INL, INL, LOP, LOP, LOP, LOP, LOP, SPC, SPC, LOP, LOP, LOP, LOP, LOP, SPC, SPC, SPC, SPC, LOP, LOP, LOP, LOP, LOP, SPC, SPC, SPC, SPC, SPC, LOP, LOP, SPC }, /* SHIFT_LSHIFTRT */ { INL, INL, INL, LOP, LOP, LOP, LOP, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, SPC, SPC, SPC, LOP, LOP, LOP, LOP, LOP, LOP, SPC, SPC, SPC, LOP, LOP, LOP, LOP, SPC }, /* SHIFT_ASHIFTRT */ }, { /* TARGET_H8300H */ /* 0 1 2 3 4 5 6 7 */ /* 8 9 10 11 12 13 14 15 */ /* 16 17 18 19 20 21 22 23 */ /* 24 25 26 27 28 29 30 31 */ { INL, INL, INL, INL, INL, LOP, LOP, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, SPC, SPC, SPC, SPC, SPC, LOP, LOP, LOP, LOP, SPC, LOP, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFT */ { INL, INL, INL, INL, INL, LOP, LOP, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, SPC, SPC, SPC, SPC, SPC, LOP, LOP, LOP, LOP, SPC, LOP, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_LSHIFTRT */ { INL, INL, INL, INL, INL, LOP, LOP, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, LOP, SPC, SPC, SPC, SPC, LOP, LOP, LOP, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, SPC }, /* SHIFT_ASHIFTRT */ }, { /* TARGET_H8300S */ /* 0 1 2 3 4 5 6 7 */ /* 8 9 10 11 12 13 14 15 */ /* 16 17 18 19 20 21 22 23 */ /* 24 25 26 27 28 29 30 31 */ { INL, INL, INL, INL, INL, INL, INL, INL, INL, INL, INL, LOP, LOP, LOP, LOP, SPC, SPC, SPC, SPC, SPC, SPC, SPC, LOP, LOP, SPC, SPC, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFT */ { INL, INL, INL, INL, INL, INL, INL, INL, INL, INL, INL, LOP, LOP, LOP, LOP, SPC, SPC, SPC, SPC, SPC, SPC, SPC, LOP, LOP, SPC, SPC, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_LSHIFTRT */ { INL, INL, INL, INL, INL, INL, INL, INL, INL, INL, INL, LOP, LOP, LOP, LOP, LOP, SPC, SPC, SPC, SPC, SPC, SPC, LOP, LOP, SPC, SPC, LOP, LOP, LOP, LOP, LOP, SPC }, /* SHIFT_ASHIFTRT */ }};#undef INL#undef ROT#undef LOP#undef SPCenum h8_cpu{ H8_300, H8_300H, H8_S};/* Initialize various cpu specific globals at start up. */voidh8300_init_once (){ static const char *const h8_push_ops[2] = { "push" , "push.l" }; static const char *const h8_pop_ops[2] = { "pop" , "pop.l" }; static const char *const h8_mov_ops[2] = { "mov.w", "mov.l" }; if (TARGET_H8300) { cpu_type = (int) CPU_H8300; h8_reg_names = names_big; } else { /* For this we treat the H8/300H and H8S the same. */ cpu_type = (int) CPU_H8300H; h8_reg_names = names_extended; } h8_push_op = h8_push_ops[cpu_type]; h8_pop_op = h8_pop_ops[cpu_type]; h8_mov_op = h8_mov_ops[cpu_type]; if (!TARGET_H8300S && TARGET_MAC) { error ("-ms2600 is used without -ms"); target_flags |= MASK_H8300S; } if (TARGET_H8300 && TARGET_NORMAL_MODE) { error ("-mn is used without -mh or -ms"); target_flags ^= MASK_NORMAL_MODE; } /* Some of the shifts are optimized for speed by default. See http://gcc.gnu.org/ml/gcc-patches/2002-07/msg01858.html If optimizing for size, change shift_alg for those shift to SHIFT_LOOP. */ if (optimize_size) { /* H8/300 */ shift_alg_hi[H8_300][SHIFT_ASHIFT][5] = SHIFT_LOOP; shift_alg_hi[H8_300][SHIFT_ASHIFT][6] = SHIFT_LOOP; shift_alg_hi[H8_300][SHIFT_ASHIFT][13] = SHIFT_LOOP; shift_alg_hi[H8_300][SHIFT_ASHIFT][14] = SHIFT_LOOP; shift_alg_hi[H8_300][SHIFT_LSHIFTRT][13] = SHIFT_LOOP; shift_alg_hi[H8_300][SHIFT_LSHIFTRT][14] = SHIFT_LOOP; shift_alg_hi[H8_300][SHIFT_ASHIFTRT][13] = SHIFT_LOOP; shift_alg_hi[H8_300][SHIFT_ASHIFTRT][14] = SHIFT_LOOP; /* H8/300H */ shift_alg_hi[H8_300H][SHIFT_ASHIFT][5] = SHIFT_LOOP; shift_alg_hi[H8_300H][SHIFT_ASHIFT][6] = SHIFT_LOOP; shift_alg_hi[H8_300H][SHIFT_LSHIFTRT][5] = SHIFT_LOOP; shift_alg_hi[H8_300H][SHIFT_LSHIFTRT][6] = SHIFT_LOOP; shift_alg_hi[H8_300H][SHIFT_ASHIFTRT][5] = SHIFT_LOOP; shift_alg_hi[H8_300H][SHIFT_ASHIFTRT][6] = SHIFT_LOOP; shift_alg_hi[H8_300H][SHIFT_ASHIFTRT][13] = SHIFT_LOOP; shift_alg_hi[H8_300H][SHIFT_ASHIFTRT][14] = SHIFT_LOOP; /* H8S */ shift_alg_hi[H8_S][SHIFT_ASHIFTRT][14] = SHIFT_LOOP; }}static const char *byte_reg (x, b) rtx x; int b;{ static const char *const names_small[] = { "r0l", "r0h", "r1l", "r1h", "r2l", "r2h", "r3l", "r3h", "r4l", "r4h", "r5l", "r5h", "r6l", "r6h", "r7l", "r7h" }; return names_small[REGNO (x) * 2 + b];}/* REGNO must be saved/restored across calls if this macro is true. */#define WORD_REG_USED(regno) \ (regno < 7 \ /* No need to save registers if this function will not return. */ \ && ! TREE_THIS_VOLATILE (current_function_decl) \ && (pragma_saveall \ /* Save any call saved register that was used. */ \ || (regs_ever_live[regno] && !call_used_regs[regno]) \ /* Save the frame pointer if it was used. */ \ || (regno == FRAME_POINTER_REGNUM && regs_ever_live[regno]) \ /* Save any register used in an interrupt handler. */ \ || (interrupt_handler && regs_ever_live[regno]) \ /* Save call clobbered registers in non-leaf interrupt \ handlers. */ \ || (interrupt_handler \ && call_used_regs[regno] \ && !current_function_is_leaf)))/* Output assembly language to FILE for the operation OP with operand size SIZE to adjust the stack pointer. */static voiddosize (file, sign, size) FILE *file; int sign; unsigned int size;{ /* On the H8/300H and H8S, for sizes <= 8 bytes, it is as good or better to use adds/subs insns rather than add.l/sub.l with an immediate value. Also, on the H8/300, if we don't have a temporary to hold the size of the frame in the prologue, we simply emit a sequence of subs since this shouldn't happen often. */ if ((TARGET_H8300 && size <= 4) || ((TARGET_H8300H || TARGET_H8300S) && size <= 8) || (TARGET_H8300 && interrupt_handler) || (TARGET_H8300 && current_function_needs_context && sign < 0)) { const char *op = (sign > 0) ? "add" : "sub"; unsigned HOST_WIDE_INT amount; /* Try different amounts in descending order. */ for (amount = (TARGET_H8300H || TARGET_H8300S) ? 4 : 2; amount > 0; amount /= 2) { char insn[100]; sprintf (insn, "\t%ss\t#%d,%s\n", op, amount, TARGET_H8300 ? "r7" : "er7"); for (; size >= amount; size -= amount) fputs (insn, file); } } else { if (TARGET_H8300) { fprintf (file, "\tmov.w\t#%d,r3\n\tadd.w\tr3,r7\n", sign * size); } else { fprintf (file, "\tadd.l\t#%d,er7\n", sign * size); } }}/* Round up frame size SIZE. */static intround_frame_size (size) int size;{ return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1) & -STACK_BOUNDARY / BITS_PER_UNIT);}/* Compute which registers to push/pop. Return a bit vector of registers. */static unsigned intcompute_saved_regs (){ unsigned int saved_regs = 0; int regno; /* Construct a bit vector of registers to be pushed/popped. */ for (regno = 0; regno <= FRAME_POINTER_REGNUM; regno++) { if (WORD_REG_USED (regno)) saved_regs |= 1 << regno; } /* Don't push/pop the frame pointer as it is treated separately. */ if (frame_pointer_needed) saved_regs &= ~(1 << FRAME_POINTER_REGNUM); return saved_regs;}/* Output assembly language code to push register RN. */static voidpush (file, rn) FILE *file; int rn;{ if (TARGET_H8300) fprintf (file, "\t%s\t%s,@-r7\n", h8_mov_op, h8_reg_names[rn]); else fprintf (file, "\t%s\t%s,@-er7\n", h8_mov_op, h8_reg_names[rn]);}/* Output assembly language code to pop register RN. */static voidpop (file, rn) FILE *file; int rn;{ if (TARGET_H8300) fprintf (file, "\t%s\t@r7+,%s\n", h8_mov_op, h8_reg_names[rn]); else fprintf (file, "\t%s\t@er7+,%s\n", h8_mov_op, h8_reg_names[rn]);}/* This is what the stack looks like after the prolog of a function with a frame has been set up:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -