⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 m68hc11.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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 + -