📄 m68hc11.c
字号:
/* Subroutines for code generation on Motorola 68HC11 and 68HC12. Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Stephane Carrez (stcarrez@nerim.fr)This file is part of GCC.GCC 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.GCC 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 GCC; 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 "coretypes.h"#include "tm.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 "libfuncs.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 emit_move_after_reload (rtx, rtx, rtx);static rtx simplify_logical (enum machine_mode, int, rtx, rtx *);static void m68hc11_emit_logical (enum machine_mode, int, rtx *);static void m68hc11_reorg (void);static int go_if_legitimate_address_internal (rtx, enum machine_mode, int);static int register_indirect_p (rtx, enum machine_mode, int);static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);static int must_parenthesize (rtx);static int m68hc11_address_cost (rtx);static int m68hc11_shift_cost (enum machine_mode, rtx, int);static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);static bool m68hc11_rtx_costs (rtx, int, int, int *);static int m68hc11_auto_inc_p (rtx);static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *);const struct attribute_spec m68hc11_attribute_table[];void create_regs_rtx (void);static void asm_print_register (FILE *, int);static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT);static void m68hc11_asm_out_constructor (rtx, int);static void m68hc11_asm_out_destructor (rtx, int);static void m68hc11_file_start (void);static void m68hc11_encode_section_info (tree, rtx, int);static const char *m68hc11_strip_name_encoding (const char* str);static unsigned int m68hc11_section_type_flags (tree, const char*, int);static int autoinc_mode (rtx);static int m68hc11_make_autoinc_notes (rtx *, void *);static void m68hc11_init_libfuncs (void);static rtx m68hc11_struct_value_rtx (tree, int);static bool m68hc11_return_in_memory (tree, tree);/* 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;#define ADDR_STRICT 0x01 /* Accept only registers in class A_REGS */#define ADDR_INCDEC 0x02 /* Post/Pre inc/dec */#define ADDR_INDEXED 0x04 /* D-reg index */#define ADDR_OFFSET 0x08#define ADDR_INDIRECT 0x10 /* Accept (mem (mem ...)) for [n,X] */#define ADDR_CONST 0x20 /* Accept const and symbol_ref */int m68hc11_addr_mode;int m68hc11_mov_addr_mode;/* 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_ASM_FILE_START#define TARGET_ASM_FILE_START m68hc11_file_start#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info#undef TARGET_SECTION_TYPE_FLAGS#define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags#undef TARGET_RTX_COSTS#define TARGET_RTX_COSTS m68hc11_rtx_costs#undef TARGET_ADDRESS_COST#define TARGET_ADDRESS_COST m68hc11_address_cost#undef TARGET_MACHINE_DEPENDENT_REORG#define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg#undef TARGET_INIT_LIBFUNCS#define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs#undef TARGET_STRUCT_VALUE_RTX#define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx#undef TARGET_RETURN_IN_MEMORY#define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory#undef TARGET_CALLEE_COPIES#define TARGET_CALLEE_COPIES hook_callee_copies_named#undef TARGET_STRIP_NAME_ENCODING#define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encodingstruct gcc_target targetm = TARGET_INITIALIZER;intm68hc11_override_options (void){ 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; } /* Do not enable -fweb because it breaks the 32-bit shift patterns by breaking the match_dup of those patterns. The shift patterns will no longer be recognized after that. */ flag_web = 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; m68hc11_addr_mode = ADDR_OFFSET; m68hc11_mov_addr_mode = 0; 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; m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0); m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0); 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 (void){ 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. */voidcreate_regs_rtx (void){ /* 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 (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 (int reg1, int 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 (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))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -