📄 m68hc11.c
字号:
/* Subroutines for code generation on Motorola 68HC11 and 68HC12. Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Stephane Carrez (stcarrez@nerim.fr)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.Note: A first 68HC11 port was made by Otto Lind (otto@coactive.com) on gcc 2.6.3. I have used it as a starting point for this port. However, this new port is a complete re-write. Its internal design is completely different. The generated code is not compatible with the gcc 2.6.3 port. The gcc 2.6.3 port is available at: ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz*/#include <stdio.h>#include "config.h"#include "system.h"#include "rtl.h"#include "tree.h"#include "tm_p.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 "toplev.h"#include "basic-block.h"#include "function.h"#include "ggc.h"#include "reload.h"#include "target.h"#include "target-def.h"static void print_options PARAMS ((FILE *));static void emit_move_after_reload PARAMS ((rtx, rtx, rtx));static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *));static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *));static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode, int));static int register_indirect_p PARAMS((rtx, enum machine_mode, int));static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx));static int must_parenthesize PARAMS ((rtx));static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int));static int autoinc_mode PARAMS ((rtx));static int m68hc11_make_autoinc_notes PARAMS ((rtx*, void*));static int m68hc11_auto_inc_p PARAMS ((rtx));static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));const struct attribute_spec m68hc11_attribute_table[];void create_regs_rtx PARAMS ((void));static void asm_print_register PARAMS ((FILE *, int));static void m68hc11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));static void m68hc11_asm_out_constructor PARAMS ((rtx, int));static void m68hc11_asm_out_destructor PARAMS ((rtx, int));static void m68hc11_encode_section_info PARAMS((tree, int));/* Must be set to 1 to produce debug messages. */int debug_m6811 = 0;extern FILE *asm_out_file;rtx ix_reg;rtx iy_reg;rtx d_reg;rtx m68hc11_soft_tmp_reg;static GTY(()) rtx stack_push_word;static GTY(()) rtx stack_pop_word;static GTY(()) rtx z_reg;static GTY(()) rtx z_reg_qi;static int regs_inited = 0;/* Set to 1 by expand_prologue() when the function is an interrupt handler. */int current_function_interrupt;/* Set to 1 by expand_prologue() when the function is a trap handler. */int current_function_trap;/* Set to 1 when the current function is placed in 68HC12 banked memory and must return with rtc. */int current_function_far;/* Min offset that is valid for the indirect addressing mode. */HOST_WIDE_INT m68hc11_min_offset = 0;/* Max offset that is valid for the indirect addressing mode. */HOST_WIDE_INT m68hc11_max_offset = 256;/* The class value for base registers. */enum reg_class m68hc11_base_reg_class = A_REGS;/* The class value for index registers. This is NO_REGS for 68HC11. */enum reg_class m68hc11_index_reg_class = NO_REGS;enum reg_class m68hc11_tmp_regs_class = NO_REGS;/* Tables that tell whether a given hard register is valid for a base or an index register. It is filled at init time depending on the target processor. */unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];/* A correction offset which is applied to the stack pointer. This is 1 for 68HC11 and 0 for 68HC12. */int m68hc11_sp_correction;/* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */rtx m68hc11_compare_op0;rtx m68hc11_compare_op1;const struct processor_costs *m68hc11_cost;/* Costs for a 68HC11. */static const struct processor_costs m6811_cost = { /* add */ COSTS_N_INSNS (2), /* logical */ COSTS_N_INSNS (2), /* non-constant shift */ COSTS_N_INSNS (20), /* shiftQI const */ { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2), COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3), COSTS_N_INSNS (2), COSTS_N_INSNS (1) }, /* shiftHI const */ { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4), COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4), COSTS_N_INSNS (2), COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4) }, /* mulQI */ COSTS_N_INSNS (20), /* mulHI */ COSTS_N_INSNS (20 * 4), /* mulSI */ COSTS_N_INSNS (20 * 16), /* divQI */ COSTS_N_INSNS (20), /* divHI */ COSTS_N_INSNS (80), /* divSI */ COSTS_N_INSNS (100)};/* Costs for a 68HC12. */static const struct processor_costs m6812_cost = { /* add */ COSTS_N_INSNS (2), /* logical */ COSTS_N_INSNS (2), /* non-constant shift */ COSTS_N_INSNS (20), /* shiftQI const */ { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2), COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3), COSTS_N_INSNS (2), COSTS_N_INSNS (1) }, /* shiftHI const */ { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4), COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4), COSTS_N_INSNS (2), COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4) }, /* mulQI */ COSTS_N_INSNS (3), /* mulHI */ COSTS_N_INSNS (3), /* mulSI */ COSTS_N_INSNS (3 * 4), /* divQI */ COSTS_N_INSNS (12), /* divHI */ COSTS_N_INSNS (12), /* divSI */ COSTS_N_INSNS (100)};/* Machine specific options */const char *m68hc11_regparm_string;const char *m68hc11_reg_alloc_order;const char *m68hc11_soft_reg_count;static int nb_soft_regs;/* Initialize the GCC target structure. */#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_infostruct gcc_target targetm = TARGET_INITIALIZER;intm68hc11_override_options (){ memset (m68hc11_reg_valid_for_index, 0, sizeof (m68hc11_reg_valid_for_index)); memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base)); /* Compilation with -fpic generates a wrong code. */ if (flag_pic) { warning ("-f%s ignored for 68HC11/68HC12 (not supported)", (flag_pic > 1) ? "PIC" : "pic"); flag_pic = 0; } /* Configure for a 68hc11 processor. */ if (TARGET_M6811) { /* If gcc was built for a 68hc12, invalidate that because a -m68hc11 option was specified on the command line. */ if (TARGET_DEFAULT != MASK_M6811) target_flags &= ~TARGET_DEFAULT; if (!TARGET_M6812) target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX); m68hc11_cost = &m6811_cost; m68hc11_min_offset = 0; m68hc11_max_offset = 256; m68hc11_index_reg_class = NO_REGS; m68hc11_base_reg_class = A_REGS; m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1; m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1; m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1; m68hc11_sp_correction = 1; m68hc11_tmp_regs_class = D_REGS; if (m68hc11_soft_reg_count == 0 && !TARGET_M6812) m68hc11_soft_reg_count = "4"; } /* Configure for a 68hc12 processor. */ if (TARGET_M6812) { m68hc11_cost = &m6812_cost; m68hc11_min_offset = -65536; m68hc11_max_offset = 65536; m68hc11_index_reg_class = D_REGS; m68hc11_base_reg_class = A_OR_SP_REGS; m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1; m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1; m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1; m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1; m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1; m68hc11_sp_correction = 0; m68hc11_tmp_regs_class = TMP_REGS; target_flags &= ~MASK_M6811; target_flags |= MASK_NO_DIRECT_MODE; if (m68hc11_soft_reg_count == 0) m68hc11_soft_reg_count = "0"; if (TARGET_LONG_CALLS) current_function_far = 1; } return 0;}voidm68hc11_conditional_register_usage (){ int i; int cnt = atoi (m68hc11_soft_reg_count); if (cnt < 0) cnt = 0; if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST) cnt = SOFT_REG_LAST - SOFT_REG_FIRST; nb_soft_regs = cnt; for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++) { fixed_regs[i] = 1; call_used_regs[i] = 1; } /* For 68HC12, the Z register emulation is not necessary when the frame pointer is not used. The frame pointer is eliminated and replaced by the stack register (which is a BASE_REG_CLASS). */ if (TARGET_M6812 && flag_omit_frame_pointer && optimize) { fixed_regs[HARD_Z_REGNUM] = 1; }}/* Reload and register operations. */static const char *const reg_class_names[] = REG_CLASS_NAMES;voidcreate_regs_rtx (){ /* regs_inited = 1; */ ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM); iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM); d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM); m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM); stack_push_word = gen_rtx (MEM, HImode, gen_rtx (PRE_DEC, HImode, gen_rtx (REG, HImode, HARD_SP_REGNUM))); stack_pop_word = gen_rtx (MEM, HImode, gen_rtx (POST_INC, HImode, gen_rtx (REG, HImode, HARD_SP_REGNUM)));}/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. - 8 bit values are stored anywhere (except the SP register). - 16 bit values can be stored in any register whose mode is 16 - 32 bit values can be stored in D, X registers or in a soft register (except the last one because we need 2 soft registers) - Values whose size is > 32 bit are not stored in real hard registers. They may be stored in soft registers if there are enough of them. */inthard_regno_mode_ok (regno, mode) int regno; enum machine_mode mode;{ switch (GET_MODE_SIZE (mode)) { case 8: return S_REGNO_P (regno) && nb_soft_regs >= 4; case 4: return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2); case 2: return G_REGNO_P (regno); case 1: /* We have to accept a QImode in X or Y registers. Otherwise, the reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined in the insns. Reload fails if the insn rejects the register class 'a' as well as if it accepts it. Patterns that failed were zero_extend_qihi2 and iorqi3. */ return G_REGNO_P (regno) && !SP_REGNO_P (regno); default: return 0; }}intm68hc11_hard_regno_rename_ok (reg1, reg2) int reg1, reg2;{ /* Don't accept renaming to Z register. We will replace it to X,Y or D during machine reorg pass. */ if (reg2 == HARD_Z_REGNUM) return 0; /* Don't accept renaming D,X to Y register as the code will be bigger. */ if (TARGET_M6811 && reg2 == HARD_Y_REGNUM && (D_REGNO_P (reg1) || X_REGNO_P (reg1))) return 0; return 1;}enum reg_classpreferred_reload_class (operand, class) rtx operand; enum reg_class class;{ enum machine_mode mode; mode = GET_MODE (operand); if (debug_m6811) { printf ("Preferred reload: (class=%s): ", reg_class_names[class]); } if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand)) return m68hc11_base_reg_class; if (class >= S_REGS && (GET_CODE (operand) == MEM || GET_CODE (operand) == CONST_INT)) { /* S_REGS class must not be used. The movhi template does not work to move a memory to a soft register. Restrict to a hard reg. */ switch (class) { default: case G_REGS: case D_OR_A_OR_S_REGS: class = A_OR_D_REGS; break; case A_OR_S_REGS: class = A_REGS; break; case D_OR_SP_OR_S_REGS: class = D_OR_SP_REGS; break; case D_OR_Y_OR_S_REGS: class = D_OR_Y_REGS; break; case D_OR_X_OR_S_REGS: class = D_OR_X_REGS; break; case SP_OR_S_REGS: class = SP_REGS; break; case Y_OR_S_REGS: class = Y_REGS; break; case X_OR_S_REGS: class = X_REGS; break; case D_OR_S_REGS: class = D_REGS; } } else if (class == Y_REGS && GET_CODE (operand) == MEM) { class = Y_REGS; } else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4) { class = D_OR_X_REGS; } else if (class >= S_REGS && S_REG_P (operand)) { switch (class) { default: case G_REGS: case D_OR_A_OR_S_REGS: class = A_OR_D_REGS; break; case A_OR_S_REGS: class = A_REGS; break; case D_OR_SP_OR_S_REGS: class = D_OR_SP_REGS; break; case D_OR_Y_OR_S_REGS: class = D_OR_Y_REGS; break; case D_OR_X_OR_S_REGS: class = D_OR_X_REGS; break; case SP_OR_S_REGS: class = SP_REGS; break; case Y_OR_S_REGS: class = Y_REGS; break; case X_OR_S_REGS: class = X_REGS; break; case D_OR_S_REGS: class = D_REGS; } } else if (class >= S_REGS) { if (debug_m6811)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -